PLAN · NO CODE YET
Six labs (drive · servo · leds · neopixels · distance · buzzer), Web Bluetooth over Nordic UART Service, same command vocabulary as maqueen. Hardware ground-truth: Robot-01 v3 schematic. Standalone repo, GitHub Pages.
drive · servo · leds · neopixels · distance · buzzer.M:, SRV:, LED:, RGB:, BUZZ:, DIST:) so any maqueen lab page that doesn't depend on micro:bit-specific surfaces (matrix, A/B button) is portable with near-zero JS changes.github.com/abourdim/esp32c3-lab, public, GitHub Pages auto-deploy.| UUID | |
|---|---|
| Service (Nordic UART) | 6e400001-b5a3-f393-e0a9-e50e24dcca9e |
| TX (write) — browser → device | 6e400002-… |
| RX (notify) — device → browser | 6e400003-… |
ESP32-C3 firmware uses NimBLE-Arduino. Browser uses Web Bluetooth (navigator.bluetooth.requestDevice). Chrome / Edge only.
Plain ASCII, lines terminated by \n. Long lines chunked at 20-byte BLE MTU.
M:80,80 ← drive motors (left%, right%) [-100..100] M:STOP ← halt motors SRV:1,90 ← servo (index 1..2, angle 0..180) SWEEP:1,0,180,1500 ← sweep servo i from a to b over T ms LED:1,1 ← simple LED (index 0..3, 0=off / 1=on) RGB:0,255,0,0 ← NeoPixel set (idx, r, g, b) RGB:ALL,0,128,0 ← all 4 NeoPixels green RGB:CLEAR ← all off BUZZ:440,200 ← play freq Hz for duration ms BUZZ:OFF ← stop tone DIST:? ← request a single ultrasonic reading STREAM:on ← enable telemetry streaming STREAM:off ← disable HELLO ← (built-in) firmware replies HELLO:<version> FW:? ← (built-in) firmware replies FW:<version>,<caps>
INFO:CONNECTED ← greeting HELLO:0.1.0 ← reply to HELLO FW:0.1.0,M+S+L+R+B+D ← capabilities DIST:37 ← distance in cm; "-" = no reading DIST:- ECHO:<seq> <verb> ← echo of the command (sequenced) ERR:<seq> <reason> BTN:1 ← SW1 (GPIO 0) pressed (only if STREAM:on) BTN:0 ← released BATT:3.86 ← battery voltage update
If a TX line begins with a sequence number followed by space — 12 M:80,80 — firmware echoes ECHO:12 M:80,80. Browser uses this to confirm delivery. js/ble-scheduler.js from maqueen handles this; we replicate. Off by default in v0.1 (fire-and-forget).
Per v3 schematic. Same maqueen command, different physical pins.
| Verb | Maqueen action (micro:bit) | Robot-01 action (ESP32-C3) |
|---|---|---|
M:left,right | I²C 0x10 motor regs | TB6612FNG: AIN1/AIN2/PWMA (GPIO 1/2/3) for left, BIN1/BIN2/PWMB (GPIO 6/7/10) for right |
M:STOP | both = 0 | brake both motors |
SRV:i,angle | I²C 0x14 / 0x15 (S1/S2) | LEDC PWM 50 Hz on GPIO 6 (J4 = servo 1) or GPIO 10 (J5 = servo 2) ⚠ shares pins with motor B — see § 7 |
LED:i,on | digital P8 / P12 | discrete LEDs D5–D8 (GPIO 1, 10) — note: shared with motor pins |
RGB:i,r,g,b | I²C 0x32 register | FastLED on GPIO 5 → onboard NeoPixel chain D1→D2→D3→D4 |
RGB:ALL,r,g,b | broadcast | fill_solid() |
BUZZ:f,ms | music.playTone() on P0 | ledcWriteTone() on GPIO 4 (transistor stage) |
BUZZ:OFF | music.stopAllSounds() | ledcWrite(0) |
DIST:? | sonarbit P1/P2 | pulseIn(ECHO) after pulse on TRIG, J6 (GPIO 20/21) |
STREAM:on/off | periodic broadcast | 100 ms loop posting BTN/BATT |
HELLO / FW:? | reply with version | reply with 0.1.0 + caps string |
esp32c3-lab/ ├── README.md ← overview · live URL · quick start ├── PLAN.md / plan.html ← this plan (md + html) ├── package.json ← npm run serve wraps tools/serve.py ├── manifest.json ← PWA manifest ├── sw.js ← minimal offline-cache service worker ├── .gitignore · .nojekyll ← repo housekeeping ├── index.html ← landing — 6 lab cards, connect, theme/lang pickers ├── assets/ │ └── styles.css ← ✅ ALREADY WRITTEN — 4 themes + UI components ├── js/ │ ├── ble.js ← Web Bluetooth NUS — connect, write, notify, reconnect │ ├── ble-scheduler.js ← serializes writes; seq# / echo │ ├── protocol.js ← high-level senders: drive(l,r), servo(i,a), led(i,s)… │ ├── lab-shell.js ← injects shared chrome (header, status pill, log) │ ├── i18n.js ← EN / FR / AR strings; RTL toggle on AR │ └── ui.js ← theme picker, lang picker, status pill, log scroll ├── labs/ │ ├── drive-lab.html ← virtual joystick → M:left,right │ ├── servo-lab.html ← two sliders → SRV:1,a / SRV:2,a + sweep │ ├── leds-lab.html ← four toggles for D5–D8 → LED:i,s │ ├── neopixels-lab.html ← four colour pickers → RGB:i,r,g,b │ ├── distance-lab.html ← live bar + numeric, polls DIST:? at 5 Hz │ └── buzzer-lab.html ← piano keys + freq/duration sliders → BUZZ:f,ms ├── firmware/ │ ├── esp32c3-lab.ino ← Arduino sketch — NimBLE NUS server + parser │ ├── platformio.ini ← pinned platform 6.7.0 + libs │ └── README.md ← wiring · flashing · troubleshooting ├── tools/ │ └── serve.py ← Python stdlib http.server → :8000 ├── serve.bat / serve.sh ← launchers └── .github/workflows/ └── pages.yml ← deploy → gh-pages
Round joystick (drag/tap) + STOP button
TX: M:l,r throttled 50 ms · M:STOP on release
Two sliders + presets (0° / 90° / 180° / sweep)
TX: SRV:i,a · SWEEP:i,a,b,t
4 toggle cards for D5–D8 + all-on/all-off
TX: LED:i,1 / LED:i,0
4 colour pickers + ALL/CLEAR + 6 preset palettes
TX: RGB:i,r,g,b · RGB:ALL,r,g,b · RGB:CLEAR
Big numeric (cm) + horizontal bar + sparkline
TX: DIST:? polled 5 Hz · RX: DIST:<n> / DIST:-
Piano (C-D-E-F-G-A-B-C) + freq/duration sliders
TX: BUZZ:f,ms · BUZZ:OFF
Every lab inherits from lab-shell.js: top header (title, back link, theme/lang pickers, status pill), right rail (or bottom on mobile) with TX/RX Message Log, BLE state banner.
paper (default, kid-friendly cream), steel (pro dark), forest (calm green), carbon (cyberpunk). Try the picker top-right of this page.BIN1/PWMB AND the servo headers. Cannot drive motor B AND a servo at the same time. Firmware enters one of two modes at boot, selectable via MODE:motors or MODE:servos (default: motors).BTN:1/0 events.BATT:? in v0.1. v0.2 needs a battery divider on a free GPIO.| Step | Command |
|---|---|
| Local serve | ./serve.sh (or serve.bat) → http://localhost:8000 |
| Flash firmware | Arduino IDE OR pio run -t upload |
| Push | git push → GitHub Action mirrors to gh-pages |
| Live | https://abourdim.github.io/esp32c3-lab/ |
ADDON:LIST)CMD: and LM: verbs from maqueen) — not on this hardwarepaper (light, classroom-ready) or steel (dark, workshop-ready)?
Default chosen: paper.ESP32-C3 Lab or Robot-01 Lab or something else?
Default chosen: ESP32-C3 Lab.<seq> prefix and waits for ECHO:<seq> before sending the next, OR fire-and-forget for v0.1?
Default chosen: fire-and-forget. Sequencing infra in ble-scheduler.js is wired but disabled.MODE:servos), or detect at runtime?
Default chosen: motor mode at boot. Servo lab issues MODE:servos on first SRV: command.github.com/abourdim/esp32c3-lab (public, gh-pages on master) on first push?
Default chosen: yes, public.Reply with:
go — I build files in this exact order and push:
git init · gh repo create · push · verify live URLgo but X — tweak (e.g. go but only 3 labs first, go but steel default, go but no PWA)stop — discard the plan and the one written file