Give Hermes recognitions, not just photos: faces(), tracking ids, discovery
Hermes asked for structured detections instead of a bare JPEG. faces() returns the
faces in view with no photo: a persistent track id, bbox, detection confidence, how
long the person has been in view, and identity {name, similarity} or null, never a
made-up name. look() returns that same JSON as text plus the photo (send_image can
skip it); list_people() gives names and counts; robot://status and two prompts make
the server discoverable, where list_resources and list_prompts were empty. The
detector now tracks faces across frames (FaceTracker) and publishes the track id and
the identity as a second hypothesis.
Deliberately not built: embeddings in responses, age/gender attributes, auto-updating
face data, and a remote enroll tool (a prompt could make the robot call anyone "Kyle").
Checked end to end: a real Hermes turn on the local ornith model called faces() (0.03 s,
no image) and answered that Kyle was there at 0.78 similarity. Also: the camera is
calibrated (18 of 24 views, 0.296 px, outlier rejection added) and the calibration is
kept in pi/calibration and restored by the installer.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AFN8nRRCiDiMN7ChBpHJhs
This commit is contained in:
+26
-2
@@ -211,8 +211,8 @@ hotter, so fit the fan before enclosing it. Playback and the servos are untested
|
||||
|
||||
The only way in or out of the ROS graph. Serves MCP (SDK 2.3, streamable HTTP) on
|
||||
`http://10.55.0.2:8765/mcp`, the USB address only (retrying the bind if the link is not up yet), with
|
||||
a bearer token. **Tool names are the stable contract with Hermes**: `look()`, and `turn_head` /
|
||||
`head_position` only when a head is fitted. With no servos only `look` is registered, by design
|
||||
a bearer token. **Tool names are the stable contract with Hermes**: `look()`, `faces()`, `list_people()`, and `turn_head` /
|
||||
`head_position` only when a head is fitted. With no servos those two are not registered, by design
|
||||
(`head: false`; the node refuses `head: true` until `hermes_head` exists). `look()` waits for the next
|
||||
camera frame taken after the call (never a stale one) and passes the camera's JPEG through (1296x972,
|
||||
~155 KB); it also publishes `looking` on `/hermes/state` so the face squints and flashes.
|
||||
@@ -250,6 +250,30 @@ Hermes does it itself, so `look()` needs no change. Two consequences: each look(
|
||||
room in talos's Hermes image cache (Hermes's retention, not the robot's), and a look-and-describe turn
|
||||
takes ~70 s on the local models, mostly the vision call.
|
||||
|
||||
### Hermes's feedback on the bridge (2026-10-05) and what was done
|
||||
|
||||
Hermes (on talos, from `~/.hermes/cache/scratch/hermes-bot-v0-face-identity.md`) asked for recognitions
|
||||
instead of raw photos. **Built:** `faces()` returns the faces in view as structured JSON with no photo
|
||||
(`track_id`, pixel and normalised `bbox`, detection `confidence`, `seen_for_s`, and `identity`
|
||||
`{name, similarity}` or `null`); `look(send_image="always"|"never")` now returns that same JSON as a
|
||||
text block plus the photo (default kept as before: the image, so scene description still works);
|
||||
`list_people()` gives names and sample counts; a `robot://status` resource (hardware present or
|
||||
absent, what is detected, enrolled count, tools) and prompts `who_is_here` and `look_around` fill the
|
||||
previously empty `list_resources` / `list_prompts`; `/vision/faces` carries a persistent track id
|
||||
(`hermes_vision.tracking.FaceTracker`, matching by box overlap, identity re-checked once a second;
|
||||
`Detection2D.id` is the track id, `results[0]` the face, `results[1]` the identity if recognised).
|
||||
Verified with a real Hermes turn on the local `ornith` model: it called `faces()` (0.03 s, 593
|
||||
characters, no image, no vision call) and answered that Kyle was there at 0.78 similarity.
|
||||
**Declined, deliberately:** embeddings in responses (biometric templates, meaningless to an LLM,
|
||||
and the registry stays on the robot); age/gender/hat attributes (no model for them here, and guessing
|
||||
age and gender from faces is unreliable and sensitive); auto-updating a person's face data from new
|
||||
captures (it lets a stranger slowly become "Kyle" with nobody deciding that); a remote `enroll` tool
|
||||
(a prompt could make the robot call anyone "Kyle": enrolment stays the owner's step on the robot,
|
||||
`python3 -m hermes_vision.people enroll NAME`; a gated enrol tool, off by default, is possible if the
|
||||
owner wants it); detecting people, objects or motion (only faces exist, and `robot://status` says so).
|
||||
`look()`'s default was not flipped to JSON-only, because the image is what lets Hermes describe a
|
||||
scene; that default is the owner's call.
|
||||
|
||||
## Face recognition (opt-in)
|
||||
|
||||
`hermes_vision.recognize` / `people`: SFace embeddings on YuNet's landmarks. Nothing is stored until
|
||||
|
||||
Reference in New Issue
Block a user