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

# 输出率调节

## 概述

本篇实践介绍如何通过 `set_rate()` 调节 Wuji Hand 2 数据流的推送频率。应用场景包括匹配应用采样频率和降低网络及数据处理开销。

对应的 Python 示例为 [4.set\_stream\_rate.py](https://github.com/wuji-technology/wuji-sdk/blob/main/examples/python/wuji_hand_2/4.set_stream_rate.py)，C 示例为 [4\_set\_stream\_rate.c](https://github.com/wuji-technology/wuji-sdk/blob/main/examples/c/wuji_hand_2/4_set_stream_rate.c)。 可调流的清单与接口定义见 [调节订阅流输出率](/docs/wuji-sdk/data-subscription#调节订阅流输出率)，本页说明集成流程和运行时行为。

<Info>
  本功能有固件版本要求。**Wuji Hand 2 固件需 v2.3.0 及以上**，低于该版本的设备调用时抛异常。本文验证所用设备的固件低于此版本，成功路径的行为依据发布记录说明，失败路径为实测。
</Info>

## 前置条件

### 硬件

| 项目 | 要求 |
| - | - |
| Wuji Hand 2 | 1 只，**固件 v2.3.0 及以上** |
| 连接方式 | 以太网 |

### 软件

| 项目 | 要求 |
| - | - |
| Wuji SDK | **v2026.8.17 及更高版本**。该版本引入 `Subscription.set_rate()` |
| Python | 3.10 及以上版本 |
| C 工具链 | CMake 3.16 及以上版本，以及解压后的 SDK 包 |

## 数据流

```mermaid theme={null}
flowchart TD
    SCAN["扫描并筛选 Wuji Hand 2<br/>Python: scan() / C: wuji_scan()"]
    CONNECT["按序列号连接<br/>Python: connect() / C: wuji_connect()"]
    SUB["订阅可调数据流<br/>Python: joint_states().subscribe()<br/>C: wuji_hand_2_subscribe_joint_states()"]
    SET["请求输出率<br/>Python: sub.set_rate(100)<br/>C: wuji_sub_set_rate()"]
    APPLY["设备量化并返回实际频率"]
    RECV["按实际频率接收状态帧<br/>Python: recv_async() / C: 回调接收"]
    RESTORE["恢复设备默认频率<br/>Python: sub.set_rate(0)<br/>C: wuji_sub_set_rate(0)"]
    CLEAN["关闭订阅并断开设备"]

    SCAN --> CONNECT --> SUB --> SET --> APPLY --> RECV --> RESTORE --> CLEAN
```

请求值会被量化到设备支持的频率，**返回值才是真正生效的值**，不要假设等于请求值。

## 可调流与派生流

| 设备 | 可调流 |
| - | - |
| Wuji Hand 2 | `joint_states`、`joint_diagnostics`、`imu`、`fingertip/{thumb,index,middle,ring,pinky}/data` |
| Wuji Glove | `emf_poses`、`tactile`、`tactile_zones`、`imu_raw/*` |

**派生流拒绝 `set_rate`。** `hand_joint_angles`、`hand_skeleton`、`tip_poses`、`imu_data/*` 这些由源流计算得出，频率跟随源流，直接对它们调用会被拒绝。

**`joint_states` 与 `joint_diagnostics` 共享同一条设备流。** 通过任一订阅调整频率，另一条同时改变。

## 集成步骤

### 1. 连接设备并建立订阅

先扫描并连接目标 Wuji Hand 2，再取得 `joint_states` 的订阅句柄。Python 使用 `scan()`、`connect()` 和 `subscribe()`，C 先调用 `wuji_init()`，再通过 `wuji_scan()`、`wuji_connect()` 连接，并注册状态回调。

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    sub = hand.joint_states().subscribe()
    ```
  </Tab>

  <Tab title="C">
    ```c theme={null}
    struct WujiSub *sub = NULL;
    WujiStatus st = wuji_hand_2_subscribe_joint_states(
        dev, on_joint_states, NULL, &sub);
    ```
  </Tab>
</Tabs>

C 回调 `on_joint_states` 接收 `WujiFrameKind`、`const WujiJointStateFrame *` 和用户上下文。订阅成功后再调整频率。

### 2. 设置频率并读取实际值

请求 100 Hz，并使用返回值确认设备实际采用的频率。Python 的 `set_rate()` 返回频率，C 的 `wuji_sub_set_rate()` 返回状态码并通过输出参数填写频率。

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    actual = sub.set_rate(100)
    print(f"device applied {actual} Hz")
    for _ in range(5):
        frame = await sub.recv_async()
        print(len(frame.joints))
    ```
  </Tab>

  <Tab title="C">
    ```c theme={null}
    uint32_t actual = 0;
    WujiStatus st = wuji_sub_set_rate(sub, 100, &actual);
    if (st == WUJI_STATUS_OK) {
        printf("device applied %u Hz\n", actual);
        sleep(2);
    }
    ```
  </Tab>
</Tabs>

Python 片段在协程中执行，C 在等待期间由后台回调接收帧。频率属于设备流，会影响该流的其他订阅者。

### 3. 恢复默认频率并释放资源

向同一接口传入 `0` 恢复默认频率，然后关闭订阅、断开设备。Python 将清理放在 `finally` 中，C 在错误退出路径也执行清理。

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    sub.set_rate(0)
    sub.close()
    manager.disconnect_all()
    ```
  </Tab>

  <Tab title="C">
    ```c theme={null}
    wuji_sub_set_rate(sub, 0, &actual);
    wuji_sub_close(sub);
    wuji_dev_disconnect(dev);
    wuji_dev_release(dev);
    wuji_shutdown();
    ```
  </Tab>
</Tabs>

## 运行与输出

<Tabs>
  <Tab title="Python">
    ```bash theme={null}
    python examples/python/wuji_hand_2/4.set_stream_rate.py
    ```
  </Tab>

  <Tab title="C">
    ```bash theme={null}
    ./build/hand2/4_set_stream_rate
    ```
  </Tab>
</Tabs>

固件支持时的输出形如：

```text theme={null}
Connected: WH2KA00XXXXXXXXX
joint_states: requested 100 Hz, device applied 100 Hz
joint_states frame at 100 Hz: 20 joints
...
restored to the device default: 1000 Hz
```

### 固件不支持时的行为

在固件低于 v2.3.0 的设备上调用，异常立即抛出：

```text theme={null}
wuji_sdk.WujiException: Unsupported operation: device 'WH2KA00XXXXXXXXX' runs firmware without rate control
```

这个异常在 `set_rate()` 调用点抛出，订阅本身不受影响——**订阅照常工作，只是维持在设备默认频率**。实测该设备的 `joint_states` 默认约 1088 Hz。

判断设备是否支持，调用一次 `set_rate()`，根据是否抛出异常判断设备是否支持。SDK 没有单独的能力查询接口。

## 注意事项

| 分支点 | 表现 | 处理 |
| - | - | - |
| **固件不支持** | 实测抛 `WujiException: Unsupported operation: device 'SN' runs firmware without rate control` | 升级固件到 v2.3.0 及以上 |
| 对派生流调用 | 被拒绝 | 改为调整其源流 |
| C 侧不支持的流 | 返回 `WUJI_STATUS_ERR_UNSUPPORTED`（-8），**不向设备发送请求** | 检查返回码 |
| 传 0 | 恢复设备默认频率 | 返回默认值 |
| 最后一个订阅关闭 | 频率自动恢复设备默认 | 想让设置持续生效就保持句柄打开 |
| 设备重连 | 频率恢复设备默认 | 重连后需要重新设置 |

## 扩展用法

### 选择合适的频率

请求值会被量化。想确认真正生效的频率，读 `set_rate()` 的返回值，或者订阅后数一段时间的帧数。

### 多个订阅者的影响

频率属于流。同一条流上有多个订阅者时，任何一个改频率，所有订阅者一起受影响。这在多进程共用一台设备时尤其要注意，别让某个进程的降频影响另一个进程的实时性。

### 降低 joint\_states 会连带 joint\_diagnostics

两者共享同一条设备流。只想降低其中一个是做不到的。

### 恢复时机

不需要显式恢复的场景可直接关闭句柄，频率将恢复为设备默认值。显式传 0 适合在同一个句柄上继续用默认频率接收。

## 相关内容

* [数据订阅：回调](/docs/wuji-hand/latest/sdk-practice/subscribe-callback)：订阅的建立与生命周期
* [数据订阅：异步](/docs/wuji-hand/latest/sdk-practice/subscribe-async)：`recv_async()` 配合降频使用
* [Wuji Glove 输出率调节](/docs/wuji-glove/sdk-practice/stream-rate/)：手套侧的同一能力，固件要求 v0.11.4 及以上


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