Appearance
ROS2基础教程 - 10 Launch
在 ROS 中,launch 系统用于启动和管理多个节点及其配置。
例如我们启动小海龟程序,要开启两个终端,在后面我们的程序可能要启动更多的节点,使用 ros2 run 命令,会非常的麻烦,使用 launch 我们可以同时启动多个节点,并进行一些参数的配置。
和 ROS1 不同, ROS2 中 launch 文件就是一个 XML 文件,在 ROS2 中,launch 文件可以使用 XML、YAML 或 Python 脚本,但是推荐使用 Python 脚本(通常是 .py 文件)作为启动文件。这些文件定义了要启动的节点、参数、条件等。
10.1 使用launch启动多个节点
1 创建功能包
我们可以在任意功能包下创建 launch 文件,为了方便演示,我这里单独创建一个功能包:
shell
ros2 pkg create --build-type ament_python launch_pythonlaunch 文件需要放在功能包下的 launch 目录下,如果没有该目录,则需要先创建。
2 编写launch文件
在 ROS2 中有一个发布订阅的demo,使用topic通信,可以分别使用如下的命令来分别启动发布者和订阅者:
shell
# 启动发布者
ros2 run demo_nodes_py talker
# 启动订阅者
ros2 run demo_nodes_py listener我们可以使用 launch 同时启动上面两个节点。
首先需要编写 launch 文件,定义需要启动的节点、参数、条件等。
在功能包的 launch 目录下创建一个 launch 文件了。
例如我创建一个 demo_launch.py 的 launch 文件,内容如下:
python
# demo_launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='demo_nodes_py',
executable='talker',
output='screen'
),
Node(
package='demo_nodes_py',
executable='listener',
output='screen'
),
])在上面的代码中,使用 Node 定义了两个节点,同时启动了发布者和订阅者。
使用
LaunchDescription对象定义一系列要执行的启动的节点;package表示的是功能包的名称;executable表示的是节点的名称。output指定节点的日志输出方式,如screen或log。
3 配置launch文件(重要)
在 setup.py 中新增 launch 相关配置:
python
from setuptools import find_packages, setup
import os
from glob import glob
package_name = 'launch_python'
setup(
# ...其他配置
data_files=[
# ...其他配置
(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 目录中,这样在运行的时候,能找到这些目录下的文件。(否则运行launch文件找不到)
注意,后面使用了通配符进行了文件的匹配,你需要按照规则命令launch文件,我这里launch文件需要以 _launch.py 结尾。
4 构建项目
在工作空间下执行如下命令:
shell
colcon build构建完成,会在 install 目录下生成功能包的文件。
5 运行launch
首先执行 source 命令,在工作空间下执行:
shell
source install/local_setup.sh上面的命令是让 ROS 找到我们的功能包,已经在 HelloWorld 章节说过了。
然后启动launch:
shell
ros2 launch launch_python demo_launch.py运行后,发现同时启动了发布者和订阅者:

10.2 Node的参数
1 name参数
为节点指定一个唯一的名称。如果不指定,ROS 2将使用可执行文件的名称作为节点的默认名称。但是,如果多个相同名称的节点被启动,可能会导致冲突。
例如下面启动两个小海龟的窗口:
python
# turtle_launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='turtlesim',
executable='turtlesim_node',
name='turtle_a',
output='screen'
),
Node(
package='turtlesim',
executable='turtlesim_node',
name='turtle_b',
output='screen'
),
])运行 launch 后,使用 ros2 node list 查看节点,可以看到两个节点:

原来如果不通过 name 设置节点名称,直接使用 ros2 run turtlesim turtlesim_node , 节点名称是 turtlesim 。
2 namespace参数
命名空间可以用于将一组相关的节点、主题、服务等资源进行分组,避免名称冲突。例如,在一个复杂的机器人系统中,可能有多个相同类型的传感器,为它们设置不同的命名空间可以方便地区分和管理。
如果有两个相同的激光雷达节点,一个用于前部感知,一个用于后部感知,可以为它们分别设置命名空间。假设前部激光雷达节点的namespace='front_lidar',那么这个节点发布的主题可能将会变成 /front_lidar/scan(假设主题名称是scan),而后部激光雷达节点如果namespace='rear_lidar',那么这个节点发布的主题将会变成 /rear_lidar/scan。
举个栗子:
python
# turtle_launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='turtlesim',
executable='turtlesim_node',
namespace='turtle',
name='turtle_a',
output='screen'
),
Node(
package='turtlesim',
executable='turtlesim_node',
namespace='turtle',
name='turtle_b',
output='screen'
),
])上面为两个节点设置了命名空间,此时查看节点列表,发现节点前面多了命名空间:

此时查看话题信息,可以看到节点发布和订阅的主题,前面也多了命名空间:

如果单独运行 ros2 run turtlesim turtlesim_node ,是没有命名空间的:

3 remappings参数
上面在同一个命名空间下运行了两个小海龟,但是有一个问题的,两个节点订阅和发布的 topic 是相同的,能否让两个节点发布和订阅的主题不同呢?可以使用 remappings 参数。
remappings是用于主题(Topic)和服务(Service)的重命名的机制。比如,一个节点发布的主题名称为/image_raw,而另一个节点期望接收的主题名称为/camera/image。通过remappings,可以将/image_raw重映射为/camera/image,使得两个节点能够正常通信。
举个栗子:
python
# turtle_launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='turtlesim',
executable='turtlesim_node',
namespace='turtle',
name='turtle_a',
output='screen',
remappings=[
('/turtle/turtle1/cmd_vel', '/turtle/cmd_vel_a'),
('/turtle/turtle1/pose', '/turtle/pose_a')
]
),
Node(
package='turtlesim',
executable='turtlesim_node',
namespace='turtle',
name='turtle_b',
output='screen',
remappings=[
('/turtle/turtle1/cmd_vel', '/turtle/cmd_vel_b'),
('/turtle/turtle1/pose', '/turtle/pose_b')
]
),
])在上面使用 remappings 分别修改了节点订阅和发布的 topic,此时使用 ros2 topic list 查看topic,显示如下:

4 parameters参数
节点会定义一些参数,我们在使用 launch 启动节点的时候,可以传递参数。
举个栗子:
以小海龟为例,可以传递窗口的背景颜色(当然,这些参数是节点中定义的)。
python
# turtle_launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='turtlesim',
executable='turtlesim_node',
namespace='turtle',
name='turtle_a',
output='screen',
parameters=[
{'background_r' : 100},
{'background_g' : 100},
{'background_b' : 100},
]
),
Node(
package='turtlesim',
executable='turtlesim_node',
namespace='turtle',
name='turtle_b',
output='screen',
parameters=[
{'background_r' : 255},
]
),
])在上面使用 parameters 传递参数。
但是对于上面的方式,但是是固定写死的,无法在运行 launch 文件的时候,动态的传递参数。如果想在运行 ros2 launch 命令的时候动态的传递参数,我们可以使用 DeclareLaunchArgument 和 LaunchConfiguration 来定义 ,举个栗子:
python
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
def generate_launch_description():
background_r_arg = DeclareLaunchArgument(
'background_r', default_value='100', description='Red component of the background color'
)
background_g_arg = DeclareLaunchArgument(
'background_g', default_value='100', description='Green component of the background color'
)
background_b_arg = DeclareLaunchArgument(
'background_b', default_value='100', description='Blue component of the background color'
)
node = Node(
package='turtlesim',
executable='turtlesim_node',
namespace='turtle',
name='turtle_a',
output='screen',
parameters=[{
'background_r': LaunchConfiguration('background_r'),
'background_g': LaunchConfiguration('background_g'),
'background_b': LaunchConfiguration('background_b'),
}]
)
# 声明并使用参数
return LaunchDescription([background_r_arg, background_g_arg, background_b_arg, node])上面 DeclareLaunchArgument 和 Node 都是 launch 中的 action,所以在使用 LaunchDescription 启动的时候,都需要加载。
那么在运行 launch 文件时动态指定参数值,如:
shell
ros2 launch my_package my_launch_file.launch.py background_r:=200 background_g:=150 background_b:=50上面配置和读取参数的方式有点复杂,如果参数很多,我们可以将参数放在参数文件中尽心配置,然后读取参数文件。
举个栗子:
首先在功能包的 config 目录创建并定义参数文件:
python
/turtle/turtle_a: # 对应指定的命名空间和节点名称
ros__parameters: # 此部分用于定义节点的参数
background_r: 255
background_g: 0
background_b: 0然后加载并使用参数文件,需要指定上面参数文件的路径:
python
# turtle_launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
import os
from ament_index_python.packages import get_package_share_directory
def generate_launch_description():
# 得到配置文件的路径
# 查找launch_python功能包下config目录下的turtle.yaml配置文件
param_path = os.path.join(
get_package_share_directory('launch_python'),
'config',
'turtle.yaml'
)
return LaunchDescription([
Node( # 启动rviz
package='turtlesim',
executable='turtlesim_node',
namespace='turtle',
name='turtle_a',
output='screen',
parameters=[param_path] # 指定配置文件
)
])5 arguments参数
arguments参数用于向节点的可执行文件传递命令行参数。
打个比方,如果 turtlesim 节点支持参数,例如 ros2 run turtlesim turtlesim_node -debug -frequency 10.0 ,那么在 launch 文件中配置如下:
python
# turtle_launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='turtlesim',
executable='turtlesim_node',
namespace='turtle',
name='turtle_a',
output='screen',
arguments=['-debug', '-frequency 10.0']
)
])有些节点的启动可以自定参数,你可以在 launch 文件中使用 arguments 参数进行配置。
例如,后面在启动 rviz 软件的时候,可以通过这个 arguments 参数来指定使用的配置文件。
在 launch 文件中启动 rviz :
python
# turtle_launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
import os
from ament_index_python.packages import get_package_share_directory
def generate_launch_description():
# 得到配置文件的路径
# 查找launch_python功能包下rviz目录下的rviz_config.rviz配置文件
rviz_config_file_path = os.path.join(
get_package_share_directory('launch_python'),
'rviz',
'rviz_config.rviz'
)
return LaunchDescription([
Node( # 启动rviz
package='rviz2',
executable='rviz2',
name='rviz2',
output='screen',
arguments=['-d', rviz_config_file_path] # 指定配置文件的路径
)
])rviz 后面再介绍。
10.3 condition
ROS2 的 launch 框架支持在启动节点时使用条件判断,例如,你想满足指定条件才启动指定的节点,
那么你可以使用 launch.conditions 模块中的条件类来控制节点的启动。
launch.conditions 主要提供了两种种条件类型,比如:
IfCondition:如果条件为真,则执行该动作。UnlessCondition:如果条件为假,则执行该动作。
1 IfCondition
举个栗子:
下面使用 IfCondition 来根据某个参数的值决定是否启动节点。
python
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch_ros.actions import Node
from launch.conditions import IfCondition
from launch.substitutions import LaunchConfiguration
def generate_launch_description():
# 声明一个布尔参数,用于控制节点的启动
enable_node_arg = DeclareLaunchArgument('enable_node', default_value='false')
# 使用 IfCondition 判断是否启动节点
node = Node(
package='turtlesim',
executable='turtlesim_node',
namespace='turtle',
name='turtle_a',
output='screen',
condition=IfCondition(LaunchConfiguration('enable_node')) # 根据参数决定是否启动
)
return LaunchDescription([
enable_node_arg,
node
])使用
DeclareLaunchArgument声明一个名为enable_node的参数,默认值为'false'。在定义节点时,使用
IfCondition来判断enable_node的值。如果这个参数为true,则启动turtlesim_node,所以上面不会启动节点。
2 UnlessCondition
如果想在某个条件不成立时启动节点,可以使用 UnlessCondition 。
举个栗子:
python
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch_ros.actions import Node
from launch.conditions import UnlessCondition
from launch.substitutions import LaunchConfiguration
def generate_launch_description():
# 声明一个布尔参数,用于控制节点的启动
enable_node_arg = DeclareLaunchArgument('enable_node', default_value='false')
# 使用 IfCondition 判断是否启动节点
node = Node(
package='turtlesim',
executable='turtlesim_node',
namespace='turtle',
name='turtle_a',
output='screen',
condition=UnlessCondition(LaunchConfiguration('enable_node')) # 根据参数决定是否启动
)
return LaunchDescription([
enable_node_arg,
node
])在上面的代码中,只有在 enable_node 为 false 时,才会启动节点。
10.4 包含其他launch文件
有什么功能很复杂,所有的节点都写在一个 launch 文件中,会很臃肿和难以维护,我们可以将需要启动的节点和配置放在多个 launch 文件中,这样可以将复杂的系统分解为更小、可复用的 launch 文件,提升维护性和可扩展性。
下面介绍一下如何包含其他的 launch 文件,并传递参数。
假设有两个 launch 文件:
child_launch.py:定义一个简单的节点和一些参数。main_launch.py:包含child_launch.py并传递参数。
1 定义子launch文件
python
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
def generate_launch_description():
param_arg = DeclareLaunchArgument(
'param_value', default_value='100', description='A parameter value for the node'
)
node = Node(
package='turtlesim',
executable='turtlesim_node',
namespace='turtle',
name='turtle_b',
output='screen',
parameters=[{'background_r': LaunchConfiguration('param_value')}]
)
return LaunchDescription([param_arg, node])子 launch 文件和之前定义 parameters 参数一样。
2 定义父launch文件
在父 launch 文件中,使用 IncludeLaunchDescription 包含其他的 launch 文件。
python
from launch import LaunchDescription
from launch.actions import IncludeLaunchDescription, DeclareLaunchArgument
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import LaunchConfiguration
import os
from ament_index_python.packages import get_package_share_directory
from launch_ros.actions import Node
def generate_launch_description():
# 获取 child_launch.py 的路径
child_launch_path = os.path.join(
get_package_share_directory('launch_python'), # 指定功能包的名字
'launch',
'child_launch.py'
)
# 声明一个参数,供 child_launch.py 使用
param_arg = DeclareLaunchArgument(
'param_value', default_value='255', description='Parameter to pass to child launch'
)
# 包含 child_launch.py 并传递参数
include_child = IncludeLaunchDescription(
PythonLaunchDescriptionSource(child_launch_path),
launch_arguments={'param_value': LaunchConfiguration('param_value')}.items()
)
# 可以再创建一个node
node = Node(
package='turtlesim',
executable='turtlesim_node',
namespace='turtle',
name='turtle_a',
output='screen',
)
return LaunchDescription([param_arg, include_child, node])在上面的代码中,定义了参数并传给包含的 launch 文件。
如果要包含多个 launch 文件,需要定义多个 IncludeLaunchDescription。
举个栗子:
python
from launch import LaunchDescription
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import LaunchConfiguration
import os
from ament_index_python.packages import get_package_share_directory
def generate_launch_description():
# 获取子 launch 文件的路径
launch_a_path = os.path.join(
get_package_share_directory('launch_python'), # 指定功能包的名字
'launch',
'launch_a.py'
)
launch_b_path = os.path.join(
get_package_share_directory('launch_python'),
'launch',
'launch_b.py'
)
# 包含 launch_a.py
include_launch_a = IncludeLaunchDescription(
PythonLaunchDescriptionSource(launch_a_path),
launch_arguments={'param1': 'value1'}.items() # 可选:传递参数
)
# 包含 launch_b.py
include_launch_b = IncludeLaunchDescription(
PythonLaunchDescriptionSource(launch_b_path),
launch_arguments={'param2': 'value2'}.items() # 可选:传递参数
)
return LaunchDescription([include_launch_a, include_launch_b])10.5 环境变量
我们在实际开发的时候,可以在系统的环境变量中配置一些变量,这样可以在代码中读取,根据不同的值处理不同的逻辑,不用每次修改代码进行重新编译。
在 launch 文件中,可以读取环境变量和修改环境变量。
1 读取环境变量
在 launch 文件中,可以使用 EnvironmentVariable 读取环境变量的值。
举个栗子:
python
from launch import LaunchDescription
from launch.substitutions import EnvironmentVariable
from launch_ros.actions import Node
def generate_launch_description():
param_value = EnvironmentVariable('MY_ENV_VAR', default_value='255')
node = Node(
package='turtlesim',
executable='turtlesim_node',
output='screen',
parameters=[{'background_r': param_value}]
)
return LaunchDescription([node])EnvironmentVariable('MY_ENV_VAR'):此行代码将读取环境变量 MY_ENV_VAR 的值,并将其作为参数传递给节点。
使用下面的方式也可以读取环境变量的值:
python
import os
my_env_value = os.getenv('MY_ENV_VAR', 'default_value')两者的区别:
EnvironmentVariable():是 ROS 2launch文件中用于读取环境变量值的类,适合在 ROS 2launch文件中定义和传递参数时使用,能够在LaunchDescription中用作参数或条件的一部分。当使用launch文件运行时,它会动态读取环境变量的值,这意味着如果环境变量在运行时被更改,这个修改会生效。os.getenv():是 Python 内置的函数,用于在任何 Python 脚本中读取环境变量,如果你在launch文件之外编写 Python 脚本并需要读取环境变量,那么使用这个。os.getenv()在 Python 脚本启动时会读取环境变量的值。如果环境变量在脚本运行后被更改,该修改不会反映在已经启动的进程中。
2 修改环境变量
SetEnvironmentVariable 是 launch.actions 模块中的一个类,它可以在 launch 文件中使用,来改变启动上下文中的环境变量。
举个栗子:
py
from launch import LaunchDescription
from launch.actions import SetEnvironmentVariable
from launch.substitutions import EnvironmentVariable
from launch_ros.actions import Node
def generate_launch_description():
# 设置环境变量
set_env_var = SetEnvironmentVariable('MY_ENV_VAR', '100')
# 读取环境变量
param_value = EnvironmentVariable('MY_ENV_VAR', default_value='255')
# 定义节点
node = Node(
package='turtlesim',
executable='turtlesim_node',
output='screen',
parameters=[{'background_r': param_value}]
)
return LaunchDescription([
set_env_var,
node
])SetEnvironmentVariable 和 Node 都是 launch 中的 action,所以都需要使用 LaunchDescription 加载,并且在 Node 之前加载,作为启动 Node 必要的环境变量,使节点能够读取这些变量并按照预期运行。
10.6 打印日志
在 ROS2 launch 框架中,launch.actions 提供了一组用于定义和控制启动行为的类,这些类被称为“动作” (actions)。每个 action 在 launch 文件中用于执行特定的任务,像前面的声明参数(DeclareLaunchArgument)、设置环境变量(SetEnvironmentVariable)、启动节点(Node)等都是 action。
同样,在 launch 中打印日志,也有对应的 action 来处理。
举个栗子:
python
from launch import LaunchDescription
from launch.actions import LogInfo
from launch.actions import DeclareLaunchArgument
from launch.substitutions import EnvironmentVariable
from launch.substitutions import LaunchConfiguration
def generate_launch_description():
# 打印简单的值
log_action1 = LogInfo(msg="Hello")
# 打印拼接
log_action2 = LogInfo(msg=["Hello ", str(123)]) # 拼接字符串和整数
# 打印环境变量
env_var_value = EnvironmentVariable('MY_ENV_VAR', default_value='foooor')
log_action3 = LogInfo(msg=["The value of MY_ENV_VAR is: ", env_var_value])
# 打印参数值
param_arg = DeclareLaunchArgument('my_param', default_value='default_value')
log_action4 = LogInfo(msg=["The value of my_param is: ", LaunchConfiguration('my_param')])
return LaunchDescription([
param_arg,
log_action1,
log_action2,
log_action3,
log_action4
])在上面的代码中,通过 LogInfo 打印日志,演示了各种打印情况。
在 launch 文件中,还可以使用以下动作来打印日志:
LogInfo:用于打印一般信息。LogWarn:用于打印警告信息。LogError:用于打印错误信息。LogDebug:用于打印调试信息。
10.7 GroupAction
GroupAction 可以在 launch 文件中将一组动作组合在一起。它允许你对这些动作应用共享的上下文设置,如命名空间、条件、参数等。
GroupAction 的主要功能和优势:
- 组织和分组:将一组相关的
launch动作(如节点启动、参数声明等)组合在一起。 - 共享设置:可以为组内的动作应用相同的设置,比如命名空间、条件等。
- 条件执行:可设置条件,只有在满足条件时,组内的动作才会被执行。
- 作用域管理:可以在同一作用域内执行多个动作。
1 基本用法示例
下面是一个使用 GroupAction 的简单示例,展示如何将多个节点放置在同一命名空间下:
python
from launch import LaunchDescription
from launch.actions import GroupAction
from launch_ros.actions import PushRosNamespace
from launch_ros.actions import Node
def generate_launch_description():
# 使用 GroupAction 将多个节点放置在同一命名空间中
group = GroupAction([
PushRosNamespace('turtle'),
Node(
package='turtlesim',
executable='turtlesim_node',
name='turtle_a',
output='screen'
),
Node(
package='turtlesim',
executable='turtlesim_node',
name='turtle_b',
output='screen'
)
]) # 为组内所有节点设置命名空间
return LaunchDescription([
group
])- 在上述示例中,
turtle1和turtle2节点都被放置在turtle命名空间下。
运行后查看节点信息:

2 使用条件执行
GroupAction 还可以用于条件执行,使组内动作只有在特定条件下才会被执行,和之前 Node 的 condition 一样。
举个栗子:
python
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, GroupAction, LogInfo
from launch.conditions import IfCondition
from launch_ros.actions import Node
from launch_ros.actions import PushRosNamespace
from launch.substitutions import LaunchConfiguration
def generate_launch_description():
# 声明用于控制组执行的参数
condition_arg = DeclareLaunchArgument('run_group', default_value='true')
group = GroupAction(
actions=[
PushRosNamespace('turtle'), # 设置命名空间
Node(
package='turtlesim',
executable='turtlesim_node',
name='turtle_a',
output='screen'
),
Node(
package='turtlesim',
executable='turtlesim_node',
name='turtle_b',
output='screen'
),
LogInfo(msg='Launching the turtle node group') # 打印日志
],
condition=IfCondition(LaunchConfiguration('run_group')) # 判断条件是否启动
)
return LaunchDescription([
condition_arg,
group
])IfCondition:设置条件,只有当run_group参数为true时,组内的动作才会被执行。
LaunchConfiguration:用于获取launch文件中的参数值。- 同样可以使用
from launch.conditions import UnlessCondition,和前面介绍condition的时候一样,这里就不介绍了。
3 嵌套使用GroupAction
还可以嵌套使用 GroupAction 来构建更复杂的层次结构。
举个栗子:
python
from launch import LaunchDescription
from launch.actions import GroupAction
from launch_ros.actions import Node
from launch_ros.actions import PushRosNamespace
def generate_launch_description():
# 子分组
child_group = GroupAction([
PushRosNamespace('child_turtle'), # 设置命名空间
Node(
package='turtlesim',
executable='turtlesim_node',
name='turtle_a',
output='screen'
),
Node(
package='turtlesim',
executable='turtlesim_node',
name='turtle_b',
output='screen'
)
])
# 父分组,包含子分组
super_group = GroupAction([
PushRosNamespace('super_turtle'), # 设置命名空间
child_group,
Node(
package='turtlesim',
executable='turtlesim_node',
name='turtle_c',
output='screen'
)
])
return LaunchDescription([
super_group
])上面使用分组打开了三个小海龟窗口,turtle_a 和 turtle_b 被放置在 child_turtle 命名空间下,而 turtle_c 和整个 child_turtle 被放置在 super_turtle 命名空间下。
运行后,查看节点信息:

查看话题信息:

可以看到,节点和话题都在指定的命令空间下。
4 配合其他Launch Actions使用
GroupAction 可以和其他 launch 动作(如 IncludeLaunchDescription、SetParameter 等)一起使用,实现更丰富的功能。
举个栗子,下面演示一下包含其他的launch文件。
首先定义 child_launch.py :
python
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, LogInfo
from launch.substitutions import LaunchConfiguration, EnvironmentVariable
from launch_ros.actions import Node
def generate_launch_description():
param_arg = DeclareLaunchArgument(
'param_value', default_value='100', description='A parameter value for the node'
)
env_value = EnvironmentVariable('MY_ENV_VAR', default_value='100')
login_action = LogInfo(msg=['MY_ENV_VAR:', env_value])
node = Node(
package='turtlesim',
executable='turtlesim_node',
namespace='turtle',
name='turtle_b',
output='screen'
parameters=[{'background_r': LaunchConfiguration('param_value')}]
)
return LaunchDescription([
param_arg,
login_action,
node
])定义一个子 launch 文件,在启动一个节点,并接收传递的参数,读取环境变量等操作。
然后定义一个 main_launch.py :
python
from launch import LaunchDescription
from launch.actions import GroupAction, IncludeLaunchDescription, SetEnvironmentVariable, DeclareLaunchArgument
from launch.launch_description_sources import PythonLaunchDescriptionSource
import os
from ament_index_python.packages import get_package_share_directory
from launch_ros.actions import Node, PushRosNamespace
def generate_launch_description():
param_arg = DeclareLaunchArgument(
'param_value', default_value='100', description='A parameter value for the node'
)
included_launch = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(get_package_share_directory('launch_python'), 'launch', 'child_launch.py')
)
)
# 创建一个node
node = Node(
package='turtlesim',
executable='turtlesim_node',
name='turtle_a',
output='screen'
)
# 通过分组设置
group = GroupAction([
PushRosNamespace('turtle'), # 设置命名空间
param_arg, # 设置参数
SetEnvironmentVariable('MY_ENV_VAR', '200'), # 设置环境变量
node, # 设置启动节点
included_launch # 包含其他launch文件
])
return LaunchDescription([
group
])在上面的 launch 文件中,GroupAction 中包含了设置命名空间、参数、环境变量、节点、包含另一个 launch 文件。
总结 :通过使用 GroupAction,可以有效组织和控制 launch 文件中多个动作的执行,使其更具可维护性和可扩展性。