使用 Python、XML 和 YAML 编写 ROS 2 Launch 文件

这篇具有很好参考价值的文章主要介绍了使用 Python、XML 和 YAML 编写 ROS 2 Launch 文件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

系列文章目录

ROS2 重要概念
ament_cmake_python 用户文档
ROS2 ament_cmake 用户文档
使用 rosdep 管理 ROS 2 依赖项



前言

ROS 2 launch 文件可以用 Python、XML 和 YAML 编写。本指南介绍了如何使用这些不同的格式来完成相同的任务,并对何时使用每种格式进行了讨论。


一、Launch 文件示例

下面是一个用 Python、XML 和 YAML 实现的 Launch 文件。每个 Launch 文件都执行以下操作:

  • 使用默认值设置命令行参数

  • 包含另一个 launch 文件

  • 在另一个命名空间中包含另一个启动文件

  • 启动节点并设置其名称空间

  • 启动一个节点,设置其名称空间,并在该节点中设置参数(使用参数)

  • 创建一个节点,将消息从一个话题重新映射到另一个话题

1.1 Python 版本

首先介绍涉及到的几个 方法

  1. ament_index_python.get_package_share_path(package_name, print_warning=True)
以 pathlib.Path 的形式返回给定软件包的共享目录。
例如,如果您将软件包 "foo "安装到"/home/user/ros2_ws/install",并以 "foo"作为参数调用此函数,那么它将返回一个代表"/home/user/ros2_ws/install/share/foo"的路径,然后您就可以用它来构建共享文件的路径,即 get_package_share_path('foo') /'urdf/robot.urdf'
  1. launch.LaunchDescription
基础: LaunchDescriptionEntity
可启动系统的描述。
该描述由一系列实体组成,这些实体代表了系统设计师的意图。
该描述还可能有参数,参数由该启动描述中的 launch.actions.DeclareLaunchArgument 操作声明。
该描述的参数可通过 get_launch_arguments() 方法访问。参数是通过搜索此启动描述中的实体和每个实体的描述(可能包括由这些实体产生的实体)收集的。
  1. launch.actions.declare_launch_argument.DeclareLaunchArgument(Action)
基础: Action
声明新启动参数的 Action。
启动参数存储在同名的 "启动配置 "中。请参阅 launch.actions.SetLaunchConfiguration 和 launch.substitutions.LaunchConfiguration。
在 launch.LaunchDescription 中声明的任何启动参数都会在包含该启动描述时作为参数显示出来,例如,在 launch.actions.IncludeLaunchDescription 动作中作为附加参数,或在使用 ros2 launch .... 启动时作为命令行参数。
除了名称(也是参数结果的存储位置)外,启动参数还可能有一个默认值、一个有效值选择列表和一个描述。如果给出了默认值,那么该参数就变成了可选参数,默认值将被放置在启动配置中。如果没有给出默认值,并且在包含启动说明时也没有给出值,则会发生错误。如果给出了一个选择列表,而给定值不在其中,则会发生错误。
默认值可以使用 Substitutions,但名称和描述只能是 Text,因为它们在启动前需要一个有意义的值,例如在列出命令行参数时。
需要注意的是,声明启动参数必须在启动描述的某个部分,而这个部分在不启动的情况下是可以描述的。例如,如果你在条件组中或作为事件处理程序的回调声明了一个启动参数,那么像 ros2 launch 这样的工具可能无法在启动描述之前知道该参数。在这种情况下,该参数在命令行上将不可见,但如果该参数在访问后未满足要求(且没有默认值),则可能引发异常。
换句话说,访问该操作的后置条件要么是同名的启动配置设置了值,要么是由于没有设置任何值且没有默认值而引发异常。但是,前置条件并不能保证在条件或情况夹杂后面的参数是可见的。
例如;
ld = LaunchDescription([
    DeclareLaunchArgument('simple_argument'),
    DeclareLaunchArgument('with_default_value', default_value='default'),
    DeclareLaunchArgument(
        'with_default_and_description',
        default_value='some_default',
        description='this argument is used to configure ...'),
    DeclareLaunchArgument(
        'mode',
        default_value='A',
        description='Choose between mode A and mode B',
        choices=['A', 'B']),
    # other actions here, ...
])
  1. launch.actions.GroupAction
基础: Action
可产生其他操作的 Action。
此操作用于嵌套其他操作,而无需包含单独的启动说明,同时还可选择具有一个条件(与所有其他操作一样)、扩展和转发启动配置和环境变量,以及/或仅为组及其产生的操作声明启动配置。
Scoped=True 时,对启动配置和环境变量的更改仅限于组操作中的操作范围。
当 scopeed=True 和 forwarding=True 时,所有现有的启动配置和环境变量都可在作用域上下文中使用。
当 scope=True 和 forwarding=False 时,所有现有的启动配置和环境变量都会从作用域上下文中移除。
launch_configurations 字典中定义的任何启动配置都将在当前上下文中设置。当 scopeed=False 时,即使 GroupAction 已完成,这些配置也将持续存在。当 scoped=True 时,这些配置将仅对 GroupAction 中的动作可用。当 scope=True 和 forwarding=False 时,launch_configurations 字典将在清除前进行评估,然后在清除的 scope 上下文中重新设置。
  1. launch.actions.IncludeLaunchDescription
基础: Action
包含启动描述源并在访问时生成其实体的动作。
可以向启动描述传递参数,这些参数是通过 launch.actions.DeclareLaunchArgument 动作声明的。
如果给定的参数与已声明的启动参数名称不匹配,则仍会使用 launch.actions.SetLaunchConfiguration 动作将其设置为启动配置。这样做的原因是,在给定的启动描述中,并非总能检测到所有已声明启动参数类的实例。
另一方面,如果给定的启动描述声明了启动参数,但未向此操作提供其值,有时会引发错误。不过,只有当声明的启动参数是无条件的(有时声明启动参数的操作只有在特定情况下才会被访问),并且没有默认值可供选择时,才会产生这种错误。
有条件包含的启动参数如果没有默认值,在尽力进行参数检查后仍无法提前发现未满足的参数时,最终将引发错误。
  1. launch.launch_description_sources.PythonLaunchDescriptionSource(LaunchDescriptionSource)
基础: LaunchDescriptionSource
Python 启动文件的封装,可在启动过程中加载。
  1. launch.substitutions.LaunchConfiguration(Substitution)
可访问启动配置变量的替代变量。
  1. launch.substitutions.TextSubstitution(Substitution)
可对单个字符串文本进行替换。
  1. PushROSNamespace(Action)
推送 ros 命名空间的动作。
在有作用域的 `GroupAction` 中使用时,它会自动弹出。没有其他方法可以弹出它。 
  1. XMLLaunchDescriptionSource(FrontendLaunchDescriptionSource)
封装 XML 启动文件,可在启动过程中加载。
  1. YAMLLaunchDescriptionSource(FrontendLaunchDescriptionSource)
封装 YAML 启动文件,可在启动过程中加载。
  1. Node(ExecuteProcess)
执行一个 ROS 节点的操作。

Python 代码如下

# example_launch.py

import os

from ament_index_python import get_package_share_directory

from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.actions import GroupAction
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import LaunchConfiguration
from launch.substitutions import TextSubstitution
from launch_ros.actions import Node
from launch_ros.actions import PushRosNamespace
from launch_xml.launch_description_sources import XMLLaunchDescriptionSource
from launch_yaml.launch_description_sources import YAMLLaunchDescriptionSource


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="255")
    )
    background_b_launch_arg = DeclareLaunchArgument(
        "background_b", default_value=TextSubstitution(text="0")
    )
    chatter_py_ns_launch_arg = DeclareLaunchArgument(
        "chatter_py_ns", default_value=TextSubstitution(text="chatter/py/ns")
    )
    chatter_xml_ns_launch_arg = DeclareLaunchArgument(
        "chatter_xml_ns", default_value=TextSubstitution(text="chatter/xml/ns")
    )
    chatter_yaml_ns_launch_arg = DeclareLaunchArgument(
        "chatter_yaml_ns", default_value=TextSubstitution(text="chatter/yaml/ns")
    )

    # include another launch file
    launch_include = IncludeLaunchDescription(
        PythonLaunchDescriptionSource(
            os.path.join(
                get_package_share_directory('demo_nodes_cpp'),
                'launch/topics/talker_listener_launch.py'))
    )
    # include a Python launch file in the chatter_py_ns namespace
    launch_py_include_with_namespace = GroupAction(
        actions=[
            # push_ros_namespace to set namespace of included nodes
            PushRosNamespace('chatter_py_ns'),
            IncludeLaunchDescription(
                PythonLaunchDescriptionSource(
                    os.path.join(
                        get_package_share_directory('demo_nodes_cpp'),
                        'launch/topics/talker_listener_launch.py'))
            ),
        ]
    )

    # include a xml launch file in the chatter_xml_ns namespace
    launch_xml_include_with_namespace = GroupAction(
        actions=[
            # push_ros_namespace to set namespace of included nodes
            PushRosNamespace('chatter_xml_ns'),
            IncludeLaunchDescription(
                XMLLaunchDescriptionSource(
                    os.path.join(
                        get_package_share_directory('demo_nodes_cpp'),
                        'launch/topics/talker_listener_launch.xml'))
            ),
        ]
    )

    # include a yaml launch file in the chatter_yaml_ns namespace
    launch_yaml_include_with_namespace = GroupAction(
        actions=[
            # push_ros_namespace to set namespace of included nodes
            PushRosNamespace('chatter_yaml_ns'),
            IncludeLaunchDescription(
                YAMLLaunchDescriptionSource(
                    os.path.join(
                        get_package_share_directory('demo_nodes_cpp'),
                        'launch/topics/talker_listener_launch.yaml'))
            ),
        ]
    )

    # start a turtlesim_node in the turtlesim1 namespace
    turtlesim_node = Node(
        package='turtlesim',
        namespace='turtlesim1',
        executable='turtlesim_node',
        name='sim'
    )

    # start another turtlesim_node in the turtlesim2 namespace
    # and use args to set parameters
    turtlesim_node_with_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
    forward_turtlesim_commands_to_second_turtlesim_node = Node(
        package='turtlesim',
        executable='mimic',
        name='mimic',
        remappings=[
            ('/input/pose', '/turtlesim1/turtle1/pose'),
            ('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'),
        ]
    )

    return LaunchDescription([
        background_r_launch_arg,
        background_g_launch_arg,
        background_b_launch_arg,
        chatter_py_ns_launch_arg,
        chatter_xml_ns_launch_arg,
        chatter_yaml_ns_launch_arg,
        launch_include,
        launch_py_include_with_namespace,
        launch_xml_include_with_namespace,
        launch_yaml_include_with_namespace,
        turtlesim_node,
        turtlesim_node_with_parameters,
        forward_turtlesim_commands_to_second_turtlesim_node,
    ])

1.2 XML 版本

<!-- example_launch.xml -->

<launch>

    <!-- args that can be set from the command line or a default will be used -->
    <arg name="background_r" default="0" />
    <arg name="background_g" default="255" />
    <arg name="background_b" default="0" />
    <arg name="chatter_py_ns" default="chatter/py/ns" />
    <arg name="chatter_xml_ns" default="chatter/xml/ns" />
    <arg name="chatter_yaml_ns" default="chatter/yaml/ns" />

    <!-- include another launch file -->
    <include file="$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener_launch.py" />
    <!-- include a Python launch file in the chatter_py_ns namespace-->
    <group>
        <!-- push_ros_namespace to set namespace of included nodes -->
        <push_ros_namespace namespace="$(var chatter_py_ns)" />
        <include file="$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener_launch.py" />
    </group>
    <!-- include a xml launch file in the chatter_xml_ns namespace-->
    <group>
        <!-- push_ros_namespace to set namespace of included nodes -->
        <push_ros_namespace namespace="$(var chatter_xml_ns)" />
        <include file="$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener_launch.xml" />
    </group>
    <!-- include a yaml launch file in the chatter_yaml_ns namespace-->
    <group>
        <!-- push_ros_namespace to set namespace of included nodes -->
        <push_ros_namespace namespace="$(var chatter_yaml_ns)" />
        <include file="$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener_launch.yaml" />
    </group>

    <!-- start a turtlesim_node in the turtlesim1 namespace -->
    <node pkg="turtlesim" exec="turtlesim_node" name="sim" namespace="turtlesim1" />
    <!-- start another turtlesim_node in the turtlesim2 namespace
        and use args to set parameters -->
    <node pkg="turtlesim" exec="turtlesim_node" name="sim" namespace="turtlesim2">
        <param name="background_r" value="$(var background_r)" />
        <param name="background_g" value="$(var background_g)" />
        <param name="background_b" value="$(var background_b)" />
    </node>
    <!-- perform remap so both turtles listen to the same command topic -->
    <node pkg="turtlesim" exec="mimic" name="mimic">
        <remap from="/input/pose" to="/turtlesim1/turtle1/pose" />
        <remap from="/output/cmd_vel" to="/turtlesim2/turtle1/cmd_vel" />
    </node>
</launch>

1.3 YAML 版本

# example_launch.yaml

launch:

# args that can be set from the command line or a default will be used
- arg:
    name: "background_r"
    default: "0"
- arg:
    name: "background_g"
    default: "255"
- arg:
    name: "background_b"
    default: "0"
- arg:
    name: "chatter_py_ns"
    default: "chatter/py/ns"
- arg:
    name: "chatter_xml_ns"
    default: "chatter/xml/ns"
- arg:
    name: "chatter_yaml_ns"
    default: "chatter/yaml/ns"


# include another launch file
- include:
    file: "$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener_launch.py"

# include a Python launch file in the chatter_py_ns namespace
- group:
    - push_ros_namespace:
        namespace: "$(var chatter_py_ns)"
    - include:
        file: "$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener_launch.py"

# include a xml launch file in the chatter_xml_ns namespace
- group:
    - push_ros_namespace:
        namespace: "$(var chatter_xml_ns)"
    - include:
        file: "$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener_launch.xml"

# include a yaml launch file in the chatter_yaml_ns namespace
- group:
    - push_ros_namespace:
        namespace: "$(var chatter_yaml_ns)"
    - include:
        file: "$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener_launch.yaml"

# start a turtlesim_node in the turtlesim1 namespace
- node:
    pkg: "turtlesim"
    exec: "turtlesim_node"
    name: "sim"
    namespace: "turtlesim1"

# start another turtlesim_node in the turtlesim2 namespace and use args to set parameters
- node:
    pkg: "turtlesim"
    exec: "turtlesim_node"
    name: "sim"
    namespace: "turtlesim2"
    param:
    -
      name: "background_r"
      value: "$(var background_r)"
    -
      name: "background_g"
      value: "$(var background_g)"
    -
      name: "background_b"
      value: "$(var background_b)"

# perform remap so both turtles listen to the same command topic
- node:
    pkg: "turtlesim"
    exec: "mimic"
    name: "mimic"
    remap:
    -
        from: "/input/pose"
        to: "/turtlesim1/turtle1/pose"
    -
        from: "/output/cmd_vel"
        to: "/turtlesim2/turtle1/cmd_vel"

二、从命令行使用 Launch 文件

1. Launching

上述任何启动文件都可以通过 ros2 launch 运行。要在本地试用它们,可以创建一个新软件包,然后使用

ros2 launch <package_name> <launch_file_name>

或通过指定 launch 文件的路径直接运行该文件

ros2 launch <path_to_launch_file>

2. 设置参数

要设置传递给启动文件的参数,应使用 key:=value 语法。例如,可以用以下方式设置 background_r 的值:

ros2 launch <package_name> <launch_file_name> background_r:=255
ros2 launch <path_to_launch_file> background_r:=255

3. 控制海龟

要测试重映射是否有效,可以在另一个终端运行以下命令来控制海龟:

ros2 run turtlesim turtle_teleop_key --ros-args --remap __ns:=/turtlesim1

三、Python、XML 或 YAML: 我应该使用哪种语言?

ROS 1 中的启动文件是用 XML 编写的,因此对于来自 ROS 1 的用户来说,XML 可能是最熟悉的。

对于大多数应用程序来说,选择哪种 ROS 2 启动格式取决于开发人员的偏好。不过,如果你的启动文件需要有 XML 或 YAML 无法实现的灵活性,你可以使用 Python 来编写启动文件。由于以下两个原因,使用 Python 编写 ROS 2 启动文件更为灵活:

  • Python 是一种脚本语言,因此您可以在启动文件中使用该语言及其库。

  • ros2/launch(一般启动功能)和 ros2/launch_ros(ROS 2 特定启动功能)都是用 Python 编写的,因此你可以访问 XML 和 YAML 可能无法提供的较低级别的启动功能。

尽管如此,用 Python 编写的启动文件可能比 XML 或 YAML 编写的文件更复杂、更冗长。

四、为什么要使用 ROS 2 Launch

ROS 2 系统通常由运行在多个不同进程(甚至不同机器)上的多个节点组成。虽然每个节点都可以单独运行,但很快就会变得非常麻烦。

ROS 2 中的启动系统旨在通过一条命令自动运行多个节点。它可以帮助用户描述系统配置,然后按描述执行。系统配置包括运行哪些程序、在哪里运行、传递哪些参数,以及 ROS 特有的约定,通过为每个组件提供不同的配置,可以方便地在整个系统中重复使用组件。它还负责监控已启动进程的状态,并对这些进程的状态变化做出报告和/或反应。

上述所有内容都在一个启动文件中指定,该文件可以用 Python、XML 或 YAML 编写。使用 ros2 launch 命令运行该启动文件后,所有指定的节点都将运行。

设计文档详细介绍了 ROS 2 启动系统的设计目标(目前尚未提供所有功能)。文章来源地址https://www.toymoban.com/news/detail-745300.html


到了这里,关于使用 Python、XML 和 YAML 编写 ROS 2 Launch 文件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【ROS2指南-8】入门Launch启动脚本

    目标: 创建launch文件以运行复杂的 ROS 2 系统。 教程级别: 初学者 时间: 10分钟 内容 背景 先决条件 任务 1 设置 2 编写启动文件 3 ros2发射 4 使用 rqt_graph 反省系统 概括 下一步 在到目前为止的教程中,您一直在为您运行的每个新节点打开新终端。随着越来越多的节点同时运

    2024年02月15日
    浏览(72)
  • 【ROS知识】比较ROS1和ROS2在处理launch的不同

            在处理launch过程中,ROS1和ROS2还是有些差别的,因为文件结构不同,不能直接搬用。这里将两者建立过程做一个比对,以提升概念的清晰度。         在ROS2中,单独的launch文件是一个python文件,因此脱离ros2环境也能启动,问题是,如果launch文件添加到ros2的包内,如

    2024年02月09日
    浏览(45)
  • 【ROS2机器人入门到实战】使用RCLCPP编写节点

    当前平台文章汇总地址:ROS2机器人从入门到实战 获取完整教程及配套资料代码,请关注公众号鱼香ROS获取 教程配套机器人开发平台:两驱版| 四驱版 为方便交流,搭建了机器人技术问答社区:地址 fishros.org.cn 节点需要存在于功能包当中、功能包需要存在于工作空间当中。所

    2024年02月02日
    浏览(100)
  • ROS入门学习三——launch文件

    launch作用:便于一次启动多个节点,可启动本地节点和远程节点及修改添加参数服务器参数。 launch文件的建立 在功能包下,新建launch文件夹 ,在launch文件夹下添加后缀为launch的文件。  launch文件的启动  一、 launch文件之node标签 上面例子中launch文件启动时是多线程的,不一

    2024年02月16日
    浏览(38)
  • 【ROS学习】节点运行管理launch文件的基本操作

    launch文件的概念和作用 launch 文件是一个 XML 格式的文件,可以启动本地和远程的多个节点,还可以在参数服务器中设置参数。 launch文件的作用是:简化节点的配置与启动,提高ROS程序的启动效率。 使用场景 launch文件在ros中使用还是比较广泛的,比如:一个程序中可能需要启

    2024年02月06日
    浏览(42)
  • ROS第 12 课 Launch 启动文件的使用方法

      我们在前面的教程里面通过命令行来尝试运行新的节点。但随着创建越来越复杂的机器人系统中,打开多个终端且重新输入设置就变得越来越麻烦。   因此我们可以通过创建一个Launch文件,可以同时启动并配置多个需执行的ROS节点,启动更多的功能,另外还可自动启动

    2024年01月21日
    浏览(51)
  • 【手把手做ROS2机器人系统开发五】使用C++实现编写简单的服务器和客户端

    目录 使用C++实现编写简单的服务器和客户端 一、程序编写 1、创建软件包  2、编译软件包 3、软件配置 4、服务器程序编写 5、客户端程序编写 6、软件包设置 7、设置编译选项 二、程序测试 1、编译程序 2、开启节点测试运行 3、执行效果展示          上一讲我们讲解了如

    2024年02月10日
    浏览(43)
  • ROS1&ROS2之CmakeList.txt和package.xml用法详解

    前言:目前还在学习ROS+无人机框架中,,, 更多更新文章详见我的个人博客主页【前往】 在 ROS 系统的功能包中 要包含 CMakeLists.txt 与 package.xml 文件来编译功能包的内容 CMakeLists.txt 原本是 Cmake 编译系统的规则文件,而 Catkin 编译系统基本沿用了 CMake 的编译风格,只是针对

    2024年02月15日
    浏览(35)
  • K8S学习笔记-01(yaml文件编写)

    原创文档编写不易,未经许可请勿转载。文档中有疑问的可以邮件联系我。 邮箱:yinwanit@163.com 记录k8s中yaml文件编写相关内容。 k8s官网文档库:https://kubernetes.io/docs/home/ kubelet 命令参考:https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands k8s中yaml文件结尾需以.yml或.yaml结

    2024年02月14日
    浏览(38)
  • k8s学习笔记-3(Pod yaml文件编写)

    原创文档编写不易,未经许可请勿转载。文档中有疑问的可以邮件联系我。 邮箱:yinwanit@163.com Pod在k8s中归属apiVersion版本为v1。在编写yaml文件中apiVersion应该设置为v1。kind才能设置成Pod。 编写Pod的yaml文件时可以参考  kubectl explain --api-version=v1  pod. 一级一级查看具体的配置项

    2024年02月14日
    浏览(116)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包