AccelStepper: smooth stepper moves that ramp up and down
AccelStepper, by Mike McCauley, is the library people move to once the built-in Stepper library is not enough. It ramps a motor up to speed and back down again, keeps track of the absolute position in steps, and never blocks: you tell it where to go with moveTo() and then call run() over and over, and each call makes at most one step when one is due.
Built in on Mokxi: #include <AccelStepper.h> and it builds, with nothing to install. Free, and no account needed.
What AccelStepper does
It drives a STEP and DIR driver such as the A4988, DRV8825 or TMC2209 (AccelStepper::DRIVER), or four pins straight to a ULN2003 board for a 28BYJ-48 (FULL4WIRE or HALF4WIRE, pins in the order IN1, IN3, IN2, IN4). The speeds are in steps per second and the acceleration in steps per second per second.
Because the step timing lives inside run(), loop() has to come back to it far more often than the motor steps. A delay(), a long Serial print or a blocking sensor read in loop() shows up as a motor that stutters. The math is floating point, so an Uno tops out around 4000 steps a second.
| Library Manager name | AccelStepper |
|---|---|
| Author | Mike McCauley |
| Include | #include <AccelStepper.h>#include <MultiStepper.h> |
| Boards | every board Mokxi compiles for but ATtiny85 |
| In the simulator | Simulated: it runs against the part the way it does on the bench. |
| Parts it drives | Stepper driver, A4988, Stepper motor, 28BYJ-48 with ULN2003 |
Install it
It builds on every board Mokxi compiles for but ATtiny85.
In Mokxi it is built in: #include <AccelStepper.h> and the sketch compiles, with no download, no zip and no Library Manager.
On a real board, install "AccelStepper" by Mike McCauley from the Arduino IDE鈥檚 Library Manager (Sketch, Include Library, Manage Libraries), or add AccelStepper to lib_deps in PlatformIO. Mokxi follows the calls of release 1.64, so a sketch written here builds there too.
ESP32-C3 路 Arduino Uno 路 Arduino Nano 路 Arduino Mega 2560 路 Arduino Leonardo 路 SparkFun Pro Micro 路 Arduino Micro 路 ESP32-C6 路 Raspberry Pi Pico 路 Raspberry Pi Pico W 路 Seeed XIAO SAMD21 路 STM32 路 STM32 Nucleo-F411RE 路 STM32 Blue Pill 路 micro:bit V2 路 Arduino Uno R4 路 ESP32 DevKit 路 ESP32-S3-DevKitC-1 路 ESP8266 NodeMCU 路 Arduino Pro Mini 3.3 V 路 Seeed XIAO ESP32-C3 路 ESP32-C3 SuperMini 路 Seeed XIAO ESP32-C6 路 ESP32-DevKitC V4 路 LOLIN32 Lite 路 Wemos D1 R32 路 Cheap Yellow Display 路 TTGO T-Display 路 Seeed XIAO ESP32-S3 路 Arduino Nano ESP32 路 Arduino Nano RP2040 Connect 路 Seeed XIAO RP2040 路 Waveshare RP2040-Zero 路 Arduino Uno R4 WiFi
The calls you will use
In the order a sketch meets them.
AccelStepper stepper(AccelStepper::DRIVER, 3, 2)
A motor on a STEP/DIR driver: the STEP pin first, then DIR.
AccelStepper small(AccelStepper::HALF4WIRE, 8, 10, 9, 11)
A 28BYJ-48 on a ULN2003 board in half steps, 4096 to a turn, pins as IN1, IN3, IN2, IN4.
stepper.setMaxSpeed(1000)
The top speed in steps per second that run() will ramp up to. Set it before the first move.
stepper.setAcceleration(500)
How fast the speed changes, in steps per second per second. Without it the motor cannot start moving under run().
stepper.moveTo(2000)
Sets an absolute target position. move(n) does the same relative to where the motor is now.
stepper.run()
Makes one step if one is due and returns true while the motor still has somewhere to go. Call it on every pass of loop().
void loop() {
if (stepper.distanceToGo() == 0) stepper.moveTo(-stepper.currentPosition());
stepper.run();
}stepper.distanceToGo()
Steps left to the target, negative when the target is behind. Zero means the move is finished.
stepper.currentPosition()
Where the motor is, in steps from zero. setCurrentPosition(0) makes the present spot the new zero, as after homing.
stepper.setSpeed(400); stepper.runSpeed()
Constant speed with no ramp and no target, for a motor that just keeps turning.
stepper.runToPosition()
Blocks until the target is reached. Handy in setup(), but it stops everything else just like Stepper.step().
Example: Stepper turntable
On the Arduino Uno R3. It runs in the browser exactly as printed.
// Stepper turntable: a photo turntable on a 28BYJ-48 and its ULN2003 board,
// with AccelStepper. Press the button and it turns the plate a full circle in
// eight stops, pausing at each one while the LED fires the camera.
//
// ULN2003 IN1 pin 8, IN2 pin 9, IN3 pin 10, IN4 pin 11, + to 5V, - to GND
// button pin 2 to GND, INPUT_PULLUP
// LED pin 13, the camera trigger (the Uno's own LED)
//
// The pins go to AccelStepper as 8, 10, 9, 11: IN1, IN3, IN2, IN4. The library
// numbers its four pins for a motor on H bridges, and that order is what makes
// its sequence walk a ULN2003's four coils round in order. Given 8, 9, 10, 11
// the motor hums and stays where it is.
//
// HALF4WIRE is half stepping: 4096 steps to a turn of the output shaft, so a
// stop every eighth of a turn is 512 steps. The plate speeds up and slows down
// for each stop, which is what keeps a real one from sliding the object on it.
// run() makes at most one step a call, so the loop never waits while the
// plate is moving.
#include <AccelStepper.h>
const int BUTTON = 2;
const int SHUTTER = 13;
const int STOPS = 8;
const long STEPS_PER_STOP = 4096 / STOPS; // 4096 half steps to a turn
AccelStepper plate(AccelStepper::HALF4WIRE, 8, 10, 9, 11);
int stop = 0;
bool turning = false;
void setup() {
pinMode(BUTTON, INPUT_PULLUP);
pinMode(SHUTTER, OUTPUT);
plate.setMaxSpeed(800);
plate.setAcceleration(400);
Serial.begin(115200);
Serial.println("turntable: press the button to start a circle");
}
void photo() {
// One digit is all eight stops need.
Serial.print("photo ");
Serial.write('1' + stop);
Serial.println();
digitalWrite(SHUTTER, HIGH);
delay(200);
digitalWrite(SHUTTER, LOW);
delay(300);
}
void loop() {
if (!turning) {
if (digitalRead(BUTTON) == LOW) {
turning = true;
stop = 0;
plate.setCurrentPosition(0);
photo();
plate.moveTo(STEPS_PER_STOP);
}
return;
}
if (plate.distanceToGo() != 0) {
plate.run();
return;
}
stop++;
if (stop < STOPS) {
photo();
plate.moveTo((stop + 1) * STEPS_PER_STOP);
} else {
Serial.println("full circle: done");
plate.disableOutputs();
turning = false;
}
}Open it in the editor, wired and ready to run 路 Stepper turntable: the project page
Common errors and how to fix them
The motor does not move at all after moveTo()
Either run() is not being called again and again in loop(), or setMaxSpeed() and setAcceleration() were never set. Both are needed before run() will start a move; the defaults leave the motor standing.
The stepper stutters or moves much slower than setMaxSpeed()
Something in loop() is keeping run() from being called often enough: a delay(), a slow display update or a lot of Serial output. Do those every few hundred milliseconds with millis(), not every pass.
runSpeed() turns the motor but run() does not
runSpeed() uses the speed from setSpeed() and ignores the target. run() uses the target from moveTo() or move(); if the motor is already at its target, run() has nothing to do.
An A4988 motor only moves in one direction
The STEP and DIR pins are swapped in the constructor, or DIR is not wired. AccelStepper::DRIVER takes STEP first and DIR second, so AccelStepper(AccelStepper::DRIVER, stepPin, dirPin).
Questions and answers
How do I move two motors so they arrive together?
Use MultiStepper, which comes with AccelStepper: add both motors, give it an array of targets with moveTo(), and call runSpeedToPosition(). It scales the speeds so both finish at the same moment, without acceleration.
Projects that use AccelStepper
Built-in projects that include it. Each page has the full sketch and opens in the editor, already wired.
Keep going
Learn
More motion libraries
Try AccelStepper without installing anything
Open the example, change the sketch, and keep your version in a free account.