Two hands on an Arduino Uno
A biaxial stepper as a clock: two A4988s step its outer and inner hands, a minute every second, counting the fractional steps they owe. The whole build, an Arduino Uno and 3 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.
Teaching? Assign it to your class in one click.
Intermediate About 30 minutes to build and run. Runs in your browser. Free, and no account needed.
The parts retail for about $35. On Mokxi they're free.
What you'll learn
- Driving steppers with STEP and DIR pins
- Full-step motion and steps per turn
- Gear ratio between minute and hour hands
- Keeping a running step count to avoid drift
- Powering motors separately from the Uno
- Difficulty: Intermediate
- Time: About 30 minutes
- Board: Arduino Uno R3
- Parts: 8
How it works
A biaxial stepper has two motors on one axis, like the movement of a clock. Two A4988 drivers move them: pins 3 and 4 for the outer hand, the minutes, and pins 5 and 6 for the inner hand, the hours.
Each pulse on a STEP pin moves a hand one full step, and 200 steps make one turn. The minute hand needs 200 steps per hour and the hour hand 200 steps per 12 hours. Neither is a whole number of steps per minute.
So the sketch keeps a running total of steps owed to each hand and pulses until it has paid them. A simulated minute passes every second, and the time is printed.
Parts list
8 parts, plus the jumper wires. They retail for about $35; on Mokxi they're free.
- 1 × Arduino Uno R3In Starter Kit, Claw Machine Kit, Vending Machine Kit.
- 2 × Stepper driver, A4988In Claw Machine Kit.
- 1 × Biaxial stepper
- 2 × Power, 12 V
- 2 × Power
Wiring table
Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.
| Part and pin | Connects to |
|---|---|
| Arduino Uno R3 pin GND | Ground |
| Stepper driver, A4988 (2) pin DIR | Arduino Uno R3 pin 6 |
| Stepper driver, A4988 (2) pin STEP | Arduino Uno R3 pin 5 |
| Stepper driver, A4988 (1) pin DIR | Arduino Uno R3 pin 4 |
| Stepper driver, A4988 (1) pin STEP | Arduino Uno R3 pin 3 |
| Stepper driver, A4988 (1) pin MS1 | Ground |
| Stepper driver, A4988 (1) pin MS2 | Ground |
| Stepper driver, A4988 (1) pin MS3 | Ground |
| Stepper driver, A4988 (1) pin SLP | Stepper driver, A4988 (1) pin RST |
| Stepper driver, A4988 (1) pin VMOT | 12 V |
| Biaxial stepper pin A1+ | Stepper driver, A4988 (1) pin 2B |
| Biaxial stepper pin A1- | Stepper driver, A4988 (1) pin 2A |
| Biaxial stepper pin B1+ | Stepper driver, A4988 (1) pin 1A |
| Biaxial stepper pin B1- | Stepper driver, A4988 (1) pin 1B |
| Stepper driver, A4988 (1) pin VDD | Supply |
| Stepper driver, A4988 (1) pin GND | Ground |
| Stepper driver, A4988 (2) pin MS1 | Ground |
| Stepper driver, A4988 (2) pin MS2 | Ground |
| Stepper driver, A4988 (2) pin MS3 | Ground |
| Stepper driver, A4988 (2) pin SLP | Stepper driver, A4988 (2) pin RST |
| Stepper driver, A4988 (2) pin VMOT | 12 V |
| Biaxial stepper pin A2+ | Stepper driver, A4988 (2) pin 2B |
| Biaxial stepper pin A2- | Stepper driver, A4988 (2) pin 2A |
| Biaxial stepper pin B2+ | Stepper driver, A4988 (2) pin 1A |
| Biaxial stepper pin B2- | Stepper driver, A4988 (2) pin 1B |
| Stepper driver, A4988 (2) pin VDD | Supply |
| Stepper driver, A4988 (2) pin GND | Ground |
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// Two hands: a biaxial stepper is a clock face's movement, two motors on
// one axis, driven here through two A4988s in full step, a minute every
// second so it can be watched.
//
// pin 3 outer hand's STEP pin 4 its DIR (the minutes)
// pin 5 inner hand's STEP pin 6 its DIR (the hours)
// both drivers: VMOT on 12 V, VDD on 5 V, RST linked to SLP, the mode pins
// left low (full step), the grounds to the Uno's
//
// 200 full steps turn a hand once. The minute hand goes round in 60 minutes
// and the hour hand in 12 hours, so after m minutes they should have taken
// m x 200 / 60 and m x 200 / 720 steps. Neither is a whole number per
// minute, so the sketch keeps the count it owes each hand and steps until
// it has paid it, the way a Bresenham line keeps its error.
const int STEP_OUTER = 3;
const int DIR_OUTER = 4;
const int STEP_INNER = 5;
const int DIR_INNER = 6;
long minutes = 0;
long outerSteps = 0;
long innerSteps = 0;
void pulse(int pin) {
digitalWrite(pin, HIGH);
delayMicroseconds(5);
digitalWrite(pin, LOW);
delay(3);
}
void setup() {
Serial.begin(9600);
pinMode(STEP_OUTER, OUTPUT);
pinMode(DIR_OUTER, OUTPUT);
pinMode(STEP_INNER, OUTPUT);
pinMode(DIR_INNER, OUTPUT);
digitalWrite(DIR_OUTER, HIGH);
digitalWrite(DIR_INNER, HIGH);
Serial.println("Two hands: a minute a second");
}
void loop() {
minutes++;
while (outerSteps < minutes * 200 / 60) {
pulse(STEP_OUTER);
outerSteps++;
}
while (innerSteps < minutes * 200 / 720) {
pulse(STEP_INNER);
innerSteps++;
}
Serial.print(minutes / 60 % 12);
Serial.print(":");
if (minutes % 60 < 10) Serial.print("0");
Serial.println(minutes % 60);
delay(1000);
}
Code walkthrough
The key functions of the sketch, and what each one does.
pulse sketch.ino
Makes one step. It sets the STEP pin HIGH for 5 microseconds, then LOW, then waits 3 ms, so the motor has time to move before the next step.
void pulse(int pin) {
digitalWrite(pin, HIGH);
delayMicroseconds(5);
digitalWrite(pin, LOW);
delay(3);
}setup sketch.ino
Opens serial, sets all four driver pins as outputs and sets both DIR pins HIGH so both hands turn the same way.
void setup() {
Serial.begin(9600);
pinMode(STEP_OUTER, OUTPUT);
pinMode(DIR_OUTER, OUTPUT);
pinMode(STEP_INNER, OUTPUT);
pinMode(DIR_INNER, OUTPUT);
digitalWrite(DIR_OUTER, HIGH);
digitalWrite(DIR_INNER, HIGH);
Serial.println("Two hands: a minute a second");
}loop sketch.ino
Adds one to minutes. While outerSteps is below minutes x 200 / 60, it pulses the outer hand. The same happens for the inner hand with minutes x 200 / 720. Then it prints the time as hours and minutes and waits one second.
void loop() {
minutes++;
while (outerSteps < minutes * 200 / 60) {
pulse(STEP_OUTER);
outerSteps++;
}
while (innerSteps < minutes * 200 / 720) {
pulse(STEP_INNER);
innerSteps++;
}
Serial.print(minutes / 60 % 12);
Serial.print(":");
if (minutes % 60 < 10) Serial.print("0");
Serial.println(minutes % 60);
delay(1000);
}Troubleshooting
The usual mistakes with this circuit, and the fix for each.
- The motors do not move This project
Each driver needs motor power on VMOT, logic power on VDD, and RST joined to SLP. Join all grounds with the Uno's ground. - The hands turn the wrong way This project
Change the DIR pin level for that hand insetupfrom HIGH to LOW. - The motor does nothing and the driver stays dead. Stepper driver
Tie RST to SLP with a jumper, or drive both HIGH. Those two pins float on many boards. Also connect the logic VDD to 5 V and ground, and the motor VMOT to its own supply. - The driver or the chip dies when you power up. Stepper driver
Put a 100 uF capacitor across VMOT and GND, close to the driver. Never connect or unplug the motor while powered, because the voltage spike can kill the chip. - The motor shakes or hums but does not turn. Biaxial stepper
Coil wires are mixed up. Find the two pairs with a meter (each pair has low resistance) and connect one pair to each coil output of the driver. - The motor does not run from an Arduino pin. Biaxial stepper
Pins cannot supply coil current. Use a driver such as a ULN2003A board, A4988 or similar, with a motor supply, and share ground. Each motor needs its own driver. - Upload fails or nothing runs after wiring pins 0 and 1 to a module. Arduino Uno R3
Pins 0 and 1 are the USB serial port. Move the module to other pins, or unplug it while uploading. Also check the right board is selected. - Pins misbehave or the board resets when you power motors or servos from it. Arduino Uno R3
Each I/O pin gives about 20 mA, 40 mA max. Power motors and servos from their own supply and join its ground to the Uno's GND.
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.