设置重置处理程序
目标: 在按下 Webots 的重置按钮时,在机器人仿真中扩展一个重置处理程序,以重新启动节点。
教程级别: 高级
时间: 10分钟
背景
在本教程中,您将学习如何在 Webots 中的机器人仿真中实现重置处理程序。Webots 的重置按钮会将世界恢复到初始状态并重新启动控制器。这很方便,因为它可以快速重置仿真,但在 ROS 2 的上下文中,机器人控制器不会重新启动,导致仿真停止。重置处理程序允许您在按下 Webots 中的重置按钮时重新启动特定的节点或执行其他操作。这在需要重置仿真状态或重新启动特定组件而无需完全重新启动完整的 ROS 系统的情况下非常有用。
先决条件
在继续本教程之前,请确保您已完成以下内容:
理解了初学者教程中涵盖的 ROS 2 节点和主题内容 教程。
了解 Webots、ROS 2 及其接口包的知识。
熟悉 设置机器人仿真(基础)。
适用于简单情况的重置处理程序(仅限控制器)
在您的包的启动文件中,添加 respawn
参数。
def generate_launch_description():
robot_driver = WebotsController(
robot_name='my_robot',
parameters=[
{'robot_description': robot_description_path}
],
# Every time one resets the simulation the controller is automatically respawned
respawn=True
)
# Starts Webots
webots = WebotsLauncher(world=PathJoinSubstitution([package_dir, 'worlds', world]))
return LaunchDescription([
webots,
robot_driver
])
在重置时,Webots 会关闭所有驱动节点。因此,要在重置后重新启动它们,您应将驱动节点的 respawn
属性设置为 True
。这将确保在重置后驱动节点正常运行。
多节点的重置处理程序(无需关闭节点)
如果还有其他必须与驱动节点一起启动的节点(例如 ros2_control
节点),则可以使用 OnProcessExit
事件处理程序:
def get_ros2_control_spawners(*args):
# Declare here all nodes that must be restarted at simulation reset
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}
],
# Every time one resets the simulation the controller is automatically respawned
respawn=True
)
# Starts Webots
webots = WebotsLauncher(world=PathJoinSubstitution([package_dir, 'worlds', world]))
# Declare the reset handler that respawns nodes when robot_driver exits
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
属性,因为生成器在启动时退出,而不是在重置仿真时退出。相反,我们应该在一个函数中声明节点列表(例如 get_ros2_control_spawners
)。此列表中的节点会在执行启动文件时与其他节点一起启动。通过 reset_handler
,该函数还被声明为在 robot_driver
节点退出时启动的操作,这对应于在 Webots 界面中重置仿真的时刻。robot_driver
节点仍然将 respawn
属性设置为 True
,以便在 ros2_control
节点一起重新启动。
需要节点关闭的重置处理程序
根据当前的 ROS 2 启动 API,在需要在重新启动之前关闭节点的启动文件中,无法使重置工作(例如 Nav2
或 RViz
)。原因是目前,ROS 2 不允许从启动文件中关闭特定节点。有一个解决方案,但需要在按下重置按钮后手动重新启动节点。
Webots 需要在一个特定的启动文件中启动,不包含其他节点。
def generate_launch_description():
# Starts Webots
webots = WebotsLauncher(world=PathJoinSubstitution([package_dir, 'worlds', world]))
return LaunchDescription([
webots
])
必须从另一个进程中启动第二个启动文件。该启动文件包含所有其他节点,包括机器人控制器/插件、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'
)
# Declare the handler that shuts all nodes down when robot_driver exits
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
])
第二个启动文件包含一个处理程序,当驱动节点退出时触发关闭事件(这是仿真重置时的情况)。必须在按下重置按钮后从命令行手动重新启动这个第二个启动文件。