Obstacle-avoiding robot
What you’ll build
A robot car that drives forward, stops when something is ahead, looks for the clearest way and turns that way. It’s a complete sense–think–act robot.
Parts
| Part | Qty | Notes |
|---|---|---|
| 2WD robot car chassis with 2 TT gear motors and wheels | 1 | Includes a caster |
| Arduino UNO (or compatible) | 1 | |
| L298N or TB6612FNG motor driver | 1 | |
| 6 × AA battery holder with switch | 1 | About 9 V with alkalines |
| Jumper wires (male–male and male–female) | ~20 | |
| HC-SR04 ultrasonic sensor | 1 | Front mounted |
| SG90 servo (optional) | 1 | To turn the sensor and “look” left and right |
Wiring
Motors as in the table below; HC-SR04: VCC → 5V, GND → GND, TRIG → 3, ECHO → 2. Optional servo signal → pin 11, powered from 5V (or a separate 5 V supply).
| Driver pin | Arduino pin | Purpose |
|---|---|---|
| ENA | 5 (PWM) | Left motor speed |
| IN1 / IN2 | 7 / 8 | Left motor direction |
| ENB | 6 (PWM) | Right motor speed |
| IN3 / IN4 | 9 / 10 | Right motor direction |
| 12V (VM) | Battery + (through the switch) | Motor power |
| GND | Battery − and Arduino GND | Shared ground |
| 5V | Arduino VIN is fed from the battery instead | Leave the driver’s 5V output unused, or check your board’s jumper |
How it decides
- Measure the distance ahead.
- If it’s more than 25 cm, drive forward.
- Otherwise stop, reverse briefly, then look left and right (turning the servo, or turning the robot) and pick the side with more space.
- Repeat.
Tips
- Mount the sensor level and at the very front; a low angle makes it see the floor.
- Narrow obstacles (chair legs) can slip past one sensor: a servo sweep or two angled sensors helps.
- Reverse a little before turning, so the robot doesn’t clip the obstacle while spinning.
The full program (with an optional servo)
#include <Servo.h>const int ENA = 5, IN1 = 7, IN2 = 8, ENB = 6, IN3 = 9, IN4 = 10;
void setMotor(int en, int a, int b, int speed) { // speed -255..255 digitalWrite(a, speed > 0); digitalWrite(b, speed < 0); analogWrite(en, min(abs(speed), 255));}
void drive(int left, int right) { setMotor(ENA, IN1, IN2, left); setMotor(ENB, IN3, IN4, right);}
void setupMotors() { int pins[] = {ENA, IN1, IN2, ENB, IN3, IN4}; for (int p : pins) pinMode(p, OUTPUT);}
const int TRIG = 3, ECHO = 2;Servo neck;
float readCm() { digitalWrite(TRIG, LOW); delayMicroseconds(2); digitalWrite(TRIG, HIGH); delayMicroseconds(10); digitalWrite(TRIG, LOW); long us = pulseIn(ECHO, HIGH, 30000); return us == 0 ? 400 : us * 0.0343 / 2;}
float lookAt(int angle) { neck.write(angle); delay(300); // let the servo arrive return readCm();}
void setup() { setupMotors(); pinMode(TRIG, OUTPUT); pinMode(ECHO, INPUT); neck.attach(11); neck.write(90); // look straight ahead delay(1000);}
void loop() { if (readCm() > 25) { drive(170, 170); return; } drive(0, 0); drive(-150, -150); delay(300); // back off drive(0, 0); float left = lookAt(160), right = lookAt(20); neck.write(90); if (left > right) drive(-160, 160); // spin left else drive(160, -160); // spin right delay(350);}No servo? Delete the servo lines and, instead of looking, always turn the same way or alternate directions.
Try it in the simulator
The virtual robot has the same front distance sensor, plus left and right distances.
Robot commands
motors(left, right): wheel power, −100 to 100lineLeft(),lineRight():trueover the black linedistance(): cm to the nearest thing ahead (max 200)distanceLeft(),distanceRight(): cm to the sideslinePosition(): where the line is, −1 (left) to 1 (right), ornullmillis(): milliseconds since Runprint(value): show a message belowsetup()runs once;loop()runs 50 times a second
Check the sensor logic in the virtual Arduino
Check your sensor logic before building: press Start simulator, replace diagram.json, paste the sketch and press ▶. Drag the sensor’s distance slider below 25 cm and the LED lights.
{ "version": 1, "author": "RoboLearn", "editor": "wokwi", "parts": [ { "type": "wokwi-arduino-uno", "id": "uno", "top": 0, "left": 0, "attrs": {} }, { "type": "wokwi-hc-sr04", "id": "sonar", "top": -110, "left": 90, "attrs": { "distance": "60" } } ], "connections": [ [ "sonar:VCC", "uno:5V", "red", [] ], [ "sonar:GND", "uno:GND.1", "black", [] ], [ "sonar:TRIG", "uno:3", "blue", [] ], [ "sonar:ECHO", "uno:2", "green", [] ] ], "dependencies": {}}const int TRIG = 3, ECHO = 2;void setup() { pinMode(TRIG, OUTPUT); pinMode(ECHO, INPUT); pinMode(LED_BUILTIN, OUTPUT); Serial.begin(9600); }void loop() { digitalWrite(TRIG, LOW); delayMicroseconds(2); digitalWrite(TRIG, HIGH); delayMicroseconds(10); digitalWrite(TRIG, LOW); long us = pulseIn(ECHO, HIGH, 30000); float cm = us == 0 ? 400 : us * 0.0343 / 2; Serial.println(cm); digitalWrite(LED_BUILTIN, cm < 25 ? HIGH : LOW); // LED = "would stop here" delay(100);}Runs on Wokwi, free, no account needed.
Never get stuckEasy
In the simulator, find a starting code change that stops the robot getting trapped in corners. Reverse for a moment before turning, or turn for longer.
Speed by distanceMedium
Make the robot slow down smoothly as it approaches an obstacle (fast when far, slow when near).
const s = Math.min(70, Math.max(20, distance())); if (distance() > 20) motors(s, s); else motors(-40, 40);
ExplorerHard
Make the robot visit all four corners of the obstacle room within 90 seconds.
Quick check
Finished this lesson?