ROS Launch
1. 基础知识
1.1 launch 如何写?
Launch 启动文件是 ROS 系统中多节点启动与配置的一种脚本。通过 launch 文件,我们可以同时启动许多节点,这样简化了用命令行去多次启动不同的 Node。
ROS1 只支持 xml 格式的 .launch 文件配置,ROS2 在兼容 xml 的基础上,还支持 yaml 和 python 格式,而 python 格式的 launch 是我们的学习重点,因为相较于另外两种配置方式,使用python更加灵活:
- python 拥有众多的函数库,可以在启动文件中使用。
- 可以方便地设置各种启动条件。
以下是一个 launch 文件示例:
from launch import LaunchDescription # launch文件的描述类
from launch_ros.actions import Node # 节点启动的描述类
def generate_launch_description(): # 自动生成launch文件的函数
return LaunchDescription([
Node( # 配置一个节点的启动
package='turtlesim', # 节点所在的功能包
namespace='turtlesim1', # 节点所在的命名空间(一般不用写)
executable='turtlesim_node', # 要执行的节点
name='sim' # 对节点重新命名
),
Node(
package='turtlesim',
namespace='turtlesim2',
executable='turtlesim_node',
name='sim'
),
Node(
package='turtlesim',
executable='mimic',
name='mimic',
remappings=[
('/input/pose', '/turtlesim1/turtle1/pose'),
('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'),
]
)
])
1.2 如何将 launch 文件集成到 ROS2 包中?
在你的包中创建 launch
目录,将你的 launch 文件放进去。
在包的 CMakeLists.txt 末尾(但在 ament_package()
之前)添加如下语句:
install(DIRECTORY
launch
DESTINATION share/${PROJECT_NAME}/
)
这样在你编译这个包时,你的 launch 文件将被安装到 install 目录中,你才可以执行它。
1.3 launch 如何运行?
ros2 launch <package_name> <launch_file_name>
2. 其他配置功能
上文我们只介绍了启动文件中 package、namespace、executable 和 name 的配置,而在实际应用中还会有其他需求,常用的比如配置参数、话题重映射等。另外还有一些复杂的用法,详细内容请参考官方文档。
2.1 节点参数配置
在以下示例中,我们将修改 turtlesim2 的窗口背景颜色。
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch.substitutions import TextSubstitution
from launch_ros.actions import Node
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="0")
)
background_b_launch_arg = DeclareLaunchArgument(
"background_b", default_value=TextSubstitution(text="255")
)
return LaunchDescription([
background_r_launch_arg,
background_g_launch_arg,
background_b_launch_arg,
# start a turtlesim_node in the turtlesim1 namespace
Node(
package='turtlesim',
namespace='turtlesim1',
executable='turtlesim_node',
name='sim'
),
# start another turtlesim_node in the turtlesim2 namespace
# and use args to set 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
Node(
package='turtlesim',
executable='mimic',
name='mimic',
remappings=[
('/input/pose', '/turtlesim1/turtle1/pose'),
('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'),
]
)
])
可以看到,turtlesim2 默认的窗口背景颜色是蓝色。
当我们执行 launch 文件时,可以设置参数:
ros2 launch <package_name> <launch_file_name> background_r:=0 background_g:=255 background_b:=0
这样启动的 turtlesim2 窗口背景颜色为绿色。
2.2 在 launch 文件中加载 yaml 配置文件
在以下示例中,我们配置 line_detect_node 节点读取 line_detect/config/line_detect_params.yaml
中的参数。
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('line_detect'),
'config', 'line_detect_params.yaml'
)
return LaunchDescription([
Node(
package='line_detect',
executable='line_detect_node',
name='line_detect_node',
parameters=[config]
),
])
2.3 话题重映射
在功能更新、话题命名重复、临时调试等情况下,节点的话题可能需要修改名称,直接修改源码并不是很友好的办法,这种情况就可以用 launch 文件内的话题重映射来实现。
有 2 种 用途:
- 把一个节点原本来发布的 topic,映射为另外一个名字。
- 把其他的节点发布的原始 topic,映射为所需要的 topic。
remap 是一个非常有用的技巧,其实就是更名改姓,瞒天过海。
以我们之前提到的 turtlesim 为例:
Node(
package='turtlesim',
executable='mimic',
name='mimic',
remappings=[
('/input/pose', '/turtlesim1/turtle1/pose'),
('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'),
]
)
2.4 包含其他 launch 文件
在复杂的项目中,launch 文件也会有很多,此时我们可以使用类似编程中的 include 机制,让 launch 文件包含其他 launch 文件。
示例:
import os
from ament_index_python.packages import get_package_share_directory # 查询功能包路径的方法
from launch import LaunchDescription # launch文件的描述类
from launch.actions import IncludeLaunchDescription # 节点启动的描述类
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.actions import GroupAction # launch文件中的执行动作
from launch_ros.actions import PushRosNamespace # ROS命名空间配置
def generate_launch_description(): # 自动生成launch文件的函数
parameter_yaml = IncludeLaunchDescription( # 包含指定路径下的另外一个launch文件
PythonLaunchDescriptionSource([os.path.join(
get_package_share_directory('learning_launch'), 'launch'),
'/parameters_nonamespace.launch.py'])
)
parameter_yaml_with_namespace = GroupAction( # 对指定launch文件中启动的功能加上命名空间
actions=[
PushRosNamespace('turtlesim2'),
parameter_yaml]
)
return LaunchDescription([ # 返回launch文件的描述信息
parameter_yaml_with_namespace
])