@@ -100,30 +100,30 @@ def __init__(
100100 self .battery_progress_bar = common_widgets .ColorProgressBar (
101101 MIN_BATTERY_VOLTAGE - self .BATTERY_MIN_OFFSET , MAX_BATTERY_VOLTAGE
102102 )
103+
103104 # Battery Voltage Label
104105 self .battery_label = QLabel ()
105- self . battery_label . setText ( "NAN" )
106+
106107 # Label changes when voltage bar level changes
107108 self .battery_progress_bar .floatValueChanged .connect (
108109 lambda float_val : self .battery_label .setText ("%.2fV" % float_val )
109110 )
110111
111112 # Stop primitive received indicator
112113 self .stop_primitive_label = QLabel ()
113- self .stop_primitive_label .setText ("NA" )
114114 self .stats_layout .addWidget (self .stop_primitive_label )
115115
116116 # Primitive loss rate label
117117 self .primitive_loss_rate_label = common_widgets .ColorQLabel (
118118 label_text = "P%" ,
119- initial_value = "NA" ,
119+ initial_value = 0 ,
120120 max_val = MAX_ACCEPTABLE_PACKET_LOSS_PERCENT ,
121121 )
122122
123123 # Primitive round-trip time label and queue
124124 self .primitive_rtt_label = common_widgets .ColorQLabel (
125125 label_text = "RTT:" ,
126- initial_value = "NA" ,
126+ initial_value = 0 ,
127127 max_val = MAX_ACCEPTABLE_MILLISECOND_ROUND_TRIP_TIME ,
128128 min_val = MIN_ACCEPTABLE_MILLISECOND_ROUND_TRIP_TIME ,
129129 )
@@ -141,17 +141,21 @@ def __init__(
141141
142142 # Control mode dropdown
143143 self .control_mode_layout = QHBoxLayout ()
144- self .control_mode_menu = self .create_control_mode_menu (available_control_modes )
144+ self .control_mode_menu = self .__create_control_mode_menu (
145+ available_control_modes
146+ )
145147
146- # Robot Status expand button
147- self .robot_status_expand = self .create_robot_status_expand_button ()
148+ # Button to expand/collapse the robot status view
149+ self .expand_robot_status_button = QPushButton ()
150+ self .expand_robot_status_button .setCheckable (True )
151+ self .expand_robot_status_button .setText ("INFO" )
148152
149153 # motor fault visualisation for the 4 wheel motors
150154 self .motor_fault_view = MotorFaultView ()
151155
152156 self .control_mode_layout .addWidget (self .motor_fault_view )
153157 self .control_mode_layout .addWidget (self .control_mode_menu )
154- self .control_mode_layout .addWidget (self .robot_status_expand )
158+ self .control_mode_layout .addWidget (self .expand_robot_status_button )
155159
156160 self .status_layout .addLayout (self .control_mode_layout )
157161
@@ -160,10 +164,10 @@ def __init__(
160164 self .robot_model_layout .setContentsMargins (0 , 5 , 5 , 0 )
161165
162166 # Vision Pattern
163- self .color_vision_pattern = self .create_vision_pattern (
167+ self .color_vision_pattern = self .__create_vision_pattern (
164168 Colors .ROBOT_MIDDLE_BLUE , ROBOT_RADIUS , True
165169 )
166- self .bw_vision_pattern = self .create_vision_pattern (
170+ self .bw_vision_pattern = self .__create_vision_pattern (
167171 Colors .BW_ROBOT_MIDDLE_BLUE , ROBOT_RADIUS , False
168172 )
169173
@@ -189,17 +193,33 @@ def __init__(
189193 self .last_robot_status = None
190194 self .last_robot_statistic = None
191195
192- def create_robot_status_expand_button (self ) -> QPushButton :
193- """Creates the button to expand / collapse the robot status view
196+ def update_robot_status (self , robot_status : RobotStatus ):
197+ """Receives a RobotStatus message and updates the UI to reflect the new data
198+
199+ :param robot_status: The latest RobotStatus message for this robot
200+ """
201+ self .time_of_last_robot_status = time .time ()
202+ self .last_robot_status = robot_status
203+
204+ self .robot_model .setPixmap (self .color_vision_pattern )
205+ self .__update_ui ()
206+
207+ # We should check in after DISCONNECT_DURATION_MS and see whether we've
208+ # received any new RobotStatus messages within the time that passed.
209+ # If not, then the robot probably disconnected.
210+ QtCore .QTimer .singleShot (
211+ int (DISCONNECT_DURATION_MS ), self .__check_for_disconnection
212+ )
194213
195- :return: QPushButton object
214+ def update_robot_statistic (self , robot_statistic : RobotStatistic ):
215+ """Receives a RobotStatistic message and updates the UI to reflect the new data
216+
217+ :param robot_statistic: The latest RobotStatistic message for this robot
196218 """
197- button = QPushButton ()
198- button .setCheckable (True )
199- button .setText ("INFO" )
200- return button
219+ self .last_robot_statistic = robot_statistic
220+ self .__update_ui ()
201221
202- def create_control_mode_menu (
222+ def __create_control_mode_menu (
203223 self , available_control_modes : list [IndividualRobotMode ]
204224 ) -> QComboBox :
205225 """Creates the drop down menu to select the input for each robot
@@ -232,7 +252,7 @@ def create_control_mode_menu(
232252
233253 return control_mode_menu
234254
235- def create_vision_pattern (
255+ def __create_vision_pattern (
236256 self , team_colour : QtGui .QColor , radius : int , connected : bool
237257 ) -> QtGui .QPixmap :
238258 """Given a robot id, team color and radius, draw the vision
@@ -295,56 +315,43 @@ def create_vision_pattern(
295315
296316 return pixmap
297317
298- def update_robot_status (self , robot_status : RobotStatus ):
299- """Receives a RobotStatus message
300-
301- Saves the current time as the last robot status time
302- Sets the robot UI as connected and updates the UI
303- Then sets a timer callback to disconnect the robot if needed
304-
305- :param robot_status: The robot status message for this robot
318+ def __check_for_disconnection (self ) -> None :
319+ """Calculates the time between the last robot status received and now.
320+ If more than our threshold, assume the robot disconnected and reset the UI.
306321 """
307- self .time_of_last_robot_status = time .time ()
308-
309- self .robot_model .setPixmap (self .color_vision_pattern )
310-
311- self .last_robot_status = robot_status
312-
313- self .__update_ui ()
314-
315- QtCore .QTimer .singleShot (int (DISCONNECT_DURATION_MS ), self .disconnect_robot )
316-
317- def update_rtt (self , robot_statistic : RobotStatistic ):
318- self .last_robot_statistic = robot_statistic
319-
320- self .__update_ui ()
321-
322- def disconnect_robot (self ) -> None :
323- """Calculates the time between the last robot status and now
324- If more than our threshold, resets UI
325- """
326- time_since_last_robot_status = time .time () - self .time_of_last_robot_status
327322 if (
328- time_since_last_robot_status
329- > DISCONNECT_DURATION_MS * SECONDS_PER_MILLISECOND
323+ time . time () - self . time_of_last_robot_status
324+ >= DISCONNECT_DURATION_MS * SECONDS_PER_MILLISECOND
330325 ):
331326 self .__reset_ui ()
332327
333328 def __reset_ui (self ) -> None :
334329 """Resets the UI to the default, uninitialized values"""
330+ self .__update_stop_primitive (None )
331+
335332 self .robot_model .setPixmap (self .bw_vision_pattern )
336333
334+ self .primitive_loss_rate_label .set_float_val (0 )
335+ self .primitive_rtt_label .set_float_val (0 )
337336 self .breakbeam_label .update_breakbeam_status (None )
337+ self .battery_progress_bar .setValue (self .battery_progress_bar .minimum ())
338+ self .motor_fault_view .reset_ui ()
338339
339- def __update_stop_primitive (self , is_running : bool ) -> None :
340+ def __update_stop_primitive (self , is_running : bool | None ) -> None :
340341 """Updates the stop primitive label based on the current running state
341342
342- :param is_running: if the robot is running currently
343+ :param is_running: true if the robot is running currently, false if the
344+ robot is stopped, or None if the robot is disconnected
345+ and there is no primitive executor status
343346 """
344- self .stop_primitive_label .setText ("RUN" if is_running else "STOP" )
345- self .stop_primitive_label .setStyleSheet (
346- f"background-color: { 'green' if is_running else 'red' } ; border: 1px solid black;"
347- )
347+ if is_running is None :
348+ self .stop_primitive_label .setVisible (False )
349+ else :
350+ self .stop_primitive_label .setVisible (True )
351+ self .stop_primitive_label .setText ("RUN" if is_running else "STOP" )
352+ self .stop_primitive_label .setStyleSheet (
353+ f"background-color: { 'green' if is_running else 'red' } ; border: 1px solid black;"
354+ )
348355
349356 def __update_ui (self ) -> None :
350357 """Receives important sections of RobotStatus proto for this robot and updates widget with alerts
@@ -357,11 +364,12 @@ def __update_ui(self) -> None:
357364 """
358365 if not self .last_robot_status or not self .last_robot_statistic :
359366 return
360- motor_status = robot_status .motor_status
361- power_status = robot_status .power_status
362- network_status = robot_status .network_status
363- primitive_executor_status = robot_status .primitive_executor_status
364- rtt_time_seconds = robot_statistic .round_trip_time_seconds
367+
368+ motor_status = self .last_robot_status .motor_status
369+ power_status = self .last_robot_status .power_status
370+ network_status = self .last_robot_status .network_status
371+ primitive_executor_status = self .last_robot_status .primitive_executor_status
372+ rtt_time_seconds = self .last_robot_statistic .round_trip_time_seconds
365373
366374 self .__update_stop_primitive (primitive_executor_status .running_primitive )
367375
@@ -374,6 +382,7 @@ def __update_ui(self) -> None:
374382 rtt_time_seconds * MILLISECONDS_PER_SECOND
375383 )
376384 )
385+
377386 self .breakbeam_label .update_breakbeam_status (power_status .breakbeam_tripped )
378387
379388 self .motor_fault_view .refresh (
0 commit comments