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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
o
Î% is(ã@sÊdZddlmZddlZddlZddlZddlZddlmZmZm   Z   ddl
m Z ddl Z ddl mZddlmZmZdd   lmZmZmZmZejGd
d „d ƒƒZGd d „d ƒZGdd„dƒZddd„ZdS)us
硬件在环 (HITL) ä»¿çœŸå™¨ï¼šç”Ÿæˆ $GPRMI/$GPIMU ä¼ æ„Ÿå™¨æ•°æ®ï¼Œå¹¶ä¸Ž STM32H7 é€šè¿‡ PythonLink é—­çŽ¯ã€‚
é)Ú annotationsN)ÚdatetimeÚ  timedeltaÚtimezone)ÚCallableé)Úgeo)ÚDifferentialDriveModelÚDifferentialDriveState)ÚPythonLinkDecoderÚPythonLinkFrameÚbuild_gpimu_sentenceÚbuild_gprmi_sentencec@sŠeZdZUdZded<ded<ded<dZded    <d
Zd ed <d Zded<dZded<dZ   d ed<dZ
d ed<dZ d ed<dZ d ed<dS)Ú
HitlConfigu&HITL ä»¿çœŸè¿è¡Œå¿…需的配置项。ÚstrÚ
uart2_portú
str | NoneÚ
uart5_portÚ
origin_gga)çrrztuple[float, float, float]Ú initial_enurÚfloatÚinitial_heading_degiÚintÚ gps_baudrateiÚ log_baudrategö(\Âõè?Ú track_widthgÍÌÌÌÌÌì?Úbaseline_distanceg@Úmax_linear_speedg€a@Úmax_angular_speed_degN) Ú__name__Ú
__module__Ú __qualname__Ú__doc__Ú__annotations__rrrrrrrr©r%r%ú1E:\GIT\Lawnmower_STM32H7\python\hitl\simulator.pyrs
       rc@sveZdZUdZded<ded<ded<ded <d
ed <dd d d„Zdd„Zdd„Zd!dd„Zd"d#dd„Z d$dd„Z
dS)%ÚSerialEndpointu线程安全的串口包装。rÚportrÚbaudraterÚtimeoutzserial.Serial | NoneÚ_serialúthreading.LockÚ_lockrcCs&||_||_||_d|_t ¡|_dS©N)r(r)r*r+Ú  threadingÚLockr-)Úselfr(r)r*r%r%r&Ú__init__4s
zSerialEndpoint.__init__cCsN|jsdS|jr|jjrdStj|j|j|jdd|_|j ¡|j ¡dS)Nr)r*Z write_timeout)   r(r+Zis_openÚserialZSerialr)r*Zreset_input_bufferZreset_output_buffer©r1r%r%r&Úopen;sü
zSerialEndpoint.opencCs*|jrz |j ¡Wd|_dSd|_wdSr.)r+Úcloser4r%r%r&r6Is
 üzSerialEndpoint.closeÚdataÚbytescCsF|r|jsdS|j|j |¡}WdƒdS1swYdSr.)r+r-Úwrite)r1r7Ú_r%r%r&r9Ps
 
"ÿzSerialEndpoint.writerÚsizeÚreturncCs0|jsdSz|j |¡WStjyYdSw©Nó)r+Úreadr3ÚSerialException)r1r;r%r%r&r?VsÿzSerialEndpoint.readcCs.|jsdSz|j ¡WStjyYdSwr=)r+Úreadliner3r@r4r%r%r&rA^s ÿzSerialEndpoint.readlineN)r)r(rr)rr*r)r7r8)r)r;rr<r8)r<r8) r r!r"r#r$r2r5r6r9r?rAr%r%r%r&r'+s
 
 r'c@seZdZUdZded<ded<ded<ded <d
ed <d ed <d ed<ded<ded<ded<ded<ded<ded<ded<ded<d@dd„Zd d!„Zd"d#„Zd$d%„Zd&d'„Z d(d)„Z
d*d+„Z d,d-„Z dAd0d1„Z dAd2d3„ZdBd5d6„ZdCd9d:„ZedDd=d>„ƒZd?S)EÚ HitlSimulatoru9电脑仿真环境与 STM32H7 æŽ§åˆ¶æ¿ä¹‹é—´çš„æ¡¥æ¢ã€‚rÚconfigz
geo.OriginÚoriginr Úmodelr,Ú _state_lockr
Ú _latest_staterÚ_target_linearÚ_target_angularrÚ  _sim_timer'Úuart2Úlog_uartr Ú_decoderzthreading.EventÚ_runningzlist[threading.Thread]Ú_threadsz%Callable[[float, float], None] | NoneÚ
on_controlzCallable[[str], None] | NoneÚon_logcCsÜ||_t |j¡|_t|j|jt  |j
¡d|_ |j j |j d|j d|j d|jdt ¡|_|j j ¡|_d|_d|_t|jƒ|_t|j|jdd|_t|j|jdd|_t |j!ƒ|_"t #¡|_$g|_%d|_&d|_'dS) N)rrÚmax_angular_speedrré)ÚeastÚnorthÚupÚ heading_degr©r*皙™™™™¹?)(rCrÚ parse_originrrDr   rrÚmathÚradiansrrEÚresetrrr/r0rFÚstateÚcopyrGrHrIÚ_initial_timestamp_from_ggarJr'rrrKrrrLr Ú_handle_control_framerMÚEventrNrOrPrQ)r1rCr%r%r&r2zs2
ýü
 
 
zHitlSimulator.__init__c  Csš|j ¡rdS|j ¡|j ¡|j ¡tj|jdddtj|j dddtj|j
dddtj|j dddtj|j dddg|_ |j D]}| ¡qDdS)Nz  hitl-physT)ÚtargetÚnameÚdaemonz
hitl-gprmiz
hitl-gpimuz hitl-ctrlzhitl-log)rNÚis_setrKr5rLÚsetr/ÚThreadÚ _loop_physicsÚ _loop_gprmiÚ _loop_gpimuÚ _loop_controlÚ    _loop_logrOÚstart©r1Útr%r%r&rn›s
 
 
 
û
 
ÿzHitlSimulator.startcCsR|j ¡sdS|j ¡|jD]}|jddq|j ¡|j ¡|j ¡dS)Ngð?rX)rNrfÚclearrOÚjoinrKr6rLror%r%r&Ústop«s
 
 
 
 
zHitlSimulator.stopcCs t ¡}|j ¡rNt ¡}t||dƒ}|}|j!|j |j|j  |¡ 
¡}||_ |j t |d7_ Wdƒn1s=wYt d¡|j ¡s dSdS)Ng-Cëâ6?)Úsecondsg{®Gázt?)ÚtimeÚ perf_counterrNrfÚmaxrFrEÚsteprHrIr_rGrJrÚsleep)r1ÚlastÚnowÚdtr^r%r%r&ri¸s
ý
øzHitlSimulator._loop_physicscCóLd}|j ¡r$t ¡}| ¡}|r|j |¡| ||¡|j ¡sdSdS)NrY)rNrfrurvÚ_build_gprmi_sentencerKr9Ú_sleep_remaining©r1ÚperiodrnÚsentencer%r%r&rjÄó
  ûzHitlSimulator._loop_gprmicCr})Nç{®Gáz„?)rNrfrurvÚ_build_gpimu_sentencerKr9rr€r%r%r&rkÍrƒzHitlSimulator._loop_gpimucCsD|j ¡r |j d¡}|r|j |¡nt d¡|j ¡sdSdS)Né€gü©ñÒMb`?)rNrfrKr?rMÚfeedrury)r1r7r%r%r&rlÖs
 
ûzHitlSimulator._loop_controlcCs†|jjs|j ¡rt d¡|j ¡s dS|j ¡rA|j ¡}|s't d¡q|jddd    ¡}|r:|j
r:| 
|¡|j ¡sdSdS)Ngà?r„zutf-8Úreplace)Úerrors) rCrrNrfruryrLrAÚdecodeÚstriprQ)r1ÚlineÚtextr%r%r&rmÞs
 
 
ÿ
 
 
 
 
ùzHitlSimulator._loop_logr<ú bytes | Nonec Csb| ¡\}}t |j|j|j|j¡\}}}t |j¡}t    |||||j
|j |j ||j |j|jjd S)N) Ú    timestampÚlat_degÚlon_degÚalt_mÚeast_velÚ   north_velÚup_velrWÚ pitch_degÚroll_degÚ
baseline_m)Ú   _snapshotrÚ
enu_to_llarTrUrVrDÚheading_math_to_navÚheadingrÚ east_velocityÚnorth_velocityÚ up_velocityr–r—rCr)r1r^rÚlatÚlonÚaltZ heading_navr%r%r&r~ïs   õz#HitlSimulator._build_gprmi_sentencecCs"| ¡\}}t||j|j|jdS)N)rÚaccel_gÚ
gyro_deg_sÚ temperature_c)r™r Ú body_accel_gr¤r¥)r1r^rr%r%r&r…s üz#HitlSimulator._build_gpimu_sentenceú'tuple[DifferentialDriveState, datetime]cCs:|j|j ¡|jfWdƒS1swYdSr.)rFrGr_rJr4r%r%r&r™ s$ÿzHitlSimulator._snapshotÚframer cCsT|j|j|_|j|_Wdƒn1swY|jr(| |j|j¡dSdSr.)rFÚforwardrHÚturnrIrP)r1r¨r%r%r&ras
þÿz#HitlSimulator._handle_control_framernrcCs.t ¡|}||}|dkrt |¡dSdS)Nr)rurvry)rnrÚelapsedÚ remainingr%r%r&rs
ÿzHitlSimulator._sleep_remainingN)rCr)r<rŽ)r<r§)r¨r )rnrrr)r r!r"r#r$r2rnrsrirjrkrlrmr~r…r™raÚ staticmethodrr%r%r%r&rBgs>
 
!       
 
 
 
rBÚggarr<rc  Csä|pd d¡}t|ƒdkrl|drl|d}zKt|dd…ƒ}t|dd…ƒ}t|dd…ƒ}d|vr=td | d¡dƒnd
}t tj¡ ¡}t|j |j
|j tjd }|j |||t|d ƒd WSt tfykYnwt tj¡S)NÚú,rrrSééÚ.z0.r)Útzinfoi@B)ÚhourÚminuteÚsecondÚ microsecond)ÚsplitÚlenrrrr{rÚutcÚdateÚyearÚmonthÚdayrˆÚ
ValueErrorÚ
IndexError) r®ÚpartsZtime_strÚhhÚmmÚssÚfracÚtodayÚbaser%r%r&r` s"ÿ r`)r®rr<r)r#Ú
__future__rÚ dataclassesr[r/rurrrÚtypingrr3r¯rÚdynamicsr   r
Ú    protocolsr r r rÚ  dataclassrr'rBr`r%r%r%r&Ú<module>s$   <: