Skip to main content

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
])