@@ -45,7 +45,7 @@ def __init__(self, motor_id, motor_name="Motor", default_angle=0, parent=None):
4545 self .dragging = False
4646 self .torque_enabled = False
4747 self .motor_connected = False # Track motor connection status
48- self .setMinimumSize (2 * (self .radius + 60 ), 2 * (self .radius + 120 )) # Larger for card design
48+ self .setMinimumSize (2 * (self .radius + 60 ), 2 * (self .radius + 160 )) # Increased height for labels and controls
4949
5050 # Card styling with shadow effect
5151 self .setStyleSheet ("""
@@ -92,15 +92,31 @@ def __init__(self, motor_id, motor_name="Motor", default_angle=0, parent=None):
9292
9393 self .main_layout .addLayout (header_layout )
9494
95- # Widget for drawing the circle
95+ # Widget for drawing the circle (just the circle, no text)
9696 self .circle_widget = QWidget ()
97- self .circle_widget .setMinimumSize (2 * (self .radius + 20 ), 2 * (self .radius + 20 )) # Smaller since we have header
97+ self .circle_widget .setMinimumSize (2 * (self .radius + 20 ), 2 * (self .radius + 20 )) # Just for the circle
9898 self .circle_widget .paintEvent = self .paintCircleWidget
9999 self .circle_widget .mousePressEvent = self .circleMousePressEvent
100100 self .circle_widget .mouseMoveEvent = self .circleMouseMoveEvent
101101 self .circle_widget .mouseReleaseEvent = self .circleMouseReleaseEvent
102102 self .main_layout .addWidget (self .circle_widget )
103103
104+ # Separate labels for angle and status information
105+ self .angle_label = QLabel (f"{ self .angle :.1f} °" )
106+ self .angle_label .setAlignment (Qt .AlignCenter )
107+ self .angle_label .setFont (QFont ('Segoe UI' , 14 , QFont .Bold ))
108+ self .angle_label .setStyleSheet ("color: #2c3e50; margin: 5px 0px;" )
109+ self .main_layout .addWidget (self .angle_label )
110+
111+ self .status_label = QLabel ("DISCONNECTED" )
112+ self .status_label .setAlignment (Qt .AlignCenter )
113+ self .status_label .setFont (QFont ('Segoe UI' , 10 ))
114+ self .status_label .setStyleSheet ("color: #e74c3c; margin: 0px 0px 10px 0px;" )
115+ self .main_layout .addWidget (self .status_label )
116+
117+ # Initialize display with current state
118+ self .update_display ()
119+
104120 # Controls section with better styling
105121 controls_container = QWidget ()
106122 controls_container .setStyleSheet ("""
@@ -177,6 +193,22 @@ def __init__(self, motor_id, motor_name="Motor", default_angle=0, parent=None):
177193
178194 def set_ros_node (self , node ):
179195 self .rosnode = node
196+
197+ def update_display (self ):
198+ """Update all visual elements (circle, angle, status)"""
199+ # Update circle drawing
200+ self .circle_widget .update ()
201+
202+ # Update angle label
203+ self .angle_label .setText (f"{ self .angle :.1f} °" )
204+
205+ # Update status label
206+ if self .motor_connected :
207+ self .status_label .setText (f"Position: { self .position } " )
208+ self .status_label .setStyleSheet ("color: #7f8c8d; margin: 0px 0px 10px 0px;" )
209+ else :
210+ self .status_label .setText ("DISCONNECTED" )
211+ self .status_label .setStyleSheet ("color: #e74c3c; margin: 0px 0px 10px 0px;" )
180212
181213 def paintCircleWidget (self , event ):
182214 painter = QPainter (self .circle_widget )
@@ -195,29 +227,6 @@ def paintCircleWidget(self, event):
195227 circle_rect = QRect (10 , 10 , 2 * self .radius , 2 * self .radius ) # Adjusted for new layout
196228 painter .drawEllipse (circle_rect )
197229
198- # Draw angle text with connection status (centered below circle)
199- painter .setFont (QFont ("Segoe UI" , 12 , QFont .Medium ))
200- if self .motor_connected :
201- angle_text = f"{ self .angle :.1f} °"
202- pos_text = f"Position: { self .position } "
203- else :
204- angle_text = f"{ self .angle :.1f} °"
205- pos_text = "DISCONNECTED"
206-
207- # Angle text
208- angle_rect = QRect (10 , 2 * self .radius + 20 , 2 * self .radius , 25 )
209- painter .setPen (QPen (Qt .black , 1 ))
210- painter .drawText (angle_rect , Qt .AlignCenter , angle_text )
211-
212- # Position/status text
213- pos_rect = QRect (10 , 2 * self .radius + 40 , 2 * self .radius , 25 )
214- if self .motor_connected :
215- painter .setPen (QPen (QColor ("#7f8c8d" ), 1 ))
216- else :
217- painter .setPen (QPen (QColor ("#e74c3c" ), 1 ))
218- painter .setFont (QFont ("Segoe UI" , 10 ))
219- painter .drawText (pos_rect , Qt .AlignCenter , pos_text )
220-
221230 # Draw line from center to edge (like a clock hand)
222231 if self .torque_enabled :
223232 painter .setPen (QPen (Qt .red , 3 ))
@@ -265,7 +274,7 @@ def updateAngle(self, x, y):
265274 self .position = int (self .angle * POSITIONS_PER_DEGREE )
266275
267276 # Update display
268- self .circle_widget . update ()
277+ self .update_display ()
269278
270279 # Only send to motor if dragging stopped (to reduce traffic)
271280 # Full position will be sent when mouse is released
@@ -280,7 +289,7 @@ def send_position_to_motor(self):
280289
281290 def toggleTorque (self , state ):
282291 self .torque_enabled = bool (state )
283- self .circle_widget . update ()
292+ self .update_display ()
284293 if self .rosnode :
285294 self .rosnode .get_logger ().info (f"{ self .motor_name } (ID: { self .motor_id } ) torque { 'enabled' if self .torque_enabled else 'disabled' } " )
286295 # In a real implementation, you would send torque command to motor here
@@ -290,7 +299,7 @@ def toggleTorque(self, state):
290299 def resetPosition (self ):
291300 self .angle = self .default_angle
292301 self .position = int (self .default_angle * POSITIONS_PER_DEGREE )
293- self .circle_widget . update ()
302+ self .update_display ()
294303
295304 if self .rosnode and self .torque_enabled :
296305 self .rosnode .get_logger ().info (f"{ self .motor_name } (ID: { self .motor_id } ) position reset to { self .default_angle } °" )
@@ -304,14 +313,14 @@ def set_position_from_motor(self, position):
304313 # Enable controls when motor is connected
305314 self .torque_checkbox .setEnabled (True )
306315 self .reset_button .setEnabled (True )
307- self .circle_widget . update ()
316+ self .update_display ()
308317
309318 def set_motor_disconnected (self ):
310319 """Mark motor as disconnected and disable controls"""
311320 self .motor_connected = False
312321 self .torque_checkbox .setEnabled (False )
313322 self .reset_button .setEnabled (False )
314- self .circle_widget . update ()
323+ self .update_display ()
315324
316325
317326class DynamixelControlUI (QMainWindow ):
0 commit comments