Launch可以实现同时启动多节点,这一不需要在终端一个一个窗口进行ros2 run
运行launch文件:
ros2 launch (功能包)(launch文件)
1 编写一个launch文件:
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package = 'learning_topic',
executable = 'topic_helloworld_pub',
),
Node(
package = 'learning_topic',
executable = 'topic_helloworld_sub',
),
])
1 from launch import LaunchDescription
from launch_ros.actions import Node
引入launch相关库,LaunchDescription描述了需要运行的节点
2 Node(
package = ‘learning_topic’,
executable = ‘topic_helloworld_pub’,
),
在LaunchDescription里声明要调用的节点,这里的调用内容可见(https://blog.csdn.net/Raine_Yang/article/details/125349724?spm=1001.2014.3001.5501)
3 def generate_launch_description():
generate_launch_description为自动生成Launch文件的函数
2 launch文件作为软件启动配置文件
(以rviz2为例)
ros2 run rviz2 rviz2 -d (launch文件完整路径)
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
rviz_config = os.path.join(
get_package_share_directory('learning_launch'),
'rviz',
'turtle_rviz.rviz'
)
return LaunchDescription([
Node(
package = 'rviz2',
executable = 'rviz2',
name = 'rviz2',
arguments = ['-d', rviz_config]
)
])
1 rviz_config = os.path.join(
get_package_share_directory(‘learning_launch’),
‘rviz’,
‘turtle_rviz.rviz’
)
在这里标明配置文件路径,类似于使用-d后面的文件完整路径
2 name = ‘rviz2’,
对节点重命名为rviz2。在launch文件里可以覆盖节点在源码里的名称,进行重命名
3 launch文件对节点和话题的重命名
该程序会打开两个turtlesim程序
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'),
]
)
])
1 命名空间
namespace = ‘turtlesim1’,
namespace = ‘turtlesim2’,
ROS2里不允许同名节点,因此直接打开两个turtlesim会报错。可以在launch文件里加入namespace进行区分,如下图

2 话题重定向
remappings = [
(‘/input/pose’, ‘/turtlesim1/turtle1/pose’),
(‘/output/cmd_vel’, ‘/turtlesim2/turtle1/cmd_vel’),
]
用remappings可以对话题发布者和接受者进行重定向。这里把输入话题名/input/pose改为/turtlesim1/turtle1/pose,把输出话题’/output/cmd_vel改为/turtlesim2/turtle1/cmd_vel
这样turtlesim1的pose会被mimic节点订阅,再由mimic发布到turtlesim2.turtlesim2会执行和turtlesim1一样的动作

4 在launch文件里配置参数
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration, TextSubstitution
from launch_ros.actions import Node
def generate_launch_description():
background_r_launch_arg = DeclareLaunchArgument(
'background_r', default_value = TextSubstitution(text = "0")
)
background_g_launch_arg = DeclareLaunchArgument(
'background_g', default_value = TextSubstitution(text = "84")
)
background_b_launch_arg = DeclareLaunchArgument(
'background_b', default_value = TextSubstitution(text = "122")
)
return LaunchDescription([
background_r_launch_arg,
background_g_launch_arg,
background_b_launch_arg,
Node(
package = 'turtlesim',
executable = 'turtlesim_node',
name = 'sim',
parameters = [{
'background_r': LaunchConfiguration('background_r'),
'background_g': LaunchConfiguration('background_g'),
'background_b': LaunchConfiguration('background_b'),
}]
),
])
1 def generate_launch_description():
background_r_launch_arg = DeclareLaunchArgument(
‘background_r’, default_value = TextSubstitution(text = “0”)
)
background_g_launch_arg = DeclareLaunchArgument(
‘background_g’, default_value = TextSubstitution(text = “84”)
)
background_b_launch_arg = DeclareLaunchArgument(
‘background_b’, default_value = TextSubstitution(text = “122”)
)
创建launch文件内参数修改R G B数值
2 parameters = [{
‘background_r’: LaunchConfiguration(‘background_r’),
‘background_g’: LaunchConfiguration(‘background_g’),
‘background_b’: LaunchConfiguration(‘background_b’),
}]
在返回值里parameters修改参数
对参数yaml文件修改可以简化以上代码
import os
from ament_index_python.packages import get_package_share_directory # 查询功能包路径的方法
from launch import LaunchDescription # launch文件的描述类
from launch_ros.actions import Node # 节点启动的描述类
def generate_launch_description(): # 自动生成launch文件的函数
config = os.path.join( # 找到参数文件的完整路径
get_package_share_directory('learning_launch'),
'config',
'turtlesim.yaml'
)
return LaunchDescription([ # 返回launch文件的描述信息
Node( # 配置一个节点的启动
package='turtlesim', # 节点所在的功能包
executable='turtlesim_node', # 节点的可执行文件名
namespace='turtlesim2', # 节点所在的命名空间
name='sim', # 对节点重新命名
parameters=[config] # 加载参数文件
)
])
1 config = os.path.join(
get_package_share_directory(‘learning_launch’),
‘config’,
‘turtlesim.yaml’
)
找到参数yaml文件的路径,我这里在learning_launch功能包,config文件夹,turtlesim.yaml文件
2 parameters=[config]
在返回值里加入parameters来加载参数文件
turtlesim.yaml参数文件:
/turtlesim2/sim:
ros__parameters:
background_b: 0
background_g: 0
background_r: 0
注意这里命名空间turtlesim2,节点名称sim都要和launch文件里保持一致,否则无法运行
5 在launch文件里包含其他launch文件
在一些大型系统可能会有多个launch文件,可以把多个launch文件嵌套在一个launch文件会更方便
import os
from ament_index_python.packages import get_package_share_directory # 查询功能包路径的方法
from launch import LaunchDescription # launch文件的描述类
from launch.actions import IncludeLaunchDescription # 节点启动的描述类
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.actions import GroupAction # launch文件中的执行动作
from launch_ros.actions import PushRosNamespace # ROS命名空间配置
def generate_launch_description(): # 自动生成launch文件的函数
parameter_yaml = IncludeLaunchDescription( # 包含指定路径下的另外一个launch文件
PythonLaunchDescriptionSource([os.path.join(
get_package_share_directory('learning_launch'), 'launch'),
'/parameters_nonamespace.launch.py'])
)
parameter_yaml_with_namespace = GroupAction( # 对指定launch文件中启动的功能加上命名空间
actions=[
PushRosNamespace('turtlesim2'),
parameter_yaml]
)
return LaunchDescription([ # 返回launch文件的描述信息
parameter_yaml_with_namespace
])
1 parameter_yaml = IncludeLaunchDescription( # 包含指定路径下的另外一个launch文件
PythonLaunchDescriptionSource([os.path.join(
get_package_share_directory(‘learning_launch’), ‘launch’),
‘/parameters_nonamespace.launch.py’])
)
获取另一个launch文件的完整地址。文件在learning_launch功能包,launch文件夹下parameters_nonamespace.launch.py文件
2 actions=[
PushRosNamespace(‘turtlesim2’),
parameter_yaml]
对加载的launch文件重命名功能空间turtlesim2。这样可以防止原launch文件命名出现冲突
在setup里面对launch文件进行声明
from setuptools import setup
import os
from glob import glob
package_name = 'learning_launch'
setup(
name=package_name,
version='0.0.0',
packages=[package_name],
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
(os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*.launch.py'))),
(os.path.join('share', package_name, 'config'), glob(os.path.join('config', '*.*'))),
(os.path.join('share', package_name, 'rviz'), glob(os.path.join('rviz', '*.*'))),
],
install_requires=['setuptools'],
zip_safe=True,
maintainer='hcx',
maintainer_email='huchunxu@guyuehome.com',
description='TODO: Package description',
license='TODO: License declaration',
tests_require=['pytest'],
entry_points={
'console_scripts': [
],
},
)
1 data_files=[
(‘share/ament_index/resource_index/packages’,
[‘resource/’ + package_name]),
(‘share/’ + package_name, [‘package.xml’]),
(os.path.join(‘share’, package_name, ‘launch’), glob(os.path.join(‘launch’, ‘.launch.py’))),
(os.path.join(‘share’, package_name, ‘config’), glob(os.path.join(‘config’, '.'))),
(os.path.join(‘share’, package_name, ‘rviz’), glob(os.path.join(‘rviz’, '.*’))),
],
这一步把所有launch文件夹下,config文件夹下,和rviz文件夹下的文件进行声明( * 代表所有文件),这样编译器会把这些文件复制到install文件夹下,可以后续运行