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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
o
:iÄ¡ã@sÚdZddlmZddlZddlZddlZddlZddlZddlZddl m
Z
ddl m Z m Z mZmZz ddlmZmZmZWn eyIdZYnwzddlmZWn ey]dZYnwdd   lmZmZmZmZmZdd
lmZmZm Z d Z!d Z"d Z#dZ$dZ%dZ&dZ'e
e(ƒ )¡j*Z+e+dZ,e+dZ-e- .d¡Z/e+dZ0d:dd„Z1d;dd„Z2d<d=d$d%„Z3d>d'd(„Z4d?d*d+„Z5Gd,d-„d-ƒZ6Gd.d/„d/ej7ƒZ8Gd0d1„d1ƒZ9Gd2d3„d3ej:ƒZ;d@d5d6„Z<d7d8„Z=e>d9krëe ?e=ƒ¡dSdS)Au]
HITL ä»¿çœŸå™¨ GUI:左侧地图显示路径/车辆,右侧显示状态与控制信息。
é)Ú annotationsN)ÚPath)ÚDictÚListÚOptionalÚTuple)ÚQtCoreÚQtGuiÚ  QtWidgets)Ú
list_portsé)Ú ControlStatusÚ
PoseStatusÚ StackStatusÚ StateStatusÚ nmea_checksum)Ú
HitlConfigÚ HitlSimulatorÚ  RunLoggerZCOM11ZCOM17zX$GNGGA,080112.000,3949.8105069,N,11616.6876082,E,4,44,0.42,48.502,M,-6.684,M,1.0,0409*73)çrrriÂiz
runlog.txtzpath_text_input.txtz.czdashboard_state.jsonÚ  path_filerÚreturnúList[Tuple[float, float]]c  Cs"| ¡s
tt|ƒƒ‚|jdd ¡}|sgSg}|j ¡dks$| d¡rZz)t    |¡}|D]}t
|t t fƒrJt |ƒdkrJ| t|dƒt|dƒf¡q,|WStjyYgYSw| d¡D]/}| ¡}|shq_| d ¡}t |ƒdkrtq_z| t|dƒt|dƒf¡Wq_tyŽYq_w|S)
Núutf-8©Úencodingz.jsonú[érr ú;ú,)ÚexistsÚFileNotFoundErrorÚstrÚ  read_textÚstripÚsuffixÚlowerÚ
startswithÚjsonÚloadsÚ
isinstanceÚlistÚtupleÚlenÚappendÚfloatZJSONDecodeErrorÚsplitÚ
ValueError)rÚtextÚpointsÚdataÚptÚtokenÚparts©r8ú/E:\GIT\Lawnmower_STM32H7\python\hitl\run_sim.pyÚload_path_points+s< 
€ÿ
 " ÿr:r2r"c   CsŽ| dd¡ d¡}g}|D]7}| ¡}|sq | d¡}t|ƒdkr"q zt|d ¡ƒ}t|d ¡ƒ}| ||f¡Wq tyDYq w|S)NÚ
ú rrrrr )Úreplacer0r$r-r/r.r1)r2Útokensr3r6r7ÚxÚyr8r8r9Úparse_path_textIs"
  ÿrArr3ÚdecimalsÚintc    Cs„|sdSd|›d}dg}t|ƒD]&\}\}}|t|ƒdkr!dnd}| d| |¡›d | |¡›d
|›¡q| d ¡d  |¡S) Nz%const float g_motion_path_xy[] = {};
z{:.zf}z"const float g_motion_path_xy[] = {r rÚz    zf, Úfz};r;)Ú enumerater-r.ÚformatÚjoin)r3rBZfmtÚlinesÚidxr?r@Zcommar8r8r9Úformat_path_for_mcu\s *
 
rKÚggac
Cs¶|pd ¡}|s
dS| d¡d}dd„| d¡Dƒ}t|ƒdkr#dS|d}|d   }|d
}|d }t|ƒd krA|d rA|d nd}|›d|›d|›d|›}   |rY|   d|›7} |   S) NrDÚ*rcSóg|]}| ¡‘qSr8©r$©Ú.0Úpr8r8r9Ú
<listcomp>móz'gga_to_short_origin.<locals>.<listcomp>réréééé   )r$r0r-)
rLr2Úbodyr7ZlatÚlat_dirZlonÚlon_dirÚaltZshortr8r8r9Úgga_to_short_originhs    r^Útemplatec CsLdd„| dd¡ d¡Dƒ}t|ƒdkrtdƒ‚|d}|d   ¡}|d
}|d  ¡}t|ƒd kr6|dnd}|d vs@|dvrDtdƒ‚|pGt}d} | d¡rW|dd…}d}   | d¡d}
|
 d¡} t| ƒdkrt|  d¡t| ƒdksi| dpyd| d<|| d
<|| d <|| d<|| d <|dur”|| d<d | ¡}
t   |
ƒ} |
›d| ›|   ›S)NcSsg|]
}| ¡r| ¡‘qSr8rO)rQÚtr8r8r9rS|sz/build_gga_from_short_origin.<locals>.<listcomp>r;r<rrWu)原点格式应为 'lat,N,lon,E[,alt]'。rr rrVrX)ÚNÚS)ÚEÚWu方向必须是 N/S/E/W。rDz
éþÿÿÿrMé z$GNGGArY)
r=r0r-r1ÚupperÚDEFAULT_ORIGIN_GGAÚendswithr.rHr) r2r_r>Zlat_dmr[Zlon_dmr\r]ÚbaseÚnewlinerZZfieldsZchecksumr8r8r9Úbuild_gga_from_short_origin{s<   
 
 
 ÿ
rlc@s.eZdZdd„Zd dd„Zdd„Zd d
„Zd S) Ú HitlGuiBridgecCstjdd|_t ¡|_dS)NéÈ)Úmaxsize)ÚqueueZQueueÚ threadingZLockÚ_lock©Úselfr8r8r9Ú__init__szHitlGuiBridge.__init__Úkindr"cCs:|j| ||f¡WdƒdS1swYdS©N)rrÚ_enqueue)rtrvr4r8r8r9Úpublish¡s"ÿzHitlGuiBridge.publishc Cs„|j5|j ¡s(z|j ¡Wn
tjyYnw|j ¡r   WdƒdSWdƒdSWdƒdS1s;wYdSrw)rrrpZemptyÚ
get_nowaitÚEmptyrsr8r8r9Úreset¥s
ÿ ýÿÿ"ûzHitlGuiBridge.resetc Csvz |j |¡WdStjy:z|j ¡Wn
tjy"Ynwz
|j |¡WYdStjy9YYdSwwrw)rpZ
put_nowaitZFullrzr{)rtÚitemr8r8r9rx­sÿÿùzHitlGuiBridge._enqueueN)rvr")Ú__name__Ú
__module__Ú __qualname__ruryr|rxr8r8r8r9rmœs
 
 rmcsheZdZe ee¡Z    ‡fdd„Zddd„Zd‡fdd    „ Z d‡fd
d „ Z
ddd„Z d‡fdd„ Z ‡Z S)ÚZoomableGraphicsViewcsztƒj|i|¤Ž| tjjd¡| tjj   ¡| 
tjj   ¡|  tjj ¡|  tjj¡d|_d|_t ¡|_d|_dS)NTgffffffò?F)ÚsuperruZ setRenderHintr    ZQPainterZ AntialiasingZsetTransformationAnchorr
Ú QGraphicsViewZAnchorUnderMouseZsetResizeAnchorZ setDragModeZNoDragÚ setCursorrÚQtÚOpenHandCursorÚ _zoom_factorÚ_panningZQPointÚ _pan_last_posÚ on_user_pan)rtÚargsÚkwargs©Ú  __class__r8r9ru¿s
 
zZoomableGraphicsView.__init__ÚeventúQtGui.QWheelEventcCs4| ¡ ¡}|dkr |jnd|j}| ||¡dS)Nrçð?)Z
angleDeltar@r‡Zscale)rtrÚdeltaZ scale_factorr8r8r9Ú
wheelEventËs zZoomableGraphicsView.wheelEventúQtGui.QMouseEventcsJ| ¡tjjkrd|_| ¡|_| tjj¡|     ¡dSt
ƒ  |¡dS)NT) Úbuttonrr…Ú
LeftButtonrˆÚposr‰r„ZClosedHandCursorÚacceptr‚ÚmousePressEvent©rtrrr8r9r™Ðs
z$ZoomableGraphicsView.mousePressEventcsŠ|jr2| | ¡¡}| |j¡}||}| ¡|_| | ¡ | ¡ ¡|jr,| ¡| ¡dS|j    j
|  | ¡¡Žt ƒ  |¡dSrw)rˆÚ
mapToScener—r‰Ú   translater?r@rŠr˜ÚsceneMouseMovedZemitÚ _scene_coordsr‚ÚmouseMoveEvent)rtrÚ   scene_posZlast_scene_posr’rr8r9rŸÙs 
z#ZoomableGraphicsView.mouseMoveEventÚview_posú QtCore.QPointrúTuple[float, float]cCs| |¡}| ¡| ¡fSrw)r›r?r@)rtr¡r r8r8r9ržçs
z"ZoomableGraphicsView._scene_coordscsF| ¡tjjkr|jrd|_| tjj¡| ¡dStƒ     |¡dS)NF)
r•rr…r–rˆr„r†r˜r‚ÚmouseReleaseEventršrr8r9r¤ës z&ZoomableGraphicsView.mouseReleaseEvent)rr)rr”)r¡r¢rr£)r~rr€rZ
pyqtSignalr/rrur“r™rŸržr¤Ú __classcell__r8r8rr9r»s  
    
rc@sNeZdZddd„Zdd„Zdd„Zdd d „Zddd„Zddd„Zd dd„Z dS)!ÚDashboardStateStoreÚpathrcCst|ƒ|_i|_| ¡dSrw)rr§r4Ú_load)rtr§r8r8r9ruõs
 zDashboardStateStore.__init__cCsL|j ¡s
i|_dSzt |jjdd¡|_WdSty%i|_YdSw)Nrr)r§r r4r(r)r#Ú    Exceptionrsr8r8r9r¨ús
  ÿzDashboardStateStore._loadcCs:z|jjtj|jdddddWdStyYdSw)NFr)Z ensure_asciiZindentrr)r§Ú
write_textr(Údumpsr4r©rsr8r8r9Úsaves
$ ÿzDashboardStateStore.saverú+Optional[Tuple[float, float, float, float]]c  CsT|j d¡}t|tƒr(t|ƒdkr(z
tdd„|DƒƒWSttfy'YdSwdS)NÚposerWcss|]}t|ƒVqdSrw)r/)rQÚvr8r8r9Ú  <genexpr> s€z/DashboardStateStore.get_pose.<locals>.<genexpr>)r4Úgetr*r+r-r,Ú    TypeErrorr1©rtr®r8r8r9Úget_pose s ÿzDashboardStateStore.get_poseÚeastr/ÚnorthÚupÚheadingcCs||||g|jd<| ¡dS©Nr®©r4r¬©rtrµr¶r·r¸r8r8r9Úset_poses zDashboardStateStore.set_poseú Optional[str]cCs|j d¡}t|tƒr |SdS©NÚorigin)r4r±r*r")rtr¿r8r8r9Ú
get_origins 
zDashboardStateStore.get_originÚ
origin_strr"cCs||jd<| ¡dSr¾rº)rtrÁr8r8r9Ú
set_origins
 zDashboardStateStore.set_originN)r§r)rr­)rµr/r¶r/r·r/r¸r/)rr½)rÁr")
r~rr€rur¨r¬r´r¼rÀrÂr8r8r8r9r¦ôs
    
 
    
r¦cseZdZdJ‡fd
d „ ZdKd d „Zdd„Zdd„ZdLdd„Zdd„ZdMdd„Z dNdKdd„Z
dOd!d"„Z d#d$„Z dPd&d'„Z dQd*d+„Zd,d-„Zd.d/„Zd0d1„Zd2d3„Zd4d5„Zd6d7„Z‡fd8d9„Zd:d;„Zd<d=„Zd>d?„ZdQd@dA„ZdBdC„ZdDdE„ZdFdG„ZdHdI„Z‡ZS)RÚ HitlDashboardÚ  simulatorrÚbridgermÚ path_pointsrÚ initial_uart2r½Ú initial_uart5csätƒ ¡||_||_t|pgƒ|_g|_d|_d|_d|_   i|_
d|_ |  d¡|  dd¡d|_g|_ttƒ|_| ||¡| ¡|j ¡ ¡sT|jrT| |j¡| ¡| ¡t |¡|_|jj |j ¡|j !d¡dS)NTuHITL ä»¿çœŸçŠ¶æ€é¢æ¿iiÐFéP)"r‚rurÄrÅr+rÆÚ trail_pointsÚcontrol_statusÚ pose_statusÚ state_statusÚ stack_statusÚ _auto_followZsetWindowTitleZresizeÚ _serial_openÚ _last_portsr¦Ú
STATE_FILEÚ state_storeÚ    _build_uiÚ_load_saved_path_textÚ   path_textÚ toPlainTextr$Ú_update_path_text_from_pointsÚ_load_saved_poseÚ _init_scenerZQTimerZtimerÚtimeoutÚconnectÚ _drain_queueÚstart)rtrÄrÅrÆrÇrÈrr8r9ru"s0
 
 
   zHitlDashboard.__init__c Csxt ¡}t |¡}| |¡t |¡|_t ¡}t |¡}| dddd¡| d¡t  |jƒ|_
|j |j
_ |j
j  |j¡|j|j
ddt ¡}t |¡}| dddd¡t d¡|_|j d¡|jj |j¡| |j¡t d¡|_|jj |j¡| |j¡| d¡t d¡|_|j d ¡| |j¡| |¡|j|d
dtdu|_t ¡} t |   ¡}
|
 d ddd¡|j| d dt  d ¡} t !| ¡} t "¡|_#t "¡|_$t d¡|_%t d¡|_&t d¡|_'|j' d¡|  t d¡dd¡|  |j#dd¡|  t d¡dd¡|  |j$dd¡|  |j%dd d d¡|  |j&d ddd
¡|  |j'd
ddd
¡|
 | ¡tdurN|j% (d¡|j# )d¡|j$ )d¡t  d¡} t | ¡}t *¡|_+|j+ ,d¡|j+ -t.j/j0¡t ¡}t d¡|_1t d¡|_2| |j1¡| |j2¡| |j+¡| 3|¡|
 | ¡t  d¡}t !|¡}t4|j5j6j7ƒ}t 8|¡|_9|j9 ,d¡t d¡|_:t d¡|_;| t d¡dddd ¡| |j9dd dd ¡| |j:dd¡| |j;dd¡gd¢}g|_<t=|ƒD]N\}}t >¡}|d
kr
| ?d d!¡| @d
¡n | ?d"d#¡| @d ¡| t |¡d|d |d d ¡| |d|d |d d d¡|j< A|¡qñt d$¡|_B| |jBd
ddd¡|
 |¡t  d%¡}t |¡}t d&¡|_C|jC DtEjFjGtEjFjHB¡|jC d'¡t I¡}| Jd¡| K|jC¡| Ld(¡| |¡|
j|ddt  d)¡}t |¡}t Mdd
¡|_N|jN Ogd*¢¡|jN P¡ Qd¡| |jN¡|
 |¡t  d+¡}t |¡}t *¡|_R|jR Sd¡| |jR¡|
j|dd|j Tt. U¡t. Vt. Wd,¡d¡¡|_X|j Tt. U¡t. Vt. Wd-¡d¡¡|_Yd.|_Z|j [|jZ |jZ |jZd |jZd t. Vt. Wd/¡d¡t. \t. Wd0¡¡¡|_]t. Vt. Wd1¡d¡}| ^tEjFj_¡|j Tt. U¡|t. \t. Wd1¡¡¡|_`d2|_a|j [|ja |ja |jad |jad t. Vt. Wd3¡¡t. \t. Wd3¡¡¡|_b|j1j |jc¡|j2j |jd¡|j:j |je¡|j;j |jf¡|jBj |jg¡|j%j |jh¡|j&j |ji¡| h||¡| jd¡| k¡dS)4NrrWr )Zstretchu自动跟随车辆Tu 清除轨迹zE: 0.00  N: 0.00zQcolor:#222; background:rgba(255,255,255,190); padding:2px 6px; border-radius:4px;rVéru 串口设置u刷新õ 打开串口õ状态: æœªè¿žæŽ¥ú color: gray;zUART2:zUART5:Fu 路径轨迹u)示例:23.36,-42.93;29.26,-52.99; ... ;u加载到地图u导出 MCU æ ¼å¼u 原点/起点z3949.9120,N,11616.8544,E[,alt]u 更新原点u复制宏定义u坐标 (lat,N,lon,E):rX)zE (m)zN (m)zU (m)z Heading (deg)g@Àg@@g€vÀg€v@u 重置位置u 车辆状态õ等待数据...z6font-family: Consolas, 'Courier New'; font-size: 14px;éôu 堆栈监测)u任务u堆栈余量(word)u剩余堆(byte)u 串口日志ZgrayZblueçÐ?z#d11d29z#ff4b5cz#ff8c00g{®Gáz´?Zgreen)lr
ZQWidgetZ QHBoxLayoutZsetCentralWidgetZQGraphicsSceneÚsceneZ QVBoxLayoutZsetContentsMarginsZ
setSpacingrÚviewÚ_handle_user_panrŠrrÜÚ_update_mouse_posZ  addWidgetZ  QCheckBoxÚfollow_checkboxÚ
setCheckedZtoggledÚ_on_follow_toggledZ QPushButtonZclear_trail_btnZclickedÚ _clear_trailZ
addStretchZQLabelÚmouse_pos_labelÚ setStyleSheetr Ú_port_refresh_supportedZ   QGroupBoxZ QGridLayoutZ QComboBoxÚ port2_comboÚ port5_comboÚport_refresh_btnÚserial_toggle_btnÚserial_status_labelÚ
setEnabledZ setEditableZQPlainTextEditrÖZsetPlaceholderTextZsetWordWrapModer  Z QTextOptionZNoWrapZ path_load_btnZpath_export_btnZ   addLayoutr^rÄÚconfigÚ
origin_ggaZ QLineEditÚ origin_textÚ
origin_btnZcopy_origin_btnÚpos_spinrFZQDoubleSpinBoxZsetRangeZ setDecimalsr.Úreset_pose_btnÚ
info_labelZ setAlignmentrr…ZAlignTopZ   AlignLeftZ QScrollAreaZsetWidgetResizableZ setWidgetZsetMinimumHeightZ QTableWidgetÚ stack_tableZsetHorizontalHeaderLabelsZhorizontalHeaderZsetStretchLastSectionÚlog_viewÚ setReadOnlyZaddPathÚ QPainterPathZQPenZQColorÚ path_itemÚ
trail_itemÚ
robot_sizeZ
addEllipseZQBrushÚ
robot_itemZ setJoinStyleZ   RoundJoinÚ heading_itemÚ target_radiusÚ target_itemÚ_load_path_from_textÚ_export_path_to_mcuÚ_update_originÚ_copy_origin_macroÚ_reset_positionÚ_refresh_serial_portsÚ_toggle_serialÚ_set_controls_enabledÚ_update_serial_ui)rtrÇrÈZcentralZlayoutZ
left_panelZ left_layoutZ
bottom_barZ bottom_layoutZ right_panelZ right_layoutZ serial_groupZ serial_layoutZ
path_groupZ path_layoutZ
button_rowZ origin_groupZgridZdefault_origin_shortZlabelsrJZlabelZspinZ status_groupZ status_layoutZ info_scrollZ stack_groupZ stack_layoutZ    log_groupZ
log_layoutZ arrow_penr8r8r9rÔFs2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$" 
 
 
 
 
 
 
 
 
 
 
 
  ""úýú   
 zHitlDashboard._build_uic
Cs‚|j ¡ ¡}|stj |dd¡dSdd„| d¡Dƒ}t|ƒdkr-tj |dd¡dSzu|d}tt |ƒd   ƒ}t |ƒd   }||d
}|d  
¡d krQ| }|d }tt   |ƒd   ƒ}t |ƒd   } || d
}
|d 
¡dkrt|
}
d} t|ƒdkr€|d} d|d›d|
d›d| ›d} tj   ¡} |   | ¡tj |dd¡WdStyÀ}ztj |dd|›¡WYd}~dSd}~ww)Nu复制u原点输入框为空cSrNr8rOrPr8r8r9rSrTz4HitlDashboard._copy_origin_macro.<locals>.<listcomp>rrWu-原点格式错误,需至少包含经纬度rédgN@r rbrrVrdz0.0rXz*#define MC_CFG_ORIGIN_LAT_DEG            (z.6fz,)
#define MC_CFG_ORIGIN_LON_DEG            (z,)
#define MC_CFG_ORIGIN_ALT_M              (ú)u!已复制宏定义到剪贴板!u数值解析错误: )rùr2r$r
Ú QMessageBoxÚwarningr0r-rCr/rgÚ QApplicationÚ   clipboardÚsetTextÚ informationr1)rtr2r7Zlat_rawZ lat_deg_intZlat_minZlat_ddZlon_rawZ lon_deg_intZlon_minZlon_ddr]ZmacrorÚer8r8r9r sJ      
ÿþÿ
 
$€ÿz HitlDashboard._copy_origin_macrocCs8|jr|j d¡|j d¡|j d¡d|_dSdS)NTF)rÏrêÚ blockSignalsrërsr8r8r9rè1s    
üzHitlDashboard._handle_user_panÚcheckedÚboolcCs4||_|r|jr|j |jj|jj ¡dSdSdSrw)rÏrÌrçÚcenterOnrµr¶)rtrr8r8r9rì8s
ÿz HitlDashboard._on_follow_toggledcCsg|_| ¡dS)u清除地图上的轨迹点N)rÊZ _update_scenersr8r8r9rí=s zHitlDashboard._clear_trailrµr/Úscene_ycCs&| }|j d|d›d|d›¡dS)NzE: z .2fú  N: )rîr)rtrµrr¶r8r8r9réCs zHitlDashboard._update_mouse_posNcsŠg‰trz dd„t ¡Dƒ‰Wn tyg‰Ynw|p#|jjjp#d}|p,|jjjp,d}d
‡fdd „ }||j|ƒ||j|ƒˆ|_   dS) NcSsg|]}|j‘qSr8)ZdevicerPr8r8r9rSKsz7HitlDashboard._refresh_serial_ports.<locals>.<listcomp>rDÚcomboúQtWidgets.QComboBoxÚsavedr"cst| ¡}| d¡| ¡ˆr| ˆ¡|r|ˆvr| |¡|p"|}|r3| |¡}|dkr3| |¡| d¡dS)NTrF)Ú currentTextrÚclearZaddItemsZaddItemZfindTextZsetCurrentIndex)r!r#ZcurrentÚtargetrJ©Zportsr8r9Ú_fillQs
 
 
 
 
z2HitlDashboard._refresh_serial_ports.<locals>._fill)r!r"r#r")
r Zcomportsr©rÄr÷Ú
uart2_portÚ
uart5_portrñròrÑ)rtrÇrÈZ saved_uart2Z saved_uart5r(r8r'r9rGs ÿ  
z#HitlDashboard._refresh_serial_portsÚenabledcCs(|j |¡|j d¡|j d¡dS)NFT)rürörùrrú)rtr+r8r8r9rds  z#HitlDashboard._set_controls_enabledcCsZt ¡r)ztjdd}Wn tyd}Ynw|j |¡t|ƒ}|r+||_dSdSdS)NrrrD)ÚPATH_TEXT_FILEr r#r©rÖÚ setPlainTextrArÆ©rtr2r3r8r8r9rÕis ÿ 
øz#HitlDashboard._load_saved_path_textr3cCs:|s    |j ¡dSd dd„|Dƒ¡d}|j |¡dS)Nrcss&|]\}}|d›d|d›VqdS)ú.2frNr8)rQr?r@r8r8r9r°xs€$z>HitlDashboard._update_path_text_from_points.<locals>.<genexpr>)rÖr%rHr-)rtr3r2r8r8r9rØts
 
z+HitlDashboard._update_path_text_from_pointsr2r"c
CsVz tj| ¡ddWdSty*}ztj |dd|›¡WYd}~dSd}~ww)Nrrõ路径u保存路径文本失败: )r,rªr$r©r
rr)rtr2Úexcr8r8r9Ú_save_path_text{s $€ÿzHitlDashboard._save_path_textcCsf|j ¡}|r1|jd |d¡|jd |d¡|jd |d¡|jd |d¡dSdS)Nrr rrV)rÓr´rûÚsetValuer³r8r8r9rفs
üzHitlDashboard._load_saved_posecCsx|j ¡ ¡}t|ƒ}|stj |dd¡dS||_|j     ¡| 
|¡|  ¡|  ¡tj  |ddt|ƒ›d¡dS)Nr0u9未解析到有效的轨迹点,请检查输入格式。u
已加载 u ä¸ªè·¯å¾„点。)rÖr×r$rAr
rrrÆrÊr%r2rÚÚ _refresh_viewrr-r.r8r8r9r    ‰s
 
 z"HitlDashboard._load_path_from_textc
Cs´|j ¡ ¡}t|ƒ}|stj |dd¡dSt|ƒ}tj  ¡}| 
|¡z t j |ddWnt yK}ztj |dd|›¡WYd}~nd}~wwtj |ddtt ƒ¡dS)Nu导出u3没有可导出的路径点,请先加载路径。rru写入文件失败: u#已复制到剪贴板,并写入:
)rÖr×r$rAr
rrrKrrrÚPATH_EXPORT_FILErªr©rr")rtr2r3Z   formattedrr1r8r8r9r
–s
 
"€ÿz!HitlDashboard._export_path_to_mcucCsÊ|j |jrdnd¡|jr0|jjjpd}|jjjpd}|j d|›d|›d¡|j d¡n |j d ¡|j d
¡|j }|j  
|pI|j   ¡¡|j  
|pT|j   ¡¡|j rc|j 
|j ¡dSdS) Nu 关闭串口ràu未知u无u状态: å·²è¿žæŽ¥ (UART2=z, UART5=rz color: green;rárâ)rôrrÐrÄÚuart2ÚportÚlog_uartrõrïrñröZ
isEditableròrðró)rtr6Úuart5Z enable_portsr8r8r9r¥s  ÿzHitlDashboard._update_serial_uic
Csò|jr   | ¡dS|j ¡ ¡}|stj |dd¡dS|j ¡ ¡}|p&d}||j   j
_ ||j j
_ ||j j _||j   j_z|j    ¡Wn#tye}z|j  ¡tj |dd|›¡WYd}~dSd}~wwd|_|j ¡| d¡| ¡dS)Nu串口u请先选择 UART2 ç«¯å£ã€‚u打开串口失败: T)rÐÚ _close_serialrñr$r$r
rrròrÄr÷r)r*r6r7r8rÞr©ÚstopZcriticalrÅr|rr)rtr6Z
uart5_textr9r1r8r8r9rµs2
 
 
 
 
€ý
 
 zHitlDashboard._toggle_serialcCs€|j ¡|j ¡|j ¡d|_d|_d|_|j   ¡|j
 ¡|j   d¡|j  d¡d|_| d¡| ¡| ¡dS)NrãrF)rÄr;rÅr|rÊr%rËrÌrÍrÎrÿrýrrþÚ setRowCountrÐrrr4rsr8r8r9r:Îs
 
 
 
 
 
 zHitlDashboard._close_serialcs|jr| ¡tƒ |¡dSrw)rÐr:r‚Ú
closeEventršrr8r9r=ÞszHitlDashboard.closeEventc
CsÆ|j ¡ ¡}|stj |dd¡dS|jjjpt   }zt
||ƒ}Wnt y?}ztj |dd|›¡WYd}~dSd}~ww|j  |¡||jj_|j  t|ƒ¡|j |¡tj |dd¡dS)Nu原点u,请输入坐标,格式:lat,N,lon,E[,alt]u格式错误: u原点已更新。)rùr2r$r
rrrÄr÷rørhrlr1Z update_originrr^rÓrÂr)rtr2r_rLr1r8r8r9r ãs"€þ 
 zHitlDashboard._update_origincCsp|jd ¡}|jd ¡}|jd ¡}|jd ¡}|j ||||¡|j ||||¡tj |dd¡dS)Nrr rrVu位置u已重置仿真状态。) rûÚvaluerÄZ reset_staterÓr¼r
rrr»r8r8r9r ôszHitlDashboard._reset_positioncCs6|js|j dddd¡dSt ¡}d}g}g}|jD]"\}}| |¡| | ¡|r6| || ¡d}q| || ¡q|j  |¡t
|ƒ}t |ƒ}t
|ƒ}   t |ƒ}
||} |
|   } t d| dƒ} t d| dƒ}t   || | || dkrx| nd| d   | dkrƒ| nd|d   ¡}|j |¡|j |t jj¡dS)
NiÿÿÿräTFg$@gè?rr‘g@)rÆræZ setSceneRectr   rr.ÚmoveToÚlineTorÚsetPathÚminÚmaxrZQRectFrçZ    fitInViewr…ZKeepAspectRatio)rtr§ÚfirstZxsZysZpxÚpyZmin_xZmax_xZmin_yZmax_yÚwidthZheightZpad_xZpad_yZ
scene_rectr8r8r9rÚýs>
  ü zHitlDashboard._init_scenecCs*|j |¡|j ¡ |j ¡ ¡¡dSrw)rÿZappendPlainTextZverticalScrollBarr3Zmaximum)rtr2r8r8r9Ú _append_logs zHitlDashboard._append_logcCsÐd}    z
|jj ¡\}}Wn
tjyYnGw|dkr ||_n;|dkr?||_|j |j|j f¡t
|jƒdkr>|j  d¡n|dkrG||_ n|dkrR||j |j<n |d kr[| |¡d}q|rf| ¡dSdS)
NFTÚcontrolr®iÐrÚstateÚstackÚlog)rÅrprzr{rËrÌrÊr.rµr¶r-ÚpoprÍrÎÚ task_namerGr4)rtÚupdatedrvr4r8r8r9rÝ#s4ÿ €
î ÿzHitlDashboard._drain_queuecCsŽg}|jr?|j}|dd|jd›d|jd›d|jd›ddd|jd    ›d
|jd   ›d |jd ›d |jd ›d|jd ›dg
7}|j rn|j   }|ddd|j
d›dd|j d›dd|j ›d|j ›d|jd›dd|j›g7}|jrŒ|j}|dd|j›d|jd›dd|jd ›dg7}|jr¯|dd g7}|j ¡D]}| d!|j›d"|j›d#|j›d$¡qš|s´d%g}|j d& |¡¡| ¡| ¡dS)'Nu位置 (ENU, m):z  E: z+7.3fr z  U: rDu 姿态 (deg):z   Heading: z+7.2fz   Pitch  : z   Roll   : z   Target : (z+6.2fz, ru
控制量:z   Forward : z+6.3fz m/sz   Turn    : z rad/sz  PWM     : steer=z
 throttle=z   Freq    : z6.2fú Hzz   Stage   : u算法状态: z   XTE    : z mz degu 堆栈监测:z  z: stack=z  words heap=z Brãr;)rÌrµr¶r·Ú heading_degZ pitch_degZroll_degÚ target_eastÚ target_northrËÚ forward_mpsÚ   turn_rateZ steering_pwmZ throttle_pwmÚfreq_hzÚstagerÍZcross_track_errorZheading_error_degrÎÚvaluesr.rMÚstack_high_waterÚheap_free_bytesrýrrHÚ_update_scene_itemsÚ_refresh_stack_table)rtZ
info_linesr®ZctrlÚstr}r8r8r9r4;sZ      ö 
ù    
ü ÿ zHitlDashboard._refresh_viewc Cs~|j t|jƒ¡t|j ¡ƒD],\}}|j |dt |j   ¡¡|j |dt t
|j ƒ¡¡|j |dt t
|j ƒ¡¡qdS)Nrr r) rþr<r-rÎrFrWZsetItemr
ZQTableWidgetItemrMr"rXrY)rtZrowÚstatusr8r8r9r[js ýz"HitlDashboard._refresh_stack_tablec
Cs|jr/t ¡}d}|jdd…D]\}}| }|r"| ||¡d}q| ||¡q|j |¡|jrD|j}|j}|j    }|j
}|j   |||||d|d¡t  d|j¡}t  |¡}   t  |¡ }
|
} |   } d} d}d}d }d
}||   | ||
| f}|d |   ||d |
|f}|d |   ||d |
|f}|d | ||d | |f|d | ||d | |f|d | ||d | |f||d | ||d | |f|d | ||d | |f|d | ||d | |fg}t ¡}|j|d Ž|d d…D]}|j|ސq | ¡|j |¡|j}|j  |j||j ||d|d¡|jrF|j ||¡dSdSdS) NTi$úÿÿFrg€V@råg333333ë?gìQ¸…ë±?gÍÌÌÌÌÌÜ?gìQ¸…ëÑ?rr )rÊr rr?r@rrArÌrµr¶rrZsetRectÚmathZradiansrPZcosZsinZ closeSubpathrrrrQrRrÏrçr)rtÚtrailrDr?r@rr®ÚsizeZ heading_radZdir_xZdir_yZperp_xZperp_yÚoffsetZ shaft_lengthZshaft_half_widthZ head_lengthZhead_half_widthrÞZ  shaft_endZtipr3Z
arrow_pathr5Z target_sizer8r8r9rZqs  "
 
 
þþþþþþþþþê 
ü²Mz!HitlDashboard._update_scene_items)
rÄrrÅrmrÆrrÇr½rÈr½)rÇr½rÈr½)rr)rµr/rr/)NN)r+r)r3r)r2r")r~rr€rurÔr rèrìrírérrrÕrØr2rÙr   r
rrr:r=r r rÚrGrÝr4r[rZr¥r8r8rr9rÃ!s:
$;1
 
 
 
 
      
"/rÃúargparse.NamespacecCsÚtjdd}|jdtdd|jdtdd|jdtd   d|jd
ttd d d |jdttddd |jdttddd |jdttdd |jdt   t
dd |jdt t dd |jddd|jdddd |  ¡S)!NuHITL ä»¿çœŸå™¨ GUI)Z descriptionz--uart2uSTM32 UART2 ä¸²å£å·)ÚdefaultÚhelpz--uart5uSTM32 UART5 ä¸²å£å·z--originu
GGA åŽŸç‚¹z--eastru 初始 E (m))Útypercrdz--northr u 初始 N (m)z--upru 初始 U (m)z   --headingu初始航向 (deg)z
--gps-bauduUART2 æ³¢ç‰¹çއz
--log-bauduUART5 æ³¢ç‰¹çއz--pathu初始路径文件 (.json/.txt))rdz--no-guiZ
store_trueu"不启动 Qt GUI,仅打印数据)Úactionrd) ÚargparseZArgumentParserZ add_argumentÚDEFAULT_UART2_PORTÚDEFAULT_UART5_PORTrhr/Ú DEFAULT_ENUÚDEFAULT_HEADING_DEGrCÚDEFAULT_UART2_BAUDÚDEFAULT_UART5_BAUDÚ
parse_args)Zparserr8r8r9rnÎs rnc
sÚtƒ}ttƒ}| ¡}| ¡}|r|n|j}|r(|d|d|df}|d}n |j|j|jf}|j }t
|j |j ||||j |jd}ttƒ}t||d} tƒ‰‡fdd„‰‡fd d
„| _‡fd d
„| _‡fd d
„| _‡fd d
„| _‡fdd
„| _g}
|jr z tt|jƒƒ}
WntyŸ} z td| ›ƒWYd} ~ nd} ~ wwtdus¨|jrzbzE|  ¡tdƒ  z ˆj j!dd\} } Wn
t j"yÈYq²w| dkrÒt| ƒn| dkrîtd| j#›d| j$d›d| j%d›d| j&d›d   ƒq³t'yûtdƒYnwW|  (¡| )¡tdƒdS|  (¡| )¡tdƒwtj* +¡p"t *g¡}t,|   ˆ|
|j |j ƒ}|jr8|j- .|j¡| /¡z| 0¡W|j1rJ| 2¡|  (¡| )¡tdƒdS|j1r`| 2¡|  (¡| )¡tdƒw)Nrr rrV)r)r*røÚ initial_enuZinitial_heading_degZ gps_baudrateZ log_baudrate)Ú
run_loggercsˆ ||¡dSrw©ry)rvr4)rÅr8r9ryüszmain.<locals>.publishcó
ˆd|ƒS)NrHr8©r]rqr8r9Ú<lambda>ÿó
zmain.<locals>.<lambda>crrr¹r8rsrqr8r9rtrucrr)NrIr8rsrqr8r9rtrucrr)NrJr8rsrqr8r9rtrucrr)NrKr8)Úlinerqr8r9rtruuARN] è·¯å¾„加载失败: uF[INFO] HITL ä»¿çœŸå™¨å·²å¯åЍ (无 GUI æ¨¡å¼)。按 Ctrl+C é€€å‡ºã€‚Tr‘)rÛrKrHz [CTRL] stage=z F=z+.2fz m/s T=z  rad/s freq=r/rOu
[INFO] ç”¨æˆ·ä¸­æ–­ã€‚u[INFO] ä»¿çœŸå™¨å·²åœæ­¢ã€‚)3rnr¦rÒrÀr´r¿rµr¶r·r¸rr6r9Zgps_baudZlog_baudrÚ RUN_LOG_PATHrrmZon_control_statusZon_pose_statusZon_state_statusZon_stack_statusZon_logr§r:rr©Úprintr
Zno_guirÞrpr±r{rVrSrTrUÚKeyboardInterruptr;ÚcloserÚinstancerÃZ path_linerZshowZexec_rÐr:)r‹rÓZ saved_originZ
saved_poserøroZinitial_headingZcfgrpZsimrÆr1rvr4ZappZ  dashboardr8)rÅryr9ÚmainÞs®
ù
 €ÿÿ
 
ÿÿþÿø ÿý
 
 ü
r|Ú__main__)rrrr)r2r"rr)r)r3rrBrCrr")rLr"rr")r2r"r_r"rr")rrb)@Ú__doc__Z
__future__rrgr(r^rpÚsysrqZpathlibrÚtypingrrrrZPyQt5rr    r
r©Z serial.toolsr Z    protocolsr rrrrrÄrrrrhrirhrjrkrlrmÚ__file__ZresolveÚparentZBASE_DIRrwr,Z with_suffixr5rÒr:rArKr^rlrmrƒrr¦Z QMainWindowrÃrnr|r~Úexitr8r8r8r9Ú<module>sj   ÿ ÿ
 
 
 
 
!9-
2Vÿ