Free Tutorial

Build Your Own Wireless Car Using ESP32 and Bluetooth Low Energy (BLE)

Beginner Difficulty
1 Est. Time
4 items Components Needed

About This Project

Ever wanted to build your own remote-controlled car from scratch? In this tutorial, we'll build a wireless car controlled via Bluetooth Low Energy (BLE) using the ESP32 microcontroller. Unlike traditional RC cars that use RF remotes, our car will be controlled directly from a smartphone app — no extra remote hardware needed!

This project is perfect for students and beginners who want to learn about:


Microcontroller programming (ESP32)
Motor control using H-Bridge driver ICs
Bluetooth Low Energy (BLE) communication
Basic robotics and circuit design


By the end of this guide, you'll have a fully functional 2-wheel-drive (or 4-wheel-drive) car that you can drive around using your phone!
Basic Flow:

Smartphone App (BLE Client)
|
| Sends command (F, B, L, R, S)
v
ESP32 (BLE Server)
|
| Controls GPIO pins
v
Motor Driver (L298N / L293D)
|
v
DC Motors → Car Moves

ESP32 to L298N Motor Driver Connections

ESP32 PinL298N PinFunctionGPIO 14IN1Motor A direction 1GPIO 27IN2Motor A direction 2GPIO 26IN3Motor B direction 1GPIO 25IN4Motor B direction 2GPIO 12ENAMotor A speed (PWM)GPIO 13ENBMotor B speed (PWM)GNDGNDCommon ground

L298N to Motors & Battery

L298N PinConnects ToOUT1, OUT2Left Motor terminalsOUT3, OUT4Right Motor terminals12V / VCCBattery positive (7.4V from 2x 18650)GNDBattery negative + ESP32 GND5V (out)Can power ESP32 VIN (if jumper enabled)

Wiring Notes


Important: Never power the ESP32 directly from the L298N's 12V input — use its regulated 5V output, or power ESP32 separately via USB/battery.
Mount the L298N module on the chassis with the motors below it for clean wiring.
Keep motor wires twisted together to reduce electrical noise.
Double-check polarity of the battery before connecting — reversed polarity can damage your ESP32.


(Tip: When publishing, insert a hand-drawn or Fritzing-style circuit diagram image here for visual clarity. Tools like Fritzing, EasyEDA, or Tinkercad Circuits work great for this.)


Step-by-Step Assembly


Build the chassis — Attach the BO motors to the chassis frame using the provided clips/screws. Attach wheels to the motor shafts.
Mount the L298N driver — Fix it in the center of the chassis using double-sided tape or small screws.
Mount the ESP32 — Place it near the motor driver, ensuring GPIO pins are accessible.
Wire the connections — Follow the wiring table above carefully.
Connect the battery pack — Attach the on/off switch in series with the battery before connecting to the L298N's power input.
Secure all wiring — Use zip ties or hot glue to prevent wires from getting caught in the wheels.

Components Required

  • ESP32
  • L298
  • Motors
  • Chassis

Circuit Diagram

Circuit diagram for Build Your Own Wireless Car Using ESP32 and Bluetooth Low Energy (BLE)

Step-by-Step Instructions

Source Code

Arduino / ESP32 Sketch
/*
  Wireless BLE Car using ESP32
  Control via BLE app sending single characters:
  F - Forward, B - Backward, L - Left, R - Right, S - Stop
*/

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>

// Motor A (Left) pins
#define IN1 14
#define IN2 27
#define ENA 12

// Motor B (Right) pins
#define IN3 26
#define IN4 25
#define ENB 13

#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

BLECharacteristic *pCharacteristic;
bool deviceConnected = false;

class MyServerCallbacks : public BLEServerCallbacks {
  void onConnect(BLEServer* pServer) { deviceConnected = true; }
  void onDisconnect(BLEServer* pServer) {
    deviceConnected = false;
    pServer->getAdvertising()->start(); // restart advertising
  }
};

class MyCallbacks : public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic *pCharacteristic) {
    String value = pCharacteristic->getValue().c_str();
    if (value.length() > 0) {
      char command = value[0];
      Serial.print("Command received: ");
      Serial.println(command);

      switch (command) {
        case 'F': moveForward(); break;
        case 'B': moveBackward(); break;
        case 'L': turnLeft(); break;
        case 'R': turnRight(); break;
        case 'S': stopCar(); break;
        default: stopCar(); break;
      }
    }
  }
};

void setup() {
  Serial.begin(115200);

  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  pinMode(ENA, OUTPUT);
  pinMode(ENB, OUTPUT);

  // Full speed by default
  digitalWrite(ENA, HIGH);
  digitalWrite(ENB, HIGH);

  stopCar();

  // BLE Setup
  BLEDevice::init("ESP32_BLE_Car");
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  BLEService *pService = pServer->createService(SERVICE_UUID);

  pCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID,
                      BLECharacteristic::PROPERTY_READ |
                      BLECharacteristic::PROPERTY_WRITE
                    );

  pCharacteristic->setCallbacks(new MyCallbacks());
  pService->start();

  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->start();

  Serial.println("BLE Car Ready. Waiting for connections...");
}

void loop() {
  // Nothing needed here — BLE callbacks handle everything
  delay(20);
}

// ---- Motor Control Functions ----

void moveForward() {
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
}

void moveBackward() {
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);
}

void turnLeft() {
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
}

void turnRight() {
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);
}

void stopCar() {
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, LOW);
}
Note: Setting Up the Mobile App Since this car doesn't have a custom app yet, the easiest way to test it is: Download "Bluetooth Terminal HC-05" or "nRF Connect" from the Play Store. Open the app, scan for BLE devices, and connect to "ESP32_BLE_Car". Find the writable characteristic (matching the UUID in our code). Send characters: F, B, L, R, S to control the car. For a polished experience: Build a custom app using MIT App Inventor with directional buttons (Forward/Backward/Left/Right/Stop) that send these same characters over BLE. This gives users a joystick-style interface instead of typing commands.

Completed this project?

Get an official Project Completion Certificate with a unique ID & QR verification — perfect for internships, resumes, and college submissions.

Get Certificate →