Hardware Atlas
Motor Driver (L298N)
The L298N is a dual H-bridge motor driver IC that allows a microcontroller to control two DC motors or one stepper motor. It bridges the logic voltage of a microcontroller to the power requirements of motors.
You will understand
- What an H-bridge is and why it is necessary to drive DC motors
- How the L298N maps logic control pins to motor direction and speed
- Safe wiring of motor power, logic power, and shared ground
- PWM speed control via the Enable pins
- The electrical limitations of the L298N (voltage drop, heat dissipation) and when to use alternatives
What is a motor driver?
A motor driver is an integrated circuit that uses power transistors (or MOSFETs) in an H-bridge configuration to deliver high current to a motor while being controlled by low-current logic signals from a microcontroller.
The L298N is a classic bipolar H-bridge IC manufactured by STMicroelectronics, first released in 1994 and still the most common motor driver in educational robotics. Each H-bridge can source up to 2 A continuously per channel, making it suitable for most hobby DC motors.
Draw four switches (transistors) in an H shape with the motor in the centre crossbar. Close the top-left and bottom-right switches: current flows left-to-right through the motor — it spins forward. Close the top-right and bottom-left switches: current flows right-to-left — motor reverses. Close both top switches or both bottom switches: motor brakes (short-circuit across motor). Close nothing: motor coasts. The L298N does this switching automatically based on the logic states of IN1–IN4.
Why it matters for AI builders
Every wheeled robot, conveyor, and cable-driven actuator needs a motor driver between the microcontroller and the motor. The L298N is ubiquitous in entry-level builds:
- Current isolation — isolates the microcontroller's delicate logic circuitry from the motor's noisy, high-current supply
- Bidirectional control — both forward and reverse without rewiring
- PWM-compatible — Enable pin accepts PWM for speed control
- Dual channel — controls two DC motors (differential drive) or one stepper
Working principle
The L298N contains two independent H-bridges (channels A and B):
Control logic:
| IN1 | IN2 | ENA (PWM) | Motor A behaviour | |-----|-----|-----------|-------------------| | HIGH | LOW | HIGH | Forward (full speed) | | LOW | HIGH | HIGH | Reverse (full speed) | | HIGH | LOW | PWM | Forward (proportional speed) | | HIGH | HIGH | any | Brake (fast stop) | | LOW | LOW | any | Coast (free wheel) |
The same table applies to IN3/IN4/ENB for Motor B.
Voltage drop. The L298N uses bipolar transistors, not MOSFETs. Each transistor has a voltage drop of approximately 2V. If your motor needs 12V, supply 14V. This 2V loss is dissipated as heat — the large metal tab (heatsink fin) on the L298N module is essential.
Large heatsink fin dissipates transistor heat. Power input: 12V (motor supply, 6–35V range), 5V logic (or internal 5V regulator when motor supply > 7V), GND. Two motor outputs: OUT1/OUT2 (Motor A) and OUT3/OUT4 (Motor B). Logic control: ENA (Motor A enable/PWM), IN1/IN2 (Motor A direction), IN3/IN4 (Motor B direction), ENB (Motor B enable/PWM).
Key parameters
| Parameter | Value | Notes |
|---|---|---|
| Motor supply voltage | 6 – 35 V | Absolute max 46V — run at least 2V above your motor rated voltage |
| Logic supply voltage | 5 V | Many modules derive 5V internally when motor supply > 7V (jumper) |
| Peak current per channel | 3 A | Continuous: 2 A with heatsink — exceeding this causes thermal shutdown |
| Total DC current | 4 A | Across both channels simultaneously |
| Standby current | 0 mA | No quiescent current when disabled |
| Voltage drop per transistor | ~2 V | Total drop across H-bridge: ~2V — supply 2V above motor rated voltage |
| PWM frequency | Up to 40 kHz | Recommended: 1–20 kHz for efficient switching |
| Operating temperature | -25 to +130 °C | Thermal shutdown at junction temperature > 150°C |
| Package | Multiwatt-15 | Module form factor adds screw terminals and voltage regulator |
Pinout
| Pin | Label | Type | Description |
|---|---|---|---|
| 12V | Motor VCC | power | Motor power supply — 6V to 35V. Name is misleading: accepts any voltage in this range. |
| GND | GND | ground | Common ground — must connect to Arduino GND and power supply GND |
| 5V | Logic VCC | power | 5V output when internal regulator jumper is installed (motor supply > 7V). Can power Arduino. |
| ENA | Enable A | analog | Motor A enable — HIGH = enable; PWM = speed control. Remove jumper to use PWM. |
| IN1 | Input 1 | digital | Motor A direction bit 1. HIGH + IN2 LOW = forward |
| IN2 | Input 2 | digital | Motor A direction bit 2. LOW + IN1 HIGH = forward; HIGH = reverse |
| IN3 | Input 3 | digital | Motor B direction bit 1 |
| IN4 | Input 4 | digital | Motor B direction bit 2 |
| ENB | Enable B | analog | Motor B enable — same function as ENA for channel B |
| OUT1 | Motor A + | power | Motor A output 1 — connect to motor terminal |
| OUT2 | Motor A - | power | Motor A output 2 — connect to motor terminal |
| OUT3 | Motor B + | power | Motor B output 1 |
| OUT4 | Motor B - | power | Motor B output 2 |
Wiring
Code
Full motor driver class with speed and direction
class MotorDriver {
public:
int enPin, in1Pin, in2Pin;
MotorDriver(int en, int in1, int in2) : enPin(en), in1Pin(in1), in2Pin(in2) {}
void begin() {
pinMode(enPin, OUTPUT);
pinMode(in1Pin, OUTPUT);
pinMode(in2Pin, OUTPUT);
stop();
}
void forward(int speed = 255) {
digitalWrite(in1Pin, HIGH);
digitalWrite(in2Pin, LOW);
analogWrite(enPin, constrain(speed, 0, 255));
}
void reverse(int speed = 255) {
digitalWrite(in1Pin, LOW);
digitalWrite(in2Pin, HIGH);
analogWrite(enPin, constrain(speed, 0, 255));
}
void brake() {
// Fast stop: both INs HIGH
digitalWrite(in1Pin, HIGH);
digitalWrite(in2Pin, HIGH);
analogWrite(enPin, 255);
}
void stop() {
// Coast: both INs LOW, disable
digitalWrite(in1Pin, LOW);
digitalWrite(in2Pin, LOW);
analogWrite(enPin, 0);
}
};
MotorDriver motorA(9, 7, 8); // ENA, IN1, IN2
MotorDriver motorB(10, 5, 6); // ENB, IN3, IN4
void setup() {
motorA.begin();
motorB.begin();
}
void loop() {
// Drive forward for 2 seconds
motorA.forward(200);
motorB.forward(200);
delay(2000);
// Brake
motorA.brake();
motorB.brake();
delay(200);
// Reverse for 1 second
motorA.reverse(150);
motorB.reverse(150);
delay(1000);
motorA.stop();
motorB.stop();
delay(1000);
}
PID velocity control with encoder feedback
// Encoder on Motor A
volatile int encoderCount = 0;
void IRAM_ATTR encoderISR() { encoderCount++; }
MotorDriver motorA(9, 7, 8);
float Kp = 2.0, Ki = 0.5, Kd = 0.1;
float targetRPM = 80.0;
float integral = 0, prevError = 0;
unsigned long prevTime = 0;
const int PULSES_PER_REV = 20;
void setup() {
motorA.begin();
attachInterrupt(digitalPinToInterrupt(2), encoderISR, RISING);
prevTime = millis();
Serial.begin(115200);
}
void loop() {
unsigned long now = millis();
float dt = (now - prevTime) / 1000.0;
if (dt < 0.05) return; // 20 Hz control rate
noInterrupts();
int pulses = encoderCount;
encoderCount = 0;
interrupts();
float actualRPM = (pulses / (float)PULSES_PER_REV) / dt * 60.0;
float error = targetRPM - actualRPM;
integral += error * dt;
float derivative = (error - prevError) / dt;
float output = Kp * error + Ki * integral + Kd * derivative;
motorA.forward(constrain((int)output, 0, 255));
Serial.printf("Target: %.1f Actual: %.1f PWM: %.0f\n", targetRPM, actualRPM, output);
prevError = error;
prevTime = now;
}
Test procedure
L298N Motor Driver Verification
With no motor connected, verify wiring: power on and check the L298N 5V output pin reads 5V with a multimeter (if jumper is installed and motor supply > 7V).
Connect a DC motor to OUT1/OUT2. Run the basic forward code. Motor should spin. Confirm direction — "forward" is arbitrary until you define it in software.
Remove the ENA jumper. Connect ENA to PWM pin 9. Run a sweep: analogWrite(9, 0) to analogWrite(9, 255) in a loop. Motor speed should increase smoothly.
Touch the L298N heatsink after 2 minutes of continuous motor operation. It should be warm but not hot (> 60°C is a concern). If very hot, reduce motor load or supply a lower voltage.
Test the brake function: run motor at full speed, then call brake(). Compare stop distance vs stop() (coast). Brake should stop significantly faster.
Common mistakes
- Leaving ENA jumper in while trying PWM control — the jumper shorts ENA to 5V (always-on at full speed). Remove the jumper and connect ENA to a PWM-capable pin to use speed control.
- Using L298N 5V output to power both Arduino and motors — the internal 5V regulator can supply only 100 mA. The Arduino Uno draws 50 mA and any sensors add more. Use a dedicated 5V supply if current exceeds this.
- No common ground — motor driver and Arduino on separate power supplies with no shared GND means the IN1–IN4 logic signals have no voltage reference and behave randomly.
- Running motors at stall from L298N — stall current through the L298N causes the bipolar transistors to heat rapidly. The thermal shutdown will trigger at ~150°C junction temperature. Add a current-limiting mechanism or upgrade to a MOSFET-based driver (DRV8871, TB6612FNG).
- Back-EMF damaging Arduino — if no motor driver is used and the motor is connected directly, the reverse voltage spike when power cuts can exceed GPIO clamp diode rating. Always use a driver or flyback diodes.
Failure Signs
- L298N very hot after a few seconds — motor current exceeds 2A continuous rating; reduce load, use a lower voltage, or upgrade to DRV8833/TB6612FNG
- Motor only runs at full speed regardless of PWM — ENA jumper is still installed; remove it and connect ENA pin to Arduino PWM output
- Motor makes noise but doesn't spin — voltage too low to overcome friction; try increasing supply voltage to rated motor voltage
- Both motors run even when you command only one — IN3/IN4 wired to same pins as IN1/IN2 by mistake; check wiring
- Arduino keeps resetting when motors start — motor inrush current browning out Arduino via shared power; use separate motor power supply with common GND only
Robotics and AI use cases
Motor Drivers in Physical AI Systems
- Mobile robot differential drive — two L298N channels (or two modules) drive left and right wheels independently. The velocity commands from a path-planning algorithm are translated to PWM duty cycles per channel.
- Policy action execution — a reinforcement learning policy outputs wheel velocity targets; the motor driver converts these to the actual current and voltage that spins the motors.
- Gripper actuation — a single L298N channel drives a DC gear motor that opens and closes a parallel gripper. Position is estimated from encoder pulses or limited by mechanical stops.
- Laboratory automation — linear slide motors, sample carousel drives, and pump motors in automated experimental platforms.
- When to upgrade — for higher efficiency, quieter operation, and thermal performance, upgrade to the TB6612FNG (2A, MOSFET-based, 1.2V drop vs 2V) or the DRV8871 (3.6A, integrated current sensing).
Beginner project — Two-motor robot car
Wire two DC motors to a single L298N. Implement forward, reverse, left turn, right turn, and brake functions. Control via Serial Monitor commands ('F', 'B', 'L', 'R', 'S').
Key learning: Motor driver wiring, differential drive kinematics, serial command parsing.
Advanced project — Line-following robot with PID
Add an IR sensor array (3 or 5 sensors) to detect a black line on white paper. Compute the weighted average of sensor readings to get line position error. Feed error into a PID controller that outputs differential speed commands to the two motors. The robot should follow curves and handle intersections.
Key learning: Sensor array normalisation, cross-track error, PID tuning on a real physical system.