SDK Data Reference

EMF & Hand Tracking

EMF Poses

sub = glove.emf_poses().subscribe()
poses = await sub.recv_async()
for pose in poses.poses:
    pos = pose.pose.position
    print(f"Position: [{pos[0]:+.3f}, {pos[1]:+.3f}, {pos[2]:+.3f}], confidence: {pose.confidence:.2f}")

EmfPose

Single-finger EMF pose.

FieldTypeDescription
posePosePose (position + orientation)
confidencefloatPositioning confidence (0.0~1.0, higher is more reliable. Values below 0.9 can be treated as unreliable)

EmfPoseArray

5-finger EMF pose array. Finger order: thumb, index, middle, ring, pinky.

FieldTypeDescription
headerFrameHeaderFrame header
posesList[EmfPose]5-finger pose list
{
  "header": {
    "seq": 100,
    "timestamp_us": 1709876543210,
    "frame_id": "l_wrist"
  },
  "poses": [
    {
      "pose": {
        "position": [0.041, 0.066, 0.022],
        "orientation": {
          "x": 0.0,
          "y": 0.0,
          "z": 0.0,
          "w": 1.0
        }
      },
      "confidence": 0.95
    }
  ]
}

Hand Tracking Products

# Joint angles
sub = glove.hand_joint_angles().subscribe()
angles = await sub.recv_async()
for i, finger in enumerate(angles.fingers):
    print(f"Finger {i}: angles={finger.angles}, confidence={finger.confidence:.2f}")

# Hand skeleton
sub = glove.hand_skeleton().subscribe()
skeleton = await sub.recv_async()
for joint in skeleton.joints:
    print(f"{joint.name}: position={joint.pose.position}")

FingertipPose

Single-finger fingertip pose.

FieldTypeDescription
posePosePose
confidencefloatConfidence

FingertipPoses

5-finger fingertip poses.

FieldTypeDescription
headerFrameHeaderFrame header
posesList[FingertipPose]5-finger fingertip poses
{
  "header": {
    "seq": 100,
    "timestamp_us": 1709876543210,
    "frame_id": "l_wrist"
  },
  "poses": [
    {
      "pose": {
        "position": [0.041, 0.066, 0.022],
        "orientation": {
          "x": 0.0,
          "y": 0.0,
          "z": 0.0,
          "w": 1.0
        }
      },
      "confidence": 0.95
    },
    ... // 5 fingers total
  ]
}

FingerJointAngles

Single-finger joint angles.

FieldTypeDescription
anglesList[float]Fixed array of 5 joint-angle slots (radians), accessed by index. The thumb uses all 5 values. The other four fingers use only the first 4, with the 5th value fixed at 0 as padding
confidencefloatIK solver confidence

HandJointAngles

Full-hand 21 DoF joint angles, where 21 DoF refers to the degrees of freedom of the hand kinematic model used by the hand tracking algorithm.

Returned per finger. The thumb maps to CMC3 + MCP1 + IP1, so all 5 slots of angles are used. The other four fingers map to MCP2 + PIP1 + DIP1, so only the first 4 slots are used, with the 5th slot as padding. Total 21 DoF for the whole hand. To keep the data structure uniform, the SDK returns a fixed-length 5 angles array per finger, so fingers contains 5 × 5 slots in total.

FieldTypeDescription
headerFrameHeaderFrame header
fingersList[FingerJointAngles]5-finger joint angles in thumb, index, middle, ring, pinky order
{
  "header": {
    "seq": 100,
    "timestamp_us": 1709876543210,
    "frame_id": ""
  },
  "fingers": [
    {
      "angles": [0.12, 0.34, 0.56, 0.78, 0.91],
      "confidence": 0.92
    },
    {
      "angles": [0.11, 0.22, 0.33, 0.44, 0.0],
      "confidence": 0.88
    },
    ... // 5 fingers total. For non-thumb fingers, the 5th value is 0 padding
  ]
}

SkeletonJoint

Hand skeleton keypoint.

FieldTypeDescription
namestrKeypoint name (such as index_finger_mcp)
posePosePose
confidencefloatConfidence

HandSkeleton

21-keypoint hand skeleton in the MediaPipe topology.

FieldTypeDescription
headerFrameHeaderFrame header
jointsList[SkeletonJoint]21 keypoints
{
  "header": {
    "seq": 100,
    "timestamp_us": 1709876543210,
    "frame_id": "l_wrist"
  },
  "joints": [
    {
      "name": "wrist",
      "pose": {
        "position": [0.0, 0.0, 0.0],
        "orientation": {
          "x": 0.0,
          "y": 0.0,
          "z": 0.0,
          "w": 1.0
        }
      },
      "confidence": 0.95
    },
    ... // 21 MediaPipe keypoints total
  ]
}

Output Rate Tuning

emf_poses and its derived streams publish at the EMF input rate (120 Hz) by default. To cut IK/FK compute, call glove.emf_poses_rate_divider() to set divider N — the output rate becomes input rate / N.

Calling

glove.emf_poses_rate_divider().set(4)   # 120 Hz → 30 Hz
n = glove.emf_poses_rate_divider().get()

Values and Default

ValueBehavior
1 (default)No decimation. Output rate equals input rate
≥ 2 integerOutput rate = input rate / N, not restricted to divisors of 120 (for example, N=5 yields 24 Hz)
< 1, non-numeric, or unsetTreated as 1. No error, no stream interruption

The change takes effect within 10 input frames (≤ ~83 ms at 120 Hz).

Affected Streams

Follows dividerUnaffected
emf_posesimu_* (IMU streams)
tip_posestf, tf_static
hand_joint_anglestactile, tactile_zones
hand_skeletontactile_binary, tactile_residual
tactile_point_cloud

EMF solving still runs per input frame. Only the publish step decimates, so tracking continuity stays intact.

Interaction with Calibration

When you call glove.calibrate() or calibrate_blocking(), the SDK temporarily forces the divider to 1 for the capture phase and restores the prior value when capture ends — including error and cancellation paths. Pre-setting N=4 won't stretch the calibration runtime by 4×. See Calibration.