前言
启动文件用于启动节点、服务和执行流程。这组操作可能有影响其行为的参数。替换机制可以在参数中使用,以便在描述可重复使用的启动文件时提供更大的灵活性。替换是仅在执行启动描述期间评估的变量,可用于获取特定信息,如启动配置、环境变量或评估任意Python表达式。
简而言之,ROS 2中的替换机制可以在启动描述运行过程中动态修改和管理修改某些参数而能改变运行状态和效果。
动动手
使用替换机制
创建功能包
在launch_ws/src下创建一份功能包launch_tutorial(C++):
$ros2 pkg create --build-type ament_cmake --license Apache-2.0 launch_tutorial
创建luanch文件夹,用来放置launch文件:
$mkdir launch_tutorial/launch
另外CMakeLists.txt中加上下面的内容:
install(DIRECTORY
launch
DESTINATION share/${PROJECT_NAME}/
)
编写父类launch文件
上面步骤都准备好后,我们开始此篇的主题重点部分。在launch文件夹下创建一份可以调用且能传参给其他launch文件的父类launch文件example_main_launch.py,格式可以python可以yaml,我们只演示下python版本,如下:
python
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()
)
])
简单说明一下:
python
PathJoinSubstitution([
FindPackageShare('launch_tutorial'),
'launch',
'example_substitutions_launch.py'
])
FindPackageShare用来查找launch_tutorial包的路径,PathJoinSubstitution用来连接到包路径下面example_substitutions_launch.py的路径。
python
launch_arguments={
'turtlesim_ns': 'turtlesim2',
'use_provided_red': 'True',
'new_background_r': TextSubstitution(text=str(colors['background_r']))
}.items()
launch_arguments字典(含turtlesim_ns、use_provided_red参数)会传给IncludeLaunchDescription动作使用,另外TextSubstitution用于使用colors字典中的background_r键的值来定义new_background_r参数。
编写有替换机制功能的launch文件
在功能包的根路径launch下创建一份example_substitutions_launch.py文件,内容如下:
python
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],
)
])
同样简单说明一下:
python
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、use_provided_red和new_background_r这三个启动配置。它们被用来存储上述变量中的启动参数值,并传递给所需的动作。这些LaunchConfiguration替换允许我们在启动描述的任何部分获取启动参数的值。
DeclareLaunchArgument
用于定义启动参数,这些参数可以从上述启动文件或控制台中传递。
python
turtlesim_node = Node(
package='turtlesim',
namespace=turtlesim_ns,
executable='turtlesim_node',
name='sim'
)
定义了名为turtlesim_node的节点,并将命名空间设置为turtlesim_ns的LaunchConfiguration替换。
python
spawn_turtle = ExecuteProcess(
cmd=[[
'ros2 service call ',
turtlesim_ns,
'/spawn ',
'turtlesim/srv/Spawn ',
'"{x: 2, y: 2, theta: 0.2}"'
]],
shell=True
)
定义了一个名为spawn_turtle的ExecuteProcess动作,并带有相应的cmd参数。这个命令调用turtlesim节点的spawn服务。
此外,LaunchConfiguration替换用于获取turtlesim_ns启动参数的值,以构建命令字符串。
python
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
)
对于改变turtlesim背景红色参数颜色的change_background_r和change_background_r_conditioned动作,采用了相同的方法。不同的是,只有当提供的new_background_r参数等于200,且use_provided_red启动参数设置为True时,change_background_r_conditioned动作才会执行。在IfCondition内部的评估是通过PythonExpression替换来完成的。
这些内容是不是有够复杂的。
构建功能包
进入工作空间的根路径下,构建完成后source一下环境(source install/setup.bash):
python
$colcon build
跑跑例子
下面我们就可以运行下launch文件了,先跑一下example_main_launch.py:
python
$ros2 launch launch_tutorial example_main_launch.py
这个launch文件将会做如下操作:
- 启动一个海龟仿真节点(蓝色背景);
- 孵化第二只海龟;
- 改变背景颜色为紫色;
- 2秒后改变颜色为粉色(如果提供的参数background_r值为200且参数use_provided值为True);
修改launch文件参数
如果要修改启动参数,除了可以直接在example_main_launch.py文件里修改launch_arguments字典内容外,还可以使用首选参数启动example_substitutions_launch.py。
要查看可能传递给启动文件的参数有哪些,运行以下命令即可:
python
$ros2 launch launch_tutorial example_substitutions_launch.py --show-args
它会返回可能传递给launch文件的参数和其对应的默认值:
我们试试利用example_substitutions_launch.py来修改参数:
python
$ros2 launch launch_tutorial example_substitutions_launch.py turtlesim_ns:='turtlesim3' use_provided_red:='True' new_background_r:=200
可以看到通过命令行里面的参数(命名空间等参数值)已经修改成功。
本篇完。