Obstacle Avoiding
Gesture Controlled Car
A dual-system robotics project integrating ultrasound sensing for obstacle avoidance and IMU-based hand gesture control via ESP-NOW.
How It Works
When the ultrasonic sensors detect a distance less than the allotted threshold, it triggers the obstacle avoidance software. The system then calculates a heuristic-based path to maneuver the car safely around the object.
The Motivation
With 1.25 million road-related deaths annually worldwide, safety systems like Automatic Emergency Braking are critical. However, many older or budget vehicles lack these features.
I wanted to prove that effective safety tech doesn't need to be expensive. By utilizing HC-SR04 sensors (~75ยข each), this entire obstacle avoidance system was built for under $50. If a student can build this, the automotive industry can implement it globally.
Circuit Design
Sender Board (Remote)
ESP32 + MPU6050 Accelerometer + OLED
Receiver Board (Car)
ESP32 + 4x HC-SR04 Sensors + Motor Drivers
Source Code
// Obstacle avoidance system is taken out
#include <esp_now.h>
#include <WiFi.h>
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_SSD1306.h>
#include <Wire.h>
Adafruit_MPU6050 mpu;
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire);
// REPLACE WITH YOUR RECEIVER MAC Address
uint8_t broadcastAddress[] = {0x0C, 0xB8, 0x15, 0xB9, 0x86, 0xB8};
// Structure example to send data
typedef struct struct_message {
float x;
float y;
} struct_message;
struct_message myData;
esp_now_peer_info_t peerInfo;
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
Serial.print("\r\nLast Packet Send Status:\t");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
void setup() {
Serial.begin(115200);
Serial.println("MPU6050 OLED demo");
if (!mpu.begin()) {
Serial.println("Sensor init failed");
while (1) yield();
}
WiFi.mode(WIFI_STA);
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
esp_now_register_send_cb(OnDataSent);
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
if (esp_now_add_peer(&peerInfo) != ESP_OK){
Serial.println("Failed to add peer");
return;
}
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
display.display();
delay(500);
display.setTextSize(2);
display.setTextColor(WHITE);
display.setRotation(0);
mpu.setAccelerometerRange(MPU6050_RANGE_16_G);
mpu.setGyroRange(MPU6050_RANGE_250_DEG);
mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
}
void loop() {
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
myData.x = a.acceleration.x;
myData.y = a.acceleration.y;
display.clearDisplay();
display.setCursor(0, 0);
if (a.acceleration.x >= 4) {
display.println("Back");
} else if (a.acceleration.x <= -4) {
display.println("Forward");
} else if (a.acceleration.y <= -4) {
display.println("Left");
} else if (a.acceleration.y >= 4) {
display.println("Right");
} else {
display.println("Stopped");
}
display.display();
delay(100);
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
if (result == ESP_OK) {
Serial.println("Sent with success");
} else {
Serial.println("Error sending the data");
}
delay(100);
}
#include <esp_now.h>
#include <WiFi.h>
const int backTrig = 13; const int frontTrig = 14;
const int leftTrig = 25; const int rightTrig = 32;
const int backEcho = 12; const int frontEcho = 27;
const int leftEcho = 33; const int rightEcho = 35;
const int A1A = 5; const int A1B = 17;
const int B1A = 18; const int B1B = 19;
typedef struct struct_message {
float x;
float y;
} struct_message;
struct_message myData;
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
memcpy(&myData, incomingData, sizeof(myData));
}
void setup() {
Serial.begin(115200);
pinMode(A1A, OUTPUT); pinMode(A1B, OUTPUT);
pinMode(B1A, OUTPUT); pinMode(B1B, OUTPUT);
digitalWrite(A1A, 0); digitalWrite(A1B, 0);
digitalWrite(B1A, 0); digitalWrite(B1B, 0);
WiFi.mode(WIFI_STA);
if (esp_now_init() != ESP_OK) {
return;
}
esp_now_register_recv_cb(OnDataRecv);
}
void loop() {
bool was_back = false;
if (myData.x >= 4) {
was_back = true;
while (myData.x >= 4) { backwards(); }
} else if (myData.x <= -4) {
was_back = false;
while (myData.x <= -4) { forward(); }
} else if (myData.y <= -4) {
while (myData.y <= -4) { right(); }
} else if (myData.y >= 4) {
while (myData.y >= 4) { left(); }
} else {
stopped();
}
}
// Logic helpers (abbreviated for display)
void forward() { digitalWrite(A1A, 1); digitalWrite(A1B, 0); digitalWrite(B1A, 1); digitalWrite(B1B, 0); }
void backwards() { digitalWrite(A1B, 1); digitalWrite(A1A, 0); digitalWrite(B1B, 1); digitalWrite(B1A, 0); }
void stopped() { digitalWrite(A1A, 0); digitalWrite(B1A, 0); digitalWrite(B1B, 0); digitalWrite(A1B, 0); }
void right() { digitalWrite(A1A, 1); digitalWrite(A1B, 0); digitalWrite(B1A, 0); digitalWrite(B1B, 0); }
void left() { digitalWrite(A1A, 0); digitalWrite(A1B, 0); digitalWrite(B1A, 1); digitalWrite(B1B, 0); }