Webots 仿真重置处理器
目标: 在机器人仿真中扩展重置处理器,以便在按下 Webots 重置按钮时重启节点。
教程级别: 进阶
预计时间: 10 分钟
在本教程中,你将学习如何在使用 Webots 的机器人仿真中实现重置处理器。
Webots 的重置按钮会将世界恢复到初始状态并重启控制器。
这个功能很方便,可以快速重置仿真。但在 ROS 2 的上下文中,机器人控制器不会自动重新启动,导致仿真停止。
重置处理器允许你在 Webots 中按下重置按钮时重启特定节点或执行额外操作。
这在需要重置仿真状态或重启特定组件、而又不想完全重启整个 ROS 系统的场景中非常实用。
在继续本教程之前,请确保你已完成以下内容:
- 了解初级教程中涵盖的 ROS 2 节点和话题。
- 了解 Webots 和 ROS 2 及其接口包。
- 熟悉 Webots 机器人仿真设置(基础)。
简单情况下的重置处理器(仅控制器)
Section titled “简单情况下的重置处理器(仅控制器)”在你的包的 launch 文件中,添加 respawn 参数。
def generate_launch_description(): robot_driver = WebotsController( robot_name='my_robot', parameters=[ {'robot_description': robot_description_path} ],
# 每次重置仿真时,控制器会自动重新启动 respawn=True )
# 启动 Webots webots = WebotsLauncher(world=PathJoinSubstitution([package_dir, 'worlds', world]))
return LaunchDescription([ webots, robot_driver ])重置时,Webots 会终止所有驱动节点。
因此,要在重置后重新启动它们,需要将驱动节点的 respawn 属性设置为 True。
这样可以确保驱动节点在重置后正常运行。
多节点的重置处理器(无需关闭)
Section titled “多节点的重置处理器(无需关闭)”如果还有其他节点需要与驱动节点一起启动(例如 ros2_control 节点),可以使用 OnProcessExit 事件处理器:
def get_ros2_control_spawners(*args): # 在此处声明所有必须在仿真重置时重启的节点 ros_control_node = Node( package='controller_manager', executable='spawner', arguments=['diffdrive_controller'] ) return [ ros_control_node ]
def generate_launch_description(): robot_driver = WebotsController( robot_name='my_robot', parameters=[ {'robot_description': robot_description_path} ],
# 每次重置仿真时,控制器会自动重新启动 respawn=True )
# 启动 Webots webots = WebotsLauncher(world=PathJoinSubstitution([package_dir, 'worlds', world]))
# 声明重置处理器,在 robot_driver 退出时重启节点 reset_handler = launch.actions.RegisterEventHandler( event_handler=launch.event_handlers.OnProcessExit( target_action=robot_driver, on_exit=get_ros2_control_spawners, ) )
return LaunchDescription([ webots, robot_driver, reset_handler ] + get_ros2_control_spawners())不能在 ros2_control 节点上使用 respawn 属性,因为 spawner 在启动期间就会退出,而不是在仿真重置时退出。
正确的做法是将节点列表放在一个函数中(例如 get_ros2_control_spawners)。
执行 launch 文件时,该列表中的节点会与其他节点一起启动。
通过 reset_handler,这个函数还被注册为在 robot_driver 节点退出时要执行的操作,而该退出的时刻正对应于在 Webots 界面中重置仿真。
robot_driver 节点仍需将 respawn 属性设置为 True,以便它与 ros2_control 节点一起重启。
需要节点关闭的重置处理器
Section titled “需要节点关闭的重置处理器”使用当前的 ROS 2 launch API,对于需要在重启前关闭节点的 launch 文件(例如包含 Nav2 或 RViz 的场景),无法自动完成重置。
原因是 ROS 2 目前不支持从 launch 文件中关闭特定节点。
有一种变通方案,但需要在按下重置按钮后手动重启节点。
Webots 需要在单独的 launch 文件中启动,不包含其他节点。
def generate_launch_description(): # 启动 Webots webots = WebotsLauncher(world=PathJoinSubstitution([package_dir, 'worlds', world]))
return LaunchDescription([ webots ])第二个 launch 文件需要从另一个进程启动。
它包含所有其他节点,包括机器人控制器/插件、Navigation2 节点、RViz、状态发布器等。
def generate_launch_description(): robot_driver = WebotsController( robot_name='my_robot', parameters=[ {'robot_description': robot_description_path} ] )
ros_control_node = Node( package='controller_manager', executable='spawner', arguments=['diffdrive_controller'] )
nav2_node = IncludeLaunchDescription( PythonLaunchDescriptionSource(os.path.join( get_package_share_directory('nav2_bringup'), 'launch', 'bringup_launch.py')), launch_arguments=[ ('map', nav2_map), ('params_file', nav2_params), ], )
rviz = Node( package='rviz2', executable='rviz2', output='screen' )
# 声明处理器,在 robot_driver 退出时关闭所有节点 shutdown_handler = launch.actions.RegisterEventHandler( event_handler=launch.event_handlers.OnProcessExit( target_action=robot_driver, on_exit=[launch.actions.EmitEvent(event=launch.events.Shutdown())], ) )
return LaunchDescription([ robot_driver, ros_control_node, nav2_node, rviz, shutdown_handler ])第二个 launch 文件中包含一个处理器,在驱动节点退出时(即仿真重置时)触发关闭事件。
按下重置按钮后,需要从命令行手动重启第二个 launch 文件。
在本教程中,你学习了如何在使用 Webots 的机器人仿真中实现重置处理器。
它允许你在 Webots 中按下重置按钮时重启特定节点或执行额外操作。
你根据仿真的复杂程度和节点需求,探索了不同的实现方法。