ros2 launch启动文件编写
ros1和ros2其中一个很大区别之一就是launch的编写方式。在ros1中采用xml格式编写launch,而ros2保留了xml格式launch,还另外引入了python和yaml编写方式。选择哪种编写取决于每位开发人员的爱好,但是ros2官方推荐使用python方式编写,理由如下:
1.Python 是一种脚本语言,使用灵活,python库强大,可以直接引入。
2.ros2 launch框架本身是用python编写,由于亲和力高python可以直接调用一些高级特性 ,而XML 和 YAML 可能无法调用。
当然了,用python编写也不是全部都是优点没有缺点,不然还要引入xml,yaml干嘛对吧?答案就是用 Python 编写的启动文件可能比 XML 或 YAML 编写的启动文件更复杂、更冗长。
一.运行方式
1.启动方式
而不管是哪种格式的launch,启动方式一样:
ros2 launch <package_name> <launch_file_name>
或者还可以直接启动指定路径文件:
ros2 launch <path_to_launch_file>
2.设置参数
ros2 launch <package_name> <launch_file_name> background_r:=255
或者这样:
ros2 launch <path_to_launch_file> background_r:=255
二、瞻仰:官网示例 (不想看的可直接看目录三 ^ . ^)
1.python编写launch示例
# 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('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,
])
2.xml编写launch示例
<!-- 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>
3.yaml编写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"
三、自己操刀编写一个launch.py
假设有三个package分别为node1_package、node2_package、node3_package,三个包里面各自有一个节点node1、node2、node3
#!/usr/bin/python3
import launch
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='node1_package',
executable='node1',
name='my_node1',
output='screen'
),
Node(
package='node2_package',
executable='node2',
name='my_node2',
output='screen'
),
Node(
package='node3_package',
executable='node3',
name='my_node3',
output='screen'
)
])
当然了LaunchDescription有类方法add_action,可以把Node对象和ExecuteProcess对象添加进入已经创建的LaunchDescription类对象实例中:
#!/usr/bin/python3
from launch import LaunchDescription
from launch_ros.actions import Node
from launch.actions import ExecuteProcess
def generate_launch_description():
ld = LaunchDescription()
node_1 = Node(
package='node1_package',
executable='node1',
name='my_node1',
output='screen'
),
node_2 = Node(
package='node2_package',
executable='node2',
name='my_node2',
output='screen'
),
node_3 = Node(
package='node3_package',
executable='node3',
name='my_node3',
output='screen'
)
ld.add_action(node_1)
ld.add_action(node_2)
ld.add_action(node_3)
return ld
也还可以这样玩,借助ExecuteProcess 用于执行外部进程的动作
#!/usr/bin/python3
from launch import LaunchDescription
from launch_ros.actions import Node
from launch.actions import ExecuteProcess
def generate_launch_description():
node1_start = ExecuteProcess(
cmd=['ros2', 'run', 'node1_package', 'node1']
),
node2_start = ExecuteProcess(
cmd=['ros2', 'run', 'node2_package', 'node2']
),
node3_start = ExecuteProcess(
cmd=['ros2', 'run', 'node3_package', 'node3']
)
return LaunchDescription([
node1_start,
node2_start,
node3_start
])
以上是一个简单的使用python编写ros2 launch启动文件示例,更多特性和功能可以参考目录二中的官方示例和加入一些python自己的特性以达到自己的需求。
作者:费码程序猿
欢迎技术交流:QQ:255895056
转载请注明出处,如有不当欢迎指正