~3 min read
Motions·
A pose is a place. A motion is a sentence — a nod, a shake, a wave — 9 of them built in. The twin below plays each one from its keyframes; tap a chip to loop it. Nothing here moves the metal.
| motion | what it says | frames | planned s | on the metal s |
|---|---|---|---|---|
approve |
a nod: the head dips and lifts twice | 5 | 3.3 | 6.5 |
deny |
a shake: the head turns left-right twice | 5 | 3.9 | 7.0 |
happy |
head up, a quick left-right wiggle with bobbing, a little bounce of the whole arm | 7 | 5.4 | 8.7 |
frustrated |
head drops, a slow look away, then a short sharp shake | 7 | 6.8 | 11.1 |
curious |
head tilts and lifts toward what it looks at, a small rise of the arm | 3 | 4.6 | 7.0 |
wave |
head raised on the wrist, three fast pans | 6 | 8.6 | 12.4 |
look_around |
a slow survey: far left, far right, up, back | 4 | 7.1 | 9.8 |
up · stays |
head up on the wrist and looking up; stays there | 1 | 2.5 | 3.2 |
sleep |
a slow fold onto the bench | 2 | 1.1 | 7.5 |
Planned seconds are travel ÷ speed per frame plus holds, from fomo/motions.py at build; "on the metal" is
what the real arm took on 2026-09-08 (5.6 V rail, settle per frame included — LIVE journal).
fomo motion happy --i-know # from the shell
motion(action="run", name="approve") # the agent's fifth tool
POST /api/control/motion {"name": "deny", "speed": 60}
"Show me you're happy" in the panel's chat ends up in the same call. A motion starts from wherever
the arm is and ends folded unless it says stay (up does). While it plays, state.busy reads
motion:happy 3/7, and stop ends it between or inside frames.
A keyframe·
rel is degrees from the calibrated home for the joints the frame moves — the others keep their
place. speed is degrees per second for the ramp (clamped to the guard's ceiling), hold_s a pause
once the frame has settled. Every frame is checked against the hard limits before the first write; a
frame the guard would never allow refuses to save.
Sign conventions on this arm: tilt + looks up, pan + looks left, wrist_flex − lifts the head up and
over (its + side is blocked at the fold), shoulder_lift + lifts.
Your own·
motion save peek frames='[{"rel":{"tilt":15,"pan":-20},"speed":60,"hold_s":0.2},{"rel":{"tilt":0,"pan":0}}]'
lands in ~/.fomo/motions.json, same shape as poses, relative to home — recalibrating shifts every
motion with the fold. A user motion named like a built-in shadows it; built-ins cannot be deleted.
What the metal did·
All nine were played twice back to back on 2026-09-08: 18/18 frames-complete, 155.7 s, servo temperatures unchanged (30–31 °C). Two things the recordings taught:
- The head servos top out near 70°/s (pan) and 55°/s (tilt) on this rail — tilt's factory torque limit is 500 ‰. Asking for more adds lag, not speed, and the guard then reads the lag as a stall. The built-ins ask for what the servos do.
- A loaded joint starts slowly. The wrist lifting the head off the forearm moves under half a degree in its first quarter second; the stall check waits 0.6 s before judging.
The built-ins do not use the elbow: on this supply it does not lift the forearm from the fold (rule 8/9 in the guard). On the 7.4 V supply, add it to your own.