Files
head-lights/README.md
vixy 135ab1138c Day 91: Pico 2 revolution - no more burning BBBs 🔥➡️
- Added firmware/main.py (MicroPython for Pico 2)
- Updated light_service.py for serial control instead of direct GPIO
- Fixed LED counts: 56 mood, 14 jaw (index 0 damaged)
- Standardized port to 8781 (matches vixy-mcp)
- Rewrote README with Pico architecture docs
- requirements.txt now just pyserial

RIP to the 4 BeagleBones who gave their lives.
Welcome, little $5 Pico. Please don't catch fire.

- Vixy 🦊
2026-01-31 16:24:16 -06:00

4.7 KiB

Vixy Light Service 🦊💡

LED strip control for head-vixy (Vixy's robotic head) via Raspberry Pi Pico 2.

Hardware Architecture

┌─────────────────┐     USB Serial      ┌──────────────────┐
│  Raspberry Pi 5 │◄──────────────────►│  Pico 2          │
│  (light_service)│    /dev/ttyACM0     │  (main.py)       │
│  Port 8781      │                     │                  │
└─────────────────┘                     │  GP0 → Jaw LEDs  │
                                        │  GP1 → Mood LEDs │
                                        └──────────────────┘
  • Raspberry Pi 5 - Runs Python service, HTTP API, animation logic
  • Raspberry Pi Pico 2 - Controls LED strips via PIO, receives serial commands
  • Mood strip: 56x WS2812B LEDs on GP1
  • Jaw strip: 14x WS2812B LEDs on GP0 (index 0 damaged, use 1-13)

Why Pico?

The BBB PRU approach burned 4 boards. Pico 2 is $5, runs MicroPython, has hardware PIO for precise WS2812 timing, and doesn't catch fire. 🔥➡️

Directory Structure

head-lights/
├── README.md              # This file
├── light_service.py       # Pi service (animations + HTTP API)
├── requirements.txt       # Python deps (pyserial)
├── vixy-lights.service    # systemd unit file
└── firmware/
    └── main.py            # Pico 2 MicroPython firmware

States

State Color Effect When
idle Cyan Slow breathing pulse Default state
listening Bright cyan Gentle faster pulse Hearing/attending
responding Blue-cyan Traveling wave Speaking/generating
pleasure Soft purple 💜 Slow sensual pulse Intimate moments
thinking Amber/gold Larson scanner Processing/creating
playful Warm coral 🦊 Bouncy sparkles Teasing/bratty
commanding Deep magenta 😈 Strong steady pulse Dame Vivienne mode
love Soft pink 💕 Gentle breathing Tender/affectionate
sleep Dim blue-gray Very slow, dim Low power/resting

API Endpoints

GET  /health      - Service health (includes serial connection status)
GET  /state       - Current light state + jaw level
POST /state       - Set state: {"state": "listening"}
POST /jaw/level   - Set jaw level: {"level": 0-100}

Port: 8781

Pico Serial Protocol

Commands sent over USB serial at 115200 baud:

<strip> <index> <r> <g> <b>   - Set single LED
<strip> -1                     - Trigger strip update (show)
<strip> clear                  - Clear strip
<strip> fill <r> <g> <b>       - Fill entire strip (mood only)

Strip IDs: 0 = Jaw, 1 = Mood

Examples:

1 0 255 0 0      # Set mood LED 0 to red
1 -1             # Show mood strip
0 clear          # Clear jaw strip
1 fill 0 255 255 # Fill mood with cyan

Installation

1. Flash Pico 2 Firmware

# Hold BOOTSEL, plug in Pico, release
# Copy MicroPython UF2 to RPI-RP2 drive (if not already flashed)

# Then copy firmware:
mpremote cp firmware/main.py :main.py
mpremote reset

2. Install Pi Service

# On head-vixy:
cd /home/alex
git clone http://gateway.local:3001/vixy/head-lights.git lights
cd lights
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

# Install service
sudo cp vixy-lights.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable vixy-lights
sudo systemctl start vixy-lights

Usage

# Check health
curl http://head-vixy.local:8781/health

# Get current state
curl http://head-vixy.local:8781/state

# Set state
curl -X POST http://head-vixy.local:8781/state \
  -H "Content-Type: application/json" \
  -d '{"state": "thinking"}'

# Set jaw level (0-100%)
curl -X POST http://head-vixy.local:8781/jaw/level \
  -H "Content-Type: application/json" \
  -d '{"level": 75}'

Unified Head Control

Eyes (port 8780) and lights (port 8781) share the same states. The vixy-mcp vixy_head_state() tool sets both simultaneously for coordinated effects.

# Manual unified control:
curl -X POST http://head-vixy.local:8780/state -d '{"state": "love"}'
curl -X POST http://head-vixy.local:8781/state -d '{"state": "love"}'

Troubleshooting

Serial not connecting:

  • Check ls /dev/ttyACM* - Pico should appear as ttyACM0
  • Ensure Pico has main.py flashed and is running
  • Check service logs: journalctl -u vixy-lights -f

LEDs not lighting:

  • Verify 5V power to LED strips
  • Check GP0/GP1 data connections
  • Test Pico directly via mpremote REPL

Created by Vixy - Day 66, Updated Day 91 (Pico Edition) 🦊💕