From 925c2254bbb36c654e192222d11e093b18568d12 Mon Sep 17 00:00:00 2001 From: ayush-shirode Date: Tue, 30 Dec 2025 11:33:51 +0530 Subject: [PATCH] Fix ROS 2 node initialization by removing invalid context manager usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary This PR fixes an incorrect usage of rclpy.init() as a context manager in the static TF broadcaster node. The previous implementation used with rclpy.init():, which is not supported in ROS 2 Python and caused a runtime AttributeError: __enter__. Problem rclpy.init() does not implement Python’s context manager protocol (__enter__ / __exit__) Using it inside a with block causes the node to crash before spinning This prevented the static transform from being published on /tf_static Solution Replaced with rclpy.init(): with the correct ROS 2 lifecycle pattern: Explicit rclpy.init() Explicit rclpy.shutdown() in a finally block Preserved existing argument validation and exception handling Why this change is necessary ROS 2 Python initialization is a process-level operation, not a scoped resource. The explicit init/shutdown pattern is the officially supported and recommended approach and ensures predictable node lifecycle management. Impact Fixes runtime crash Allows static TF broadcaster to start correctly Aligns code with ROS 2 Python best practices Signed-off-by: ayush-shirode --- .../Writing-A-Tf2-Static-Broadcaster-Py.rst | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/source/Tutorials/Intermediate/Tf2/Writing-A-Tf2-Static-Broadcaster-Py.rst b/source/Tutorials/Intermediate/Tf2/Writing-A-Tf2-Static-Broadcaster-Py.rst index b3ae335f1ed..90762f982b6 100644 --- a/source/Tutorials/Intermediate/Tf2/Writing-A-Tf2-Static-Broadcaster-Py.rst +++ b/source/Tutorials/Intermediate/Tf2/Writing-A-Tf2-Static-Broadcaster-Py.rst @@ -166,26 +166,28 @@ Now open the file called ``static_turtle_tf2_broadcaster.py`` using your preferr def main(): + logger = rclpy.logging.get_logger('logger') + + # obtain parameters from command line arguments + if len(sys.argv) != 8: + logger.info('Invalid number of parameters. Usage: \n' + '$ ros2 run learning_tf2_py static_turtle_tf2_broadcaster' + 'child_frame_name x y z roll pitch yaw') + sys.exit(1) + + if sys.argv[1] == 'world': + logger.info('Your static turtle name cannot be "world"') + sys.exit(2) + + # pass parameters and initialize node try: - logger = rclpy.logging.get_logger('logger') - - # obtain parameters from command line arguments - if len(sys.argv) != 8: - logger.info('Invalid number of parameters. Usage: \n' - '$ ros2 run learning_tf2_py static_turtle_tf2_broadcaster' - 'child_frame_name x y z roll pitch yaw') - sys.exit(1) - - if sys.argv[1] == 'world': - logger.info('Your static turtle name cannot be "world"') - sys.exit(2) - - # pass parameters and initialize node - with rclpy.init(): - node = StaticFramePublisher(sys.argv) - rclpy.spin(node) + rclpy.init() + node = StaticFramePublisher(sys.argv) + rclpy.spin(node) except (KeyboardInterrupt, ExternalShutdownException): pass + finally: + rclpy.shutdown() 2.1 Examine the code ~~~~~~~~~~~~~~~~~~~~