Control Commands
These are per-tick, non-persistent commands sent under each device's commands
map. They are applied once and forgotten — if you stop sending them, the
device returns to idle.
All control commands are WebSocket-only (no HTTP equivalent) unless noted.
set_cursor_force
Apply a Cartesian force to the cursor (end-effector).
{
"inverse3": [{
"device_id": "049D",
"commands": {
"set_cursor_force": {
"vector": { "x": 0.0, "y": 0.0, "z": 1.5 }
}
}
}]
}
| Field | Type | Description |
|---|---|---|
vector | vec3 | Force in Newtons, in application space |
Forces are additive within a tick — multiple sources (your app, SDF HFX, navigation) sum before being sent to the device.
set_cursor_position
Command the cursor to a target position (position-mode control).
{
"inverse3": [{
"device_id": "049D",
"commands": {
"set_cursor_position": {
"position": { "x": 0.0, "y": -0.12, "z": 0.15 }
}
}
}]
}
| Field | Type | Description |
|---|---|---|
position | vec3 | Target position in metres, in application space |
The service computes the force needed to move the cursor toward the target. If safe-trajectory is enabled, the cursor velocity is rate-limited.
set_angular_torques
Apply torques to the three joints (angular force-mode control).
{
"inverse3": [{
"device_id": "049D",
"commands": {
"set_angular_torques": {
"torques": { "a0": 0.0, "a1": 0.0, "a2": 0.0 }
}
}
}]
}
| Field | Type | Description |
|---|---|---|
torques | angles3 | Joint torques |
set_angular_position
Command the joints to target angles (angular position-mode control).
{
"inverse3": [{
"device_id": "049D",
"commands": {
"set_angular_position": {
"angles": { "a0": 30.0, "a1": 45.0, "a2": 60.0 }
}
}
}]
}
| Field | Type | Description |
|---|---|---|
angles | angles3 | Target joint angles in degrees |
set_transform
Set the workspace transform (device-space → application-space). Unlike the other
commands, set_transform is persistent — the service remembers the last
value you sent. Stream it during camera motion, or send it once and leave it.
- WebSocket
- HTTP
{
"inverse3": [{
"device_id": "049D",
"commands": {
"set_transform": {
"transform": {
"position": { "x": 1.0, "y": 0.0, "z": 0.0 },
"rotation": { "x": 0.0, "y": 0.0, "z": 0.0, "w": 1.0 },
"scale": { "x": 1.0, "y": 1.0, "z": 1.0 }
}
}
}
}]
}
curl -X POST "http://localhost:10001/inverse3/049D/state/transform?session=:0" \
-H "Content-Type: application/json" \
-d '{"transform":{"position":{"x":1,"y":0,"z":0},"rotation":{"w":1,"x":0,"y":0,"z":0},"scale":{"x":1,"y":1,"z":1}}}'
For grip devices, only rotation has an effect. position and scale are
accepted for schema consistency with Inverse3 but have no effect on the grip.
If you need continuous locomotion, use the Navigation module
instead of manually streaming set_transform — it handles the physics, haptic
feedback, and workspace bounding for you.
probe_position / probe_orientation
Monitoring-only keepalives for sessions that don't send control commands (e.g., Haply Hub observing devices).
{
"inverse3": [{ "device_id": "049D", "commands": { "probe_position": {} } }]
}
{
"verse_grip": [{ "device_id": "DEF456", "commands": { "probe_orientation": {} } }]
}
If your session is already sending any control command (set_cursor_force,
set_cursor_position, etc.), the device state is refreshed automatically with
every response. Probes are only useful for read-only monitoring sessions.