An AI-powered autonomous navigation system that enables an ELEGOO Smart Robot Car to find objects in unknown environments using computer vision, LiDAR mapping, and intelligent path planning.
Give your robot a mission like "Find the red coffee mug" and watch it:
- 🎥 See - Uses YOLO11n AI to detect objects in real-time
- 🗺️ Map - Combines iPhone LiDAR + ESP32 camera for 3D environment mapping
- 🧠 Think - Google Gemini 2.0 Flash AI makes navigation decisions
- 🚗 Navigate - D* Lite algorithm plans optimal paths around obstacles
- ✅ Succeed - Autonomously drives to the target object
No pre-mapping required! The robot learns its environment on the fly.
User: "Find the red mug"
↓
[Robot scans environment with camera + LiDAR]
↓
[YOLO detects objects, Gemini decides which to investigate]
↓
[D* Lite plans path around obstacles]
↓
[Robot navigates autonomously]
↓
Robot: "Target found! ✓"
┌─────────────────────────────────────────────────────────────┐
│ iPhone (LiDAR) │
│ Scans 360° environment │
└──────────────────────────┬──────────────────────────────────┘
│ WiFi WebSocket
↓
┌─────────────────────────────────────────────────────────────┐
│ Backend Server (Python/FastAPI) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 🔄 Detection Loop (YOLO11n) - 3-5s │ │
│ │ 🔄 Planning Loop (Gemini ADK) - 1s │ │
│ │ 🔄 Fusion Loop (Sensor Fusion) - 500ms │ │
│ │ 🔄 Path Planning (D* Lite) - 1s │ │
│ │ 🔄 Motor Control Loop - 3s │ │
│ └─────────────────────────────────────────────────────┘ │
└──────────────────────────┬──────────────────────────────────┘
│ WiFi WebSocket
↓
┌─────────────────────────────────────────────────────────────┐
│ ESP32 WiFi Bridge │
│ Forwards commands via Serial │
└──────────────────────────┬──────────────────────────────────┘
│ Serial TX/RX
↓
┌─────────────────────────────────────────────────────────────┐
│ Arduino Uno (ELEGOO Smart Car) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ • Receives JSON motor commands │ │
│ │ • Controls L298N motor driver │ │
│ │ • Reads MPU6050 IMU (heading) │ │
│ │ • Sends telemetry back to backend │ │
│ └─────────────────────────────────────────────────────┘ │
└──────────────────────────┬──────────────────────────────────┘
│
↓
4x DC Motors
CAR MOVES! 🚗💨
Hardware:
- ELEGOO Smart Robot Car V4.0 kit
- ESP32 development board
- iPhone with LiDAR (iPhone 12 Pro or newer)
- ESP32-CAM (optional, for camera)
- Laptop/Desktop (backend server)
Software:
- Python 3.9 or higher
- Arduino IDE 1.8.19 or 2.x
- Google Gemini API key (Get one here)
- Web browser (Chrome/Firefox recommended)
# 1. Clone repository
git clone https://github.com/yourusername/blindfolded-navigation.git
cd blindfolded-navigation
# 2. Install Python dependencies
cd backend
pip install -r requirements.txt
# 3. Set Gemini API key
export GOOGLE_API_KEY="your-gemini-api-key-here"
# 4. Start backend server
python main.pyThat's it! The backend is now running on http://0.0.0.0:8000
- Backend Setup
- Frontend Setup
- Arduino Setup
- System Workflow
- API Documentation
- Troubleshooting
- Architecture Details
cd backend
# Install Python packages
pip install -r requirements.txtRequired packages:
fastapi- Web frameworkuvicorn- ASGI serveropencv-python- Image processingultralytics- YOLO11google-genai- Gemini ADKnumpy- Math operationswebsockets- WebSocket support
Create a .env file:
# backend/.env
GOOGLE_API_KEY=your-gemini-api-key-hereOr export as environment variable:
export GOOGLE_API_KEY="your-gemini-api-key-here"Edit backend/config.py if needed:
class Settings:
# Server
server_host = "0.0.0.0" # Listen on all interfaces
server_port = 8000
# YOLO
yolo_model_path = "yolo11n.pt" # Auto-downloads
confidence_threshold = 0.7 # Detection threshold
# Mission
default_objective = "Find the target object"
# Loop intervals (milliseconds)
detection_loop_interval = 3000 # 3 seconds
planning_loop_interval = 1000 # 1 second
fusion_loop_interval = 500 # 500mspython main.pyExpected output:
============================================================
SERVER INITIALIZATION STARTED
============================================================
Step 1: Loading YOLO model...
✓ YOLO model loaded successfully
Step 2: Initializing ADK Navigation Agent...
✓ ADK Navigation Agent initialized successfully
Step 3: Initializing shared state manager...
✓ Mission started: Find the target object
Step 4: Starting ADK session...
✓ ADK session started successfully
Step 5: Starting concurrent loops...
✓ Detection loop started (3000ms interval)
✓ Planning loop started (1000ms interval)
✓ Motor control loop started (3000ms interval)
✓ Path planning loop started (1000ms interval)
✓ Sensor fusion loop started (500ms interval)
============================================================
SERVER READY - Waiting for sensor input...
============================================================
INFO: Uvicorn running on http://0.0.0.0:8000
backend/
├── main.py # FastAPI server entry point
├── config.py # Configuration settings
├── state_manager.py # Thread-safe state management
├── adk_session_manager.py # Gemini ADK session handler
│
├── loops/ # Concurrent processing loops
│ ├── detection_loop.py # YOLO object detection
│ ├── planning_loop.py # Gemini AI planning
│ ├── fusion_loop.py # Sensor fusion (LiDAR+Camera)
│ ├── path_planning_loop.py # D* Lite pathfinding
│ └── motor_control_loop.py # Motor command generation
│
├── models/
│ └── yolo_model.py # YOLO11n wrapper
│
├── agents/
│ └── navigation_agent.py # Gemini agent definition
│
├── pathfinding/
│ ├── d_star_lite.py # D* Lite algorithm
│ ├── occupancy_grid.py # Grid representation
│ ├── priority_queue.py # Min-heap for pathfinding
│ └── utils.py # Coordinate utilities
│
└── tools/
├── odometry.py # Position tracking
├── motor_command_translator.py
└── navigation_tools.py
No installation required! Just open the HTML file:
# From project root
open frontenddashboard.html
# Or drag-and-drop into Chrome/Firefox-
Click "Configure Backend" (gear icon)
-
Enter your laptop's IP address:
http://192.168.1.100:8000(Replace
192.168.1.100with your actual IP) -
Click "Test & Save"
-
Status should show: ✅ Connected
- Enter objective:
"Find the red mug" - Click "Start Mission"
- Watch the robot navigate autonomously!
- 📹 Live Camera Feed - Real-time video from ESP32-CAM
- 🎯 Bounding Boxes - YOLO detections with labels and depth
- 📊 Activity Log - Real-time backend updates
- 🎮 Mission Control - Start/stop autonomous navigation
- 📡 LiDAR Status - Scan counter and depth data
- 📈 Progress Bar - Mission completion percentage
frontenddashboard.html # Single-page React app
├── Mission Control UI
├── Live Video Stream with Canvas Overlay
├── Activity Log (auto-updates every 500ms)
└── System Status Dashboard
ESP32 Arduino Uno
───────────── ──────────────
TX2 (GPIO17) → RX (Pin 0)
RX2 (GPIO16) → TX (Pin 1)
GND → GND
5V → 5V
L298N Arduino Uno
───────────── ──────────────
ENA → Pin 5 (PWM)
IN1 → Pin 7
IN2 → Pin 8
IN3 → Pin 9
IN4 → Pin 11
ENB → Pin 6 (PWM)
-
Install ESP32 Board Support:
- Arduino IDE →
File > Preferences - Add to "Additional Boards Manager URLs":
https://dl.espressif.com/dl/package_esp32_index.json Tools > Board > Boards Manager→ Install "esp32"
- Arduino IDE →
-
Install Libraries:
Sketch > Include Library > Manage Libraries- Install:
ArduinoJson(6.x),WebSockets
-
Configure WiFi:
- Open
backend/arduino/elegoo_wifi_bridge/elegoo_wifi_bridge.ino - Edit lines 28-32:
const char* WIFI_SSID = "YourWiFiName"; const char* WIFI_PASSWORD = "YourPassword"; const char* SERVER_HOST = "192.168.1.100"; // Your laptop IP
- Open
-
Upload:
Tools > Board > ESP32 Dev ModuleTools > Port > [Your ESP32 port]- Click Upload
-
Verify:
- Open Serial Monitor (115200 baud)
- Should see:
[WiFi] Connected!and[WebSocket] Connected to server
-
IMPORTANT: Disconnect ESP32 TX/RX from Arduino Pin 0/1 first!
-
Open sketch:
backend/arduino/elegoo_car_modified/elegoo_car_modified.ino
-
Verify motor pins (lines 40-45):
#define ENA 5 // Left motor PWM #define ENB 6 // Right motor PWM #define IN1 7 // Left motor direction 1 #define IN2 8 // Left motor direction 2 #define IN3 9 // Right motor direction 1 #define IN4 11 // Right motor direction 2
-
Upload:
Tools > Board > Arduino UnoTools > Port > [Your Arduino port]- Click Upload
-
Reconnect ESP32 TX/RX to Arduino Pin 0/1
-
Calibrate IMU:
- Place car on flat surface (don't move!)
- Power on
- Wait 2 seconds for auto-calibration
backend/arduino/
├── elegoo_wifi_bridge/
│ └── elegoo_wifi_bridge.ino # ESP32 WiFi bridge (upload to ESP32)
│
├── elegoo_car_modified/
│ └── elegoo_car_modified.ino # Modified ELEGOO code (upload to Arduino Uno)
│
└── HARDWARE_SETUP_GUIDE.md # Detailed wiring diagrams
User opens frontenddashboard.html
↓
User types: "Find the red mug"
↓
User clicks: "Start Mission"
↓
Frontend sends: POST /api/start_mission
{
"mission": "Find the red mug",
"timestamp": "2025-10-26T12:00:00Z"
}
↓
Backend receives and activates:
✓ state_manager.mission_active = True
✓ All 5 loops start processing
ESP32-CAM sends camera frame via WebSocket
↓
Backend receives JPEG bytes
↓
OpenCV decodes: cv2.imdecode(bytes) → numpy array
↓
YOLO11n processes image
↓
Detects: [{"label": "cup", "confidence": 0.85, "bbox": [100, 150, 80, 120]}]
↓
Gets depth from fusion loop
↓
Stores: DetectedObject(label="cup", depth=2.3m, position=(2.3, 1.8))
iPhone sends LiDAR point cloud via WebSocket
{
"points": [
{"x": 0.5, "y": 0.2, "z": 1.2},
{"x": 1.0, "y": 0.3, "z": 2.3},
...1000+ points
]
}
↓
Backend processes:
1. Project 3D points → 2D occupancy grid (100x100)
→ [0=free space, 255=obstacle]
2. Project 3D points → Camera frame using OpenCV
→ Creates aligned depth map (640x480)
3. Use cv2.inpaint() to fill gaps
↓
Stores:
• occupancy_grid (for D* Lite pathfinding)
• depth_map (for YOLO depth estimation)
Get detected objects from state_manager
↓
Ask Gemini 2.0 Flash ADK agent:
"I see a cup at 2.3m, 45° right.
Mission: Find the red mug.
Should I navigate to it?"
↓
Gemini analyzes and responds:
{
"action": "navigate_to_object",
"target": "cup",
"reasoning": "Cup detected with high confidence,
investigate to verify if it's the target"
}
↓
Sets goal: state_manager.goal_position = (2.3, 1.8)
↓
Updates status: path_status = "PLANNING"
Get occupancy grid from fusion loop
↓
Get goal position from planning loop
↓
Get current robot position from odometry
↓
Run D* Lite algorithm:
1. Initialize grid with costs
2. Find optimal path avoiding obstacles
3. Generate waypoint sequence
↓
Path found: [(0,0) → (0.5,0.3) → (1.0,0.8) → (2.3,1.8)]
↓
Next waypoint: (0.5, 0.3)
↓
Updates:
• state_manager.current_path = [...]
• state_manager.next_waypoint = (0.5, 0.3)
• path_status = "PATH_FOUND"
Get next waypoint: (0.5, 0.3)
↓
Get robot position from odometry: (0, 0, heading=0°)
↓
Calculate required movement:
• Distance to waypoint: 0.58 meters
• Angle to waypoint: 31°
• Required turn: 31° right
↓
Translate to motor speeds:
• Left motor: 180 (slower to turn right)
• Right motor: 220 (faster to turn right)
↓
Create JSON command:
{
"N": 6, // Direct motor control
"H": "cmd_42", // Command ID
"D1": 180, // Left motor speed
"D2": 220 // Right motor speed
}
↓
Send via WebSocket to ESP32 → /ws/arduino
Backend sends JSON via WebSocket
↓
ESP32 WiFi Bridge receives:
{
"N": 6,
"H": "cmd_42",
"D1": 180,
"D2": 220
}
↓
ESP32 forwards to Arduino via Serial (TX2→RX)
↓
Arduino Uno receives and parses JSON
↓
Extracts: commandType=6, leftSpeed=180, rightSpeed=220
↓
Calls: setMotorSpeeds(180, 220)
↓
Controls L298N motor driver:
• Left motor: digitalWrite(IN1, HIGH), analogWrite(ENA, 180)
• Right motor: digitalWrite(IN3, HIGH), analogWrite(ENB, 220)
↓
L298N outputs PWM to motors
↓
🚗 CAR TURNS RIGHT AND MOVES FORWARD!
Arduino reads MPU6050 IMU every 100ms
↓
Current heading: 31° (turned right as expected!)
↓
Creates JSON: {"yaw": 31.0, "pitch": 0.2, "roll": -0.1}
↓
Sends to ESP32 via Serial (TX→RX2)
↓
ESP32 forwards to backend via WebSocket
↓
Backend receives IMU data
↓
Odometry updates robot position:
• Old: (0, 0, heading=0°)
• New: (0.1, 0.05, heading=31°)
↓
Path planning recalculates:
"Still on track, continue to next waypoint"
↓
CONTINUOUS NAVIGATION UNTIL TARGET REACHED!
Frontend polls: GET /api/mission_status
↓
Backend responds:
{
"status": "ACTIVE",
"progress": 65,
"current_action": "Navigating to target",
"completed": false
}
↓
Frontend updates UI:
• Activity Log: ✓ "Navigating to target"
• Progress Bar: 65%
• Status: ACTIVE
Frontend polls: GET /api/detections
↓
Backend responds:
{
"objects": [
{"label": "cup", "confidence": 0.85, "bbox": [100,150,80,120], "depth": 2.3}
]
}
↓
Frontend canvas draws:
• Green bounding box at [100, 150, 80, 120]
• Label: "cup 85% 2.3m"
↓
USER SEES LIVE VISUALIZATION!
Purpose: Get complete system status
Response:
{
"server": "running",
"yolo_loaded": true,
"adk_agent_initialized": true,
"loops": {
"detection": {"running": true, "total_runs": 42},
"planning": {"running": true},
"motor_control": {"running": true},
"path_planning": {"running": true},
"fusion": {"running": true, "total_fusions": 128}
},
"mission": {
"objective": "Find the red mug",
"mission_active": true,
"elapsed_time_seconds": 23.5
}
}Purpose: Start autonomous navigation
Request:
{
"mission": "Find the red mug",
"timestamp": "2025-10-26T12:00:00Z"
}Response:
{
"status": "started",
"objective": "Find the red mug"
}Purpose: Emergency stop
Response:
{
"status": "stopped",
"message": "Mission stopped successfully"
}Purpose: Real-time mission progress (polled by frontend every 500ms)
Response:
{
"status": "ACTIVE",
"progress": 65,
"current_action": "Navigating to target",
"completed": false,
"objective": "Find the red mug"
}Purpose: Get YOLO-detected objects with depth
Response:
{
"count": 3,
"objects": [
{
"label": "cup",
"confidence": 0.85,
"bbox": [100, 150, 80, 120],
"depth": 2.3,
"timestamp": 1730000000.0
}
]
}Purpose: Receive iPhone LiDAR point cloud
Client sends:
{
"timestamp": 1730000000.0,
"points": [
{"x": 0.5, "y": 0.2, "z": 1.2},
{"x": 1.0, "y": 0.3, "z": 2.3}
]
}Purpose: Receive ESP32 camera frames
Client sends: Raw JPEG bytes (binary)
Purpose: Bidirectional Arduino communication
Server sends (motor command):
{
"N": 6,
"H": "cmd_42",
"D1": 180,
"D2": 220
}Client sends (IMU data):
{
"type": "imu",
"yaw": 45.2,
"pitch": 0.1,
"roll": -0.5
}Problem: ModuleNotFoundError: No module named 'fastapi'
# Solution: Install dependencies
pip install -r requirements.txtProblem: GOOGLE_API_KEY not set
# Solution: Set environment variable
export GOOGLE_API_KEY="your-key-here"Problem: YOLO model download fails
# Solution: Manually download
python -c "from ultralytics import YOLO; YOLO('yolo11n.pt')"Problem: "Backend connection failed"
- Check backend is running:
python main.py - Verify IP address is correct
- Check firewall settings (allow port 8000)
Problem: Video stream not showing
- ESP32-CAM might not be connected
- Check WebSocket connection in browser console
- Verify camera is streaming via
/ws/camera
Problem: ESP32 won't connect to WiFi
- Check SSID/password are correct
- WiFi must be 2.4GHz (ESP32 doesn't support 5GHz)
- Move closer to router
Problem: Arduino upload fails
- Disconnect ESP32 TX/RX from Arduino Pin 0/1
- Select correct board: "Arduino Uno"
- Try different USB cable
Problem: Motors don't move
- Check battery voltage (7-12V)
- Verify L298N wiring
- Check if motor driver is overheating
Backend:
- FastAPI - Async web framework
- YOLO11n - Object detection (Ultralytics)
- Google Gemini 2.0 Flash - AI planning (ADK)
- OpenCV - Image processing & sensor fusion
- D* Lite - Dynamic pathfinding algorithm
- WebSockets - Real-time communication
Frontend:
- React (via CDN) - UI framework
- Canvas API - Bounding box overlay
- Fetch API - Backend polling
Hardware:
- ELEGOO Smart Car V4.0 - Robot platform
- Arduino Uno - Motor control
- ESP32 - WiFi bridge
- MPU6050 - IMU (gyro/accelerometer)
- L298N - Motor driver
- iPhone LiDAR - 3D environment scanning
- ESP32-CAM - Vision
- YOLO11n - Object detection with 80+ classes
- D* Lite - Incremental pathfinding with replanning
- Sensor Fusion - LiDAR + Camera alignment via OpenCV
- Complementary Filter - IMU noise reduction
- Occupancy Grid - 2D environment representation
| Component | Frequency | Latency |
|---|---|---|
| YOLO Detection | 0.2-0.3 Hz | ~200ms |
| Gemini Planning | 1 Hz | ~500ms |
| Sensor Fusion | 2 Hz | ~10ms |
| Path Planning | 1 Hz | ~50ms |
| Motor Control | 0.3 Hz | ~5ms |
| Total Loop Time | 30 Hz | ~800ms |
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Commit your changes
- Push to the branch
- Open a Pull Request
MIT License - see LICENSE file for details
- ELEGOO - Robot car platform
- Ultralytics - YOLO implementation
- Google - Gemini AI
- OpenCV - Computer vision library
Issues? Open a GitHub issue or contact the maintainers.
Documentation:
- Backend API:
http://localhost:8000/docs(when running) - Hardware Setup:
backend/arduino/HARDWARE_SETUP_GUIDE.md - Code Audit:
backend/CODE_AUDIT.md
Your autonomous navigation system is complete!
# Start backend
cd backend && python main.py
# Open frontend
open ../frontenddashboard.html
# Upload Arduino code
# (See Arduino Setup section)
# Give it a mission!
"Find the red coffee mug" 🚗💨Happy exploring! 🤖✨