Relay Modules & DC Motors with Drivers
By the end of this lesson you will be able to switch a small 5 V water pump on and off with a relay module, read a relay's terminals correctly, and control a DC motor's speed and direction with a motor driver. You will also understand why an Arduino pin must never power a motor directly.
These skills move your projects from blinking lights to things that actually do work: pumps that water plants, fans that cool, and wheels that drive a robot.
Why a pin cannot drive a motor
An UNO R4 pin can handle about 8 mA. A small DC motor or pump needs a hundred milliamps or more just to run, and much more to start. Motors also misbehave electrically: when the current through a coil is switched off, the collapsing magnetic field produces a voltage spike, called back-EMF or an inductive kick, that can destroy a pin.
So we always use a middleman. Think of it as a railway signal cabin. The signal operator (the Arduino pin) moves a small lever. That lever controls the heavy points on the track (the motor current), which come from a completely separate source of power.
| Middleman | What it switches | Best for |
|---|---|---|
| Relay module | On/off only, with an isolated mechanical switch | Pumps, small DC loads, slow switching |
| MOSFET module | On/off and fast PWM, one direction | LED strips, fans, pump speed |
| Motor driver (H-bridge) | Speed and both directions | Robot wheels, motors that reverse |
Part 1: Relay modules
A relay is a switch flipped by an electromagnet. When current flows through its coil, a small metal arm is pulled across and the switch contacts change position. The coil side and the contact side are not electrically connected, so the controlled circuit is isolated from the Arduino.
A relay module adds everything needed to drive the coil safely from a pin: a transistor, a protection diode across the coil (the flyback diode), and an LED. Many also have an optocoupler, which passes the signal using light for extra isolation.
| Terminal | Name | Connection when the relay is off | When on |
|---|---|---|---|
| COM | Common | Connected to NC | Connected to NO |
| NO | Normally open | Not connected | Connected to COM |
| NC | Normally closed | Connected to COM | Not connected |
For a pump that should run only when commanded, use COM and NO. Then if the Arduino crashes, loses power or is unplugged, the pump stops. That is a safe default.
Step 1: Wire a 5 V pump through a relay module
| Part | Pin or terminal | Connects to |
|---|---|---|
| Relay module | VCC | Arduino 5V |
| Relay module | GND | Arduino GND |
| Relay module | IN | Arduino D7 |
| Pump supply (5 V USB power bank or adapter, separate from the Arduino) | + | Relay COM |
| Relay module | NO | Pump red wire (+) |
| Pump | Black wire (-) | Pump supply - |
The pump's current never passes through the Arduino. Keep the pump supply's + wire away from the Arduino's pins. Check the pump's current rating in its listing, and make sure your supply can provide it with room to spare.
Step 2: Check whether your module is active LOW
Many relay modules switch on when IN is LOW. Find out before connecting the pump: run this sketch and listen for the click and watch the module's LED.
const int RELAY_PIN = 7;
const bool ACTIVE_LOW = true; // change to false if your module is active HIGH
void relayOn() { digitalWrite(RELAY_PIN, ACTIVE_LOW ? LOW : HIGH); }
void relayOff() { digitalWrite(RELAY_PIN, ACTIVE_LOW ? HIGH : LOW); }
void setup() {
pinMode(RELAY_PIN, OUTPUT);
relayOff(); // safe state first
Serial.begin(9600);
while (!Serial && millis() < 3000) { }
Serial.println("relay OFF");
}
void loop() {
relayOn();
Serial.println("relay ON");
delay(2000);
relayOff();
Serial.println("relay OFF");
delay(2000);
}relay OFF relay ON relay OFF relay ON relay OFF
If the relay LED is lit when the monitor says OFF, your module is active HIGH: set ACTIVE_LOW to false. Hiding the logic in relayOn() and relayOff() means the rest of your code never has to think about it.
Step 3: Run the pump for a fixed time, safely
A pump should never run without a limit. This function runs it for a requested time but never beyond a hard maximum, using the guard idea from Electronics Safety First:
const int RELAY_PIN = 7;
const unsigned long PUMP_MAX_MS = 8000; // hard limit
void relayOn() { digitalWrite(RELAY_PIN, LOW); } // active-low module
void relayOff() { digitalWrite(RELAY_PIN, HIGH); }
unsigned long pumpFor(unsigned long ms) {
if (ms > PUMP_MAX_MS) ms = PUMP_MAX_MS; // clip unsafe requests
relayOn();
delay(ms); // fine for a short, simple test
relayOff();
return ms;
}
void setup() {
pinMode(RELAY_PIN, OUTPUT);
relayOff();
Serial.begin(9600);
while (!Serial && millis() < 3000) { }
Serial.print("Pumped for ");
Serial.print(pumpFor(3000));
Serial.println(" ms");
Serial.print("Pumped for ");
Serial.print(pumpFor(60000));
Serial.println(" ms");
}
void loop() {
}Pumped for 3000 ms Pumped for 8000 ms
The second request asked for a full minute, but the guard cut it to 8 seconds. Never let a pump run dry: it overheats. In the final project, the pump also stops if the water tank is empty.
Part 2: DC motors with a driver
A DC motor spins one way when current flows one way, and the other way when the current is reversed. Speed depends on the average voltage, which PWM controls. To do both, you need an H-bridge: four electronic switches arranged like the letter H around the motor, so current can be sent either way. A motor driver chip contains the H-bridge plus protection.
| Driver | Notes |
|---|---|
| TB6612FNG | Modern, efficient MOSFET driver for two small motors; a good choice for kits and robots |
| DRV8833 | Similar modern low-voltage dual driver |
| L298N | Older and very common in Indian kits; works, but wastes around 2 V or more as heat and gets warm |
Step 4: Wire a TB6612FNG
| Part | Pin | Connects to |
|---|---|---|
| TB6612FNG | VM (motor power) | Battery pack + (for example 4 × AA, 6 V) |
| TB6612FNG | VCC (logic power) | Arduino 5V |
| TB6612FNG | GND (all GND pins) | Battery - and Arduino GND (common ground) |
| TB6612FNG | PWMA | Arduino D5 (PWM) |
| TB6612FNG | AIN1 | Arduino D4 |
| TB6612FNG | AIN2 | Arduino D3 |
| TB6612FNG | STBY | Arduino D8 (HIGH = driver enabled) |
| TB6612FNG | AO1, AO2 | The two motor wires |
The driver's datasheet truth table, simplified:
| AIN1 | AIN2 | Motor |
|---|---|---|
| HIGH | LOW | Turns one way (call it forward) |
| LOW | HIGH | Turns the other way |
| HIGH | HIGH | Short brake: stops quickly |
| LOW | LOW | Coasts to a stop |
Step 5: Speed and direction in one function
A single number from -255 to 255 can describe both: the sign gives the direction and the size gives the speed.
const int MOTOR_PWM = 5, MOTOR_IN1 = 4, MOTOR_IN2 = 3, MOTOR_STBY = 8;
void setMotor(int speed) { // -255 .. 255
speed = constrain(speed, -255, 255);
bool forward = speed >= 0;
digitalWrite(MOTOR_IN1, forward ? HIGH : LOW);
digitalWrite(MOTOR_IN2, forward ? LOW : HIGH);
analogWrite(MOTOR_PWM, abs(speed));
Serial.print("speed ");
Serial.print(speed);
Serial.print(": AIN1=");
Serial.print(forward ? 1 : 0);
Serial.print(" AIN2=");
Serial.print(forward ? 0 : 1);
Serial.print(" PWM=");
Serial.println(abs(speed));
}
void setup() {
pinMode(MOTOR_PWM, OUTPUT);
pinMode(MOTOR_IN1, OUTPUT);
pinMode(MOTOR_IN2, OUTPUT);
pinMode(MOTOR_STBY, OUTPUT);
digitalWrite(MOTOR_STBY, HIGH); // enable the driver
Serial.begin(9600);
while (!Serial && millis() < 3000) { }
setMotor(200); delay(2000); // forward, fast
setMotor(-120); delay(2000); // reverse, slower
setMotor(300); delay(2000); // too big: clipped to 255
setMotor(0); // stop
}
void loop() {
}speed 200: AIN1=1 AIN2=0 PWM=200 speed -120: AIN1=0 AIN2=1 PWM=120 speed 255: AIN1=1 AIN2=0 PWM=255 speed 0: AIN1=1 AIN2=0 PWM=0
The motor runs forward fast, reverses slower, runs at full speed, then stops (PWM 0). Very low PWM values may only make the motor hum, because it needs a minimum voltage to start turning.
Common mistakes
- Powering a motor or pump from the Arduino 5V pin. Use a separate supply and a common GND.
- Using NC for a pump. If the Arduino fails, the pump would run. Use NO.
- Not checking active LOW or HIGH. The relay works backwards, and the pump runs at start-up.
- Forgetting STBY on the TB6612FNG. If it is LOW, the motor never moves.
- Wiring mains to a relay module. Never. Use certified products and a qualified electrician.
Key points
- Pins give signals, not power; relays, MOSFET modules and motor drivers switch the real current.
- A relay module's COM-NO contacts close only when the relay is on, which is the safe choice for pumps.
- Hide active LOW logic inside
relayOn()andrelayOff(), set it off first, and limit run times. - An H-bridge driver such as the TB6612FNG controls direction (AIN1/AIN2) and speed (PWM).
- Motor supplies and the Arduino must share GND; this course never switches mains.
Exercise
Write rampTo(int target) for the TB6612FNG setup. It should change the motor speed from the current speed to target in steps of 50, calling setMotor() at each step with a 100 ms pause, and finish exactly at target. Starting from 0, what lines are printed for rampTo(180)?
Show solution
int currentSpeed = 0;
void rampTo(int target) {
while (currentSpeed != target) {
if (currentSpeed < target) currentSpeed = min(currentSpeed + 50, target);
else currentSpeed = max(currentSpeed - 50, target);
setMotor(currentSpeed); // setMotor() from Step 5
delay(100);
}
}Calling rampTo(180) from 0 prints:
speed 50: AIN1=1 AIN2=0 PWM=50 speed 100: AIN1=1 AIN2=0 PWM=100 speed 150: AIN1=1 AIN2=0 PWM=150 speed 180: AIN1=1 AIN2=0 PWM=180
min() stops the last step at exactly 180 instead of overshooting to 200. Gentle ramps reduce current spikes and are kinder to gears.
Quick Quiz
1. Which relay terminals should a pump use, so it stops if the Arduino fails?
Normally open contacts close only when the relay is energised, so the pump is off by default.
2. Why can't an Arduino pin drive a DC motor directly?
A driver or relay handles the current and protects the pin.
3. On a TB6612FNG, AIN1 is LOW and AIN2 is HIGH. What does the motor do?
Swapping which input is HIGH reverses the current through the motor.
4. A project must switch a 230 V ceiling fan. What does this course recommend?
Mains wiring is never part of a student project.
Learn IoT & Arduino with a mentor
Free lessons get you started. Our IoT & Embedded Systems training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
