使用事件处理器
目标: 了解 ROS 2 launch 文件中的事件处理器
教程级别: 中级
时间: 15 分钟
ROS 2 的 launch 系统负责执行和管理用户定义的进程,同时监控这些进程的状态变化,并据此报告和响应。这些状态变化称为事件(event),可以通过向 launch 系统注册事件处理器来处理。为特定事件注册事件处理器,对于监控进程状态非常有用。此外,事件处理器还可以用来定义一组复杂的规则,从而动态修改 launch 行为。
本教程展示了 ROS 2 launch 文件中事件处理器的使用示例。
本教程使用 turtlesim 包。同时,本教程假设你已经创建了一个构建类型为 ament_python、名为 launch_tutorial 的新包。
本教程的代码基于使用替换教程中的示例,并在此基础上做了扩展。
使用事件处理器
Section titled “使用事件处理器”1. 事件处理器示例 launch 文件
Section titled “1. 事件处理器示例 launch 文件”在 launch_tutorial 包的 launch 文件夹中创建一个名为 example_event_handlers_launch.py 的新文件。
from launch import LaunchDescriptionfrom launch.actions import ( DeclareLaunchArgument, EmitEvent, ExecuteProcess, LogInfo, RegisterEventHandler, TimerAction)from launch.conditions import IfConditionfrom launch.event_handlers import ( OnExecutionComplete, OnProcessExit, OnProcessIO, OnProcessStart, OnShutdown)from launch.events import Shutdownfrom launch.substitutions import ( EnvironmentVariable, FindExecutable, LaunchConfiguration, LocalSubstitution, PythonExpression)from launch_ros.actions import Node
def generate_launch_description(): turtlesim_ns = LaunchConfiguration('turtlesim_ns') use_provided_red = LaunchConfiguration('use_provided_red') new_background_r = LaunchConfiguration('new_background_r')
turtlesim_ns_launch_arg = DeclareLaunchArgument( 'turtlesim_ns', default_value='turtlesim1' ) use_provided_red_launch_arg = DeclareLaunchArgument( 'use_provided_red', default_value='False' ) new_background_r_launch_arg = DeclareLaunchArgument( 'new_background_r', default_value='200' )
turtlesim_node = Node( package='turtlesim', namespace=turtlesim_ns, executable='turtlesim_node', name='sim' ) spawn_turtle = ExecuteProcess( cmd=[[ FindExecutable(name='ros2'), ' service call ', turtlesim_ns, '/spawn ', 'turtlesim_msgs/srv/Spawn ', '"{x: 2, y: 2, theta: 0.2}"' ]], shell=True ) change_background_r = ExecuteProcess( cmd=[[ FindExecutable(name='ros2'), ' param set ', turtlesim_ns, '/sim background_r ', '120' ]], shell=True ) change_background_r_conditioned = ExecuteProcess( condition=IfCondition( PythonExpression([ new_background_r, ' == 200', ' and ', use_provided_red ]) ), cmd=[[ FindExecutable(name='ros2'), ' param set ', turtlesim_ns, '/sim background_r ', new_background_r ]], shell=True )
return LaunchDescription([ turtlesim_ns_launch_arg, use_provided_red_launch_arg, new_background_r_launch_arg, turtlesim_node, RegisterEventHandler( OnProcessStart( target_action=turtlesim_node, on_start=[ LogInfo(msg='Turtlesim started, spawning turtle'), spawn_turtle ] ) ), RegisterEventHandler( OnProcessIO( target_action=spawn_turtle, on_stdout=lambda event: LogInfo( msg='Spawn request says "{}"'.format( event.text.decode().strip()) ) ) ), RegisterEventHandler( OnExecutionComplete( target_action=spawn_turtle, on_completion=[ LogInfo(msg='Spawn finished'), change_background_r, TimerAction( period=2.0, actions=[change_background_r_conditioned], ) ] ) ), RegisterEventHandler( OnProcessExit( target_action=turtlesim_node, on_exit=[ LogInfo(msg=(EnvironmentVariable(name='USER'), ' closed the turtlesim window')), EmitEvent(event=Shutdown( reason='Window closed')) ] ) ), RegisterEventHandler( OnShutdown( on_shutdown=[LogInfo( msg=['Launch was asked to shutdown: ', LocalSubstitution('event.reason')] )] ) ), ])在 launch 描述中,定义了针对 OnProcessStart、OnProcessIO、OnExecutionComplete、OnProcessExit 和 OnShutdown 事件的 RegisterEventHandler 动作。
OnProcessStart 事件处理器注册的回调会在 turtlesim 节点启动时触发:先向控制台输出一条日志消息,然后执行 spawn_turtle 动作。
RegisterEventHandler( OnProcessStart( target_action=turtlesim_node, on_start=[ LogInfo(msg='Turtlesim started, spawning turtle'), spawn_turtle ] ) ),OnProcessIO 事件处理器注册的回调会在 spawn_turtle 动作向标准输出写入内容时触发,负责记录 spawn 请求的结果。
RegisterEventHandler( OnProcessIO( target_action=spawn_turtle, on_stdout=lambda event: LogInfo( msg='Spawn request says "{}"'.format( event.text.decode().strip()) ) ) ),OnExecutionComplete 事件处理器注册的回调会在 spawn_turtle 动作完成时触发:先输出一条日志消息,然后依次执行 change_background_r 和 change_background_r_conditioned 动作。
RegisterEventHandler( OnExecutionComplete( target_action=spawn_turtle, on_completion=[ LogInfo(msg='Spawn finished'), change_background_r, TimerAction( period=2.0, actions=[change_background_r_conditioned], ) ] ) ),OnProcessExit 事件处理器注册的回调会在 turtlesim 节点退出时触发:先输出一条日志消息,然后通过 EmitEvent 动作发出 Shutdown 事件。这意味着当用户关闭 turtlesim 窗口时,整个 launch 进程也会随之退出。
RegisterEventHandler( OnProcessExit( target_action=turtlesim_node, on_exit=[ LogInfo(msg=(EnvironmentVariable(name='USER'), ' closed the turtlesim window')), EmitEvent(event=Shutdown( reason='Window closed')) ] ) ),最后,OnShutdown 事件处理器注册的回调会在 launch 系统收到关闭请求时触发,负责输出一条包含关闭原因的日志消息——例如 turtlesim 窗口关闭或用户按下了 ctrl-c。
RegisterEventHandler( OnShutdown( on_shutdown=[LogInfo( msg=['Launch was asked to shutdown: ', LocalSubstitution('event.reason')] )] ) ),进入工作空间的根目录,构建包:
colcon build构建后,请记得 source 工作空间。
现在你可以使用 ros2 launch 命令启动 example_event_handlers_launch.py 文件。
ros2 launch launch_tutorial example_event_handlers_launch.py turtlesim_ns:='turtlesim3' use_provided_red:='True' new_background_r:=200这将执行以下操作:
- 启动一个蓝色背景的 turtlesim 节点
- 生成第二只乌龟
- 将颜色改为紫色
- 如果提供的
background_r参数为200且use_provided_red参数为True,则在两秒后将颜色改为粉色 - 当 turtlesim 窗口关闭时,关闭 launch 文件
此外,它还会在以下时刻输出日志消息:
- turtlesim 节点启动时
- spawn 动作执行时
change_background_r动作执行时change_background_r_conditioned动作执行时- turtlesim 节点退出时
- launch 进程被要求关闭时
launch 文档提供了关于可用事件处理器的详细信息。
在本教程中,你学习了如何在 launch 文件中使用事件处理器,了解了它们的语法和使用示例,并掌握了如何通过事件处理器定义复杂规则来动态修改 launch 行为。