Build pathBeginnerA weekend

Build an Obstacle-Avoiding Robot: Sense, Scan, and Steer

A robot that roams on its own—sensing obstacles, scanning for openings, and turning toward clear space—built from parts you understood and tuned in simulation first.

Build an Obstacle-Avoiding Robot: Sense, Scan, and Steer technical schematicCLEARANCE FIELD

An obstacle-avoiding robot is the natural next build after a line follower. A line follower follows—it tracks a line someone drew for it. This robot decides: with no track and no map, it senses the space around it and chooses where to go. That one difference—reacting to the world instead of following it—is the first real taste of autonomy, and it is still simple enough to understand completely.

The core is a short, repeating loop: sense–scan–decide–turn. The HC-SR04 ultrasonic sensor pings forward and times the echo to estimate distance; when something is closer than a safety threshold, the robot stops, sweeps the sensor left and right on an SG90 servo, and turns toward the most open bearing. That threshold is not arbitrary — it is a safety distance built from current speed, sense-decide-actuate latency, braking distance (which grows with the square of speed), the robot’s radius and a margin, all visible as the stopping-distance curve in the simulator.

You add components a mobile robot needs and learn what each one does: an Arduino Uno for forgiving 5 V logic, the ultrasonic sensor and its blind zone (the minimum range below which it cannot report), the servo that gives the beam a second viewpoint, the L298N H-bridge that switches motor current the logic pins cannot provide, two TT gearmotors where the gearbox trades speed for usable torque, a 2WD chassis with a caster for differential steering, and a battery pack that must feed motor and logic on separate rails. The tech tree also carries you through two learning roadmaps — motor control and reactive navigation — so the same PWM, odometry and filtering ideas you met in the line follower return here in a navigation context.

Then — before spending anything or risking a miswire — tune the avoidance behaviour in the browser simulator until it navigates a cluttered space cleanly. The workspace there is top-down and two-dimensional with instant, noise-free rays; a real ultrasonic beam spreads about 15°, is blocked by the robot’s own body, and is disturbed by soft or angled surfaces, so you will filter readings and add a median filter and a short settle delay after the servo moves before trusting a distance on hardware. Finding a safe stopping distance and a clear-direction rule in simulation removes most of the guesswork before the robot ever moves.

Only then do you wire the real robot — trigger and echo to the correct voltage, servo signal to a PWM-capable pin, motor PWM and direction to the driver, motor battery to the driver’s VM pin only, every ground tied together — and let it roam a floor with boxes or chairs. The same sensing and filtering lessons lead directly into the Micromouse walled maze if you later want mapping, or into ROS 2 navigation if you add a Raspberry Pi.

Follow the tech tree below top to bottom. Each node opens once its prerequisites are done, and your progress is saved on this device, so you can build the robot over a weekend without losing your place.

Bill of materials

Part Qty Approx. cost Notes
Arduino Uno 1 $5–8 5 V logic is genuinely helpful here — the HC-SR04’s echo is 5 V
HC-SR04 1 $2 A VL53L0X is a good second sensor, not a replacement
SG90 servo 1 $2 For the scanning head. MG90S if it will run for hours
L298N 1 $2–4 Or a TB6612FNG, which wastes far less of the battery
TT gearmotor 2 $4
2WD chassis 1 $6–10
Battery pack 1 $6 6×AA NiMH or 2×18650
Bump switches 2 $1 Add these. See below

Total: roughly $30–40.

The two bump switches are the best forty cents on the robot, and they are the part most builds leave out. Every ranging sensor has surfaces it cannot see — a sonar is blind to curtains and to walls met at a steep angle — and a robot with no contact sensing will push a curtain until something gives. Two switches behind a wrapped bumper turn “usually avoids things” into “never gets stuck against something it could not see”.

How it all connects

From To Note
HC-SR04 VCC, GND 5 V, GND ~15 mA, spiking during a ping
HC-SR04 Trig D9 Any digital pin
HC-SR04 Echo D10 5 V output — fine on an Uno, needs a divider on a 3.3 V board
Servo signal D6 The Servo library uses Timer 1, which also drives D9/D10 PWM
Servo power Separate 5 V, common ground 650 mA stalled — not the Arduino’s 5 V pin
Driver ENA, ENB D5, D3 PWM-capable pins. Remove the L298N’s enable jumpers
Driver IN1–IN4 D8, D7, D4, D2
Bump switches D11, D12, INPUT_PULLUP COM to ground, NO to the pin
Battery + Driver VM / +12V Never the Arduino
All grounds One point Arduino, driver, servo supply, battery negative

Watch the timer conflict: the Servo library takes over Timer 1, which on an Uno drives PWM on pins 9 and 10. Put the motor PWM on 3, 5, 6 or 11 and the servo on any pin, and the problem never arises. Put a motor enable on pin 9 and its speed control will silently stop working the moment you attach a servo.

The stopping distance, computed rather than guessed

The stop threshold is the single most important number in this project, and it is not arbitrary. It is the sum of four distances:

stop_distance = (v x t_latency) + (v^2 / (2 x a_brake)) + robot_radius + margin
Term Where it comes from Typical
Sensing and decision latency Ping (up to 25 ms), servo settle, loop period 60–100 ms
Braking distance Speed squared over twice the deceleration Grows fast
Robot radius Front of the chassis to the pivot centre 80–100 mm
Margin Because the sensor cone is 15° wide and lies about soft things 50 mm

Worked, for a robot at 0.3 m/s with 80 ms of latency and 1.0 m/s² of braking:

= (0.3 x 0.08) + (0.09 / 2.0) + 0.09 + 0.05
= 0.024 + 0.045 + 0.09 + 0.05 = 0.21 m

So about 21 cm. Now double the speed to 0.6 m/s:

= 0.048 + 0.18 + 0.09 + 0.05 = 0.37 m

The threshold has not doubled — it has grown by 76%, because the braking term goes with the square of speed. This is why a robot that avoids reliably at walking pace starts hitting things when you speed it up, and why the fix is a speed-dependent threshold rather than one large fixed number that makes the robot timid everywhere.

Build it in milestones

# Milestone The test A pass looks like
1 Motors drive Forward, reverse, pivot both ways on blocks All six states work; you know each wheel’s deadband
2 Distance reads Point at a wall at 30 cm and print for a minute Steady within a centimetre or two, no zeros
3 Timeout works Aim at open air and at the ceiling The loop keeps its rate — no echo must not mean a frozen robot
4 Median filter Wave a hand repeatedly through the beam Wild single readings vanish; the real approach still registers
5 Servo sweeps Command −60°, 0°, +60° and print distance at each Repeatable sweep to sweep, with a settle delay before each ping
6 Settle delay proven Remove the delay deliberately Readings smear across angles — now you know that failure
7 Stop threshold Drive at a wall and let it stop It stops with your computed margin, not by luck
8 Turn decision Place it facing a corner with one open side It turns toward the open side, not randomly
9 Hysteresis Park it hovering at the threshold It commits to a decision instead of stuttering
10 Bump recovery Drive it at a cushion Sonar misses it, the switch catches it, the robot backs off and turns
11 Free roam Five minutes in a cluttered room Survives; when it does get stuck you can name the state

Milestone 10 is the one that separates a demo from a robot. A cushion absorbs the ultrasonic pulse entirely, so the sensor reports open space and the robot drives into it at full speed. Without a bump switch it then pushes until the motors stall.

Troubleshooting

Symptom Likely cause Fix
Robot freezes at random intervals pulseIn with no timeout Pass a 25000 µs timeout; handle “no echo” explicitly
Emergency-stops in an empty room Treating a timeout as 0 cm A timeout means far, not near. Return a sentinel
Drives into curtains and cushions Sound absorbed — physics, not a bug Add bump switches
Drives into walls at an angle Ping reflecting away from the receiver Same fix; also scan more angles
Turns confidently into a wall Reading before the servo settled Add 100–200 ms after commanding the angle, before pinging
Stutters at obstacles One threshold, no hysteresis Stop at 20 cm, do not resume until 30 cm
Servo jitters, board resets Servo current through the Arduino Separate 5 V supply for the servo, common ground
Motor speed control stopped working Servo library took Timer 1 (pins 9, 10) Move motor PWM to 3, 5, 6 or 11
Stuck in a corner forever No memory — inherent to reactive navigation Add a random component and a stuck-detector escape
Avoids well slowly, hits things fast Fixed threshold, quadratic braking term Make the threshold speed-dependent
Wild readings when two robots run together They hear each other’s chirps Stagger the ping timing

Where to take it next

Add wall following. A robot that holds a fixed distance from a wall on one side traverses a room deterministically rather than wandering, and it is the first behaviour that starts to look like a plan. It is a small code change and a big conceptual one.

Add a second sensor type. A VL53L0X fails on almost exactly the opposite surfaces to the sonar — dark matte and mirrors, versus soft and angled. Together they cover far more of the room than either alone.

Accept the ceiling and move on. A reactive robot cannot be sent anywhere, cannot promise it covered the floor, and can loop in a horseshoe-shaped room forever. Those are properties of having no map, not bugs. When they start to matter, the micromouse adds mapping and planning, and the coverage robot tackles the “have I been everywhere?” question directly.

Project roadmap

The build path

Follow the tech tree from parts to a robot that follows a taped line. Each node unlocks when its prerequisites are done, and your progress saves on this device.

0 / 18 done

100%
Learning path

Robot electronics foundations

Learning path

Open path
Learning path

Reactive navigation

Learning path

Open path
Build

Wire the robot

45 min

Build

Assemble and run

60 min

Goal

Obstacle-avoiding robot complete

You built it

Components

Tutorials in this path

Practise before you wire

Tune it in the live simulator

The build path routes through a browser lab. Find gains that follow the track cleanly here, then transfer them to the real robot.

Frequently asked questions

How does an obstacle-avoiding robot work?

It drives forward while an ultrasonic sensor watches the distance ahead. When something is closer than a set threshold, the robot stops, sweeps the sensor left and right on a servo to measure distance in each direction, and turns toward whichever way is most open—then resumes driving. The whole thing is a short sense–scan–decide–turn loop running many times a second.

Which sensor is best for an obstacle-avoiding robot?

The HC-SR04 ultrasonic sensor is the default: it's cheap, easy to wire, and reliable out to a few metres. A time-of-flight sensor gives a tighter, faster, more precise reading if you need it, but for a first obstacle-avoider the ultrasonic is the right balance of cost and simplicity.

Do I need to buy parts before I start this project?

No. The sensing and the avoidance logic run in the browser simulator, so you can understand and tune the behaviour before buying anything. Only the final build steps—wiring and assembly—need the physical Arduino, HC-SR04, servo, driver, motors, chassis, and battery.

Why isn't my obstacle-avoiding robot working?

The three usual culprits are a noisy or blocked ultrasonic reading (add a median filter and keep the sensor unobstructed), reading the sensor before the servo has finished moving (add a short settle delay), and powering the motors straight from the Arduino instead of through the driver (which browns out and resets the board).

How is this different from a line follower?

A line follower follows a track laid out for it; an obstacle-avoiding robot has no track and must decide where to go. It adds a scanning sensor and a real decision loop, which makes it the natural second robot to build after a line follower.