@@ -50,6 +50,10 @@ def __init__(self, node=None):
5050 self .frame_lock = threading .Lock ()
5151 self .frame_timestamp = 0 # Track frame freshness
5252
53+ # UI frame rate control
54+ self .last_ui_update = 0
55+ self .min_ui_interval = 1.0 / 30 # Target 30 FPS for UI
56+
5357 # Publishing rate control
5458 self .last_publish_time = 0
5559 self .min_publish_interval = 1.0 / 30.0 # Max 30 fps for publishing
@@ -652,8 +656,11 @@ def _process_loop(self):
652656 with self .frame_lock :
653657 self .processed_frame = frame
654658
655- # Emit frame for UI
656- self .frame_ready .emit (frame )
659+ # Emit frame for UI with rate limiting
660+ current_time = time .time ()
661+ if current_time - self .last_ui_update >= self .min_ui_interval :
662+ self .frame_ready .emit (frame )
663+ self .last_ui_update = current_time
657664 except Exception as e :
658665 self .error .emit (f"Error in process thread: { str (e )} " )
659666
@@ -960,10 +967,15 @@ def closeEvent(self, event):
960967
961968
962969class CameraNode (Node ):
963- def __init__ (self ):
970+ def __init__ (self , executor ):
971+ # Initialize node
964972 super ().__init__ ('coffee_camera_node' )
965973 self .get_logger ().info ('Camera node is starting...' )
966974
975+ # Store executor
976+ self .executor = executor
977+ self .executor .add_node (self )
978+
967979 # Start the UI
968980 app = QApplication (sys .argv )
969981 self .ui = CameraViewer (self )
@@ -975,13 +987,18 @@ def __init__(self):
975987 self .ros_thread .daemon = True
976988 self .ros_thread .start ()
977989
978- # Start Qt event loop
979- sys .exit (app .exec_ ())
990+ try :
991+ # Start Qt event loop
992+ app .exec_ ()
993+ except KeyboardInterrupt :
994+ self .spinning = False
995+ self .destroy_node ()
980996
981997 def spin_thread (self ):
982998 """Background thread for ROS spinning"""
983999 while self .spinning :
984- rclpy .spin_once (self , timeout_sec = 0.1 )
1000+ self .executor .spin_once (timeout_sec = 0.1 )
1001+ self .destroy_node ()
9851002
9861003 def destroy_node (self ):
9871004 """Clean shutdown"""
@@ -1002,20 +1019,25 @@ def destroy_node(self):
10021019
10031020
10041021def main (args = None ):
1005- rclpy .init (args = args )
10061022 try :
1007- node = CameraNode ()
1008- except KeyboardInterrupt :
1009- pass
1023+ # Initialize ROS2
1024+ rclpy .init (args = args )
1025+
1026+ # Create executor first
1027+ executor = rclpy .executors .SingleThreadedExecutor ()
1028+
1029+ # Create and run the node
1030+ node = CameraNode (executor )
10101031 except Exception as e :
1011- print (f"Error in camera node: { e } " )
1032+ print (f"Error in camera node: { str ( e ) } " )
10121033 import traceback
10131034 traceback .print_exc ()
10141035 finally :
1015- if 'node' in locals ():
1016- node .destroy_node ()
1017- rclpy .shutdown ()
1036+ try :
1037+ rclpy .shutdown ()
1038+ except Exception :
1039+ pass
10181040
10191041
10201042if __name__ == '__main__' :
1021- main ()
1043+ main ()
0 commit comments