Files
go1_pro_sdk/docs/PROTOCOL.md
2026-06-20 20:02:36 +08:00

4.2 KiB
Raw Blame History

Go1 PRO 协议规格

完全实测/抓包验证 (2026-06-20)。

LowCmd (主控 → MCU)

616 字节 Blowfish ECB 密文 (明文 616B, 加密后还是 616B),通过 UDP 发到 192.168.123.10:8007

明文 616B 布局

偏移 字节 字段 说明
0..2 2 head fe ef
2..3 1 levelFlag 0xff
3..4 1 frameReserve 0
4..12 8 SN 全 0 (PRO 不填)
12..20 8 version 全 0 (PRO 不填)
20..22 2 bandWidth 3a c0 (BE 字节序, 不是 LE!)
22..562 540 motorCmd[20] 每电机 27B (mode + q + dq + tau + Kp + Kd + reserve)
562..566 4 bms 0
566..606 40 wirelessRemote 0
606..610 4 reserve 0
610..612 2 固定填充 00 00
612..616 4 CRC gen_crc(cmd[:612]) 裸 CRC, 不 XOR

MotorCmd 单电机 27B

0..1:  mode (uint8)
1..5:  q (float, Unitree 自定义 hex 编码, 不是标准 IEEE 754)
5..9:  dq (同上)
9..11: tau (2B 自定义)
11..13: Kp (2B 自定义)
13..15: Kd (2B 自定义)
15..27: reserve (12B = 3 × 4B)

各字段编解码见 go1_pro_sdk/utils/common.py

跟 EDU 版差异 (free-dog-sdk lowCmd)

EDU PRO
总长 614B 616B
CRC 偏移 610..614 612..616
CRC 算法 encryptCrc(genCrc(cmd[:-6])) (XOR 0xedcab9de) gen_crc(cmd[:612])
bandWidth 字节序 LE BE
SN/version 用户提供 全 0
是否加密 Blowfish ECB

LowState (MCU → 主控)

858 字节 Blowfish ECB 密文 (Blowfish 8B 块, 858 取 8 对齐 = 856B 解密)。

解密后 807B 是有效 LowState后面 49B 填充/MCU 内部。

明文 807B 布局 (跟 free-dog-sdk 的 ucl/lowState.py 一致)

偏移 字节 字段
0..2 2 head
2..3 1 levelFlag
3..4 1 frameReserve
4..12 8 SN
12..20 8 version
20..22 2 bandWidth
22..75 53 IMU (quaternion 16B + gyro 12B + accel 12B + rpy 12B + temp 1B)
75..715 640 motorState[20] × 32B
715..739 24 BMS
739..759 20 footForce / footForceEst (混合)
759..799 40 wirelessRemote (遥控器原始数据)
799..803 4 reserve
803..807 4 CRC

Blowfish

ECB 模式LE word 字节序 (Unitree ARM64 LDP 读取顺序,不是标准 BE Blowfish)。

state (4168B) = P[18] + S0[256] + S1[256] + S2[256] + S3[256],每项 4B uint32。

F 函数

def F(X):
    a = (X >> 24) & 0xff
    b = (X >> 16) & 0xff
    c = (X >> 8) & 0xff
    d = X & 0xff
    return ((((S0[a] + S1[b]) & 0xFFFFFFFF) ^ S2[c]) + S3[d]) & 0xFFFFFFFF

注意 Python 运算符优先级: +^ 高,必须完整括号否则结果错。

16 轮 Feistel

标准 Blowfish 算法 (见 go1_pro_sdk/codec/blowfish.py),无定制。

已知明密文对 (用于验证 state)

encrypt(0000000000000000) = 12aa0354236b66e3
encrypt(feefff0004020305) = 5d9874ad7eee5851
encrypt(0802010000010900) = c5ce0887ceb86f91

遥控器 wirelessRemote (40B)

布局 (Unitree 公开 xRockerBtnDataStruct):

偏移 字节 字段
0..2 2 head 0x55 0xAA
2..4 2 btn bitmap (uint16 LE)
4..8 4 lx (float, -1..+1)
8..12 4 rx
12..16 4 ry
16..20 4 L2 (0..1, 模拟扳机)
20..24 4 ly
24..40 16 reserved

按键 bitmap

按键 按键
0x0001 R1 0x0100 A
0x0002 L1 0x0200 B
0x0004 START 0x0400 X
0x0008 SELECT 0x0800 Y
0x0010 R2 0x1000 UP
0x0020 L2 0x2000 RIGHT
0x0040 F1 0x4000 DOWN
0x0080 F2 0x8000 LEFT

MCU 客户端切换机制

MCU 按"最近发包者的 IP:port"切换客户端。也就是说:

  • 我们 Mac 不需要绑特定端口,任意 OS 分配的端口都行
  • 一旦我们发包MCU 把后续 LowState 回复给我们 (Legged_sport 不再收到)
  • Legged_sport 没收到 state 就停止 sendto等价于"挂起"

含义: 必须先在 Pi 上杀 keep_sport_alive.shLegged_sportappTransit 三个抢占者,否则会跟 MCU 反复切换导致控制失败。