Relays reverse a motor on an Arduino Uno
Two motors turned both ways by relays: one on a two-channel board wired as an H bridge, one on a bare DPDT relay switched by a transistor. The whole build, an Arduino Uno and 7 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 35 minutes to build and run. Runs in your browser. Free, and no account needed.
The parts retail for about $36. On Mokxi they're free.
What you'll learn
- Reversing a motor with relays
- H bridge from two relays
- Active-low relay boards
- Switching a relay coil with a transistor
- Why a diode goes across a coil
- Difficulty: Intermediate
- Time: About 35 minutes
- Board: Arduino Uno R3
- Parts: 11
How it works
A motor turns the other way when its two wires swap places. Here relays do the swapping. Motor A sits between the COM pins of two relay channels, each wired between 5 V and ground. Pin 6 turns it one way, pin 7 the other. This makes an H bridge.
Motor B uses a single DPDT relay, whose two switches move together. A transistor on pin 8 drives its coil, with a diode to absorb the kick. The sketch runs both motors forward, brakes, reverses, and brakes again, with lamp pins chasing between.
Parts list
11 parts, plus the jumper wires. They retail for about $36; on Mokxi they're free.
- 1 × Arduino Uno R3In Starter Kit, Claw Machine Kit, Vending Machine Kit.
- 1 × Half breadboard
- 1 × Resistor, 1k ΩIn Starter Kit, Claw Machine Kit, Halloween Prop Kit.
- 1 × Transistor (NPN or PNP)In LED Cube Kit.
- 1 × DiodeIn Pinball Table Kit.
- 1 × DPDT relay
- 2 × DC motorIn Robot Car Kit.
- 1 × Relay board, two channels
- 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 |
|---|---|
| Transistor (NPN or PNP) pin E | Arduino Uno R3 pin GND |
| DPDT relay pin NO1 | Arduino Uno R3 pin GND |
| DPDT relay pin NC2 | Arduino Uno R3 pin GND |
| Relay board, two channels pin NC1 | Arduino Uno R3 pin GND |
| Relay board, two channels pin NC2 | Arduino Uno R3 pin GND |
| Resistor, 1k Ω pin 1 | Arduino Uno R3 pin 8 |
| Relay board, two channels pin IN2 | Arduino Uno R3 pin 7 |
| Relay board, two channels pin IN1 | Arduino Uno R3 pin 6 |
| Transistor (NPN or PNP) pin B | Resistor, 1k Ω pin 2 |
| Diode pin A | Transistor (NPN or PNP) pin C |
| DPDT relay pin COIL2 | Transistor (NPN or PNP) pin C |
| Diode pin C | Supply |
| DPDT relay pin COIL1 | Supply |
| DPDT relay pin NC1 | Supply |
| DPDT relay pin NO2 | Supply |
| Relay board, two channels pin NO1 | Supply |
| Relay board, two channels pin NO2 | Supply |
| DC motor (1) pin 1 | DPDT relay pin COM1 |
| DC motor (1) pin 2 | DPDT relay pin COM2 |
| Relay board, two channels pin GND | Ground |
| Relay board, two channels pin VCC | Supply |
| DC motor (2) pin 1 | Relay board, two channels pin COM1 |
| DC motor (2) pin 2 | Relay board, two channels pin COM2 |
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// Relay board: three ways to switch things a pin cannot.
//
// pins 2 to 5 IN1 to IN4 of the four-channel board: four lamps
// pins 6, 7 IN1 and IN2 of the two-channel board: motor A both ways
// pin 8 the DPDT relay's transistor, through 1 k: motor B both ways
//
// Two circuits run this sketch: "Relay board" wires the lamps, and "Relays
// reverse a motor" wires the two motors. Whatever a circuit leaves unwired
// is simply a pin toggling with nothing on it.
//
// # Active low
//
// The relay boards are active low: an optocoupler's LED sits between VCC and
// each IN pin, so a channel is ON when its pin is LOW. relayOn() hides that,
// and setup() writes every pin HIGH *before* making it an output, because the
// other order leaves each pin low for an instant and every relay clicks on at
// power-up.
//
// # Two relays make an H bridge
//
// Motor A sits between the two channels' COMs. Each NC is on ground and each
// NO on 5 V. Both released: both ends on ground, which is a brake. Channel 1
// in: that end goes to 5 V and the motor turns. Channel 2 in instead: the
// other way. Both in: both ends on 5 V, a brake again, and never a short,
// because each COM is only ever on one contact.
//
// # One coil, two poles
//
// The DPDT relay does the same with one coil, because its two poles move
// together: the motor between the COMs, the supply crossed over between the
// NOs and the NCs. It is a bare relay, so its 40 mA coil hangs off 5 V
// through a 2N2222, with a 1N4007 across it for the kick.
//
// Relays are slow: 10 ms to pull in, 5 ms to let go. Nothing here asks more of
// them than a few clicks a second.
const int LAMPS[] = {2, 3, 4, 5};
const int MOTOR_A[] = {6, 7};
const int DPDT = 8;
void relayOn(int pin, bool on) {
digitalWrite(pin, on ? LOW : HIGH);
}
void setup() {
for (int pin = 2; pin <= 7; pin++) {
digitalWrite(pin, HIGH); // off, before it is even an output
pinMode(pin, OUTPUT);
}
pinMode(DPDT, OUTPUT);
digitalWrite(DPDT, LOW);
Serial.begin(115200);
Serial.println("Mokxi Uno: relays three ways");
}
void chase() {
for (int i = 0; i < 4; i++) {
relayOn(LAMPS[i], true);
delay(250);
relayOn(LAMPS[i], false);
}
}
void loop() {
Serial.println("motor A forward, motor B forward");
relayOn(MOTOR_A[0], true);
digitalWrite(DPDT, LOW);
chase();
Serial.println("both motors braked");
relayOn(MOTOR_A[0], false);
delay(600);
Serial.println("motor A reverse, motor B reverse");
relayOn(MOTOR_A[1], true);
digitalWrite(DPDT, HIGH);
chase();
relayOn(MOTOR_A[1], false);
delay(600);
}
Code walkthrough
The key functions of the sketch, and what each one does.
relayOn sketch.ino
Hides that the board is active low. A channel is on when its pin is LOW, so this function writes LOW to turn it on and HIGH to turn it off.
void relayOn(int pin, bool on) {
digitalWrite(pin, on ? LOW : HIGH);
}setup sketch.ino
Writes each relay pin HIGH before making it an output. In the other order the pin is briefly LOW and every relay clicks on at power-up. It also makes pin 8 an output, starting LOW.
void setup() {
for (int pin = 2; pin <= 7; pin++) {
digitalWrite(pin, HIGH); // off, before it is even an output
pinMode(pin, OUTPUT);
}
pinMode(DPDT, OUTPUT);
digitalWrite(DPDT, LOW);
Serial.begin(115200);
Serial.println("Mokxi Uno: relays three ways");
}loop sketch.ino
Turns channel 1 on and sets pin 8 LOW for forward, then releases for a brake, then channel 2 on and pin 8 HIGH for reverse. Never both channels together, so the bridge is never shorted.
void loop() {
Serial.println("motor A forward, motor B forward");
relayOn(MOTOR_A[0], true);
digitalWrite(DPDT, LOW);
chase();
Serial.println("both motors braked");
relayOn(MOTOR_A[0], false);
delay(600);
Serial.println("motor A reverse, motor B reverse");
relayOn(MOTOR_A[1], true);
digitalWrite(DPDT, HIGH);
chase();
relayOn(MOTOR_A[1], false);
delay(600);
}Troubleshooting
The usual mistakes with this circuit, and the fix for each.
- Relays click when the board starts This project
Write the pin HIGH before callingpinMode, assetupdoes. - The motor does not reverse This project
Check that the NC contacts are on ground and the NO contacts are on the supply, on both channels. - The DPDT motor is erratic This project
Check the diode across the coil: its anode goes to the transistor side and its cathode to the supply. - The LED is dim, burns out, or the pin reads wrong because the resistor value is off. Resistor
Read the color bands again. A 220 ohm to 330 ohm resistor suits a typical LED on 5 V. 10k is a common pull-up or pull-down value. Check with a multimeter if unsure. - A pull-up or pull-down resistor is missing, so the input floats and reads random values. Resistor
Tie the input to 5 V or ground through about 10k. Or use INPUT_PULLUP and wire the switch to ground. - The load never turns on, or is always on, because the legs are in the wrong order. Transistor (NPN or PNP)
Check the pinout in the datasheet for your part. A 2N2222 or BC547 can have emitter, base, collector in a different order. Flat side orientation is easy to get wrong. - The base is wired straight to the pin with no resistor, or the motor has no flyback diode. Transistor (NPN or PNP)
Put about 1k between the pin and the base. For motors and relays, add a diode across the coil with the stripe toward the positive side. - The diode is in backwards, so nothing flows, or a flyback diode conducts all the time. Current flows from the anode to the cathode, the end with the stripe. Diode
Put the striped end toward the more positive side for a series diode. For flyback across a coil, the stripe goes to the positive supply side of the coil.
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.