启动文件中的替代变量
启动文件用于启动节点、服务和执行进程。这些操作可能带有参数,这些参数会影响它们的行为。替代变量可用于参数中,在描述可重用启动文件时提供了很大的灵活性。替代变量是在启动文件执行期间才生效的变量,可用于获取特定信息,例如启动配置、环境变量,或运行任意 Python 表达式。本节展示了 ROS2 启动文件中替代变量的使用示例。
创建并设置功能包
首先,创建一个名为 launch_tutorial, 构建类型为 ament_python 的功能包:
ros2 pkg create --build-type ament_python --license Apache-2.0 launch_tutorial
在该功能包中,创建一个名为 launch 的目录:
mkdir launch_tutorial/launch
最后,确保安装启动文件,在功能包的 setup.py 文件中添加以下内容:
import os
from glob import glob
from setuptools import find_packages, setup
package_name = 'launch_tutorial'
setup(
# 其他参数 ...
data_files=[
# ... 其他数据文件
# 包含所有启动文件。
(os.path.join('share', package_name, 'launch'), glob('launch/*'))
]
)
编写父启动文件
接下来,创建一个父启动文件,该文件将调用并传递参数给另一个启动文件。启动文件可以使用 YAML、XML 或 Python 语言编写,这里以 python 为例。
在 launch_tutorial 功能包的 launch 文件夹中创建 example_main_launch.py 文件,并编写如下代码:
from launch import LaunchDescription
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import PathJoinSubstitution, TextSubstitution
from launch_ros.substitutions import FindPackageShare
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()
)
])
LaunchDescription 是 launch 模块中的一个类,用于定义启动文件的顶层结构。它是一个容器,可以包含多个启动动作(如节点启动、参数设置等)。启动文件的主要目的是描述如何启动和配置一个 ROS 2 系统,LaunchDescription 就是这个描述的载体。
IncludeLaunchDescription 是 launch.actions 模块中的一个类,用于在当前启动文件中包含另一个启动文件。它允许你将复杂的启动配置分解为多个较小的启动文件,并在主启动文件中动态加载它们。通过这种方式,可以实现启动文件的模块化和重用。
PythonLaunchDescriptionSource 是 launch.launch_description_sources 模块中的一个类,用于指定被包含的启动文件的来源。它用于加载 Python 格式的启动文件。这个类的作用是告诉 IncludeLaunchDescription 如何找到和加载被包含的启动文件。
PathJoinSubstitution 和 TextSubstitution 是 launch.substitutions 模块中的两个类,用于在启动文件中动态生成路径和文本内容。
FindPackageShare 是 launch_ros.substitutions 模块中的一个类,用于查找 ROS 2 功能包的路径。它可以帮助你在启动文件中动态获取功能包的路径,而不需要硬编码路径。这使得启动文件更加灵活和可移植。
首先,FindPackageShare 查找 launch_tutorial 功能包的路径。然后使用 PathJoinSubstitution 替代变量将该功能包路径与 example_substitutions_launch.py 文件名连接起来。
PathJoinSubstitution([
FindPackageShare('launch_tutorial'),
'launch',
'example_substitutions_launch.py'
])
launch_arguments 字典包含 turtlesim_ns 和 use_provided_red 参数,这些参数传递给 IncludeLaunchDescription 动作。TextSubstitution 替代变量用于定义 new_background_r 参数,其值为 colors 字典中 background_r 的值。
launch_arguments={
'turtlesim_ns': 'turtlesim2',
'use_provided_red': 'True',
'new_background_r': TextSubstitution(text=str(colors['background_r']))
}.items()
子启动文件示例
现在,在同一个文件夹 launch 中创建启动文件 example_substitutions_launch.py ,该文件属于子启动文件,并插入以下代码:
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, ExecuteProcess, TimerAction
from launch.conditions import IfCondition
from launch.substitutions import LaunchConfiguration, 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=[[
'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],
)
])
正如前面介绍的,启动文件的主要目的是描述如何启动和配置一个 ROS2 系统,下面简单说明不同的模块的作用:
1 LaunchDescription
- 定义启动文件的顶层结构
- 包含多个启动动作,如节点启动、参数设置、条件判断等
2 launch.actions
模块中包含多种启动动作类,这些类用于定义启动文件中的具体操作
-
2.1
DeclareLaunchArgument:- 用于声明一个启动参数。
- 启动参数可以在启动文件中被引用,并且可以在运行时通过命令行或环境变量进行设置。
- 例如,声明一个启动参数
turtlesim_ns,默认值为turtlesim1。
DeclareLaunchArgument(
'turtlesim_ns',
default_value='turtlesim1'
) -
2.2
ExecuteProcess:- 用于执行一个外部进程
- 可以指定要执行的命令及其参数
- 例如,调用
turtlesim的spawn服务来生成一个新的海龟
ExecuteProcess(
cmd=[
'ros2 service call',
turtlesim_ns,
'/spawn',
'turtlesim/srv/Spawn',
'"{x: 2, y: 2, theta: 0.2}"'
],
shell=True
) -
2.3
TimerAction:- 用于在指定的时间间隔后执行某个动作
- 可以指定一个延迟时间(以秒为单位)和要执行的动作
- 例如,2秒后改变背景颜色
TimerAction(
period=2.0,
actions=[change_background_r_conditioned],
)
3 launch.conditions
模块中包含条件判断类,这些类用于在启动文件中实现不同条件下命令如何执行
-
3.1
IfCondition:- 用于根据条件判断是否执行某个动作。
- 可以传入一个布尔表达式,只有当表达式为
True时,才会执行指定的动作。 - 例如,只有当
use_provided_red为True且new_background_r等于200时,才改变背景颜色。
IfCondition(
PythonExpression([
new_background_r,
' == 200',
' and ',
use_provided_red
])
)
4 launch.substitutions 模块中包含替代变量类,这些类用于在启动文件中动态生成设定的值
-
4.1
LaunchConfiguration:- 用于引用启动参数的值。
- 可以在启动文件中动态获取启动参数的值。
- 例如,获取
turtlesim_ns启动参数的值。
turtlesim_ns = LaunchConfiguration('turtlesim_ns') -
4.2
PythonExpression:- 用于计算 Python 表达式。
- 可以在启动文件中动态计算复杂的表达式。
- 例如,计算
new_background_r == 200 and use_provided_red。
PythonExpression([
new_background_r,
' == 200',
' and ',
use_provided_red
])
launch_ros.actions 模块中包含与 ROS 2 相关的启动动作类,这些类用于定义 ROS 2 节点的启动配置。
-
Node:- 用于定义一个 ROS 2 节点的启动配置。
- 可以指定节点的包名、可执行文件名、节点名称、命名空间等。
- 例如,启动一个
turtlesim_node节点。
Node(
package='turtlesim',
namespace=turtlesim_ns,
executable='turtlesim_node',
name='sim'
)
构建功能包并修改参数
在工作空间的根目录构建功能包:
colcon build
构建完成后加载工作空间(source install/setup.bash )。使用 ros2 launch 命令启动父文件:
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
这将显示可以传递给启动文件的参数及其默认值。
参数(以 <name>:=<value> 的形式传递参数):
'turtlesim_ns':- 未提供描述
- (默认值:
'turtlesim1')
'use_provided_red':- 未提供描述
- (默认值:
'False')
'new_background_r':- 未提供描述
- (默认值:
'200')
现在,按照以下方式将所需的参数传递给启动文件:
ros2 launch launch_tutorial example_substitutions_launch.py turtlesim_ns:='turtlesim3' use_provided_red:='True' new_background_r:=200
这将执行以下操作,启动一个背景为蓝色的 turtlesim3 节点->生成第二个海龟->颜色更改为紫色->两秒后将颜色更改为粉色。

图 1: 启动文件的流程图
结合图 1,我们可以重新梳理本章中启动文件的工作原理。父启动文件 example_main_launch.py 通过 IncludeLaunchDescription() 等指令加载了子启动文件 example_substitutions_launch.py,并在加载的同时向子启动文件传递相关参数。子启动文件则负责具体的任务,例如启动节点、生成海龟模型以及配置参数等。
采用多级启动文件结构的优势在于:父启动文件可以集中管理多个复杂模块,从而简化系统整体的启动与配置;同时,每个子启动文件依然可以独立运行,增强了系统的灵活性与可维护性。
总结
本教程展示了如何在启动文件中使用替代变量,并学习了如何创建可重用的启动文件。启动文件可以使用 XML、YAML 或 Python 编写,可以启动和停止不同的节点,以及触发和响应各种事件。launch 文件对于 ROS2 初学者来说有些复杂,尤其是 Python 语法、参数加载、替换变量这些概念叠加在一起容易让人困惑。初学者可以从简单的 launch 文件开始,逐步引入多个节点,参数文件、替换变量等概念。