yincheng.zhong
2 天以前 567085ead3f6adaabd884f16ab4b17c62e8f0403
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import struct
from datetime import datetime, timezone
 
import pytest
 
from hitl import protocols
 
 
def _checksum_matches(frame: bytes) -> bool:
    calc = sum(frame[:-4]) & 0xFFFF
    stored = struct.unpack("<H", frame[-4:-2])[0]
    return calc == stored
 
 
def test_build_im23a_nav_frame_format():
    ts = datetime(2025, 11, 21, 8, 1, 12, tzinfo=timezone.utc)
    frame = protocols.build_im23a_nav_frame(
        timestamp=ts,
        lat_deg=39.8301751,
        lon_deg=116.2781268,
        alt_m=48.5,
        east_vel=0.2,
        north_vel=0.1,
        up_vel=0.0,
        heading_deg=123.4,
        pitch_deg=1.2,
        roll_deg=-0.6,
        accel_bias=(0.0, 0.0, 0.0),
        gyro_bias=(0.0, 0.0, 0.0),
        temperature_c=29.5,
        status_flags=4,
    )
 
    assert frame.startswith(b"fmin")
    assert frame.endswith(b"ed")
    assert len(frame) == protocols.IM23A_NAV_LEN
    assert _checksum_matches(frame)
 
    # 解码部分字段验证顺序
    ts_val = struct.unpack("<d", frame[4:12])[0]
    assert ts_val == pytest.approx(8 * 3600 + 1 * 60 + 12, rel=1e-6)
    lat = struct.unpack("<d", frame[12:20])[0]
    lon = struct.unpack("<d", frame[20:28])[0]
    assert lat == pytest.approx(39.8301751)
    assert lon == pytest.approx(116.2781268)
 
 
def test_build_im23a_imu_frame_format():
    ts = datetime(2025, 11, 21, 8, 1, 12, tzinfo=timezone.utc)
    frame = protocols.build_im23a_imu_frame(
        timestamp=ts,
        accel_g=(0.01, -0.02, -0.99),
        gyro_deg_s=(0.1, 0.2, -0.3),
    )
 
    assert frame.startswith(b"fmim")
    assert frame.endswith(b"ed")
    assert len(frame) == protocols.IM23A_IMU_LEN
    assert _checksum_matches(frame)
 
    accel_x = struct.unpack("<f", frame[12:16])[0]
    gyro_z = struct.unpack("<f", frame[28:32])[0]
    assert accel_x == pytest.approx(0.01)
    assert gyro_z == pytest.approx(-0.3)
 
 
def _build_control_frame(payload: bytes) -> bytes:
    header = b"\xAA\x55"
    frame_type = b"\x10"
    length = struct.pack("<H", len(payload))
    checksum = (sum(frame_type + length + payload)) & 0xFFFF
    footer = b"\x0D\x0A"
    return header + frame_type + length + payload + struct.pack("<H", checksum) + footer
 
 
def test_pythonlink_decoder_float_payload():
    received = []
    decoder = protocols.PythonLinkDecoder(lambda frame: received.append(frame))
    frame = _build_control_frame(struct.pack("<ff", 1.2, -0.4))
    decoder.feed(frame[:5])
    decoder.feed(frame[5:])
 
    assert len(received) == 1
    assert received[0].forward == pytest.approx(1.2)
    assert received[0].turn == pytest.approx(-0.4)
 
 
def test_pythonlink_decoder_pwm_payload():
    received = []
    decoder = protocols.PythonLinkDecoder(lambda frame: received.append(frame))
    frame = _build_control_frame(struct.pack("<HH", 2000, 1600))
    decoder.feed(frame)
 
    assert len(received) == 1
    assert received[0].forward == pytest.approx(0.3, rel=0.05)  # (1600-1500)/500 * 1.5
    assert received[0].turn == pytest.approx(1.5708, rel=0.05)