跳到主要内容

启动文件中的替代变量

启动文件用于启动节点、服务和执行进程。这些操作可能带有参数,这些参数会影响它们的行为。替代变量可用于参数中,在描述可重用启动文件时提供了很大的灵活性。替代变量是在启动文件执行期间才生效的变量,可用于获取特定信息,例如启动配置、环境变量,或运行任意 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()
)
])

LaunchDescriptionlaunch 模块中的一个类,用于定义启动文件的顶层结构。它是一个容器,可以包含多个启动动作(如节点启动、参数设置等)。启动文件的主要目的是描述如何启动和配置一个 ROS 2 系统,LaunchDescription 就是这个描述的载体。

IncludeLaunchDescriptionlaunch.actions 模块中的一个类,用于在当前启动文件中包含另一个启动文件。它允许你将复杂的启动配置分解为多个较小的启动文件,并在主启动文件中动态加载它们。通过这种方式,可以实现启动文件的模块化和重用。

PythonLaunchDescriptionSourcelaunch.launch_description_sources 模块中的一个类,用于指定被包含的启动文件的来源。它用于加载 Python 格式的启动文件。这个类的作用是告诉 IncludeLaunchDescription 如何找到和加载被包含的启动文件。

PathJoinSubstitutionTextSubstitutionlaunch.substitutions 模块中的两个类,用于在启动文件中动态生成路径和文本内容。

FindPackageSharelaunch_ros.substitutions 模块中的一个类,用于查找 ROS 2 功能包的路径。它可以帮助你在启动文件中动态获取功能包的路径,而不需要硬编码路径。这使得启动文件更加灵活和可移植。

首先,FindPackageShare 查找 launch_tutorial 功能包的路径。然后使用 PathJoinSubstitution 替代变量将该功能包路径与 example_substitutions_launch.py 文件名连接起来。

PathJoinSubstitution([
FindPackageShare('launch_tutorial'),
'launch',
'example_substitutions_launch.py'
])

launch_arguments 字典包含 turtlesim_nsuse_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:

    • 用于执行一个外部进程
    • 可以指定要执行的命令及其参数
    • 例如,调用 turtlesimspawn 服务来生成一个新的海龟
    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_redTruenew_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 文件开始,逐步引入多个节点,参数文件、替换变量等概念。