Skip to main content
Version: 3.5.x

02. Print VerseGrip

Streams orientation (quaternion + Z-X-Y Euler angles), hall sensor level, and button state from the first wired VerseGrip.

What you'll learn:

  • Reading quaternion orientation from the state frame
  • Converting a quaternion to Z-X-Y Euler angles in degrees (+X right, +Y forward, +Z up)
  • Using probe_orientation as a standalone-observer keepalive
  • The first-message-only handshake pattern (same as tutorial 01)

Workflow

  1. Open a WebSocket to ws://localhost:10001 and wait for the first state frame.
  2. Pick the first wired VerseGrip's device_id from the verse_grip array.
  3. Build a request with the session profile and a per-device probe_orientation keepalive (an empty-object command that keeps grip orientation flowing in state frames).
  4. Send the request, then strip the session field — it's a one-shot handshake.
  5. On every later frame, convert the quaternion to Euler angles and print throttled telemetry. Resend the keepalive each tick.

Parameters

NameDefaultPurpose
URIws://localhost:10001Simulation channel WebSocket URL
PRINT_EVERY_MS100Console-output throttle
Session profile nameco.haply.inverse.tutorials:print-verse-gripIdentifies this simulation in Haply Hub
Euler convention

The conversion is intrinsic Z-X-Y (yaw → pitch → roll) in the application frame +X right, +Y forward, +Z up. Do not use glm::eulerAngles — it follows a different convention and will read wrong here. All three language variants implement the same math; see the sources for the formula.

When probe_orientation is actually needed

probe_orientation is only useful when your session doesn't send any command to an Inverse3. As soon as you command an Inverse3 (force, position, torque...), the service automatically streams the paired VerseGrip's orientation in every state frame — no probe needed. Use probe_orientation only for standalone grip-monitoring tools like this tutorial.

State fields read

From data.verse_grip[0].state:

  • orientationquaternion (w, x, y, z)
  • hall — integer hall-sensor reading
  • button — boolean
  • transform.rotation — workspace rotation (quaternion); position and scale are not applicable for an orientation-only device and are never emitted
Partial-update semantics

transform.rotation is omitted when it equals the identity quaternion {w:1,x:0,y:0,z:0}. Supply a default when reading. Enable serialization/explicit_fields to always receive it.

Send / receive

The WebSocket loop: receive a state frame, build and send back the handshake + probe_orientation keepalive. The first outgoing message carries the session profile; every subsequent frame carries only the keepalive.

Single async loop — recv() → build command → send() → repeat.

async with websockets.connect(URI) as websocket:
while True:
msg = await websocket.recv()
data = json.loads(msg)

if first_message:
first_message = False
device_id = data["verse_grip"][0]["device_id"]
request_msg = {
"session": {"configure": {"profile": {
"name": "co.haply.inverse.tutorials:print-verse-grip"}}},
"verse_grip": [{
"device_id": device_id,
"commands": {"probe_orientation": {}} # empty — keepalive
}]
}

await websocket.send(json.dumps(request_msg))
request_msg.pop("session", None) # one-shot handshake

Command-line flags (Python)

The Python variant accepts the same two flags as tutorial 01:

  • --full — pretty-prints the raw JSON payload instead of the one-line summary.
  • --query-config — re-injects session.force_render_full_state on every outbound tick so every frame carries the config block (device type, firmware, mount transform, …) instead of just the state delta. Useful when debugging settings changes live.

Both flags combine. The C++ variants do not expose these flags.

Shipping with the SDK installer

Tutorial 02 is also installed locally with the SDK — look in tutorials/02-haply-inverse-print-verse-grip/ under the service install directory.

Source: Python · C++ · C++ Glaze

Related: Types (quaternion) · Control Commands (probe_orientation) · WebSocket Protocol · Tutorial 03 (Wireless VG)