The L298N is the motor driver in nearly every Indian robot-car kit. It takes a direction signal on IN1–IN4 and a PWM speed signal on ENA/ENB, and switches the battery pack through to two DC motors.
With a NodeMCU, the work is in the pin choice: six control pins on a board whose boot pins (D3, D4, D8) you want to keep clear. This guide uses D1 and D5 for PWM speed, and D2, D0, D6, D7 for direction.
Wiring
| NodeMCU ESP8266 | L298N dual H-bridge motor driver | Wire | Notes |
|---|---|---|---|
| — | OUT1 | — | To Left motor (+) (not drawn) |
| — | OUT2 | — | To Left motor (−) (not drawn) |
| — | OUT3 | — | To Right motor (+) (not drawn) |
| — | OUT4 | — | To Right motor (−) (not drawn) |
| 2× 18650 Li-ion pack (7.4 V) · + | 12V | red | Motor supply. Keep the 5V-EN jumper on (pack under 12 V) so the L298N makes its own 5 V logic supply. |
| 2× 18650 Li-ion pack (7.4 V) · - | GND | black | |
| GND | GND | black | Common ground between the NodeMCU and the driver — the motors won’t respond without it. |
| D1 | ENA | orange | PWM speed, left motor. Pull the ENA jumper off first. |
| D2 | IN1 | yellow | |
| D0 | IN2 | green | D0 (GPIO16) has no PWM, but a direction pin doesn’t need it. |
| D5 | ENB | orange | PWM speed, right motor. Pull the ENB jumper off first. |
| D6 | IN3 | blue | |
| D7 | IN4 | purple |
Motor supply 5–35 V on the 12V terminal; logic 5 V part, 3.3 V board. The L298N’s inputs see anything above about 2.3 V as HIGH, so 3.3 V boards drive IN1–IN4 and ENA/ENB directly. Always connect the board’s GND to the driver’s GND.
Board quirks
- Two motors need six pins, and the NodeMCU has only five that are free and boot-safe (D1, D2, D5, D6, D7). The sixth comes from D0 (GPIO16): it can’t do PWM or interrupts, so it gets a direction input (IN2), never an enable. D3, D4 and D8 stay free so a driver input can’t upset booting.
- On ESP8266 core 3.x
analogWrite()takes 0–255 by default. Old core 2.x tutorials use 0–1023; on 3.x those values all mean full speed. CallanalogWriteRange(1023)if you want the old scale. - The ESP8266 makes PWM in software.
analogWriteFreq(1000)gives 1 kHz, which suits the slow bipolar L298N; much higher frequencies just make it run hot. - The L298N drops about 2 V inside, so a 7.4 V pack gives the motors roughly 5 V. That is why 6 V “BO” gear motors with a 2S pack are the usual Indian robot-kit combination.
- Don’t power the NodeMCU from the L298N’s 5V pin while it is on USB. Run it from USB while testing; for a free-running robot, feed the L298N 5V into VIN with USB unplugged.
Code
// L298N dual motor driver on a NodeMCU (ESP8266) — two DC motors, speed and direction.
// ENA → D1 (GPIO5, PWM), IN1 → D2, IN2 → D0, IN3 → D6, IN4 → D7, ENB → D5 (GPIO14, PWM), GND → GND.
// Motors on OUT1/OUT2 and OUT3/OUT4; battery pack on 12V/GND. Remove the ENA/ENB jumpers.
const uint8_t ENA = D1, IN1 = D2, IN2 = D0; // left motor (D0 has no PWM, fine for a direction pin)
const uint8_t ENB = D5, IN3 = D6, IN4 = D7; // right motor
// speed -255..255. On core 3.x analogWrite() takes 0–255 by default (core 2.x used 0–1023).
void motor(uint8_t en, uint8_t a, uint8_t b, int speed) {
digitalWrite(a, speed > 0 ? HIGH : LOW);
digitalWrite(b, speed < 0 ? HIGH : LOW);
analogWrite(en, abs(speed));
}
void drive(const char* what, int left, int right) {
Serial.printf("%-8s left %4d right %4d\n", what, left, right);
motor(ENA, IN1, IN2, left);
motor(ENB, IN3, IN4, right);
}
void setup() {
const uint8_t pins[] = {ENA, IN1, IN2, ENB, IN3, IN4};
for (uint8_t p : pins) {
digitalWrite(p, LOW); // motors stopped before the pins become outputs
pinMode(p, OUTPUT);
}
analogWriteFreq(1000); // 1 kHz PWM suits the slow L298N
Serial.begin(115200);
Serial.println();
Serial.println("L298N test: forward, reverse, turn, stop");
}
void loop() {
drive("forward", 200, 200);
delay(2000);
drive("stop", 0, 0);
delay(500);
drive("reverse", -200, -200);
delay(2000);
drive("turn", 180, -180);
delay(1000);
drive("stop", 0, 0);
delay(2000);
}// L298N dual motor driver on a NodeMCU (ESP8266) — two DC motors, speed and direction.
// ENA → D1 (GPIO5, PWM), IN1 → D2, IN2 → D0, IN3 → D6, IN4 → D7, ENB → D5 (GPIO14, PWM), GND → GND.
// Motors on OUT1/OUT2 and OUT3/OUT4; battery pack on 12V/GND. Remove the ENA/ENB jumpers.
const uint8_t ENA = D1, IN1 = D2, IN2 = D0; // left motor (D0 has no PWM, fine for a direction pin)
const uint8_t ENB = D5, IN3 = D6, IN4 = D7; // right motor
// speed -255..255. On core 3.x analogWrite() takes 0–255 by default (core 2.x used 0–1023).
void motor(uint8_t en, uint8_t a, uint8_t b, int speed) {
digitalWrite(a, speed > 0 ? HIGH : LOW);
digitalWrite(b, speed < 0 ? HIGH : LOW);
analogWrite(en, abs(speed));
}
void drive(const char* what, int left, int right) {
Serial.printf("%-8s left %4d right %4d\n", what, left, right);
motor(ENA, IN1, IN2, left);
motor(ENB, IN3, IN4, right);
}
void setup() {
const uint8_t pins[] = {ENA, IN1, IN2, ENB, IN3, IN4};
for (uint8_t p : pins) {
digitalWrite(p, LOW); // motors stopped before the pins become outputs
pinMode(p, OUTPUT);
}
analogWriteFreq(1000); // 1 kHz PWM suits the slow L298N
Serial.begin(115200);
Serial.println();
Serial.println("L298N test: forward, reverse, turn, stop");
}
void loop() {
drive("forward", 200, 200);
delay(2000);
drive("stop", 0, 0);
delay(500);
drive("reverse", -200, -200);
delay(2000);
drive("turn", 180, -180);
delay(1000);
drive("stop", 0, 0);
delay(2000);
}Expected serial output
L298N test: forward, reverse, turn, stop
forward left 200 right 200
stop left 0 right 0
reverse left -200 right -200
turn left 180 right -180
stop left 0 right 0L298N test: forward, reverse, turn, stop forward left 200 right 200 stop left 0 right 0 reverse left -200 right -200 turn left 180 right -180 stop left 0 right 0
Common errors
Motors run at full speed whatever the PWM value
The ENA/ENB jumpers are still on, so EN is tied to 5 V. Remove them and wire ENA to D1, ENB to D5.
NodeMCU resets when the motors start
Motor current is pulling the shared supply down. Run the board from USB or a separate supply, keep only GND common, and add a 100 nF capacitor across each motor.
One motor turns the wrong way
Swap that motor’s two wires on OUT1/OUT2 (or OUT3/OUT4).