From 265173e74625efa5957920f2d5038fc0292d7336 Mon Sep 17 00:00:00 2001 From: cyy_mac Date: Sun, 26 Jul 2026 20:51:57 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96crc=E9=80=9F=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go1_pro_sdk/codec/lowcmd_builder.py | 11 ++++++---- go1_pro_sdk/utils/common.py | 34 ++++++++++++++++++++++------- tests/test_common.py | 27 +++++++++++++++++++++++ 3 files changed, 60 insertions(+), 12 deletions(-) create mode 100644 tests/test_common.py diff --git a/go1_pro_sdk/codec/lowcmd_builder.py b/go1_pro_sdk/codec/lowcmd_builder.py index 01faec7..9825fbe 100644 --- a/go1_pro_sdk/codec/lowcmd_builder.py +++ b/go1_pro_sdk/codec/lowcmd_builder.py @@ -50,9 +50,12 @@ def build_low_cmd_plain(lowcmd: LowCmd) -> bytes: # 20..22 bandWidth BE cmd[20:22] = struct.pack('>H', lowcmd.bandWidth) # 22..562 motorCmd[20] × 27B - motor_bytes = b''.join(m.to_bytes() for m in lowcmd.motorCmd) - assert len(motor_bytes) == 540, f'motorCmd 序列化长度错: {len(motor_bytes)}' - cmd[22:562] = motor_bytes + offset = 22 + for motor in lowcmd.motorCmd: + motor_bytes = motor.to_bytes() + assert len(motor_bytes) == 27, f'motorCmd 序列化长度错: {len(motor_bytes)}' + cmd[offset:offset + 27] = motor_bytes + offset += 27 # 562..566 bms (默认 0) # 566..606 wirelessRemote cmd[566:606] = lowcmd.wirelessRemote @@ -60,7 +63,7 @@ def build_low_cmd_plain(lowcmd: LowCmd) -> bytes: cmd[606:610] = lowcmd.reserve # 610..612 固定填充 0x0000 # 612..616 CRC - cmd[612:616] = gen_crc(bytes(cmd[:612])) + cmd[612:616] = gen_crc(memoryview(cmd)[:612]) return bytes(cmd) diff --git a/go1_pro_sdk/utils/common.py b/go1_pro_sdk/utils/common.py index 30d69c5..be067ef 100644 --- a/go1_pro_sdk/utils/common.py +++ b/go1_pro_sdk/utils/common.py @@ -15,20 +15,38 @@ import binascii # ===== CRC32 (用于 LowCmd 末尾 4 字节, PRO 不 XOR, EDU 才 XOR encryptCrc) ===== +_CRC32_POLY = 0x04c11db7 + + +def _make_crc32_table(): + table = [] + for byte in range(256): + crc = byte << 24 + for _ in range(8): + if crc & 0x80000000: + crc = ((crc << 1) ^ _CRC32_POLY) & 0xFFFFFFFF + else: + crc = (crc << 1) & 0xFFFFFFFF + table.append(crc) + return tuple(table) + + +_CRC32_TABLE = _make_crc32_table() +_CRC_PACK = struct.Struct(' bytes: """CRC-32 with polynomial 0x04c11db7 (custom 实现, 跟 Unitree MCU 对齐). 跟 Python zlib.crc32 不同 (zlib 用反射 + 0xEDB88320), 所以这个手动实现保留. """ + table = _CRC32_TABLE crc = 0xFFFFFFFF - for j in struct.unpack("<%dI" % (len(data) // 4), data): - for b in range(32): - x = (crc >> 31) & 1 - crc <<= 1 - crc &= 0xFFFFFFFF - if x ^ (1 & (j >> (31 - b))): - crc ^= 0x04c11db7 - return struct.pack('> 24) ^ ((word >> 24) & 0xff)) & 0xff] + crc = ((crc << 8) & 0xFFFFFFFF) ^ table[((crc >> 24) ^ ((word >> 16) & 0xff)) & 0xff] + crc = ((crc << 8) & 0xFFFFFFFF) ^ table[((crc >> 24) ^ ((word >> 8) & 0xff)) & 0xff] + crc = ((crc << 8) & 0xFFFFFFFF) ^ table[((crc >> 24) ^ (word & 0xff)) & 0xff] + return _CRC_PACK(crc) # ===== float ↔ hex 字段 (Unitree 用 big-endian float 但小端整数读) ===== diff --git a/tests/test_common.py b/tests/test_common.py new file mode 100644 index 0000000..0808f1f --- /dev/null +++ b/tests/test_common.py @@ -0,0 +1,27 @@ +"""Common codec utility tests.""" +import struct + +from go1_pro_sdk.utils.common import gen_crc + + +def _gen_crc_bitwise(data: bytes) -> bytes: + crc = 0xFFFFFFFF + for (word,) in struct.iter_unpack("> 31) & 1 + crc <<= 1 + crc &= 0xFFFFFFFF + if x ^ (1 & (word >> (31 - bit))): + crc ^= 0x04c11db7 + return struct.pack("