330 lines
12 KiB
Markdown
330 lines
12 KiB
Markdown
# Go1 PRO SDK
|
||
|
||
Unitree Go1 **PRO** 机型的低层电机控制 Python/C++ SDK。完整逆向 PRO 版的私有协议(Blowfish 加密 + 私有 LowCmd 格式),不依赖官方二进制库,Mac 直连可达 480Hz 控制频率。
|
||
|
||
> 这是为 PRO 准备的 SDK。如果你有 **EDU** 版机器狗,请用原版 [free-dog-sdk](https://github.com/Bin4ry/free-dog-sdk) — PRO 跟 EDU 协议有显著差异,互不兼容。
|
||
|
||
## 关键特性
|
||
|
||
- 完整 Blowfish ECB 加解密(用从机器狗内存提取的 state,不依赖原始 key)
|
||
- PRO 私有 LowCmd 格式(616B / CRC@612 / bandWidth BE 字节序),跟 EDU 不同
|
||
- LowState 解析(12 关节 + IMU + BMS + 足端力 + 遥控器)
|
||
- 实时遥控器按键/摇杆/L2 读取
|
||
- 三层安全保护(PositionLimit / PowerProtect 1-10 / PositionProtect),实测扭矩过载自动停机
|
||
- 实测频率: **Mac 直连 480Hz**(接近原版 EDU 500Hz)
|
||
- 实测延迟: **每帧 1.74ms p50**(Blowfish 加密 1ms + 解密 0.7ms + sendto 0.02ms)
|
||
|
||
## 快速上手
|
||
|
||
### 语言与入口
|
||
|
||
| 使用方式 | 源码位置 | 构建入口 | 用户入口 |
|
||
|---|---|---|---|
|
||
| Python 原生 PRO API | `go1_pro_sdk/` | `pyproject.toml` | `import go1_pro_sdk` |
|
||
| Python 官方兼容 API | `robot_interface.py`、`go1_pro_sdk/compat/` | `pyproject.toml` | `import robot_interface as sdk` |
|
||
| Python 可选原生加速 | `fast_lowcmd_cpp/` | `fast_lowcmd_cpp/setup.py` | `FastLowCmdBuilder` |
|
||
| C++ 官方兼容 SDK | `include/`、`src/` | `CMakeLists.txt` | `#include <unitree_legged_sdk/unitree_legged_sdk.h>` |
|
||
|
||
`fast_lowcmd_cpp` 是供 Python 调用的 CPython 扩展,不是 C++ 用户的公共 SDK。C++ 用户
|
||
只依赖根目录 CMake 生成的 `unitree_legged_sdk` 库以及 `include/unitree_legged_sdk/`
|
||
中的公共头文件。两套实现共享同一份 PRO 协议和 Blowfish state,但运行时不互相依赖。
|
||
|
||
Python 开发环境安装:
|
||
|
||
```bash
|
||
conda activate free_dog_sdk
|
||
python -m pip install -e .
|
||
```
|
||
|
||
### 官方 Python SDK 兼容接口
|
||
|
||
需要复用官方 `unitree_legged_sdk` Python 示例时,可以继续使用原来的模块名和
|
||
调用顺序:
|
||
|
||
```python
|
||
import robot_interface as sdk
|
||
|
||
LOWLEVEL = 0xff # 官方 wrapper 不导出这个常量,官方示例也是在应用中定义
|
||
|
||
udp = sdk.UDP(LOWLEVEL, 8080, "192.168.123.10", 8007)
|
||
safe = sdk.Safety(sdk.LeggedType.Go1)
|
||
cmd, state = sdk.LowCmd(), sdk.LowState()
|
||
udp.InitCmdData(cmd)
|
||
|
||
udp.Recv()
|
||
udp.GetRecv(state)
|
||
safe.PowerProtect(cmd, state, 1)
|
||
udp.SetSend(cmd)
|
||
udp.Send()
|
||
```
|
||
|
||
兼容范围和协议差异见 [`docs/OFFICIAL_API_COMPATIBILITY.md`](docs/OFFICIAL_API_COMPATIBILITY.md)。
|
||
官方 `HighCmd/HighState` UDP 通道和二进制 ABI 当前不在兼容范围内。
|
||
需要同一份代码同时运行在本项目和官方 SDK 上时,只使用官方实际导出的接口;参考
|
||
[`examples/example_official_compatible_position.py`](examples/example_official_compatible_position.py)。
|
||
|
||
### 官方 C++ SDK 兼容接口
|
||
|
||
同一份低层 C++ 源码可分别链接本项目或官方 `unitree_legged_sdk`:
|
||
|
||
```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{};
|
||
udp.InitCmdData(cmd);
|
||
```
|
||
|
||
```bash
|
||
cmake -S . -B build-cpp -DCMAKE_BUILD_TYPE=Release
|
||
cmake --build build-cpp
|
||
ctest --test-dir build-cpp --output-on-failure
|
||
```
|
||
|
||
PRO 环境链接本项目生成的 `libunitree_legged_sdk`;官方机器人环境链接官方同名库。
|
||
参考 [`examples/cpp/example_official_compatible_position.cpp`](examples/cpp/example_official_compatible_position.cpp)。
|
||
Blowfish state 默认随库安装,也可用 `GO1_PRO_BLOWFISH_STATE` 指定。
|
||
|
||
### 高层控制 (走/跳/姿态, 通过 sportMode 系统)
|
||
|
||
```python
|
||
from go1_pro_sdk import Go1, Velocity, Pose, LED
|
||
|
||
with Go1() as dog:
|
||
dog.stand_up()
|
||
dog.set_walk_mode()
|
||
dog.walk(Velocity(vx=0.3)) # 前进
|
||
dog.dance_1()
|
||
dog.set_led(LED(0, 255, 0))
|
||
dog.stand_down()
|
||
```
|
||
|
||
通过 MQTT 控制树莓派上的 Legged_sport. 跟低层互不冲突, 但只能二选一同时用.
|
||
|
||
### 低层控制 (直接控 12 个电机)
|
||
|
||
```python
|
||
from go1_pro_sdk import MCUClient, LowCmd, MotorCmd, MotorMode
|
||
|
||
with MCUClient() as client:
|
||
client.wake_mcu() # 唤醒并切换为我们的客户端
|
||
state = client.recv_state() # 读一帧状态
|
||
print(f"FR_0 q = {state.motorState[0].q}")
|
||
print(f"电量: {state.bms.SOC}%")
|
||
print(f"遥控器按下: {state.remote.pressed}")
|
||
|
||
# 控制 FR 大腿 (注意先悬空 + 安全保护层)
|
||
cmd = LowCmd()
|
||
cmd.set_motor('FR_1', MotorCmd(
|
||
mode=MotorMode.Servo, q=1.2, Kp=5, Kd=1
|
||
))
|
||
client.send(cmd)
|
||
|
||
client.safe_stop() # 退出前发 damping
|
||
```
|
||
|
||
## 调试与验证
|
||
|
||
### 离线完整回归
|
||
|
||
以下测试使用 fake socket 和 `data/captures/` 中的实机历史抓包,不连接机器狗,也不会向
|
||
MCU 发送 UDP 数据。先在仓库根目录准备 Python 包和可选原生扩展:
|
||
|
||
```bash
|
||
conda run -n free_dog_sdk python -m pip install -e .
|
||
cd fast_lowcmd_cpp
|
||
PYTHONPATH=.. conda run -n free_dog_sdk python setup.py build_ext --inplace
|
||
cd ..
|
||
conda run -n free_dog_sdk python -m pytest -q tests fast_lowcmd_cpp/test_fast_lowcmd.py
|
||
```
|
||
|
||
C++ Release 回归会检查官方结构布局、PRO 明密文字节一致性、LowState 实机抓包、安全接口、
|
||
Loop,以及安装后被独立 CMake 项目消费:
|
||
|
||
```bash
|
||
cmake -S . -B build-cpp -DCMAKE_BUILD_TYPE=Release \
|
||
-DGO1_PRO_CAPTURE_DIR="$PWD/data/captures"
|
||
cmake --build build-cpp --parallel
|
||
ctest --test-dir build-cpp --output-on-failure
|
||
```
|
||
|
||
配置阶段若显示 `Private data/captures fixtures not found`,说明只运行公共契约测试,未运行
|
||
实机抓包字节回归。`ctest` 不会运行 `examples/` 中会发送命令的示例程序。
|
||
|
||
### 定点调试
|
||
|
||
Python 可用 pytest 节点路径只运行单项并显示输出;C++ 可直接运行兼容测试,或交给
|
||
LLDB(macOS)/GDB(Linux):
|
||
|
||
```bash
|
||
conda run -n free_dog_sdk python -m pytest -vv -s \
|
||
tests/test_capture_fixtures.py
|
||
ctest --test-dir build-cpp -R cpp_official_compat -V
|
||
lldb -- build-cpp/test_cpp_compat
|
||
# Linux: gdb --args build-cpp/test_cpp_compat
|
||
```
|
||
|
||
需要验证另一份 Blowfish state 或外部抓包目录时:
|
||
|
||
```bash
|
||
GO1_PRO_BLOWFISH_STATE=/path/to/blowfish_state.bin ./build-cpp/test_cpp_compat
|
||
cmake -S . -B build-cpp -DGO1_PRO_CAPTURE_DIR=/path/to/captures
|
||
cmake --build build-cpp --target test_cpp_compat --parallel
|
||
```
|
||
|
||
### C++ 编译与运行时检查
|
||
|
||
先用严格警告检查可移植性;ASan/UBSan 用于检查越界、生命周期和未定义行为,TSan 单独
|
||
构建,不能与 ASan 混用:
|
||
|
||
```bash
|
||
cmake -S . -B build-cpp-warn -DCMAKE_BUILD_TYPE=Release \
|
||
-DCMAKE_CXX_FLAGS="-Wall -Wextra -Wpedantic"
|
||
cmake --build build-cpp-warn --parallel
|
||
ctest --test-dir build-cpp-warn --output-on-failure
|
||
|
||
cmake -S . -B build-cpp-sanitize -DCMAKE_BUILD_TYPE=Debug \
|
||
-DCMAKE_CXX_FLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer"
|
||
cmake --build build-cpp-sanitize --parallel
|
||
ctest --test-dir build-cpp-sanitize --output-on-failure
|
||
|
||
cmake -S . -B build-cpp-tsan -DCMAKE_BUILD_TYPE=Debug \
|
||
-DCMAKE_CXX_FLAGS="-fsanitize=thread -fno-omit-frame-pointer"
|
||
cmake --build build-cpp-tsan --parallel
|
||
ctest --test-dir build-cpp-tsan --output-on-failure
|
||
```
|
||
|
||
### C++ 编解码基准
|
||
|
||
基准默认不参与构建。存在 `data/captures/mcu_response_new.bin` 时会同时测量
|
||
`EncodeLowCmd` 和 `DecodeLowState`;缺少抓包时只测编码:
|
||
|
||
```bash
|
||
cmake -S . -B build-cpp-benchmark -DCMAKE_BUILD_TYPE=Release \
|
||
-DGO1_PRO_BUILD_BENCHMARKS=ON
|
||
cmake --build build-cpp-benchmark --target benchmark_cpp_codec --parallel
|
||
./build-cpp-benchmark/benchmark_cpp_codec
|
||
```
|
||
|
||
### 实机烟雾验证
|
||
|
||
自动测试通过后再进入下一节的实机流程。`monitor_state.py` 和 `monitor_remote.py` 虽不发送
|
||
运动目标,但会执行 `wake_mcu()` 并持续发送 damping LowCmd 以维持回包,因此不是纯被动
|
||
抓包;运行前仍须悬空机器狗、停掉抢占源,结束后恢复 sportMode。C++ position 示例会发送
|
||
实际关节位置命令,只应按 [`docs/SAFETY.md`](docs/SAFETY.md) 的检查清单手动运行。
|
||
|
||
## 准备工作
|
||
|
||
### 1. 提取 Blowfish 密钥(仅需一次)
|
||
|
||
`go1_pro_sdk/_data/blowfish_state.bin` 已包含我们项目用的密钥。如果你的狗用的是不同的 key(很少见,除非固件升级),需要重新提取:
|
||
|
||
```bash
|
||
# SSH 到狗 (192.168.123.161)
|
||
scp tools/extract_blowfish_key.sh pi@192.168.123.161:/tmp/
|
||
ssh pi@192.168.123.161 "sudo bash /tmp/extract_blowfish_key.sh"
|
||
scp pi@192.168.123.161:/tmp/blowfish_dump.tar.gz ./data/
|
||
|
||
# Mac 端分析
|
||
python tools/analyze_blowfish_dump.py data/blowfish_dump.tar.gz
|
||
# → 输出 go1_pro_sdk/_data/blowfish_state.bin
|
||
```
|
||
|
||
### 2. 停掉狗上的抢占源
|
||
|
||
PRO 的 MCU 一次只接受一个客户端的命令。要让 SDK 工作,必须先停掉狗上的:
|
||
|
||
```bash
|
||
ssh pi@192.168.123.161 "sudo pkill -9 -f keep_sport_alive; \
|
||
sudo pkill -9 -f Legged_sport; \
|
||
sudo pkill -9 -f appTransit"
|
||
```
|
||
|
||
或用我们提供的:
|
||
|
||
```bash
|
||
bash tools/stop_sportmode.sh stop
|
||
```
|
||
|
||
### 3. 跑示例
|
||
|
||
```bash
|
||
# 状态监听(会发送 damping LowCmd,不是纯被动监听)
|
||
python examples/monitor_state.py --duration 30 --verbose
|
||
|
||
# 遥控器监听(会发送 damping LowCmd)
|
||
python examples/monitor_remote.py
|
||
|
||
# 单腿 sin 摆动 (狗悬空, 振幅 0.3 rad)
|
||
python examples/example_sin_leg.py --amplitude 0.3 --freq 0.5
|
||
|
||
# 复刻原版 example_position(lowlevel).py
|
||
python examples/example_position.py
|
||
```
|
||
|
||
### 4. 测完恢复
|
||
|
||
```bash
|
||
bash tools/stop_sportmode.sh start
|
||
```
|
||
|
||
## ⚠️ 安全
|
||
|
||
直接控制 12 个电机是**危险操作**:
|
||
|
||
- 第一次测试 **狗必须悬空** (脚架/吊带)
|
||
- 用 `apply_safety(cmd, state, power_factor=1)` 限制力矩到 10%
|
||
- 准备 **拔电池** 作为终极停机 (Legged_sport 被杀后,遥控器 L2+B 不会工作)
|
||
- 见 `docs/SAFETY.md`
|
||
|
||
## 包结构
|
||
|
||
```
|
||
go1_pro_sdk/ # Python 原生 PRO SDK
|
||
├── connection/ # MCUClient: UDP 客户端
|
||
├── codec/ # Python Blowfish、LowCmd、LowState
|
||
├── compat/ # 官方 robot_interface Python facade
|
||
├── highlevel/ # sportMode MQTT API
|
||
├── safety/ # Python Safety 实现
|
||
├── types/ # Python 数据结构
|
||
├── utils/ # CRC、常量和字段编解码
|
||
└── _data/ # Python wheel 内的 Blowfish state
|
||
|
||
robot_interface.py # 官方 Python SDK 同名顶层入口
|
||
pyproject.toml # Python 构建和安装入口
|
||
fast_lowcmd_cpp/ # Python 可选 CPython 加速扩展
|
||
|
||
include/unitree_legged_sdk/ # C++ 公共头文件,路径与官方一致
|
||
src/ # C++ 私有实现,不作为公共头文件安装
|
||
cmake/ # C++ find_package 配置模板
|
||
CMakeLists.txt # C++ 构建、测试和安装入口
|
||
|
||
examples/*.py # Python 示例
|
||
examples/cpp/ # C++ 同源码兼容示例
|
||
tests/*.py # Python、实机抓包和 facade 回归
|
||
tests/cpp/ # C++ 契约、安装消费测试与可选性能基准
|
||
data/captures/ # 本机实机抓包,存在时自动参与回归
|
||
```
|
||
|
||
Python 和 C++ 的公共 API 不交叉包含:Python 安装由 `pyproject.toml` 管理,不会安装
|
||
C++ 头文件;C++ 安装由 CMake 管理,不会安装 Python 包。两边唯一共享的运行数据是
|
||
`blowfish_state.bin`,安装时分别进入 Python package data 和 C++ data directory。
|
||
|
||
## 文档
|
||
|
||
- `docs/PROTOCOL.md` — PRO LowCmd/LowState 字节级格式规格
|
||
- `docs/SAFETY.md` — 安全测试清单
|
||
- `docs/REVERSE_ENGINEERING.md` — 逆向工程过程精华
|
||
- `docs/ARCHITECTURE.md` — 包结构与数据流
|
||
|
||
## 致谢
|
||
|
||
- 原版 [free-dog-sdk](https://github.com/Bin4ry/free-dog-sdk) by Bin4ry (Andreas Makris) — 提供了 EDU 版的基础数据结构和 CRC 实现
|
||
- Unitree 官方 [unitree_legged_sdk](https://github.com/unitreerobotics/unitree_legged_sdk) — 公开了 safety.h 的接口定义
|
||
|
||
## License
|
||
|
||
MIT (跟 free-dog-sdk 一致)
|