In this project, we will build a 4WD robotic car that can be controlled wirelessly using a smartphone. The car uses an Arduino Uno, HC-05/HC-06 Bluetooth module, Adafruit Motor Shield V1, and four DC geared motors.
The mobile phone sends commands through Bluetooth, and the Arduino controls the motors, headlights, rear lights, and horn.
Components Required
- Arduino Uno
- Adafruit Motor Shield V1 (L293D)
- HC-05 or HC-06 Bluetooth module
- 4 × DC geared motors
- 4 × Wheels
- 4WD robot chassis
- Battery pack
- 2 or more front LEDs
- 2 or more rear LEDs
- 220Ω–330Ω resistors
- Buzzer
- Jumper wires
- On/Off switch
Motor Connections
| Motor | Motor Shield |
|---|---|
| Left Front | M1 |
| Left Rear | M2 |
| Right Front | M3 |
| Right Rear | M4 |
The project uses the AFMotor library, which is compatible with the Adafruit Motor Shield V1.
Bluetooth Connections
| HC-05/HC-06 | Arduino Uno |
| VCC | 5V |
| GND | GND |
| TXD | D0 (RX) |
| RXD | D1 (TX) |
The Bluetooth module is configured for 9600 baud.
Important: Disconnect the Bluetooth TX/RX wires from D0 and D1 while uploading the Arduino code. Reconnect them after uploading.
Lights and Buzzer
| Component | Arduino Pin |
| Front Lights | D10 |
| Rear Lights | D13 |
| Buzzer | A0 |
Use a suitable current-limiting resistor with LEDs. For a larger buzzer, use a transistor driver circuit.
Power Supply
Connect the battery to the motor shield’s motor power input. Do not power the four motors from the Arduino 5V pin.
Make sure the Arduino and motor power system have a common GND.
Bluetooth Commands
The smartphone app should send the following characters:
| Command | Function |
| F | Forward |
| B | Backward |
| G | Forward Left |
| I | Forward Right |
| H | Backward Left |
| J | Backward Right |
| L | Turn Left |
| R | Turn Right |
| S | Stop |
| W | Front Lights ON |
| w | Front Lights OFF |
| U | Rear Lights ON |
| u | Rear Lights OFF |
| V | Horn ON |
| v | Horn OFF |
The car uses differential drive. During diagonal movement, one side runs slower than the other, allowing the car to move in a curved direction. During left and right turns, the motors on opposite sides rotate in opposite directions, allowing the car to pivot in place.
Arduino Code:
#include <AFMotor.h>
// ---------- Motors (shield channels) ----------
AF_DCMotor motorLF(1); // Left-front -> M1
AF_DCMotor motorLR(2); // Left-rear -> M2
AF_DCMotor motorRF(3); // Right-front -> M3
AF_DCMotor motorRR(4); // Right-rear -> M4
// ---------- Accessory pins ----------
const int FRONT_LIGHTS_PIN = 10;
const int REAR_LIGHTS_PIN = 13;
const int BUZZER_PIN = A0;
// ---------- Tuning ----------
int fullSpeed = 250; // 0-255, current driving speed (adjustable via app's speed slider)
int slowSpeed = 120; // 0-255, speed for the "slowed" side during a diagonal move
// ---------- Failsafe ----------
// If the car is moving and no new command arrives within this window,
// assume the Bluetooth link dropped and stop automatically.
const unsigned long COMMAND_TIMEOUT = 800; // ms
unsigned long lastCommandTime = 0;
bool isMoving = false;
void setup() {
Serial.begin(9600); // This IS the Bluetooth link now (D0/D1), not USB debug.
// Default HC-05/HC-06 baud rate is 9600.
pinMode(FRONT_LIGHTS_PIN, OUTPUT);
pinMode(REAR_LIGHTS_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
stopCar();
digitalWrite(FRONT_LIGHTS_PIN, LOW);
digitalWrite(REAR_LIGHTS_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
}
void loop() {
if (Serial.available()) {
char command = Serial.read();
handleCommand(command);
lastCommandTime = millis();
// Note: no Serial.println() debug prints here on purpose -
// this Serial line is shared with the Bluetooth module, so anything
// printed here gets sent to the phone app instead of a USB debug console.
}
// Failsafe: if we're supposed to be moving but haven't heard from the
// app in a while, the Bluetooth link likely dropped - stop the car.
if (isMoving && (millis() - lastCommandTime > COMMAND_TIMEOUT)) {
stopCar();
}
}
void handleCommand(char command) {
switch (command) {
// ---- 8-direction movement ----
case 'F': forward(); break;
case 'B': backward(); break;
case 'G': forwardLeft(); break;
case 'I': forwardRight(); break;
case 'H': backwardLeft(); break;
case 'J': backwardRight(); break;
case 'L': turnLeft(); break;
case 'R': turnRight(); break;
case 'S': stopCar(); break;
// ---- Lights ----
case 'W': digitalWrite(FRONT_LIGHTS_PIN, HIGH); break;
case 'w': digitalWrite(FRONT_LIGHTS_PIN, LOW); break;
case 'U': digitalWrite(REAR_LIGHTS_PIN, HIGH); break;
case 'u': digitalWrite(REAR_LIGHTS_PIN, LOW); break;
// ---- Horn ----
case 'V': digitalWrite(BUZZER_PIN, HIGH); break;
case 'v': digitalWrite(BUZZER_PIN, LOW); break;
// ---- Speed slider (0-9 = 0%-90%, q = 100%) ----
case '0': setSpeed(0); break;
case '1': setSpeed(28); break;
case '2': setSpeed(57); break;
case '3': setSpeed(85); break;
case '4': setSpeed(113); break;
case '5': setSpeed(142); break;
case '6': setSpeed(170); break;
case '7': setSpeed(198); break;
case '8': setSpeed(226); break;
case '9': setSpeed(255); break;
case 'q': setSpeed(255); break;
default: break; // ignore unknown / newline characters
}
}
// ---------- Speed ----------
void setSpeed(int newSpeed) {
fullSpeed = newSpeed;
slowSpeed = newSpeed * 0.6; // keep the diagonal-turn slowdown proportional
// If the car is already moving, apply the new speed right away
// instead of waiting for the next direction command.
if (isMoving) {
setLeftSpeed(fullSpeed);
setRightSpeed(fullSpeed);
}
}
// ---------- Helpers ----------
void setLeftSpeed(int speed) { motorLF.setSpeed(speed); motorLR.setSpeed(speed); }
void setRightSpeed(int speed) { motorRF.setSpeed(speed); motorRR.setSpeed(speed); }
void leftForward() { motorLF.run(FORWARD); motorLR.run(FORWARD); }
void leftBackward() { motorLF.run(BACKWARD); motorLR.run(BACKWARD); }
void leftStop() { motorLF.run(RELEASE); motorLR.run(RELEASE); }
void rightForward() { motorRF.run(FORWARD); motorRR.run(FORWARD); }
void rightBackward() { motorRF.run(BACKWARD); motorRR.run(BACKWARD); }
void rightStop() { motorRF.run(RELEASE); motorRR.run(RELEASE); }
// ---------- Movement ----------
void forward() {
setLeftSpeed(fullSpeed); setRightSpeed(fullSpeed);
leftForward(); rightForward();
isMoving = true;
}
void backward() {
setLeftSpeed(fullSpeed); setRightSpeed(fullSpeed);
leftBackward(); rightBackward();
digitalWrite(REAR_LIGHTS_PIN, HIGH); // reverse/brake indicator while backing up
isMoving = true;
}
void forwardLeft() {
// moving forward while veering left: slow the left side down
setLeftSpeed(slowSpeed); setRightSpeed(fullSpeed);
leftForward(); rightForward();
isMoving = true;
}
void forwardRight() {
// moving forward while veering right: slow the right side down
setLeftSpeed(fullSpeed); setRightSpeed(slowSpeed);
leftForward(); rightForward();
isMoving = true;
}
void backwardLeft() {
setLeftSpeed(slowSpeed); setRightSpeed(fullSpeed);
leftBackward(); rightBackward();
digitalWrite(REAR_LIGHTS_PIN, HIGH);
isMoving = true;
}
void backwardRight() {
setLeftSpeed(fullSpeed); setRightSpeed(slowSpeed);
leftBackward(); rightBackward();
digitalWrite(REAR_LIGHTS_PIN, HIGH);
isMoving = true;
}
void turnLeft() {
// pivot in place: left side backward, right side forward
setLeftSpeed(fullSpeed); setRightSpeed(fullSpeed);
leftBackward(); rightForward();
isMoving = true;
}
void turnRight() {
// pivot in place: left side forward, right side backward
setLeftSpeed(fullSpeed); setRightSpeed(fullSpeed);
leftForward(); rightBackward();
isMoving = true;
}
void stopCar() {
leftStop(); rightStop();
digitalWrite(REAR_LIGHTS_PIN, LOW);
isMoving = false;
}
Testing
After uploading the code:
- Connect the HC-05/HC-06 to the Arduino.
- Power the robotic car.
- Pair the phone with the Bluetooth module.
- Open a Bluetooth control app.
- Configure the buttons to send the commands listed above.
- Test forward, backward, left, right, lights, and horn.
If the car moves in the wrong direction, reverse the motor wires of the affected motor.