找回密码
 立即注册
首页 业界区 业界 ROS2之Launch介绍

ROS2之Launch介绍

蝌棚煌 2 小时前
在前面的ROS2学习中,每当我们运行一个ROS节点,都需要打开一个新的终端运行一个命令。机器人系统中节点很多,每次都这样启动好麻烦。有没有一种方式可以一次性启动所有节点呢?答案当然是肯定的,那就是Launch启动文件,它是ROS系统中多节点启动与配置的一种脚本。
一、Launch文件

ROS2的launch文件有三种格式,python、xml、yaml。其中ROS2官方推荐的时python方式编写launch文件。
原因在于,相较于XML和YAML,Python是一个编程语言,更加的灵活,我们可以利用Python的很多库来做一些其他工作(比如创建一些初始化的目录等)。
我们首先创建my_learning_launch的Python版本的功能包;
  1. pi@NanoPC-T6:~/dev_ws$ cd src
  2. pi@NanoPC-T6:~/dev_ws/src$ ros2 pkg create --build-type ament_python my_learning_launch
复制代码
打开my_learning_launch功能包,在my_learning_launch文件夹下创建子文件launch。
1.1 多节点启动

我们首先来看看如何启动多个节点。
1.1.1 代码实现

在launch文件夹下新建simple.launch.py;
  1. from launch import LaunchDescription           # launch文件的描述类
  2. from launch_ros.actions import Node            # 节点启动的描述类
  3. def generate_launch_description():             # 自动生成launch文件的函数
  4.     return LaunchDescription([                 # 返回launch文件的描述信息
  5.         Node(                                  # 配置一个节点的启动
  6.             package='my_learning_topic',       # 节点所在的功能包
  7.             executable='topic_helloworld_pub', # 节点的可执行文件
  8.         ),
  9.         Node(                                  # 配置一个节点的启动
  10.             package='my_learning_topic',       # 节点所在的功能包
  11.             executable='topic_helloworld_sub', # 节点的可执行文件名
  12.         ),
  13.     ])
复制代码
generate_launch_description是ROS2 launch文件的入口函数;

  • 必须命名为 generate_launch_description;
  • 必须返回一个 LaunchDescription 对象;
  • 这个函数会被launch系统自动调用。
Node配置详解:

  • package:节点所属的功能包名称
  • executable:可执行文件名称(通常是 setup.py 或 CMakeLists.txt 中定义的目标);
  • name:如果不指定 name,默认使用可执行文件名,指定name可以覆盖默认名称,节点全名 = 命名空间 + 节点名。
1.1.2 运行测试

启动终端,使用ros2中的launch命令来启动第一个launch文件:
  1. ros2 launch my_learning_launch simple.launch.py
复制代码
运行成功后,就可以在终端中看到发布者和订阅者两个节点的日志信息啦。
1.2 命令行参数配置

我们使用ros2命令在终端中启动节点时,还可以在命令后配置一些传入程序的参数,使用launch文件一样可以做到。
1.2.1 代码实现

命令行后边的参数是如何通过launch传入节点的呢?来看下这个launch文件。
在launch文件夹下创建rviz.launch.py;
  1. import os
  2. from ament_index_python.packages import get_package_share_directory # 查询功能包路径的方法
  3. from launch import LaunchDescription    # launch文件的描述类
  4. from launch_ros.actions import Node     # 节点启动的描述类
  5. def generate_launch_description():      # 自动生成launch文件的函数
  6.    rviz_config = os.path.join(          # 找到配置文件的完整路径
  7.       get_package_share_directory('my_learning_launch'),
  8.       'rviz',
  9.       'turtle_rviz.rviz'
  10.       )
  11.    return LaunchDescription([           # 返回launch文件的描述信息
  12.       Node(                             # 配置一个节点的启动
  13.          package='rviz2',               # 节点所在的功能包
  14.          executable='rviz2',            # 节点的可执行文件名
  15.          name='rviz2',                  # 对节点重新命名
  16.          arguments=['-d', rviz_config]  # 加载命令行参数
  17.       )
  18.    ])
复制代码
这是一个ros2启动Rviz2并加载自定义配置文件的launch文件,这里通过arguments指定了命令行参数。
1.2.2 运行测试

比如我们想要运行一个Rviz可视化上位机,并且加载某一个配置文件,使用命令行的话,是这样的:
  1. ros2 run rviz2 rviz2 -d <PACKAGE-PATH>/rviz/turtle_rviz.rviz
复制代码
命令后边还得跟一长串配置文件的路径,如果放在launch文件里,启动就优雅很多了:
  1. ros2 launch my_learning_launch rviz.launch.py
复制代码
1.3 资源重映射

ROS社区中的资源非常多,当我们使用别人代码的时候,经常会发现通信的话题名称不太符合我们的要求,能否对类似的资源重新命名呢?
为了提高软件的复用性,ROS提供了资源重映射的机制,可以帮助我们解决类似的问题。
1.3.1 代码实现

在launch文件夹下创建remapping.launch.py;
  1. from launch import LaunchDescription      # launch文件的描述类
  2. from launch_ros.actions import Node       # 节点启动的描述类
  3. def generate_launch_description():        # 自动生成launch文件的函数
  4.     return LaunchDescription([            # 返回launch文件的描述信息
  5.         Node(                             # 配置一个节点的启动
  6.             package='turtlesim',          # 节点所在的功能包
  7.             namespace='turtlesim1',       # 节点所在的命名空间
  8.             executable='turtlesim_node',  # 节点的可执行文件名
  9.             name='sim'                    # 对节点重新命名
  10.         ),
  11.         Node(                             # 配置一个节点的启动
  12.             package='turtlesim',          # 节点所在的功能包
  13.             namespace='turtlesim2',       # 节点所在的命名空间
  14.             executable='turtlesim_node',  # 节点的可执行文件名
  15.             name='sim'                    # 对节点重新命名
  16.         ),
  17.         Node(                             # 配置一个节点的启动
  18.             package='turtlesim',          # 节点所在的功能包
  19.             executable='mimic',           # 节点的可执行文件名
  20.             name='mimic',                 # 对节点重新命名
  21.             remappings=[                  # 资源重映射列表
  22.                 ('/input/pose', '/turtlesim1/turtle1/pose'),         # 将/input/pose话题名修改为/turtlesim1/turtle1/pose
  23.                 ('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'),  # 将/output/cmd_vel话题名修改为/turtlesim2/turtle1/cmd_vel
  24.             ]
  25.         )
  26.     ])
复制代码
这段代码实现了一个 "海龟模仿" 功能,让第二只海龟(turtlesim2)模仿第一只海龟(turtlesim1)的运动。这是ROS中一个经典的演示示例。
代码中首先创建两个独立的海龟仿真环境节点:

  • 第一个海龟仿真器:/turtlesim1/sim;
  • 第二个海龟仿真器:/turtlesim2/sim;
两个独立的海龟窗口会打开,每只海龟都有自己的话题和服务(可以通过ros2 topic list验证);

  • /turtlesim1/turtle1/pose (海龟1的位置);
  • /turtlesim2/turtle1/pose (海龟2的位置);
  • /turtlesim1/turtle1/cmd_vel (控制海龟1);
  • /turtlesim2/turtle1/cmd_vel (控制海龟2)。
接着创建模仿节点实现运动同步,这里要用到turtlesim功能包里另外一个节点,叫做mimic,它的功能是订阅某一个海龟的Pose位置,通过计算变换成一个同样运动的速度指令发布出去;具体原理如下:

  • 订阅:/input/pose(海龟1的位置话题)
  • 发布:/output/cmd_vel(海龟2的控制命令)
  • 算法:根据海龟1的当前位置,计算海龟2应该以什么速度运动才能到达相同位置。
1.3.2 数据流分析
  1. [海龟1运动] → [发布pose] → /turtlesim1/turtle1/pose
  2.                                     ↓
  3.                               mimic节点订阅
  4.                                     ↓  
  5.                         [计算控制命令] → /turtlesim2/turtle1/cmd_vel
  6.                                     ↓
  7.                             [海龟2接收命令并运动]
复制代码
具体话题映射:
  1. mimic节点内部:       重映射后:
  2. /input/pose      →   /turtlesim1/turtle1/pose  (订阅)
  3. /output/cmd_vel  →   /turtlesim2/turtle1/cmd_vel (发布)
复制代码
1.3.3 运行测试

启动一个终端,运行如下例程,很快会看到出现了两个小海龟仿真器界面;
  1. ros2 launch my_learning_launch rviz.launch.py
复制代码
再打开一个终端,发布如下话题,让海龟1动起来,海龟2也会一起运动:
  1. ros2 topic pub --rate 1 /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.8}}"
复制代码
或者使用键盘控制:
  1. ros2 run turtlesim turtle_teleop_key --ros-args --remap turtle1/cmd_vel:=/turtlesim1/turtle1/cmd_vel
复制代码
1.4 ROS参数设置

ROS系统中的参数,也可以在Launch文件中设置。
1.4.1 代码实现

在launch文件夹下创建parameters.launch.py;
  1. from launch import LaunchDescription                   # launch文件的描述类
  2. from launch.actions import DeclareLaunchArgument       # 声明launch文件内使用的Argument类
  3. from launch.substitutions import LaunchConfiguration, TextSubstitution
  4. from launch_ros.actions import Node                    # 节点启动的描述类
  5. def generate_launch_description():                     # 自动生成launch文件的函数
  6.    background_r_launch_arg = DeclareLaunchArgument(
  7.       'background_r', default_value=TextSubstitution(text='0')     # 创建一个Launch文件内参数(arg)background_r
  8.    )
  9.    background_g_launch_arg = DeclareLaunchArgument(
  10.       'background_g', default_value=TextSubstitution(text='84')    # 创建一个Launch文件内参数(arg)background_g
  11.    )
  12.    background_b_launch_arg = DeclareLaunchArgument(
  13.       'background_b', default_value=TextSubstitution(text='122')   # 创建一个Launch文件内参数(arg)background_b
  14.    )
  15.    return LaunchDescription([                                      # 返回launch文件的描述信息
  16.       background_r_launch_arg,                                     # 调用以上创建的参数(arg)
  17.       background_g_launch_arg,
  18.       background_b_launch_arg,
  19.       Node(                                                        # 配置一个节点的启动
  20.          package='turtlesim',
  21.          executable='turtlesim_node',                              # 节点所在的功能包
  22.          name='sim',                                               # 对节点重新命名
  23.          parameters=[{                                             # ROS参数列表
  24.             'background_r': LaunchConfiguration('background_r'),   # 创建参数background_r
  25.             'background_g': LaunchConfiguration('background_g'),   # 创建参数background_g
  26.             'background_b': LaunchConfiguration('background_b'),   # 创建参数background_b
  27.          }]
  28.       ),
  29.    ])
复制代码
注意:launch文件中出现的argument和parameter,虽都译为“参数”,但含义不同:

  • argument:仅限launch文件内部使用,方便在launch中调用某些数值;
  • parameter:ROS系统的参数,方便在节点见使用某些数值;
1.4.2 代码进阶

以上例程我们在launch文件中一个一个的设置参数,略显麻烦,当参数比较多的时候,建议使用参数文件进行加载。
在launch文件夹下创建parameters_yaml.launch.py;
  1. import os
  2. from ament_index_python.packages import get_package_share_directory  # 查询功能包路径的方法
  3. from launch import LaunchDescription   # launch文件的描述类
  4. from launch_ros.actions import Node    # 节点启动的描述类
  5. def generate_launch_description():     # 自动生成launch文件的函数
  6.    config = os.path.join(              # 找到参数文件的完整路径
  7.       get_package_share_directory('my_learning_launch'),
  8.       'config',
  9.       'turtlesim.yaml'
  10.       )
  11.    return LaunchDescription([          # 返回launch文件的描述信息
  12.       Node(                            # 配置一个节点的启动
  13.          package='turtlesim',          # 节点所在的功能包
  14.          executable='turtlesim_node',  # 节点的可执行文件名
  15.          namespace='turtlesim2',       # 节点所在的命名空间
  16.          name='sim',                   # 对节点重新命名
  17.          parameters=[config]           # 加载参数文件
  18.       )
  19.    ])
复制代码
注意:这里我们需要创建子文件夹config,并新增turtlesim.yaml;
  1. /turtlesim:
  2.   ros__parameters:
  3.     background_b: 150
  4.     background_g: 50
  5.     background_r: 100
  6.     qos_overrides:
  7.       /parameter_events:
  8.         publisher:
  9.           depth: 1000
  10.           durability: volatile
  11.           history: keep_last
  12.           reliability: reliable
  13.     use_sim_time: false
复制代码
1.4.3 运行测试

启动一个终端,运行如下命令:
  1. ros2 launch my_learning_launch parameters.launch.py
复制代码
在启动的海龟仿真器中,我们看到背景颜色被改变了,这个颜色参数的设置就是在launch文件中完成的;
1.5 嵌套

在复杂的机器人系统中,launch文件也会有很多,此时我们可以使用类似编程中的include机制,让launch文件互相包含。
在launch文件夹下创建namespaces.launch.py;
  1. import os
  2. from ament_index_python.packages import get_package_share_directory  # 查询功能包路径的方法
  3. from launch import LaunchDescription                 # launch文件的描述类
  4. from launch.actions import IncludeLaunchDescription  # 节点启动的描述类
  5. from launch.launch_description_sources import PythonLaunchDescriptionSource
  6. from launch.actions import GroupAction               # launch文件中的执行动作
  7. from launch_ros.actions import PushRosNamespace      # ROS命名空间配置
  8. def generate_launch_description():                   # 自动生成launch文件的函数
  9.    parameter_yaml = IncludeLaunchDescription(        # 包含指定路径下的另外一个launch文件
  10.       PythonLaunchDescriptionSource([os.path.join(
  11.          get_package_share_directory('my_learning_launch'), 'launch'),
  12.          '/parameters_nonamespace.launch.py'])
  13.       )
  14.    parameter_yaml_with_namespace = GroupAction(      # 对指定launch文件中启动的功能加上命名空间
  15.       actions=[
  16.          PushRosNamespace('turtlesim2'),
  17.          parameter_yaml]
  18.       )
  19.    return LaunchDescription([                        # 返回launch文件的描述信息
  20.       parameter_yaml_with_namespace
  21.    ])
复制代码
二、功能包编译配置

我们需要修改setup.py文件,添加配置文件;
  1.     ...
  2.     data_files=[
  3.         ('share/ament_index/resource_index/packages',
  4.             ['resource/' + package_name]),
  5.         ('share/' + package_name, ['package.xml']),
  6.         (os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*.launch.py'))),
  7.         (os.path.join('share', package_name, 'config'), glob(os.path.join('config', '*.*'))),
  8.         (os.path.join('share', package_name, 'rviz'), glob(os.path.join('rviz', '*.*'))),
  9.     ],
  10.     ...
复制代码
参考文章
[1] 古月居ROS2入门教程学习笔记

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册