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

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

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

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