Metadata-Version: 2.5
Name: qnbot-sdk-exo
Version: 1.0.0
Requires-Python: >=3.10
Requires-Dist: qnbot-sdk-core==1.4.0
Description-Content-Type: text/markdown

# QnBot Exo Python SDK

`qnbot-sdk-exo` 提供 QnBot 外骨骼功能的 Python API。安装时会自动安装对应版本的
`qnbot-sdk-core`，当前依赖版本为 `1.3.0`；平台相关运行文件由 Core 依赖提供，无需单独安装 Exo 二进制
或其他开发工具链。
应用只创建一个 `Sdk`，再通过 `sdk.exo()` 使用外骨骼设备。

## 安装

使用产品发布说明给出的 Exo 版本：

```bash
python -m pip install "qnbot-sdk-exo==<exo-version>"
python -m pip check
```

无需另外下载平台运行文件，也不需要在本机安装 Rust 工具链。

## 支持的客户流程

- 设备发现，并查看每个串口的设备信息或结构化失败原因；
- 使用自动发现或显式串口创建共享 `Sdk`；
- 使用配置中的逻辑名称选择设备；
- 在 `start()` 前读取创建期冻结的 `get_device_info()`；
- 使用 `telemetry()`、`status()` 的 callback、`latest()` 或异步 `next()`；
- 使用 `haptics().set()` 和 `clear()` 控制左右手柄振动；
- 使用 `health()` 查看健康状态，并通过 `stop()`、`close()` 清理资源。
- 使用 `update()` 手动推进一次运行，或使用 `run_forever()`、`run_background()`、
  `request_stop()` 和 `join()` 管理当前线程与后台运行。

## 设备发现

公共客户示例位于独立的 examples 仓库目录：

```bash
python examples-public/examples/exo/python/src/discover_exos.py
```

发现结果包含每个候选设备的明确串口。成功记录包含产品、协议、固件、能力、组件数量，
以及设备支持时提供的描述性序列号和名称；失败记录包含串口与结构化问题。SDK 创建成功后，
所选候选串口才成为该实例使用的最终物理串口。

## 配置与运行

自动发现唯一设备：

```bash
python examples-public/examples/exo/python/src/quick_start.py
```

使用显式串口：

```bash
python examples-public/examples/exo/python/src/device_info.py --port /dev/ttyUSB0
```

Windows 可使用 `--port COM3`。设置左右触觉强度：

```bash
python examples-public/examples/exo/python/src/haptics.py --port /dev/ttyUSB0 \
  --left 20 --right 30
```

示例使用 `primary-exo` 作为逻辑名称。逻辑名称用于 SDK 内选择设备，不等同于串口名称；
最终物理串口由 SDK 创建期间的显式配置或自动发现确定。停止后重新启动仍使用该 SDK
实例已经确定的最终物理串口。

应用配置的核心形式如下：

```python
from qnbot_sdk import Sdk, SerialConnection
from qnbot_sdk.exo import ExoConfig

sdk = Sdk(
    devices=(
        ExoConfig(
            name="primary-exo",
            connection=SerialConnection(port="/dev/ttyUSB0"),
        ),
    )
)
device = sdk.exo().device("primary-exo")
```

省略 `port` 并使用 `SerialConnection(auto_discover=True)` 即为自动发现。一个应用只需
创建一个 `Sdk`，并从该实例访问配置的 Exo 及其他设备。

## 信息、数据与触觉

`get_device_info()` 返回 SDK 创建期间取得的不可变快照，可以在 `start()` 前调用，也不会
触发新的串口请求。`telemetry()` 提供双臂编码器和关节角、双手柄状态及可选 IMU；
`status()` 返回 Core 的 `DeviceStatus`，提供连接、数据新鲜度和有限错误摘要。Exo
不维护独立设备名称列表，应用使用配置中已知的逻辑名称调用 `device(name)`。

成功设置 haptics 后可以通过 `latest()` 读取当前有效的触觉状态。设备停止、断线或
关闭时该状态会失效，并且不会在恢复后重放；应用需要重新调用 `set()`。未导致断线的临时
写入失败不会伪造成功状态。

## 清理

正常结束时先调用 `haptics.clear()`，再调用 `device.stop()`；最后调用 `sdk.close()`。
根级关闭会清理剩余资源。订阅对象可主动调用 `unsubscribe()`，也会在所属 device、Exo
domain 或 SDK 关闭时失效。

## 当前不提供的能力

Exo v1 不提供原始 QnTP、固件/DFU 控制器、编码器零位校准、数据流 profile、无线配网、
外骨骼主动助力、标定工作流、算法、target、retargeting、Skeleton、高频遥测。

当前版本同时提供独立 Exo 示例和 Exo+Glove 共享串口示例；融合设备请参考
`examples-public/examples/composite-exo-glove/README.md`。
