常见的launch文件:
我们将节点的启动方式、名称、参数、输出等信息都通过 Node 类来描述,并将这个Node类添加到 LaunchDescription 实例中。
可以先单独生成不同节点的Node类实例,再将这些Node示例作为 LaunchDescription实例的参数
# turtlesim/launch/multisim.launch.py
from launch import LaunchDescription # launch包中的一个类,用于描述和启动 ROS2节点和相关组件
import launch_ros.actions # Node 是 ROS 2 中 launch_ros 包中的一个类,用于启动 ROS 2 节点
# 通常使用 from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
launch_ros.actions.Node(
namespace= "turtlesim1", package='turtlesim', executable='turtlesim_node', output='screen'),
launch_ros.actions.Node(
namespace= "turtlesim2", package='turtlesim', executable='turtlesim_node', output='screen'),
])
常见的详细点儿的launch文件:
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'),
]
)
])
在package.xml中添加依赖
<exec_depend>ros2launch</exec_depend>
包结构
src/
package_name/
launch/
package.xml
package_name/
resource/
setup.cfg
setup.py
test/
Inside your launch directory, create a new launch file called my_script_launch.py.
在 setup.py 中,package_data 和 data_files 都是用于描述软件包中包含的数据文件的参数。它们的区别在于:
package_data 参数用于包含软件包中特定包或模块下的数据文件。通常情况下,这些数据文件是与软件包中的某个 Python 模块或程序相关联的,例如配置文件、资源文件等。在使用 setuptools 打包 Python 软件包时,package_data 参数可以帮助将这些文件打包到软件包中,并在安装时将它们安装到指定的路径中。例如,package_data={
'my_package': ['config/*', 'data/*']} 表示将软件包中 my_package 包中的 config 和 data 文件夹中的所有文件打包到软件包中。
data_files 参数用于包含软件包中非 Python 模块的数据文件。这些文件可以是软件包中的启动文件、仿真描述文件等与 Python 代码无关的文件。在使用 setuptools 打包 Python 软件包时,data_files 参数可以帮助将这些文件打包到软件包中,并在安装时将它们安装到指定的路径中。例如,data_files=[(os.path.join('share', package_name), glob('launch/*.launch.py'))] 表示将软件包中 launch 文件夹中所有扩展名为 .launch.py 的文件打包到软件包中。
因此,总的来说,package_data 适用于将软件包中与 Python 模块相关的数据文件打包到软件包中,而 data_files 适用于将与 Python 代码无关的数据文件打包到软件包中。在使用 setuptools 打包 Python 软件包时,这两个参数可以帮助你更好地管理软件包中的数据文件,并将它们正确地安装到指定路径下。
文件格式
import launch
import launch_ros.actions
def generate_launch_description():
return launch.LaunchDescription([
launch_ros.actions.Node(
package='demo_nodes_cpp',
executable='talker',
name='talker'),
])
给定参数
# 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")
)
include另一个launch
# include another launch file
launch_include = 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'
)
给定命名空间并给定参数值
# 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'),
}]
)
节点末尾
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,
])
基本格式
launch文件需要有generate_launch_description()函数以及它返回的launch.LaunchDescription(),这使得它能被ros2 launch命令使用。
import launch
import launch_ros.actions
def generate_launch_description():
return launch.LaunchDescription([
launch_ros.actions.Node(
package='demo_nodes_cpp',
executable='talker',
name='talker'),
])
修改setup.py
为了使Colcon编译工具能找到launch文件,需要设置setup()的data_files参数来通知Python中使用launch文件的 setuptools。
在setup.py文件中:
import os
from glob import glob
from setuptools import setup
package_name = 'py_launch_example'
setup(
# Other parameters ...
data_files=[
# ... Other data files
# Include all launch files.
(os.path.join('share', package_name), glob('launch/*launch.[pxy][yma]*'))
]
)
为Launch文件添加依赖
当包中有launch文件时,在package.xml中添加
<exec_depend>ros2launch</exec_depend>
编译
colcon build --symlink-install
运行Launch文件
ros2 launch <package_name> <launch_file_name>
1
上面的所有启动文件都启动了一个包含三个节点的系统,全部来自turtlesim包。该系统的目标是启动两个 turtlesim 窗口,让一只乌龟模仿另一只乌龟的动作。
启动两个 turtlesim 节点时,它们之间的唯一区别是它们的命名空间值。唯一的命名空间允许系统启动两个节点而不会出现节点名称或主题名称冲突。该系统中的两只海龟都接收关于同一主题的命令,并在同一主题上发布它们的姿势。使用唯一的命名空间,可以区分发往不同海龟的消息。
最后一个节点也来自turtlesim包,但不同的可执行文件:mimic. 此节点以重新映射的形式添加了配置详细信息。 mimic的/input/pose主题被重新映射到/turtlesim1/turtle1/pose并且它的/output/cmd_vel主题是/turtlesim2/turtle1/cmd_vel。这意味着mimic将订阅/turtlesim1/simpose 主题并将其重新发布为/turtlesim2/sim要订阅的 velocity command 主题。换句话说,turtlesim2会模仿turtlesim1的动作。
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'),
]
)
])
Reference : The Disign of Launch in ROS2
Reference : ROS2 Launch Documentation
嵌套启动的主启动文件案例
from launch_ros.substitutions import FindPackageShare
from launch import LaunchDescription
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import PathJoinSubstitution, TextSubstitution
def generate_launch_description():
colors = {
'background_r': '200'
}
return LaunchDescription([
IncludeLaunchDescription(
PythonLaunchDescriptionSource([
PathJoinSubstitution([
FindPackageShare('launch_tutorial'),
'example_substitutions.launch.py'
])
]),
launch_arguments={
'turtlesim_ns': 'turtlesim2',
'use_provided_red': 'True',
'new_background_r': TextSubstitution(text=str(colors['background_r']))
}.items()
)
])
条件判断
from launch_ros.actions import Node
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, ExecuteProcess, TimerAction
from launch.conditions import IfCondition
from launch.substitutions import LaunchConfiguration, PythonExpression
def generate_launch_description():
turtlesim_ns = LaunchConfiguration('turtlesim_ns')
use_provided_red = LaunchConfiguration('use_provided_red')
new_background_r = LaunchConfiguration('new_background_r')
turtlesim_ns_launch_arg = DeclareLaunchArgument(
'turtlesim_ns',
default_value='turtlesim1'
)
use_provided_red_launch_arg = DeclareLaunchArgument(
'use_provided_red',
default_value='False'
)
new_background_r_launch_arg = DeclareLaunchArgument(
'new_background_r',
default_value='200'
)
turtlesim_node = Node(
package='turtlesim',
namespace=turtlesim_ns,
executable='turtlesim_node',
name='sim'
)
spawn_turtle = ExecuteProcess(
cmd=[[
'ros2 service call ',
turtlesim_ns,
'/spawn ',
'turtlesim/srv/Spawn ',
'"{x: 2, y: 2, theta: 0.2}"'
]],
shell=True
)
change_background_r = ExecuteProcess(
cmd=[[
'ros2 param set ',
turtlesim_ns,
'/sim background_r ',
'120'
]],
shell=True
)
change_background_r_conditioned = ExecuteProcess(
condition=IfCondition(
PythonExpression([
new_background_r,
' == 200',
' and ',
use_provided_red
])
),
cmd=[[
'ros2 param set ',
turtlesim_ns,
'/sim background_r ',
new_background_r
]],
shell=True
)
return LaunchDescription([
turtlesim_ns_launch_arg,
use_provided_red_launch_arg,
new_background_r_launch_arg,
turtlesim_node,
spawn_turtle,
change_background_r,
TimerAction(
period=2.0,
actions=[change_background_r_conditioned],
)
])
launch_ros和launch中Node类的区别
在 ROS 2 中,launch
和 launch_ros
模块中都有 Node
类,它们的主要区别在于提供的参数不同。
launch
模块中的 Node
类提供了一些常用的参数,例如节点名称、命名空间、要运行的可执行文件路径、节点参数等。例如,以下是使用 launch
模块中的 Node
类启动 ROS 节点的示例代码:
from launch import LaunchDescription
from launch.actions import Node
def generate_launch_description():
ld = LaunchDescription()
node = Node(
package='my_package',
executable='my_node',
name='my_node',
parameters=[{
'my_parameter': 123}]
)
ld.add_action(node)
return ld
在这个例子中,我们使用 launch
模块中的 Node
类创建了一个 ROS 节点,并指定了节点名称、要运行的可执行文件路径以及节点参数。
launch_ros
模块中的 Node
类提供了一些 ROS 特定的参数,例如节点名称、命名空间、节点命名空间、发布者和订阅者的 QoS 配置等。例如,以下是使用 launch_ros
模块中的 Node
类启动 ROS 节点的示例代码:
from launch import LaunchDescription
from launch_ros.actions import Node
from rclpy.qos import qos_profile_default
def generate_launch_description():
ld = LaunchDescription()
node = Node(
package='my_package',
executable='my_node',
name='my_node',
namespace='my_namespace',
node_namespace='/my_namespace',
parameters=[{
'my_parameter': 123}],
remappings=[('my_topic', 'my_renamed_topic')],
qos_profile=qos_profile_default
)
ld.add_action(node)
return ld
在这个例子中,我们使用 launch_ros
模块中的 Node
类创建了一个 ROS 节点,并指定了节点名称、命名空间、节点命名空间、节点参数、重映射规则以及发布者和订阅者的 QoS 配置。
总之,launch
模块中的 Node
类提供了一些常用的参数,适用于大多数 ROS 节点的启动;而 launch_ros
模块中的 Node
类提供了一些 ROS 特定的参数,适用于一些需要定制化的 ROS 节点的启动。你可以根据具体需求选择使用哪个类。
同样的对于launch和launch_ros模块来说
在 ROS 2 中,launch 和 launch_ros 是两个不同的 Python 模块,用于启动 ROS 2 节点。它们的主要区别在于功能和提供的类不同。
launch 模块提供了一些通用的功能,例如加载和运行 launch 文件、设置环境变量、启动 ROS 节点、启动进程等。此外,launch 模块还提供了一些常用的类,例如 LaunchDescription 类和 Node 类。LaunchDescription 类用于描述整个启动文件,包括要启动的节点、参数、重映射规则等;Node 类用于启动 ROS 节点,提供了一些常用的参数,例如节点名称、命名空间、要运行的可执行文件路径、节点参数等。
launch_ros 模块提供了一些 ROS 特定的功能,例如设置 ROS 2 命名约定、发布者和订阅者的 QoS 配置、加载参数文件等。此外,launch_ros 模块还提供了一些 ROS 特定的类,例如 Node 类和 LifecycleNode 类。Node 类用于启动 ROS 节点,提供了一些 ROS 特定的参数,例如节点名称、命名空间、节点命名空间、发布者和订阅者的 QoS 配置等;LifecycleNode 类用于启动 ROS 2 生命周期节点,提供了一些 ROS 生命周期相关的参数和方法。
综上所述,launch 模块提供了一些通用的功能和类,适用于大多数的启动文件;而 launch_ros 模块提供了一些 ROS 特定的功能和类,适用于一些需要定制化的 ROS 节点的启动。
变量的声明:
使用 DeclareLaunchArgument 类声明了一个名为 node_name 的启动参数,并设置了默认值和描述信息。接下来,我们使用 Node 类创建了一个 ROS 2 节点,并使用 LaunchConfiguration 类将启动参数值传递给节点的名称。这意味着,节点的名称将从启动文件中的 node_name 参数中读取,并在启动时传递给节点。这样,你就可以通过修改启动文件中的参数值来更改节点的名称,而无需修改 Python 代码。
总之,LaunchConfiguration 类是 ROS 2 启动文件的参数类,用于从启动文件的参数中读取值,例如节点的名称、参数值、命名空间等。你可以在 Node 类或其他操作中使用 LaunchConfiguration 类将参数值传递给节点或其他操作。
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch_ros.actions import Node
from launch.substitutions import LaunchConfiguration
def generate_launch_description():
ld = LaunchDescription()
# Declare a launch argument for the node name
node_name = DeclareLaunchArgument(
'node_name',
default_value='my_node',
description='Name of the ROS node'
)
ld.add_action(node_name)
# Create the ROS 2 node with the given name
node = Node(
package='my_package',
executable='my_node',
name=LaunchConfiguration('node_name')
)
ld.add_action(node)
return ld