在launch多节点执行方面,ROS2与ROS1有很大不同。首先,ros2与ros1不同之处,在于ROS2不再有*.launch脚本文件,取而代之的是 3 种格式得以实现:
ros2 launch <package_name> <launch_file_name>
像这样:
ros2 launch turtlesim_mimic_launch.py
3.1 launch 文件内容描述
因为launch file 文件毕竟是多节点执行脚本,因此,与“ ros2 run ” 指令的内容大致相同,如包名、节点名。当然,要丰富一些。如:
"turtlesim" exec="turtlesim_node" name="sim" namespace="turtlesim2"> -
- "background_r" value="$(var background_r)"/>
-
- "background_g" value="$(var background_g)"/>
-
- "background_b" value="$(var background_b)"/>
-
-
3.2 关于include
include 可以在一个 launch file 中包含另外的 launch file
group 可以把多个 node 组合在一起
无论是 python、xml 还是 yaml,编写 launch file 的步骤差不多一样。
以下是官方文档 一个例子,是针对海龟turtlesim的例子:
- from launch import LaunchDescriptionfrom 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'),
- ])
-
- ])
以上代码很清晰,就是启动两个海龟节点,一个mimic节点;上述有些需要解释的概念有:命名空间啥作用?重映射有什么要点?(需要执行后,用指令行进行分析)
remap 是一个非常有用的技巧,一般用来做 Topic 的映射的。某节点本来不认识这个Topic,但通过重起名,或叫伪名,或叫重新伪装(注意,这里订阅者只收某种名称的Topic),使某些接收到该Topic。
from="/different_topic" to="/needed_topic"/>
把 from 中的 topic,转换成 to 指定的 topic
有 2 种用途:
我们注意到上面的 launch file 中有 args,比如 background_r,命令行启动时可以将数据透传过去,通过 key:=value 形式。 如:
ros2 launch <package_name> <launch_file_name> background_r:=255
以下代码用于参考,是同样内容的三种文件实现方法,因为比较长,希望大家慢慢对照阅读。
- # 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 中 标签中的内容
-
- <launch>
-
-
- <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 file="$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener.launch.py"/>
-
- <group>
-
- <push-ros-namespace namespace="$(var chatter_ns)"/>
- <include file="$(find-pkg-share demo_nodes_cpp)/launch/topics/talker_listener.launch.py"/>
- group>
-
-
- <node pkg="turtlesim" exec="turtlesim_node" name="sim" namespace="turtlesim1"/>
-
- <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>
-
- <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>
- # 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"
参考文章:
Using Python, XML, and YAML for ROS 2 Launch Files — ROS 2 Documentation: Foxy documentation
ROS2 中的 launch 文件入门的 6 个疑问 - 知乎 (zhihu.com)