yincheng.zhong
2025-11-22 820749d41d8bc0fdfeb1f10283a2ba3b426e60f2
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
o
Ì% iã @sþdZddlmZddlZddlZddlmZddlmZmZddl m
Z
m Z m Z eddd   ej d
ZdYdd„ZdZdd„Zd[d\dd„Zd]dd„Zdddddddd d!d"d#d$œ d^d;d<„Zd_dAdB„Zd`dadJdK„ZdbdOdP„ZdcdSdT„ZeGdUdV„dVƒƒZGdWdX„dXƒZdS)dud
与 STM32H7 äº¤äº’的协议封装:
- æž„造 $GPRMI / $GPIMU å¥å­
- è§£æž PythonLink æŽ§åˆ¶å¸§
é)Ú annotationsN)Ú    dataclass)ÚdatetimeÚtimezone)ÚCallableÚOptionalÚTuplei¼éé©ÚtzinfoÚdtrÚreturncCs$|jdur |jtjdS| tj¡S)Nr )r ÚreplacerÚutcÚ
astimezone)r ©rú1E:\GIT\Lawnmower_STM32H7\python\hitl\protocols.pyÚ _ensure_utcs
 rÚ timestampúTuple[int, float]cCs8t|ƒ}|t}| ¡}t|dƒ}||d}||fS)Ni€:    )rÚ   GPS_EPOCHÚ total_secondsÚint)rr ÚdeltarÚweekÚtowrrrÚgps_week_and_tows   réÚdecimalsrÚstrcCsDt|ƒ}| d¡}|jd}|d|›d› d¡d}|›d|›S)Nz%H%M%Sg€„.AÚ.Úfr   )rÚstrftimeÚ microsecondÚsplit)rrr ÚbaseÚfracZfrac_strrrrÚ format_hhmmss!s
 
 
r(Úsentence_without_starcCs*d}|dd…D]}|t|ƒN}q|d›S)Nrr  Ú02X)Úord)r)ÚcsÚchrrrÚ nmea_checksum)sr.gü©ñÒMb€?g{®Gáz”?gš™™™™™¹?çð?ééé) Úlat_stdÚlon_stdÚalt_stdÚvel_stdÚ heading_stdÚ   pitch_stdÚroll_stdÚ
baseline_mÚ sat_countÚambiguity_countÚqualityÚlat_degÚfloatÚlon_degÚalt_mÚeast_velÚ  north_velÚup_velÚ heading_degÚ pitch_degÚroll_degr3r4r5r6r7r8r9r:r;r<r=Úbytesc
Csæt|ƒ}t|dd}t|ƒ\}}|t|ƒ|d›|d›|d›|d›|
d›| d›| d›|d›|d›|d›| d›|d›|d›|   d›|d›|d›|d›|d›tt|ƒƒtt|ƒƒtt|ƒƒg}dd |¡}t|ƒ}|›d|›d}| d   ¡S)
Né©rz.3fz.9fz$GPRMI,ú,Ú*ú
Úascii)rr(rr rÚjoinr.Úencode)rr>r@rArBrCrDrErFrGr3r4r5r6r7r8r9r:r;r<r=Úutc_strrrÚfieldsÚbodyÚchecksumÚsentencerrrÚbuild_gprmi_sentence0s>  
 
 
é
rVÚaccel_gúTuple[float, float, float]Ú
gyro_deg_sÚ temperature_cc   CsŒt|ƒ}t|dd}||dd›|dd›|dd›|dd›|dd›|dd›|d›g}dd  |¡}t|ƒ}|›d
|›d }| d ¡S) NrrJrz+.4fr   rIz.2fz$GPIMU,rKrLrMrN)rr(rOr.rP)  rrWrYrZrQrRrSrTrUrrrÚbuild_gpimu_sentencels 
 
 
 
 
 
ø 
r[éÜéôçø?ÚvalueÚcenterÚspanÚ max_speedcCst|||ddƒ}||S)Ngð¿r/)Ú_clamp)r_r`rarbZratiorrrÚ_pwm_to_velocity†srdÚvalÚmin_valÚmax_valcCst|t||ƒƒS©N)ÚmaxÚmin)rerfrgrrrrc‹srcÚpayloadúTuple[float, float]cCstt|ƒdkrt d|¡\}}||fSt|ƒdkr1t d|¡\}}t|ƒ}t t|dd¡}||fStdt|ƒ›ƒ‚)Néz<ffr2z<HHg€V@)rbu ä¸æ”¯æŒçš„æŽ§åˆ¶è´Ÿè½½é•¿åº¦: )ÚlenÚstructÚunpackrdÚmathÚradiansÚ
ValueError)rkÚforwardÚturnZ steering_pwmZ throttle_pwmrrrÚ_decode_payloads  rvc@seZdZUded<ded<dS)ÚPythonLinkFramer?rtruN)Ú__name__Ú
__module__Ú __qualname__Ú__annotations__rrrrrwœs
 rwc@sNeZdZdZdZdZdZddd„Zdd d „Zddd„Z   ddd„Z
ddd„Z dS)ÚPythonLinkDecoderu>
    è§£æž PythonLink æŽ§åˆ¶å¸§ (0xAA 0x55 ... 0D 0A)。
    sªUs
éÚon_frameú!Callable[[PythonLinkFrame], None]cCstƒ|_||_dSrh)Ú  bytearrayÚ_bufferÚ _on_frame)Úselfr~rrrÚ__init__«s
zPythonLinkDecoder.__init__ÚdatarHcCsÌ|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ÚextendÚ _find_headerÚclearrnÚ_expected_frame_lengthrHÚ _parse_framer‚Ú    Exception)rƒr…ÚstartZ   frame_lenÚframeÚparsedrrrÚfeed¯s4 
 
 
€ þîzPythonLinkDecoder.feedrrcCst|jƒ}| |j¡}|Srh)rHrÚfindÚ FRAME_HEADER)rƒr…ÚidxrrrrˆÉs
 zPythonLinkDecoder._find_headerú Optional[int]cCs8t|jƒdkr dSt |jdd…d¡}d|ddS)NérÚlittlerI)rnr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)NrIrr•r–iÿÿu校验和不匹配)rtru) Ú
startswithr’ÚendswithÚ FRAME_FOOTERÚ TYPE_CONTROLrr—Úsumrsrvrw) rƒrŽÚ
frame_typer˜Z payload_startZ payload_endrkZchecksum_receivedZ checksum_calcrtrurrrr‹Ôs
   zPythonLinkDecoder._parse_frameN)r~r)r…rH)rr)rr”)rŽrHrr™) rxryrzÚ__doc__r’rœrr„rrˆrŠr‹rrrrr|¢s
 
 
 
r|)r rrr)rrrr)r)rrrrrr )r)r rr ),rrr>r?r@r?rAr?rBr?rCr?rDr?rEr?rFr?rGr?r3r?r4r?r5r?r6r?r7r?r8r?r9r?r:r?r;rr<rr=rrrH)
rrrWrXrYrXrZr?rrH)r\r]r^)
r_rr`rrarrbr?rr?)rer?rfr?rgr?rr?)rkrHrrl)r Ú
__future__rrqroÚ dataclassesrrrÚtypingrrrrrrrr(r.rVr[rdrcrvrwr|rrrrÚ<module>s>  
 
   
ê
<