yincheng.zhong
2025-11-23 212ccb49d3e7c7fa138c5f9d335d0b8c5a08d2a3
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
o
À #i¿+ã @sŠdZddlmZddlZddlZddlmZddlmZmZddl m
Z
m Z m Z eddd   ej d
Zdtdd„Zdudd„Zdvdwdd„Zdxdd„Zdddddddd d!d"d#d$œ dyd;d<„ZdzdAdB„Zd{d|dJdK„Zd}dOdP„Zd~dSdT„ZeGdUdV„dVƒƒZeGdWdX„dXƒƒZeGdYdZ„dZƒƒZeGd[d\„d\ƒƒZeGd]d^„d^ƒƒZeGd_d`„d`ƒƒZGdadb„dbƒZddedf„Zd€didj„Z ddldm„Z!d‚dodp„Z"dƒdrds„Z#dS)„u€
与 STM32H7 äº¤äº’的协议封装:
- æž„造 $GPRMI / $GPIMU å¥å­
- è§£æž PythonLink æŽ§åˆ¶å¸§
- è§£æž ASCII çŠ¶æ€æŠ¥æ–‡
é)Ú 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$GPFMI,ú,Ú*ú
Úascii)rr(rr rÚjoinr.Úencode)rr>r@rArBrCrDrErFrGr3r4r5r6r7r8r9r:r;r<r=Úutc_strrrÚfieldsÚbodyÚchecksumÚsentencerrrÚbuild_gprmi_sentence1s>  
 
 
é
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_sentencems 
 
 
 
 
 
ø 
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ÚturnÚ steering_pwmÚ throttle_pwmrrrÚ_decode_payloads  rxc@seZdZUded<ded<dS)ÚPythonLinkFramer?rtruN©Ú__name__Ú
__module__Ú __qualname__Ú__annotations__rrrrryó
 ryc@seZdZUded<ded<dS)ÚPythonAsciiMessager Útagz list[str]rRNrzrrrrr€£rr€c@sFeZdZUded<ded<ded<ded<ded<ded    <ded
<d S) Ú ControlStatusr?Ú forward_mpsÚ  turn_rateÚfreq_hzrrvrwr ÚstageÚ timestamp_msNrzrrrrr‚©s
 r‚c@sVeZdZUded<ded<ded<ded<ded<ded<ded<ded   <ded
<d S) Ú
PoseStatusr?ÚeastÚnorthÚuprErFrGÚ target_eastÚ target_northr‡Nrzrrrrrˆ´s
 rˆc@s.eZdZUded<ded<ded<ded<dS)Ú StateStatusr r†r?Úcross_track_errorÚheading_error_degr‡NrzrrrrrŽÁs
 
 rŽc@s&eZdZUded<ded<ded<dS)Ú StackStatusr Ú task_namerÚstack_high_waterÚheap_free_bytesNrzrrrrr‘É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ƒ|_||_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°Úsumrsrxry) rœr§Ú
frame_typer±Z payload_startZ payload_endrkZchecksum_receivedZ checksum_calcrtrurrrr¤s
   zPythonLinkDecoder._parse_frameN)r—r˜)ržrH)rr)rr­)r§rHrr²) r{r|r}Ú__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ú$ÚrLéÿÿÿÿr rrr–rK)rrR)    Ústripr³rnrªr+rrsr%r€) rºZ checksum_strZdata_endZstar_idxrkZcalcr-ZprovidedÚpartsrrRrrrÚparse_ascii_messages:
 
  ÿ
  rÁÚmsgúOptional[ControlStatus]c CsÈ|j ¡dkst|jƒdkrdSz>t|jdƒ}t|jdƒ}t|jdƒ}tt|jdƒƒ}tt|jdƒƒ}|jd}t|jƒdkrKt|jdƒnd }Wn
tyXYdSwt|||||||d
S) NZCTRLr
rr   rIrr2r®ç)rƒr„r…rvrwr†r‡)rÚupperrnrRr?rrsr‚)rÂrtruÚfreqZsteeringZthrottler†rrrrÚdecode_control_status3s,
$ ÿù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) NZPOSErmrr  rIrr2r®r
érÄ)  r‰rŠr‹rErFrGrŒrr‡)rrÅrnrRr?rsrˆ)
rÂr‰rŠr‹ÚheadingZpitchZrollZtarget_eZtarget_nrrrrÚdecode_pose_statusKs4$ ÿ÷rËúOptional[StateStatus]cCs|j ¡dkst|jƒdkrdS|jd}z t|jdƒ}t|jdƒ}t|jƒdkr2t|jdƒnd}Wn
ty?YdSwt||||dS)NZSTATErrr   rIrÄ)r†rrr‡)rrÅrnrRr?rsrŽ)rÂr†ZxteZ heading_errrrrrÚdecode_state_statusgs 
$ ÿürÍúOptional[StackStatus]cCsv|j ¡dkst|jƒdkrdS|jd}ztt|jdƒƒ}tt|jdƒƒ}Wn
ty3YdSwt|||dS)NZSTACKrrr rI)r’r“r”)rrÅrnrRrr?rsr‘)rÂÚtaskZstack_hwZ heap_freerrrÚdecode_stack_statusys
 ÿþ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ºr rr»)rÂr€rrÃ)rÂr€rrÈ)rÂr€rrÌ)rÂr€rrÎ)$r¹Ú
__future__rrqroÚ dataclassesrrrÚtypingrrrrrrrr(r.rVr[rdrcrxryr€r‚rˆrŽr‘r•rÁrÇrËrÍrÐrrrrÚ<module>s\  
 
   
ê
< 
 
 
 
D