前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ROS2 中的 launch 文件入门的 6 个疑问

ROS2 中的 launch 文件入门的 6 个疑问

作者头像
Frank909
发布2021-12-06 12:17:07
1.1K0
发布2021-12-06 12:17:07
举报
文章被收录于专栏:Frank909Frank909Frank909

本文记录了 ROS2 中 launch 文件学习过程中我个人觉得重要的 6 个基本问题,和大家分享,希望可以帮到初学者。

疑问1:launch 文件有什么用?

通过 launch 文件,ROS2 可以同时启动许多节点,这样简化了用命令行去多次启动不同的 Node。​

疑问2:launch 文件怎么用?

完整的命令:​

ros2 launch <package_name> <launch_file_name>

也可以直接启动 launch 文件,像这样:​

ros2 launch turtlesim_mimic_launch.py

turtlesim_mimic_launch.py 是一个 python 文件,在里面定义了一个 launch 文件的内容。​

但 ROS1 launch 是不支持 py 文件的,而事实上 launch 文件在 ROS2 中有 3 种格式可以实现:​

  1. python 脚本
  2. xml 文件
  3. yaml 文件

疑问3:launch 文件里面应该有什么?

node 相关

launch file 文件当中最重要的是 node 信息,它指定了包的信息、node 的名字还有可执行文件的路径。​

<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>

include

include 可以在一个 launch file 中包含另外的 launch file​

group

group 可以把多个 node 组合在一起​

疑问4:如何编写一个 launch file?

无论是 python、xml 还是 yaml,编写 launch file 的步骤差不多一样。​

  1. 设置命令行参数的默认值,
  2. 设置 launch file 的包含关系,通过 标签
  3. 设置 Node 信息,包括 name、namespace、parameter
  4. 如果需要设置 remmaping 则设置 remapping 关系

官方文档有出示个一个例子

# 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 IncludeLaunchDescription
from launch.actions import GroupAction
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


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_ns_launch_arg = DeclareLaunchArgument(
        "chatter_ns", default_value=TextSubstitution(text="my/chatter/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 another launch file in the chatter_ns namespace
    launch_include_with_namespace = GroupAction(
        actions=[
            # push-ros-namespace to set namespace of included nodes
            PushRosNamespace(LaunchConfiguration('chatter_ns')),
            IncludeLaunchDescription(
                PythonLaunchDescriptionSource(
                    os.path.join(
                        get_package_share_directory('demo_nodes_cpp'),
                        'launch/topics/talker_listener.launch.py'))
            ),
        ]
    )

    # 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_ns_launch_arg,
        launch_include,
        launch_include_with_namespace,
        turtlesim_node,
        turtlesim_node_with_parameters,
        forward_turtlesim_commands_to_second_turtlesim_node,
    ])

这是用 python 写的,最后返回的是 LaunchDescription 信息,这个等同于 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_ns" default="my/chatter/ns"/>

  <!-- include another launch file -->
  <include file="$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener.launch.py"/>
  <!-- include another launch file in the chatter_ns namespace-->
  <group>
    <!-- push-ros-namespace to set namespace of included nodes -->
    <push-ros-namespace namespace="$(var chatter_ns)"/>
    <include file="$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener.launch.py"/>
  </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>

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_ns"
    default: "my/chatter/ns"


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

# include another launch file in the chatter_ns namespace
- group:
    - push-ros-namespace:
        namespace: "$(var chatter_ns)"
    - include:
        file: "$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener.launch.py"

# 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"

疑问5:如何在 ros2 launch 时传递参数?

我们注意到上面的 launch file 中有 args,比如 background_r,命令行启动时可以将数据透传过去,通过 key:=value 形式。 如:

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

疑问6:remap 起什么作用?

remap 是一个非常有用的技巧,一般用来做 Topic 的映射的。​

其实就是移花接木,或者说是瞒天过海。​

<remap from="/different_topic" to="/needed_topic"/>

把 from 中的 topic,转换成 to 指定的 topic​

有 2 种用途:

  1. 把一个 node 原本来发布的 topic,映射为另外一个名字
  2. 把其他的 node 发布的原始 topic,映射为所需要的 topic

ROS2 官方教程的示例中有如下代码

Node(
    package='turtlesim',
    executable='mimic',
    name='mimic',
    remappings=[
      ('/input/pose', '/turtlesim1/turtle1/pose'),
      ('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'),
    ]
)

实践

官方教程有很详细的指引,这里简单概述一下。

1.创建 launch 文件

turtlesim_mimic_launch.py

from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        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'),
                ('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'),
            ]
        )
    ])

2.启动

ros2 launch turtlesim_mimic_launch.py

你会看到两个乌龟界面。

在这里插入图片描述
在这里插入图片描述

3. 调试

发送命令让乌龟动起来.​

新开一个终端,敲下面的命令。

ros2 topic pub -r 1 /turtlesim1/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}}"

我们仔细观察看到,发送的是 /turtlesim1/turtle1/cmd_vel 这个 Topic,但 2 只乌龟都运动起来,这是因为我们在 mimic 这个节点中做了remap 动作,相当于进行了消息的透传。​

我们可以通过 rqt_graph 查看更详细的信息。​

新开一个终端然后输入 rqt_graph。

在这里插入图片描述
在这里插入图片描述

它们之间的关系还是一目了然的。

参考

1.ROS2官方文档 2.ROS1官方文档

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-09-16 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 疑问1:launch 文件有什么用?
  • 疑问2:launch 文件怎么用?
  • 疑问3:launch 文件里面应该有什么?
    • node 相关
      • include
        • group
        • 疑问4:如何编写一个 launch file?
        • 疑问5:如何在 ros2 launch 时传递参数?
        • 疑问6:remap 起什么作用?
        • 实践
          • 1.创建 launch 文件
            • 2.启动
              • 3. 调试
              • 参考
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档