Inspiration

We wanted to recreate the modern social experience of playing video games with friends by bringing co-op gameplay into the real world! Enter Adventure Bugs; the digital generation's key to collaborative outdoor exploration. The goal was simple: make hardware feel social—a drop-in platform that turns any place into an interactive playground.


What it does

Adventure Bug is a remote-controlled mini rover built on a Seeed Studio XIAO ESP32S3 Sense.

  • Creates its own Wi-Fi network (AP) so it works anywhere (no internet needed).
  • Streams a live camera feed to a webpage.
  • Lets you control movement using WASD / arrow keys (plus on-screen buttons).
  • Drives using differential drive (2× TT motors + DRV8833 motor driver).

The math behind the motion (with every part explained)

1) Differential-drive kinematics

We model the rover as two wheels (left/right) separated by a track width (L).

$$ v=\frac{v_R+v_L}{2}, \qquad \omega=\frac{v_R-v_L}{L} $$

What each symbol means

  • \(v_L\): left wheel linear speed
  • \(v_R\): right wheel linear speed
  • \(v\): robot forward speed
  • \(\omega\): robot angular speed (turn rate)
  • \(L\): distance between wheels (track width)

Intuition

  • If \(v_L=v_R\), the rover goes straight (\(\omega=0\)).

- If \(v_L=-v_R\), the rover spins in place (\(v=0\)).

2) Turning keyboard inputs into motor commands

We turn keys into two control signals:

  • \(u_f \in {-1,0,1}\): forward/back intent

    • \(1\)=forward (W/↑), \(-1\)=back (S/↓), \(0\)=stop
  • \(u_t \in {-1,0,1}\): turning intent

    • \(1\)=right (D/→), \(-1\)=left (A/←), \(0\)=no turn

Then we compute motor targets:

$$ m_L=\operatorname{clip}(u_f-u_t,-1,1), \qquad m_R=\operatorname{clip}(u_f+u_t,-1,1) $$

What each part means

  • \(m_L, m_R\): normalized left/right motor command (range \([-1,1]\))
  • \(\operatorname{clip}(\cdot)\): clamps values so we never exceed safe limits
    Finally, PWM is proportional to command magnitude:

$$ \text{PWM} = P \cdot |m| $$

  • (P): chosen max PWM (sets top speed)
  • (|m|): how hard we drive
  • sign of (m) sets direction (forward vs reverse)

3) Camera stream bandwidth (why resolution/FPS matters)

A simple raw bandwidth estimate is:

$$ R_{\text{raw}}=\text{FPS}\cdot W\cdot H\cdot \text{bpp} $$

  • \(R_{\text{raw}}\): raw bits/sec (before compression)
  • \(\text{FPS}\): frames per second
  • \(W, H\): width/height in pixels
  • \(\text{bpp}\): bits per pixel
    In practice we stream compressed frames, but this explains why higher FPS/resolution can overload the link.

How we built it

Hardware

  • XIAO ESP32S3 Sense (camera + Wi-Fi)
  • DRV8833 dual H-bridge motor driver
  • 2× TT motors + wheels + caster/skid
  • **10V Power supply

Core wiring (XIAO → DRV8833)

XIAO Pin GPIO DRV8833 Pin Motor
D0 GPIO1 AIN1 Left motor
D1 GPIO2 AIN2 Left motor
D2 GPIO3 BIN1 Right motor
D3 GPIO4 BIN2 Right motor
3V3 VCC Logic power (if needed)
GND GND Common ground
Battery+ VM Motor power (3.7V)
Battery- GND Ground

Important: DRV8833 VM goes directly to the battery, not through the XIAO regulator.


Software

  • Firmware written in Arduino IDE
  • Libraries:

    • ESPAsyncWebServer
    • AsyncTCP

The ESP32 runs:

  • a web server (UI)
  • a WebSocket server (low-latency control)
  • a camera stream server

Expected boot output (Serial @115200)

  • Camera initialized OK
  • AP IP: 192.168.4.1
  • Web server on port 80, stream on 81

Frontend control (browser)

  • Keyboard input (WASD / arrow keys)
  • Mobile-friendly on-screen buttons
  • Sends compact commands like F, B, L, R, S over WebSocket
  • Displays connection status (“Connected”) + live feed

Challenges we ran into

  • Power separation: Buck Converter/motors introduced noise / brown-outs if wiring and grounds aren’t clean.
  • Raspberry Pi SSH + networking issues: direct connection worked, but SSH kept rejecting passwords (“Permission denied”), and some networks block device-to-device traffic.
  • Camera stability: ESP32 camera depends heavily on correct PSRAM settings and stream constraints.
  • Latency tuning: making keypress → WebSocket → motion feel instant required minimal messages and tight handling.

Accomplishments that we're proud of

  • Fully offline control (ESP32 AP mode) — works anywhere.
  • Live camera + real-time driving from a normal browser (no joystick needed).
  • A clear “from scratch” setup flow so others can reproduce it quickly.
  • Smooth differential-drive behavior with a simple, explainable control model.

What we learned

  • How to build an embedded stack: Wi-Fi AP + web UI + WebSockets + camera streaming on ESP32.
  • Why PSRAM configuration is critical for camera-based projects.
  • Real-world debugging: power issues, control systems, faulty connections
  • How lightweight math (clipping + differential drive) makes controls feel reliable.

What's next for Adventure Bugs

  • PID speed control for smoother steering and straighter driving.
  • Battery monitoring + low-voltage cutoff for safety.
  • Gamepad/joystick mode and adjustable sensitivity.
  • Simple autonomy: obstacle avoidance / line following / waypoint moves.
  • Adaptive streaming (auto-adjust FPS/resolution by link quality).
  • Optional spectator mode: one driver, multiple viewers.

Built With

Share this project:

Updates