Skip to main content

Two drivers, one controller

What this example shows​

Two stepper motors running from one controller, each with its own DRV8825 board. Both motors move to a target position, and when they arrive they reverse to mirror it, so they travel back and forth indefinitely. Acceleration is handled for you: the motors ramp up and slow down into each target rather than starting and stopping abruptly.

You need two of these boards, one per motor, and four controller pins.

Despite its file name, DualMotorShield.ino does not use a motor shield. It builds two BasicStepper instances on the DRIVER interface, which is exactly how this board is driven.

The example code​

The four pin numbers are the NULA DeepSleep ESP32-S3 assignment. The shipped sketch uses 2, 3, 6 and 7, which is Arduino Uno numbering; the rest is unchanged.

Select Board
DualMotorShield.ino
#include "Basic-Stepper-Driver-SOLDERED.h"

// The X Stepper pins
#define STEPPER1_DIR_PIN 4
#define STEPPER1_STEP_PIN 5
// The Y stepper pins
#define STEPPER2_DIR_PIN 6
#define STEPPER2_STEP_PIN 7

// Define some steppers and the pins the will use
BasicStepper stepper1(BasicStepper::DRIVER, STEPPER1_STEP_PIN, STEPPER1_DIR_PIN);
BasicStepper stepper2(BasicStepper::DRIVER, STEPPER2_STEP_PIN, STEPPER2_DIR_PIN);

void setup()
{
stepper1.setMaxSpeed(200.0);
stepper1.setAcceleration(200.0);
stepper1.moveTo(100);

stepper2.setMaxSpeed(100.0);
stepper2.setAcceleration(100.0);
stepper2.moveTo(100);
}

void loop()
{
// Change direction at the limits
if (stepper1.distanceToGo() == 0)
stepper1.moveTo(-stepper1.currentPosition());
if (stepper2.distanceToGo() == 0)
stepper2.moveTo(-stepper2.currentPosition());
stepper1.run();
stepper2.run();
}

Expected result:

Both motors step to position 100, then reverse to -100, then back again, continuing indefinitely. Each move accelerates away and decelerates in. The first motor runs at up to 200 steps per second and the second at up to 100, so it visibly takes about twice as long to cover the same distance and the two drift out of step with each other.

There is no serial output.

Functions used​

BasicStepper(uint8_t interface, uint8_t pin1, uint8_t pin2)returns None

Constructs a stepper on the given interface. Pass BasicStepper::DRIVER for this board, then the STEP pin and the DIR pin, in that order. Inherited from AccelStepper, which also accepts two further pins and an enable flag for the direct-drive interfaces.

ReturnsConstructor; no return value.

Parameters

TypeNameDescription
uint8_tinterfaceMotor interface type. BasicStepper::DRIVER (1) for a step/dir driver. Defaults to FULL4WIRE (4).
uint8_tpin1With DRIVER, the STEP pin. Defaults to 2.
uint8_tpin2With DRIVER, the DIR pin. Defaults to 3.
setMaxSpeed(float speed)returns void

Sets the highest speed the motor is allowed to reach. Acceleration ramps up to this value and no further.

ReturnsNothing.

Parameters

TypeNameDescription
floatspeedMaximum speed in steps per second.
setAcceleration(float acceleration)returns void

Sets how quickly the motor changes speed, used for both accelerating and decelerating. This is what makes the motor ease into a target position instead of stopping dead.

ReturnsNothing.

Parameters

TypeNameDescription
floataccelerationAcceleration in steps per second squared.
moveTo(long absolute)returns void

Sets an absolute target position in steps. It does not move the motor by itself; run() does the stepping. Calling it with the negative of the current position, as this example does, sends the motor back the way it came.

ReturnsNothing.

Parameters

TypeNameDescription
longabsoluteTarget position in steps, relative to where the motor started.
distanceToGo()returns long

How many steps remain before the target position is reached. Zero means the motor has arrived, which is how this example knows when to reverse.

ReturnsSteps still to go. Negative when the target is behind the current position.

Parameters

This function takes no parameters.

currentPosition()returns long

The motor's position in steps, counted from where it started.

ReturnsCurrent position in steps.

Parameters

This function takes no parameters.

run()returns boolean

Steps the motor at most once, applying the acceleration curve. It has to be called repeatedly for the motor to keep moving, which is why it sits in loop() with nothing blocking around it.

ReturnsTrue while the motor is still travelling to its target.

Parameters

This function takes no parameters.

Putting it together​

The pattern is the same for one motor or several. Configure speed and acceleration once in setup(), set a target, then call run() on every pass through loop(). Because run() steps at most once per call, anything that blocks, a delay() or a slow sensor read, stalls the motor. Keep loop() fast and let distanceToGo() tell you when a move has finished.

Both drivers need their own board, their own motor supply connection and their own current limit set at the trimmer. They can share the controller's ground.