爱折腾-创客智造实验室 - ros2与launch入门教程
ROS2与launch入门教程-目录 说明: 介绍如何制作和使用launch文件来启动ros2节点 相关例程文件可以访问gitee仓库 目录: ROS2与launch入门教程-创建ROS2的launch(启动)文件 ROS2与launch入门教程-使用Launch启动和监控多个节点 ROS2与launch入门教程-使用substitutions ROS2与launch入门教程-launch文件中使用事件处理程序 ROS2与launch入门教程-使用ROS2 launch文件启动大型项目 ROS2与launch入门教程-使用Python、XML 和 YAML格式编写ROS2 launch文件 ROS2与launch入门教程-如何迁移ROS1的launch文件到ROS2
ROS2与launch入门教程-创建ROS2的launch(启动)文件 说明： 介绍创建launch文件以运行复杂的ROS2系统 测试环境: ubuntu 20.04 galactic 创建一个launch文件来启动两个小海龟 准备: 更新软件源 sudo apt update 安装turtlesim sudo apt install ros-galactic-turtlesim 安装rqt sudo apt install ~nros-galactic-rqt* 独立launch文件测试: 创建luanch目录 mkdir -p ~/launch_ws 新建launch文件turtlesim_mimic.launch.py cd ~/launch_ws vim turtlesim_mimic.launch.py 内容如下 #引用launch相关包 from launch import LaunchDescription from launch_ros.actions import Node #定义launch描述 def generate_launch_description(): return LaunchDescription([ #调用节点turtlesim_node,生成第一个小海龟 Node( package='turtlesim', namespace='turtlesim1', executable='turtlesim_node', name='sim' ), #调用节点turtlesim_node,生成第二个小海龟 Node( package='turtlesim', namespace='turtlesim2', executable='turtlesim_node', name='sim' ), #调用节点mimic,实现跟随 Node( package='turtlesim', executable='mimic', name='mimic', remappings=[ ('/input/pose', '/turtlesim1/turtle1/pose'), ('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'), ] ) ]) mimic的/input/pose话题重映射到/turtlesim1/turtle1/pose /output/cmd_vel的话题/turtlesim2/turtle1/cmd_vel 根据海龟1的位置,评估海龟2的速度,并发布给海龟2执行,从而实现海龟2跟随海龟1走同样的路径 启动launch文件 cd ~/launch_ws ros2 launch turtlesim_mimic.launch.py 控制海龟1运行 ros2 topic pub -r 1 /turtlesim1/turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -1.8}}" 效果图： 查看节点 rqt_graph - 效果图：
ROS2与launch入门教程-使用Launch启动和监控多个节点 说明： 介绍使用Launch启动和监控多个节点 launch系统： ROS 2中的launch(启动)系统负责帮助用户描述他们系统的配置，然后按照描述执行它。 系统的配置包括运行什么程序、在哪里运行它们、传递它们的参数以及 ROS 特定的约定，这些约定通过给它们不同的配置，使得在整个系统中重用组件变得容易。 它还负责监视启动的进程的状态，并报告和/或对这些进程的状态变化做出反应。 用 Python 编写的启动文件可以启动和停止不同的节点以及触发和作用于各种事件。 提供这个框架的包是launch_ros，它使用了底层非ROS特定的启动框架。 设计文档详细说明了 ROS 2 launch系统的设计目标（目前并非所有功能都可用）。 步骤： 1.首先要让ROS包知道那里找到launch文件 python包主要修改setup.py 具体内容如 import os from glob import glob from setuptools import setup package_name = 'my_package' setup( # Other parameters ... data_files=[ # ... Other data files # Include all launch files. This is the most important line here! (os.path.join('share', package_name), glob('launch/*launch.py')) ] ) 增加setup的参数data_files内容，指定使用的launch文件格式 C++包修改CMakeLists.txt 具体内容如 # Install launch files. install(DIRECTORY launch DESTINATION share/${PROJECT_NAME}/ ) ament_package()前增加上面代码 2.编写launch文件 launch的文件应该以*launch.py的格式结束，如my_script_launch.py或my_script.launch.py 定义generate_launch_description()，返回launch.LaunchDescription()，以便ros2 launch能调用 代码如： import platform import launch import launch.actions import launch.substitutions import launch_ros.actions env_var_name = 'USER' if platform.system() != 'Windows' else 'USERNAME' def generate_launch_description(): return launch.LaunchDescription([ launch.actions.DeclareLaunchArgument( 'node_prefix', default_value=[launch.substitutions.EnvironmentVariable(env_var_name), '_'], description='Prefix for node names'), launch_ros.actions.Node( package='demo_nodes_cpp', executable='talker', output='screen', name=[launch.substitutions.LaunchConfiguration('node_prefix'), 'talker']), ]) launch文件可以作为独立文件来启动 更常用是使用ros2工具来启动，如 ros2 launch my_package my_script_launch.py 或者作为独立文件启动 ros2 launch my_script_launch.py 更详细的介绍可以查看launch文档和launch的代码 ROS2的python包launch文件测试: 创建工作空间和包 mkdir -p ~/launch_ws/src cd ~/launch_ws/src ros2 pkg create --build-type ament_python test_launch_py 创建luanch目录 mkdir -p ~/launch_ws/src/test_launch_py/launch 拷贝turtlesim_mimic_launch.py cp ~/launch_ws/turtlesim_mimic.launch.py ~/launch_ws/src/test_launch_py/launch/turtlesim_mimic.launch.py 修改setup.py vim ~/launch_ws/src/test_launch_py/setup.py 内容修改为 from setuptools import setup import os from glob import glob package_name = 'test_launch_py' setup( name=package_name, version='0.0.0', packages=[package_name], data_files=[ ('share/ament_index/resource_index/packages', ['resource/' + package_name]), ('share/' + package_name, ['package.xml']), (os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*.launch.py'))), ], install_requires=['setuptools'], zip_safe=True, maintainer='ncnynl', maintainer_email='1043931@qq.com', description='TODO: Package description', license='TODO: License declaration', tests_require=['pytest'], entry_points={ 'console_scripts': [ ], }, ) 指定构建test_launch_py包,并使用symlink的方式 cd ~/launch_ws/ colcon build --symlink-install --packages-select test_launch_py 加载工作空间 . ~/launch_ws/install/local_setup.bash 启动launch文件 ros2 launch test_launch_py turtlesim_mimic.launch.py 控制海龟1运行 ros2 topic pub -r 1 /turtlesim1/turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -1.8}}" ROS2的c++包launch文件测试: 创建ros2包test_launch_cpp cd -p ~/launch_ws/src/ ros2 pkg create --build-type ament_cmake test_launch_cpp 创建luanch目录 mkdir -p ~/launch_ws/src/test_launch_cpp/launch 拷贝之前建立的launch文件 cp ~/launch_ws/turtlesim_mimic.launch.py ~/launch_ws/src/test_launch_cpp/launch/ CMakelist.txt增加内容 install( DIRECTORY launch DESTINATION share/${PROJECT_NAME} ) package.xml增加内容 <exec_depend>launch</exec_depend> <exec_depend>launch_ros</exec_depend> 指定构建test_launch_cpp包,并使用symlink的方式 cd ~/launch_ws/ colcon build --symlink-install --packages-select test_launch_cpp 加载工作空间 . ~/launch_ws/install/local_setup.bash 启动launch文件 ros2 launch test_launch_cpp turtlesim_mimic.launch.py 控制海龟1运行 ros2 topic pub -r 1 /turtlesim1/turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -1.8}}"
ROS2与launch入门教程-使用substitutions 说明： 介绍如何在launch中使用substitutions 背景： launch文件用于启动节点、服务和执行进程。 这组动作可能有参数，这些参数会影响它们的行为。 在描述可重用的启动文件时，可以在参数中使用替换以提供更大的灵活性。 替换是仅在启动描述执行期间评估的变量，可用于获取特定信息，如启动配置、环境变量或评估任意 Python 表达式。 准备 创建名为launch_tutorial的ros2的python包 cd ~/launch_ws/src ros2 pkg create --build-type ament_python launch_tutorial 创建luanch目录 mkdir -p ~/launch_ws/src/launch_tutorial/launch 修改setup.py vim ~/launch_ws/src/launch_tutorial/setup.py 内容修改为 from setuptools import setup import os from glob import glob package_name = 'launch_tutorial' setup( name=package_name, version='0.0.0', packages=[package_name], data_files=[ ('share/ament_index/resource_index/packages', ['resource/' + package_name]), ('share/' + package_name, ['package.xml']), (os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*launch.py'))), ], install_requires=['setuptools'], zip_safe=True, maintainer='ncnynl', maintainer_email='1043931@qq.com', description='TODO: Package description', license='TODO: License declaration', tests_require=['pytest'], entry_points={ 'console_scripts': [ ], }, ) 指定构建launch_tutorial包,并使用symlink的方式 cd ~/launch_ws/ colcon build --symlink-install --packages-select launch_tutorial 加载工作空间 . ~/launch_ws/install/local_setup.bash 父launch文件： 首先，我们将创建一个launch文件，该文件将调用并将参数传递给另一个launch文件。 在 launch_tutorial包的/launch文件夹中创建一个example_main.launch.py文件。 cd ~/launch_ws/src/launch_tutorial/launch vim example_main.launch.py 内容如下 from launch_ros.substitutions import FindPackageShare from launch import LaunchDescription from launch.actions import IncludeLaunchDescription from launch.launch_description_sources import PythonLaunchDescriptionSource from launch.substitutions import PathJoinSubstitution, TextSubstitution def generate_launch_description(): colors = { 'background_r': '200' } return LaunchDescription([ IncludeLaunchDescription( PythonLaunchDescriptionSource([ PathJoinSubstitution([ FindPackageShare('launch_tutorial'), 'launch', 'example_substitutions.launch.py' ]) ]), launch_arguments={ 'turtlesim_ns': 'turtlesim2', 'use_provided_red': 'True', 'new_background_r': TextSubstitution(text=str(colors['background_r'])) }.items() ) ]) 在 example_main.launch.py 文件中，FindPackageShare 替换用于查找 launch_tutorial包的路径。 然后使用 PathJoinSubstitution 替换将路径与 example_substitutions.launch.py 文件名连接到该包路径。 代码块： PathJoinSubstitution([ FindPackageShare('launch_tutorial'), 'launch', 'example_substitutions.launch.py' ]) 带有turtlesim_ns 和use_provided_red 参数的launch_arguments 字典被传递给IncludeLaunchDescription 操作。 TextSubstitution 替换用于使用颜色字典中 background_r 键的值定义 new_background_r 参数。 代码块： launch_arguments={ 'turtlesim_ns': 'turtlesim2', 'use_provided_red': 'True', 'new_background_r': TextSubstitution(text=str(colors['background_r'])) }.items() 创建example_substitutions.launch.py cd ~/launch_ws/src/launch_tutorial/launch vim example_substitutions.launch.py 内容如下 from launch_ros.actions import Node from launch import LaunchDescription from launch.actions import DeclareLaunchArgument, ExecuteProcess, TimerAction from launch.conditions import IfCondition from launch.substitutions import LaunchConfiguration, PythonExpression 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=[[ 'ros2 service call ', turtlesim_ns, '/spawn ', 'turtlesim/srv/Spawn ', '"{x: 2, y: 2, theta: 0.2}"' ]], shell=True ) change_background_r = ExecuteProcess( cmd='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='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, spawn_turtle, change_background_r, TimerAction( period=2.0, actions=[change_background_r_conditioned], ) ]) 在 example_substitutions.launch.py 文件中，定义了 turtlesim_ns、use_provided_red 和 new_background_r 启动配置。 它们用于在上述变量中存储启动参数的值并将它们传递给所需的操作。 这些 LaunchConfiguration 替换允许我们在启动描述的任何部分获取启动参数的值。 DeclareLaunchArgument 用于定义可以从上述启动文件或控制台传递的启动参数。 代码块: 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_ns LaunchConfiguration 替换的 turtlesim_node 节点。 代码块: turtlesim_node = Node( package='turtlesim', namespace=turtlesim_ns, executable='turtlesim_node', name='sim' ) 之后，使用相应的 cmd 参数定义名为 spawn_turtle 的 ExecuteProcess 操作。 此命令调用 turtlesim 节点的 spawn 服务。 此外，LaunchConfiguration 替换用于获取 turtlesim_ns 启动参数的值以构造命令字符串。 代码块: spawn_turtle = ExecuteProcess( cmd=[[ 'ros2 service call ', turtlesim_ns, '/spawn ', 'turtlesim/srv/Spawn ', '"{x: 2, y: 2, theta: 0.2}"' ]], shell=True ) 相同的方法用于更改 turtlesim 背景的红色参数的 change_background_r 和 change_background_r_condition 操作。 不同之处在于，仅当提供的 new_background_r 参数等于 200 并且 use_provided_red 启动参数设置为 True 时才会执行 change_background_r_condition 操作。 IfCondition 内部的评估是使用 PythonExpression 替换完成的。 代码块: change_background_r = ExecuteProcess( cmd='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='ros2 param set ', turtlesim_ns, '/sim background_r ', new_background_r , shell=True ) 编译包 cd ~/launch_ws/ colcon build --symlink-install --packages-select=launch_tutorial 启动launch文件 . ~/launch_ws/install/local_setup.bash ros2 launch launch_tutorial example_main.launch.py 这将执行以下操作： 启动一个蓝色背景的turtlesim节点 生成第二只海龟 将颜色更改为紫色 如果提供的 background_r 参数为 200 且 use_provided_red 参数为 True，则在两秒后将颜色更改为粉红色 修改启动参数 如果要更改提供的启动参数，可以在 example_main.launch.py 的 launch_arguments 字典中更新它们 或者使用首选参数启动 example_substitutions.launch.py。 要查看可能提供给启动文件的参数，请运行以下命令： ros2 launch launch_tutorial example_substitutions.launch.py --show-args 这将显示可能提供给启动文件的参数及其默认值 Arguments (pass arguments as '<name>:=<value>'): 'turtlesim_ns': no description given (default: 'turtlesim1') 'use_provided_red': no description given (default: 'False') 'new_background_r': no description given (default: '200') 现在您可以将所需的参数传递给启动文件，如下所示： ros2 launch launch_tutorial example_substitutions.launch.py turtlesim_ns:='turtlesim3' use_provided_red:='True' new_background_r:=200
ROS2与launch入门教程-launch文件中使用事件处理程序 说明： 本教程展示了ROS2launch文件中事件处理程序的使用示例 背景： ROS2 中的 Launch 是一个执行和管理用户定义流程的系统。 它负责监控它启动的进程的状态，以及报告和响应这些进程的状态变化。 这些更改称为事件，可以通过向启动系统注册事件处理程序来处理。 可以为特定事件注册事件处理程序，并可用于监视进程的状态。 此外，它们可用于定义一组复杂的规则，可用于动态修改启动文件。 使用事件处理 新建example_event_handlers.launch.py文件 cd ~/launch_ws/src/launch_tutorial/launch vim example_event_handlers.launch.py 内容如下 from launch_ros.actions import Node from launch import LaunchDescription from launch.actions import (DeclareLaunchArgument, EmitEvent, ExecuteProcess, LogInfo, RegisterEventHandler, TimerAction) from launch.conditions import IfCondition from launch.event_handlers import (OnExecutionComplete, OnProcessExit, OnProcessIO, OnProcessStart, OnShutdown) from launch.events import Shutdown from launch.substitutions import (EnvironmentVariable, FindExecutable, LaunchConfiguration, LocalSubstitution, PythonExpression) 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/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')] )] ) ), ]) 启动描述中定义了 OnProcessStart、OnProcessIO、OnExecutionComplete、OnProcessExit 和 OnShutdown 事件的 RegisterEventHandler 操作。 OnProcessStart 事件处理程序用于注册一个回调函数，该函数在 turtlesim 节点启动时执行。 它会向控制台记录一条消息，并在 turtlesim 节点启动时执行 spawn_turtle 操作。 代码块: RegisterEventHandler( OnProcessStart( target_action=turtlesim_node, on_start=[ LogInfo(msg='Turtlesim started, spawning turtle'), spawn_turtle ] ) ), OnProcessIO 事件处理程序用于注册一个回调函数，该回调函数在 spawn_turtle 操作写入其标准输出时执行。 它记录生成请求的结果。 代码块: RegisterEventHandler( OnProcessIO( target_action=spawn_turtle, on_stdout=lambda event: LogInfo( msg='Spawn request says "{}"'.format( event.text.decode().strip()) ) ) ), OnExecutionComplete 事件处理程序用于注册在 spawn_turtle 操作完成时执行的回调函数。 它将一条消息记录到控制台并在 spawn 操作完成时执行 change_background_r 和 change_background_r_condition 操作。 代码块: 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 操作以在 turtlesim 节点退出时发出 Shutdown 事件。 这意味着当turtlesim窗口关闭时启动过程将关闭。 代码块: RegisterEventHandler( OnProcessExit( target_action=turtlesim_node, on_exit=[ LogInfo(msg=(EnvironmentVariable(name='USER'), ' closed the turtlesim window')), EmitEvent(event=Shutdown( reason='Window closed')) ] ) ), 最后，OnShutdown 事件处理程序用于注册一个回调函数，该函数在启动文件被要求关闭时执行。 它会向控制台记录为什么要求关闭启动文件的消息。 它会记录关闭原因的消息，例如关闭 turtlesim 窗口或用户发出的 ctrl-c 信号。 代码块: RegisterEventHandler( OnShutdown( on_shutdown=[LogInfo( msg=['Launch was asked to shutdown: ', LocalSubstitution('event.reason')] )] ) ), 指定构建test_launch_py包,并使用symlink的方式 cd ~/launch_ws/ colcon build --symlink-install --packages-select launch_tutorial 加载工作空间 . ~/launch_ws/install/local_setup.bash 测试: 启动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窗口关闭时关闭启动文件 此外，它会在以下情况下将消息记录到控制台： turtlesim 节点启动 执行生成动作 执行 change_background_r 动作 执行 change_background_r_condition 动作 turtlesim 节点退出 启动过程被要求关闭。
ROS2与launch入门教程-使用ROS2 launch文件启动大型项目 说明: 学习使用ROS 2 launch文件管理大型项目的最佳实践 背景： 本教程描述了为大型项目编写启动文件的一些技巧。 重点是如何构建launch文件，以便在不同情况下尽可能多地重用它们。 此外，它还涵盖了不同 ROS 2 启动工具的使用示例，例如参数、YAML 文件、重新映射、命名空间、默认参数和 RViz 配置。 介绍: 机器人上的大型应用程序通常涉及多个相互连接的节点，每个节点都可以有许多参数。 在海龟模拟器中模拟多只海龟就是一个很好的例子。 海龟模拟由多个海龟节点、world配置以及 TF 广播器和侦听器节点组成。 在所有节点之间，存在大量影响这些节点行为和外观的 ROS 参数。 ROS 2 launch文件允许我们在一个地方启动所有节点并设置相应的参数。 在教程结束时，您将在 launch_tutorial 包中构建 launch_turtlesim.launch.py 启动文件。 这个启动文件会调出不同的节点，负责模拟两个turtlesim模拟，启动TF广播器和监听器，加载参数，启动一个RViz配置。 在本教程中，我们将介绍这个启动文件和使用的所有相关功能。 顶层结构 编写启动文件过程中的目标之一应该是使它们尽可能可重用。 这可以通过将相关节点和配置集群到单独的启动文件中来完成。 之后，可以编写专用于特定配置的顶级启动文件。 这将允许在完全不更改启动文件的情况下在相同的机器人之间移动。 即使是从真正的机器人移动到模拟机器人这样的变化，也只需进行少量更改即可完成。 我们现在将讨论使这成为可能的顶级启动文件结构。 首先，我们将创建一个launch文件，该文件将调用单独的启动文件。 为此，让我们在 launch_tutorial 包的 /launch 文件夹中创建一个 launch_turtlesim.launch.py 文件。 cd ~/launch_ws/src/launch_tutorial/launch vim launch_turtlesim.launch.py 内容如下： import os from ament_index_python.packages import get_package_share_directory from launch import LaunchDescription from launch.actions import IncludeLaunchDescription from launch.launch_description_sources import PythonLaunchDescriptionSource def generate_launch_description(): turtlesim_world_1 = IncludeLaunchDescription( PythonLaunchDescriptionSource([os.path.join( get_package_share_directory('launch_tutorial'), 'launch'), '/turtlesim_world_1.launch.py']) ) turtlesim_world_2 = IncludeLaunchDescription( PythonLaunchDescriptionSource([os.path.join( get_package_share_directory('launch_tutorial'), 'launch'), '/turtlesim_world_2.launch.py']) ) broadcaster_listener_nodes = IncludeLaunchDescription( PythonLaunchDescriptionSource([os.path.join( get_package_share_directory('launch_tutorial'), 'launch'), '/broadcaster_listener.launch.py']), launch_arguments={'target_frame': 'carrot1'}.items(), ) mimic_node = IncludeLaunchDescription( PythonLaunchDescriptionSource([os.path.join( get_package_share_directory('launch_tutorial'), 'launch'), '/mimic.launch.py']) ) fixed_frame_node = IncludeLaunchDescription( PythonLaunchDescriptionSource([os.path.join( get_package_share_directory('launch_tutorial'), 'launch'), '/fixed_broadcaster.launch.py']) ) rviz_node = IncludeLaunchDescription( PythonLaunchDescriptionSource([os.path.join( get_package_share_directory('launch_tutorial'), 'launch'), '/turtlesim_rviz.launch.py']) ) return LaunchDescription([ turtlesim_world_1, turtlesim_world_2, broadcaster_listener_nodes, mimic_node, fixed_frame_node, rviz_node ]) 此启动文件包括一组其他启动文件。 这些包含的启动文件中的每一个都包含节点、参数和可能的嵌套包含，它们与系统的一个部分有关。 确切地说，我们推出了两个turtlesim 模拟世界，TF 广播器、TF 监听器、模仿器、固定帧广播器和 RViz 节点。 设计提示：顶级启动文件应该很短，包含与应用程序的子组件相对应的其他文件的包含，以及经常更改的参数。 用以下方式编写启动文件可以很容易地换出系统的一部分，我们稍后会看到。 但是，由于性能和使用原因，某些节点或启动文件必须单独启动。 设计提示：在决定您的应用程序需要多少顶级启动文件时，请注意权衡取舍。 参数： 我们将首先编写一个启动文件，该文件将启动我们的第一个 turtlesim 模拟。 1.首先，创建一个名为 turtlesim_world_1.launch.py 的新文件 cd ~/launch_ws/src/launch_tutorial/launch vim turtlesim_world_1.launch.py 内容如下： from launch import LaunchDescription from launch.actions import DeclareLaunchArgument from launch.substitutions import LaunchConfiguration, TextSubstitution from launch_ros.actions import Node def generate_launch_description(): background_r_launch_arg = DeclareLaunchArgument( 'background_r', default_value=TextSubstitution(text='0') ) background_g_launch_arg = DeclareLaunchArgument( 'background_g', default_value=TextSubstitution(text='84') ) background_b_launch_arg = DeclareLaunchArgument( 'background_b', default_value=TextSubstitution(text='122') ) return LaunchDescription([ background_r_launch_arg, background_g_launch_arg, background_b_launch_arg, Node( package='turtlesim', executable='turtlesim_node', name='sim', parameters=[{ 'background_r': LaunchConfiguration('background_r'), 'background_g': LaunchConfiguration('background_g'), 'background_b': LaunchConfiguration('background_b'), }] ), ]) 此启动文件启动 turtlesim_node 节点，该节点启动 turtlesim 模拟，模拟配置参数已定义并传递给节点。 2.从YAML 文件加载参数 在第二次启动中，我们将使用不同的配置启动第二次 turtlesim 模拟。 现在创建一个 turtlesim_world_2.launch.py 文件。 cd ~/launch_ws/src/launch_tutorial/launch vim turtlesim_world_2.launch.py 内容如下： import os from ament_index_python.packages import get_package_share_directory from launch import LaunchDescription from launch_ros.actions import Node def generate_launch_description(): config = os.path.join( get_package_share_directory('launch_tutorial'), 'config', 'turtlesim.yaml' ) return LaunchDescription([ Node( package='turtlesim', executable='turtlesim_node', namespace='turtlesim2', name='sim', parameters=[config] ) ]) 此启动文件将使用直接从 YAML 配置文件加载的参数值启动相同的 turtlesim_node。 在 YAML 文件中定义参数和参数可以轻松存储和加载大量变量。 此外，YAML 文件可以很容易地从当前的 ros2 参数列表中导出。 要了解如何执行此操作，请参阅了解 ROS 2 参数教程。 现在让我们在包的 /config 文件夹中创建一个配置文件，turtlesim.yaml，它将由我们的启动文件加载。 mkdir -p ~/launch_ws/src/launch_tutorial/config cd ~/launch_ws/src/launch_tutorial/config vim turtlesim.yaml 内容如下： /turtlesim2/sim: ros__parameters: background_b: 255 background_g: 86 background_r: 150 如果我们现在启动 turtlesim_world_2.launch.py 启动文件，我们将使用预配置的背景颜色启动 turtlesim_node。 要了解有关使用参数和使用 YAML 文件的更多信息，请查看了解 ROS 2 参数教程。 3.在 YAML 文件中使用通配符 有时我们想在多个节点中设置相同的参数。 这些节点可能具有不同的命名空间或名称，但仍具有相同的参数。 定义显式定义命名空间和节点名称的单独 YAML 文件效率不高。 一种解决方案是使用通配符，作为文本值中未知字符的替换，将参数应用于几个不同的节点。 现在让我们创建一个类似于turtlesim_world_2.launch.py 的新turtlesim_world_3.launch.py 文件，以包含更多的turtlesim_node 节点。 cd ~/launch_ws/src/launch_tutorial/launch vim turtlesim_world_3.launch.py 增加如下内容 ... Node( package='turtlesim', executable='turtlesim_node', namespace='turtlesim3', name='sim', parameters=[config] ) 然而，加载相同的 YAML 文件不会影响第三个 turtlesim 世界的外观。 原因是它的参数存储在另一个命名空间下，如下所示： /turtlesim3/sim: background_b background_g background_r 因此，我们可以使用通配符语法，而不是为使用相同参数的同一节点创建新配置。 /** 将分配每个节点中的所有参数，尽管节点名称和命名空间不同。 我们现在将按照以下方式更新 /config 文件夹中的 turtlesim.yaml： /**: ros__parameters: background_b: 255 background_g: 86 background_r: 150 现在在我们的主启动文件中包含 turtlesim_world_3.launch.py 启动描述。 在我们的启动描述中使用该配置文件会将 background_b、background_g 和 background_r 参数分配给 turtlesim3/sim 和 turtlesim2/sim 节点中的指定值。 命名空间 您可能已经注意到，我们在 turtlesim_world_2.launch.py 文件中定义了 turlesim 世界的命名空间。 唯一的命名空间允许系统启动两个相似的节点，而不会出现节点名或主题名冲突。 namespace='turtlesim2', 但是，如果启动文件包含大量节点，则为每个节点定义命名空间可能会变得乏味。 为了解决这个问题，可以使用 PushRosNamespace 操作为每个启动文件描述定义全局命名空间。 每个嵌套节点都会自动继承该命名空间。 为此，首先，我们需要从 turtlesim_world_2.launch.py 文件中删除 namespace='turtlesim2' 行。 之后，我们需要更新 launch_turtlesim.launch.py 以包含以下行： from launch.actions import GroupAction from launch_ros.actions import PushRosNamespace ... turtlesim_world_2 = IncludeLaunchDescription( PythonLaunchDescriptionSource([os.path.join( get_package_share_directory('launch_tutorial'), 'launch'), '/turtlesim_world_2.launch.py']) ) turtlesim_world_2_with_namespace = GroupAction( actions=[ PushRosNamespace('turtlesim2'), turtlesim_world_2, ] ) 最后，我们在 return LaunchDescription 语句中将 turtlesim_world_2 替换为 turtlesim_world_2_with_namespace。 因此，turtlesim_world_2.launch.py 启动描述中的每个节点都会有一个 turtlesim2 命名空间。 重用节点 现在创建一个 broadcaster_listener.launch.py 文件。 cd ~/launch_ws/src/launch_tutorial/launch vim broadcaster_listener.launch.py 内容如下： from launch import LaunchDescription from launch.actions import DeclareLaunchArgument from launch.substitutions import LaunchConfiguration from launch_ros.actions import Node def generate_launch_description(): return LaunchDescription([ DeclareLaunchArgument( 'target_frame', default_value='turtle1', description='Target frame name.' ), Node( package='turtle_tf2_py', executable='turtle_tf2_broadcaster', name='broadcaster1', parameters=[ {'turtlename': 'turtle1'} ] ), Node( package='turtle_tf2_py', executable='turtle_tf2_broadcaster', name='broadcaster2', parameters=[ {'turtlename': 'turtle2'} ] ), Node( package='turtle_tf2_py', executable='turtle_tf2_listener', name='listener', parameters=[ {'target_frame': LaunchConfiguration('target_frame')} ] ), ]) - 在这个文件中，我们用默认值turtle1 声明了target_frame 启动参数。 默认值意味着启动文件可以接收一个参数转发给它的节点，或者如果没有提供参数，它会将默认值传递给它的节点。 之后，我们在启动期间使用不同的名称和参数两次使用 turtle_tf2_broadcaster 节点。 这允许我们复制同一个节点而不会发生冲突。 我们还启动了一个 turtle_tf2_listener 节点并设置了我们在上面声明和获取的 target_frame 参数。 参数覆盖 回想一下，我们在顶级启动文件中调用了 broadcaster_listener.launch.py 文件。 除此之外，我们还向它传递了 target_frame 启动参数，如下所示： broadcaster_listener_nodes = IncludeLaunchDescription( PythonLaunchDescriptionSource([os.path.join( get_package_share_directory('launch_tutorial'), 'launch'), '/broadcaster_listener.launch.py']), launch_arguments={'target_frame': 'carrot1'}.items(), ) 此语法允许我们将默认目标目标框架更改为carrot1。 如果您希望turtle2 跟随turtle1 而不是carrot1，只需删除定义launch_arguments 的行。 这将为 target_frame 分配其默认值，即 turtle1。 重新映射 现在创建一个mimic.launch.py 文件 cd ~/launch_ws/src/launch_tutorial/launch vim mimic.launch.py 内容如下： from launch import LaunchDescription from launch_ros.actions import Node def generate_launch_description(): return LaunchDescription([ Node( package='turtlesim', executable='mimic', name='mimic', remappings=[ ('/input/pose', '/turtle2/pose'), ('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'), ] ) ]) 该启动文件将启动模拟节点，该节点将向一个turtlesim 发出命令以跟随另一个。 该节点旨在接收话题/输入/姿势上的目标姿势。 在我们的例子中，我们想要从 /turtle2/pose 话题重新映射目标姿势。 最后，我们将 /output/cmd_vel 话题重新映射到 /turtlesim2/turtle1/cmd_vel。 这样，我们的turtlesim2 模拟世界中的turtle1 将跟随我们最初的turtlesim 世界中的turtle2。 配置文件 现在让我们创建一个名为 turtlesim_rviz.launch.py 的文件 cd ~/launch_ws/src/launch_tutorial/launch vim turtlesim_rviz.launch.py 内容如下： import os from ament_index_python.packages import get_package_share_directory from launch import LaunchDescription from launch_ros.actions import Node def generate_launch_description(): rviz_config = os.path.join( get_package_share_directory('turtle_tf2_py'), 'rviz', 'turtle_rviz.rviz' ) return LaunchDescription([ Node( package='rviz2', executable='rviz2', name='rviz2', arguments=['-d', rviz_config] ) ]) 此启动文件将使用在 turtle_tf2_py 包中定义的配置文件启动 RViz。 此 RViz 配置将设置世界框架，启用 TF 可视化，并以自上而下的视图启动 RViz。 环境变量 现在让我们在包中创建最后一个名为 fixed_broadcaster.launch.py 的启动文件 cd ~/launch_ws/src/launch_tutorial/launch vim fixed_broadcaster.launch.py 内容如下： from launch import LaunchDescription from launch.actions import DeclareLaunchArgument from launch.substitutions import EnvironmentVariable, LaunchConfiguration from launch_ros.actions import Node def generate_launch_description(): return LaunchDescription([ DeclareLaunchArgument( 'node_prefix', default_value=[EnvironmentVariable('USER'), '_'], description='prefix for node name' ), Node( package='turtle_tf2_py', executable='fixed_frame_tf2_broadcaster', name=[LaunchConfiguration('node_prefix'), 'fixed_broadcaster'], ), ]) 该启动文件显示了在启动文件中可以调用环境变量的方式。 环境变量可用于定义或推送命名空间，以区分不同计算机或机器人上的节点。 重新编译： 打开 setup.py 并添加以下行，以便安装 launch/ 文件夹中的启动文件和 config/ 中的配置文件。 cd ~/launch_ws/src/launch_tutorial/ vim setup.py data_files 字段现在应该如下所示： data_files=[ ... (os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*.launch.py'))), (os.path.join('share', package_name, 'config'), glob(os.path.join('config', '*.yaml'))), ], 指定构建launch_tutorial 包,并使用symlink的方式 cd ~/launch_ws/ colcon build --symlink-install --packages-select launch_tutorial 加载工作空间 . ~/launch_ws/install/local_setup.bash 要最终查看我们的代码的结果，请构建包并使用以下命令启动顶级启动文件： ros2 launch launch_tutorial launch_turtlesim.launch.py 您现在将看到两个turtlesim 模拟已启动。 第一个有两只乌龟，第二个有一只。 在第一个模拟中，turtle2 生成在世界的左下角。 它的目标是到达相对于turtle1 框架在x 轴上5 米远的carrot1 框架。 第二个中的turtlesim2/turtle1 旨在模仿turtle2 的行为。 如果要控制turtle1，请运行teleop 节点。 ros2 run turtlesim turtle_teleop_key 效果图： 除此之外，RViz 应该已经启动。 它将显示相对于世界框架的所有海龟框架，其原点位于左下角。
ROS2与launch入门教程-使用Python、XML 和 YAML格式编写ROS2 launch文件
ROS2与launch入门教程-使用Python、XML 和 YAML格式编写ROS2 launch文件 说明： ROS 2 launch文件可以用 Python、XML 和 YAML 编写。 本指南展示了如何使用这些不同的格式来完成相同的任务，并讨论了何时使用每种格式。 launch文件 下面是一个用 Python、XML 和 YAML 实现的启动文件。 每个启动文件执行以下操作： 使用默认值设置命令行参数 包含另一个启动文件 在另一个命名空间中包含另一个启动文件 启动一个节点并设置它的命名空间 启动一个节点，设置其命名空间，并在该节点中设置参数（使用 args） 创建一个节点以将消息从一个主题重新映射到另一个主题 Python版本 # example.launch.py import os from ament_index_python import get_package_share_directory from launch import LaunchDescription from launch.actions import DeclareLaunchArgument from launch.actions import IncludeLaunchDescription from launch.actions import GroupAction from launch.launch_description_sources import PythonLaunchDescriptionSource from launch.substitutions import LaunchConfiguration from launch.substitutions import TextSubstitution from launch_ros.actions import Node from launch_ros.actions import PushRosNamespace def generate_launch_description(): # args that can be set from the command line or a default will be used background_r_launch_arg = DeclareLaunchArgument( "background_r", default_value=TextSubstitution(text="0") ) background_g_launch_arg = DeclareLaunchArgument( "background_g", default_value=TextSubstitution(text="255") ) background_b_launch_arg = DeclareLaunchArgument( "background_b", default_value=TextSubstitution(text="0") ) chatter_ns_launch_arg = DeclareLaunchArgument( "chatter_ns", default_value=TextSubstitution(text="my/chatter/ns") ) # include another launch file launch_include = IncludeLaunchDescription( PythonLaunchDescriptionSource( os.path.join( get_package_share_directory('demo_nodes_cpp'), 'launch/topics/talker_listener.launch.py')) ) # include another launch file in the chatter_ns namespace launch_include_with_namespace = GroupAction( actions=[ # push_ros_namespace to set namespace of included nodes PushRosNamespace(LaunchConfiguration('chatter_ns')), IncludeLaunchDescription( PythonLaunchDescriptionSource( os.path.join( get_package_share_directory('demo_nodes_cpp'), 'launch/topics/talker_listener.launch.py')) ), ] ) # start a turtlesim_node in the turtlesim1 namespace turtlesim_node = Node( package='turtlesim', namespace='turtlesim1', executable='turtlesim_node', name='sim' ) # start another turtlesim_node in the turtlesim2 namespace # and use args to set parameters turtlesim_node_with_parameters = Node( package='turtlesim', namespace='turtlesim2', executable='turtlesim_node', name='sim', parameters=[{ "background_r": LaunchConfiguration('background_r'), "background_g": LaunchConfiguration('background_g'), "background_b": LaunchConfiguration('background_b'), }] ) # perform remap so both turtles listen to the same command topic forward_turtlesim_commands_to_second_turtlesim_node = Node( package='turtlesim', executable='mimic', name='mimic', remappings=[ ('/input/pose', '/turtlesim1/turtle1/pose'), ('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'), ] ) return LaunchDescription([ background_r_launch_arg, background_g_launch_arg, background_b_launch_arg, chatter_ns_launch_arg, launch_include, launch_include_with_namespace, turtlesim_node, turtlesim_node_with_parameters, forward_turtlesim_commands_to_second_turtlesim_node, ]) XML版本 <launch> <arg name="background_r" default="0"/> <arg name="background_g" default="255"/> <arg name="background_b" default="0"/> <arg name="chatter_ns" default="my/chatter/ns"/> <include file="$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener.launch.py"/> <group> <push_ros_namespace namespace="$(var chatter_ns)"/> <include file="$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener.launch.py"/> </group> <node pkg="turtlesim" exec="turtlesim_node" name="sim" namespace="turtlesim1"/> <node pkg="turtlesim" exec="turtlesim_node" name="sim" namespace="turtlesim2"> </node> <node pkg="turtlesim" exec="mimic" name="mimic"> <remap from="/input/pose" to="/turtlesim1/turtle1/pose"/> <remap from="/output/cmd_vel" to="/turtlesim2/turtle1/cmd_vel"/> </node> </launch> YAML版本 # example.launch.yaml launch: # args that can be set from the command line or a default will be used - arg: name: "background_r" default: "0" - arg: name: "background_g" default: "255" - arg: name: "background_b" default: "0" - arg: name: "chatter_ns" default: "my/chatter/ns" # include another launch file - include: file: "$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener.launch.py" # include another launch file in the chatter_ns namespace - group: - push_ros_namespace: namespace: "$(var chatter_ns)" - include: file: "$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener.launch.py" # start a turtlesim_node in the turtlesim1 namespace - node: pkg: "turtlesim" exec: "turtlesim_node" name: "sim" namespace: "turtlesim1" # start another turtlesim_node in the turtlesim2 namespace and use args to set parameters - node: pkg: "turtlesim" exec: "turtlesim_node" name: "sim" namespace: "turtlesim2" param: - name: "background_r" value: "$(var background_r)" - name: "background_g" value: "$(var background_g)" - name: "background_b" value: "$(var background_b)" # perform remap so both turtles listen to the same command topic - node: pkg: "turtlesim" exec: "mimic" name: "mimic" remap: - from: "/input/pose" to: "/turtlesim1/turtle1/pose" - from: "/output/cmd_vel" to: "/turtlesim2/turtle1/cmd_vel" 从命令行使用 Launch 文件 启动launch文件 上面的任何启动文件都可以使用 ros2 启动运行。 要在本地尝试它们，您可以创建一个新包并使用 ros2 launch <package_name> <launch_file_name> 或通过指定启动文件的路径直接运行文件 ros2 launch <path_to_launch_file> 2.设置参数 要设置传递给启动文件的参数，您应该使用 key:=value 语法。 例如，您可以通过以下方式设置 background_r 的值： ros2 launch <package_name> <launch_file_name> background_r:=255 或者 ros2 launch <path_to_launch_file> background_r:=255 3.控制海龟 ros2 run turtlesim turtle_teleop_key --ros-args --remap __ns:=/turtlesim1 如何选择格式 ROS1 中的启动文件是用 XML 编写的，因此来自 ROS 1 的人可能最熟悉 XML。 要查看发生了什么变化，您可以访问将启动文件从 ROS 1 迁移到 ROS 2。 对于大多数应用程序，选择哪种 ROS 2 启动格式取决于开发人员的偏好。 但是，如果您的启动文件需要 XML 或 YAML 无法实现的灵活性，您可以使用 Python 编写启动文件。 由于以下两个原因，使用 Python 启动 ROS 2 更加灵活： Python 是一种脚本语言，因此您可以在启动文件中利用该语言及其库。 ros2/launch（一般启动功能）和 ros2/launch_ros（ROS 2 特定启动功能）是用 Python 编写的，因此您对 XML 和 YAML 可能未公开的启动功能具有较低级别的访问权限。 但是，用 Python 编写的启动文件可能比用 XML 或 YAML 编写的启动文件更复杂和冗长。
ROS2与launch入门教程-如何迁移ROS1的launch文件到ROS2 说明： 介绍如何编写 XML 启动文件以便从 ROS 1 轻松迁移。 ###将标签从 ROS 1 迁移到 ROS 2### launch标签 在 ROS 1 中可用。 launch 是任何 ROS 2 启动 XML 文件的根元素。 node标签 在 ROS 1 中可用。 启动一个新节点。 与 ROS 1 的区别： type 属性现在是 exec。 ns 属性现在是命名空间。 以下属性不可用：machine、respawn_delay、clear_params。 示例： <launch> <node pkg="demo_nodes_cpp" exec="talker"/> <node pkg="demo_nodes_cpp" exec="listener"/> </launch> param标签 在 ROS 1 中可用。 用于将参数传递给节点。 ROS 2 中没有全局参数的概念，因此只能嵌套在node标签中使用。 ROS 2 不支持某些属性：type, textfile, binfile, executable, command。 示例1： <launch> <node pkg="demo_nodes_cpp" exec="parameter_event"> </node> </launch> 示例1： <node pkg="my_package" exec="my_executable" name="my_node"> </node> 参数分组 在 ROS 2 中，允许嵌套 param 标签。 例如： <node pkg="my_package" exec="my_executable" name="my_node" ns="/an_absoulute_ns"> </node> 这将创建两个参数： 一个值为 1 的 group1.group2.my_param，由节点 /an_absolute_ns/my_node 托管。 由节点 /an_absolute_ns/my_node 托管的值为 2 的 group1.another_param。 也可以使用完整的参数名称： <node pkg="my_package" exec="my_executable" name="my_node" ns="/an_absoulute_ns"> </node> rosparam标签 在 ROS 1 中可用。 从 yaml 文件加载参数。 它已被 param 标记中的 from 属性替换。 示例： <node pkg="my_package" exec="my_executable" name="my_node" ns="/an_absoulute_ns"> </node> remap标签 在 ROS 1 中可用。 用于将重映射规则传递给节点。 它只能在节点标签中使用。 示例： <launch> <node pkg="demo_nodes_cpp" exec="talker"> <remap from="chatter" to="my_topic"/> </node> <node pkg="demo_nodes_cpp" exec="listener"> <remap from="chatter" to="my_topic"/> </node> </launch> include标签： 在 ROS 1 中可用。 允许包含另一个启动文件。 与 ROS 1 的区别： 在 ROS 1 中可用，包含的内容是有范围的。 在 ROS 2 中，它不是。 Nest 包含在组标签中以限定它们的范围。 不支持 ns 属性。 有关解决方法，请参见 push_ros_namespace 标记的示例。 嵌套在包含标签中的 arg 标签不支持条件（如果或除非）。 不支持嵌套的 env 标签。 可以使用 set_env 和 unset_env 代替。 不支持 clear_params 和 pass_all_args 属性。 arg标签 在 ROS 1 中可用。 arg 用于声明启动参数，或在使用包含标签时传递参数。 与 ROS 1 的区别： 不允许使用 value 属性。 为此使用 let 标签。 doc 现在是描述。 当嵌套在包含标签中时，不允许使用 if 和 unless 属性。 - 示例： <launch> <arg name="topic_name" default="chatter"/> <node pkg="demo_nodes_cpp" exec="talker"> <remap from="chatter" to="$(var topic_name)"/> </node> <node pkg="demo_nodes_cpp" exec="listener"> <remap from="chatter" to="$(var topic_name)"/> </node> </launch> - 通过命令行传递参数 env标签 在 ROS 1 中可用。 设置环境变量。 它已被 env、set_env 和 unset_env 取代： env 只能嵌套在节点或可执行标签中使用。 不支持 if 和 unless 标签。 set_env 可以嵌套在根标签启动或组标签中。 它接受与 env 相同的属性，以及 if 和 unless 标记。 unset_env 取消设置环境变量。 它接受名称属性和条件。 - 示例： <launch> <set_env name="MY_ENV_VAR" value="MY_VALUE" if="CONDITION_A"/> <set_env name="ANOTHER_ENV_VAR" value="ANOTHER_VALUE" unless="CONDITION_B"/> <set_env name="SOME_ENV_VAR" value="SOME_VALUE"/> <node pkg="MY_PACKAGE" exec="MY_EXECUTABLE" name="MY_NODE"> <env name="NODE_ENV_VAR" value="SOME_VALUE"/> </node> <unset_env name="MY_ENV_VAR" if="CONDITION_A"/> <node pkg="ANOTHER_PACKAGE" exec="ANOTHER_EXECUTABLE" name="ANOTHER_NODE"/> <unset_env name="ANOTHER_ENV_VAR" unless="CONDITION_B"/> <unset_env name="SOME_ENV_VAR"/> </launch> group标签 在 ROS 1 中可用。 允许限制启动配置的范围。 通常与 let、include 和 push_ros_namespace 标签一起使用。 与 ROS 1 的区别： 没有 ns 属性。 请参阅新的 push_ros_namespace 标记作为解决方法。 clear_params 属性不可用。 它不接受 remap 或 param 标签作为子标签。 - launch-prefix配置会影响executable和node标签的操作。 - 如果 use_time_prefix_in_talker 参数为 1，此示例将使用时间作为前缀，仅适用于说话者。 - 示例： machine标签 不再支持 test标签 不再支持 ###ROS 2 中的新标签### set_env and unset_env标签 查看env标签 push_ros_namespace标签 include 和 group 标签不接受 ns 属性。 此操作可用作解决方法： 示例： <!-Other tags--> <group> <push_ros_namespace namespace="my_ns"/> <push_ros_namespace namespace="another_ns"/> <push_ros_namespace namespace="/absolute_ns"/> <node pkg="my_pkg" exec="my_executable" name="my_node" ns="/asd"/> </group> <!-Other tags--> let标签 它是用 value 属性替换 arg 标签。 示例： <let var="foo" value="asd"/> executable标签 它允许运行任何可执行文件 示例： <executable cmd="ls -las" cwd="/var/log" name="my_exec" launch-prefix="something" output="screen" shell="true"> <env name="LD_LIBRARY" value="/lib/some.so"/> </executable> 替换包含标签 为了在 ROS 1 中的命名空间下包含启动文件，那么包含标签必须嵌套在组标签中。 <group> <include file="another_launch_file"/> </group> 然后，不使用 ns 属性，而是添加 push_ros_namespace 操作标签来指定命名空间： <group> <push_ros_namespace namespace="my_ns"/> <include file="another_launch_file"/> </group> 只有在指定命名空间时才需要在group标签下嵌套include标签 Substitutions标签 有关 ROS 1 替换的文档可以在 roslaunch XML wiki 中找到。 替换语法没有改变，即它仍然遵循 $(substitution-name arg1 arg2 ...) 模式。 然而，有一些变化w.r.t ROS 1： env 和 optenv 标签已被 env 标签取代。 如果环境变量不存在，$(env ) 将失败。 $(env '') 与 ROS 1 的 $(optenv ) 相同。 $(env ) 与 ROS 1 的 $(env ) 或 $(optenv ) 相同。 find 已替换为 find-pkg-share（替换已安装包的共享目录）。 或者 find-pkg-prefix 将返回已安装包的根目录。 有一个新的 exec-in-pkg 替换。 例如：$(exec-in-pkg <package_name> <exec_name>)。 有一个新的 find-exec 替换。 arg 已替换为 var。 它查看使用 arg 或 let 标记定义的配置。 eval 和 dirname 替换没有改变。 不支持匿名替换。 类型推理规则 param 标记的类型推断规则小节中显示的规则适用于任何属性。 例如： <tag1 attr-expecting-an-int="'1'"/> <tag1 attr-expecting-an-int="1"/> <tag2 attr-expecting-a-str="1"/> <tag2 attr-expecting-a-str="'1'"/> <tag3 attr-expecting-a-str="asd, bsd" str-attr-sep=", "/> <tag3 attr-expecting-a-str="don't use a separator"/> 某些属性接受多个类型，例如 param 标记的 value 属性。 通常 int（或 float）类型的参数也接受 str，稍后将替换它并尝试通过操作转换为 int（或 float）。