Project Overview & Difficulty Rating
Building a functional 2WD robot car with Arduino Uno R3 requires an L298N dual H-bridge motor driver, two 130-size TT gearmotors, and a 2S 18650 lithium-ion power pack. The total component cost sits around $30 to $40. This guide targets the standard Arduino Uno R3 (ATmega328P) board variant, though the code and wiring are directly compatible with the Uno R4 Minima and most Nano clones.
Spec Sheet & Difficulty Rating
- Difficulty: 2/5 (Beginner-friendly, but requires strict power management)
- Build Time: 2 hours (mechanical assembly + wiring + code upload)
- Estimated Cost: $32 - $45 USD
- Target Board: Arduino Uno R3 (ATmega328P DIP or SMD)
- Operating Voltage: 7.4V nominal (6.0V - 8.4V range from 2S Li-ion)
Exact Parts List & Spec Sheet
Do not buy generic, unbranded "Ultrafire" 18650 batteries from random marketplaces. They often have dangerous protection circuits that trip under motor stall currents, or they simply lie about capacity. Stick to reputable cells.
| Component | Exact Variant / Model | Estimated Cost | Notes |
|---|---|---|---|
| Microcontroller | Arduino Uno R3 (ATmega328P) | $12 - $15 | Official or reputable clone (e.g., Elegoo) |
| Motor Driver | L298N Dual H-Bridge Module | $4 - $6 | Expect a 2V voltage drop across the internal BJTs |
| Motors (x2) | 130-size TT Gearmotors (3-6V, 200 RPM) | $6 - $8 | Stall current is ~800mA per motor |
| Battery Cells (x2) | Molicel P26A or Samsung 25R 18650 | $12 - $16 | Must be unprotected (flat top) for high discharge |
| Battery Holder | 2S 18650 Plastic Holder with 18AWG leads | $2 | Thin 22AWG leads will cause voltage sag |
| Sensor | HC-SR04 Ultrasonic Distance Sensor | $2 - $3 | 5V tolerant, requires 10μs trigger pulse |
| Chassis | 2WD Acrylic base + metal castor wheel | $5 - $7 | Ensure castor has a smooth ball bearing |
Wiring & Pin Mapping Table
The most common point of failure in Arduino robot cars is a missing logic ground bond. The Arduino and the L298N must share a common ground reference, otherwise the 5V logic signals from the Uno are floating relative to the motor driver’s internal optocouplers and BJT gates.
| Arduino Uno R3 Pin | Destination Module | Module Pin | Wire Color / Gauge Recommendation |
|---|---|---|---|
| D5 (Digital) | L298N | IN1 | 22 AWG (Orange) |
| D6 (Digital) | L298N | IN2 | 22 AWG (Yellow) |
| D9 (PWM) | L298N | ENA | 22 AWG (Blue) - Remove jumper! |
| D7 (Digital) | L298N | IN3 | 22 AWG (Green) |
| D8 (Digital) | L298N | IN4 | 22 AWG (White) |
| D10 (PWM) | L298N | ENB | 22 AWG (Purple) - Remove jumper! |
| GND | L298N | GND | 20 AWG (Black) - CRITICAL BOND |
| D2 (Digital) | HC-SR04 | Trig | 22 AWG (Gray) |
| D3 (Digital) | HC-SR04 | Echo | 22 AWG (Brown) |
| 5V | HC-SR04 | VCC | 22 AWG (Red) |
| GND | HC-SR04 | GND | 22 AWG (Black) |
| N/A (Battery +) | L298N | 12V (VCC) | 18 AWG (Red) from 2S Holder |
| N/A (Battery -) | L298N | GND | 18 AWG (Black) from 2S Holder |
The L298N module has a 5V output pin and a jumper cap next to it. If your input voltage (from the 18650s) is under 12V, leave this jumper ON to power the Arduino via the L298N’s onboard 7805 linear regulator. If you use a 3S (11.1V) or 4S (14.8V) pack later, you MUST remove this jumper and supply the Arduino 5V separately, or you will fry the 7805 regulator.
Compilable Arduino Code
The following C++ code implements a basic obstacle-avoidance routine. It includes explicit pin definitions, motor control abstraction, and error handling for the HC-SR04 ultrasonic sensor. The pulseIn() function can hang indefinitely if the sensor fails to receive an echo; we enforce a strict timeout to prevent the robot from freezing.
#include <Arduino.h>
// --- Pin Definitions ---
#define ENA 9
#define IN1 5
#define IN2 6
#define ENB 10
#define IN3 7
#define IN4 8
#define TRIG_PIN 2
#define ECHO_PIN 3
// --- Constants ---
const int MOTOR_SPEED = 200; // PWM value (0-255)
const int TURN_SPEED = 150; // PWM value for turning
const long STOP_DISTANCE_CM = 20; // Obstacle threshold
const long ULTRASONIC_TIMEOUT_US = 30000; // 30ms timeout (~5 meters max)
void setup() {
Serial.begin(115200);
// Configure motor pins as outputs
pinMode(ENA, OUTPUT);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(ENB, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
// Configure ultrasonic pins
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
// Ensure motors are stopped on boot
stopMotors();
Serial.println("Robot Car Initialized. Scanning...");
}
void loop() {
long distance = getDistanceCM();
// Error handling: If sensor times out or returns garbage, halt safely
if (distance == 0 || distance > 400) {
Serial.println("Sensor Error: Timeout or out of range. Stopping.");
stopMotors();
delay(500);
return;
}
Serial.print("Distance: ");
Serial.print(distance);
Serial.println(" cm");
if (distance <= STOP_DISTANCE_CM) {
// Obstacle detected: Stop, reverse, and turn
stopMotors();
delay(200);
driveBackward(MOTOR_SPEED, 400);
turnRight(TURN_SPEED, 500);
} else {
// Path clear: Drive forward
driveForward(MOTOR_SPEED);
}
delay(50); // Small loop delay for stability
}
// --- Motor Control Functions ---
void driveForward(int speed) {
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
analogWrite(ENA, speed);
analogWrite(ENB, speed);
}
void driveBackward(int speed, int duration_ms) {
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
analogWrite(ENA, speed);
analogWrite(ENB, speed);
delay(duration_ms);
stopMotors();
}
void turnRight(int speed, int duration_ms) {
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
analogWrite(ENA, speed);
analogWrite(ENB, speed);
delay(duration_ms);
stopMotors();
}
void stopMotors() {
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, LOW);
analogWrite(ENA, 0);
analogWrite(ENB, 0);
}
// --- Sensor Functions with Error Handling ---
long getDistanceCM() {
// Clear the trigger pin
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
// Set the trigger pin HIGH for 10 microseconds
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// Read the echo pin, returns the sound wave travel time in microseconds
// The timeout parameter prevents infinite hanging if no echo is received
long duration = pulseIn(ECHO_PIN, HIGH, ULTRASONIC_TIMEOUT_US);
// Calculate distance (speed of sound = 343 m/s -> 29.1 us per cm, divided by 2 for round trip)
long distance = duration / 58.2;
return distance;
}
Debugging: First 3 Things to Check When It Fails
When your robot car refuses to move or behaves erratically, do not immediately rewrite the code. 90% of embedded hardware failures are electrical. Run through these three diagnostic steps first.
1. Verify the Logic Ground Bond
Symptom: The L298N relay clicks faintly, or the Arduino powers on but motors never spin regardless of code.
Fix: Check the wire connecting Arduino GND to L298N GND. The L298N uses optical isolation or BJT logic gates that require a shared reference voltage. Without this bond, the 5V signal from Arduino Pin D5 is floating relative to the L298N’s ground plane, and the chip reads it as 0V.
2. Remove the ENA and ENB Jumper Caps
Symptom: Motors spin at 100% speed and ignore your analogWrite() PWM commands, or the Arduino resets when motors start.
Fix: The L298N ships with metal jumper caps connecting ENA/ENB to a 5V logic rail. If you are using PWM pins (D9 and D10) to control speed, you must pull these jumpers off. Leaving them on creates a direct electrical short between the Arduino’s PWM output and the L298N’s internal 5V regulator when the PWM signal goes LOW.
3. Measure Voltage Sag Under Load
Symptom: The robot moves for one second, then the Arduino’s onboard LED dims and the board resets (brownout).
Fix: TT gearmotors draw ~200mA no-load, but up to 800mA at stall. If you are using cheap alkaline AA batteries, their high internal resistance causes the voltage to sag below the Arduino’s 7805 dropout threshold (~6.5V). Switch to high-discharge 18650 Li-ion cells (like the Molicel P26A) which can sustain 20A continuous discharge without sagging.
If you see the exact error string:
fatal error: NewPing.h: No such file or directoryRanked Causes:
1. You copied code from a tutorial using the NewPing library but haven’t installed it. Fix: Go to Sketch > Include Library > Manage Libraries, search "NewPing", and install.
2. You are using PlatformIO and forgot to add
lib_deps = marcoschwartz/NewPing to your platformio.ini file.3. Typo in the include statement (e.g.,
#include <newping.h> instead of #include <NewPing.h> on case-sensitive file systems like Linux).
Extending or Simplifying the Build
Once the base 2WD platform is reliable, you can scale the complexity up or down based on your application.
How to Simplify (Lower Cost & Complexity)
- Drop the Ultrasonic Sensor: Remove the HC-SR04 and rewrite the loop to use timed dead-reckoning (e.g., drive forward for 2 seconds, blind-turn right for 0.6 seconds). This eliminates sensor noise and wiring.
- Switch to 4x AA NiMH: If 18650s are too expensive or require a specialized charger, use 4x Eneloop Pro NiMH cells in a 4S AA holder. They provide a stable 4.8V - 5.2V. Note: You will need to wire the battery directly to the Arduino’s 5V pin, bypassing the L298N’s 12V input and onboard regulator entirely, as 5V is too low for the L298N logic to trigger reliably.
How to Extend (Advanced Robotics)
- Add I2C Dead Reckoning: Wire an MPU6050 accelerometer/gyroscope to the A4/A5 I2C pins. TT gearmotors have a 5-10% RPM variance, causing the car to pull to one side. Use the MPU6050’s Z-axis gyro data in a PID control loop to dynamically adjust the left/right PWM values and drive perfectly straight.
- Add Bluetooth RC Control: Integrate an HC-05 or JDY-31 BLE module on the hardware serial pins (D0/D1) or via SoftwareSerial. This allows you to drive the car manually using a smartphone app over UART.
Robot Car with Arduino FAQ
Can I power the robot car with Arduino Uno directly from the motor driver’s 5V pin?
Yes, but only under specific conditions. The L298N module features an onboard 7805 linear voltage regulator. If your battery pack is between 7V and 12V, and the 5V jumper cap on the L298N is installed, the module will step down the battery voltage to 5V and feed it to the Arduino via the 5V pin. However, linear regulators waste excess voltage as heat. If your battery pack exceeds 12V (like a 3S LiPo at 12.6V), the 7805 will overheat and trigger its internal thermal shutdown, killing power to the Arduino. For packs over 12V, remove the jumper and use a dedicated buck converter (like an LM2596) to supply the Arduino.
Why does my robot car with Arduino pull to one side when driving straight?
This is a mechanical and electrical reality of cheap TT gearmotors. They are manufactured with loose tolerances, resulting in a natural 5% to 10% RPM variance between the left and right motors. Additionally, the L298N H-bridge has slight internal resistance differences between Channel A and Channel B. To fix this without adding a gyroscope, perform a "trim test": place the car on a stand, run both motors at PWM 255, measure the actual RPM with a tachometer (or count wheel spoke passes), and reduce the PWM value of the faster motor by 10-20 points in your code until they match.
What is the best battery chemistry for a 2WD Arduino robot car in 2026?
For hobbyist 2WD platforms, a 2S (7.4V nominal) Lithium-Ion 18650 pack is the undisputed standard. Li-ion offers high energy density and, crucially, a low internal resistance that can supply the 1.5A+ spike current required when both TT motors start from a dead stop or stall against an obstacle. Avoid 9V alkaline batteries entirely; their internal resistance is so high that voltage collapses to under 4V under motor load, instantly resetting the Arduino. While LiPo (Lithium Polymer) packs offer similar performance in a lighter package, they pose a severe puncture and fire risk on beginner chassis that lack protective battery enclosures. Always use a proper 2S Li-ion balance charger and never discharge cells below 3.0V per cell to prevent permanent capacity degradation (Battery University Lithium-Ion Safety).






