> ## 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.

# 时间同步与坐标变换

设备输出的每一帧数据都带时间戳。SDK 连接设备后自动完成时间同步，让设备时间戳与主机的 UTC 时钟对齐。本页说明时间戳的含义、同步机制，以及如何手动触发同步。

## 数据帧时间戳

除 Wuji Hand 配对触觉感知手套帧外，数据帧共享相同的 [`FrameHeader`](/docs/wuji-sdk/data-reference#frameheader)，其中 `timestamp_us` 是 64 位微秒时间戳。对设备侧打戳的数据帧（Wuji Hand 2、Wuji Glove），它的含义取决于是否已完成时间同步：

* **同步后**：`timestamp_us` 是 UTC 微秒时间戳（Unix 时间戳），可与主机时钟直接对齐
* **同步前**：`timestamp_us` 是设备 uptime，自上电起经过的微秒数

Wuji Hand 2 与 Wuji Glove 设备本身没有实时时钟 (RTC)，上电后从 0 开始计时。时间同步的作用就是把这个 uptime 计数对齐到真实的 UTC 时间。

### 打戳时刻与派生数据

各产品数据帧的打戳时刻：

**Wuji Hand 2**：反馈帧的 `timestamp_us` 由固件在发送时刻打戳。

**Wuji Glove**：各数据流由固件在设备侧打戳，而非主机收到数据的时刻：

* **EMF 帧**：该采样点数据采集完成的时刻
* **触觉帧**：整帧压力矩阵扫描完成的时刻
* **IMU 帧**：固件定时轮询所有 IMU 的数据，该周期内读出的采样共用该周期的起始时间戳

由 EMF 帧解算出的派生数据（手部关节角、骨架与指尖位姿）不另行打戳：`timestamp_us` 直接取自源 EMF 帧，可用于派生结果与源数据的严格对齐。`header` 其余字段（`frame_id`、`seq`）不保证与源帧一致，以各产物的字段说明为准。

**Wuji Hand**：关节状态帧的 `timestamp_us` 由 SDK 在主机侧打戳（主机 UTC），不参与设备时间同步。配对触觉感知手套帧不含 `FrameHeader`，其 `timestamp_ms` 为设备侧毫秒时间戳，SDK 原样透传，不随时间同步转换为 UTC，与 `timestamp_us` 无对齐保证。

## 同步机制

SDK 采用客户端授时：设备不主动获取时间，而是由 SDK 把主机时钟下发给设备。

同步流程沿用 NTP 的四时间点模型——SDK 与设备交换一组请求/响应消息，记录四个时刻（请求发出、设备接收、设备回复、响应收到），据此算出设备时钟相对主机 UTC 的偏移量 `offset_us`，再下发给设备。设备据此换算：

```
设备时间 = uptime_us + offset_us
```

这是一种 PTP-like（类 PTP）的轻量同步，不依赖标准 PTP 硬件。同步精度取决于 SDK 与设备之间的网络往返时延。

<Info>
  周期性自动同步需要较新的固件支持。早期固件只在连接后的首次同步应用偏移量，后续的周期性同步不会刷新设备时钟。建议将固件升级到最新版本，以获得完整的时间同步效果。
</Info>

## 自动同步

SDK 连接设备后自动维护时间同步，应用层通常无需介入：

* **首次同步**：`connect()` 完成时立即执行一次完整同步
* **周期同步**：连接后默认每 30 秒在后台自动同步一次，对抗设备晶振漂移

后台同步的间隔通过 `ConnectOptions.auto_time_sync_interval_ms` 配置：

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from wuji_sdk import ConnectOptions

    # 默认 30 秒
    options = ConnectOptions()

    # 自定义为 10 秒
    options = ConnectOptions(auto_time_sync_interval_ms=10_000)

    # 关闭后台自动同步
    options = ConnectOptions(auto_time_sync_interval_ms=None)
    ```
  </Tab>

  <Tab title="C">
    ```c theme={null}
    // 默认 30 秒
    WujiConnectOptions options = wuji_connect_options_default();

    // 自定义为 10 秒
    options.auto_time_sync_interval_ms = 10000;

    // 关闭后台自动同步
    options.auto_time_sync_interval_enabled = false;
    ```
  </Tab>
</Tabs>

| 取值 | 行为 |
| - | - |
| 不设置 | 默认 30000（30 秒） |
| `None` | 关闭后台自动同步 |
| 整数（毫秒） | 自定义间隔，需 ≥ 100 |

会话关闭时同步状态自动清除，下次连接重新同步。

## 手动同步

需要在自选时机强制同步时（例如长录制开始前、关键操作前），调用设备的 `sync_time()`：

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    result = glove.sync_time()
    print(f"偏移量: {result.offset_us} us")
    print(f"往返时延: {result.round_trip_us} us")
    print(f"同步完成时刻: {result.synced_at_us} us")
    ```
  </Tab>

  <Tab title="C">
    ```c theme={null}
    WujiTimeSyncResult tsr = {0};
    if (wuji_glove_sync_time(glove, &tsr) == WUJI_STATUS_OK) {
        printf("偏移量: %lld us\n", (long long)tsr.offset_us);
        printf("往返时延: %lld us\n", (long long)tsr.round_trip_us);
        printf("同步完成时刻: %llu us\n", (unsigned long long)tsr.synced_at_us);
    }
    ```
  </Tab>
</Tabs>

该调用触发一次完整同步并把偏移量下发到设备，Python 返回 `TimeSyncResult`，C 写入 `WujiTimeSyncResult`：

| 字段 | 类型 | 说明 |
| - | - | - |
| `offset_us` | `int` | 设备时钟偏移量，`设备时间 = uptime_us + offset_us` |
| `round_trip_us` | `int` | 本次同步的网络往返时延（微秒），用单调时钟测量，越小越精准 |
| `synced_at_us` | `int` | 本次同步完成时的主机 UTC 时间戳（微秒） |

两侧都是阻塞调用，与 SDK 后台的周期同步任务串行。C 侧失败时保持 `*out` 不变，失败原因用 `wuji_last_error()` 读取。

<Info>
  SDK 已内置 30 秒后台自动同步，大多数场景无需手动调用 `sync_time()`。两种情况下手动调用有意义：在时间敏感操作前强制立即同步，或通过返回的 `round_trip_us` 检查最近一次同步的质量。
</Info>

## 时间戳单调性

设备侧打戳的 `timestamp_us`（Wuji Hand 2、Wuji Glove）在所有同步场景下严格单调递增。即使主机时钟回拨，或周期同步算出反向偏移，设备也通过平滑校正避免时间戳回退。每一帧的 `timestamp_us` 大于上一帧，可直接用于时序排序和采样间隔计算。Wuji Hand 关节状态帧的主机侧时间戳随主机时钟变化，不在此保证范围内。

## 同步精度

同步精度主要由 SDK 与设备之间的网络往返时延决定。`TimeSyncResult.round_trip_us` 反映这一指标，往返时延越小，偏移量估计越精准。有线以太网直连下，往返时延通常在数百微秒量级。

后台周期同步持续校正设备晶振漂移，长时间运行也能保持设备时钟与主机 UTC 对齐。

## 接口清单

| 操作 | Python | C |
| - | - | - |
| 配置后台同步间隔 | `ConnectOptions(auto_time_sync_interval_ms=...)` | `WujiConnectOptions` 的 `auto_time_sync_interval_ms` 与 `auto_time_sync_interval_enabled` |
| 关闭后台自动同步 | `ConnectOptions(auto_time_sync_interval_ms=None)` | `auto_time_sync_interval_enabled` 置 `false` |
| 手动触发一次完整同步 | `glove.sync_time()` | `wuji_glove_sync_time()` |
| 读取同步结果 | `TimeSyncResult` 的 `offset_us`、`round_trip_us`、`synced_at_us` | `WujiTimeSyncResult` 的同名三个字段 |
| 读取数据帧时间戳 | `frame.header.timestamp_us` | `frame->header.timestamp_us` |

C 用一个布尔字段表达 Python 的 `None` 语义：Python 传 `None` 关闭后台同步，C 把 `auto_time_sync_interval_enabled` 置 `false`。`WujiTimeSyncResult` 是纯 POD，无堆字段、无需释放。


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