python部分官方化对齐接口

This commit is contained in:
cyy_mac
2026-07-29 21:50:15 +08:00
parent 81f14e14ca
commit dbfcb95566
15 changed files with 678 additions and 14 deletions

View File

@@ -0,0 +1,140 @@
"""Contract tests for the official ``robot_interface`` compatibility API."""
from copy import deepcopy
import pytest
import robot_interface as sdk
from go1_pro_sdk import build_low_cmd_plain
class _FakeMCUClient:
instances = []
def __init__(self, mcu_ip, mcu_port, local_port):
self.mcu_ip = mcu_ip
self.mcu_port = mcu_port
self.local_port = local_port or 49152
self.next_state = sdk.LowState()
self.next_state.motorState[sdk.FR_1].q = 1.23
self.sent = []
self.closed = False
self.__class__.instances.append(self)
def send(self, cmd):
self.sent.append(deepcopy(cmd))
return 616
def recv_latest(self):
return deepcopy(self.next_state)
def recv_state(self, timeout):
return deepcopy(self.next_state)
def close(self):
self.closed = True
@pytest.fixture
def fake_client(monkeypatch):
_FakeMCUClient.instances.clear()
monkeypatch.setattr(
"go1_pro_sdk.compat.robot_interface.MCUClient",
_FakeMCUClient,
)
return _FakeMCUClient
def test_official_names_and_data_types_are_available():
assert sdk.LOWLEVEL == 0xff
assert sdk.LeggedType.Go1 == 2
assert sdk.Go1 is sdk.LeggedType.Go1
assert sdk.FR_0 == 0
assert sdk.RL_2 == 11
assert sdk.BmsState().SOC == 0
assert sdk.HighCmd().velocity == [0.0, 0.0]
def test_init_cmd_data_uses_official_stop_sentinels():
udp = sdk.UDP(sdk.LOWLEVEL, 0, "192.168.123.10", 8007)
cmd = sdk.LowCmd()
assert udp.InitCmdData(cmd) is None
assert cmd.levelFlag == sdk.LOWLEVEL
assert len(cmd.motorCmd) == 20
assert all(m.mode == 0x0A for m in cmd.motorCmd)
assert all(m.q == sdk.PosStopF for m in cmd.motorCmd)
assert all(m.dq == sdk.VelStopF for m in cmd.motorCmd)
def test_official_lowlevel_send_receive_sequence(fake_client):
udp = sdk.UDP(sdk.LOWLEVEL, 0, "192.168.123.10", 8007)
cmd = sdk.LowCmd()
state = sdk.LowState()
udp.InitCmdData(cmd)
assert udp.Recv() == 858
assert udp.GetRecv(state) is None
assert state.motorState[sdk.FR_1].q == pytest.approx(1.23)
cmd.motorCmd[sdk.FR_1].q = 1.2
cmd.motorCmd[sdk.FR_1].dq = 0.0
cmd.motorCmd[sdk.FR_1].Kp = 5.0
cmd.motorCmd[sdk.FR_1].Kd = 1.0
assert udp.SetSend(cmd) == 0
assert udp.Send() == 616
client = fake_client.instances[0]
assert client.sent[0].motorCmd[sdk.FR_1].q == pytest.approx(1.2)
assert udp.udpState.SendCount == 1
assert udp.udpState.RecvCount == 1
def test_position_limit_skips_stop_sentinel():
cmd = sdk.LowCmd()
sdk.UDP(sdk.LOWLEVEL, 0, "192.168.123.10", 8007).InitCmdData(cmd)
cmd.motorCmd[sdk.FR_1].q = 99.0
safe = sdk.Safety(sdk.LeggedType.Go1)
assert safe.PositionLimit(cmd) is None
assert cmd.motorCmd[sdk.FR_0].q == sdk.PosStopF
assert cmd.motorCmd[sdk.FR_1].q == pytest.approx(3.5)
def test_bms_command_is_serialized():
cmd = sdk.LowCmd()
cmd.bms.off = 0xA5
cmd.bms.reserve = [1, 2, 3]
plain = build_low_cmd_plain(cmd)
assert plain[562:566] == b"\xa5\x01\x02\x03"
def test_official_reserved_field_shapes_are_serialized():
cmd = sdk.LowCmd()
cmd.SN = [0x04030201, 0x08070605]
cmd.version = [0x01020304, 0x05060708]
cmd.reserve = 0x44332211
plain = build_low_cmd_plain(cmd)
assert plain[4:12] == bytes.fromhex("0102030405060708")
assert plain[12:20] == bytes.fromhex("0403020108070605")
assert plain[606:610] == bytes.fromhex("11223344")
def test_fixed_size_official_arrays_are_validated():
cmd = sdk.LowCmd()
cmd.wirelessRemote = [0] * 39
with pytest.raises(ValueError, match="wirelessRemote"):
build_low_cmd_plain(cmd)
def test_highlevel_udp_reports_the_unsupported_boundary():
udp = sdk.UDP(sdk.HIGHLEVEL, 8080, "192.168.123.161", 8082)
cmd = sdk.HighCmd()
udp.InitCmdData(cmd)
udp.SetSend(cmd)
with pytest.raises(NotImplementedError, match="HighCmd/HighState UDP"):
udp.Send()