优化crc速度
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -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
27
tests/test_common.py
Normal 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)
|
||||
Reference in New Issue
Block a user