Obstacle-Avoiding Robot with HC-SR04 and Arduino

This is the project that makes people say “it’s alive”: the car drives around a room, stops before hitting things, looks left and right, and picks the open path. It builds directly on the 2WD robot car — same chassis, same drive code, plus one sensor and one servo.

How the HC-SR04 works

The HC-SR04 is sonar: pulse the TRIG pin for 10 µs and it emits an ultrasonic chirp at 40 kHz; the ECHO pin then goes HIGH until the reflection returns. Sound covers about 1 cm in 58 µs round-trip, so distance_cm = echo_time_µs / 58. Practical range is 2 cm to ~3–4 m, in a cone roughly 15° wide. Soft, angled, or very thin objects (curtains, chair legs) reflect poorly — that is physics, not a bug, and the code below treats “no echo” as open space for that reason.

Extra parts needed

Additions to the robot car
PartNotesIndicative price (India)
HC-SR04 ultrasonic sensorThe 4-pin classic₹60–120
SG90 micro servo (9 g)Pan the sensor left/right₹90–150
Sensor bracket / mount for HC-SR04 + servo hornOr a zip-tie-and-hot-glue solution₹40–100
Female–female jumpers ×7Sensor and servo leads₹40–70
About prices

Prices shown are indicative online street prices in India as of mid-2026. They vary by seller and stock — treat them as a budgeting guide, not a quote.

Mounting and wiring

Mount the servo at the front centre of the chassis and fix the HC-SR04 to the servo horn facing forward at the 90° position — eyes level, not tilted at the floor.

Wiring additions
Module pinConnects toNote
HC-SR04 VCCArduino 5V 
HC-SR04 GNDArduino GND 
HC-SR04 TRIGArduino D12Output
HC-SR04 ECHOArduino D11Input
Servo brownGND 
Servo redL298N 5V rail / 5 V supplySee warning below
Servo orangeArduino D9Signal
Servo library vs PWM pins

On an Uno, attaching the Servo library disables analogWrite on pins 9 and 10. That is exactly why the Hobby Robots pinout puts motor PWM on D5 and D6 — if you wired ENA/ENB to 9/10 from another tutorial, your motors will mysteriously stop working the moment the servo attaches.

Servo power

A moving SG90 can draw a few hundred mA in spikes. Powering one small servo from the L298N’s 5 V regulator output is generally OK; powering it from the Arduino’s 5 V pin while on USB is asking for resets. If the Arduino reboots whenever the servo moves, that is your clue.

Test the sensor alone

Wheels off the ground, upload a minimal sketch that prints readDistanceCm() (copy the function from the code below) every 200 ms and watch the Serial Monitor while moving a book toward and away from the sensor. You should see stable centimetre readings from ~3 cm to a couple of metres. Do not proceed until this works — debugging sonar and driving logic at the same time is misery.

The full roaming code

// Hobby Robots — obstacle-avoiding robot
// Drive pinout as per the robot car guide. Servo on D9, HC-SR04 on D11/D12.
#include <Servo.h>

const int ENA = 5, IN1 = 7, IN2 = 8;
const int ENB = 6, IN3 = 4, IN4 = 2;
const int TRIG = 12, ECHO = 11;
const int SERVO_PIN = 9;

const int SAFE_CM   = 25;    // closer than this = obstacle
const int CRUISE    = 170;

Servo neck;

void drive(int left, int right) {
  digitalWrite(IN1, left  >= 0 ? HIGH : LOW);
  digitalWrite(IN2, left  >= 0 ? LOW  : HIGH);
  analogWrite (ENA, min(abs(left), 255));
  digitalWrite(IN3, right >= 0 ? HIGH : LOW);
  digitalWrite(IN4, right >= 0 ? LOW  : HIGH);
  analogWrite (ENB, min(abs(right), 255));
}

long readDistanceCm() {
  digitalWrite(TRIG, LOW);  delayMicroseconds(2);
  digitalWrite(TRIG, HIGH); delayMicroseconds(10);
  digitalWrite(TRIG, LOW);
  long us = pulseIn(ECHO, HIGH, 25000UL);   // ~4 m timeout
  if (us == 0) return 400;                  // no echo: treat as clear
  return us / 58;                           // microseconds -> cm
}

long lookAt(int angle) {        // 0 = right, 90 = ahead, 180 = left
  neck.write(angle);
  delay(350);                   // let the servo arrive
  return readDistanceCm();
}

void setup() {
  pinMode(ENA, OUTPUT); pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT);
  pinMode(ENB, OUTPUT); pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT);
  pinMode(TRIG, OUTPUT); pinMode(ECHO, INPUT);
  neck.attach(SERVO_PIN);
  neck.write(90);
  delay(2000);
}

void loop() {
  if (readDistanceCm() > SAFE_CM) {
    drive(CRUISE, CRUISE);              // path is clear
    delay(60);
    return;
  }
  // Obstacle: stop, back off, look both ways, take the open side.
  drive(0, 0);              delay(150);
  drive(-150, -150);        delay(350);
  drive(0, 0);
  long right = lookAt(15);
  long left  = lookAt(165);
  neck.write(90);
  if (left > right) drive(-160, 160);   // rotate left
  else              drive(160, -160);   // rotate right
  delay(420);                           // ~90 degrees; tune this
  drive(0, 0);
}

Tuning and behaviour tweaks

  • Stops too late: raise SAFE_CM, or lower CRUISE — stopping distance grows with speed.
  • Turn angle wrong: the delay(420) spin is open-loop; tune it per surface (carpet needs more, tile less). Wheel encoders fix this properly.
  • Twitchy near walls: average 3 readings and act on the median to reject the HC-SR04’s occasional ghost echo.
  • Make it smarter: scan 5 angles instead of 2 and steer proportionally toward the most open direction.

Troubleshooting

Symptoms and causes
SymptomCauseFix
Distance always 0 or 400TRIG/ECHO swapped, or 3.3 V supplyHC-SR04 wants 5 V; re-check D11/D12
Arduino resets when servo movesServo powered from Uno 5 V on USBFeed the servo from the L298N 5 V rail
Motors die when servo attachesENA/ENB wired to pins 9/10Move motor PWM to D5/D6 as per this guide
Robot circles endlesslyOne motor reversed or much weakerRe-run the robot car spin test; swap motor wires
Ignores thin chair legsNarrow objects reflect little ultrasoundNormal — add IR “whisker” sensors or a bumper switch

Next steps