Overview
The Wuji Glove exposes six device data streams at once: raw tactile, zoned tactile, EMF poses, finger joint angles, hand skeleton, and tactile point cloud. Add the two cross-device coordinate-transform streamstf and tf_static, and a single subscription pass gives you everything the glove produces in real time.
Callbacks fire on SDK background worker threads, so your main thread never blocks. This is the shortest path to glove data.
Matching examples: examples/python/wuji_glove/0.subscribe_callback.py and examples/c/wuji_glove/0_subscribe_callback.c.
For field definitions of each stream, see SDK Reference. This page covers only how to run it and what the measurements show.
Prerequisites
Hardware
This example only reads. It writes no parameters.
Software
- Python
- C
Before You Start
Nothing. Power the device and connect the network. Hand model calibration isn’t a prerequisite for subscribing, though it does affect how wellhand_joint_angles and hand_skeleton match your hand. See Hand Model Calibration.
Data Flow
Device streams subscribe through a device handle. Global streams take no device handle and are subscribed once per process.Frame Structures
Measured on a glove resting on a desk, unworn, sampled for 3 seconds.Six Device Streams
Two Global Streams
tf runs an order of magnitude faster than the device streams because several upstream sources drive it. Heavy work inside a callback shows up here first.
Why 744, 572, and 526 Add Up
-1.0 marks a taxel as invalid or masked. It isn’t a pressure reading. On this glove, 218 of the 744 channels report -1.0:
All three converge on 526.
tactile_zones includes only channels that map to a hand region, and the 172 unzoned channels happen to be invalid. tactile_point_cloud drops invalid channels entirely and emits only points that have coordinates.
Use the point cloud when you need to know where the force lands, zones when you need to know which finger, and tactile when you need raw channel alignment.
Skeleton Joint Names
The 21 joints inhand_skeleton follow the MediaPipe hand topology in a fixed order:
joints[0] is wrist, and its pose is always the origin, because the whole skeleton chain uses the wrist as its reference frame. For where the wrist sits in the world, read the waist → r_wrist transform on the tf stream. The example printing wrist=[+0.000, +0.000, +0.000] is expected, not a data fault.
The Fifth Joint Angle
hand_joint_angles.fingers[i].angles always has length 5, but only the thumb uses all of it. Measured at rest:
For every finger but the thumb the fifth value stays 0 as alignment padding.
confidence reflects solver quality and drifts between 0.4 and 0.75 at rest on an uncalibrated glove.
Runtime Handling
C callbacks fire on dedicated worker threads, and the
frame pointer is valid only for the duration of the callback. Heap arrays such as data, joints, and poses are freed as soon as it returns, so never retain the pointer.
Integration Steps
- Python
- C
Running It
- Python
- C
Adapting It
The Example’s avg() Goes Negative on Invalid Channels
This is the one thing worth watching in this example. The Python example averages each zone withavg():
-1.0 lands straight in the numerator. With 20 of the palm’s 308 channels invalid, the output reads palm=-0.1 — a negative reading from a glove under no load at all. The C example prints palm[0], so when that first channel happens to be invalid it shows -1.000, which is exactly what the measurement produced.
Filter negatives first on both sides:
+0.015. The share of invalid channels varies by glove, so don’t hard-code a count.
Name an SN When Several Devices Share a Network
Both examples iterate every glove they find and connect to each one. On a shared network, limit that with--sn:
list[i].serial_number in the source before connecting.
Subscribe Only to What You Need
All six streams open means about 640 callbacks per second at rest. For tactile analysis keeptactile or tactile_point_cloud, for hand pose keep hand_skeleton, and callback pressure drops immediately.
Keep Callbacks Light
Each subscription gets its own worker thread. Callbacks within one subscription run serially and in order, while different subscriptions may run concurrently, so guard any state you share across them. Move file writes, algorithms, and lock waits to a consumer thread, and copy only the minimum inside the callback.Switch to Async
If callbacks don’t suit you, usesubscribe() with recv() and control the pacing yourself. See Subscribing Asynchronously.
Related
- Subscribing Asynchronously: the async/await form of the same streams
- Recording Data: write these streams to a replayable file
- Adjusting Stream Rate: bring 130 Hz down to what your application needs
- Data Subscription: subscription model and lifecycle
- Common Data Types:
FrameHeader,TactileFrame,HandSkeleton, and related structures