ESP32 Bluetooth RC Car with L298N Motor Driver
Build a 2WD Bluetooth-controlled RC car using ESP32 WROOM-32 and L298N dual H-bridge. Control forward, reverse, left, right, and speed from any Bluetooth terminal app on Android or iOS.
Architecture
The L298N is a dual full H-bridge that can drive two DC motors independently at up to 2A each. It accepts direction signals (IN1–IN4) and PWM enable signals (ENA/ENB) from the ESP32. We use LEDC (ESP32's hardware PWM) for smooth speed control instead of the Arduino analogWrite() alias.
Bluetooth Serial is handled by the built-in BluetoothSerial library — no extra hardware. Commands arrive as single characters: F=forward, B=backward, L=left, R=right, S=stop, 0-9=speed.
⚠️ Warning
The L298N's 5V regulator (if using the onboard one) can only supply ~50 mA. Power the ESP32 separately from a 5V UBEC or LiPo BEC — do NOT power it from the L298N's +5V pin when using motors over 1A.
Components required
Wiring
| L298N Pin | ESP32 GPIO | |-----------|------------| | IN1 | 25 | | IN2 | 26 | | IN3 | 27 | | IN4 | 14 | | ENA | 32 (PWM) | | ENB | 33 (PWM) | | 12V | Battery+ | | GND | Battery− & ESP32 GND |
ESP32 VIN → 5V UBEC output. UBEC input → Battery+/−.
// ── ESP32 Bluetooth RC Car ────────────────────────────────────────────────────
// Control via any Bluetooth Serial terminal app (e.g. Serial Bluetooth Terminal)
// Commands: F=forward B=backward L=left R=right S=stop 0-9=speed
// ─────────────────────────────────────────────────────────────────────────────
#include <BluetoothSerial.h>
BluetoothSerial BT;
// ── Motor A (left) ───────────────────────────────────────────────────────────
#define IN1 25
#define IN2 26
#define ENA 32
// ── Motor B (right) ──────────────────────────────────────────────────────────
#define IN3 27
#define IN4 14
#define ENB 33
// ── LEDC PWM setup ────────────────────────────────────────────────────────────
#define LEDC_FREQ 5000
#define LEDC_RES 8 // 8-bit → 0–255
#define CH_A 0
#define CH_B 1
int speed = 200; // Default speed (0–255)
void motorSetup() {
pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT);
ledcSetup(CH_A, LEDC_FREQ, LEDC_RES);
ledcSetup(CH_B, LEDC_FREQ, LEDC_RES);
ledcAttachPin(ENA, CH_A);
ledcAttachPin(ENB, CH_B);
}
void motorA(int dir) {
// dir: 1=fwd, -1=rev, 0=stop
digitalWrite(IN1, dir == 1 ? HIGH : LOW);
digitalWrite(IN2, dir == -1 ? HIGH : LOW);
}
void motorB(int dir) {
digitalWrite(IN3, dir == 1 ? HIGH : LOW);
digitalWrite(IN4, dir == -1 ? HIGH : LOW);
}
void drive(int dirA, int dirB, int spd = -1) {
if (spd < 0) spd = speed;
motorA(dirA);
motorB(dirB);
ledcWrite(CH_A, spd);
ledcWrite(CH_B, spd);
}
void stopCar() { drive(0, 0, 0); }
void setup() {
Serial.begin(115200);
motorSetup();
stopCar();
BT.begin("ESP32-RCCar"); // Bluetooth device name
Serial.println("Bluetooth RC Car ready — pair with 'ESP32-RCCar'");
}
void loop() {
if (!BT.available()) return;
char cmd = (char)BT.read();
BT.print("CMD: "); BT.println(cmd);
switch (cmd) {
case 'F': drive( 1, 1); break; // Both forward
case 'B': drive(-1, -1); break; // Both reverse
case 'L': drive(-1, 1); break; // Left spin
case 'R': drive( 1, -1); break; // Right spin
case 'S': stopCar(); break;
default:
if (cmd >= '0' && cmd <= '9') {
// Map '0'–'9' to 60–255 (60 = minimum movement threshold)
speed = map(cmd - '0', 0, 9, 60, 255);
BT.print("Speed set to: "); BT.println(speed);
}
}
}Live simulation
Steps
- 1Assemble the car chassis and mount both TT motors per kit instructions
- 2Wire L298N to ESP32 following the table — double-check IN1-4 polarity
- 3Power ESP32 from the 5V UBEC, L298N motor supply from the 7.4V LiPo
- 4Upload the sketch and pair your phone with 'ESP32-RCCar' in Bluetooth settings
- 5Open 'Serial Bluetooth Terminal' app, connect to ESP32-RCCar
- 6Send 'F' to move forward, 'S' to stop — adjust speed with '5' or '8'
- 7If one motor spins the wrong direction, swap its IN1/IN2 wires