当前位置: 首页 > news >正文

ROS2 Humble 笔记(十二)launch 文件与 namespace 启动多个节点

这篇博客是 B 站《古月·ROS2入门21讲》的第十五个视频的图文记录,主要介绍了 launch 文件如何实现多个节点加载、命名空间隔离、参数启动加载、多个launch嵌套 的功能。原始视频链接如下:

  • B 站视频链接:15. Launch:多节点启动与配置脚本

【Note】:ROS2 的 launch 文件编写规则和 ROS1 之间存在巨大差异,ROS2 更像是在写 python 脚本,而 ROS1 则是在写 xml。尽管也可以用 launch 或 yaml 编写,但官方建议用 python 格式撰写。


1. 多个节点启动

使用下面的命令运行 learning_launch 功能包下的 simple.launch.py 文件:

$ ros2 launch learning_launch simple.launch.py 

运行后可以看见同时启动了两个节点 topic_helloworld_pub-1topic_helloworld_sub-2,这两个节点有各自的 PID,说明是两个独立的进程:

在这里插入图片描述


2. launch 文件内容

learning_launch 功能包下有 launch/simple.launch.py 文件,具体位置为 src/ros2_21_tutorials/learning_launch/launch

【Note】:虽然没有强制要求 launch 文件必须放在 launch 文件夹中,但这已经成为了一个约定俗成的习惯

从该文件的内容中可以发现其本身是 python 写法,这和 ROS1 中的 launch 文件编写规则有较大差异:

from launch import LaunchDescription           # launch文件的描述类
from launch_ros.actions import Node            # 节点启动的描述类def generate_launch_description():             # 自动生成launch文件的函数return LaunchDescription([                 # 返回launch文件的描述信息Node(                                  # 配置一个节点的启动package='learning_topic',          # 节点所在的功能包executable='topic_helloworld_pub', # 节点的可执行文件),Node(                                  # 配置一个节点的启动package='learning_topic',          # 节点所在的功能包executable='topic_helloworld_sub', # 节点的可执行文件名),])

在这里插入图片描述


3. 加载 rviz 配置

3.1 launch 加载配置

launch 文件可以用来在打开 rviz 时加载配置好的信息,使用下面的命令运行一个 launch 文件:

$ ros2 launch learning_launch rviz.launch.py

如果你此时再开一个终端运行一个空的 rviz 就可以看见两者之间的差异:

$ ros2 run rviz2 rviz2

下图中左边的是通过 rviz.launch.py 启动的 rviz 窗口,右边的是 rviz2 启动的窗口,可以看见在视角上有明显不同。当你进入开发后期有时候需要展现多个内容的时候这种自动加载配置的方式就非常方便。

在这里插入图片描述


3.2 命令行加载配置

当然,也不是说命令行就不能在启动 rviz 的时候加载配置文件,你仍然可以用 -d 参数的形式指明配置文件路径,如:

$ ros2 run rviz2 rviz2 -d \
src/ros2_21_tutorials/learning_launch/rviz/turtle_rviz.rviz

这种方式启动的依旧是上面 rviz.launch.py 相同的节点:

在这里插入图片描述


3.3 launch 文件内容

打开 learning_launch 功能包中 launch/rviz.launch.py 文件,具体位置在 src/ros2_21_tutorials/learning_launch/launch/rviz.launch.py 处:

import osfrom ament_index_python.packages import get_package_share_directory # 查询功能包路径的方法from launch import LaunchDescription    # launch文件的描述类
from launch_ros.actions import Node     # 节点启动的描述类def generate_launch_description():      # 自动生成launch文件的函数rviz_config = os.path.join(          # 找到配置文件的完整路径get_package_share_directory('learning_launch'),'rviz','turtle_rviz.rviz')return LaunchDescription([           # 返回launch文件的描述信息Node(                             # 配置一个节点的启动package='rviz2',               # 节点所在的功能包executable='rviz2',            # 节点的可执行文件名name='rviz2',                  # 对节点重新命名arguments=['-d', rviz_config]  # 加载命令行参数)])

从文件内容上可以看出其本质依旧是使用 -d 参数实现加载,和命令行加载方式完全一致。

在这里插入图片描述

另一方面,由于 ROS中不允许有重名节点,当你有一个节点功能需要服用的时候就可以以 launch 文件的形式加载节点,加载时会 使用 name 值强制覆盖节点脚本中的节点名。这种情况在复合机器人中十分常见,例如一台机器人上可能有多个相机,如果给每个相机都写一个脚本既不通用也不优雅,但用 launch 文件重命名就可以很便捷地修改节点名。

在这里插入图片描述


4. namespace 命名空间

4.1 话题前的 namespace

使用下面命令启动 learning_launch 功能包中的 launch/remapping.launch.py 文件,具体位置为 src/ros2_21_tutorials/learning_launch/launch/remapping.launch.py

$ ros2 launch learning_launch remapping.launch.py

启动后可以发现有两个小海龟仿真器:

在这里插入图片描述

此时可以看到可用的话题有以下几个,在话题前有两个额外的字段 /turtlesim1/turtlesim2,这表示话题在不同的命名空间:

$ ros2 topic list

在这里插入图片描述


4.2 launch 文件中 namespace 规则

打开 learning_launch 功能包中的 launch/remapping.launch.py 文件,具体位置为 src/ros2_21_tutorials/learning_launch/launch/remapping.launch.py 内容如下:

from launch import LaunchDescription      # launch文件的描述类
from launch_ros.actions import Node       # 节点启动的描述类def generate_launch_description():        # 自动生成launch文件的函数return LaunchDescription([            # 返回launch文件的描述信息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'),         # 将/input/pose话题名修改为/turtlesim1/turtle1/pose('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'),  # 将/output/cmd_vel话题名修改为/turtlesim2/turtle1/cmd_vel])])

在这里插入图片描述

命名空间的概念实际上就是在强化 隔离 的思想。想象一下,在一个空间中有两台机器人,这两台机器人的硬件完全一样,假设每台都有 camera_headcamera_leftcamera_right 三个相机,如果仅重命名节点的形式规避节点重名,那么你会得到以下几个话题:

  • Robot1: camera_head_1camera_left_1camera_right_1
  • Robot2: camera_head_2camera_left_2camera_right_2

难道我们每个话题和服务都要以后缀数字的形式进行编号么,这显然过于繁琐,且对算法而言要区分的就太多了。如果有需要修改一个机器人的信息则要全局范围修改。命名空间则可以帮助我们简化这一流程,通过命名空间可以将话题转化为:

  • Robot1:Robot1/camera_headRobot1/camera_leftRobot1/camera_right
  • Robot2:Robot2/camera_headRobot2/camera_leftRobot2/camera_right

当需要对机器人进行重命名或者将机器人移动到其他组中,则可以直接修改命名空间即可。


4.3 同时控制两只海龟

remapping.launch.py 文件中还有一个名为 minic 的节点,该节点实现的功能是 将一个海龟的位置转换成另一个海龟的控制指令

在这里插入图片描述

此时新开一个终端向话题 `` 发送控制指令会看到两只海龟同步运动:

$  ros2 topic pub /turtlesim1/turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.5, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.3}}"

在这里插入图片描述

体验完后就可以关闭这两个仿真器。


5. param 参数加载

5.1 直接在 launch 文件中加载参数

同样可以通过 launch 文件在启动的时候将参数加载进去,打开 learning_launch 功能包中 launch/parameters.launch.py 文件,具体位置在 src/ros2_21_tutorials/learning_launch/launch/parameters.launch.py 处:

from launch import LaunchDescription                   # launch文件的描述类
from launch.actions import DeclareLaunchArgument       # 声明launch文件内使用的Argument类
from launch.substitutions import LaunchConfiguration, TextSubstitutionfrom launch_ros.actions import Node                    # 节点启动的描述类def generate_launch_description():                     # 自动生成launch文件的函数background_r_launch_arg = DeclareLaunchArgument('background_r', default_value=TextSubstitution(text='0')     # 创建一个Launch文件内参数(arg)background_r)background_g_launch_arg = DeclareLaunchArgument('background_g', default_value=TextSubstitution(text='84')    # 创建一个Launch文件内参数(arg)background_g)background_b_launch_arg = DeclareLaunchArgument('background_b', default_value=TextSubstitution(text='122')   # 创建一个Launch文件内参数(arg)background_b)return LaunchDescription([                                      # 返回launch文件的描述信息background_r_launch_arg,                                     # 调用以上创建的参数(arg)background_g_launch_arg,background_b_launch_arg,Node(                                                        # 配置一个节点的启动package='turtlesim',executable='turtlesim_node',                              # 节点所在的功能包name='sim',                                               # 对节点重新命名parameters=[{                                             # ROS参数列表'background_r': LaunchConfiguration('background_r'),   # 创建参数background_r'background_g': LaunchConfiguration('background_g'),   # 创建参数background_g'background_b': LaunchConfiguration('background_b'),   # 创建参数background_b}]),])

在这里插入图片描述

使用下面命令运行该 launch 文件:

$ ros2 launch learning_launch parameters.launch.py 

在这里插入图片描述


5.2 通过参数文件形式加载

在之前讲 param 的博客中提到了参数可以写成 yaml 文件的形式然后用 dump 和 load 命令进行加载,launch 也可以实现相同的功能。

参数配置文件 yaml 在 src/ros2_21_tutorials/learning_launch/config/turtlesim.yaml 处:

/turtlesim2/sim:ros__parameters:background_b: 0background_g: 0background_r: 0

启动的 launch 文件在 src/ros2_21_tutorials/learning_launch/launch/parameters_yaml.launch.py 处:

import osfrom ament_index_python.packages import get_package_share_directory  # 查询功能包路径的方法from launch import LaunchDescription   # launch文件的描述类
from launch_ros.actions import Node    # 节点启动的描述类def generate_launch_description():     # 自动生成launch文件的函数config = os.path.join(              # 找到参数文件的完整路径get_package_share_directory('learning_launch'),'config','turtlesim.yaml')return LaunchDescription([          # 返回launch文件的描述信息Node(                            # 配置一个节点的启动package='turtlesim',          # 节点所在的功能包executable='turtlesim_node',  # 节点的可执行文件名namespace='turtlesim2',       # 节点所在的命名空间name='sim',                   # 对节点重新命名parameters=[config]           # 加载参数文件)])

在这里插入图片描述

使用下面的命令启动这个 launch 文件:

$ ros2 launch learning_launch parameters_yaml.launch.py

在这里插入图片描述


6. launch 文件嵌套

在复杂机器人系统中经常会出现 launch 文件嵌套的情况,例如一个 launch 文件只包含各种算法、一个 launch 文件只包含各种硬件驱动、一个 launch 文件只包含和上层的交互功能。

打开 learning_launch 功能包中的 launch/namespaces.launch.py 文件,具体位置在 src/ros2_21_tutorials/learning_launch/launch/namespaces.launch.py

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

在这里插入图片描述

在上面的代码中还需要注意的是 PushRosNamespace 函数,该函数的功能是给新包含的 launch 文件添加一个命名空间,这样做的意义在于 当你不知道嵌套的 launch 文件中是否存在冲突的名字时,多套一层命名空间准没错:

在这里插入图片描述

该 launch 文件嵌套了一个 parameters_nonamespace.launch.py 文件:

import osfrom ament_index_python.packages import get_package_share_directoryfrom launch import LaunchDescription
from launch_ros.actions import Nodedef generate_launch_description():config = os.path.join(get_package_share_directory('learning_launch'),'config','turtlesim.yaml')return LaunchDescription([Node(package='turtlesim',executable='turtlesim_node',name='sim',parameters=[config])])

在这里插入图片描述


7. 配置 launch 编译条件

在编写好 launch 文件后需要告诉编译器将这些文件安装到 install 目录下,和之前博客中添加节点一样,同样需要在 setup.py 文件中添加这些 launch 文件,具体位置在 src/ros2_21_tutorials/learning_launch/setup.py
处:

from setuptools import setup
import os
from glob import globpackage_name = 'learning_launch'setup(name=package_name,version='0.0.0',packages=[package_name],data_files=[('share/ament_index/resource_index/packages',['resource/' + package_name]),('share/' + package_name, ['package.xml']),(os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*.launch.py'))),(os.path.join('share', package_name, 'config'), glob(os.path.join('config', '*.*'))),(os.path.join('share', package_name, 'rviz'), glob(os.path.join('rviz', '*.*'))),],install_requires=['setuptools'],zip_safe=True,maintainer='hcx',maintainer_email='huchunxu@guyuehome.com',description='TODO: Package description',license='TODO: License declaration',tests_require=['pytest'],entry_points={'console_scripts': [],},
)

在这里插入图片描述

http://www.dtcms.com/a/588957.html

相关文章:

  • nginx源码安装以及平滑升级
  • [特殊字符] Spring AOP 注解方式详解
  • C++——二叉搜索树
  • 青少年机器人技术等级考试理论综合试卷(一级)2020年9月
  • Redis_9_Set
  • 计算机网络培训课程大庆网站建设优化
  • 网站正在建设中永久wordpress 前台文章
  • Electron 桌面应用开发入门指南:从零开始打造 Hello World
  • 深入解析手机快充技术原理与实现
  • JavaScript 数组方法大全
  • 电子商务网站建设与管理的实验报告个人怎样免费建网站
  • STM32F103学习笔记-16-RCC(第3节)-使用HSE配置系统时钟并使用MCO输出监控系统时钟
  • LeRobot 入门教程(十五)从Hub加载环境
  • HTML DOM 总结
  • 社群经济下开源链动2+1模式AI智能名片S2B2C商城小程序的信任重构机制研究
  • Git 命令大全:从基础到高级操作
  • Git_Rebase
  • 【深度学习|学习笔记】异常检测概论 — 从经典算法到深度学习(含实用 Python 示例)
  • 如何建立一个视频网站html5 手机网站页面实例
  • FlutterPlugin接口实现与插件架构设计
  • 图漾GM461-E1相机专栏
  • Flutter与鸿蒙原生MethodChannel通信机制深度解析
  • Navigation2 行为树架构源码级分析与设计原理
  • 基于时频域霍夫变换的汽车雷达互干扰抑制——论文阅读
  • 贵阳网站建设建站系统怎么找网站是由什么建的
  • 一本通网站1128题:图像模糊处理
  • DrissionPage遇到iframe
  • 基于信号分解的FMCW雷达相互干扰抑制——论文阅读
  • 未来的一些想法和规划
  • 线代强化NO3|线性方程组|特征值和特征向量|矩阵的相似性|实对称矩阵|二次型