Bring up the USB gadget link (package 0b, Pi side and talos side)

The Pi presents NCM Ethernet and ACM serial from a configfs gadget, started by
robot-usb-gadget.service before networking. usb0 gets 10.55.0.2/30 with no
gateway through netplan, matched by interface name: a MAC match turns into
PermanentMACAddress= in networkd, which a gadget interface does not have, so it
stayed unmanaged. talos reaches the Pi at 10.55.0.2 (ping ~2.4 ms, SSH works)
through a NetworkManager profile, host/omarchy/robot-usb-link.sh, matched by the
gadget's fixed host MAC.

Also clamp the face's tunable parameters (focus sets a blur radius, persistence
divides) and fps, after a review flagged unvalidated node parameters.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AFN8nRRCiDiMN7ChBpHJhs
This commit is contained in:
2026-10-04 20:53:09 -07:00
co-authored by Claude Sonnet 5.5
parent 55d33ab490
commit 69a93eeb2f
9 changed files with 181 additions and 11 deletions
+28 -6
View File
@@ -12,7 +12,8 @@ printed enclosure, speakers. Work until those arrive is limited to what the Pi,
- Ubuntu 24.04.5 server, kernel `6.8.0-1065-raspi` (fully upgraded), flashed from `talos`. User
`hermes` (key-only; passwordless sudo), SSH keys for `kyle@vade` (talos) and `kyle@straylight`.
- On Wi-Fi at `192.168.88.152` (MAC `d8:3a:dd:0d:66:f5`); `eth0` is not cabled. The owner says it has
a static IP on the rack switch; that address is not recorded here yet. `avahi-daemon` is
a static IP on the rack switch; that address is not recorded here yet. **USB link: `10.55.0.2`**
(see package 0b below); `ssh hermes@10.55.0.2` works from talos. `avahi-daemon` is
installed, but mDNS is off in `systemd-resolved` on talos, so `hermes-bot.local` doesn't resolve
there; use the IP.
- **cloud-init applies `network-config` and `user-data` on the first boot only.** To change Wi-Fi
@@ -40,6 +41,26 @@ printed enclosure, speakers. Work until those arrive is limited to what the Pi,
- Not done: audio (`wm8960-soundcard` overlay + mixer), camera (`cam -l`, `camera_ros`), PWM
(waits for servos). Ask before rebooting the Pi.
## Package 0b (USB link): Pi side and talos side working
- Pi: `dtoverlay=dwc2,dr_mode=peripheral`; `robot-usb-gadget.service` builds a configfs gadget
(NCM `usb0` + ACM `ttyGS0`, host MAC `02:68:65:72:6d:01`, robot MAC `02:68:65:72:6d:02`) before
networking; `serial-getty@ttyGS0` is enabled; `/etc/netplan/60-usb0.yaml` gives `usb0`
`10.55.0.2/30` with no gateway, so the default route stays on Wi-Fi. Installed by
`pi/install-usb-gadget.sh` (a backup of `config.txt` is `config.txt.bak-usbgadget`). NCM works on
the Pi 4 with kernel 1065; ECM was not needed.
- **netplan gotcha:** match the gadget interface by `name: usb0`. A `macaddress:` match becomes
`PermanentMACAddress=` in networkd, which a gadget interface lacks, so it stays unmanaged.
- talos (Omarchy, NetworkManager): `host/omarchy/robot-usb-link.sh` (needs sudo) adds profile
`hermes-robot-usb`: `10.55.0.1/30` on the interface with MAC `02:68:65:72:6d:01`, priority 100,
never-default. Verified from talos: ping ~2.4 ms, SSH over the link.
- Not yet verified: serial login prompt (talos's `/dev/ttyACM0` is `root:uucp`; use
`sudo screen /dev/ttyACM0 115200`). The `hermes` account has no password, so the console shows a
login prompt but cannot log in until the owner sets one; no autologin by design. Also not done:
the nftables rewrite, the Pi booting with Wi-Fi off, replug and second-host recovery,
`get_throttled` after a servo sweep on the splitter, the NixOS snippet, and straylight/other-host
testing. Currently the Pi is powered from talos's USB port (bench test, no servos).
## Face (`ros/hermes_face`)
- `render.py`: numpy port of `docs/face-prototype.html`, **flat face only** (head and lowpoly not
@@ -55,7 +76,8 @@ printed enclosure, speakers. Work until those arrive is limited to what the Pi,
`focus`, `jitter`, `intensity`, `initial_state`.
- `demo.py`: no ROS. `python -m hermes_face.demo --sequence` cycles the states on the panel;
`--png-dir DIR` writes a PNG per state without hardware.
- Tests: `python3 -m pytest test` in `ros/hermes_face` (23 pass on the Pi).
- Tests: `python3 -m pytest test` in `ros/hermes_face` (25 pass on the Pi). Renderer parameters
(`focus`, `persistence_ms`, `intensity`, `jitter`) are clamped; `fps` is clamped to 1-60.
- Measured on the Pi 4: ~9 ms per frame in isolation. With the CPU at full clock: 24% of a core at
20 fps and 40% at 30 fps (target was under 40% at 20 fps or more). Under `ondemand` the same
load reads 40% at 20 fps and ~67% at 30 fps. No C++ rewrite was needed.
@@ -66,10 +88,10 @@ printed enclosure, speakers. Work until those arrive is limited to what the Pi,
## Next
1. Package 0b: USB gadget Ethernet (`dwc2` peripheral, NCM + ACM, `usb0` at `10.55.0.2/30`). Needs a
reboot and a USB-C data cable to a host; the splitter has not arrived, so a bench test would
power the Pi from the host's port (fine without servos). Keep Wi-Fi up throughout.
2. Audio (package 1), camera (package 3), then the rest of the packages in `HANDOFF.md`.
1. Finish package 0b: nftables rewrite (accept 4713/8765 only on `usb0` from `10.55.0.1`), Wi-Fi-off
boot test, replug recovery, NixOS snippet in `host/nixos/`.
2. Audio (package 1; needs the `wm8960-soundcard` overlay and a reboot), camera (package 3), then
the rest of the packages in `HANDOFF.md`.
## Repository