优化crc速度

This commit is contained in:
cyy_mac
2026-07-26 20:51:57 +08:00
parent cd9f8e204d
commit 265173e746
3 changed files with 60 additions and 12 deletions

View File

@@ -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)

View File

@@ -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('<I').pack
def gen_crc(data: bytes) -> 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('<I', crc)
for (word,) in struct.iter_unpack('<I', data):
crc = ((crc << 8) & 0xFFFFFFFF) ^ table[((crc >> 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 但小端整数读) =====

27
tests/test_common.py Normal file
View File

@@ -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("<I", data):
for bit in range(32):
x = (crc >> 31) & 1
crc <<= 1
crc &= 0xFFFFFFFF
if x ^ (1 & (word >> (31 - bit))):
crc ^= 0x04c11db7
return struct.pack("<I", crc)
def test_gen_crc_matches_reference_bitwise():
samples = [
b"",
bytes(4),
bytes(range(64)),
b"\xfe\xef\xff\x00" + bytes(range(252)) * 2,
]
for sample in samples:
assert gen_crc(sample) == _gen_crc_bitwise(sample)