Movements¶
Whenever no control-pose stream is driving it, the control hand plays from a set of named predefined movements. This page covers the set, the two modes it comes in, and the TOML file that defines the poses.
The movement set¶
VHI ships 23 movement definitions (Movements in src/MovementDefinitions.cs):
Rest, Thumb, Index, Middle, Ring, Pinky, Fist, TwoFingerPinch, ThreeFingerPinch, Pointing, ThumbExtension, IndexExtension, MiddleExtension, RingExtension, PinkyExtension, WristUpDown, WristLeftRight, PrecisionSphere, RockNRoll, Hook, PeaceSign, Pistol, ExtendedHand
A movement defines one max-flexion pose per animated joint (Euler degrees);
the rest pose is always neutral ([0, 0, 0]) and is not stored. The state
machine interpolates between rest and that max-flexion pose (see
held state, or a swept trajectory
for cycle).
Which movements are offered¶
The 17 the build exposes: Rest, the five fingers, Fist, the two pinches, Pointing, the
five extensions, WristUpDown and WristLeftRight. A movement the config names but this
list does not — PrecisionSphere, RockNRoll, Hook, PeaceSign, Pistol,
ExtendedHand — is hidden from cycling; a fully custom TOML whose names match neither
is exposed in full.
A gRPC client doesn't have to hard-code any of this: GetRecordingSessionState returns
available_movements, which is the valid set. Discover, don't guess.
Cycling through the set¶
The keyboard (Left / Right) walks the currently
available movement list - the same list
GetRecordingSessionState.available_movements returns. Cycling is circular: pressing Right at the end of the
list wraps to index 0, and Left at index 0 wraps to the last entry.
No "end of list" stop state, no error, no applied=false.
The programmatic equivalent is a standard discrete DOF with the desired name -
which is also how a client programmatically cycles (it iterates over
available_movements itself and issues a a discrete DOF for each). There is
no "cycle by index" RPC by design: the client owns the iteration order so it
can do something other than wrap-forward if needed (skip Rest, randomise,
follow a predicted-class trajectory, etc.).
The TOML config¶
The actual joint poses live in a TOML file, not in code:
- On first run VHI generates a default
user://movements.toml(MovementConfigGenerator). MovementConfigLoaderreads it into the in-memory pose set.- A
FileSystemWatcherhot-reloads the file - edit the TOML and the hand updates without restarting VHI. - The config path is the
ConfigFilePath[Export](defaultuser://movements.toml); a different file can also be loaded at runtime from the control panel.
This is the seam for customisation: to add or tweak a named movement, edit the TOML - no rebuild. See Add a custom movement.
Named movements vs. arbitrary poses
The TOML route is for movements you can name ahead of time. If you need to drive the control hand with an arbitrary, runtime-generated pose (a data glove, another model, generated trajectories), publish a control-pose stream instead - see Stream a custom pose.