Arduino UNO Obstacle Avoidance & Bluetooth Controlled Robot Car
A 4WD smart robot with 3 operating modes — autonomous obstacle avoidance, line following, and Bluetooth smartphone control. Full code, wiring & simulation included.
Project Overview
This project combines three intelligent operating modes in a single 4-wheel-drive robot. The Arduino UNO acts as the central controller, reading data from multiple sensors and switching between autonomous and manual operation based on Bluetooth or IR remote commands.
180° Scanning
SG90 servo sweeps the HC-SR04 ultrasonic sensor left and right to find the clearest path forward.
Dual Input
Both Bluetooth (HC-05) and IR remote control are decoded simultaneously for flexible operation.
PWM Speed
Motor speed is set via analogWrite(enA/enB) PWM — adjustable from the app in real time.
18650 Li-ion
Rechargeable 18650 battery pack provides stable 7.4V–8.4V to the L298N motor driver.
Components List
SoftwareSerial (built-in) · IRremote by shirriff · No additional libs needed for servo (manual PWM pulses used).Wiring Diagram
All digital and analog pins are used. The servo is driven by manual PWM pulses on A4, and SoftwareSerial uses pins 2 (RX) and 3 (TX) for Bluetooth.
Full Pin Reference
| Module | Module Pin | Arduino Pin | Notes |
|---|---|---|---|
| HC-05 Bluetooth | VCC | 5V | |
| HC-05 Bluetooth | GND | GND | |
| HC-05 Bluetooth | TXD | D2 (SoftSerial RX) | HC-05 TX → Arduino D2 |
| HC-05 Bluetooth | RXD | D3 (SoftSerial TX) | Use voltage divider for 3.3V |
| L298N | ENA | D10 (PWM) | Right motor speed |
| L298N | IN1 | D9 | Right motor dir A |
| L298N | IN2 | D8 | Right motor dir B |
| L298N | IN3 | D7 | Left motor dir A |
| L298N | IN4 | D6 | Left motor dir B |
| L298N | ENB | D5 (PWM) | Left motor speed |
| IR Sensor Right | OUT | A0 | Digital read |
| IR Sensor Left | OUT | A1 | Digital read |
| HC-SR04 | Echo | A2 | Input |
| HC-SR04 | Trigger | A3 | Output |
| SG90 Servo | Signal | A4 | Manual PWM pulses |
| IR Receiver | OUT | A5 | RECV_PIN for IRremote lib |
How It Works — Three Modes
Mode 2 · cmd=10 — Obstacle Avoidance (Autonomous)
- Servo sweeps the HC-SR04 to scan forward continuously.
- If front distance > 20 cm (set variable), robot moves forward.
- Obstacle detected, robot stops, calls
Check_side(). - Servo rotates left (140°) reads
distance_L, then right (0°) readsdistance_R. compareDistance(): turns toward the side with more space (350 ms turn). If both blocked, reverse and turn 600 ms.- Servo returns to 70° (centre) and resumes forward motion.
Mode 1 · cmd=9 — Line Following
- Speed set to 130 (moderate) for smooth line tracking.
- R_S=0, L_S=0 (both on white):
forward() - R_S=1, L_S=0 (right on black):
turnRight() - R_S=0, L_S=1 (left on black):
turnLeft() - R_S=1, L_S=1 (both on black / end of track):
Stop()
Mode 0 · cmd=8 — Bluetooth / IR Remote Manual Control
- HC-05 or IR remote sends a numeric command (1–10).
- If value > 20, it is treated as a new PWM speed value (0–255).
- Commands 1–5: Forward / Backward / Left / Right / Stop.
- Commands 6–7: Timed turns (voice control style, auto-stop after 400 ms).
- Commands 8/9/10 switch mode: Stop / Line Follow / Obstacle Avoid.
Servo Sweep Logic — Manual PWM Pulse Generation
- No Servo library used, pulses are generated manually via
servoPulse(pin, angle). - Formula:
pwm = (angle x 11) + 500microseconds. - At 70° = 1270 µs, At 0° = 500 µs, At 140° = 2040 µs.
- 50 ms delay between pulses provides the refresh cycle.
Bluetooth / IR Command Reference
Send these integer values from your Bluetooth app (e.g. Arduino Bluetooth Controller on Android). IR remote codes are mapped to the same numbers via IRremote_data().
150 or 200.Interactive Robot Simulator
🎮 Mini Control Demo
Full Arduino Code
#include <SoftwareSerial.h> SoftwareSerial BT_Serial(2, 3); // RX=D2, TX=D3 #include <IRremote.h> const int RECV_PIN = A5; IRrecv irrecv(RECV_PIN); decode_results results; // ── L298N Motor Driver Pins ── #define enA 10 // Enable Right motors (PWM) #define in1 9 // Right motor forward #define in2 8 // Right motor backward #define in3 7 // Left motor backward #define in4 6 // Left motor forward #define enB 5 // Enable Left motors (PWM) #define servo A4 // SG90 Servo signal #define R_S A0 // IR sensor Right #define L_S A1 // IR sensor Left #define echo A2 // HC-SR04 Echo #define trigger A3 // HC-SR04 Trigger int distance_L, distance_F = 30, distance_R; long distance; int set = 20; // obstacle threshold (cm) int bt_ir_data; int Speed = 130; int mode = 0; int IR_data; void setup() { pinMode(R_S, INPUT); pinMode(L_S, INPUT); pinMode(echo, INPUT); pinMode(trigger, OUTPUT); pinMode(enA, OUTPUT); pinMode(enB, OUTPUT); pinMode(in1, OUTPUT); pinMode(in2, OUTPUT); pinMode(in3, OUTPUT); pinMode(in4, OUTPUT); pinMode(servo, OUTPUT); irrecv.enableIRIn(); irrecv.blink13(true); Serial.begin(9600); BT_Serial.begin(9600); // Servo startup sweep (calibration) for (int a = 70; a <= 140; a += 5) servoPulse(servo, a); for (int a = 140; a >= 0; a -= 5) servoPulse(servo, a); for (int a = 0; a <= 70; a += 5) servoPulse(servo, a); delay(500); } void loop() { // Read Bluetooth if (BT_Serial.available() > 0) { bt_ir_data = BT_Serial.read(); Serial.println(bt_ir_data); if (bt_ir_data > 20) { Speed = bt_ir_data; } // speed update } // Read IR Remote if (irrecv.decode(&results)) { bt_ir_data = IRremote_data(); irrecv.resume(); delay(100); } // Mode switching if (bt_ir_data == 8) { mode = 0; Stop(); } else if (bt_ir_data == 9) { mode = 1; Speed = 130; } else if (bt_ir_data == 10) { mode = 2; Speed = 255; } analogWrite(enA, Speed); analogWrite(enB, Speed); if (mode == 0) { // ── Manual / Bluetooth control ── if (bt_ir_data == 1) forword(); else if (bt_ir_data == 2) backword(); else if (bt_ir_data == 3) turnLeft(); else if (bt_ir_data == 4) turnRight(); else if (bt_ir_data == 5) Stop(); else if (bt_ir_data == 6) { turnLeft(); delay(400); bt_ir_data = 5; } else if (bt_ir_data == 7) { turnRight(); delay(400); bt_ir_data = 5; } } if (mode == 1) { // ── Line Following ── if (!digitalRead(R_S) && !digitalRead(L_S)) forword(); else if ( digitalRead(R_S) && !digitalRead(L_S)) turnRight(); else if (!digitalRead(R_S) && digitalRead(L_S)) turnLeft(); else if ( digitalRead(R_S) && digitalRead(L_S)) Stop(); } if (mode == 2) { // ── Obstacle Avoidance ── distance_F = Ultrasonic_read(); if (distance_F > set) forword(); else Check_side(); } delay(10); } long IRremote_data() { if (results.value == 0xFF02FD) IR_data = 1; else if (results.value == 0xFF9867) IR_data = 2; else if (results.value == 0xFFE01F) IR_data = 3; else if (results.value == 0xFF906F) IR_data = 4; else if (results.value == 0xFF629D || results.value == 0xFFA857) IR_data = 5; else if (results.value == 0xFF30CF) IR_data = 8; else if (results.value == 0xFF18E7) IR_data = 9; else if (results.value == 0xFF7A85) IR_data = 10; return IR_data; } void servoPulse(int pin, int angle) { int pwm = (angle * 11) + 500; digitalWrite(pin, HIGH); delayMicroseconds(pwm); digitalWrite(pin, LOW); delay(50); } long Ultrasonic_read() { digitalWrite(trigger, LOW); delayMicroseconds(2); digitalWrite(trigger, HIGH); delayMicroseconds(10); digitalWrite(trigger, LOW); distance = pulseIn(echo, HIGH); return distance / 29 / 2; } void compareDistance() { if (distance_L > distance_R) { turnLeft(); delay(350); } else if (distance_R > distance_L) { turnRight(); delay(350); } else { backword(); delay(300); turnRight(); delay(600); } } void Check_side() { Stop(); delay(100); for (int a = 70; a <= 140; a += 5) servoPulse(servo, a); delay(300); distance_L = Ultrasonic_read(); delay(100); for (int a = 140; a >= 0; a -= 5) servoPulse(servo, a); delay(500); distance_R = Ultrasonic_read(); delay(100); for (int a = 0; a <= 70; a += 5) servoPulse(servo, a); delay(300); compareDistance(); } // ── Motor Control Functions ── void forword() { digitalWrite(in1,HIGH); digitalWrite(in2,LOW); digitalWrite(in3,LOW); digitalWrite(in4,HIGH); } void backword() { digitalWrite(in1,LOW); digitalWrite(in2,HIGH);digitalWrite(in3,HIGH); digitalWrite(in4,LOW); } void turnRight() { digitalWrite(in1,LOW); digitalWrite(in2,HIGH);digitalWrite(in3,LOW); digitalWrite(in4,HIGH); } void turnLeft() { digitalWrite(in1,HIGH); digitalWrite(in2,LOW); digitalWrite(in3,HIGH); digitalWrite(in4,LOW); } void Stop() { digitalWrite(in1,LOW); digitalWrite(in2,LOW); digitalWrite(in3,LOW); digitalWrite(in4,LOW); }
Online Simulation
▶ Try it in CirkitDesigner
Simulate the full 4WD robot circuit online — test all three modes without any hardware. Use the serial monitor to send Bluetooth commands.
Open CirkitDesignerStep-by-Step Simulation Guide
| # | Step |
|---|---|
| 1 | Open CirkitDesigner, create a new project, add Arduino UNO. |
| 2 | Add HC-SR04, SG90 Servo, 2× IR sensors, IR receiver, 4× DC motors, and L298N from the library. |
| 3 | Wire all modules per the pin table above. Use the diagram.json to auto-import connections. |
| 4 | Paste the code above into the Arduino editor. Install IRremote library. |
| 5 | Click Simulate. Open Serial Monitor — type 10 to enter obstacle avoidance mode. |
| 6 | Move a virtual object in front of the HC-SR04 to trigger avoidance. Watch servo sweep and motors respond. |
| 7 | Type 9 to switch to line-following mode; toggle IR sensor inputs HIGH/LOW to test steering logic. |
| 8 | Type 8 for manual mode, then 1–5 to drive forward/backward/turn/stop manually. |
Applications & Upgrades
Possible Upgrades
ESP32-CAM
Add live video streaming to monitor the robot's path remotely from a browser.
GPS Navigation
Add a NEO-6M GPS module for outdoor waypoint navigation and route tracking.
Voice Control
Use Google Assistant via an ESP8266 + IFTTT bridge to control the robot with voice commands.
AI Object Recognition
Swap to a Raspberry Pi + camera and add TensorFlow Lite for real-time object detection.
Comments
Post a Comment