Skip to content

zeyad-shaban/CodeRover

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CodeRover

CodeRover is an ESP32-based differential drive robot built for autonomous point-to-point navigation and manual remote control.

The project combines Android computer vision, BLE communication, embedded motor control, Unity simulation, and a web joystick interface into a single robotics platform.


Demo

Demo

Simulation

Simulation demo

Real-life demos

Demo

Real-life demo 1


Project Overview

The robot supports two control modes.

Autonomous Mode

The Android app detects the robot using an ArUco marker and estimates its pose from the phone camera. The user taps a target point on the live video feed, and a proportional controller computes the required wheel velocities to reach that point.

autonomous_arch_overview

Manual Mode

A browser-based joystick allows direct teleoperation of the robot through Web Bluetooth.

Both modes send commands to the ESP32, which drives the motors using PWM through an H‑bridge driver.

manual_arch_overview


Control Law

The robot uses a proportional controller that was first tuned in Unity simulation before deployment to hardware. The controller computes wheel velocities based on the robot’s pose error relative to a target point.

State Estimation

The robot’s current state is extracted from ArUco marker detection:

  • Position (x, y): Center of the detected marker
  • Heading (θ): Orientation vector from marker's bottom to top corner
val theta = Math.atan2(yTop - yBtm, xTop - xBtm)  // Robot heading
val xCntr = mapX(result.centerX, result.centerY)  // Robot position
val yCntr = mapY(result.centerX, result.centerY)

Error Computation

Given a target point (x_t, y_t) selected by the user:

angleError = atan2(y_t - y, x_t - x) - θ

The angle error is normalized to [-π, π] to avoid wrap-around issues:

var angleError = angleToTarget - theta
while (angleError > Math.PI) angleError -= 2 * Math.PI
while (angleError < -Math.PI) angleError += 2 * Math.PI

The distance error is:

distanceError = sqrt((x_t - x)^2 + (y_t - y)^2)

Proportional Control Law

The controller generates linear and angular velocity commands:

ω = kω * angleError
v = kv * distanceError

Where:

  • kω = 0.6 (angular gain)
  • kv = 0.3 (linear gain)

Turn-in-Place Strategy

To ensure stable navigation, the robot first aligns itself with the target before moving forward:

v = 0                          if |angleError| > π/4
v = kv * distanceError         otherwise

This prevents the robot from drifting while turning sharply.

Differential Drive Kinematics

The linear and angular velocities are converted to individual wheel speeds using the robot's kinematics model:

v_right = v + (ω * L / 2)
v_left  = v - (ω * L / 2)

Where:

  • L = 100 mm is the wheelbase (distance between wheels).
vRight = v - (w * wheelbase / 2.0)
vLeft = v + (w * wheelbase / 2.0)

Implementation Details

  • The control loop runs at 20 Hz (50 ms throttle) to balance responsiveness with BLE bandwidth.
  • Wheel velocities are sent as CSV strings over BLE: "vLeft,vRight,honk".
  • The ESP32 maps these velocities to 8-bit PWM duty cycles (0–255) for motor control.

This control strategy enables smooth point-to-point navigation while maintaining stability through the turn-in-place behavior and carefully tuned proportional gains.


BLE Communication Protocol

The CodeRover uses Bluetooth Low Energy (BLE) for wireless communication between controllers (Android/Web) and the ESP32 rover. The protocol is designed for low-latency, real-time motor control with built-in safety features.

GATT Service Specification

Attribute Value Purpose
Device Name CarRover Identifiable device name during scanning
Service UUID 12345678-1234-1234-1234-1234567890ab Custom service for motor control
Characteristic UUID abcd1234-1234-1234-1234-abcdef123456 Write-only characteristic for commands
Property WRITE_NR (Write Without Response) Minimizes latency for real-time control

Payload Format

Commands are sent as CSV strings with three values:

vLeft, vRight, honk

Where value ranges are

  • vLeft, vRight: -255 to 255 (negative = reverse, positive = forward, 0 to brake)
  • honk: 0 (off) or = 1 (on)

Implementation Details

Android Client

// BLEManager sends formatted payload
val payload = String.format(Locale.US, "%.3f, %.3f, %d", vLeft, vRight, honk)
chr.value = payload.toByteArray(Charsets.UTF_8)
bluetoothGatt?.writeCharacteristic(chr)

ESP32 Server

// Parse incoming CSV payload
float vLeft = 0.0f, vRight = 0.0f, honk = 0.0f;
if (sscanf(val.c_str(), "%f, %f, %f", &vLeft, &vRight, &honk) >= 2) {
    updateMotors(vLeft, vRight);
    if (honk >= 1) Serial2.println(honk);
}

Web Client

// Web Bluetooth sends same CSV format
const dataString = `${vLeft},${vRight},${honk}`;
bleCharacteristic.writeValue(encoder.encode(dataString));

Safety Features

Watchdog Timer

The ESP32 implements a 300 ms safety watchdog that automatically stops the motors if no commands are received:

if (now - lastReceiveMillis >= TIMEOUT_MS) {
    if (!stoppedByTimeout) {
        stop();
        stoppedByTimeout = true;
    }
}

Connection Management

The Android app automatically scans and reconnects if the connection is lost.

Connection Flowchart


Hardware

CodeRover is built around an ESP32 that drives two DC motors through an H-bridge motor driver. A separate Arduino Uno handles the horn module, which keeps the motor-control path simple and lets the honk actuator stay isolated from the main drive logic.

Motor Driver Architecture

The H-bridge is used to control both speed and direction of each DC motor using PWM outputs from the ESP32. By toggling the input pins in opposite states, each motor can rotate in either direction.

H-Bridge Schematic

Motor Control Pins

The ESP32 uses four GPIO pins configured with LEDC PWM at 5 kHz and 8-bit resolution:

ESP32 Pin PWM Channel Motor Side Direction
GPIO 27 0 Right Backward
GPIO 26 1 Right Forward
GPIO 19 2 Left Backward
GPIO 13 3 Left Forward

Each motor uses two pins for direction control. Setting one pin high and the other low drives the motor in one direction; swapping them reverses rotation.

Hardware Connections

Serial Communication

The ESP32 communicates with the Arduino Uno over Serial2 to forward horn commands.

ESP32 Pin Purpose Destination
GPIO 23 Serial2 TX (115200 baud) Arduino Uno RX

The ESP32 sends honk commands through this serial link, and the Arduino Uno handles the actual horn actuation.


Software Components

Android App

  • Kotlin-based Android application
  • OpenCV 4.12.0 for ArUco detection
  • CameraX camera pipeline
  • Control loop running at ~20 Hz
  • BLE command transmission to ESP32

Responsibilities:

  • Detect robot pose
  • Compute control commands
  • Send motor commands over BLE

ESP32 Firmware

  • BLE server using NimBLE-Arduino
  • Parses incoming motor commands
  • Generates PWM via LEDC hardware timers

PWM configuration:

  • Frequency: 5 kHz
  • Resolution: 8-bit

Safety feature:

Motor watchdog timeout: 300 ms

If commands stop arriving, the robot automatically stops.


Web GUI

Web GUI Controller

Browser-based interface for manual driving.

Features:

  • Virtual joystick
  • Speed and drift sliders
  • Honk button
  • Input logging with timestamps

Stack:

  • Vanilla JavaScript
  • Web Bluetooth
  • FastAPI backend
  • SQLite logging

Unity Simulation

Unity environment used to validate controller behavior before running on hardware.

Key scripts:

Script Purpose
Brain.cs Proportional controller
DifferentialDriveController.cs Wheel physics

Setup

Android App

  1. Open android_app/ in Android Studio
  2. Download OpenCV Android SDK 4.12.0
  3. Import it as module opencv
  4. Sync Gradle
  5. Run on device

Required permissions:

CAMERA
BLUETOOTH_SCAN
BLUETOOTH_CONNECT
ACCESS_FINE_LOCATION

Minimum Android version:

Android 7.0 (API 24)

ESP32 Firmware

  1. Install PlatformIO
  2. Open esp32/ project
  3. Connect board
  4. Build and upload

Dependencies are installed automatically.


Arduino Uno (Honk Module, optional)

Flash the firmware in arduino/ and connect:

ESP32 GPIO 23 → Arduino RX (Pin 12)

Web GUI

cd web_gui
pip install fastapi uvicorn sqlalchemy
uvicorn server:app --reload

Then open:

static/index.html

in a Web Bluetooth compatible browser.


AI / Research Notebooks

Install dependencies:

pip install jupyter numpy opencv-python

Open notebooks in:

ai/notebooks/

  • Flowcharts were generated thanks to deepwiki

About

ESP32 differential drive robot with Unity-simulated control laws, Android autonomy, and web-based manual override.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors