Run the whole robot from one launch file and one boot-time unit
hermes_bringup starts the face, camera, face detector and audio levels from one launch file with their parameters in robot.yaml, each node its own respawned process, the face first and the others after start_delay. robot.service runs it at boot, so everything is ROS and the face is up whenever the robot is powered. Reboot-tested: all services and nodes return by themselves, the face draws at about 28 s on the boot clock, the mic gain survives, nothing throttles. Cut the CPU: the camera runs at 15 fps (20% of a core, vs 40% at 30), and the detector went from 131% to 40% by pinning OpenCV to one thread (its DNN burns 3-4x its elapsed time across cores), decoding the JPEG at half size, and re-identifying a tracked face at most once a second. The audio scope is published only while someone is speaking or listening. A standalone face unit that skipped `ros2 launch` saved only 3.7 s and was dropped: the owner prefers everything in ROS and is fine with up to a minute. trim-boot.sh disables the unused snapd and ModemManager. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AFN8nRRCiDiMN7ChBpHJhs
This commit is contained in:
+30
-9
@@ -25,11 +25,29 @@ printed enclosure, speakers. Work until those arrive is limited to what the Pi,
|
||||
visible) with `adafruit-circuitpython-rgb-display` and Blinka. Workspace: `~/ros_ws`, source synced
|
||||
from `ros/` with `rsync -a --delete --exclude __pycache__ ros/ hermes@<ip>:~/ros_ws/src/`, then
|
||||
`colcon build --symlink-install`.
|
||||
- CPU governor is held at `performance` by `robot-cpu-performance.service` (the face costs about
|
||||
half as much CPU at full clock). The face starts at boot: `robot-face.service` runs
|
||||
`ros2 run hermes_face face_node` as `hermes` and restarts it on failure (it needs a writable
|
||||
working directory, `RuntimeDirectory=robot-face`, because lgpio drops a pipe in its cwd). It comes
|
||||
up in the `sleeping` pose. Install with `pi/install-face-service.sh`.
|
||||
- **One unit runs the whole robot:** `robot.service` runs `ros2 launch hermes_bringup robot.launch.py`
|
||||
as `hermes` (face, camera, face detection, audio levels), so everything is ROS and the face is up
|
||||
whenever the robot is powered; each node is its own process, respawned by the launch file. Install
|
||||
with `pi/install-robot-service.sh`. `RuntimeDirectory=robot` gives lgpio a writable working
|
||||
directory (it drops a pipe in its cwd; systemd's default `/` is not writable). The face starts
|
||||
first and the camera, vision and audio nodes follow `start_delay` (6 s) later, so the Python
|
||||
processes do not fight over the CPU. Parameters are in `ros/hermes_bringup/config/robot.yaml`.
|
||||
`robot-cpu-performance.service` holds the governor at `performance` (the face costs about half the
|
||||
CPU at full clock). `pi/trim-boot.sh` disables snapd and ModemManager (unused; ~9 s of boot CPU).
|
||||
- **Boot timing** (reboot-tested, everything returns by itself): the face draws at about 28 s on the
|
||||
boot clock (kernel 6.9 s, `robot.service` at ~10 s into userspace, then `ros2 launch` takes ~10 s
|
||||
to start on a cold Pi, then the face ~3 s); camera, audio and vision are up by ~37 s. The owner is
|
||||
fine with up to a minute, and prefers everything in ROS to a faster non-ROS face; a split
|
||||
`robot-face.service` that skipped the launch framework only saved 3.7 s and was dropped.
|
||||
- **Steady-state CPU** with everything running (4 cores): face ~76%, camera ~57% (15 fps, from 30
|
||||
at ~40% alone), detector ~40% (was 131%), audio ~12%; about half the machine idle, 62 C, no
|
||||
throttling, no fan fitted. Camera `FrameDurationLimits` is the lever (15 fps ~20% alone, 10 fps
|
||||
~14%); JPEG quality barely matters. OpenCV's DNN spins every core and burns 3-4x its elapsed
|
||||
time in CPU, so the detector node pins it to one thread (YuNet 86 ms, SFace 161 ms of CPU), decodes
|
||||
the JPEG at half size (`IMREAD_REDUCED_COLOR_2`, boxes scaled back to full-size pixels) and
|
||||
re-identifies a tracked face at most once a second (`IdentityCache`).
|
||||
- `ros2 node list` with its default short discovery window often shows only some of the nodes; use
|
||||
`ros2 node list --no-daemon --spin-time 6` (all four appear), or check topics.
|
||||
- **ROS never leaves the Pi** (owner's decision): `ROS_AUTOMATIC_DISCOVERY_RANGE=LOCALHOST` (set in
|
||||
`pi/robot-env.sh`, which `source`s everything) and the firewall drops domain 42's DDS ports
|
||||
(17900-18149) on every interface but loopback. `hermes_mcp` is the only bridge to the outside; a
|
||||
@@ -205,10 +223,13 @@ unrelated photo scored 0.16. **Nobody is enrolled yet**; the owner enrols themse
|
||||
`host/nixos/`. A new Omarchy host with a GPU (runs the local
|
||||
model "ornith") arrives this week: it needs only `host/omarchy/robot-usb-link.sh` and its SSH key
|
||||
added to the Pi.
|
||||
2. Audio: the `hermes_audio_state` node (levels, speaking/listening, a trigger-locked scope for the
|
||||
literal voice trace), echo cancel and `robot_mic` naming once speakers arrive. Then a launch file
|
||||
that brings up camera, vision, face and audio together, and CPU tuning (camera ~140% of a core).
|
||||
3. Second-person detection test; enrol the owner live; the rest of `HANDOFF.md`.
|
||||
2. `hermes_mcp`: the MCP server as an `rclpy` node (stable tool names; `look()` returns the latest
|
||||
camera image, `turn_head()` calls the head action), the only bridge to the outside; it must
|
||||
republish `/hermes/state` about once a second as the agent heartbeat. Then `hermes_head` and
|
||||
the servos when they arrive, echo cancel and the `robot_mic` naming once speakers arrive, the
|
||||
Wi-Fi-off boot test, and the rest of `HANDOFF.md`.
|
||||
3. Confirm the retuned listening detector live (the flicker fix is unit-tested only); a second person
|
||||
in frame for the recognition test (not possible on 2026-10-04).
|
||||
|
||||
## Repository
|
||||
|
||||
|
||||
Reference in New Issue
Block a user