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
- arduino
- asynctcp
- c
- c++
- css
- esp32
- espasyncwebserver
- html
- javascript
- mjpeg
- websockets
Log in or sign up for Devpost to join the conversation.