To build a reliable, responsive Bluetooth arduino control car, you need an Arduino Uno R3, an L298N dual H-bridge motor driver, an HC-05 Bluetooth module, and a 4WD TT motor chassis. The total build cost sits between $35 and $45, and assembly takes roughly two hours. This guide skips the generic overviews and goes straight into the specific voltage drops, logic-level shifting requirements, and exact code needed to get your chassis moving without burning out your microcontroller.
Parts List and Component Specifications
Before cutting wires, verify your exact module variants. The market is flooded with clones, and minor silicon differences dictate your power supply requirements. Below is the exact bill of materials (BOM) and the electrical characteristics you must respect.
| Component | Variant / IC | Operating Voltage | Max Continuous Current | Critical Voltage Drop | Approx. Cost |
|---|---|---|---|---|---|
| Microcontroller | Arduino Uno R3 (ATmega328P) | 5V Logic, 7-12V Vin | 40mA per GPIO pin | N/A | $22.00 |
| Motor Driver | L298N (STMicroelectronics clone) | 5V-35V (Motor), 5V (Logic) | 2A per channel (3A peak) | ~2.0V (Darlington pair) | $4.50 |
| Bluetooth Module | HC-05 (ZigBee/BT 2.0 SPP) | 3.3V Logic, 4.5-5.5V VCC | 30mA (paired), 50mA (pairing) | N/A | $6.00 |
| Drive Motors | TT Gearmotor (1:48 ratio, 4x) | 3V-6V Nominal | 150mA (no-load), 800mA (stall) | N/A | $3.00 (each) |
| Power Supply | 2S LiPo (7.4V) or 6x AA (9V) | 7.4V - 9.0V | 2000mAh+ recommended | N/A | $12.00 |
Wiring the Arduino Control Car Chassis
Physical wiring is where most hobby builds fail. The HC-05 operates at 3.3V logic, while the Arduino Uno outputs 5V. Feeding 5V directly into the HC-05 RX pin will degrade the module over time and eventually brick it. You must use a voltage divider on the RX line.
Pin Mapping Table
| Arduino Uno Pin | Target Module | Module Pin | Notes / Constraints |
|---|---|---|---|
| D5 (PWM) | L298N | ENA | Controls speed for Left Motors (Channel A) |
| D4 | L298N | IN1 | Left Motor Direction 1 |
| D7 | L298N | IN2 | Left Motor Direction 2 |
| D6 (PWM) | L298N | ENB | Controls speed for Right Motors (Channel B) |
| D8 | L298N | IN3 | Right Motor Direction 1 |
| D9 | L298N | IN4 | Right Motor Direction 2 |
| D10 (RX) | HC-05 | TXD | Direct connection (3.3V to 5V tolerant) |
| D11 (TX) | HC-05 | RXD | Must use 1k/2k voltage divider |
| 5V | HC-05 / L298N | VCC / 5V | Power logic circuits only |
| GND | All | GND | Common ground is mandatory |
Assembly Steps
- Prepare the Voltage Divider: Connect a 1kΩ resistor from Arduino Pin 11 to the HC-05 RXD pin. Connect a 2kΩ resistor from the HC-05 RXD pin to GND. This drops the 5V TX signal down to a safe ~3.33V.
- Set the L298N Jumper: If your supply voltage is under 12V, leave the 5V-EN jumper on the L298N in place. This enables the onboard 7805 regulator to output 5V, which you will use to power the Arduino Uno via its Vin pin and the HC-05 VCC pin.
- Wire the Motors: Parallel the two left TT motors and connect them to L298N OUT1 and OUT2. Parallel the two right TT motors and connect them to OUT3 and OUT4.
- Connect Main Power: Wire your 7.4V LiPo or 9V battery pack to the L298N 12V terminal and the adjacent GND terminal. Ensure the GND is shared with the Arduino and HC-05.
Compilable Code for Bluetooth Motor Control
This code targets the Arduino Uno R3 (ATmega328P). It uses the SoftwareSerial library to communicate with the HC-05 on pins 10 and 11, leaving the hardware serial (pins 0 and 1) free for debugging via the USB Serial Monitor. The code includes bounds checking on PWM values to prevent integer overflow errors that can cause erratic motor behavior.
#include <SoftwareSerial.h>
// Pin Definitions
#define ENA 5 // PWM for Left Motors
#define IN1 4 // Left Motor Dir 1
#define IN2 7 // Left Motor Dir 2
#define ENB 6 // PWM for Right Motors
#define IN3 8 // Right Motor Dir 1
#define IN4 9 // Right Motor Dir 2
// Bluetooth Serial Setup (RX, TX)
SoftwareSerial BTSerial(10, 11);
const int MAX_SPEED = 255;
const int MIN_SPEED = 100; // Motors stall below this PWM value on TT chassis
void setup() {
// Initialize hardware serial for USB debugging
Serial.begin(9600);
// Initialize Bluetooth serial (HC-05 default baud rate is 9600)
BTSerial.begin(9600);
// Set motor control pins as outputs
pinMode(ENA, OUTPUT);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(ENB, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
// Ensure car is stopped on boot
stopMotors();
Serial.println("Arduino Control Car Initialized. Waiting for BT commands...");
}
void loop() {
if (BTSerial.available() > 0) {
char command = BTSerial.read();
// Error handling: Ignore newline/carriage return artifacts from mobile apps
if (command == '\n' || command == '\r') return;
Serial.print("Received: ");
Serial.println(command);
switch (command) {
case 'F': moveForward(MAX_SPEED); break;
case 'B': moveBackward(MAX_SPEED); break;
case 'L': turnLeft(MAX_SPEED); break;
case 'R': turnRight(MAX_SPEED); break;
case 'S': stopMotors(); break;
default:
// Failsafe: stop if unknown character is received
stopMotors();
break;
}
}
}
// Motor Control Functions with PWM bounding
void moveForward(int speed) {
speed = constrain(speed, MIN_SPEED, MAX_SPEED);
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
analogWrite(ENA, speed);
analogWrite(ENB, speed);
}
void moveBackward(int speed) {
speed = constrain(speed, MIN_SPEED, MAX_SPEED);
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
analogWrite(ENA, speed);
analogWrite(ENB, speed);
}
void turnLeft(int speed) {
speed = constrain(speed, MIN_SPEED, MAX_SPEED);
digitalWrite(IN1, LOW); // Left motors reverse
digitalWrite(IN2, HIGH);
digitalWrite(IN3, HIGH); // Right motors forward
digitalWrite(IN4, LOW);
analogWrite(ENA, speed);
analogWrite(ENB, speed);
}
void turnRight(int speed) {
speed = constrain(speed, MIN_SPEED, MAX_SPEED);
digitalWrite(IN1, HIGH); // Left motors forward
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW); // Right motors reverse
digitalWrite(IN4, HIGH);
analogWrite(ENA, speed);
analogWrite(ENB, speed);
}
void stopMotors() {
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, LOW);
analogWrite(ENA, 0);
analogWrite(ENB, 0);
}
Debugging: First Three Things to Check When It Fails
When your arduino control car refuses to move or fails to upload, do not start rewriting code. Hardware and serial conflicts cause 90% of failures in this specific build. Here are the first three things to check, ranked by probability.
1. Upload Fails with Sync Error
Exact Error String: avrdude: stk500_getsync() attempt 10 of 10: not in sync: resp=0x00
- Cause: You wired the HC-05 TX/RX directly to Arduino hardware pins 0 and 1. The HC-05 interferes with the USB-to-serial chip (ATmega16U2) during code upload.
- Fix: Ensure the HC-05 is wired to pins 10 and 11 using
SoftwareSerialas shown in the code above. If you must use pins 0 and 1, physically disconnect the HC-05 RX/TX wires before clicking "Upload" in the Arduino IDE, then reconnect them.
2. Motors Hum or Click but Do Not Turn
Symptom: You hear a high-pitched whine from the TT motors, and the L298N gets hot, but the wheels don't spin.
- Cause: The L298N's 2.0V Darlington voltage drop is starving the motors. If you are using a 4x AA (6V) battery pack, the motors are only seeing 4V, which is below their starting torque threshold under load.
- Fix: Upgrade your power supply to a 2S LiPo (7.4V) or a 9V alkaline battery. Alternatively, as noted in the Adafruit Motor Selection Guide, swap the L298N for a MOSFET-based driver like the TB6612FNG, which only drops ~0.5V.
3. HC-05 LED Blinks Rapidly but Won't Pair
Symptom: The HC-05 LED flashes quickly (approx 2-3 times per second) and your phone's Bluetooth menu cannot find the device, or rejects the default '1234' PIN.
- Cause: The module is either in AT command mode (baud rate mismatch) or the internal firmware state is locked due to a brownout during a previous pairing attempt.
- Fix: Power cycle the entire car. If it still fails, disconnect the HC-05 VCC, hold down the micro-pushbutton on the HC-05 module, reconnect VCC, and wait 3 seconds to force it into AT mode. Send
AT+ORGLvia a USB-serial adapter to restore factory defaults, then reboot.
Extending and Simplifying the Build
Once the base arduino control car is operational, you will likely want to modify the platform. Here is how to scale the build up or down based on your budget and project goals.
How to Simplify (Cost & Power Reduction)
If you are building this for a classroom setting or want to extend battery life, drop the chassis from 4WD to 2WD. Remove the front two TT motors and replace them with a passive caster wheel. This cuts your stall current draw in half (from ~3.2A to ~1.6A), allowing you to use cheaper 4x AA battery holders without triggering the L298N's internal thermal shutdown. In the code, you can wire both left and right motors to a single L298N channel if you only need basic forward/backward movement, freeing up GPIO pins.
How to Extend (Autonomy & Sensor Integration)
To convert this from a remote-control toy into an autonomous rover:
- Add Collision Avoidance: Mount an HC-SR04 ultrasonic sensor on a micro-servo (SG90) at the front of the chassis. Use the
pulseIn()function to measure distance. If the distance drops below 20cm, trigger thestopMotors()function, sweep the servo left and right, and calculate the path of least resistance. - Upgrade the Motor Driver: If you plan to add heavy sensors or a robotic arm, the L298N will overheat. Upgrade to a TI-based or dual MOSFET driver. The TB6612FNG handles 1.2A continuous per channel with a fraction of the heat dissipation, allowing you to shrink the chassis footprint.
- Add Gyroscopic Stabilization: Wire an MPU6050 accelerometer/gyroscope via I2C (pins A4/A5). Use the Madgwick filter library to detect if the car is tipping on an incline, and dynamically adjust the PWM values to the left and right motors to maintain a straight trajectory.
By respecting the logic-level limits of the HC-05 and compensating for the L298N's voltage drop, your arduino control car will transition from a frustrating weekend project into a robust, extensible robotics platform.






