一篇学懂roslaunch文件语法
参考:
【ROS学习笔记】15.launch启动文件的使用方法
ROS的launch文件
ROS知识篇—ROS的launch文件
ROS1 中的 launch 文件是使用 XML 格式编写的,通常用于启动多个节点、设置参数、重映射话题等。
1 launch文件常用语法汇总
1. <launch> 根元素
每个 launch 文件都以 <launch> 为根节点。
<launch>
...
</launch>
2. 启动节点:<node>
<node name="my_node" pkg="my_package" type="my_node_exe" output="screen" />
name:节点名称(重命名)pkg:所属包名type:可执行文件名(不加路径)output="screen":将输出打印到终端

参数说明:
output:控制某个节点node把日志信息打印到终端。
respawn:节点奔溃后是否重启
required:节点是否为必须节点,即改节点奔溃后须终止其他节点
ns:自定义的命名空间,在自定义的命名空间中运行节点
args:输入参数用
3. 参数设定:<param> 和 <rosparam>
方式一:设置单个参数
<param name="robot_name" value="uav1" />
方式二:加载 YAML 文件
<rosparam file="$(find my_package)/config/params.yaml" command="load" />
方式三:直接嵌入参数
<rosparam>
robot:
name: uav1
id: 1
</rosparam>
4. 重映射话题:<remap>
<node name="my_node" pkg="my_package" type="my_node" output="screen">
<remap from="/original_topic" to="/new_topic"/>
</node>
5. 使用变量和替换参数:$(arg ...), $(env ...), $(find ...)
$(arg my_arg):使用传入的参数$(env ENV_VAR):获取环境变量$(find my_package):查找包路径
6. 定义与使用参数:<arg>
<arg name="robot_name" default="uav1" />
<node name="$(arg robot_name)_node" pkg="my_pkg" type="my_node" />
可以从命令行传入:
roslaunch my_pkg my.launch robot_name:=uav2
7. 启动文件嵌套:<include>
<include file="$(find my_package)/launch/another_launch.launch">
<arg name="robot_name" value="uav1"/>
</include>
8. 条件启动:if 和 unless
<node name="debug_node" pkg="debug_pkg" type="debug" if="$(arg debug_mode)" />
<node name="safe_node" pkg="safe_pkg" type="safe" unless="$(arg debug_mode)" />
9. 命名空间:<group ns="uav1"> 和 <node ns="uav1" />
方法一:通过 group 指定命名空间
<group ns="uav1">
<node name="mavros" pkg="mavros" type="mavros_node" />
</group>
方法二:在 node 中指定 ns
<node ns="uav1" name="mavros" pkg="mavros" type="mavros_node" />
10. 设置参数服务器上的命名空间
<param name="~local_param" value="123"/> <!-- 相对于节点的私有命名空间 -->
2.多无人机系统launch文件示例
设计一个多无人机场景,启动两个无人机(uav1 和 uav2)模拟系统,每个无人机使用 MAVROS 与 PX4 通信,并加载各自的参数、命名空间和话题重映射,同时允许外部控制是否开启调试节点、并嵌套加载子启动文件。
2.1 场景说明:多无人机系统
- 使用参数文件配置 MAVROS
- 每个无人机都运行在自己的命名空间下
- 使用
<arg>控制调试节点是否开启 - 使用
<include>加载通用 MAVROS 启动模板 - 重映射 UAV 的
/cmd_vel到/uavX/vel_cmd - 使用
<rosparam>和 YAML 文件加载参数 - 使用条件语句
if来决定是否加载 debug 节点 - 使用替换参数
$(arg ...),$(find ...)等 - 使用
<group>管理命名空间 - 使用
<param>设置参数服务器值
2.2 文件结构
my_drone_project/
├── launch/
│ ├── dual_uav_system.launch # 主 launch 文件
│ ├── single_uav.launch # 子 launch,负责一个 UAV 启动
├── config/
│ ├── uav1.yaml
│ └── uav2.yaml
2.3 主启动文件:dual_uav_system.launch
<launch>
<!-- ========== 1. 定义通用参数 ========== -->
<arg name="enable_debug" default="true" />
<!-- 启动 uav1 -->
<include file="$(find my_drone_project)/launch/single_uav.launch">
<arg name="uav_name" value="uav1" />
<arg name="fcu_url" value="udp://:14540@127.0.0.1:14557" />
<arg name="system_id" value="1" />
<arg name="param_file" value="$(find my_drone_project)/config/uav1.yaml" />
<arg name="enable_debug" value="$(arg enable_debug)" />
</include>
<!-- 启动 uav2 -->
<include file="$(find my_drone_project)/launch/single_uav.launch">
<arg name="uav_name" value="uav2" />
<arg name="fcu_url" value="udp://:14541@127.0.0.1:14558" />
<arg name="system_id" value="2" />
<arg name="param_file" value="$(find my_drone_project)/config/uav2.yaml" />
<arg name="enable_debug" value="$(arg enable_debug)" />
</include>
</launch>
2.4 单个无人机启动:single_uav.launch
<launch>
<!-- ========== 2. 定义参数 ========== -->
<arg name="uav_name" />
<arg name="fcu_url" />
<arg name="system_id" />
<arg name="param_file" />
<arg name="enable_debug" />
<!-- ========== 3. 命名空间 group ========== -->
<group ns="$(arg uav_name)">
<!-- ========== 4. 设置参数 ========== -->
<param name="tgt_system" value="$(arg system_id)" />
<!-- ========== 5. 加载 YAML 参数 ========== -->
<rosparam file="$(arg param_file)" command="load" />
<!-- ========== 6. 启动 MAVROS 节点 ========== -->
<node name="mavros" pkg="mavros" type="mavros_node" output="screen">
<!-- ========== 7. 参数设置 ========== -->
<param name="fcu_url" value="$(arg fcu_url)" />
<param name="gcs_url" value="" />
<!-- ========== 8. 话题重映射 ========== -->
<remap from="/cmd_vel" to="/$(arg uav_name)/vel_cmd" />
</node>
<!-- ========== 9. 条件启动调试节点 ========== -->
<node name="debug_tool" pkg="my_debug_tools" type="debug_node" output="screen"
if="$(arg enable_debug)">
<param name="log_level" value="debug" />
</node>
</group>
</launch>
2.5 YAML 配置文件(config/uav1.yaml)
mavros:
gps:
use_sim_time: true
imu:
calibration: true
使用方法
roslaunch my_drone_project dual_uav_system.launch enable_debug:=false
问题1:arg 和 param在launch文件中有什么区别?
一句话总结:
arg是用于 launch 脚本中变量替换,控制节点名、路径、逻辑param是要传递给 ROS 节点的实际参数
<arg> 和 <param> 在 ROS1 launch 文件中扮演不同角色,职责不一样。
| 项目 | 作用域 | 作用 | 示例 |
|---|---|---|---|
<arg> | launch 文件内部变量 | 作为变量传参,用于控制 launch 文件逻辑、传递值给子文件或 <param> | <arg name="robot_name" default="uav1" /> |
<param> | ROS 参数服务器 | 设置 ROS 节点运行时的参数(会上传到 ROS 参数服务器) | <param name="max_speed" value="1.5" /> |
更具体
| 比较点 | <arg> | <param> |
|---|---|---|
| 定义位置 | 只能在 <launch> 或 <include> 的内部定义 | 可在 <launch> 内,也可嵌套在 <node> 或 <group> 中 |
| 用途 | 作为脚本变量使用,可被多个地方复用 | 设置实际传给节点的参数,存在于 /rosparam 空间 |
| 生命周期 | 仅在当前 launch 文件中有效 | 会上传到 ROS 参数服务器,供节点通过 rosparam get 获取 |
| 使用对象 | 用来传递值给 <param>、文件路径、<node>、<group> | 直接配置给节点,作为其参数 |
| 是否被节点读取 | 否,节点无法通过 ros::param::get 或动态参数读取 <arg> | 是,节点可以用 rosparam, ros::param::get, 或 yaml 加载 |

问题2:如何读取ROS参数服务器的参数?
<launch>
<!-- 定义一个变量 arg -->
<arg name="robot_name" default="uav1" />
<arg name="max_speed" default="1.5" />
<!-- 将 arg 用作 param 值,设置到 ROS 参数服务器中 -->
<param name="robot_name" value="$(arg robot_name)" />
<param name="max_speed" value="$(arg max_speed)" />
<!-- 启动节点 -->
<node name="$(arg robot_name)_controller" pkg="my_pkg" type="control_node" />
</launch>
arg是用于 launch 脚本中变量替换,控制节点名、路径、逻辑param是要传递给 ROS 节点的实际参数
launch 文件:
<param name="max_speed" value="1.5"/>
C++ 读取:
double max_speed;
ros::NodeHandle nh;
nh.getParam("max_speed", max_speed);
问题3:ROS 参数读取方法:结构体批量处理参数
1. 参数结构体定义
在头文件中定义参数结构体,集中管理节点所需的所有参数:
struct GA_Params{
int population_size; // 种群大小
int generation_max; // 最大代数
double crossover_fraction; // 交叉概率
double mutation_rate; // 变异率
int best_stall_max; // 最优停滞最大代数
int elite_count; // 精英保留数量
int max_steps; // 最大步骤数
};
在类中创建结构体对象:
GA_Params ga_params_; // GA参数结构体实例
2. 参数读取实现
在初始化函数中读取参数并设置默认值:
void GA::init(ros::NodeHandle &nh){
// 读取参数,若未设置则使用默认值
nh.param("population_size", ga_params_.population_size, 50);
nh.param("generation_max", ga_params_.generation_max, 50);
nh.param("crossover_fraction", ga_params_.crossover_fraction, 0.7);
nh.param("mutation_rate", ga_params_.mutation_rate, 0.1);
nh.param("best_stall_max", ga_params_.best_stall_max, 10);
nh.param("elite_count", ga_params_.elite_count, 5);
nh.param("max_steps", ga_params_.max_steps, 100);
// 参数校验
if (ga_params_.population_size <= 0)
throw std::invalid_argument("Population size must be positive");
if (ga_params_.generation_max <= 0)
throw std::invalid_argument("Max generations must be positive");
if (ga_params_.crossover_fraction < 0.0 || ga_params_.crossover_fraction > 1.0)
throw std::invalid_argument("Crossover fraction must be between 0 and 1");
if (ga_params_.mutation_rate < 0.0 || ga_params_.mutation_rate > 1.0)
throw std::invalid_argument("Mutation rate must be between 0 and 1");
if (ga_params_.best_stall_max <= 0)
throw std::invalid_argument("Best stall max must be positive");
if (ga_params_.elite_count < 0)
throw std::invalid_argument("Elite count cannot be negative");
}
注意:crossover_fraction参数是double类型,在赋初始值的时候必须赋值为0.7浮点型,而不能是1整型。
3. 节点句柄与参数命名空间
在函数中调用初始化函数时,需注意节点句柄的类型:
Position GA::solve() {
ros::NodeHandle nh; // 全局命名空间句柄
init(nh); // 传入句柄用于读取参数
}
两种句柄类型的区别:
-
全局命名空间
ros::NodeHandle nh; // 无参数构造 // 查找参数: /population_size (全局命名空间) -
私有命名空间
ros::NodeHandle nh("~"); // 带~构造 // 查找参数: /节点名/population_size (节点私有空间)
4. Launch 文件配置
全局参数配置
<launch>
<!-- 定义参数默认值 -->
<arg name="population_size" default="20"/>
<arg name="generation_max" default="10"/>
<arg name="crossover_fraction" default="0.5"/>
<arg name="mutation_rate" default="0.5"/>
<arg name="best_stall_max" default="5"/>
<arg name="elite_count" default="2"/>
<arg name="max_steps" default="5"/>
<!-- 设置全局参数 -->
<param name="population_size" value="$(arg population_size)"/>
<param name="generation_max" value="$(arg generation_max)"/>
<param name="crossover_fraction" value="$(arg crossover_fraction)"/>
<param name="mutation_rate" value="$(arg mutation_rate)"/>
<param name="best_stall_max" value="$(arg best_stall_max)"/>
<param name="elite_count" value="$(arg elite_count)"/>
<param name="max_steps" value="$(arg max_steps)"/>
</launch>
私有参数配置
方法 1:在 node 标签内定义
<node name="GA_node" pkg="xxx" type="xxx" output="screen">
<param name="population_size" value="$(arg population_size)"/>
<param name="generation_max" value="$(arg generation_max)"/>
<!-- 其他参数 -->
</node>
方法 2:使用~前缀
<param name="~population_size" value="$(arg population_size)"/>
<param name="~generation_max" value="$(arg generation_max)"/>
<!-- 其他参数 -->
问题4:ROS 中 param () 与 getParam () 的区别
核心差异
| 特性 | param() | getParam() |
|---|---|---|
| 返回值 | 无返回值 | 返回 bool(true = 成功,false = 失败) |
| 默认值处理 | 自动应用默认值 | 需手动设置默认值 |
| 用法示例 | nh.param("name", var, 50); | nh.getParam("name", var); |
| 适用场景 | 简单场景,自动用默认值 | 需要判断参数是否存在的场景 |
关键区别
-
param()方法- 语法:
nh.param(参数名, 存储变量, 默认值) - 功能:尝试获取参数值并存储到变量中。如果参数不存在,会自动将默认值赋给变量
- 返回值:无返回值(通过引用修改传入的变量)
int population_size; nh.param("population_size", population_size, 50); // 不存在时自动设为50 - 语法:
-
getParam()方法- 语法:
nh.getParam(参数名, 存储变量) - 功能:尝试获取参数值并存储到变量中。如果参数不存在,不会修改变量
- 返回值:返回
bool类型,true表示获取成功,false表示参数不存在
int population_size = 50; // 手动设置默认值 bool success = nh.getParam("population_size", population_size); if (!success) { ROS_WARN("使用默认值: population_size = 50"); } - 语法:
问题5:重映射话题的使用时机
//1号无人机需要订阅
std::string topic = "/drone_1_data/odom";
odom_subs_ = nh.subscribe<nav_msgs::Odometry>(topic, 10);
//2号无人机需要订阅
std::string topic = "/drone_2_data/odom";
odom_subs_ = nh.subscribe<nav_msgs::Odometry>(topic, 10);
使用话题重映射
// 在launch文件中重映射话题到一个统一话题
<node ...>
<arg name="drone_id" value="2"/>
<remap from="~odom" to="/drone_$(arg drone_id)_data/odom"/>
</node>
// 然后使用简单订阅
ros::Subscriber odom_sub = nh.subscribe("odom", 10, &odomCallback);
当需要创建多个无人机节点,只需在启动时修改drone_id参数的值即可,无需修改重映射规则。
问题6:如何在launch文件中进行运算
在一开始就定义一个新参数:
<arg name="drone_id" default="1"/>
<arg name="drone_id_x" default="$(eval arg('drone_id') - 1)"/>
然后在后面节点里用 $(arg drone_id_x)。
问题7:include和node在launch文件中的使用区别
1. 作用对象不同
<node>- 启动的是一个可执行程序(节点),并且可以通过
<param>或<rosparam>给该节点加载参数。 - 这些参数会放在 该节点的私有命名空间 下(
~param_name)。 - 也可以用
remap改变话题名。
- 启动的是一个可执行程序(节点),并且可以通过
<include>- 用来包含另一个
.launch文件,可以给 被包含的 launch 文件 传递参数。 - 这些参数通常通过
<arg>机制传递,而不是直接<param>。 - 所以
<include>更像是 组合多个 launch 文件 的工具,而不是直接启动节点。
- 用来包含另一个
2. 参数传递方式
(1)<node> 中传递参数
-
通过
<param>或<rosparam>标签传递,参数直接加载到该节点。 -
语法示例:
<node pkg="demo_pkg" type="demo_node" name="demo_node">
<param name="speed" value="3.0"/>
<rosparam file="$(find demo_pkg)/config/settings.yaml"/>
</node>
- 这些参数会在节点的 私有命名空间 下(如
~speed),节点用ros::param::get("~speed", ...)或rclcpp::Node::get_parameter("speed")来取。
(2)<include> 中传递参数
-
不能直接
<param>给节点,而是用<arg>把值传给被 include 的 launch 文件。 -
被 include 的 launch 文件需要用
<arg>接收,然后在它里面再用<param>或<rosparam>传给节点。 -
语法示例:
<!-- 主 launch 文件 -->
<include file="$(find demo_pkg)/launch/child.launch">
<arg name="speed" value="3.0"/>
</include>
子 launch 文件:
<launch>
<arg name="speed" default="1.0"/>
<node pkg="demo_pkg" type="demo_node" name="demo_node">
<param name="speed" value="$(arg speed)"/>
</node>
</launch>
- 参数不会直接影响某个节点,必须由子 launch 处理。
问题8:总结node ns="…“与group ns=”…"的区别
1.基本作用
-
<node ns="...">
给单个节点加命名空间。只影响这个节点及它的参数、话题。<node ns="uav1" name="mavros" pkg="mavros" type="mavros_node"/>→ 节点名:
/uav1/mavros
→ 话题:/uav1/mavros/...
→ 参数:/uav1/mavros/... -
<group ns="...">
给一组节点/参数统一加命名空间。<group ns="uav1"> <node name="mavros" pkg="mavros" type="mavros_node"/> <param name="speed" value="1.0"/> </group>→ 节点名:
/uav1/mavros
→ 参数:/uav1/speed
2. 参数命名空间的不同
- 在
<node>内用ns="...":
节点的私有参数(~param)会落到/uav1/mavros/param,公共参数(param)则落到/uav1/mavros/param(因为它们都相对节点)。 - 在
<group>内设置<param>:
参数会直接落到/uav1/param,不依赖节点名。
总结:
<node ns>→ 参数挂在节点下。<group ns>→ 参数挂在命名空间下。
3.使用场景
- 适合用
<node ns>的情况:- 想单独给某个节点分命名空间。
- 多个相同节点需要在不同命名空间运行,避免话题/参数冲突。
- 例:多架无人机的 MAVROS 节点。
- 适合用
<group ns>的情况:- 想把一批节点、参数打包进统一的命名空间。
- 一个命名空间下可能有多个节点、多个参数,方便组织。
- 例:
uav1下有mavros、planner、controller等多个节点。
2734




被折叠的 条评论
为什么被折叠?



