If you are building an arduino obstacle avoiding robot, the difference between a rover that navigates smoothly and one that spasms into a wall usually comes down to power delivery and sensor timing. This guide targets the Arduino Uno R3 (ATmega328P variant). We bypass the vague wiring diagrams found in starter kits and provide exact pin mappings, a robust C++ codebase with serial error handling, and a hardware decision framework to ensure your motors actually get the voltage they need.

The Verdict: Which Chassis and Driver Combo to Pick

Before buying parts, you need to match your motor driver to your chassis payload. The L298N is the default for beginners, but it has a massive voltage drop. Use this decision tree to lock in your hardware.

If your scenario is...Then pick this DriverAnd this Chassis
Budget < $30, indoor use, payload < 500gL298N Dual H-Bridge2WD TT Motor Acrylic Chassis
Budget $30-$50, outdoor/carpet, payload > 500gTB6612FNG (MOSFET)4WD TT Motor Chassis
Need precision, dead-reckoning, or heavy payloadDRV8833 + EncodersMetal-gear 2WD with encoder disks

Default Pick for this Build: We are proceeding with the 2WD TT Motor Chassis and the L298N driver. It is the most widely documented baseline, and the code provided below maps directly to it.

Exact Parts List & Spec Sheet

Do not substitute the battery pack. The standard 4x AA (6V) holder included in most kits will cause brownouts when the motors stall. Use a 2S LiPo.

ComponentExact Model / VariantEst. Price (2026)Critical Spec
MicrocontrollerArduino Uno R3 (ATmega328P DIP)$24.005V logic, 20mA max per GPIO
Motor DriverL298N Dual Full-Bridge Driver$4.50~2V voltage drop, 2A peak per channel
SensorHC-SR04 Ultrasonic (5V tolerant)$2.0015° beam angle, 2cm-400cm range
Scanner ServoTowerPro SG90 Micro Servo$3.50180° rotation, 1.8kg/cm torque
Chassis2WD Acrylic Base + TT Gearmotors$12.003-6V nominal, 200 RPM no-load
Power Source2S LiPo Battery (7.4V, 1500mAh+)$18.00Minimum 20C discharge rating

Pin Mapping & Wiring Steps

The number one reason an HC-SR04 returns garbage data on a moving robot is a missing common ground. The Arduino, L298N, and HC-SR04 must share the exact same GND reference.

Component PinArduino Uno R3 PinNotes
HC-SR04 VCC5VDo not use 3.3V; echo pulse will be weak.
HC-SR04 GNDGNDMust tie to L298N GND.
HC-SR04 TrigD9Output
HC-SR04 EchoD10Input (5V tolerant on Uno)
SG90 SignalD11PWM required
L298N IN1D5Right Motor Logic
L298N IN2D6Right Motor Logic
L298N IN3D7Left Motor Logic
L298N IN4D8Left Motor Logic
L298N ENA & ENBD3 & D4 (or 5V)Jumpers ON for full speed, or use PWM pins.
L298N 12V InLiPo + (Red)7.4V nominal.
L298N GNDLiPo - (Black) + Uno GNDCRITICAL COMMON GROUND
Warning: The L298N has an onboard 7805 voltage regulator. If your input voltage is < 12V, leave the 5V-EN jumper ON to power the logic side. However, do not draw more than 50mA from the L298N's 5V output pin, or you will overheat the regulator. Power the SG90 servo directly from the Arduino's 5V pin instead.

Numbered Assembly Steps

  1. Mount the L298N: Bolt it to the rear of the chassis. Keep the 5V-EN jumper installed since we are using a 7.4V LiPo.
  2. Wire Power: Connect the LiPo XT60 pigtail to the L298N 12V and GND screw terminals. Do not connect the Arduino yet.
  3. Establish Common Ground: Run a jumper wire from the L298N GND terminal to one of the Arduino Uno GND pins.
  4. Mount the Servo: Fix the SG90 to the front center of the chassis. Route the wires under the acrylic plate to avoid snagging.
  5. Connect Logic: Wire the IN1-IN4 pins to D5-D8 as per the table above. Connect HC-SR04 and Servo signal wires.
  6. Verify: Before plugging in the LiPo, use a multimeter in continuity mode to beep-test the GND path from the L298N terminal to the Arduino GND pin, and to the HC-SR04 GND pin.

Complete Compilable Code (Arduino Uno R3)

This sketch uses the built-in Arduino Servo library. It includes a serial debugging toggle and explicit timeout handling for the pulseIn() function to prevent the robot from freezing if the ultrasonic sensor misses an echo.

#include <Servo.h>

// --- PIN DEFINITIONS ---
#define TRIG_PIN 9
#define ECHO_PIN 10
#define SERVO_PIN 11

#define RIGHT_FWD 5
#define RIGHT_BWD 6
#define LEFT_FWD 7
#define LEFT_BWD 8

// --- CONFIGURATION ---
#define DEBUG true
#define STOP_DISTANCE 25 // cm
#define SCAN_DELAY 400   // ms, allow servo to settle
#define MAX_DISTANCE 200 // cm, sensor timeout threshold

Servo scanServo;

void setup() {
  if (DEBUG) Serial.begin(9600);
  
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  
  pinMode(RIGHT_FWD, OUTPUT);
  pinMode(RIGHT_BWD, OUTPUT);
  pinMode(LEFT_FWD, OUTPUT);
  pinMode(LEFT_BWD, OUTPUT);
  
  scanServo.attach(SERVO_PIN);
  scanServo.write(90); // Center position
  delay(1000);
  
  stopMotors();
  if (DEBUG) Serial.println("[SYS] Arduino Obstacle Avoiding Robot Initialized.");
}

void loop() {
  int frontDist = readDistance();
  
  if (frontDist < STOP_DISTANCE) {
    if (DEBUG) Serial.println("[ACT] Obstacle detected. Stopping.");
    stopMotors();
    delay(200);
    
    int leftDist = scanDirection(160);
    int rightDist = scanDirection(20);
    
    scanServo.write(90); // Return to center
    delay(SCAN_DELAY);
    
    if (leftDist > rightDist) {
      if (DEBUG) Serial.println("[NAV] Turning Left.");
      turnLeft();
      delay(400);
    } else if (rightDist > leftDist) {
      if (DEBUG) Serial.println("[NAV] Turning Right.");
      turnRight();
      delay(400);
    } else {
      if (DEBUG) Serial.println("[NAV] Dead end. Reversing.");
      reverseMotors();
      delay(600);
    }
  } else {
    moveForward();
  }
  delay(50);
}

int readDistance() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  
  // Timeout set to ~34ms (Max distance ~5 meters)
  long duration = pulseIn(ECHO_PIN, HIGH, 34000);
  
  if (duration == 0) {
    if (DEBUG) Serial.println("[ERR] HC-SR04 Echo timeout. Check Trig/Echo wiring.");
    return MAX_DISTANCE; // Fail-safe: assume path is clear if sensor errors
  }
  
  int distance = duration * 0.034 / 2;
  return distance;
}

int scanDirection(int angle) {
  scanServo.write(angle);
  delay(SCAN_DELAY);
  return readDistance();
}

void moveForward() {
  digitalWrite(RIGHT_FWD, HIGH); digitalWrite(RIGHT_BWD, LOW);
  digitalWrite(LEFT_FWD, HIGH);  digitalWrite(LEFT_BWD, LOW);
}

void stopMotors() {
  digitalWrite(RIGHT_FWD, LOW); digitalWrite(RIGHT_BWD, LOW);
  digitalWrite(LEFT_FWD, LOW);  digitalWrite(LEFT_BWD, LOW);
}

void reverseMotors() {
  digitalWrite(RIGHT_FWD, LOW); digitalWrite(RIGHT_BWD, HIGH);
  digitalWrite(LEFT_FWD, LOW);  digitalWrite(LEFT_BWD, HIGH);
}

void turnLeft() {
  digitalWrite(RIGHT_FWD, HIGH); digitalWrite(RIGHT_BWD, LOW);
  digitalWrite(LEFT_FWD, LOW);   digitalWrite(LEFT_BWD, HIGH);
}

void turnRight() {
  digitalWrite(RIGHT_FWD, LOW);  digitalWrite(RIGHT_BWD, HIGH);
  digitalWrite(LEFT_FWD, HIGH);  digitalWrite(LEFT_BWD, LOW);
}

Debugging: The First Three Things to Check When It Fails

Embedded hardware rarely works perfectly on the first power-on. When your rover fails, follow this ranked diagnostic path based on exact symptoms.

1. Symptom: Arduino Resets Silently When Motors Engage

The Cause: Voltage brownout. TT motors can draw 800mA+ each during stall/startup. If your battery cannot supply this current spike, the voltage drops below the Arduino's 2.7V brownout threshold, triggering a hardware reset. You won't get a serial error string; the Uno just reboots and the onboard 'L' LED flickers.

The Fix: Solder a 1000µF electrolytic capacitor directly across the L298N's 12V and GND screw terminals to act as a local energy buffer. If the issue persists, your LiPo's C-rating is too low; upgrade to a 20C or 30C pack.

2. Symptom: Serial Monitor Prints '[ERR] HC-SR04 Echo timeout'

The Cause: The pulseIn() function hit the 34ms timeout without seeing a HIGH pulse on the Echo pin. This almost always means the Echo pin is being pulled LOW, or the sensor isn't firing.

The Fix:

  1. Verify the Common Ground. If the HC-SR04 GND isn't tied to the Uno GND, the 5V logic pulse has no return path.
  2. Check that you haven't accidentally wired the Echo pin to an analog-only pin (A0-A5) without configuring it as a digital input.
  3. Measure the HC-SR04 VCC pin with a multimeter while the motors are running. If it drops below 4.5V, the sensor will fail to trigger the piezo element. Power the HC-SR04 directly from the Arduino 5V pin, not the L298N 5V output.

3. Symptom: Compiler Error: 'Servo' does not name a type

The Exact Error String: error: 'Servo' does not name a type; did you mean 'Serial'?

The Cause: The IDE cannot find the Servo library header.

The Fix: Ensure #include <Servo.h> is at the very top of your sketch. In the Arduino IDE, go to Sketch > Include Library > Servo. This library is built-in for the Uno R3 ATmega328P, but if you are using an ESP32 or Arduino R4 Minima, you may need to install the ESP32Servo or official R4 Servo wrapper via the Library Manager.

Extending or Simplifying the Build

Once the baseline rover is navigating, you need to decide whether to strip it down for reliability or scale it up for autonomy.

How to Simplify (For Reliability)

Servos introduce mechanical failure points and draw continuous idle current. To simplify:

  • Remove the SG90 Servo. Mount the HC-SR04 facing forward.
  • Update the Logic: If frontDist < STOP_DISTANCE, stop, reverse for 500ms, turn right 90 degrees (via timed delay), and resume. This 'bump-and-turn' logic eliminates servo jitter and reduces code complexity by 40%.

How to Extend (For Precision)

The L298N and TT motors lack feedback, meaning a 400ms turn delay might yield 85° on carpet and 110° on hardwood. To fix this:

  • Upgrade the Driver: Swap the L298N for a TI DRV8833. It uses MOSFETs instead of BJTs, dropping only ~0.2V instead of 2V, giving your motors significantly more torque.
  • Add Encoders: Install slotted optical encoders on the TT motor shafts. Use hardware interrupts on the Arduino to count ticks, implementing a basic PID loop to ensure both wheels spin at the exact same RPM, resulting in perfectly straight lines.

Bench Tip: When tuning your STOP_DISTANCE, remember that the HC-SR04 has a 15-degree beam angle. If your robot approaches a wall at a sharp angle, the acoustic wave will reflect away from the receiver, causing a false 'clear' reading. Keep your stop threshold above 20cm to allow the beam to bounce back reliably from angled surfaces.