Files
go1_pro_sdk/docs/OFFICIAL_API_COMPATIBILITY.md
2026-07-30 15:25:48 +08:00

170 lines
7.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Unitree 官方 SDK 接口兼容说明
对比基准Unitree [`unitree_legged_sdk`](https://github.com/unitreerobotics/unitree_legged_sdk)
`go1` 分支README 版本 `v3.8.6`,提交
`4539a6c10dfbc9781cea6fcb7d51bc6ddc6f71e1`2023-07-11
## 结论
本项目和官方 SDK 使用相近的低层对象模型,但此前不是调用兼容:本项目入口是
`MCUClient.send()/recv_state()`,官方 Python wrapper 入口是
`robot_interface.UDP.SetSend()/Send()/Recv()/GetRecv()`
当前项目已提供 `robot_interface` 兼容模块。官方低层 Python 示例可保留原来的
导入和主要调用流程,同时底层会使用 Go1 PRO 所需的 Blowfish 加密和 616 字节
私有 `LowCmd` 协议。
反过来,要让本项目编写的程序直接在官方 SDK 上复现,应用必须导入
`robot_interface`,并限制在官方 wrapper 真正导出的公共子集内。应用不应直接导入
`go1_pro_sdk`
## 接口矩阵
| 官方接口 | 本项目原接口 | 当前兼容状态 |
|---|---|---|
| `robot_interface.LowCmd/LowState` | 同名类型 | 已对齐命令和常用状态字段名 |
| `MotorCmd/MotorState/IMU` | 同名类型 | 常用字段已对齐 |
| `BmsState` | `BMS` | 名称已对齐PRO 状态区较短,见下文 |
| `BmsCmd`, `Cartesian`, `UDPState` | 原先缺失 | 已补齐 |
| `UDP(LOWLEVEL, ...)` | `MCUClient(...)` | 已适配标准四参数构造 |
| `InitCmdData` | 原先缺失 | 已实现官方 stop sentinel 初始化 |
| `Recv/GetRecv/SetSend/Send` | `recv_latest/send` | 已适配 |
| `Safety.PositionLimit` | `position_limit` | 已适配,跳过 `PosStopF` |
| `Safety.PowerProtect` | `power_protect` | 调用兼容,算法不是官方闭源实现 |
| `Safety.PositionProtect` | `position_protect` | 调用兼容,保护动作更保守 |
| `HighCmd/HighState` | MQTT `Go1/Go1MQTT` | 类型已提供UDP 传输不支持 |
| `Loop/LoopFunc` | 无 | C++ 已提供;官方 Python wrapper 本身未导出 |
| C++ headers/static library | 无 | 低层 C++ 源码兼容;不承诺二进制 ABI |
## 关键协议差异
官方 SDK 的公开结构不能直接描述本项目实测的 Go1 PRO 线协议。PRO 低层通道需要:
- 616 字节 `LowCmd`CRC 位于 612
- Blowfish ECB 加密;
- `bandWidth` 使用实测字节序和值;
- 858 字节加密状态包中取 856 字节块解密,再解析 807 字节有效状态。
因此兼容层只对齐用户代码接口,不替换本项目现有 codec也不承诺二进制包与官方
EDU SDK 相同。
## 官方风格用法
```python
import robot_interface as sdk
LOWLEVEL = 0xff
FR_1 = 1
udp = sdk.UDP(LOWLEVEL, 8080, "192.168.123.10", 8007)
safe = sdk.Safety(sdk.LeggedType.Go1)
cmd = sdk.LowCmd()
state = sdk.LowState()
udp.InitCmdData(cmd)
udp.Recv()
udp.GetRecv(state)
cmd.motorCmd[FR_1].q = 1.2
cmd.motorCmd[FR_1].dq = 0.0
cmd.motorCmd[FR_1].Kp = 5.0
cmd.motorCmd[FR_1].Kd = 1.0
safe.PositionLimit(cmd)
safe.PowerProtect(cmd, state, 1)
udp.SetSend(cmd)
udp.Send()
```
这里故意不使用 `sdk.LOWLEVEL``sdk.FR_1`、上下文管理器或 `close()`:这些是本项目
提供的便利能力,但不属于官方 Python wrapper 的导出契约。
## C++ 同源码用法
C++ 公共入口、命名空间、结构字段和低层方法签名与官方 v3.8.6 对齐:
```cpp
#include "unitree_legged_sdk/unitree_legged_sdk.h"
using namespace UNITREE_LEGGED_SDK;
UDP udp(LOWLEVEL, 8090, "192.168.123.10", 8007);
Safety safe(LeggedType::Go1);
LowCmd cmd{};
LowState state{};
udp.InitCmdData(cmd);
```
业务源码和 `#include` 不变只切换链接库。PRO 端用本项目 CMake 目标
`unitree_legged_sdk`,官方 Go1 端用官方仓库的 `libunitree_legged_sdk.a`。本项目已经用
官方头文件反向编译可移植示例,并用本项目头文件编译官方仓库的五个 C++ 示例。
本项目构建方法:
```bash
cmake -S . -B build-cpp -DCMAKE_BUILD_TYPE=Release
cmake --build build-cpp
ctest --test-dir build-cpp --output-on-failure
```
标准四参数 `UDP(LOWLEVEL, ...)` 会在库内部完成 PRO 编解码。默认从安装数据目录读取
Blowfish state需要覆盖时设置 `GO1_PRO_BLOWFISH_STATE=/path/to/blowfish_state.bin`
## 可移植程序规则
要求同一份源码直接运行时,主控制流程只使用:
- `import robot_interface as sdk`
- `sdk.UDP``sdk.Safety``sdk.LeggedType`
- `sdk.LowCmd/LowState``MotorCmd/MotorState``IMU/BmsState`
- `InitCmdData/Recv/GetRecv/SetSend/Send`
- 官方结构中公开的字段,例如 `motorCmd[i].q``motorState[i].q`
所有官方结构对象都应先无参构造,再逐字段赋值。例如使用
`motor = sdk.MotorCmd(); motor.q = 1.0`,不要写 `sdk.MotorCmd(q=1.0)`。后者是 Python
dataclass 常见写法,但官方 pybind wrapper 不接受构造参数。
枚举也按官方对象使用,例如 `sdk.Safety(sdk.LeggedType.Go1)`。不要把枚举当作整数比较
或直接写 `sdk.Safety(2)`;本项目的严格兼容入口会和官方一样拒绝后一种写法。
以下接口属于 PRO 扩展,使用后程序不再能在只安装官方 SDK 的环境中直接运行:
- `from go1_pro_sdk import ...`
- `MCUClient``Go1``Go1MQTT`
- `LowCmd.set_motor()``all_damping()`
- `LowState.remote``apply_safety()`
- `wake_mcu()``safe_stop()`、Blowfish 和快速 C++ builder。
推荐把程序分为“官方公共控制核心”和“可选 PRO 增强”两个模块。公共核心不能导入
增强模块;增强模块可以包装公共核心,但必须允许在官方环境中完全不加载。
`Send()``Recv()``SetSend()` 的具体正整数来自线协议和底层 socket不属于跨
SDK 稳定契约。初始化时可以用 `Recv() > 0` 判断是否收到包,但不应比较具体字节数。
首次进入 PRO 低层通道前,应先反复发送 `InitCmdData()` 产生的 stop sentinel并在
收到第一帧 `LowState` 后再写入有效位置目标。可移植示例已采用这一时序,避免在状态
仍为全零默认值时直接驱动关节。
`UDP(HIGHLEVEL, ..., "192.168.123.161", 8082)` 不会被静默映射到 MQTT。两种通道
状态模型和时序不同,兼容层会明确抛出 `NotImplementedError`。高层控制继续使用
`Go1``Go1MQTT`
## 尚未完全对齐的风险
- 官方 `PowerProtect` 实现在静态库中,头文件只公开签名。本项目当前保护逻辑按
关节力矩限幅和实测过载执行,不等价于官方内部的累计功率算法。
- 官方 `BmsState` 是 34 字节,本项目实测的 PRO 状态布局只给 BMS 分配 24 字节;
`cell_vol` 后半部分不能视为完整的官方数据。
- `LowState.tick` 当前没有从 PRO 包中解析,仍为默认值;`footForce`
`footForceEst` 的偏移来自逆向推断,尚未达到官方字段的同等可信度。
- `head/SN/version/reserve/crc` 在本地原生类型中部分使用 `bytes`,官方 wrapper
使用定长整数数组或整数。命令 builder 接受两种常见赋值形态,但读取后的 Python
类型不保证完全相同。
- 本项目 `LowState` 是 PRO 抓包格式的解释,不应按官方 `#pragma pack(1)` 结构大小
直接做内存映射。
- C++ 类型布局和公开符号用于源码重编译兼容,不保证本项目库与官方预编译对象之间
的 ABI 互换;切换实现时应重新编译应用。
- 两个自定义包长 C++ `UDP` 构造函数和 `SetSend(char*)` 提供原始 UDP 透传,但不会
自动把任意自定义结构转换为 PRO 私有协议;主动断连时间和 accessible 时间参数
仅保留调用形状。Python 兼容入口仍只保证标准四参数 `LOWLEVEL` 通道。
- 官方 SDK 和本项目都提供顶层 `robot_interface`,同一个 Python 环境不要同时安装
两种实现。应在 PRO 环境安装本项目,在官方机器人环境安装官方 SDK。