ROS2-016-ROS2工具:启动文件 launch 的介绍及其简单使用
简介
在机器人操作系统中,节点是程序的基本构成单元。一个完整的、系统性的功能模块由多个节点构成,在启动某个功能模块时可能需要依次启动这些节点。
以机器人的导航功能为例,其涉及的节点主要有以下几种:
- 底盘驱动;
- 雷达驱动;
- 摄像头驱动;
- imu 驱动;
- 地图服务;
- 路径规划;
- 运动控制;
- 环境感知;
- 定位;
- etc.
且不同的节点启动时,可能还会涉及到各种参数的导入、节点间执行逻辑的处理等。
如果在此时继续只使用 ros2 run
指令逐一执行节点,则过于繁琐。这时我们便可以通过 ROS2 所提供的 launch
模块以实现节点的批量启动。
launch
模块通常由 launch
文件 与 ros2 launch
命令 两个部分所组成,前者用于打包并配置节点,而后者用于执行 launch 文件。
文件实现的准备工作
终端下创建工作空间:
mkdir -p ws02_tools/src
cd ws02_tools/src
colcon build
进入工作空间的src目录:
cd src/
调用如下两条命令分别创建C++功能包、Python功能包:
C++:
ros2 pkg create cpp01_launch --build-type ament_cmake --dependencies rclcpp
Python:
ros2 pkg create py01_launch --build-type ament_python --dependencies rclpy
launch 的简单使用流程
在 ROS2 中,launch 文件可以使用 Python
、XML
或 YAML
编写,不同格式的 launch 文件基本使用流程一致。
为了之后编写 Python 格式文件时能够更加方便,你可以……
在使用Python版的 launch 文件时,由于其涉及到的 API 众多,为了提高编码效率,你可以在 VScode 中设置 launch 文件的代码模板。参照这里。在 VScode 的配置文件 python.json 中,你可以添加如下内容:
"ros2 launch py": {
"prefix": "ros2_launch_py",
"body": [
"from launch inport LaunchDescription",
"from launch_ros.actions import Node",
"# 封装终端指令相关类------",
"# from launch.actions import ExecuteProcess",
"# from launch.substitutions import FindExecutable",
"# 参数声明与获取------",
"from launch.actions import DeclareLaunchArgument",
"from launch.substitutions import LaunchConfiguration",
"# 文件包含相关------",
"# from launch.actions import IncludeLaunchDescription",
"# from launch.launch_description_sources import PythonLaunchDescriptionSource",
"# 分组相关------",
"# from launch_ros.actions import PushRosNamespace",
"# from launch.actions import GroupAction",
"# 事件相关------",
"# from launch.event_handlers import OnProcessStart, OnProcessExit",
"# from launch.actions import ExecuteProcess, RegisterEventHandler, LogInfo",
"# 获取功能包下share目录路径------",
"# from ament_index_python.packages import get_package_share_directory",
"",
"def generate_launch_description():",
" ",
" return LaunchDescription([])"
],
"description": "ros2 launch"
}
接下来我们通过一个案例演示 launch 文件的简单编写编译流程,案例需求:编写并执行 launch 文件,可以启动两个节点。
其实现步骤一般有如下几步:
- 编写launch文件;
- 编辑配置文件;
- 编译;
- 执行。
我们将该案例分为 C++ 实现 及 Python 实现 两个部分。
C++ 实现
1. 编写launch文件
在功能包 cpp01_launch
下创建 launch 目录,launch 文件
可以是 Python 文件
、xml 文件
或者 yaml 文件
,不同类型的 launch 文件
可以直接存储于 launch 目录 下,为了方便管理,我们也可以在 launch 目录 下新建 py
、xml
、yaml
三个文件夹,以分别存储对应类型的 launch 文件。
在为上述不同格式的 launch 文件在命名时,一般会使用 _launch.py
、_launch.xml
、_launch.yaml
或者 .launch.py
、.launch.xml
、.launch.yaml
作为后缀名。不同类型的 launch 文件 命名示例如下:
- Python 文件:
py00_base_launch.py
或py00_base.launch.py
- xml 文件:
py00_base_launch.xml
或xml00_base.launch.xml
- yaml 文件:
py00_base_launch.yaml
或yaml00_base.launch.yaml
不同类型的 launch 文件 内容示例如下:
Python 文件:以
py00_base.launch.py
为例from launch inport LaunchDescription from launch_ros.actions import Node def generate_launch_description(): turtle1 = Node(package = "turtlesim", executable = "turtlesim_node", name = "t1") turtle2 = Node(package = "turtlesim", executable = "turtlesim_node", name = "t2") return LaunchDescription([turtle1, turtle2])
xml 文件:以
xml00_base.launch.xml
为例<launch> <node pkg="turtlesim" exec="turtlesim_node" name="t1"/> <node pkg="turtlesim" exec="turtlesim_node" name="t1"/> </launch>
yaml 文件:以
yaml00_base.launch.yaml
为例launch: - node: pkg: "turtlesim" exec: "turtlesim_node" name: "sim" namespace: "t1" - node: pkg: "turtlesim" exec: "turtlesim_node" name: "sim" namespace: "t2"
2. 编辑配置文件
你需要编辑配置文件后,才可以正常使用 launch 文件 。若没有进行配置文件的编辑而直接进行编译,则在编译过程中,这些 launch 文件 并不会自动被系统识别。
你必须在 CMakeLists.txt
中通过 install(DIRECTORY ...)
代码明确指定将 launch 文件 安装到 ROS2 的共享资源目录 (即 share/${PROJECT_NAME}
)。只有安装到该路径后,才能够通过 ros2 launch
命令或 launch 描述文件
对它们进行调用。
在针对功能包进行首次配置时,在 CMakeLists.txt
中 👈
位置添加以下语句:
......
find_package(rclcpp REQUIRED)
install(DIRECTORY launch DESTINATION share/${PROJECT_NAME}) 👈
if(BUILD_TESTING)
......
该相关配置在该功能包中仅需设置此次一次,即无论之后该功能包的 launch 目录 下会配置多少个 launch 文件 皆仅需此配置适用即可。
做完这一步,请提前编译下
为确保该配置无误,在进行该配置后,建议提前使用 colcon
进行一次编译。若配置无误,其会在 install/${PROJECT_NAME}/share/${PROJECT_NAME}
目录下正常生成 launch 目录
结构。
拓展阅读
${PROJECT_NAME}
指的是功能包同名目录,简单点说就是和你所编译的那个功能包一样名字的另一个目录。
当然,对于带有启动文件的功能包,最好在功能包的 package.xml
中添加一个执行依赖包 ros2launch
:
<exec_depend>ros2launch</exec_depend>
这可以确保构建功能包后可以使用 ros2 launch
命令,以及能够确保可以识别不同格式的 launch 文件。
3. 编译
在终端中进入当前工作空间,编译功能包:
colcon build --package-select cpp01_launch
4. 执行
在当前工作空间下进入终端中,使用以下指令进行运行:(以 py00_base.launch.py
为例)
. install/setup.bash
ros2 launch cpp01_launch py00_base.launch.py
Python 实现
在 Python 中实现 launch 文件的编写使用实际上与 在 C++ 中所经历的实现流程基本一致,其主要区别在 编辑配置文件上。
Ⅰ. 编写launch文件
与前文所述相同。
Ⅱ. 编辑配置文件
在该步骤中,你需要编辑 setup.py
文件。在其 data_files
属性中,添加你所编写的相关 launch 文件的 文件路径。
......
from glob import glob
......
setup(
name=package_name,
...
data_files=[
('share/ament_index/resource_index/packages', ['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
# launch 文件相关配置
# 这里按照你的文件命名而定。若为"_launch",则使用"_launch"
('share/' + package_name, glob("launch/py/*.launch.py")),
('share/' + package_name, glob("launch/xml/*.launch.xml")),
('share/' + package_name, glob("launch/yaml/*.launch.yaml")),
],
...
)
当然,对于带有启动文件的功能包,最好在功能包的 package.xml
中添加一个执行依赖包 ros2launch
:
<exec_depend>ros2launch</exec_depend>
这可以确保构建功能包后可以使用 ros2 launch
命令,以及能够确保可以识别不同格式的 launch 文件。
Ⅲ. 编译
在终端中进入当前工作空间,编译功能包:
colcon build --package-select py01_launch
Ⅳ. 执行
在当前工作空间下进入终端中,使用以下指令进行运行:(以 py00_base.launch.py
为例)
. install/setup.bash
ros2 launch py01_launch py00_base.launch.py
关于 launch 文件的更系统介绍
你可以参考下一篇内容,那里详细的介绍了使用[python]、[XML]、[YAML] 三种语言编写 launch 文件 时所涉及的相关语法。