From 291c789b848a12f9f19a75a43c1f7dc4ea0180c8 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Wed, 24 Jul 2024 13:39:51 -0400 Subject: [PATCH] Switch to using the rclpy context manager everywhere. (#389) * Switch to using the rclpy context manager everywhere. This lets us use less code, but still effectively manage the lifetime of the rclpy.init. We also change ExternalShutdownException handling to work just like a KeyboardInterrupt. Signed-off-by: Chris Lalancette --- .../client.py | 15 +-- .../client_asyncio.py | 68 +++++++------- .../client_cancel.py | 15 +-- .../client_not_composable.py | 61 ++++++------ .../server.py | 16 ++-- .../server_defer.py | 16 ++-- .../server_not_composable.py | 45 +++++---- .../server_queue_goals.py | 14 +-- .../server_single_goal.py | 16 ++-- .../callback_group.py | 32 +++---- .../examples_rclpy_executors/composed.py | 30 +++--- .../custom_callback_group.py | 11 +-- .../custom_executor.py | 20 ++-- .../examples_rclpy_executors/listener.py | 12 +-- .../examples_rclpy_executors/talker.py | 12 +-- .../trigger_guard_condition.py | 56 ++++++----- .../examples_rclpy_minimal_client/client.py | 41 ++++---- .../client_async.py | 47 +++++----- .../client_async_callback.py | 93 +++++++++---------- .../client_async_member_function.py | 29 ++---- .../examples_rclpy_minimal_service/service.py | 21 ++--- .../service_member_function.py | 13 +-- .../publisher_local_function.py | 45 ++++----- .../publisher_member_function.py | 13 +-- .../publisher_old_school.py | 28 +++--- .../subscriber_lambda.py | 20 ++-- .../subscriber_member_function.py | 13 +-- .../subscriber_old_school.py | 18 ++-- .../pointcloud_publisher.py | 12 +-- 29 files changed, 355 insertions(+), 477 deletions(-) diff --git a/rclpy/actions/minimal_action_client/examples_rclpy_minimal_action_client/client.py b/rclpy/actions/minimal_action_client/examples_rclpy_minimal_action_client/client.py index 384672d5..f7a5d292 100644 --- a/rclpy/actions/minimal_action_client/examples_rclpy_minimal_action_client/client.py +++ b/rclpy/actions/minimal_action_client/examples_rclpy_minimal_action_client/client.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - from action_msgs.msg import GoalStatus from example_interfaces.action import Fibonacci @@ -71,18 +69,15 @@ def send_goal(self): def main(args=None): - rclpy.init(args=args) - try: - action_client = MinimalActionClient() + with rclpy.init(args=args): + action_client = MinimalActionClient() - action_client.send_goal() + action_client.send_goal() - rclpy.spin(action_client) - except KeyboardInterrupt: + rclpy.spin(action_client) + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/actions/minimal_action_client/examples_rclpy_minimal_action_client/client_asyncio.py b/rclpy/actions/minimal_action_client/examples_rclpy_minimal_action_client/client_asyncio.py index 9af6bcbe..88781b2e 100644 --- a/rclpy/actions/minimal_action_client/examples_rclpy_minimal_action_client/client_asyncio.py +++ b/rclpy/actions/minimal_action_client/examples_rclpy_minimal_action_client/client_asyncio.py @@ -19,6 +19,7 @@ import rclpy from rclpy.action import ActionClient +from rclpy.executors import ExternalShutdownException from rclpy.node import Node @@ -69,48 +70,49 @@ async def spinning(node): async def run(args, loop): - logger = rclpy.logging.get_logger('minimal_action_client') + # init ROS 2 + with rclpy.init(args=args): + logger = rclpy.logging.get_logger('minimal_action_client') - # init ros2 - rclpy.init(args=args) + # create node + action_client = MinimalActionClientAsyncIO() - # create node - action_client = MinimalActionClientAsyncIO() + # start spinning + spin_task = loop.create_task(spinning(action_client)) - # start spinning - spin_task = loop.create_task(spinning(action_client)) + # Parallel example + # execute goal request and schedule in loop + my_task1 = loop.create_task(action_client.send_goal()) + my_task2 = loop.create_task(action_client.send_goal()) - # Parallel example - # execute goal request and schedule in loop - my_task1 = loop.create_task(action_client.send_goal()) - my_task2 = loop.create_task(action_client.send_goal()) + # glue futures together and wait + wait_future = asyncio.wait([my_task1, my_task2]) + # run event loop + finished, unfinished = await wait_future + logger.info(f'unfinished: {len(unfinished)}') + for task in finished: + logger.info('result {} and status flag {}'.format(*task.result())) - # glue futures together and wait - wait_future = asyncio.wait([my_task1, my_task2]) - # run event loop - finished, unfinished = await wait_future - logger.info(f'unfinished: {len(unfinished)}') - for task in finished: - logger.info('result {} and status flag {}'.format(*task.result())) + # Sequence + result, status = await loop.create_task(action_client.send_goal()) + logger.info(f'A) result {result} and status flag {status}') + result, status = await loop.create_task(action_client.send_goal()) + logger.info(f'B) result {result} and status flag {status}') - # Sequence - result, status = await loop.create_task(action_client.send_goal()) - logger.info(f'A) result {result} and status flag {status}') - result, status = await loop.create_task(action_client.send_goal()) - logger.info(f'B) result {result} and status flag {status}') - - # cancel spinning task - spin_task.cancel() - try: - await spin_task - except asyncio.exceptions.CancelledError: - pass - rclpy.shutdown() + # cancel spinning task + spin_task.cancel() + try: + await spin_task + except asyncio.exceptions.CancelledError: + pass def main(args=None): - loop = asyncio.get_event_loop() - loop.run_until_complete(run(args, loop=loop)) + try: + loop = asyncio.get_event_loop() + loop.run_until_complete(run(args, loop=loop)) + except (KeyboardInterrupt, ExternalShutdownException): + pass if __name__ == '__main__': diff --git a/rclpy/actions/minimal_action_client/examples_rclpy_minimal_action_client/client_cancel.py b/rclpy/actions/minimal_action_client/examples_rclpy_minimal_action_client/client_cancel.py index 35e3bd6f..53bcc573 100644 --- a/rclpy/actions/minimal_action_client/examples_rclpy_minimal_action_client/client_cancel.py +++ b/rclpy/actions/minimal_action_client/examples_rclpy_minimal_action_client/client_cancel.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - from example_interfaces.action import Fibonacci import rclpy @@ -79,18 +77,15 @@ def send_goal(self): def main(args=None): - rclpy.init(args=args) - try: - action_client = MinimalActionClient() + with rclpy.init(args=args): + action_client = MinimalActionClient() - action_client.send_goal() + action_client.send_goal() - rclpy.spin(action_client) - except KeyboardInterrupt: + rclpy.spin(action_client) + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/actions/minimal_action_client/examples_rclpy_minimal_action_client/client_not_composable.py b/rclpy/actions/minimal_action_client/examples_rclpy_minimal_action_client/client_not_composable.py index e1ddbe89..1eef86fd 100644 --- a/rclpy/actions/minimal_action_client/examples_rclpy_minimal_action_client/client_not_composable.py +++ b/rclpy/actions/minimal_action_client/examples_rclpy_minimal_action_client/client_not_composable.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - from action_msgs.msg import GoalStatus from example_interfaces.action import Fibonacci @@ -28,53 +26,48 @@ def feedback_cb(logger, feedback): def main(args=None): - rclpy.init(args=args) - try: - node = rclpy.create_node('minimal_action_client') + with rclpy.init(args=args): + node = rclpy.create_node('minimal_action_client') - action_client = ActionClient(node, Fibonacci, 'fibonacci') + action_client = ActionClient(node, Fibonacci, 'fibonacci') - node.get_logger().info('Waiting for action server...') + node.get_logger().info('Waiting for action server...') - action_client.wait_for_server() + action_client.wait_for_server() - goal_msg = Fibonacci.Goal() - goal_msg.order = 10 + goal_msg = Fibonacci.Goal() + goal_msg.order = 10 - node.get_logger().info('Sending goal request...') + node.get_logger().info('Sending goal request...') - send_goal_future = action_client.send_goal_async( - goal_msg, feedback_callback=lambda feedback: feedback_cb(node.get_logger(), feedback)) + send_goal_future = action_client.send_goal_async( + goal_msg, + feedback_callback=lambda feedback: feedback_cb(node.get_logger(), feedback)) - rclpy.spin_until_future_complete(node, send_goal_future) + rclpy.spin_until_future_complete(node, send_goal_future) - goal_handle = send_goal_future.result() + goal_handle = send_goal_future.result() - if not goal_handle.accepted: - node.get_logger().info('Goal rejected :(') - action_client.destroy() - node.destroy_node() - rclpy.shutdown() - return + if not goal_handle.accepted: + node.get_logger().info('Goal rejected :(') + return - node.get_logger().info('Goal accepted :)') + node.get_logger().info('Goal accepted :)') - get_result_future = goal_handle.get_result_async() + get_result_future = goal_handle.get_result_async() - rclpy.spin_until_future_complete(node, get_result_future) + rclpy.spin_until_future_complete(node, get_result_future) - result = get_result_future.result().result - status = get_result_future.result().status - if status == GoalStatus.STATUS_SUCCEEDED: - node.get_logger().info( - 'Goal succeeded! Result: {0}'.format(result.sequence)) - else: - node.get_logger().info('Goal failed with status code: {0}'.format(status)) - except KeyboardInterrupt: + result = get_result_future.result().result + status = get_result_future.result().status + if status == GoalStatus.STATUS_SUCCEEDED: + node.get_logger().info( + 'Goal succeeded! Result: {0}'.format(result.sequence)) + else: + node.get_logger().info('Goal failed with status code: {0}'.format(status)) + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/actions/minimal_action_server/examples_rclpy_minimal_action_server/server.py b/rclpy/actions/minimal_action_server/examples_rclpy_minimal_action_server/server.py index 599a367a..b5ba8438 100644 --- a/rclpy/actions/minimal_action_server/examples_rclpy_minimal_action_server/server.py +++ b/rclpy/actions/minimal_action_server/examples_rclpy_minimal_action_server/server.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys import time from example_interfaces.action import Fibonacci @@ -92,19 +91,16 @@ async def execute_callback(self, goal_handle): def main(args=None): - rclpy.init(args=args) - try: - minimal_action_server = MinimalActionServer() + with rclpy.init(args=args): + minimal_action_server = MinimalActionServer() - # Use a MultiThreadedExecutor to enable processing goals concurrently - executor = MultiThreadedExecutor() + # Use a MultiThreadedExecutor to enable processing goals concurrently + executor = MultiThreadedExecutor() - rclpy.spin(minimal_action_server, executor=executor) - except KeyboardInterrupt: + rclpy.spin(minimal_action_server, executor=executor) + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/actions/minimal_action_server/examples_rclpy_minimal_action_server/server_defer.py b/rclpy/actions/minimal_action_server/examples_rclpy_minimal_action_server/server_defer.py index b6abcb01..53a4872c 100644 --- a/rclpy/actions/minimal_action_server/examples_rclpy_minimal_action_server/server_defer.py +++ b/rclpy/actions/minimal_action_server/examples_rclpy_minimal_action_server/server_defer.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys import time from example_interfaces.action import Fibonacci @@ -106,19 +105,16 @@ async def execute_callback(self, goal_handle): def main(args=None): - rclpy.init(args=args) - try: - minimal_action_server = MinimalActionServer() + with rclpy.init(args=args): + minimal_action_server = MinimalActionServer() - # Use a MultiThreadedExecutor to enable processing goals concurrently - executor = MultiThreadedExecutor() + # Use a MultiThreadedExecutor to enable processing goals concurrently + executor = MultiThreadedExecutor() - rclpy.spin(minimal_action_server, executor=executor) - except KeyboardInterrupt: + rclpy.spin(minimal_action_server, executor=executor) + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/actions/minimal_action_server/examples_rclpy_minimal_action_server/server_not_composable.py b/rclpy/actions/minimal_action_server/examples_rclpy_minimal_action_server/server_not_composable.py index 60bb3705..796a6cca 100644 --- a/rclpy/actions/minimal_action_server/examples_rclpy_minimal_action_server/server_not_composable.py +++ b/rclpy/actions/minimal_action_server/examples_rclpy_minimal_action_server/server_not_composable.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys import time from example_interfaces.action import Fibonacci @@ -71,32 +70,30 @@ async def execute_callback(goal_handle): def main(args=None): global logger - rclpy.init(args=args) try: - node = rclpy.create_node('minimal_action_server') - logger = node.get_logger() - - # Use a ReentrantCallbackGroup to enable processing multiple goals concurrently - # Default goal callback accepts all goals - # Default cancel callback rejects cancel requests - action_server = ActionServer( - node, - Fibonacci, - 'fibonacci', - execute_callback=execute_callback, - cancel_callback=cancel_callback, - callback_group=ReentrantCallbackGroup()) - action_server # Quiet flake8 warnings about unused variable - - # Use a MultiThreadedExecutor to enable processing goals concurrently - executor = MultiThreadedExecutor() - - rclpy.spin(node, executor=executor) - except KeyboardInterrupt: + with rclpy.init(args=args): + node = rclpy.create_node('minimal_action_server') + logger = node.get_logger() + + # Use a ReentrantCallbackGroup to enable processing multiple goals concurrently + # Default goal callback accepts all goals + # Default cancel callback rejects cancel requests + action_server = ActionServer( + node, + Fibonacci, + 'fibonacci', + execute_callback=execute_callback, + cancel_callback=cancel_callback, + callback_group=ReentrantCallbackGroup()) + action_server # Quiet flake8 warnings about unused variable + + # Use a MultiThreadedExecutor to enable processing goals concurrently + executor = MultiThreadedExecutor() + + rclpy.spin(node, executor=executor) + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/actions/minimal_action_server/examples_rclpy_minimal_action_server/server_queue_goals.py b/rclpy/actions/minimal_action_server/examples_rclpy_minimal_action_server/server_queue_goals.py index eae970fb..0c910e06 100644 --- a/rclpy/actions/minimal_action_server/examples_rclpy_minimal_action_server/server_queue_goals.py +++ b/rclpy/actions/minimal_action_server/examples_rclpy_minimal_action_server/server_queue_goals.py @@ -13,7 +13,6 @@ # limitations under the License. import collections -import sys import threading import time @@ -123,18 +122,15 @@ def execute_callback(self, goal_handle): def main(args=None): - rclpy.init(args=args) - try: - minimal_action_server = MinimalActionServer() + with rclpy.init(args=args): + minimal_action_server = MinimalActionServer() - executor = MultiThreadedExecutor() + executor = MultiThreadedExecutor() - rclpy.spin(minimal_action_server, executor=executor) - except KeyboardInterrupt: + rclpy.spin(minimal_action_server, executor=executor) + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/actions/minimal_action_server/examples_rclpy_minimal_action_server/server_single_goal.py b/rclpy/actions/minimal_action_server/examples_rclpy_minimal_action_server/server_single_goal.py index a172963c..c3a398c1 100644 --- a/rclpy/actions/minimal_action_server/examples_rclpy_minimal_action_server/server_single_goal.py +++ b/rclpy/actions/minimal_action_server/examples_rclpy_minimal_action_server/server_single_goal.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys import threading import time @@ -117,18 +116,15 @@ def execute_callback(self, goal_handle): def main(args=None): - rclpy.init(args=args) - try: - action_server = MinimalActionServer() + with rclpy.init(args=args): + action_server = MinimalActionServer() - # We use a MultiThreadedExecutor to handle incoming goal requests concurrently - executor = MultiThreadedExecutor() - rclpy.spin(action_server, executor=executor) - except KeyboardInterrupt: + # We use a MultiThreadedExecutor to handle incoming goal requests concurrently + executor = MultiThreadedExecutor() + rclpy.spin(action_server, executor=executor) + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/executors/examples_rclpy_executors/callback_group.py b/rclpy/executors/examples_rclpy_executors/callback_group.py index 3a71a894..084dcd80 100644 --- a/rclpy/executors/examples_rclpy_executors/callback_group.py +++ b/rclpy/executors/examples_rclpy_executors/callback_group.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - from examples_rclpy_executors.listener import Listener import rclpy from rclpy.callback_groups import MutuallyExclusiveCallbackGroup @@ -47,25 +45,23 @@ def timer_callback(self): def main(args=None): - rclpy.init(args=args) try: - talker = DoubleTalker() - listener = Listener() - # MultiThreadedExecutor executes callbacks with a thread pool. If num_threads is not - # specified then num_threads will be multiprocessing.cpu_count() if it is implemented. - # Otherwise it will use a single thread. This executor will allow callbacks to happen in - # parallel, however the MutuallyExclusiveCallbackGroup in DoubleTalker will only allow its - # callbacks to be executed one at a time. The callbacks in Listener are free to execute in - # parallel to the ones in DoubleTalker however. - executor = MultiThreadedExecutor(num_threads=4) - executor.add_node(talker) - executor.add_node(listener) + with rclpy.init(args=args): + talker = DoubleTalker() + listener = Listener() + # MultiThreadedExecutor executes callbacks with a thread pool. If num_threads is not + # specified then num_threads will be multiprocessing.cpu_count() if it is implemented. + # Otherwise it will use a single thread. This executor will allow callbacks to happen + # in parallel, however the MutuallyExclusiveCallbackGroup in DoubleTalker will only + # allow its callbacks to be executed one at a time. The callbacks in Listener are free + # to execute in parallel to the ones in DoubleTalker however. + executor = MultiThreadedExecutor(num_threads=4) + executor.add_node(talker) + executor.add_node(listener) - executor.spin() - except KeyboardInterrupt: + executor.spin() + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/executors/examples_rclpy_executors/composed.py b/rclpy/executors/examples_rclpy_executors/composed.py index c88fa6e0..77c395d7 100644 --- a/rclpy/executors/examples_rclpy_executors/composed.py +++ b/rclpy/executors/examples_rclpy_executors/composed.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - from examples_rclpy_executors.listener import Listener from examples_rclpy_executors.talker import Talker import rclpy @@ -22,23 +20,21 @@ def main(args=None): - rclpy.init(args=args) try: - talker = Talker() - listener = Listener() - - # Runs all callbacks in the main thread - executor = SingleThreadedExecutor() - # Add imported nodes to this executor - executor.add_node(talker) - executor.add_node(listener) - - # Execute callbacks for both nodes as they become ready - executor.spin() - except KeyboardInterrupt: + with rclpy.init(args=args): + talker = Talker() + listener = Listener() + + # Runs all callbacks in the main thread + executor = SingleThreadedExecutor() + # Add imported nodes to this executor + executor.add_node(talker) + executor.add_node(listener) + + # Execute callbacks for both nodes as they become ready + executor.spin() + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/executors/examples_rclpy_executors/custom_callback_group.py b/rclpy/executors/examples_rclpy_executors/custom_callback_group.py index 056ce3a2..75d7276a 100644 --- a/rclpy/executors/examples_rclpy_executors/custom_callback_group.py +++ b/rclpy/executors/examples_rclpy_executors/custom_callback_group.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys import threading import rclpy @@ -99,14 +98,12 @@ def timer_callback(self): def main(args=None): - rclpy.init(args=args) try: - talker = ThrottledTalker() - rclpy.spin(talker) - except KeyboardInterrupt: + with rclpy.init(args=args): + talker = ThrottledTalker() + rclpy.spin(talker) + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/executors/examples_rclpy_executors/custom_executor.py b/rclpy/executors/examples_rclpy_executors/custom_executor.py index c6048abd..c47ff2df 100644 --- a/rclpy/executors/examples_rclpy_executors/custom_executor.py +++ b/rclpy/executors/examples_rclpy_executors/custom_executor.py @@ -80,17 +80,17 @@ def spin_once(self, timeout_sec=None): def main(args=None): - rclpy.init(args=args) try: - listener = Listener() - talker = Talker() - estopper = Estopper() - - executor = PriorityExecutor() - executor.add_high_priority_node(estopper) - executor.add_node(listener) - executor.add_node(talker) - executor.spin() + with rclpy.init(args=args): + listener = Listener() + talker = Talker() + estopper = Estopper() + + executor = PriorityExecutor() + executor.add_high_priority_node(estopper) + executor.add_node(listener) + executor.add_node(talker) + executor.spin() except KeyboardInterrupt: pass except ExternalShutdownException: diff --git a/rclpy/executors/examples_rclpy_executors/listener.py b/rclpy/executors/examples_rclpy_executors/listener.py index 4db789e7..5989a101 100644 --- a/rclpy/executors/examples_rclpy_executors/listener.py +++ b/rclpy/executors/examples_rclpy_executors/listener.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - import rclpy from rclpy.executors import ExternalShutdownException from rclpy.node import Node @@ -48,14 +46,12 @@ def main(args=None): :param args: Arguments passed in from the command line. """ - rclpy.init(args=args) try: - listener = Listener() - rclpy.spin(listener) - except KeyboardInterrupt: + with rclpy.init(args=args): + listener = Listener() + rclpy.spin(listener) + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/executors/examples_rclpy_executors/talker.py b/rclpy/executors/examples_rclpy_executors/talker.py index c2951f34..0c0a8893 100644 --- a/rclpy/executors/examples_rclpy_executors/talker.py +++ b/rclpy/executors/examples_rclpy_executors/talker.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - import rclpy from rclpy.executors import ExternalShutdownException from rclpy.node import Node @@ -58,14 +56,12 @@ def main(args=None): :param args: Arguments passed in from the command line. """ # Run standalone - rclpy.init(args=args) try: - talker = Talker() - rclpy.spin(talker) - except KeyboardInterrupt: + with rclpy.init(args=args): + talker = Talker() + rclpy.spin(talker) + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/guard_conditions/examples_rclpy_guard_conditions/trigger_guard_condition.py b/rclpy/guard_conditions/examples_rclpy_guard_conditions/trigger_guard_condition.py index 1f839221..0abe0e47 100644 --- a/rclpy/guard_conditions/examples_rclpy_guard_conditions/trigger_guard_condition.py +++ b/rclpy/guard_conditions/examples_rclpy_guard_conditions/trigger_guard_condition.py @@ -12,43 +12,39 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - import rclpy from rclpy.executors import ExternalShutdownException def main(args=None): - rclpy.init(args=args) try: - node = rclpy.create_node('demo_guard_condition') - executor = rclpy.executors.SingleThreadedExecutor() - executor.add_node(node) - - def guard_condition_callback(): - rclpy.shutdown() - node.get_logger().info('guard callback called shutdown') - - def timer_callback(): - guard_condition.trigger() - node.get_logger().info('timer callback triggered guard condition') - - node.create_timer(timer_period_sec=2, callback=timer_callback) - guard_condition = node.create_guard_condition(guard_condition_callback) - - while rclpy.ok(): - # First loop: `spin_once` waits for timer to be ready, then calls - # the timer's callback, which triggers the guard condition. - # Second loop: The guard condition is ready so it's callback is - # called. The callback calls shutdown, so the loop doesn't run - # again and the program exits. - node.get_logger().info("waiting for 'spin_once' to finish...") - executor.spin_once() - node.get_logger().info("...'spin_once' finished!\n") - except KeyboardInterrupt: + with rclpy.init(args=args): + node = rclpy.create_node('demo_guard_condition') + executor = rclpy.executors.SingleThreadedExecutor() + executor.add_node(node) + + def guard_condition_callback(): + rclpy.shutdown() + node.get_logger().info('guard callback called shutdown') + + def timer_callback(): + guard_condition.trigger() + node.get_logger().info('timer callback triggered guard condition') + + node.create_timer(timer_period_sec=2, callback=timer_callback) + guard_condition = node.create_guard_condition(guard_condition_callback) + + while rclpy.ok(): + # First loop: `spin_once` waits for timer to be ready, then calls + # the timer's callback, which triggers the guard condition. + # Second loop: The guard condition is ready so it's callback is + # called. The callback calls shutdown, so the loop doesn't run + # again and the program exits. + node.get_logger().info("waiting for 'spin_once' to finish...") + executor.spin_once() + node.get_logger().info("...'spin_once' finished!\n") + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/services/minimal_client/examples_rclpy_minimal_client/client.py b/rclpy/services/minimal_client/examples_rclpy_minimal_client/client.py index db81dd22..a5b278a5 100644 --- a/rclpy/services/minimal_client/examples_rclpy_minimal_client/client.py +++ b/rclpy/services/minimal_client/examples_rclpy_minimal_client/client.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - from example_interfaces.srv import AddTwoInts import rclpy @@ -21,29 +19,26 @@ def main(args=None): - rclpy.init(args=args) - try: - node = rclpy.create_node('minimal_client') - cli = node.create_client(AddTwoInts, 'add_two_ints') - - req = AddTwoInts.Request() - req.a = 41 - req.b = 1 - while not cli.wait_for_service(timeout_sec=1.0): - node.get_logger().info('service not available, waiting again...') - - future = cli.call_async(req) - rclpy.spin_until_future_complete(node, future) - - result = future.result() - node.get_logger().info( - 'Result of add_two_ints: for %d + %d = %d' % - (req.a, req.b, result.sum)) - except KeyboardInterrupt: + with rclpy.init(args=args): + node = rclpy.create_node('minimal_client') + cli = node.create_client(AddTwoInts, 'add_two_ints') + + req = AddTwoInts.Request() + req.a = 41 + req.b = 1 + while not cli.wait_for_service(timeout_sec=1.0): + node.get_logger().info('service not available, waiting again...') + + future = cli.call_async(req) + rclpy.spin_until_future_complete(node, future) + + result = future.result() + node.get_logger().info( + 'Result of add_two_ints: for %d + %d = %d' % + (req.a, req.b, result.sum)) + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/services/minimal_client/examples_rclpy_minimal_client/client_async.py b/rclpy/services/minimal_client/examples_rclpy_minimal_client/client_async.py index 6d19a58d..a1cfbea1 100644 --- a/rclpy/services/minimal_client/examples_rclpy_minimal_client/client_async.py +++ b/rclpy/services/minimal_client/examples_rclpy_minimal_client/client_async.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - from example_interfaces.srv import AddTwoInts import rclpy @@ -21,32 +19,29 @@ def main(args=None): - rclpy.init(args=args) - try: - node = rclpy.create_node('minimal_client_async') - - cli = node.create_client(AddTwoInts, 'add_two_ints') - - req = AddTwoInts.Request() - req.a = 41 - req.b = 1 - while not cli.wait_for_service(timeout_sec=1.0): - node.get_logger().info('service not available, waiting again...') - - future = cli.call_async(req) - while rclpy.ok(): - rclpy.spin_once(node) - if future.done(): - result = future.result() - node.get_logger().info( - 'Result of add_two_ints: for %d + %d = %d' % - (req.a, req.b, result.sum)) - break - except KeyboardInterrupt: + with rclpy.init(args=args): + node = rclpy.create_node('minimal_client_async') + + cli = node.create_client(AddTwoInts, 'add_two_ints') + + req = AddTwoInts.Request() + req.a = 41 + req.b = 1 + while not cli.wait_for_service(timeout_sec=1.0): + node.get_logger().info('service not available, waiting again...') + + future = cli.call_async(req) + while rclpy.ok(): + rclpy.spin_once(node) + if future.done(): + result = future.result() + node.get_logger().info( + 'Result of add_two_ints: for %d + %d = %d' % + (req.a, req.b, result.sum)) + break + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/services/minimal_client/examples_rclpy_minimal_client/client_async_callback.py b/rclpy/services/minimal_client/examples_rclpy_minimal_client/client_async_callback.py index 03f3a2b6..53b13ef9 100644 --- a/rclpy/services/minimal_client/examples_rclpy_minimal_client/client_async_callback.py +++ b/rclpy/services/minimal_client/examples_rclpy_minimal_client/client_async_callback.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - from example_interfaces.srv import AddTwoInts import rclpy @@ -22,55 +20,52 @@ def main(args=None): - rclpy.init(args=args) - try: - node = rclpy.create_node('minimal_client') - - executor = rclpy.executors.SingleThreadedExecutor() - executor.add_node(node) - - # Node's default callback group is mutually exclusive. This would prevent the client - # response from being processed until the timer callback finished, but the timer callback - # in this example is waiting for the client response - cb_group = ReentrantCallbackGroup() - cli = node.create_client(AddTwoInts, 'add_two_ints', callback_group=cb_group) - did_run = False - did_get_result = False - - async def call_service(): - nonlocal cli, node, did_run, did_get_result - did_run = True - try: - req = AddTwoInts.Request() - req.a = 41 - req.b = 1 - future = cli.call_async(req) - result = await future - node.get_logger().info( - 'Result of add_two_ints: for %d + %d = %d' % - (req.a, req.b, result.sum)) - finally: - did_get_result = True - - while not cli.wait_for_service(timeout_sec=1.0): - node.get_logger().info('service not available, waiting again...') - - timer = node.create_timer(0.5, call_service, callback_group=cb_group) - - while rclpy.ok() and not did_run: - executor.spin_once() - - if did_run: - # call timer callback only once - timer.cancel() - - while rclpy.ok() and not did_get_result: - executor.spin_once() - except KeyboardInterrupt: + with rclpy.init(args=args): + node = rclpy.create_node('minimal_client') + + executor = rclpy.executors.SingleThreadedExecutor() + executor.add_node(node) + + # Node's default callback group is mutually exclusive. This would prevent the client + # response from being processed until the timer callback finished, but the timer + # callback in this example is waiting for the client response + cb_group = ReentrantCallbackGroup() + cli = node.create_client(AddTwoInts, 'add_two_ints', callback_group=cb_group) + did_run = False + did_get_result = False + + async def call_service(): + nonlocal cli, node, did_run, did_get_result + did_run = True + try: + req = AddTwoInts.Request() + req.a = 41 + req.b = 1 + future = cli.call_async(req) + result = await future + node.get_logger().info( + 'Result of add_two_ints: for %d + %d = %d' % + (req.a, req.b, result.sum)) + finally: + did_get_result = True + + while not cli.wait_for_service(timeout_sec=1.0): + node.get_logger().info('service not available, waiting again...') + + timer = node.create_timer(0.5, call_service, callback_group=cb_group) + + while rclpy.ok() and not did_run: + executor.spin_once() + + if did_run: + # call timer callback only once + timer.cancel() + + while rclpy.ok() and not did_get_result: + executor.spin_once() + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/services/minimal_client/examples_rclpy_minimal_client/client_async_member_function.py b/rclpy/services/minimal_client/examples_rclpy_minimal_client/client_async_member_function.py index a23ef8bf..49dea516 100644 --- a/rclpy/services/minimal_client/examples_rclpy_minimal_client/client_async_member_function.py +++ b/rclpy/services/minimal_client/examples_rclpy_minimal_client/client_async_member_function.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - from example_interfaces.srv import AddTwoInts import rclpy @@ -33,28 +31,21 @@ def __init__(self): def send_request(self): self.req.a = 41 self.req.b = 1 - self.future = self.cli.call_async(self.req) + return self.cli.call_async(self.req) def main(args=None): - rclpy.init(args=args) - try: - minimal_client = MinimalClientAsync() - minimal_client.send_request() - - while rclpy.ok(): - rclpy.spin_once(minimal_client) - if minimal_client.future.done(): - response = minimal_client.future.result() - minimal_client.get_logger().info( - 'Result of add_two_ints: for %d + %d = %d' % - (minimal_client.req.a, minimal_client.req.b, response.sum)) - break - except KeyboardInterrupt: + with rclpy.init(args=args): + minimal_client = MinimalClientAsync() + future = minimal_client.send_request() + rclpy.spin_until_future_complete(minimal_client, future) + response = future.result() + minimal_client.get_logger().info( + 'Result of add_two_ints: for %d + %d = %d' % + (minimal_client.req.a, minimal_client.req.b, response.sum)) + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/services/minimal_service/examples_rclpy_minimal_service/service.py b/rclpy/services/minimal_service/examples_rclpy_minimal_service/service.py index 5ade5c50..bb3058b0 100644 --- a/rclpy/services/minimal_service/examples_rclpy_minimal_service/service.py +++ b/rclpy/services/minimal_service/examples_rclpy_minimal_service/service.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - from example_interfaces.srv import AddTwoInts import rclpy @@ -33,20 +31,17 @@ def add_two_ints_callback(request, response): def main(args=None): global g_node - rclpy.init(args=args) try: - g_node = rclpy.create_node('minimal_service') - - srv = g_node.create_service(AddTwoInts, 'add_two_ints', add_two_ints_callback) - srv # Quiet flake8 warnings about unused variable - while rclpy.ok(): - rclpy.spin_once(g_node) - - except KeyboardInterrupt: + with rclpy.init(args=args): + g_node = rclpy.create_node('minimal_service') + + srv = g_node.create_service(AddTwoInts, 'add_two_ints', add_two_ints_callback) + srv # Quiet flake8 warnings about unused variable + while rclpy.ok(): + rclpy.spin_once(g_node) + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/services/minimal_service/examples_rclpy_minimal_service/service_member_function.py b/rclpy/services/minimal_service/examples_rclpy_minimal_service/service_member_function.py index 6eedd736..82d5a0a8 100644 --- a/rclpy/services/minimal_service/examples_rclpy_minimal_service/service_member_function.py +++ b/rclpy/services/minimal_service/examples_rclpy_minimal_service/service_member_function.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - from example_interfaces.srv import AddTwoInts import rclpy @@ -35,16 +33,13 @@ def add_two_ints_callback(self, request, response): def main(args=None): - rclpy.init(args=args) - try: - minimal_service = MinimalService() + with rclpy.init(args=args): + minimal_service = MinimalService() - rclpy.spin(minimal_service) - except KeyboardInterrupt: + rclpy.spin(minimal_service) + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_local_function.py b/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_local_function.py index 88f3c942..d02345e8 100644 --- a/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_local_function.py +++ b/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_local_function.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - import rclpy from rclpy.executors import ExternalShutdownException @@ -21,31 +19,28 @@ def main(args=None): - rclpy.init(args=args) - try: - node = rclpy.create_node('minimal_publisher') - publisher = node.create_publisher(String, 'topic', 10) - - msg = String() - i = 0 - - def timer_callback(): - nonlocal i - msg.data = 'Hello World: %d' % i - i += 1 - node.get_logger().info('Publishing: "%s"' % msg.data) - publisher.publish(msg) - - timer_period = 0.5 # seconds - timer = node.create_timer(timer_period, timer_callback) - timer # Quiet flake8 warnings about unused variable - - rclpy.spin(node) - except KeyboardInterrupt: + with rclpy.init(args=args): + node = rclpy.create_node('minimal_publisher') + publisher = node.create_publisher(String, 'topic', 10) + + msg = String() + i = 0 + + def timer_callback(): + nonlocal i + msg.data = 'Hello World: %d' % i + i += 1 + node.get_logger().info('Publishing: "%s"' % msg.data) + publisher.publish(msg) + + timer_period = 0.5 # seconds + timer = node.create_timer(timer_period, timer_callback) + timer # Quiet flake8 warnings about unused variable + + rclpy.spin(node) + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_member_function.py b/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_member_function.py index 45ae3f5b..5ea61a5d 100644 --- a/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_member_function.py +++ b/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_member_function.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - import rclpy from rclpy.executors import ExternalShutdownException from rclpy.node import Node @@ -39,16 +37,13 @@ def timer_callback(self): def main(args=None): - rclpy.init(args=args) - try: - minimal_publisher = MinimalPublisher() + with rclpy.init(args=args): + minimal_publisher = MinimalPublisher() - rclpy.spin(minimal_publisher) - except KeyboardInterrupt: + rclpy.spin(minimal_publisher) + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_old_school.py b/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_old_school.py index 8873fad9..b4594e49 100644 --- a/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_old_school.py +++ b/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_old_school.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys from time import sleep import rclpy @@ -27,26 +26,23 @@ def main(args=None): - rclpy.init(args=args) - try: - node = rclpy.create_node('minimal_publisher') + with rclpy.init(args=args): + node = rclpy.create_node('minimal_publisher') - publisher = node.create_publisher(String, 'topic', 10) + publisher = node.create_publisher(String, 'topic', 10) - msg = String() + msg = String() - i = 0 - while rclpy.ok(): - msg.data = 'Hello World: %d' % i - i += 1 - node.get_logger().info('Publishing: "%s"' % msg.data) - publisher.publish(msg) - sleep(0.5) # seconds - except KeyboardInterrupt: + i = 0 + while rclpy.ok(): + msg.data = 'Hello World: %d' % i + i += 1 + node.get_logger().info('Publishing: "%s"' % msg.data) + publisher.publish(msg) + sleep(0.5) # seconds + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_lambda.py b/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_lambda.py index 83331f1c..72f1be92 100644 --- a/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_lambda.py +++ b/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_lambda.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - import rclpy from rclpy.executors import ExternalShutdownException @@ -21,20 +19,18 @@ def main(args=None): - rclpy.init(args=args) - try: - node = rclpy.create_node('minimal_subscriber') + with rclpy.init(args=args): + node = rclpy.create_node('minimal_subscriber') - subscription = node.create_subscription( - String, 'topic', lambda msg: node.get_logger().info('I heard: "%s"' % msg.data), 10) - subscription # prevent unused variable warning + subscription = node.create_subscription( + String, 'topic', + lambda msg: node.get_logger().info('I heard: "%s"' % msg.data), 10) + subscription # prevent unused variable warning - rclpy.spin(node) - except KeyboardInterrupt: + rclpy.spin(node) + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_member_function.py b/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_member_function.py index 4346f4ce..ffd5c92e 100644 --- a/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_member_function.py +++ b/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_member_function.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - import rclpy from rclpy.executors import ExternalShutdownException from rclpy.node import Node @@ -37,16 +35,13 @@ def listener_callback(self, msg): def main(args=None): - rclpy.init(args=args) - try: - minimal_subscriber = MinimalSubscriber() + with rclpy.init(args=args): + minimal_subscriber = MinimalSubscriber() - rclpy.spin(minimal_subscriber) - except KeyboardInterrupt: + rclpy.spin(minimal_subscriber) + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_old_school.py b/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_old_school.py index 06bda5fd..70c2376e 100644 --- a/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_old_school.py +++ b/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_old_school.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - import rclpy from rclpy.executors import ExternalShutdownException @@ -30,20 +28,18 @@ def chatter_callback(msg): def main(args=None): global g_node - rclpy.init(args=args) try: - g_node = rclpy.create_node('minimal_subscriber') + with rclpy.init(args=args): + g_node = rclpy.create_node('minimal_subscriber') - subscription = g_node.create_subscription(String, 'topic', chatter_callback, 10) - subscription # prevent unused variable warning + subscription = g_node.create_subscription(String, 'topic', chatter_callback, 10) + subscription # prevent unused variable warning - while rclpy.ok(): - rclpy.spin_once(g_node) - except KeyboardInterrupt: + while rclpy.ok(): + rclpy.spin_once(g_node) + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__': diff --git a/rclpy/topics/pointcloud_publisher/examples_rclpy_pointcloud_publisher/pointcloud_publisher.py b/rclpy/topics/pointcloud_publisher/examples_rclpy_pointcloud_publisher/pointcloud_publisher.py index 8638a51e..b67b9a34 100644 --- a/rclpy/topics/pointcloud_publisher/examples_rclpy_pointcloud_publisher/pointcloud_publisher.py +++ b/rclpy/topics/pointcloud_publisher/examples_rclpy_pointcloud_publisher/pointcloud_publisher.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys - import numpy as np import rclpy @@ -62,14 +60,12 @@ def timer_callback(self): def main(args=None): - rclpy.init(args=args) try: - pc_publisher = PointCloudPublisher() - rclpy.spin(pc_publisher) - except KeyboardInterrupt: + with rclpy.init(args=args): + pc_publisher = PointCloudPublisher() + rclpy.spin(pc_publisher) + except (KeyboardInterrupt, ExternalShutdownException): pass - except ExternalShutdownException: - sys.exit(1) if __name__ == '__main__':