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

# 输出率调节

## 概述

`joint_states` 默认以约 1 kHz 广播，多数应用用不上这么高。`set_rate()` 让固件按指定频率推送，降低网络与 CPU 开销。

频率属于**数据流**，不属于订阅句柄：设置对该流的所有订阅者生效，最后一个订阅关闭或设备重连后恢复设备默认。

对应的 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)。

可调流的清单与接口定义见 [SDK 接口](https://docs.wuji.tech/docs/zh/wuji-hand/beta1/sdk-reference.md)，本页只讲怎么跑起来与实测结果。

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

## 前置条件

### 硬件

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

### 软件

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

## 可调流与派生流

| 设备 | 可调流 |
| - | - |
| Wuji Hand 2 | `joint_states`、`joint_diagnostics`、`imu` |
| Wuji Glove | `emf_poses`、`tactile`、`tactile_zones`、`imu_raw/palm` |

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

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

## 数据流

```mermaid theme={null}
flowchart TD
    SUB["joint_states().subscribe()<br/>取得订阅句柄"]
    SET["sub.set_rate(100)<br/>向固件请求 100 Hz"]
    FW["固件<br/>按支持的频率量化"]
    RET["返回实际生效频率<br/>可能不等于请求值"]
    ALL["该流的全部订阅者<br/>一起按新频率接收"]
    REST["sub.set_rate(0)<br/>恢复设备默认"]

    SUB --> SET
    SET --> FW
    FW --> RET
    RET --> ALL
    ALL -->|"或最后一个订阅关闭<br/>或设备重连"| REST
```

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

## 运行时分支

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

## 调用顺序

> [tab] Python
>
> ```python theme={null}
> import asyncio
> from wuji_sdk import DeviceType, SdkManager
>
> async def main():
>     manager = SdkManager.instance()
>     hands = [d for d in manager.scan() if d.device_type == DeviceType.WujiHand2]
>     sub = None
>     try:
>         hand = manager.connect(sn=hands[0].sn, device_name="hand")
>
>         # 1. 取订阅句柄。频率在句柄存活期间有效
>         sub = hand.joint_states().subscribe()
>
>         # 2. 请求降频，返回值是设备实际生效的频率
>         actual = sub.set_rate(100)
>         print(f"requested 100 Hz, device applied {actual} Hz")
>
>         for _ in range(5):
>             frame = await sub.recv_async()
>             print(f"frame at {actual} Hz: {len(frame.joints)} joints")
>
>         # 3. 传 0 恢复设备默认
>         print(f"restored to default: {sub.set_rate(0)} Hz")
>     finally:
>         if sub is not None:
>             sub.close()
>         manager.disconnect_all()
>
> asyncio.run(main())
> ```

> [tab] C
>
> ```c theme={null}
> #include "wuji_sdk.h"
>
> /* 1. 订阅 */
> struct WujiSub *sub = NULL;
> wuji_hand_2_subscribe_joint_states(dev, on_frame, &ctx, &sub);
>
> /* 2. 调频。任意订阅句柄都可调用 */
> uint32_t actual = 0;
> WujiStatus st = wuji_sub_set_rate(sub, 100, &actual);
> if (st == WUJI_STATUS_ERR_UNSUPPORTED) {
>     /* -8：该流不支持调频，且没有向设备发送请求 */
> } else if (st == WUJI_STATUS_OK) {
>     printf("requested 100 Hz, device applied %u Hz\n", actual);
> }
>
> /* 3. 传 0 恢复默认 */
> wuji_sub_set_rate(sub, 0, &actual);
>
> wuji_sub_close(sub);
> ```

句柄关闭后频率自动恢复，所以要让设置持续生效就保持句柄打开。

## 运行与输出

> [tab] Python
>
> ```bash theme={null}
> python examples/python/wuji_hand_2/4.set_stream_rate.py
> ```

> [tab] C
>
> ```bash theme={null}
> ./build/hand2/4_set_stream_rate
> ```

固件支持时的输出形如：

```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 没有单独的能力查询接口。

## 调整与适配

### 选择合适的频率

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

### 多个订阅者的影响

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

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

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

### 恢复时机

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

## 相关内容

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


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