Data Structure Reference
This page lists all common data type field definitions in the Wuji SDK.
For device-specific data structures, see the corresponding device documentation: Wuji Glove SDK data reference.
Common Types
FrameHeader
Header information for each data frame.
| Field | Type | Description |
|---|---|---|
seq | int | Incrementing sequence number |
timestamp_us | int | Device timestamp (microseconds) |
frame_id | str | Coordinate frame ID (e.g., "l_wrist"), max 32 characters |
Vector3 / Vector3F64
Three-dimensional vector. Vector3 uses f32 precision, Vector3F64 uses f64 precision (used for IMU data, ROS compatible).
| Field | Type | Description |
|---|---|---|
x | float | X component |
y | float | Y component |
z | float | Z component |
Quaternion
f64 precision quaternion representing 3D rotation.
| Field | Type | Description |
|---|---|---|
x | float | X component |
y | float | Y component |
z | float | Z component |
w | float | W component |
Pose
Position and orientation.
| Field | Type | Description |
|---|---|---|
position | List[float] | Position [x, y, z] (meters) |
orientation | Quaternion | Rotation quaternion |
Handedness
Device handedness enum, used for connecting by handedness.
| Value | Description |
|---|---|
Handedness.Left | Left hand (fourth character of serial number is J) |
Handedness.Right | Right hand (fourth character of serial number is K) |
ImuData
IMU sensor data, following the ROS sensor_msgs/Imu convention.
| Field | Type | Description |
|---|---|---|
header | FrameHeader | Frame header |
orientation | Quaternion | Orientation quaternion |
orientation_covariance | list[float] | Orientation covariance (length 9). A first element of -1 marks the orientation as unavailable |
angular_velocity | Vector3F64 | Angular velocity (rad/s) |
angular_velocity_covariance | list[float] | Angular velocity covariance (length 9) |
linear_acceleration | Vector3F64 | Linear acceleration (m/s²) |
linear_acceleration_covariance | list[float] | Linear acceleration covariance (length 9) |
Wuji Hand 2 does not run onboard orientation fusion, so orientation_covariance[0] is always -1 when subscribing through hand.imu().
Coordinate Transforms
FrameTransform
Single coordinate transform.
| Field | Type | Description |
|---|---|---|
timestamp_us | int | Timestamp (microseconds) |
parent_frame_id | str | Parent frame |
child_frame_id | str | Child frame |
translation | List[float] | Translation [x, y, z] (meters) |
rotation | Quaternion | Rotation quaternion |
FrameTransforms
Collection of coordinate transforms.
| Field | Type | Description |
|---|---|---|
transforms | List[FrameTransform] | Transform list |
Recording Types
For complete usage and code examples, see Data Recording.
TopicRecorder
MCAP recording session configurator. Register channels, then call start() to begin recording.
| Method | Parameters | Description |
|---|---|---|
__init__() | compression: str = "lz4", chunk_size: int = None | Create a recorder. Supports "lz4", "zstd", "none" |
record() | sub: Subscription | Register a subscription channel |
start() | output_path: str | Start recording, returns RecordingHandle |
RecordingHandle
Recording control handle returned by TopicRecorder.start().
| Method | Returns | Description |
|---|---|---|
pause() | — | Pause recording |
resume() | — | Resume recording |
stop() | RecordingSummary | Stop recording and return summary |
subscribe_metrics() | MetricsStream | Subscribe to real-time quality metrics |
subscribe_status() | StatusStream | Subscribe to recording status updates |
subscribe_alerts() | AlertStream | Subscribe to quality alerts |
RecordingSummary
Recording statistics returned by handle.stop().
| Field | Type | Description |
|---|---|---|
total_frames | int | Total frames recorded |
file_size | int | MCAP file size in bytes |
duration_s | float | Recording duration in seconds |
quality | QualitySummary | Quality statistics summary |
QualityMetrics
Real-time quality metrics (5-second sliding window).
| Field | Type | Description |
|---|---|---|
frame_drop_rate | float | Frame drop rate (0.0–1.0) |
frame_jitter_us | float | Inter-frame jitter in microseconds |
sync_offset_ms | float | Cross-channel sync offset in milliseconds |
sync_rate | float | Sync success rate (0.0–1.0) |
timestamp_ns | int | Nanosecond timestamp |
QualitySummary
Aggregate recording quality statistics.
| Field | Type | Description |
|---|---|---|
total_frames | int | Total frames received |
dropped_frames | int | Total frames dropped |
frame_drop_rate | float | Drop rate (0.0–1.0) |
avg_sync_offset_ms | float | Average sync offset in milliseconds |
max_sync_offset_ms | float | Maximum sync offset in milliseconds |
sync_rate | float | Sync success rate (0.0–1.0) |
spc_alert_count | int | Total SPC alerts triggered |
duration_s | float | Recording duration in seconds |
RecordingAlert
Quality alert.
| Field | Type | Description |
|---|---|---|
metric | str | Name of the metric that triggered the alert |
current_value | float | Current measured value |
threshold | float | Alert threshold |
message | str | Human-readable alert message |
RecordingStatus
Recording runtime status.
| Field | Type | Description |
|---|---|---|
state | str | Current state ("recording" or "paused") |
frame_count | int | Frames recorded so far |
duration_s | float | Elapsed duration in seconds |
Wuji Hand 2 Types
The schemas below are exposed by wuji_sdk.WujiHand2 through the resource-style interface. Feedback frames all carry a FrameHeader. frame_id is l_wrist or r_wrist (filled by the firmware from the device's own handedness), and timestamp_us is the firmware send time. Whole-hand feedback frames are variable-length and contain only online joints, identified by nid.
JointStateFrame
Whole-hand joint state subscription frame (hand.joint_states().subscribe()).
| Field | Type | Description |
|---|---|---|
header | FrameHeader | Frame header (seq + timestamp_us + frame_id) |
num_joints | int | Number of online joints in this frame (equals len(joints)) |
joints | list[JointStateEntry] | Online joint state entries, variable-length |
JointStateEntry
Single-joint state.
| Field | Type | Description |
|---|---|---|
nid | int | Node ID, identifies the joint across frames |
position | float | Position in radians |
velocity | float | Velocity in rad/s |
effort | float | Effort in amperes (Kt=1 placeholder) |
JointDiagnosticsFrame
Whole-hand joint diagnostics subscription frame (hand.joint_diagnostics().subscribe()), derived from the same realtime stream as joint_states.
| Field | Type | Description |
|---|---|---|
header | FrameHeader | Frame header |
num_joints | int | Number of online joints in this frame |
joints | list[JointDiagnosticsEntry] | Online joint diagnostics entries, variable-length |
comm | Hand2CommSummary | Frame-level communication health summary, refreshed at 1 Hz |
JointDiagnosticsEntry
Single-joint diagnostics snapshot.
| Field | Type | Description |
|---|---|---|
nid | int | Node ID |
status_word | StatusWord | Decoded status word |
current | float | Phase current in amperes |
vbus_v_fb | float | Bus voltage feedback in volts |
mcu_temp_c_fb | float | MCU temperature feedback in Celsius |
error_code_current | int | Current error code (stop / warning bits), decode with WujiHand2.describe_error() |
comm_response_rate_pct | int | This joint's RS485 bus response rate over the last second, 0–100 |
comm_timeout_total | int | This joint's cumulative RS485 bus timeouts |
Hand2CommSummary
Frame-level communication health, combining the device-internal (RS485) view with the SDK-local end-to-end (Ethernet) view. The device-internal part comes from a snapshot the SDK refreshes automatically at 1 Hz — no polling required.
| Field | Type | Description |
|---|---|---|
age_ms | int | Age of the device-internal snapshot in milliseconds. 65535 = never sampled successfully (the device-internal fields are zeros). 65534 = saturated, the snapshot is 65.5 s or older |
tactile_online_mask | int | Fingertip tactile online bitmap, bit0 = thumb … bit4 = pinky |
e2e_received | int | Frames received across all subscribed streams (cumulative) |
e2e_lost | int | Frames lost on the Ethernet segment, detected via sequence gaps (cumulative) |
e2e_reordered | int | Late/reordered frames (cumulative) |
e2e_duplicates | int | Duplicate frames (cumulative) |
e2e_window_loss_x100 | int | Loss rate over the last second, in 0.01% units |
rpc_total | int | Requests sent (cumulative). 0 means this transport does not report RPC statistics (only the wuji-proto transport does, and a live wuji-proto connection has always sent at least one request), so a zero here is not the same as "no retries happened" |
rpc_retries | int | Request retransmissions (cumulative) |
rpc_timeouts | int | Requests that ultimately timed out (cumulative) |
comm_get_failures | int | Failed internal snapshot refreshes (cumulative) |
tactile_response_rate_pct | list[int] | Per-finger tactile (node 5) bus response rate, 0–100, index 0 = thumb … 4 = pinky |
tactile_timeout_total | list[int] | Per-finger tactile cumulative bus timeouts, same index order |
sdk_dropped | int | Frames dropped inside the SDK because one of its in-process hops fell behind (cumulative) — either your subscription consumer or the internal stream handler. Distinct from e2e_lost, which is network loss |
Reading the device-internal fields. age_ms, tactile_* and the per-joint
comm_* fields all come from one snapshot the SDK refreshes at 1 Hz. The refresh is
deliberately skipped while a firmware upgrade or a tactile calibration is running, so a
briefly stale snapshot is expected rather than a fault. Tell the two cases apart with
comm_get_failures: a growing age_ms while comm_get_failures stays flat means the
refresh is being skipped on purpose, while comm_get_failures increasing means the refresh
itself is failing.
Counters saturate, they do not wrap. Every counter in this table stops at its
maximum (65535 for the 16-bit ones — e2e_reordered, e2e_duplicates,
rpc_retries, rpc_timeouts, comm_get_failures — and 4294967295 for the 32-bit ones)
and stays there. On a 1 kHz stream a long-running session can reach those ceilings, so
read these as deltas between two samples rather than as absolute lifetime totals.
StatusWord
Decoded status word public view (lower 16 bits).
| Field | Type | Description |
|---|---|---|
ext_state | int | Extended state value (Init / Ready / Enabled / Stopped, and so on) |
ext_state_name | str | Semantic name of ext_state |
position_limit_active | bool | Position limit triggered |
velocity_limit_active | bool | Velocity limit triggered |
current_limit_active | bool | Current limit triggered |
JointCommand
Single-joint realtime command (an element of the publisher.send([JointCommand, ...×20]) argument).
| Field | Type | Description |
|---|---|---|
position | float | Target position in radians |
velocity | float | Target velocity in rad/s, pass 0 when no feed-forward |
effort | float | Target effort in amperes, pass 0 when no feed-forward |
Constructor: JointCommand(position, velocity, effort). Each publisher.send(joints) call must pass a list[JointCommand] of length exactly 20 — include placeholders for offline joints.
Wuji Hand Types
The schemas below are exposed by wuji_sdk.WujiHand for Wuji Hand. For full field definitions, see Wuji Hand SDK Guide.
HandJointStates
Real-time 20-joint state (the hand.joint_states().subscribe() frame). Joint order is finger-major: {left,right}_finger{1..5}_joint{1..4}.
| Field | Type | Description |
|---|---|---|
header | FrameHeader | Frame header |
position | list[float] | 20 joint positions in radians, always length 20 |
velocity | list[float] | Angular velocity, length 0 when not provided |
effort | list[float] | Joint effort, length 0 when not provided |
{
"header": { "seq": 42, "timestamp_us": 1709876543210, "frame_id": "" },
"position": [0.001, -0.012, 0.087, 0.045, ...],
"velocity": [],
"effort": []
}HandJointCommand
20-joint command frame. seq is client-incrementing so receivers can detect dropped frames.
| Field | Type | Description |
|---|---|---|
seq | int | Client-incremented sequence number |
position | list[float] | Target positions, length 20 |
velocity | list[float] | Target velocity, optional |
effort | list[float] | Target effort, optional |
TactileGloveFrame
A single pressure frame from the paired tactile glove, on a 20×31 grid.
| Field | Type | Description |
|---|---|---|
handedness | int | Handedness (0 = Left, 1 = Right — note this is the opposite of the WujiHand SDO encoding) |
sequence | int | Frame sequence number |
timestamp_ms | int | Device timestamp in milliseconds |
pressure | list[float] | 620 f32 pressure values, row-major 20×31 |