Files
head-lights/docs/plans/2026-01-31-pico-side-animations-design.md
Alex c74371a24a Move all animations to Pico firmware, Pi becomes HTTP-serial bridge
Pico runs all 9 mood animations and jaw modes locally instead of
receiving per-LED serial commands from the Pi. New protocol: bare
integers for fire-and-forget jaw amplitude, "mood X" / "jaw X" for
mode switches. Cuts light_service.py from 409 to 193 lines.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 21:34:03 -06:00

1.5 KiB

Pico-Side Animations - Phase 1

Move all animation logic from Pi's light_service.py to Pico's firmware/main.py. Pi becomes a thin HTTP-to-serial bridge.

New Serial Protocol

Input Example Response Description
<int> 72 (none) Jaw amplitude 0-100, fire-and-forget
mood <mode> mood thinking OK Switch mood animation
jaw <mode> jaw talking OK Switch jaw animation

Mood modes: idle, listening, responding, pleasure, thinking, playful, commanding, love, sleep, off Jaw modes: idle, talking, off

Bare integers are jaw amplitude (fast path, no response). This replaces per-LED serial flooding.

Pico Firmware Architecture

Non-blocking main loop:

  1. Check serial (non-blocking poll)
  2. If data: integer -> jaw amplitude; string -> mode command
  3. Tick mood animation (based on mood_mode + time)
  4. Tick jaw animation (based on jaw_mode or amplitude)
  5. ~10-20ms frame pacing

All 9 mood animations ported from light_service.py using time.ticks_ms(). Jaw: "level" mode maps 0-100 to 13 LEDs, "talking" mode oscillates autonomously.

Pi light_service.py Changes

Remove: all animation logic, mood_buffer, per-LED helpers, main animation loop. Keep: HTTP API, serial connection management. POST /state -> sends mood <state>\n, waits for OK. POST /jaw/level -> sends <level>\n, fire-and-forget (no readline).

Files Changed

  • firmware/main.py - Full rewrite with animation engine
  • light_service.py - Strip down to HTTP-to-serial bridge