> ## 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](/docs/wuji-sdk/) 的原始数据转换支持采集时只保存轻量的原始数据，事后再把它们复算成完整的后处理产物——指尖位姿、关节角度、手骨架、IMU 融合姿态。离线复算结果与在线实时计算完全一致。

完整的操作流程与离线重放和在线求解的一致性实测见 [SDK 使用实践 · 离线数据处理](/docs/wuji-glove/sdk-practice/offline-replay)。

## 何时使用

实时逆向运动学解算对 CPU 消耗较高。若采集阶段仅需记录原始数据、之后再离线分析，无需全程运行实时解算。原始数据转换适合：

* 采集时只订阅轻量的 `emf_poses` 和原始 IMU，降低 CPU 占用
* 事后再决定需要哪些后处理产物
* 用任意自选格式保存原始数据，不绑定特定文件格式

## 工作流

1. **在线采集**：只订阅 `emf_poses` 和原始 IMU 数据
2. **保存**：用任意格式保存原始数据帧
3. **离线复算**：用 `WujiGlove.offline_pipeline()` 把保存的帧复算成后处理产物

<Info>
  离线复算与在线实时计算结果一致：相同的输入加相同的标定，得到相同的输出。
</Info>

## 创建离线 pipeline

`WujiGlove.offline_pipeline()` 创建一条不依赖真实设备连接的 pipeline。

```python theme={null}
from wuji_sdk import WujiGlove

pipeline = WujiGlove.offline_pipeline(
    sn="WujiGlove-12345",   # 必填，加载该设备的参数表
    hand_side="right",       # 必填，"left" 或 "right"
    urdf_path=None,          # 可选，指定标定手部模型文件
)
```

| 参数 | 说明 |
| - | - |
| `sn` | 设备序列号，用于加载该设备的参数表 |
| `hand_side` | 手别，`"left"` 或 `"right"`。非法值抛 `ValueError` |
| `urdf_path` | 可选，显式指定 URDF 手部模型路径 |

pipeline 创建后可查询实际使用的标定来源：

```python theme={null}
print(pipeline.sn)               # "WujiGlove-12345"
print(pipeline.hand_side)        # "right"
print(pipeline.urdf_source)      # "override" | "calibration_file" | "builtin_default"
print(pipeline.urdf_source_path) # 实际 URDF 路径，或 None
```

### URDF 查找顺序

手部产物依赖标定的手部模型。pipeline 按以下规则确定 URDF：

1. **显式 `urdf_path`**：传入时直接使用该文件，优先于其他所有来源。文件无法读取时直接抛错，不回退
2. **托管模型**：未传 `urdf_path` 时，检查 `calibration.hand_model_path` 是否指向 SDK 托管目录之外的文件。是则使用该自定义文件，否则使用当前 SDK 用户对应左右手的稳定文件 `left_hand.urdf` / `right_hand.urdf`。两者是二选一，不互为回退
3. **内置默认模型**：上一步选中的文件不存在或不可用时，回退到内置默认 URDF，并打印 warning

<Warning>
  默认 SDK 用户跳过托管模型，未传 `urdf_path` 时始终使用内置默认模型。要复算出与在线一致的手部产物，先切换到采集这批数据时所用的具名用户，详见 [标定](/docs/wuji-glove/sdk-data-reference/calibration)。
</Warning>

<Warning>
  回退到内置默认模型（`urdf_source` 为 `builtin_default`）时，手部产物可能不准确。IMU 融合产物不依赖 URDF，不受影响。
</Warning>

## 复算手部产物

手部链以 `emf_poses` 帧为输入，复算出三种产物。三者共享同一次解算，结果与在线一致。

```python theme={null}
for emf_poses in my_recording_reader():   # 自定义读取器，逐帧返回 EmfPoseArray
    angles   = pipeline.hand_joint_angles().compute(emf_poses)
    tips     = pipeline.tip_poses().compute(emf_poses)
    skeleton = pipeline.hand_skeleton().compute(emf_poses)
    save(angles, tips, skeleton)   # 自定义写入器
```

| 资源 | 返回类型 | 内容 |
| - | - | - |
| `pipeline.hand_joint_angles()` | `HandJointAngles` | 21 DoF 手部关节角 |
| `pipeline.tip_poses()` | `FingertipPoses` | 5 指指尖位姿 |
| `pipeline.hand_skeleton()` | `HandSkeleton` | 21 个 MediaPipe 关键点骨架 |

产物的完整字段定义见 [SDK 资源](/docs/wuji-glove/sdk-data-reference/)。

## 复算 IMU 融合

IMU 链以原始 IMU 帧为输入，复算出融合姿态。手套手背 IMU 用 `imu_data_palm()`。

```python theme={null}
for raw_frame in my_imu_reader():   # 逐帧返回原始 ImuData
    fused = pipeline.imu_data_palm().compute(raw_frame)
    save(fused)   # 自定义写入器
```

原始 IMU 帧用 `ImuData.raw()` 构造，`orientation_covariance[0]` 自动标记为 -1（未融合）。IMU 融合产物不依赖标定 URDF。

## 构造输入帧

用 schema 构造器在内存中构造输入帧：

```python theme={null}
from wuji_sdk import (
    EmfPose, EmfPoseArray, FrameHeader, ImuData,
    Pose, Quaternion, Vector3F64,
)

emf = EmfPoseArray(
    header=FrameHeader(seq=1, timestamp_us=0, frame_id="r_hand_emf_tx"),
    poses=[
        EmfPose(
            pose=Pose(position=[0.05, 0.0, 0.0],
                      orientation=Quaternion(0.0, 0.0, 0.0, 1.0)),
            confidence=1.0,
        )
        for _ in range(5)
    ],
)

raw_imu = ImuData.raw(
    header=FrameHeader(seq=1, timestamp_us=0, frame_id="imu_raw/palm"),
    angular_velocity=Vector3F64(0.0, 0.0, 0.0),
    linear_acceleration=Vector3F64(0.0, 0.0, 9.8),
)
```

完整可运行示例见 SDK 安装包中的 `examples/3.offline_pipeline.py`。


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