目标:了解 ROS 2 启动文件中的替代项。
教程级别:中级
时间:15 分钟
目录
背景
先决条件
使用替代品
1. 创建并设置包
2. 父启动文件
3 替代示例启动文件
4. 构建包
启动示例
修改启动参数
文档
摘要
背景
启动文件用于启动节点、服务和执行进程。这组动作可能有参数,这些参数会影响它们的行为。在参数中可以使用替代来提供在描述可重用启动文件时更多的灵活性。替代是一种变量,只有在执行启动描述时才会评估,可用于获取特定信息,如启动配置、环境变量,或评估任意 Python 表达式。
本教程展示了 ROS 2 启动文件中替代用法的示例。
先决条件
本教程使用 turtlesim 包。本教程还假设您熟悉创建包。
始终不要忘记在您打开的每个新终端中获取 ROS 2 的源。
使用替代品
1. 创建并设置包
首先,创建一个名为 launch_tutorial
的新包:
Python包: 创建一个新的 build_type ament_python
包:
ros2 pkg create --build-type ament_python --license Apache-2.0 launch_tutorial
C++包: 创建一个新的 build_type ament_cmake
包:
ros2 pkg create --build-type ament_cmake --license Apache-2.0 launch_tutoria
在那个包内部,创建一个名为 launch
的目录:
mkdir launch_tutorial/launch
最后,请确保安装启动文件:
Python包:将以下更改添加到包裹的 setup.py
中:
import os
from glob import glob
from setuptools import find_packages, setup
package_name = 'launch_tutorial'
setup(
# Other parameters ...
data_files=[
# ... Other data files
# Include all launch files.
(os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*launch.[pxy][yma]*')))
]
)
C++包:将以下代码添加到 CMakeLists.txt
中,就在 ament_package()
之前:
install(DIRECTORY
launch
DESTINATION share/${PROJECT_NAME}/
)
2 父级启动文件
让我们创建一个启动文件,它将调用另一个启动文件并传递参数。这个启动文件可以是 Python 格式的,也可以是 YAML 格式的。
为此,在 launch_tutorial
包的 launch
文件夹中创建以下文件。
Python:将完整代码复制并粘贴到 launch/example_main_launch.py
文件中:
# 导入FindPackageShare类,用于查找ROS包的路径
from launch_ros.substitutions import FindPackageShare
# 导入LaunchDescription类,用于描述要启动的节点
from launch import LaunchDescription
# 导入IncludeLaunchDescription类,用于包含其他的启动描述
from launch.actions import IncludeLaunchDescription
# 导入PythonLaunchDescriptionSource类,用于指定Python文件作为启动源
from launch.launch_description_sources import PythonLaunchDescriptionSource
# 导入PathJoinSubstitution和TextSubstitution类,用于路径和文本的替换
from launch.substitutions import PathJoinSubstitution, TextSubstitution
# 定义generate_launch_description函数,用于生成启动描述
def generate_launch_description():
# 定义一个字典,存储颜色配置
colors = {
'background_r': '200' # 背景颜色红色分量的值
}
# 返回一个启动描述对象
return LaunchDescription([
# 包含另一个启动描述
IncludeLaunchDescription(
# 指定Python文件作为启动源
PythonLaunchDescriptionSource([
# 使用路径拼接替换,找到'launch_tutorial'包的路径,再拼接后续的路径
PathJoinSubstitution([
FindPackageShare('launch_tutorial'), # 查找'launch_tutorial'包的路径
'launch', # launch文件夹
'example_substitutions_launch.py' # 启动文件名
])
]),
# 设置启动参数
launch_arguments={
'turtlesim_ns': 'turtlesim2', # 设置turtlesim的命名空间为'turtlesim2'
'use_provided_red': 'True', # 使用提供的红色分量值
# 新的背景颜色红色分量,使用文本替换从colors字典中获取
'new_background_r': TextSubstitution(text=str(colors['background_r']))
}.items() # 将字典转换为项的列表
)
])
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
替换用于用 colors
字典中 background_r
键的值定义 new_background_r
参数。
launch_arguments={
'turtlesim_ns': 'turtlesim2',
'use_provided_red': 'True',
'new_background_r': TextSubstitution(text=str(colors['background_r']))
}.items()
YAML:将完整代码复制并粘贴到 launch/example_main_launch.yaml
文件中:
launch:
- let:
name: 'background_r'
value: '200'
- include:
file: '$(find-pkg-share launch_tutorial)/launch/example_substitutions_launch.yaml'
arg:
- name: 'turtlesim_ns'
value: 'turtlesim2'
- name: 'use_provided_red'
value: 'True'
- name: 'new_background_r'
value: '$(var background_r)'
$(find-pkg-share launch_tutorial)
替换用于找到通往 launch_tutorial
包的路径。然后将路径替换与 example_substitutions_launch.yaml
文件名连接起来。
file: '$(find-pkg-share launch_tutorial)/launch/example_substitutions_launch.yaml'
将 background_r
变量与 turtlesim_ns
和 use_provided_red
参数一起传递给 include
操作。 $(var background_r)
替换用于用 background_r
变量的值定义 new_background_r
参数。
arg:
- name: 'turtlesim_ns'
value: 'turtlesim2'
- name: 'use_provided_red'
value: 'True'
- name: 'new_background_r'
value: '$(var background_r)'
3 . 替代示例启动文件
现在在同一个文件夹中创建替换启动文件:
Python: 创建文件 launch/example_substitutions_launch.py
并插入以下代码:
# 导入Node类,用于创建节点
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' # 默认值为'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 # 在shell中执行
)
# 执行进程,改变背景颜色的红色分量
change_background_r = ExecuteProcess(
cmd=[[
'ros2 param set ', # 设置参数的命令
turtlesim_ns, # 命名空间
'/sim background_r ', # 参数名
'120' # 参数值
]],
shell=True
)
# 执行进程,根据条件改变背景颜色的红色分量
change_background_r_conditioned = ExecuteProcess(
condition=IfCondition( # 条件
PythonExpression([ # Python表达式
new_background_r, # 新的背景红色分量
' == 200', # 如果新的背景红色分量等于200
' and ', # 并且
use_provided_red # 使用提供的红色
])
),
cmd=[[
'ros2 param set ', # 设置参数的命令
turtlesim_ns, # 命名空间
'/sim background_r ', # 参数名
new_background_r # 参数值
]],
shell=True # 在shell中执行
)
# 返回启动描述对象
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, # 定时器周期,每2.0秒执行一次
actions=[change_background_r_conditioned], # 定时器动作,满足条件时改变背景颜色的红色分量
)
])
定义了 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_node
的 namespace
设置为 turtlesim_ns
LaunchConfiguration
替换已定义。
turtlesim_node = Node(
package='turtlesim',
namespace=turtlesim_ns,
executable='turtlesim_node',
name='sim'
)
随后,定义了名为 spawn_turtle
的 ExecuteProcess
操作,并带有相应的 cmd
参数。此命令调用了 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
)
相同的方法用于 change_background_r
和 change_background_r_conditioned
动作,这些动作改变了 turtlesim 背景的红色参数。不同的是,只有当提供的 new_background_r
参数等于 200
,并且 use_provided_red
启动参数设置为 True
时,才执行 change_background_r_conditioned
动作。在 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
)
YAML:创建文件 launch/example_substitutions_launch.yaml
并插入以下代码:
launch: # 启动文件开始
- arg: # 定义一个参数
name: 'turtlesim_ns' # 参数名为'turtlesim_ns'
default: 'turtlesim1' # 默认值为'turtlesim1'
- arg: # 定义另一个参数
name: 'use_provided_red' # 参数名为'use_provided_red'
default: 'False' # 默认值为'False'
- arg: # 定义第三个参数
name: 'new_background_r' # 参数名为'new_background_r'
default: '200' # 默认值为'200'
- node: # 定义一个节点
pkg: 'turtlesim' # 节点所在的包名为'turtlesim'
namespace: '$(var turtlesim_ns)' # 节点的命名空间为参数'turtlesim_ns'的值
exec: 'turtlesim_node' # 节点执行的程序为'turtlesim_node'
name: 'sim' # 节点的名字为'sim'
- executable: # 定义一个可执行命令
cmd: 'ros2 service call $(var turtlesim_ns)/spawn turtlesim/srv/Spawn "{x: 5, y: 2, theta: 0.2}"' # 执行的命令内容
- executable: # 定义另一个可执行命令
cmd: 'ros2 param set $(var turtlesim_ns)/sim background_r 120' # 执行的命令内容
- timer: # 定义一个定时器
period: 2.0 # 定时器的周期为2.0秒
children: # 定时器的子任务
- executable: # 子任务中的一个可执行命令
cmd: 'ros2 param set $(var turtlesim_ns)/sim background_r $(var new_background_r)' # 执行的命令内容
if: '$(eval "$(var new_background_r) == 200 and $(var use_provided_red)")' # 如果满足条件,则执行该命令
4. 构建包
转到工作区的根目录,然后构建包:
colcon build
cxy@ubuntu2404-cxy:~/ros2_ws$ colcon build --packages-select launch_tutorial
Starting >>> launch_tutorial
Finished <<< launch_tutorial [10.7s]
Summary: 1 package finished [21.2s]
也请记得在构建后配置工作空间的环境变量。
启动示例
现在您可以使用 ros2 launch
命令启动。
python: ros2 launch launch_tutorial example_main_launch.py
yaml: ros2 launch launch_tutorial example_main_launch.yaml
cxy@ubuntu2404-cxy:~/ros2_ws$ . install/setup.bash
cxy@ubuntu2404-cxy:~/ros2_ws$ ros2 launch launch_tutorial example_main_launch.py
[INFO] [launch]: All log files can be found below /home/cxy/.ros/log/2024-07-10-09-48-44-027642-ubuntu2404-cxy-16505
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [turtlesim_node-1]: process started with pid [16508]
[INFO] [Spawn "{x: 2, y: 2, theta: 0.2}"-2]: process started with pid [16509]
[INFO] [sim background_r 120-3]: process started with pid [16510]
[INFO] [sim background_r 200-4]: process started with pid [16519]
[turtlesim_node-1] [INFO] [1720576129.770325485] [turtlesim2.sim]: Starting turtlesim with node name /turtlesim2/sim
[turtlesim_node-1] [INFO] [1720576130.671123227] [turtlesim2.sim]: Spawning turtle [turtle1] at x=[5.544445], y=[5.544445], theta=[0.000000]
[turtlesim_node-1] [INFO] [1720576131.486514250] [turtlesim2.sim]: Spawning turtle [turtle2] at x=[2.000000], y=[2.000000], theta=[0.200000]
[INFO] [Spawn "{x: 2, y: 2, theta: 0.2}"-2]: process has finished cleanly [pid 16509]
[INFO] [sim background_r 200-4]: process has finished cleanly [pid 16519]
[INFO] [sim background_r 120-3]: process has finished cleanly [pid 16510]
这将做以下事情:
启动一个带有蓝色背景的 turtlesim 节点
生成第二只乌龟
将颜色更改为紫色
如果提供的
background_r
参数是200
并且use_provided_red
参数是True
,则在两秒后将颜色更改为粉红色
修改启动参数
Python:
如果您想更改提供的启动参数,您可以在 example_main_launch.py
中的 launch_arguments
字典中更新它们,或者用首选参数启动 example_substitutions_launch.py
。要查看可能给予启动文件的参数,请运行以下命令:
ros2 launch launch_tutorial example_substitutions_launch.py --show-args
YAML:
如果您想更改提供的启动参数,您可以更新 example_main_launch.yaml
中的 background_r
变量,或者用首选参数启动 example_substitutions_launch.yaml
。要查看可能传递给启动文件的参数,请运行以下命令:
ros2 launch launch_tutorial example_substitutions_launch.yaml --show-args
这将显示可能提供给启动文件及其默认值的参数。
cxy@ubuntu2404-cxy:~/ros2_ws$ 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')
现在您可以按如下方式将所需参数传递给启动文件:
Python:
ros2 launch launch_tutorial example_substitutions_launch.py turtlesim_ns:='turtlesim3' use_provided_red:='True' new_background_r:=200
YAML:
ros2 launch launch_tutorial example_substitutions_launch.yaml turtlesim_ns:='turtlesim3' use_provided_red:='True' new_background_r:=200
文档
启动文档 https://docs.ros.org/en/jazzy/p/launch/architecture.html 提供了有关可用替代品的详细信息。
摘要
在本教程中,您学习了如何在启动文件中使用替换。您了解了它们的可能性和能力,以创建可重用的启动文件。
您现在可以了解更多关于在启动文件中使用事件处理程序的信息 https://docs.ros.org/en/jazzy/Tutorials/Intermediate/Launch/Using-Event-Handlers.html ,这些启动文件用于定义一组复杂的规则,这些规则可用于动态修改启动文件。