576 Stepper Motors
Learning Objectives
After completing this chapter, you will be able to:
- Understand stepper motor construction and step sequences
- Control stepper motors with ULN2003 and A4988/DRV8825 drivers
- Implement acceleration profiles to prevent missed steps
- Use the AccelStepper library for smooth motion
- Configure microstepping for increased resolution
- Size stepper motors for precision applications
576.1 Stepper Motor Fundamentals
Stepper motors move in discrete steps, providing precise position control without feedback sensors (open-loop control).
Characteristics:
- Precise angular positioning (typically 1.8 deg/step = 200 steps/rev)
- Open-loop control (no encoder needed)
- High holding torque at standstill
- Step-by-step movement (can be jerky at low speeds)
- Higher power consumption than servos
576.1.1 Step Sequences
Full-Step Sequence (28BYJ-48 with ULN2003):
| Step | IN1 | IN2 | IN3 | IN4 |
|---|---|---|---|---|
| 1 | 1 | 0 | 0 | 0 |
| 2 | 0 | 1 | 0 | 0 |
| 3 | 0 | 0 | 1 | 0 |
| 4 | 0 | 0 | 0 | 1 |
Half-Step Sequence (smoother, double resolution):
| Step | IN1 | IN2 | IN3 | IN4 |
|---|---|---|---|---|
| 1 | 1 | 0 | 0 | 0 |
| 2 | 1 | 1 | 0 | 0 |
| 3 | 0 | 1 | 0 | 0 |
| 4 | 0 | 1 | 1 | 0 |
| 5 | 0 | 0 | 1 | 0 |
| 6 | 0 | 0 | 1 | 1 |
| 7 | 0 | 0 | 0 | 1 |
| 8 | 1 | 0 | 0 | 1 |
576.2 28BYJ-48 with ULN2003
The 28BYJ-48 is a popular low-cost stepper for hobby projects.
Specifications:
- Steps per revolution: 2048 (with 64:1 gearbox)
- Operating voltage: 5V DC
- Current: 200-300mA
- Step angle: 5.625 deg/64 = 0.18 deg effective
#include <AccelStepper.h>
#define MOTOR_PIN1 19
#define MOTOR_PIN2 18
#define MOTOR_PIN3 5
#define MOTOR_PIN4 17
// 28BYJ-48 with 64:1 gearbox = 2048 steps per revolution
AccelStepper stepper(AccelStepper::HALF4WIRE,
MOTOR_PIN1, MOTOR_PIN3, MOTOR_PIN2, MOTOR_PIN4);
const int STEPS_PER_REV = 2048;
void setup() {
Serial.begin(115200);
stepper.setMaxSpeed(1000); // Steps per second
stepper.setAcceleration(500); // Steps per second^2
Serial.println("Stepper Motor Controller");
Serial.println("Commands: 0-360 = angle, h = home, f = full rotation");
}
void loop() {
if (Serial.available()) {
String input = Serial.readStringUntil('\n');
input.trim();
if (input == "h") {
Serial.println("Homing to 0 degrees...");
stepper.moveTo(0);
}
else if (input == "f") {
Serial.println("Full rotation...");
stepper.move(STEPS_PER_REV);
}
else {
int angle = input.toInt();
if (angle >= 0 && angle <= 360) {
long targetSteps = (long)angle * STEPS_PER_REV / 360;
Serial.print("Moving to ");
Serial.print(angle);
Serial.println(" degrees");
stepper.moveTo(targetSteps);
}
}
}
stepper.run(); // Must be called frequently
}
// Convert angle to steps
long angleToSteps(int angle) {
return (long)angle * STEPS_PER_REV / 360;
}
// Convert steps to angle
int stepsToAngle(long steps) {
return (int)(steps * 360 / STEPS_PER_REV);
}576.3 NEMA 17 with A4988/DRV8825
For higher performance, NEMA 17 steppers with A4988 or DRV8825 drivers are the standard choice.
NEMA 17 Specifications:
- Steps per revolution: 200 (1.8 deg/step)
- Holding torque: 40+ kg-cm
- Operating current: 1.2-2.0A per phase
- Voltage: 12-24V
A4988 Driver Features:
- Microstepping: 1, 1/2, 1/4, 1/8, 1/16
- Current limit adjustment
- Sleep mode for power saving
- Step/direction interface
Microstepping Settings:
| MS1 | MS2 | MS3 | Resolution | Steps/Rev |
|---|---|---|---|---|
| 0 | 0 | 0 | Full step | 200 |
| 1 | 0 | 0 | 1/2 step | 400 |
| 0 | 1 | 0 | 1/4 step | 800 |
| 1 | 1 | 0 | 1/8 step | 1600 |
| 1 | 1 | 1 | 1/16 step | 3200 |
#include <AccelStepper.h>
#define STEP_PIN 25
#define DIR_PIN 26
#define ENABLE_PIN 27
// NEMA 17 with 1/16 microstepping = 3200 steps per revolution
AccelStepper stepper(AccelStepper::DRIVER, STEP_PIN, DIR_PIN);
const int STEPS_PER_REV = 3200;
void setup() {
Serial.begin(115200);
pinMode(ENABLE_PIN, OUTPUT);
digitalWrite(ENABLE_PIN, LOW); // Enable driver (active LOW)
stepper.setMaxSpeed(3000); // Steps per second
stepper.setAcceleration(1000); // Steps per second^2
Serial.println("NEMA 17 Stepper Ready");
}
void loop() {
if (Serial.available()) {
char cmd = Serial.read();
switch(cmd) {
case 'f': // Forward one revolution
stepper.move(STEPS_PER_REV);
break;
case 'b': // Backward one revolution
stepper.move(-STEPS_PER_REV);
break;
case 'h': // Home position
stepper.moveTo(0);
break;
case 's': // Stop
stepper.stop();
break;
case 'd': // Disable (power saving)
digitalWrite(ENABLE_PIN, HIGH);
break;
case 'e': // Enable
digitalWrite(ENABLE_PIN, LOW);
break;
}
}
stepper.run();
}576.4 Acceleration Profiles
Steppers cannot instantly change speed. Attempting to start at full speed causes missed steps because the rotor can’t keep up with the magnetic field changes.
Trapezoidal velocity profile:
- Acceleration phase: Gradually increase speed
- Constant velocity: Maintain max speed during travel
- Deceleration: Gradually decrease speed to prevent overshoot
The AccelStepper library handles this automatically!
// Manual trapezoidal profile (if not using AccelStepper)
void moveWithAcceleration(int targetSteps, int maxSpeed, int acceleration) {
int currentSpeed = 0;
int position = 0;
int direction = (targetSteps > 0) ? 1 : -1;
targetSteps = abs(targetSteps);
// Calculate distances for accel/decel phases
int accelSteps = (maxSpeed * maxSpeed) / (2 * acceleration);
int decelSteps = accelSteps;
int constSteps = targetSteps - accelSteps - decelSteps;
if (constSteps < 0) {
// Can't reach max speed, use triangular profile
accelSteps = targetSteps / 2;
decelSteps = targetSteps - accelSteps;
constSteps = 0;
maxSpeed = sqrt(2 * acceleration * accelSteps);
}
// Acceleration phase
for (int i = 0; i < accelSteps; i++) {
currentSpeed = sqrt(2 * acceleration * i);
step(direction);
delayMicroseconds(1000000 / currentSpeed);
}
// Constant speed phase
for (int i = 0; i < constSteps; i++) {
step(direction);
delayMicroseconds(1000000 / maxSpeed);
}
// Deceleration phase
for (int i = decelSteps; i > 0; i--) {
currentSpeed = sqrt(2 * acceleration * i);
step(direction);
delayMicroseconds(1000000 / currentSpeed);
}
}576.5 Common Pitfalls
The Mistake: Setting the stepper driver current limit to the motor’s rated current (e.g., 2.0A) without considering that stepper motors are rated for maximum holding torque at stall, not continuous operation.
Why It Happens: Datasheets list “rated current per phase” which represents the maximum the motor can handle when stationary with proper heat sinking.
The Fix: Start with 70-80% of rated current (e.g., 1.4-1.6A for a 2.0A motor) and increase only if torque is insufficient. Monitor motor temperature after 30 minutes of continuous operation - the case should not exceed 70-80C.
The Mistake: Assuming a stepper motor will always reach the commanded position without feedback, then discovering position errors accumulate over time.
Why It Happens: Stepper motors are marketed as “precise” (1.8 deg/step), creating false confidence. In reality, missed steps from overloading, mechanical binding, or acceleration too fast cause cumulative drift.
The Fix: For precision applications, add encoder verification or use limit switches for homing/calibration routines.
576.6 Interactive Lab: Stepper Precision
Challenges:
- Make the stepper rotate exactly 90 degrees
- Implement a clock with the second hand driven by the stepper
- Add buttons for forward/reverse step control
576.7 What’s Next?
Now that you understand motor control, you’re ready to explore relay and solenoid switching for on/off control applications.