> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wuji.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# 通用数据类型

本页列出 Wuji SDK 中所有通用数据类型的字段定义。

<Info>
  各设备特定的数据结构请参阅[下方对应的产品文档](#设备专属类型)。
</Info>

## 通用类型

### FrameHeader

每帧数据的头部信息。

| 字段 | 类型 | 说明 |
| - | - | - |
| `seq` | `int` | 递增序列号 |
| `timestamp_us` | `int` | 设备时间戳（微秒），含义见[数据帧时间戳](/docs/wuji-sdk/time-sync/#数据帧时间戳) |
| `frame_id` | `str` | 坐标系 ID（如 `"l_wrist"`），最大 32 字符 |

### Vector3 / Vector3F64

三维向量。`Vector3` 使用 f32 精度，`Vector3F64` 使用 f64 精度（用于 IMU 数据，ROS 兼容）。

| 字段 | 类型 | 说明 |
| - | - | - |
| `x` | `float` | X 分量 |
| `y` | `float` | Y 分量 |
| `z` | `float` | Z 分量 |

### Quaternion

旋转四元数。Python 统一为 `Quaternion`，C 按数据流的实际精度分为 `WujiQuaternionF32` 与 `WujiQuaternionF64`。

| 字段 | 类型 | 说明 |
| - | - | - |
| `x` | `float` | X 分量 |
| `y` | `float` | Y 分量 |
| `z` | `float` | Z 分量 |
| `w` | `float` | W 分量 |

### Pose

位姿，包含位置和朝向。

| 字段 | 类型 | 说明 |
| - | - | - |
| `position` | `List[float]` | 位置 \[x, y, z]（米） |
| `orientation` | [Quaternion](#quaternion) | 旋转四元数 |

### Handedness

设备手性枚举，用于[按手性连接](/docs/wuji-sdk/device-connection/)。C 侧的等价常量是 `WUJI_HANDEDNESS_LEFT`（`0`）与 `WUJI_HANDEDNESS_RIGHT`（`1`）。Wuji Hand 的两个 handedness 读取接口返回原始 `uint8_t` 而非该枚举，且两者编码彼此相反，取值约定见 [Wuji Hand 数据订阅](/docs/wuji-sdk/data-subscription/)。

| 值 | 说明 |
| - | - |
| `Handedness.Left` | 左手（序列号第 4 位为 `J`） |
| `Handedness.Right` | 右手（序列号第 4 位为 `K`） |

### ImuData

IMU 传感器数据，遵循 ROS `sensor_msgs/Imu` 约定。

| 字段 | 类型 | 说明 |
| - | - | - |
| `header` | [FrameHeader](#frameheader) | 帧头 |
| `orientation` | [Quaternion](#quaternion) | 朝向四元数 |
| `orientation_covariance` | `list[float]` | 朝向协方差（长度 9），首元素为 `-1` 表示朝向不可用 |
| `angular_velocity` | [Vector3F64](#vector3-/-vector3f64) | 角速度（rad/s） |
| `angular_velocity_covariance` | `list[float]` | 角速度协方差（长度 9） |
| `linear_acceleration` | [Vector3F64](#vector3-/-vector3f64) | 线加速度（m/s²） |
| `linear_acceleration_covariance` | `list[float]` | 线加速度协方差（长度 9） |

## 坐标变换

### FrameTransform

单个坐标变换。

| 字段 | 类型 | 说明 |
| - | - | - |
| `timestamp_us` | `int` | 时间戳（微秒） |
| `parent_frame_id` | `str` | 父坐标系 |
| `child_frame_id` | `str` | 子坐标系 |
| `translation` | `List[float]` | 平移 \[x, y, z]（米） |
| `rotation` | [Quaternion](#quaternion) | 旋转四元数 |

### FrameTransforms

坐标变换集合。

| 字段 | 类型 | 说明 |
| - | - | - |
| `transforms` | `List[FrameTransform]` | 变换列表 |

## 录制类型

完整用法和代码示例详见 [数据录制与离线处理](/docs/wuji-sdk/data-recording/)。

### TopicRecorder

MCAP 录制会话配置器。注册通道后调用 `start()` 开始录制。

| 方法 | 参数 | 说明 |
| - | - | - |
| `__init__()` | `compression: str = "lz4"`, `chunk_size: int = None` | 创建录制器，支持 `"lz4"`、`"zstd"`、`"none"` |
| `record()` | `sub: Subscription` | 注册订阅通道到录制器 |
| `start()` | `output_path: str` | 开始录制，返回 `RecordingHandle` |

### RecordingHandle

录制控制句柄，由 `TopicRecorder.start()` 返回。

| 方法 | 返回值 | 说明 |
| - | - | - |
| `pause()` | — | 暂停录制 |
| `resume()` | — | 恢复录制 |
| `stop()` | `RecordingSummary` | 停止录制，返回统计摘要 |
| `subscribe_metrics()` | `MetricsStream` | 订阅实时质量指标流 |
| `subscribe_status()` | `StatusStream` | 订阅录制状态流 |
| `subscribe_alerts()` | `AlertStream` | 订阅质量告警流 |

### RecordingSummary

录制统计摘要，由 `handle.stop()` 返回。

| 字段 | 类型 | 说明 |
| - | - | - |
| `total_frames` | `int` | 总帧数 |
| `file_size` | `int` | MCAP 文件大小（字节） |
| `duration_s` | `float` | 录制时长（秒） |
| `quality` | `QualitySummary` | 质量统计摘要 |

### QualityMetrics

实时质量指标（5 秒滑动窗口）。

| 字段 | 类型 | 说明 |
| - | - | - |
| `frame_drop_rate` | `float` | 丢帧率（0.0\~1.0） |
| `frame_jitter_us` | `float` | 帧间抖动（微秒） |
| `sync_offset_ms` | `float` | 跨通道同步偏差（毫秒） |
| `sync_rate` | `float` | 同步成功率（0.0\~1.0） |
| `timestamp_ns` | `int` | 纳秒时间戳 |
| `channels` | `list[ChannelHealth]` | 每通道健康明细，见 [ChannelHealth](#channelhealth) |

### ChannelHealth

单通道健康明细（[QualityMetrics](#qualitymetrics) 的 `channels` 元素）。

| 字段 | 类型 | 说明 |
| - | - | - |
| `channel_name` | `str` | 通道名 |
| `channel_id` | `int` | 通道 ID |
| `actual_hz` | `float` | 实测帧率（Hz） |
| `drop_rate` | `float` | 该通道丢帧率（0.0\~1.0） |
| `last_frame_age_ms` | `int \| None` | 距最近一帧的毫秒数，尚未收到帧时为 `None` |
| `jitter_us` | `float` | 帧间抖动（微秒） |
| `is_online` | `bool` | 通道当前是否在收数 |
| `last_downtime_ms` | `int \| None` | 最近一次断流时长（毫秒），从未断流为 `None` |

### QualitySummary

录制质量汇总统计。

| 字段 | 类型 | 说明 |
| - | - | - |
| `total_frames` | `int` | 总帧数 |
| `dropped_frames` | `int` | 丢失帧数 |
| `frame_drop_rate` | `float` | 丢帧率（0.0\~1.0） |
| `avg_sync_offset_ms` | `float` | 平均同步偏差（毫秒） |
| `max_sync_offset_ms` | `float` | 最大同步偏差（毫秒） |
| `sync_rate` | `float` | 同步成功率（0.0\~1.0） |
| `spc_alert_count` | `int` | SPC 告警次数 |
| `duration_s` | `float` | 录制时长（秒） |

### RecordingAlert

质量告警。

| 字段 | 类型 | 说明 |
| - | - | - |
| `metric` | `str` | 触发告警的指标名称 |
| `current_value` | `float` | 当前测量值 |
| `threshold` | `float` | 告警阈值 |
| `message` | `str` | 可读的告警信息 |

### RecordingStatus

录制运行状态。

| 字段 | 类型 | 说明 |
| - | - | - |
| `state` | `str` | 当前状态（`"recording"` 或 `"paused"`） |
| `frame_count` | `int` | 已录制帧数 |
| `duration_s` | `float` | 已用时长（秒） |

## 设备专属类型

| 产品 | 类型定义 |
| - | - |
| Wuji Hand 2.2 (Beta) | [Wuji Hand SDK 接口参考](/docs/wuji-hand/latest/sdk-reference/#数据类型) |
| Wuji Hand 2.1 (Beta) | [Wuji Hand SDK 接口参考](/docs/wuji-hand/beta1/sdk-reference#数据类型) |
| Wuji Glove | [Wuji Glove 数据流概览](/docs/wuji-glove/sdk-data-reference/) |

## 错误码分类

SDK 有三类互不相通的错误码，数值不能跨类解读：

| 类别 | 出现位置 | 解码方式 |
| - | - | - |
| 编码器标定码（`u8`） | 编码器标定结果的 `enc1_error_code` / `enc2_error_code` | 标定专用错误码，表示该次标定步骤的失败原因（enc1 是 0–9 的小枚举，enc2 按标定阶段分段编码），不可传 `describe_error()`。可读名称用标定结果对象的 `enc1_error_name` / `enc2_error_name` 只读属性获取 |

错误码 `0` 表示当前无故障，码表不包含该值。`describe_error(0)` 返回 `None` 时无需处理。如果非零错误码返回 `None`，应保留原始数值用于日志和故障报告。这可能表示固件包含 SDK 码表尚未收录的错误码。

## C SDK 通用约定

本节补充 C SDK 的初始化、错误处理、内存生命周期、回调约束和 CMake 构建约定。具体设备能力仍在对应产品页面中说明。

## 初始化与约定

**初始化**

进程级初始化一次，结束时释放：

```c theme={null}
#include "wuji_sdk.h"

if (wuji_init(NULL) != WUJI_STATUS_OK) {
    fprintf(stderr, "init failed: %s\n", wuji_last_error());
    return 1;
}

// ... 业务逻辑

wuji_shutdown();
```

**返回值分类**

* `WujiStatus` — 多数操作（`wuji_init` / `wuji_scan` / `wuji_connect` / 订阅打开等），`WUJI_STATUS_OK` 表示成功，失败时通过 `wuji_last_error()` 获取当前线程错误描述。
* `int32_t` — 元信息读取（`wuji_dev_serial_number` / `wuji_dev_device_name`）返回写入字节数。
* `uint8_t` — 状态查询 `wuji_dev_is_connected`。
* `void` — `wuji_shutdown` 与资源释放函数。

**资源释放函数**

* `wuji_discovered_free` — `wuji_scan` 后释放设备列表
* `wuji_dev_release` — 与 `wuji_connect` 配套，断开后释放设备句柄
* `wuji_sub_close` — 关闭订阅句柄

**用户信息结构体**

`WujiUserInfo` 含 7 个字段：`user_id`、`display_name`、`description`、`external_id`、`is_default`、`created_at`、`updated_at`。`wuji_update_user` 通过 `WujiUserUpdate` 只传要改的字段，置位 `clear_description` / `clear_external_id` 可清空对应值。用户管理的完整接口清单见 [SDK 用户与标定数据](/docs/wuji-sdk/device-params/#sdk-用户管理)。

## 错误码描述

`wuji_hand_2_describe_error` 是静态函数（无需设备连接），把设备故障码（来自 `joint_diagnostics` 的 `error_code_current`，与 Python SDK 错误历史、标定结果携带的是同一套码值）解码到 `WujiErrorInfo`。函数只接受设备故障码。Python SDK 的标定结果中另有编码器专用的错误字节，属不同枚举，不可传入本函数。Wuji Hand 关节诊断（`wuji_hand_get_all_diagnostics` 返回）的 `WujiHandJointDiagnostics.error_code` 位域同样不可传入：

```c theme={null}
WujiErrorInfo info = {0};
// 0x2102 = Overcurrent（ImmediateStop / ManualClear），生产中真实可能命中的故障码
if (wuji_hand_2_describe_error(0x2102, &info) == WUJI_STATUS_OK) {
    printf("name=%s severity=%s\ndesc=%s\ncause=%s\n",
           info.name, info.severity, info.desc, info.cause);
}
```

未知错误码返回 `WUJI_STATUS_ERR_NOT_FOUND`。`severity` 取值：`Warning` / `DeferredStop` / `ImmediateStop` / `Fatal`。`clear_policy` 取值：`AutoClear` / `ManualClear` / `NonClearable`。

## 使用约束

C SDK 用户必须遵守以下约束，否则会出现 use-after-free、死锁或读到失效错误描述：

* typed 回调的 frame 指针仅在回调期间有效，返回后堆字段即被释放。需要保留的数据必须在回调内拷贝出来，不得保存指针。
* 不要在订阅自身的回调里调 `wuji_sub_close`。`close` 会 join worker 线程，在自身回调中调用必死锁。请在外部线程上 close。
* `wuji_last_error()` 返回值仅在同线程下一次 `wuji_*` 调用前有效。需要保留的错误描述应立即拷贝。
* `END` / `ERROR` 是终止帧，回调收到这两类帧后流不再有新数据，但仍需调用 `wuji_sub_close` 释放订阅句柄。
* 字符串 getter 使用两步查询：先用 `buf=NULL, buf_len=0` 获取 `*needed`（所需字节，含 NUL），再分配缓冲第二次调用填充。直接传不足缓冲会返回 `WUJI_STATUS_ERR_BUFFER_TOO_SMALL`，不做截断。
* 整手批量读（`get_all_effort_limit` / `get_all_mit_params`）返回 flat-20 数组 + 在线 bitmap，用 `WUJI_JOINT_ONLINE(mask, i)` 宏判断槽位是否有效，否则读到离线关节的占位值（0 或 NaN）。
* 标定反馈回调在标定 worker 线程触发，`feedback` 指针仅回调期间有效。回调内调用 session 接口不会死锁，SDK 会拦截：`wuji_glove_calibration_wait` 与 `wuji_glove_calibration_try_finish` 返回 `WUJI_STATUS_ERR_INVALID_ARG`，`wuji_glove_calibration_session_free` 把原因记录到 `wuji_last_error()` 并跳过这次释放——session 仍然存活，必须在回调返回后再释放一次。`wuji_glove_calibration_cancel` 可以在回调内安全调用。session 使用完毕后调用 `wuji_glove_calibration_session_free`，标定结果使用完毕后调用 `wuji_glove_calibration_result_free`。
* `WujiUserInfo` 持堆字符串：单个结构用 `wuji_user_info_free`，`wuji_list_users` 返回的数组用 `wuji_user_info_array_free`。

## Python 接口对照

下表按功能列出 C 与 Python 的对应接口。跨设备能力的完整用法见上方导语列出的能力章，设备专属接口见本页对应小节。

<div style={{overflowX: "auto"}}>
  <table>
    <thead>
      <tr><th className="nowrap">功能</th><th className="nowrap">C</th><th className="nowrap">Python</th></tr>
    </thead>

    <tbody>
      <tr><td className="nowrap">初始化</td><td className="nowrap"><code>wuji\_init(NULL)</code></td><td className="nowrap"><code>SdkManager.instance()</code></td></tr>
      <tr><td className="nowrap">扫描</td><td className="nowrap"><code>wuji\_scan(\&devs, \&count)</code></td><td className="nowrap"><code>manager.scan()</code></td></tr>
      <tr><td className="nowrap">连接</td><td className="nowrap"><code>wuji\_connect(\&target, alias, \&opts, \&dev)</code></td><td className="nowrap"><code>manager.connect(...)</code> / <code>manager.auto\_connect(...)</code></td></tr>
      <tr><td className="nowrap">连接选项默认值</td><td className="nowrap"><code>wuji\_connect\_options\_default()</code></td><td className="nowrap"><code>ConnectOptions()</code></td></tr>
      <tr><td className="nowrap">设备订阅</td><td className="nowrap"><code>wuji\_glove\_subscribe\_tactile(dev, cb, user, \&sub)</code></td><td className="nowrap"><code>glove.tactile().subscribe\_with\_callback(...)</code></td></tr>
      <tr><td className="nowrap">全局订阅</td><td className="nowrap"><code>wuji\_subscribe\_tf(cb, user, \&sub)</code></td><td className="nowrap"><code>manager.tf().subscribe()</code></td></tr>
      <tr><td className="nowrap">订阅流输出率</td><td className="nowrap"><code>wuji\_sub\_set\_rate(sub, hz, \&actual)</code></td><td className="nowrap"><code>sub.set\_rate(hz)</code></td></tr>
      <tr><td className="nowrap">Hand 2 控制动作</td><td className="nowrap"><code>wuji\_hand\_2\_enable(dev, mask)</code></td><td className="nowrap"><code>hand.enable(joints=mask)</code></td></tr>
      <tr><td className="nowrap">Hand 2 实时指令</td><td className="nowrap"><code>wuji\_hand\_2\_joint\_command\_publish</code> + <code>wuji\_joint\_command\_publisher\_send</code></td><td className="nowrap"><code>hand.joint\_command().publish().send(\[...])</code></td></tr>
      <tr><td className="nowrap">Hand 2 关节状态订阅</td><td className="nowrap"><code>wuji\_hand\_2\_subscribe\_joint\_states</code></td><td className="nowrap"><code>hand.joint\_states().subscribe()</code></td></tr>
      <tr><td className="nowrap">Hand 2 关节诊断订阅</td><td className="nowrap"><code>wuji\_hand\_2\_subscribe\_joint\_diagnostics</code></td><td className="nowrap"><code>hand.joint\_diagnostics().subscribe()</code></td></tr>
      <tr><td className="nowrap">Hand 2 IMU 订阅</td><td className="nowrap"><code>wuji\_hand\_2\_subscribe\_imu</code></td><td className="nowrap"><code>hand.imu().subscribe()</code></td></tr>
      <tr><td className="nowrap">Hand 2 nid 与关节索引换算</td><td className="nowrap"><code>wuji\_hand\_2\_nid\_to\_joint\_index(nid, \&index)</code> / <code>wuji\_hand\_2\_joint\_index\_to\_nid(joint\_index, \&nid)</code></td><td className="nowrap"><code>WujiHand2.nid\_to\_joint\_index(nid)</code> / <code>WujiHand2.joint\_index\_to\_nid(joint\_index)</code></td></tr>
      <tr><td className="nowrap">Hand 2 错误码描述</td><td className="nowrap"><code>wuji\_hand\_2\_describe\_error(code, \&info)</code></td><td className="nowrap"><code>WujiHand2.describe\_error(code)</code></td></tr>
      <tr><td className="nowrap">Hand 2 Flash 日志导出</td><td className="nowrap"><code>wuji\_hand\_2\_export\_flash\_logs</code> + <code>wuji\_hand\_2\_flash\_log\_export\_free</code></td><td className="nowrap"><code>hand.export\_flash\_logs()</code></td></tr>
      <tr><td className="nowrap">Hand 连接（USB SN）</td><td className="nowrap"><code>wuji\_hand\_connect\_sn(sn, alias, \&dev)</code></td><td className="nowrap"><code>WujiHand.connect\_sn(sn, alias)</code></td></tr>
      <tr><td className="nowrap">Hand 关节状态订阅</td><td className="nowrap"><code>wuji\_hand\_subscribe\_joint\_states</code></td><td className="nowrap"><code>hand.joint\_states().subscribe()</code></td></tr>
      <tr><td className="nowrap">Hand 实时指令</td><td className="nowrap"><code>wuji\_hand\_joint\_command\_publish</code> + <code>wuji\_hand\_joint\_command\_publisher\_send</code></td><td className="nowrap"><code>hand.joint\_command().publish().send(\[...])</code></td></tr>
      <tr><td className="nowrap">Hand 实时控制器</td><td className="nowrap"><code>wuji\_hand\_realtime\_controller\_open</code> / <code>\_set\_target\_position</code> / <code>*get\_actual*\*</code></td><td className="nowrap"><code>hand.realtime\_controller(LowPass(...))</code></td></tr>
      <tr><td className="nowrap">Glove 时间同步</td><td className="nowrap"><code>wuji\_glove\_sync\_time(dev, \&tsr)</code></td><td className="nowrap"><code>glove.sync\_time()</code></td></tr>
      <tr><td className="nowrap">Glove 手部模型路径</td><td className="nowrap"><code>wuji\_glove\_get\_hand\_model\_path</code> / <code>wuji\_glove\_set\_hand\_model\_path</code></td><td className="nowrap"><code>glove.hand\_model\_path().get()</code> / <code>.set(path)</code></td></tr>
      <tr><td className="nowrap">SDK 用户管理</td><td className="nowrap"><code>wuji\_create\_user</code> / <code>wuji\_switch\_user</code> / <code>wuji\_list\_users</code></td><td className="nowrap"><code>manager.create\_user()</code> / <code>switch\_user()</code> / <code>list\_users()</code></td></tr>
      <tr><td className="nowrap">用户数据导入导出</td><td className="nowrap"><code>wuji\_user\_data\_export</code> / <code>wuji\_user\_data\_preview</code> / <code>wuji\_user\_data\_import</code></td><td className="nowrap"><code>manager.export\_user\_data()</code> / <code>preview\_user\_data()</code> / <code>import\_user\_data()</code></td></tr>
      <tr><td className="nowrap">Glove 手部模型标定（异步）</td><td className="nowrap"><code>wuji\_glove\_calibration\_start</code> + <code>wuji\_glove\_calibration\_try\_finish</code></td><td className="nowrap"><code>glove.calibrate()</code></td></tr>
      <tr><td className="nowrap">Glove 手部模型标定（同步）</td><td className="nowrap"><code>wuji\_glove\_calibrate</code></td><td className="nowrap"><code>glove.calibrate\_blocking()</code></td></tr>
      <tr><td className="nowrap">Glove 触觉接触标定（同步）</td><td className="nowrap"><code>wuji\_glove\_calibrate\_tactile\_blocking</code></td><td className="nowrap"><code>glove.calibrate\_tactile\_blocking()</code></td></tr>
      <tr><td className="nowrap">断开</td><td className="nowrap"><code>wuji\_dev\_disconnect</code> + <code>wuji\_dev\_release</code></td><td className="nowrap"><code>device.disconnect()</code></td></tr>
    </tbody>
  </table>
</div>

## CMake 工程示例

完整可运行 C 工程（含 `CMakeLists.txt` + 订阅回调示例）见 [wuji-sdk 仓库的 examples/c/ 目录](https://github.com/wuji-technology/wuji-sdk/blob/main/examples/c/README.md)，按设备分别存放在 `examples/c/wuji_glove/`（设置订阅流输出率、在线 IK 自定义手部模型、SDK 用户管理与手部模型标定）、`examples/c/wuji_hand_2/`（订阅关节状态、控制动作、设备信息、[指尖触觉数据](/docs/wuji-sdk/wuji-hand-2-tactile/)、设置订阅流输出率、Flash 日志导出、对掌回放与 MIT 扫频）与 `examples/c/wuji_hand/`（订阅、发布、抓握循环与触觉状态）子目录，构建步骤参见该目录 README。最小链接方式：

```bash theme={null}
cc my_app.c -I "${SDK}/include" -L "${SDK}/lib" -lwuji_sdk_c -o my_app
LD_LIBRARY_PATH="${SDK}/lib" ./my_app
```

其中 `${SDK}` 是解压后的 tarball 根目录。CMake 工程通过 `-DWUJI_SDK_INCLUDE_DIR` 与 `-DWUJI_SDK_LIB` 指向同样路径。

## 接口清单

Python 与 C 的类型一一对应，字段语义相同，命名与内存表示按各自语言习惯：

| 类型 | Python | C |
| - | - | - |
| 帧头 | `FrameHeader` | `WujiFrameHeader` |
| 三维向量（f32） | `Vector3` | 无独立结构，f32 三分量按 `float[3]` 内联，如 `WujiPose.position` |
| 三维向量（f64） | `Vector3F64` | `WujiVector3F64` |
| 旋转四元数 | `Quaternion` | `WujiQuaternionF32`、`WujiQuaternionF64` |
| 位姿 | `Pose` | `WujiPose` |
| 设备手性 | `Handedness.Left`、`Handedness.Right` | `WUJI_HANDEDNESS_LEFT`、`WUJI_HANDEDNESS_RIGHT` |
| IMU 数据 | `ImuData` | `WujiImuData` |
| 单个坐标变换 | `FrameTransform` | `WujiFrameTransform` |
| 坐标变换集合 | `FrameTransforms` | `WujiFrameTransforms` |
| 录制器与控制句柄 | `TopicRecorder`、`RecordingHandle` | 无对应类型，录制只在 Python 提供 |
| 录制摘要与质量指标 | `RecordingSummary`、`QualitySummary`、`QualityMetrics`、`ChannelHealth`、`RecordingAlert`、`RecordingStatus` | 无对应类型 |
| Wuji Hand 关节状态 | `HandJointStates` | `WujiHandJointStates` |
| Wuji Hand 关节指令 | `HandJointCommand` | 无对应帧结构，按 20 项 `WujiJointCommand` 数组下发 |
| Wuji Hand 触觉压力帧 | `TactileGloveFrame` | `WujiTactileGloveFrame` |
| 设备故障码解码结果 | `WujiHand2.describe_error()` 返回的 `dict` | `WujiErrorInfo` |

表示方式的差异有三处。Python 的 `str` 字段在 C 是定长 `char` 数组，例如 `frame_id[32]`、`parent_frame_id[32]`。Python 的 `list` 字段在 C 是指针加长度，例如 `WujiFrameTransforms` 的 `transforms` 与 `transforms_len`。Python 只有一个 `Quaternion`，C 按数据流的实际精度分为 `WujiQuaternionF32` 与 `WujiQuaternionF64`。C 的帧指针仅在订阅回调期间有效，需要保留的数据必须在回调内拷贝，约束详见 [C 接口参考](/docs/wuji-sdk/data-reference/)。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.