Introduction: Drive a Stepper Motor With an Arduino and a A4988 Stepstick/Pololu Driver
There are several ways to make a Stepper Motor run, and the best way will depend on the application, the motor and the electronics available. For running a stepper motor from an Arduino these are the main ways to go
1. A ULN2003 Darlington driver board. Typically sold with small geared steppers this requires four digital pins and the Arduino sketch needs to directly drive each coil
2. A driver board/shield with a constant voltage driver, such as the Adafruit Motor Shield. This runs over SPI (so only needs two pins) and can run many kinds of steppers and normal motors fine, unfortunately it couldn't run my steppers.
3. A 'chopper' driver that will vary the voltage to keep a constant current, such as the A4988 or the DRV8825 chip, either direct or via a board/shield such as the Stepstick or Pololu.
This instructable covers the third method, running one or more steppers via an A4988 IC on a StepStick board.
Step 1: A Little About Stepper Motors
There's lots of great resources out there about Stepper Motors, how they work and what kinds are available, I'd recommend
About Steppers on Adafruit Learn
Stepper motor page on RepRap wiki
I had acquired some Stepper Motors from Ebay, that didn't work well with the Adafruit Motor Shield. Looking at the specs the problem here was the resistance/current/voltage rating;
Rated Current/phase2.0A
Phase Resistance1.4ohms
Voltage2.8V
So, for Stepper motors, the resistance per phase is a constant. The Rated current is the MAXIMUM current the motor will take before bad things happen, and the voltage is the calculated voltage that will give a constant current at the rated current, for the motors resistance (V = I x R, V = 2.0A x 1.4Ohm = 2.8V).
The Adafruit stepper motor shield cant supply 2A,and has trouble with voltages below about 5V, so couldn't properly run my motors (they jittered but didn't smoothly move).
So, I got some stepsticks and decided to wire them up to my Arduino.
Other Materials
For this I also used;
An Arduino Uno, but any Arduino compatible should do
A Stepstick, or compatible stepper driver using a A4988 or DRV8825
A 12V power supply
A breadboard
Some hookup wire, I used solid Cat5 strands.
I also used a couple of LEDs and some 220Ohm resistors
Step 2: Wiring Up the StepStick and Arduino
The stepstick is an A4988 chip mounted on a small PCB with headers on either side. It's available in many places (Pololu). To use it it needs the following connections
- 4 connections to the stepper motor, marked 1A, 1B and 2A, 2B. Connect the first coil to 1A and 1B and the second coil to 2A and 2B.
- Logic Power and GND, Connect this to the GND and +5V of the Arduino
- Dir sets the direction the stepper will move. I connected this to Pin 4 on the Arduino
- Step will make the stepper step each time this pin goes form Low to High. I connected this to Pin 5 on the Arduino
- Enable. When this pin is pulled low the board is enabled and the motor energised. When set high the board is disabled and the motor is de-energised. I connected this to Pin 6 on the Arduino
- Sleep and Reset control the board, either sending it to sleep or resetting it. To use the board I tied these together which allows the board to run normally
- Motor Power and GND. This needs to be a high voltage/current supply to run the motor. I had a 12V, 2A wall Swart available. Do not connect this yet
See the fritzing diagram above. Next is loading an Arduino sketch and Setting the Current limit on the StepStick
Step 3: Initial Arduino Sketch
Here is the initial sketch I loaded to my Arduino
// Run a A4998 Stepstick from an Arduino UNO. // Paul Hurley Aug 2015 int x; #define BAUD (9600) void setup() { Serial.begin(BAUD); pinMode(6,OUTPUT); // Enable pinMode(5,OUTPUT); // Step pinMode(4,OUTPUT); // Dir digitalWrite(6,LOW); // Set Enable low } void loop() { digitalWrite(6,LOW); // Set Enable low digitalWrite(4,HIGH); // Set Dir high Serial.println("Loop 200 steps (1 rev)"); for(x = 0; x < 200; x++) // Loop 200 times { digitalWrite(5,HIGH); // Output high delay(10); // Wait digitalWrite(5,LOW); // Output low delay(100); // Wait } Serial.println("Pause"); delay(1000); // pause one second }
Load that into the Arduino Editor, Verify/Compile it, upload it to your Arduino. Remember, at this point the Arduino should be powered, but the Motor Power should be disconnected.
Step 4: Set the Maximum Current
To prevent damage to the driver chip, it uses circuitry to limit the maximum current that can be used. This is set via the adjustable resistor on the board, in co-operation with some of the other components, the sense resistors (S1 and S2) and the resistor (R1). As different drivers may have different components (especially generic Chinese imports) its best to check these values before continuing.
For my stepsticks S1 and S2 are marked 'R10' and R1 is marked '303' (in very small writing !). These correspond to 0.1Ohm for S1 and S2 and 30kOhm for R1. The trimpot should be 10kOhm
According to the A4998 datasheet, and substituting those values, gives
VREF max = (TrimpotMaxR/(TrimpotMaXR+R1)) x VDD = (10,000 / (10,000 + 30,000)) * 5 = 1.25V
ITripMAX (effectively max motor current) = VREF / ( 8 x Sense_resistor) = 1.25 / ( 8 * 0.1 ) = 1.5625A
To calculate amps from measured VREF: A = VREF / 0.8
To calculate VREF required for a target current: VREF = A * 0.8
As my stepper motors are 2.0A, I can't get maximum current from this driver, however,if I drive them at 70% (2.0A x 70% = 1.4A) I want to a VREF of 1.4A x 0.8 = 1.12V, plus driving them at 70% will reduce the temperature of the stepper.
I start with the trim pot turned anti-clockwise, and measure the voltage with my multimeter between the logic Gnd pin and the centre of the trimpot itself, slowly turning it up until I get just under 1.12V
Once that is done, you can connect the Motor power supply (12V). Hopefully your motor will start running !
If not, unplug the Motor power and recheck all the connections with a multimeter. Always unplug the motor power first, then the Arduino power before disconnecting the motor
Warning: Connecting or disconnecting a stepper motor
while the driver is powered can destroy the driver. (More generally, rewiring anything while it is powered is asking for trouble.)
Step 5: A More Complicated Program
Once you have this working, there’s several things you can do to expand.
Add another stepper (or more). Each driver needs at least two pins (step and dir) and possibly Enable. Use the same logic voltage, ground and motor voltage
Use the AccelStepper library to do fancier control of the stepper. Here's a sketch the randomly moves the stepper at random speeds and accelerations
// Run a A4998 Stepstick from an Arduino UNOusing AccelStepper // Paul Hurley Aug 2015 #include AccelStepper stepper(1,5,4);//initialise accelstepper for a two wire board, pin 5 step, pin 4 dir void setup() { Serial.begin(9600); pinMode(6,OUTPUT); // Enable digitalWrite(6,LOW); // Set Enable low } void loop() { digitalWrite(6,LOW); // Set Enable low if (stepper.distanceToGo() == 0) { // Random change to speed, position and acceleration // Make sure we dont get 0 speed or accelerations delay(1000); stepper.moveTo(rand() % 400); stepper.setMaxSpeed((rand() % 400) + 200); stepper.setAcceleration((rand() % 200) + 100); } Serial.println(stepper.distanceToGo()); stepper.run(); // Actually makes stepper move }
19 Comments
4 years ago
This is an interesting article. But it looks like you have errors in the pictures with the lines from the driver to the engines. The pins of the stepper motor windings are mirrored on the board:
2B corresponds to B +
2A corresponds to B-
1A corresponds to A-
1B corresponds to A +
So from top to bottom there should be wires of the following colors:
Red
Black
Black
Red
Question 5 years ago on Step 2
this was the complee code , sorry about the previous one
int delaylaser = 4;
int delay_motor = 6;
int LaserState = LOW;
int LaserPin = 7;
int threshold=220; // Threshold for the light readings
int sensor=0;
int note5 = 0x37;
int note4 = 0x34;
int note3 = 0x32;
int note2 = 0x30;
int note1 = 0x2F;
int state=1; // Motor status
int a = 0, b = 0, c = 0, d = 0, e = 0; // Note status
void forward()
{
switch(state){
case 1:
digitalWrite(2, HIGH);
digitalWrite(3, HIGH);
digitalWrite(4, LOW);
digitalWrite(5, LOW);
delay(delay_motor);
state=2;
break;
case 2:
digitalWrite(2, LOW);
digitalWrite(3, HIGH);
digitalWrite(4, HIGH);
digitalWrite(5, LOW);
delay(delay_motor);
state=3;
break;
case 3:
digitalWrite(2, LOW);
digitalWrite(3, LOW);
digitalWrite(4, HIGH);
digitalWrite(5, HIGH);
delay(delay_motor);
state=4;
break;
case 4:
digitalWrite(2, HIGH);
digitalWrite(3, LOW);
digitalWrite(4, LOW);
digitalWrite(5, HIGH);
delay(delay_motor);
state=1;
break;
}
}
void backward()
{
switch(state){
case 3:
digitalWrite(2, HIGH);
digitalWrite(3, HIGH);
digitalWrite(4, LOW);
digitalWrite(5, LOW);
delay(delay_motor);
state=2;
break;
case 4:
digitalWrite(2, LOW);
digitalWrite(3, HIGH);
digitalWrite(4, HIGH);
digitalWrite(5, LOW);
delay(delay_motor);
state=3;
break;
case 1:
digitalWrite(2, LOW);
digitalWrite(3, LOW);
digitalWrite(4, HIGH);
digitalWrite(5, HIGH);
delay(delay_motor);
state=4;
break;
case 2:
digitalWrite(2, HIGH);
digitalWrite(3, LOW);
digitalWrite(4, LOW);
digitalWrite(5, HIGH);
delay(delay_motor);
state=1;
break;
}
}
void setup()
{
Serial.begin(9600);
pinMode(2, OUTPUT); // Motor pins
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(LaserPin, OUTPUT); // Laser pin
pinMode(13, OUTPUT); // Status led.
// Position calibration
digitalWrite(LaserPin, HIGH);
// The motor goes forward until the sensor receives light
// In that moment, the mirror will be perpendicular to the beam
while(sensor<threshold)
{
forward();
sensor=analogRead(0);
}
// Once calibrated, the motor goes backward to its initial position
int i;
for(i = 0; i < 8; i++) {
backward();
}
}
void noteOn(int cmd, int pitch, int velocity) // Function to play the notes
{
Serial.write(cmd);
Serial.write(pitch);
Serial.write(velocity);
}
void loop()
{
digitalWrite(LaserPin, HIGH);
delay(delaylaser);
if(analogRead(0) > threshold) // If the sensor gets a signal
{
if(b+c+d+e == 0) { // If there are not any notes playing
if(a == 0) { // If this note is not being played
digitalWrite(13, HIGH); // Switch on status led
noteOn(0x90, note1, 0x7F); // Play note 1
}
a = 1;
}
}
else if(analogRead(0) < threshold) // If the sensor does not get a signal:
{
if(a >= 1) { // If this note is being played
if(++a == 3) { // If we have not had any readings for 3 cycles
digitalWrite(13, LOW); // Switch off the status led.
noteOn(0x90, note1, 0x00); // Stop playing note 1.
a = 0;
}
}
}
digitalWrite(LaserPin, LOW);
forward();
// The next steps are similar to the previous one. Each one of them corresponds
// to a different note
digitalWrite(LaserPin, HIGH);
delay(delaylaser);
if(analogRead(0) > threshold)
{
if(a+c+d+e == 0) {
if(b == 0) {
digitalWrite(13, HIGH);
noteOn(0x90, note2, 0x7F);
}
b = 1;
}
}
else if(analogRead(0) < threshold)
{
if(b >= 1) {
if(++b == 3) {
digitalWrite(13, LOW);
noteOn(0x90, note2, 0x00);
b = 0;
}
}
}
digitalWrite(LaserPin, LOW);
forward();
digitalWrite(LaserPin, HIGH);
delay(delaylaser);
if(analogRead(0) > threshold)
{
if(a+b+d+e == 0) {
if(c == 0) {
digitalWrite(13, HIGH);
noteOn(0x90, note3, 0x7F);
}
c = 1;
}
}
else if(analogRead(0) < threshold)
{
if(c >= 1) {
if(++c == 3) {
digitalWrite(13, LOW);
noteOn(0x90, note3, 0x00);
c = 0;
}
}
}
digitalWrite(LaserPin, LOW);
forward();
digitalWrite(LaserPin, HIGH);
delay(delaylaser);
if(analogRead(0) > threshold)
{
if(a+b+c+e == 0) {
if(d == 0) {
digitalWrite(13, HIGH);
noteOn(0x90, note4, 0x7F);
}
d = 1;
}
}
else if(analogRead(0) < threshold)
{
if(d >= 1) {
if(++d == 3) {
digitalWrite(13, LOW);
noteOn(0x90, note4, 0x00);
d = 0;
}
}
}
digitalWrite(LaserPin, LOW);
forward();
digitalWrite(LaserPin, HIGH);
delay(delaylaser);
if(analogRead(0) > threshold)
{
if(a+b+c+d == 0) {
if(e == 0) {
digitalWrite(13, HIGH);
noteOn(0x90, note5, 0x7F);
}
e = 1;
}
}
else if(analogRead(0) < threshold)
{
if(e >= 1) {
if(++e == 3) {
digitalWrite(13, LOW);
noteOn(0x90, note5, 0x00);
e = 0;
}
}
}
digitalWrite(LaserPin, LOW);
// Once it reaches the last note, the motor moves backwards
// until it reaches the first note again
backward();
digitalWrite(LaserPin, HIGH);
delay(delaylaser);
if(analogRead(0) > threshold)
{
if(a+b+c+e == 0) {
if(d == 0) {
digitalWrite(13, HIGH);
noteOn(0x90, note4, 0x7F);
}
d = 1;
}
}
else if(analogRead(0) < threshold)
{
if(d >= 1) {
if(++d == 3) {
digitalWrite(13, LOW);
noteOn(0x90, note4, 0x00);
d = 0;
}
}
}
digitalWrite(LaserPin, LOW);
backward();
digitalWrite(LaserPin, HIGH);
delay(delaylaser);
if(analogRead(0) > threshold)
{
if(a+b+d+e == 0) {
if(c == 0) {
digitalWrite(13, HIGH);
noteOn(0x90, note3, 0x7F);
}
c = 1;
}
}
else if(analogRead(0) < threshold)
{
if(c >= 1) {
if(++c == 3) {
digitalWrite(13, LOW);
noteOn(0x90, note3, 0x00);
c = 0;
}
}
}
digitalWrite(LaserPin, LOW);
backward();
digitalWrite(LaserPin, HIGH);
delay(delaylaser);
if(analogRead(0) > threshold)
{
if(a+c+d+e == 0) {
if(b == 0) {
digitalWrite(13, HIGH);
noteOn(0x90, note2, 0x7F);
}
b = 1;
}
}
else if(analogRead(0) < threshold)
{
if(b >= 1) {
if(++b == 3) {
digitalWrite(13, LOW);
noteOn(0x90, note2, 0x00);
b = 0;
}
}
}
digitalWrite(LaserPin, LOW);
backward();
}
Question 5 years ago on Step 3
Hello ! I was wondering if you could help me modify this code in order for it to work with a A4988 driver , its a frameless laser harp , cant wait to finish it ! Thanks in advance
{
if(a+c+d+e == 0) {
if(b == 0) {
digitalWrite(13, HIGH);
noteOn(0x90, note2, 0x7F);
}
b = 1;
}
}
else if(analogRead(0) < threshold)
{
if(b >= 1) {
if(++b == 3) {
digitalWrite(13, LOW);
noteOn(0x90, note2, 0x00);
b = 0;
}
}
}
5 years ago
hallo...
I am a newbie...
I want to know,
Is the dir & step is same thing as dir & pull in TB6600 driver?
thank you
5 years ago
Thanks for the instructable.
You say "The trimpot should be 10kOhm", but I don't understand how you determined that.
How do I determine what my trimpot is? I've attached a pic of my A4988 in case that helps.
Reply 5 years ago
Here's said pot' current adjuster screw...for what I know.
What are you making?
7 years ago
Hey, thanks for the tutorial. However, I think I fried my arduino uno attempting this. Would someone be able to tell my why it fried? Basically I connected everything except the motor power supply and then I plugged a 12V power supply into the arduino, and then it fried. I posted the question here
http://electronics.stackexchange.com/questions/209...
with more detail. Of course, feel free to respond in the comments of this instructable if you want.
Reply 6 years ago
it fired because the arduino can only take 5v, the 12v was to be used for the stepper motors only!
Reply 7 years ago
NOTE: I did not have reset wired to sleep, however.
6 years ago
PS would it not make sense to have your primary image showing what you are using rather than an apparently random pick of one of the many combos of motor/driver you aren't using?
6 years ago
Thanks for a concise summary.
You didn't mention that it is entirely possible to run motors at much higher voltage/ current combos it it's not continuous, eg if you switch off between steps using the enable pin (which you accidently left off your fritzing diagram - you mentioned connecting pin 6 in the text).
Also the higher the voltage the faster/ more accurate the step and generally I found it a good idea to use the highest possible voltage and correspondingly decrease the current to avoid burning out the motor. Thus it should have been entirely possible to use your adafruit driver with your stated specs.
Finally I've never calculated current and measured voltage at the stepstick, always just turned the pot down low then manually adjusted the current up to get reliable function.
Also microstepping seems to help the motor run quieter/cooler (but I don't know why)
7 years ago
Paul,
You mention that for a second stepper the same Pins/logic voltage is to be applied, but I'm not sure how to implement in the code. I've read elsewhere that steppers cannot execute steps simultaneously and they must step one at a time. I'm running a second A4988, that is wired according to your diagram, but, how might I run step exclusive to one stepper or another.
Please let me know. Thanks for the tut.
7 years ago
Hi
How to stop the stepper .. I want to move it 200 steps then stop it
7 years ago
if i connect an unipolar motor to the driver with the common pin connect to the power supply gnd will it work
7 years ago
Can I get away with using a 2.8amp 2.5 volt motor or will this overload the stepstick?
Reply 7 years ago
AFAIK The stepstick will supply as much current as it is able, until it gets too hot and shuts down, so depending on which driver is on the stepstick means a limit of around 2A (A4988) or 2.2A (DRV8825) with sufficient cooling. Your 2.8A motors would run with this current, but not at their rated strength/speed.
7 years ago on Introduction
2 Amp 1.4 Ohms per coil are actually really good stepper motors. They would maintain torque at higher RPM. It is the drivers you're using that are weak.
7 years ago on Introduction
well explained
7 years ago on Introduction
Great info, thank you.