Project Overview & Difficulty Rating

This guide walks you through building a 2WD obstacle-avoiding arduino bot using the Arduino Uno R3 (ATmega328P). While the newer Uno R4 Minima is available, the R3 remains the standard for 5V logic motor drivers and PWM timer compatibility out of the box. We pair it with an L298N dual H-bridge and an HC-SR04 ultrasonic sensor to create a rover that navigates autonomously.

Spec Sheet & Difficulty Rating

  • Target Board: Arduino Uno R3 (ATmega328P)
  • Build Time: 90 - 120 minutes
  • Estimated Cost: $35 - $45 (excluding soldering iron/tools)
  • Skill Level: Intermediate (Requires understanding of PWM, H-bridges, and Li-ion safety)

Exact Parts List & Component Variants

Do not substitute the motor driver or battery chemistry without recalculating voltage drops. The TT gear motors included in most chassis kits stall at ~800mA; the L298N handles this, but smaller drivers like the L293D will overheat and trigger thermal shutdown.

Component Exact Variant / Model 2026 Price Est. Critical Notes
Microcontroller Arduino Uno R3 (Rev3) $27.00 Ensure it is the ATmega328P DIP or SMD variant. Code targets R3 timers.
Motor Driver L298N Dual H-Bridge Module $6.50 Red PCB variant. Drops ~2V across the Darlingtons (TI L298 Datasheet).
Range Sensor HC-SR04 Ultrasonic $3.00 5V logic. Do not use the 3.3V HC-SR04P variant without a level shifter.
Chassis & Motors 2WD Smart Car Kit (TT Motors) $12.00 Yellow TT motors rated 3-6V, 200 RPM no-load.
Power Supply 2S 18650 Holder + 2x Li-ion $18.00 Use Samsung 25R or Molicel P26A. Never use unprotected cells in parallel.

Pin Mapping & Wiring Steps

Proper wiring is where most builds fail. The L298N requires a shared ground reference with the Arduino, and the PWM enable pins must be freed from their default 5V jumper caps.

Arduino Uno R3 Pin L298N / Sensor Pin Function
D5 (PWM)ENALeft Motor Speed Control
D4IN1Left Motor Direction A
D7IN2Left Motor Direction B
D6 (PWM)ENBRight Motor Speed Control
D8IN3Right Motor Direction A
D12IN4Right Motor Direction B
D9HC-SR04 TrigSensor Trigger Pulse
D10HC-SR04 EchoSensor Echo Return
GNDGND (L298N & Sensor)Common Ground (CRITICAL)
5VVCC (HC-SR04 only)Sensor Logic Power
Wiring Step 1: Remove the two jumper caps on the L298N labeled ENA and ENB. If left in place, the motors will run at 100% speed and ignore your PWM code.

Wiring Step 2: Connect the 2S 18650 battery holder's positive (red) wire to the L298N 12V terminal, and the negative (black) wire to the L298N GND terminal.

Wiring Step 3: Run a jumper wire from the L298N GND terminal to the Arduino Uno GND pin. Without this common ground, the logic signals will float and the motors will stutter or spin erratically.

Complete Compilable Code

This C++ code is written for the Arduino IDE (2.x or 1.8.x). It includes explicit pin definitions, non-blocking sensor timeouts to prevent the bot from freezing, and a modular movement function. Arduino Uno R3 Documentation confirms D5 and D6 use Timer 0 and Timer 2, which is ideal for balanced motor PWM.

// Target Board: Arduino Uno R3 (ATmega328P)
// Ultrasonic Obstacle Avoiding Arduino Bot

// --- PIN DEFINITIONS ---
const int TRIG_PIN = 9;
const int ECHO_PIN = 10;

// Left Motor (L298N)
const int ENA = 5;   // PWM
const int IN1 = 4;
const int IN2 = 7;

// Right Motor (L298N)
const int ENB = 6;   // PWM
const int IN3 = 8;
const int IN4 = 12;

// --- CONFIGURATION ---
const int MAX_SPEED = 200;      // PWM 0-255
const int TURN_SPEED = 150;
const int STOP_DISTANCE = 20;   // cm
const long SENSOR_TIMEOUT = 30000; // microseconds (30ms)

void setup() {
  Serial.begin(115200);
  
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  
  pinMode(ENA, OUTPUT);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(ENB, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  
  // Ensure motors are stopped on boot
  moveMotors(0, 0);
  Serial.println("Arduino Bot Initialized.");
}

void loop() {
  int distance = readUltrasonic();
  
  // Error handling for sensor timeout or invalid reads
  if (distance == 0 || distance > 400) {
    Serial.println("Error: Sensor timeout (0 cm)");
    moveMotors(0, 0); // Fail-safe: stop immediately
    delay(500);
    return;
  }
  
  Serial.print("Distance: ");
  Serial.print(distance);
  Serial.println(" cm");
  
  if (distance <= STOP_DISTANCE) {
    // Obstacle detected: Stop, Reverse, Turn
    moveMotors(0, 0);
    delay(200);
    moveMotors(-MAX_SPEED, -MAX_SPEED); // Reverse
    delay(400);
    moveMotors(-TURN_SPEED, TURN_SPEED); // Pivot right
    delay(500);
  } else {
    // Path clear: Drive forward
    moveMotors(MAX_SPEED, MAX_SPEED);
  }
  
  delay(50); // Loop pacing
}

// --- HELPER FUNCTIONS ---
int readUltrasonic() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  
  long duration = pulseIn(ECHO_PIN, HIGH, SENSOR_TIMEOUT);
  
  if (duration == 0) return 0; // Timeout triggered
  
  // Calculate distance (speed of sound = 343 m/s -> 29.1 us per cm, divided by 2 for round trip)
  int distance = duration / 58.2; 
  return distance;
}

void moveMotors(int leftSpeed, int rightSpeed) {
  // Left Motor Logic
  if (leftSpeed > 0) {
    digitalWrite(IN1, HIGH);
    digitalWrite(IN2, LOW);
  } else if (leftSpeed < 0) {
    digitalWrite(IN1, LOW);
    digitalWrite(IN2, HIGH);
  } else {
    digitalWrite(IN1, LOW);
    digitalWrite(IN2, LOW);
  }
  analogWrite(ENA, abs(leftSpeed));
  
  // Right Motor Logic
  if (rightSpeed > 0) {
    digitalWrite(IN3, HIGH);
    digitalWrite(IN4, LOW);
  } else if (rightSpeed < 0) {
    digitalWrite(IN3, LOW);
    digitalWrite(IN4, HIGH);
  } else {
    digitalWrite(IN3, LOW);
    digitalWrite(IN4, LOW);
  }
  analogWrite(ENB, abs(rightSpeed));
}

Debugging: First 3 Checks & Common Errors

When your arduino bot fails to move or navigates erratically, do not immediately rewrite the code. Hardware and power delivery account for 90% of embedded failures.

The First Three Things to Check

  1. Common Ground Integrity: Measure resistance between the Arduino GND pin and the L298N GND terminal with the power off. It must read < 1 ohm. If it is higher, your logic signals are floating.
  2. ENA/ENB Jumper Caps: Visually verify the metal jumper caps on the L298N are removed. If they are installed, the module overrides your PWM pins and feeds 5V directly to the enable logic, locking the motors at 100% duty cycle.
  3. Battery Voltage Sag Under Load: TT motors draw ~800mA at stall. If your 18650 cells are depleted or low-quality, the voltage will sag below 6.5V when the bot starts moving. The L298N drops ~2V, leaving the motors with 4.5V, while the Arduino's onboard regulator struggles to maintain 5V logic, causing brownouts.

Resolving: Error: Sensor timeout (0 cm)

If your serial monitor repeatedly prints the exact string Error: Sensor timeout (0 cm), the pulseIn() function hit the 30ms limit without seeing the echo pin go HIGH. Ranked causes:

  1. Swapped Trig/Echo Wires: The most common breadboard mistake. Verify D9 goes to Trig and D10 goes to Echo.
  2. Power Rail Brownout: The HC-SR04 requires a stable 5V. If the motors draw heavy current and drag the 5V rail down to 4.2V, the sensor's internal oscillator fails to trigger. Measure the 5V pin with a multimeter while the motors are spinning.
  3. Acoustic Absorption / Angles: Ultrasonic sensors bounce poorly off soft materials (couches, curtains) or angled walls. The sound wave scatters and never returns to the receiver. Test the bot against a hard, flat surface like a cardboard box.

Extending vs. Simplifying the Build

Depending on your parts bin and project goals, you can scale this arduino bot up or down.

How to Simplify

If you lack PWM-capable pins or want to reduce code complexity, wire ENA and ENB to standard digital pins (e.g., D2 and D3) and leave the L298N jumper caps installed. You lose variable speed control, but the bot will run at full speed using simple HIGH/LOW logic.

How to Extend

Swap the HC-SR04 for a VL53L0X Time-of-Flight I2C sensor. It uses an infrared laser, eliminating acoustic blind spots and angled-wall scattering. Add an MPU6050 IMU via I2C to implement dead-reckoning and PID-controlled straight-line driving.

Arduino Bot FAQ

How do I make my Arduino bot follow a line instead of avoiding obstacles?

To convert this into a line-following arduino bot, remove the HC-SR04 and mount two or three TCRT5000 infrared reflectance sensors on the front bumper, pointing down at the floor. Wire their digital outputs to the Uno. In the code, replace the readUltrasonic() logic with a differential steering algorithm: if the left sensor sees black (low reflectivity), reduce left motor speed to steer left; if the right sees black, steer right. You will need to calibrate the sensor threshold potentiometers on the TCRT5000 modules for your specific track tape color.

Why is my Arduino bot drifting to one side when driving straight?

Drifting is caused by three factors: mechanical friction differences in the TT motor gearboxes, uneven battery voltage distribution across the L298N channels, or slight PWM timing offsets. To fix it in software, introduce a steering bias constant. If the bot pulls right, reduce the right motor PWM by 10-15 points in the moveMotors() function (e.g., analogWrite(ENB, abs(rightSpeed) - 15);). For a hardware fix, swap the left and right motors to rule out a defective gearbox.

Can I power an Arduino bot directly from the Uno's 5V pin?

No. The Arduino Uno's onboard 5V linear regulator (typically an NCP1117 or similar) is rated for roughly 800mA to 1A maximum, and that assumes adequate heat dissipation. TT motors draw 200mA no-load and up to 800mA at stall each. If you wire motors to the 5V pin, the regulator will overheat, trigger thermal shutdown, and potentially destroy the Uno's voltage regulator or USB interface IC. Always use a dedicated battery pack routed through a motor driver like the L298N.