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 rclcppPython:
ros2 pkg create py01_launch --build-type ament_python --dependencies rclpylaunch 的简单使用流程
在 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.pyPython 实现
在 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 文件 时所涉及的相关语法。
