Initial commit

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-04 14:28:01 -07:00
co-authored by Claude Sonnet 5.5
commit 4bd4729b46
44 changed files with 519803 additions and 0 deletions
+205
View File
@@ -0,0 +1,205 @@
# Hermes robot
A small Wi-Fi robot that gives Hermes Agent eyes, ears, a voice and (optionally) a
neck. All thinking happens on your Omarchy machine. The robot only takes pictures,
moves its head, and carries audio.
```
Omarchy machine Robot (Pi Zero 2 W)
─────────────── ───────────────────
hermes-robot ─► Hermes Agent
│ voice mode / wake word
├── default mic = "Robot microphone" ◄─┐
├── default sink = "Robot speaker" ─────┤ PipeWire pulse tunnel, TCP 4713
│ └─► pipewire-pulse ─► I²S mic(s) + amp
└── MCP tools: look(), turn_head() ──────► robot_mcp_server.py, HTTP 8765
├─ Camera Module 3
└─ PCA9685 ─► 2 servos (optional)
```
## Parts
Prices are rough single-unit figures and will vary by vendor.
| Part | Notes | ≈ USD |
|---|---|---|
| Raspberry Pi Zero 2 W (the "WH" has headers soldered) | 2.4 GHz Wi-Fi only | 15–18 |
| microSD card, 16–32 GB | | 8 |
| Raspberry Pi Camera Module 3 | Autofocus; the "Wide" variant suits a desk robot | 25 |
| **Pi Zero camera cable** (22-pin to 15-pin) | The camera ships with the wrong cable for a Zero | 3 |
| INMP441 I²S MEMS microphone breakout, ×2 | One works; two give a stereo pair and a better signal | 3 each |
| MAX98357A I²S amplifier breakout | | 2–6 |
| Speaker, 4–8 Ω, 2–3 W, ~40 mm | | 3 |
| 5 V 3 A USB power supply | | 10 |
| *Optional head:* PCA9685 16-channel servo board | Clean hardware PWM over I²C | 6 |
| *Optional head:* 2× SG90 servos + pan/tilt bracket | | 8 |
| *Optional head:* 1000 µF electrolytic capacitor | Across the servo supply, against brown-outs | 1 |
| Dupont jumper wires, a bit of perfboard | | 5 |
Without the head, the robot is roughly $70; with it, about $85.
## Wiring
Pin numbers are **physical header pins** (1–40), not GPIO numbers. The microphone(s)
and amplifier share the I²S clock lines; that's expected.
**Microphones (INMP441)**
| INMP441 | Pi pin | |
|---|---|---|
| VDD | 1 (3.3 V) | **3.3 V only**, never 5 V |
| GND | 6 (GND) | |
| SCK | 12 (GPIO18, I²S BCLK) | |
| WS | 35 (GPIO19, I²S LRCLK) | |
| SD | 38 (GPIO20, I²S DIN) | |
| L/R | GND for mic A; 3.3 V for mic B | Selects left or right channel |
With two microphones, wire both identically except L/R, so their SD lines share pin 38.
**Amplifier (MAX98357A)**
| MAX98357A | Pi pin | |
|---|---|---|
| Vin | 2 (5 V) | |
| GND | 9 (GND) | |
| BCLK | 12 (GPIO18) | Shared with the mics |
| LRC | 35 (GPIO19) | Shared with the mics |
| DIN | 40 (GPIO21, I²S DOUT) | |
| SD, GAIN | leave unconnected | Defaults: enabled, 9 dB gain |
| Speaker + / − | to the speaker | |
**Optional head (PCA9685)**
| PCA9685 | Connects to | |
|---|---|---|
| VCC | Pi pin 17 (3.3 V) | Logic supply |
| GND | Pi pin 14 (GND) | |
| SDA | Pi pin 3 (GPIO2) | |
| SCL | Pi pin 5 (GPIO3) | |
| V+ terminal | **5 V from the power supply**, not from the Pi's header | Servos' power; add the capacitor here |
| Channel 0 | pan servo | |
| Channel 1 | tilt servo | |
Servos draw current spikes that will brown out the Pi if they share its header pins. Feed
the supply's 5 V to both the Pi (micro-USB) and the PCA9685's V+ terminal, with a common ground.
**Camera:** the Zero cable's narrow end goes in the Pi, contacts facing the board.
The `googlevoicehat-soundcard` overlay is the standard trick for this exact mic + amp pairing.
Google's AIY Voice HAT used the same chips, so its driver drives both in one full-duplex sound card.
## Setting up the Pi
1. Flash **Raspberry Pi OS Lite (64-bit)** with Raspberry Pi Imager. In its settings, set the
hostname (e.g. `robot`), your user, your Wi-Fi, and enable SSH.
2. Boot, find the Pi's IP, and give it a **DHCP reservation** on your router.
3. Copy the `pi/` folder over and run the installer, passing your Omarchy machine's IP:
```bash
scp -r pi robot.local:~/robot-setup
ssh robot.local
cd ~/robot-setup && chmod +x install.sh
./install.sh 192.168.1.20 # add --servos if you built the head
sudo reboot
```
The installer prints a token at the end. Keep it for the Hermes step.
4. After the reboot, check things on the Pi:
```bash
arecord -l # a "googlevoicehat" card should be listed
wpctl status # its source and sink should appear under Audio
rpicam-still -o test.jpg # camera works
systemctl status robot-mcp # MCP server running
```
5. If the camera is mounted upside down, set both `ROBOT_CAM_HFLIP=1` and `ROBOT_CAM_VFLIP=1`
in `/etc/robot-mcp.env`, then run `sudo systemctl restart robot-mcp`.
## Setting up Omarchy
1. **Audio tunnel.** Copy `omarchy/50-robot-tunnel.conf` to
`~/.config/pipewire/pipewire.conf.d/`, replace both `ROBOT_IP`s, then:
```bash
systemctl --user restart pipewire pipewire-pulse wireplumber
pactl list short sources | grep robot_mic # should show the robot
```
Omarchy's audio mixer (`wiremix`) will now list "Robot speaker" and "Robot microphone".
If `pactl` is missing, install it with `sudo pacman -S libpulse`.
2. **Hermes.** Add `ROBOT_MCP_TOKEN=<token>` to `~/.hermes/.env`. Merge
`omarchy/hermes-config-snippet.yaml` into `~/.hermes/config.yaml`, with `ROBOT_IP` replaced.
Then check the connection:
```bash
hermes mcp test robot
```
The tools will appear in Hermes as `mcp_robot_look`, `mcp_robot_turn_head` and so on.
3. **Launcher.** Install the wrapper, which switches your default audio to the robot for the
length of the session and restores it afterwards:
```bash
install -Dm755 omarchy/hermes-robot ~/.local/bin/hermes-robot
hermes-robot
```
Inside Hermes, `/voice on` starts the conversation. Set up the wake word as described in the
Hermes docs ("Wake Word") so you never need the keyboard.
## First test
Say or type: *"Look around and tell me what's on my desk."* Hermes should call `look`, then
describe the scene.
**One thing to confirm early:** that the image actually reaches the model. The server returns a
standard MCP image block, and the test client sees it correctly. If Hermes answers as though it
saw nothing, check `~/.hermes/logs/agent.log`, and make sure your model supports vision. If
Hermes turns out to drop image blocks from MCP results, the fallback is a small change to
`look()` to save the JPEG and return a path for Hermes's own vision tool. Tell me if that happens.
## Tuning and troubleshooting
- **Mic too quiet** (the level bar barely moves): on the Pi, run
`wpctl set-volume @DEFAULT_AUDIO_SOURCE@ 2.5`. Alternatively, lower `voice.silence_threshold`
in Hermes. A single mic is about 6 dB quieter than a pair, because the unused channel is
averaged in.
- **Hermes interrupts itself:** this is the robot hearing its own speaker. Raise
`voice.barge_in_threshold_multiplier`, point the speaker away from the mics, or enable
`pi/pipewire/60-echo-cancel.conf.optional` and uncomment the `pulse.device` lines in the
tunnel config.
- **Audio crackles:** this means weak Wi-Fi. Raise `pulse.latency` to 300–400. The Zero 2 W has
only 2.4 GHz Wi-Fi and a small antenna, so keep it within reasonable range of the router.
- **Robot devices vanish after the Pi reboots:** the tunnels reconnect every 5 s by themselves.
Start `hermes-robot` again once they reappear.
- **Head turns the wrong way:** set `ROBOT_PAN_INVERT=1` or `ROBOT_TILT_INVERT=1` in
`/etc/robot-mcp.env`, then restart `robot-mcp`.
## Security
- The microphone stream (port 4713) and the camera server (port 8765) are open only to your
Omarchy machine's IP, via nftables on the Pi.
- The camera additionally requires the bearer token.
- Traffic is unencrypted on your LAN. If that matters to you, put both machines on Tailscale and
use the Pi's tailnet address in both configs.
- If your Omarchy machine's IP changes, re-run `install.sh` with the new one.
## Files
```
pi/
install.sh one-shot Pi setup
robot_mcp_server.py MCP server: look, turn_head, head_position
requirements.txt MCP Python SDK 2.x
robot-mcp.service systemd unit
nftables-robot.nft port restriction
pipewire/50-network-server.conf exposes audio to the network
pipewire/60-echo-cancel.conf.optional
omarchy/
50-robot-tunnel.conf robot audio as local devices
hermes-config-snippet.yaml MCP and voice settings for Hermes
hermes-robot launcher that swaps default audio devices
```