yincheng.zhong
2025-12-05 18f1d1afd16ae159b9f20cef640a594c848ad249
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
o
Ÿe2iM5ã@s’dZddlmZddlZddlZddlmZddlmZmZddl m
Z
m Z m Z djdkdd„Z dZdZdZdZdZdldd„Zdmdd„Zdnd#d$„Zdnd%d&„Zdod'd(„Zdod)d*„Zdpd+d,„Zdqd=d>„Z  ?drdsdCdD„ZdtdEdF„ZdudIdJ„ZeGdKdL„dLƒƒZeGdMdN„dNƒƒZeGdOdP„dPƒƒZ eGdQdR„dRƒƒZ!eGdSdT„dTƒƒZ"eGdUdV„dVƒƒZ#GdWdX„dXƒZ$dvd[d\„Z%dwd_d`„Z&dxdbdc„Z'dydedf„Z(dzdhdi„Z)dS){uŠ
与 STM32H7 äº¤äº’的协议封装:
- æž„造 IM23A "fmin"/"fmim" ä¼ æ„Ÿå™¨å¸§
- è§£æž PythonLink æŽ§åˆ¶å¸§
- è§£æž ASCII çŠ¶æ€æŠ¥æ–‡
é)Ú annotationsN)Ú    dataclass)ÚdatetimeÚtimezone)ÚCallableÚOptionalÚTupleéÜéôçø?ÚvalueÚintÚcenterÚspanÚ  max_speedÚfloatÚreturncCsd|dkrd}|dkr d}d|}|dkr"d}t|ƒdkrdS||Sd}t|ƒd   kr,dS||}|S)
u×
    å°† PWM ä¿¡å·è½¬æ¢ä¸ºçº¿é€Ÿåº¦æˆ–角速度。
    åŸºäºŽ motion_config.h ä¸­çš„æ¨¡åž‹å‚数:
    Forward: v = K_fwd * (1500 - pwm) + Bias (但模拟器这里主要是为了闭环,不需要完美匹配Bias,只要方向对)
             1000 PWM = 0.56 m/s
             1500 PWM = 0.0 m/s
             2000 PWM = -0.2 m/s (backward)
    Turn:    w = K_turn * (1500 - pwm)
             1000 PWM = 63 deg/s (Left)
             2000 PWM = -61.5 deg/s (Right)
    ièiÐr g$@gú~j¼t“X?é(çg¸…ëQ¸¾?é
)Úabs)r rrrÚdeltaZk_linZ k_ang_degZdeg_s©rú1E:\GIT\Lawnmower_STM32H7\python\hitl\protocols.pyÚ_pwm_to_velocitys  rédé4sfminsfmimsedÚdtrcCs$|jdur |jtjdS| tj¡S)N)Útzinfo)rÚreplacerÚutcZ
astimezone)rrrrÚ _ensure_utcHs
 r!Úsentence_without_starÚstrcCs*d}|dd…D]}|t|ƒN}q|d›S)NréZ02X)Úord)r"ZcsÚchrrrÚ nmea_checksumNsr'ÚbufÚ    bytearrayÚNonecCó| t dt|ƒ¡¡dS)Nz<d©ÚextendÚstructÚpackr©r(r rrrÚ _write_doubleUór1cCr+)Nz<fr,r0rrrÚ _write_floatYr2r3cCr+)Nz<I©r-r.r/r r0rrrÚ
_write_u32]r2r5cCr+)Nú<Hr4r0rrrÚ
_write_u16ar2r7cCs,t|ƒd@}| t d|¡¡| t¡dS)Néÿÿr6)Úsumr-r.r/Ú
IM23A_TAIL)r(ÚchecksumrrrÚ _append_tailes r<Ú   timestampÚlat_degÚlon_degÚalt_mÚeast_velÚ   north_velÚup_velÚ heading_degÚ pitch_degÚroll_degÚ
accel_biasúTuple[float, float, float]Ú gyro_biasÚ temperature_cÚ status_flagsÚbytescCsôttƒ}t|t|ƒƒt||ƒt||ƒt||ƒt||ƒt||ƒt|| ƒt||    ƒt||ƒt||ƒt|dƒt||
dƒt||
dƒt||
dƒt|| dƒt|| dƒt|| dƒt|| ƒt|| ƒt|ƒt|ƒS)Ng{®Gáz”?rr$é)r)ÚIM23A_NAV_HEADERr1Ú_seconds_of_dayr3r5r<rL)r=r>r?r@rArBrCrDrErFrGrIrJrKr(rrrÚbuild_im23a_nav_frameks,
 
 
 
 
 
 
 
 
 
 
rP©rrrÚaccel_gÚ
gyro_deg_sÚreservescCs¤ttƒ}t|t|ƒƒt||dƒt||dƒt||dƒt||dƒt||dƒt||dƒt||dƒt||dƒt||dƒt|ƒt|ƒS)Nrr$rM)r)ÚIM23A_IMU_HEADERr1rOr3r<rL)r=rRrSrTr(rrrÚbuild_im23a_imu_frame“srVcCs,t|ƒ}|jd|jd|j|jdS)Nié<g€„.A)r!ZhourZminuteÚsecondZ microsecond)rr rrrrO¨sÿþýÿrOÚpayloadúTuple[float, float]cCsxt|ƒdkrt d|¡\}}||fSt|ƒdkr3t d|¡\}}t|dd}t t|dd¡}||fStdt|ƒ›ƒ‚)  Néz<fféz<HHgð?)rg€V@u ä¸æ”¯æŒçš„æŽ§åˆ¶è´Ÿè½½é•¿åº¦: )Úlenr.ÚunpackrÚmathÚradiansÚ
ValueError)rYÚforwardÚturnÚ steering_pwmÚ throttle_pwmrrrÚ_decode_payload²s   rfc@seZdZUded<ded<dS)ÚPythonLinkFramerrbrcN©Ú__name__Ú
__module__Ú __qualname__Ú__annotations__rrrrrg¿ó
 rgc@seZdZUded<ded<dS)ÚPythonAsciiMessager#Útagz list[str]ÚfieldsNrhrrrrrnÅrmrnc@s~eZdZUded<ded<ded<ded<ded<ded <ded
<ded <ded <ded <ded<ded<ded<ded<dS)Ú ControlStatusrÚ forward_mpsÚ  turn_rateÚfreq_hzr rdrer#ÚstageÚ timestamp_msÚeastÚnorthÚuprDÚtarget_heading_degÚ target_eastÚ target_northNrhrrrrrqËs
 rqc@sVeZdZUded<ded<ded<ded<ded<ded<ded<ded <ded
<d S) Ú
PoseStatusrrwrxryrDrErFr{r|rvNrhrrrrr}Ýs
 r}c@s.eZdZUded<ded<ded<ded<dS)Ú StateStatusr#rurÚcross_track_errorÚheading_error_degrvNrhrrrrr~ês
 
 r~c@s&eZdZUded<ded<ded<dS)Ú StackStatusr#Ú task_namer Ústack_high_waterÚheap_free_bytesNrhrrrrròs
 rc@sNeZdZdZdZdZdZddd„Zdd d „Zddd„Z ddd„Z
ddd„Z dS)ÚPythonLinkDecoderu>
    è§£æž PythonLink æŽ§åˆ¶å¸§ (0xAA 0x55 ... 0D 0A)。
    sªUs
éÚon_frameú!Callable[[PythonLinkFrame], None]cCstƒ|_||_dS©N)r)Ú_bufferÚ  _on_frame)Úselfr‡rrrÚ__init__s
zPythonLinkDecoder.__init__ÚdatarLcCsÌ|sdS|j |¡  | ¡}|dkr|j ¡dS|dkr$|jd|…=t|jƒdkr-dS| ¡}|dus<t|jƒ|kr>dSt|jd|…ƒ}|jd|…=z| |¡}|rZ| |¡Wn  t ydYq
wq )NTré  )
rŠr-Ú _find_headerÚclearr]Ú_expected_frame_lengthrLÚ _parse_framer‹Ú   Exception)rŒrŽÚstartZ   frame_lenÚframeÚparsedrrrÚfeeds4 
 
 
€ þîzPythonLinkDecoder.feedrr cCst|jƒ}| |j¡}|Sr‰)rLrŠÚfindÚ FRAME_HEADER)rŒrŽÚidxrrrr s
 zPythonLinkDecoder._find_headerú Optional[int]cCs8t|jƒdkr dSt |jdd…d¡}d|ddS)NééÚlittlerM)r]rŠr Ú
from_bytes)rŒÚ payload_lenrrrr’%sz(PythonLinkDecoder._expected_frame_lengthr–úOptional[PythonLinkFrame]c Cs²| |j¡r | |j¡sdS|d}||jkrdSt |dd…d¡}d}||}|||…}t |||d…d¡}t|d|…ƒd@}||krMtdƒ‚t  |ƒ\} }
t
|   |
dS)NrMržrrŸr8u校验和不匹配)rbrc) Ú
startswithršÚendswithÚ FRAME_FOOTERÚ TYPE_CONTROLr r r9rarfrg) rŒr–Z
frame_typer¡Z payload_startZ payload_endrYZchecksum_receivedZ checksum_calcrbrcrrrr“+s
   zPythonLinkDecoder._parse_frameN)r‡rˆ)rŽrL)rr )rrœ)r–rLrr¢) rirjrkÚ__doc__ršr¥r¦rr˜rr’r“rrrrr…ùs
 
 
 
r…ÚlineúOptional[PythonAsciiMessage]c Csà|sdS| ¡}| d¡sdSd}t|ƒ}| d¡}|dkr*|}||d|d…}|d|…}d}|D]}|t|ƒN}q4|rWzt|dƒ}Wn
tyPYdSw||krWdS| d   ¡}|s`dS|d} |dd…}
t| |
d
S) Nú$ÚÚ*éÿÿÿÿr$ržrr†ú,)rorp)    Ústripr£r]r™r%r raÚsplitrn) r¨Z checksum_strZdata_endZstar_idxrYZcalcr&ZprovidedÚpartsrorprrrÚparse_ascii_message=s:
 
  ÿ
  r²ÚmsgúOptional[ControlStatus]cCs&|j ¡dkst|jƒdkrdSzft|jdƒ}t|jdƒ}t|jdƒ}tt|jdƒƒ}tt|jdƒƒ}|jd}t|jd   ƒ}t|jd
ƒ}t|jd ƒ} t|jd ƒ}
t|jd ƒ} t|jdƒ} t|jdƒ} t|jdƒ}Wn
ty€YdSwt||||||||| |
| | | |dS)NZCTRLérr$rMržr\réér[rré é é )rrrsrtrdrerurvrwrxryrDrzr{r|)roÚupperr]rprr rarq)r³rbrcZfreqZsteeringZthrottlerur=rwrxryÚheadingZtarget_headingÚtarget_eÚtarget_nrrrÚdecode_control_status\sH
 ÿòr¿úOptional[PoseStatus]c
Csä|j ¡dkst|jƒdkrdSzJt|jdƒ}t|jdƒ}t|jdƒ}t|jdƒ}t|jdƒ}t|jdƒ}t|jd   ƒ}t|jd
ƒ}t|jƒdkrWt|jdƒnd }   Wn
tydYdSwt||||||||| d  S) NZPOSEr[rr$rMržr\rr¶r·r)  rwrxryrDrErFr{r|rv)ror»r]rprrar})
r³rwrxryr¼ZpitchZrollr½r¾r=rrrÚdecode_pose_status‚s4$ ÿ÷rÁúOptional[StateStatus]cCs|j ¡dkst|jƒdkrdS|jd}z t|jdƒ}t|jdƒ}t|jƒdkr2t|jdƒnd}Wn
ty?YdSwt||||dS)NZSTATEržrr$rMr)rurr€rv)ror»r]rprrar~)r³ruZxteZ heading_errr=rrrÚdecode_state_statusžs 
$ ÿürÃúOptional[StackStatus]cCsv|j ¡dkst|jƒdkrdS|jd}ztt|jdƒƒ}tt|jdƒƒ}Wn
ty3YdSwt|||dS)NZSTACKržrr$rM)r‚rƒr„)ror»r]rpr rrar)r³ZtaskZstack_hwZ heap_freerrrÚdecode_stack_status°s
 ÿþrÅ)r   r
r )
r r rr rr rrrr)rrrr)r"r#rr#)r(r)r rrr*)r(r)r r rr*)r(r)rr*)r=rr>rr?rr@rrArrBrrCrrDrrErrFrrGrHrIrHrJrrKr rrL)rQ)
r=rrRrHrSrHrTrHrrL)rrrr)rYrLrrZ)r¨r#rr©)r³rnrr´)r³rnrrÀ)r³rnrrÂ)r³rnrrÄ)*r§Ú
__future__rr.r_Z dataclassesrrrÚtypingrrrrZ IM23A_NAV_LENZ IM23A_IMU_LENrNrUr:r!r'r1r3r5r7r<rPrVrOrfrgrnrqr}r~rr…r²r¿rÁrÃrÅrrrrÚ<module>sV   2
 
 
 
 
 
 
 
, ü
 
 
 
D
 
&