3DProject guides
Obstacle-avoiding robot
An ultrasonic “eye” on a servo measures the distance ahead; when something gets close, the robot stops, looks left and right, and turns towards the open side.
- Difficulty
- Medium
- Time
- ~150 min
- Parts
- 12 parts
- Step by step
- 4 steps
- Measuring distance with an HC-SR04
- Turning a servo
- Making decisions from sensor readings
Parts
- 1 × Arduino UNO R3 (ATmega328P, SMD)45,000 UZS
- 1 × 2WD Robot Chassis (Plastic Deck)30,000 UZS
- 1 × HC-SR04 Ultrasonic Distance Sensor15,000 UZS
- 1 × SG90 Micro Servo Motor (9g)20,000 UZS
- 1 × L298N Dual H-Bridge Motor Driver20,000 UZS
- 2 × TT Gear Motor with Wheel (Yellow, 3–6V)30,000 UZS
- 1 × 360° Wheel: Ball Caster / Mecanum12,000 UZS
- 2 × Lithium Battery (18650 / LiPo)30,000 UZS
- 1 × Battery Holder for 18650 Cells6,000 UZS
- 1 × Jumper Wires 20 cm, Male-Female (40 pcs)12,000 UZS
You'll also need
- — A computer with the Arduino IDE (free from arduino.cc)
- — A USB cable for the UNO (the UNO SMD “+ USB cable” option)
- — A small Phillips screwdriver
Step by step
- 01
Build the car
Build the chassis, motors, L298N and power exactly as in the Robot car guide — the pins are the same.
- 02
Mount the servo and sensor
Fix the SG90 at the front. The code centres the servo at 90° on start — after that, mount the HC-SR04 on its bracket facing straight ahead.
- 03
Wire the sensor and servo
The extra rows in the table: TRIG → D12, ECHO → D11, servo signal (orange) → D3, both powered from 5V and GND.
- 04
Upload and test
The sketch uses the Servo library, which comes with the Arduino IDE. Upload, insert the cells and let it go. Serial Monitor (9600) shows the distance.
Wiring
- Power (+)
- Ground (−)
- Signal pin
- I²C / SPI bus
- L298NENA→UNOD5 remove the jumper on ENA
- L298NIN1→UNOD7
- L298NIN2→UNOD8
- L298NIN3→UNOD2
- L298NIN4→UNOD4
- L298NENB→UNOD6 remove the jumper on ENB
- L298NGND→UNOGND common ground — required
- L298N5V→UNO5V powers the UNO from the driver
- L298NOUT1OUT2→Left motor
- L298NOUT3OUT4→Right motor
- Battery+(2×18650)→L298N12V
- Battery−→L298NGND
- HC-SR04VCC→UNO5V
- HC-SR04GND→UNOGND
- HC-SR04TRIG→UNOD12
- HC-SR04ECHO→UNOD11
- SG90signal(orange)→UNOD3
- SG90red→UNO5V
- SG90brown→UNOGND
The code
sketch.ino
#include <Servo.h>
// motors (L298N)
const int ENA = 5, IN1 = 7, IN2 = 8; // left
const int ENB = 6, IN3 = 2, IN4 = 4; // right
void motors(int left, int right) { // -255 … 255
digitalWrite(IN1, left >= 0); digitalWrite(IN2, left < 0);
digitalWrite(IN3, right >= 0); digitalWrite(IN4, right < 0);
analogWrite(ENA, abs(left)); analogWrite(ENB, abs(right));
}
void setupMotors() {
int pins[] = {ENA, IN1, IN2, ENB, IN3, IN4};
for (int p : pins) pinMode(p, OUTPUT);
motors(0, 0);
}
const int TRIG = 12, ECHO = 11;
Servo neck;
long distanceCm() {
digitalWrite(TRIG, LOW); delayMicroseconds(2);
digitalWrite(TRIG, HIGH); delayMicroseconds(10);
digitalWrite(TRIG, LOW);
long us = pulseIn(ECHO, HIGH, 25000); // ~4 m max
return us ? us / 58 : 400; // nothing heard = far away
}
long look(int angle) {
neck.write(angle); delay(350);
return distanceCm();
}
void setup() {
Serial.begin(9600);
setupMotors();
pinMode(TRIG, OUTPUT); pinMode(ECHO, INPUT);
neck.attach(3);
neck.write(90);
delay(1500);
}
void loop() {
long ahead = distanceCm();
Serial.println(ahead);
if (ahead > 25) {
motors(170, 170);
delay(40);
return;
}
motors(0, 0);
motors(-150, -150); delay(250); // a step back
motors(0, 0);
long left = look(160), right = look(20);
neck.write(90); delay(200);
if (left > right) motors(-170, 170); else motors(170, -170);
delay(380); // about a quarter turn
motors(0, 0);
}If something doesn't work
- Distance is always 0 or 400: TRIG and ECHO may be swapped.
- Motor speed doesn't change: make sure ENA/ENB aren't on D9/D10 — the Servo library takes them over.
- The servo jitters and the UNO resets: weak cells — charge the 18650s.
- It doesn't see a wall: soft surfaces (curtains, sofas) swallow ultrasound — that's normal.
Where to go from here
- Add a second sensor to watch the sides
- Change speed smoothly with distance

