An Arduino library to spin stepper motors in continuous motions.
Contrary to other stepper libraries, this one doesn't provide any function to move the shaft at a specific angle. Instead, it provides one function to spin the shaft at a specific speed. It smoothly accelerates and decelerates when the speed changes.
- Supports multiple stepper types:
- stepper drivers with step and dir pins (and optionally enable pin)
- four-wire stepper motors
- Optionally runs with TimerOne, TimerThree or TeensyTimerTool
- Optionally uses
tone()
instead ofdigitalWrite()
for the step pin - Optionally uses PWM with
analogWriteFrequency()
on Teensy 3 and 4 - Optionally uses Khoi Hoang's PWM libraries (RP2040_PWM, SAMD_PWM, AVR_PWM, STM32_PWM, Teensy_PWM...)
- Accelerates and decelerates smoothly
- Negative speed rotates backward
- Uses neither
delay()
nordelayMicroseconds()
- Tape recorders
- Conveyors
- Wheels
#include <ContinuousStepper.h>
ContinuousStepper<StepperDriver> stepper;
void setup() {
stepper.begin(stepPin, dirPin)
stepper.spin(200); // rotate at 200 steps per seconds
}
void loop() {
stepper.loop(); // this function must be called as frequently as possible
}
#include <ContinuousStepper.h>
ContinuousStepper<FourWireStepper> stepper;
void setup() {
stepper.begin(pin1, pin2, pin3, pin4);
stepper.spin(200); // rotate at 200 steps per seconds
}
void loop() {
stepper.loop(); // this function must be called as frequently as possible
}
In the basic example above, the level of the step pin is changed with digitalWrite()
. We can offload this task to the tone()
function, which uses a timer to generate a square wave.
#include <ContinuousStepper.h>
#include <ContinuousStepper/Tickers/Tone.hpp>
ContinuousStepper<StepperDriver, ToneTicker> stepper;
void setup() {
stepper.begin(stepPin, dirPin);
stepper.spin(200);
}
void loop() {
stepper.loop();
}
Of course, this only work for StepperDriver
, don't try to use it with FourWireStepper
. The same remark applies to AwfTicker
and KhoiTicker
.
Alternatively, you can install the TimerOne to have the loop()
function called in the timer interrupt handler:
#include <ContinuousStepper.h>
#include <ContinuousStepper/Tickers/TimerOne.hpp>
ContinuousStepper<FourWireStepper, TimerOneTicker> stepper;
void setup() {
stepper.begin(pin1, pin2, pin3, pin4);
stepper.spin(200);
}
void loop() {
// no need to call stepper.loop()
}
You can do this for either StepperDriver
or FourWireStepper
.
CAUTION: this example only proved to work correctly on Teensy 3.1.
Here is the general overview of the ContinuousStepper
class:
template <class TStepper, class TTicker = LoopTicker>
class ContinuousStepper {
public:
// Initialize the class and attaches to the specified pins.
void begin(/* depends, see below */);
// Updates the status of the step and dir pins.
// You must call this function as frequently as possible.
void loop();
// Turn the power on and restores the current speed.
// See StepperDriver and FourWireStepper below for details.
void powerOn();
// Turn the power off.
// See StepperDriver and FourWireStepper below for details.
void powerOff();
// Tells whether the power is on.
bool isPowered() const;
// Sets the target speed.
// The shaft will smoothly accelerate or decelerate to reach the
// target speed.
void spin(float_t speed);
// Sets the target speed to 0.
// The shaft will smoothly decelerate.
// Call isSpinning() to know when the motion is complete.
void stop();
// Gets the acceleration in steps/s².
float_t acceleration() const;
// Returns the current speed.
// During accelerations and decelerations, this value differs from the
// target speed configured with spin().
float_t speed() const;
// Sets the acceleration in steps/s².
void setAcceleration(float_t acceleration);
// Tells whether the shaft is currently spinning.
bool isSpinning() const;
};
In addition, ContinuousStepper
inherits some functions the TStepper
class:
class StepperDriver {
// Configures the stepper with the specified pins.
void begin(uint8_t stepPin, uint8_t dirPin);
// Configures the "enable" pin.
// You can pass LOW as the second argument to invert the logic.
// The pin is set to its active level unless powerOff() was called.
void setEnablePin(uint8_t pin, bool activeLevel = HIGH);
// Sets the enable pin's level to its active level and restores the current speed.
void powerOn();
// Sets the enable pin's level to its inactive level.
void powerOff();
}
class FourWireStepper {
// Configures the stepper with the specified pins.
void begin(uint8_t pin1, uint8_t pin2, uint8_t pin3, uint8_t pin4);
// Restore current in the coils and restores the current speed.
void powerOn();
// Set the four pins to LOW, hereby stopping all current in the coils.
void powerOff();
}
AccelStepper is an excellent library when you want to move a stepper motor shaft at a specific angle (for example, in a 3D printer), but it doesn't support applications that need continuous rotations.
AccelStepper provides a runSpeed()
function for continuous motion, but it doesn't accelerate smoothly.
You could repeatedly call move()
, but after a while, the 32-bit integer that stores the target position will overflow, causing the motor to reverse its rotation.
Moreover, even if you can control the speed with setMaxSpeed()
, you'll see that it accelerates smoothly but decelerates abruptly.
AccelStepper | ContinuousStepper |
---|---|
disableOutputs() |
powerOff() |
enableOutputs() |
powerOn() |
isRunning() |
isSpinning() |
move() |
spin() |
moveTo() |
spin() |
run() |
loop() |
setAcceleration() |
setAcceleration() |
setEnablePin() |
setEnablePin() |
setMaxSpeed() |
spin() |
setMinPulseWidth() |
Automatic |
stop() |
stop() |