Files
hermes-bot/README.md
T
kyleandClaude Sonnet 5.5 4bd4729b46 Initial commit
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 14:28:01 -07:00

8.8 KiB
Raw Blame History

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:

    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:

    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_IPs, then:

    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:

    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:

    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