3D Scanner Day 3-4
Day 3: Intro to Stepper Motors:
Why should I even bother spending my time understanding stepper motors?
What’s the purpose of writing code, and what does a “good reflection” even mean when I’m drowning in questions?
I’ve thrown every spare moment of my life into chasing new things—new ideas, new tools, new possibilities. But I never stop to look back. The further I stretch my gaze, the smaller I become, as if I’m collapsing under the sheer weight of everything I’m supposed to learn. It’s overwhelming, almost suffocating, to stare into an infinity of knowledge and realize how little of it I actually grasp.
I wish I had more time to explore the robotic arm, to actually touch the future I keep imagining. But the window to that future is so high above me that I can barely see the light leaking through. And somewhere along the way, I realized the truth: before I can reach that window, I have to build a ladder—one rung at a time. Before I can touch the “cool stuff,” I have to grind, to dig in, to strengthen the foundations I’ve been pretending I already had.
I can’t build an empire of knowledge out of thin air. And right now, I’m standing here without the bones, without the structure, without the anchor I need to support everything I’m trying to become.
Less is more…
Stepper Motors
I am going to provide a simple summary of this video. For those who have a attention span of less than 5 seconds, this will only take 5 hours. Let assume 5 hour < 5 seconds.
I will attach the video link again for reference:
So let look at these two photos:
A stepper motor does not spin continuously like a DC motor.
Instead, it moves in discrete steps. This comes from the interaction between two things inside the motor:
- Permanent Magnets
The rotor contains permanent magnets. Their north and south poles are fixed and never change. Sometimes in a “Hybrid” Motor, you will see N and S on different directional axels.
- Coils
Around the rotor, there are multiple coils of wire.
When electric current flows through a coil, it becomes an electromagnet.
The Opposite ends of N/S motivates the permanent magnets to adjust.
The stepper driver energizes the coils in a specific sequence.
Every time the magnetic field shifts to a new coil, the rotor aligns itself with that coil.
This alignment is one “step”.
Did YOU KNOW:
The Rotor have more teeth than the stator.
The Rotor have 50 TEETH and the STATOR have 48.
Why the Rotor Has More Teeth Than the Stator
If the rotor and stator had the same number of teeth, the motor would only snap into one alignment for each stator position.
That would give you terrible resolution.
Instead, the designers intentionally make the rotor tooth count slightly different from the stator tooth count.
This creates a “detuning” effect.
You can think of it like two gears with slightly different tooth counts. As you energize different stator poles, the rotor’s tooth alignment shifts by a tiny angle each time.
Why Stepper Motors Are Precise
You know exactly how many steps the motor must take to rotate by a chosen angle.
For example:
1.8° per step
50 steps = 90°
200 steps = full rotation
This is why 3D printers, CNCs, and your 3D scanner use them. No encoders are required for position.
The A4988 Stepper Motor Driver
The A4988 is the small module between your Arduino and the motor.
Its job is to do all the coil switching and current control.
You do not energize coils yourself; you just send simple logic signals.
A4988 Inputs IMPORTANTE
STEP pin
Each rising edge = one microstep.
Pulse the STEP pin fast → motor moves fast.
DIR pin
High = one direction.
Low = opposite direction.
ENABLE pin
Low = motor is active.
High = motor is disabled and free to move.
What the A4988 Actually Does Internally
It switches current between the two motor windings in the correct sequence so the rotor turns.
It uses an internal chopper circuit to limit the current to a safe value.
It generates microsteps, which interpolate the current between coils.
It handles high motor current even though the Arduino pins supply almost none.
Video Explaining Stepper Motor:
Simple Stepper Motor Code:
SET UP
I plug in the stepper motor on the X of the CNC shield.
We know that the Step pin for X axis is 2, and Direction Pin is 5.
So we write:
1 | const int STEP_PIN = 2; |
Where:
-
STEP_PIN= 2 → Arduino digital pin 2 is wired to the A4988 STEP input. -
DIR_PIN= 5 → Arduino digital pin 5 is wired to the A4988 DIR (direction) input. -
ENABLE_PIN= 8 → Arduino digital pin 8 is wired to the A4988 ENABLE input.
Next: We want to set up a standard pause time.
So we write:
1 | const int STEP_DELAY_US = 1000 |
Now We have to setup() Where the code only runs once, uno,----:
1 | void setup() { |
So UNPACK:
-
pinMode(STEP_PIN, OUTPUT); -
Tells the Arduino: “Pin 2 will send signals out,” not read them.
-
pinMode(DIR_PIN, OUTPUT); -
Pin 5 is also an output; we’ll use it to set the direction.
-
pinMode(ENABLE_PIN, OUTPUT); -
Pin 8 is an output; used to enable/disable the driver
-
Note: This is consistent for X,Y,and Z axis.
-
digitalWrite(ENABLE_PIN, LOW); -
On A4988: ENABLE = LOW means “turn the driver ON.”
So as soon as setup finishes, the motor is energized and holding position.
LOOP FUNC
Next Lep write a Loop function:
1 | void loop() { |
This code sets the direction into clockwise, and calls in the function stepMotor and asks it to move 200 steps.
And we will have to write the function by ourselves.
Our expected solution will be.
1 | > | > | > | > | < | < | < | < |
Where > mean High or Clockwise Position, and | mean delay 500 msec and < mean Counter Clockwise Position.
STEPPerMOTOR FUNC
1 | void stepMotor(int steps) { |
This is a function that only takes in 1 Input:
1 | void stepMotor(int steps) |
Void: means that the function doesn’t return and value.
The medium difficulty part: For-Loop
Let use the basic example of for loops in Python
for i in range(steps):
1 | for char in "Hello": |
Now let transform it into C:
1 | for (int i = 0; i < steps; i++) { |
If you want to make it crazier:
1 | names = ["Thomas", "Fat", "Pig"] |
1 | # The expected output would be: |
In C how should you write it???
Well you can’t or it is very painful:
1 |
|
Back to stepMotor Func:
1 | void stepMotor(int steps) { |
-
Starts with
i = 0. -
Repeats the code inside while
i < steps. -
Each time it runs, i increases by 1 using
(i++)ori = i + 1.
- So if steps = 200, it runs 200 times.
digitalWrite(STEP_PIN, HIGH);
-
Sets the STEP pin to HIGH.
-
The A4988 looks for a LOW → HIGH to trigger a step.
delayMicroseconds(STEP_DELAY_US);
- Wait so the pulse stays HIGH long enough to be registered. If it’s too short, the driver might miss it.
digitalWrite(STEP_PIN, LOW)
- Sets the STEP pin back to LOW.
delayMicroseconds(STEP_DELAY_US);
- Wait again before sending the next step.
The delay also determine the maximum time needed to perform each step.
Day 4 Combining
How should we combine all of our progress.
How should I obtain and use all of my data.
And How can I apply the theories into test?
To be Honest, by this point of the day, I still don’t have a clear strategy to which I am able to play with both the IR sensor and the Stepper Motor at the same time.
My mistake:
Though I had clarified what I need and what I want, Steps and Measurements, I wrote the wrong variable name, confused myself with Directions and tricked myself with incorrect data_.
I am going to list my code here and debug my data:
1 | // IR sensor on A2, Stepper on pins 2,5,8 |
Debugging Time:
OOFF: That must be overwhelming watching so much code.
Mistake 1: Self-Contradictory Scanning;
In Scan, I set the direction:
1 | void scan(bool clockwise) { |
Or in if-else statement:
1 | void scan(bool clockwise) { |
However, I then wrote in moveSteps:
1 | void moveSteps(int steps, bool direction) { |
Why does having an direction assigned in a direction matter? Why is it problematic?
This is because the real direction used is whatever I pass as direction into moveSteps(), not the clockwise value I set before the loop.
And inside the scan(bool clockwis), I already set the direction:
1 | moveSteps(stepsPerMove, false); |
This means that clockwise is completely ignored.
And the motor always moves in false direction, regardless of moveSteps.
SOLUTION:
The answer is easy, I simply have to pass it through. I will remove the settling of dir in scan() and pass it:
1 | void scan(bool clockwise) { |
Mistake 2: I am terrible at fundamentals:
We know that: int is always an integer.
Therefore: 2/3 equals to 0, because it truncates.
However, I did this:
1 | int stepsPerMove = 1; //ANGLE_INCREMENT * STEPS_PER_REV / 360; |
Consequently:
1 | ANGLE_INCREMENT * STEPS_PER_REV / 360 |
So I should change it into a float:
1 | const float STEPS_PER_DEG = (float)STEPS_PER_REV / 360.0; |
Continue: Mapping
Ignore all the bug, and here is a very last minute test:
1 | import serial |
I used pip to download both pyserial and matplotlib
Then here is a 10 step summary from WebbGPT
-
Import serial for Arduino communication and matplotlib.pyplot for plotting.
-
Open a serial port connection on /dev/cu.usbmodem21301 at 115200 baud.
-
Initialize two empty lists to store step indices and distance readings.
-
Loop up to 50 times to read individual data lines from the Arduino.
- 50 * 1.8 = 90
-
Read each line using read_until() and decode it from bytes to text.
-
Skip empty lines that contain no usable data.
-
Attempt to split each line into a step value and a distance value separated by a comma.
-
Convert the parsed step to int and distance to float, then append them to lists.
-
Handle and report any malformed lines using a ValueError exception block.
-
After closing the serial connection, plot the collected step vs. distance data with labels, grid, and markers.
Day 0 Images:
Here is how I thought I could implement it:
Looking back, it is. a lot of confusion and excitement.
I look forward to work with the CAD team!


