当前位置: 首页 > web >正文

roslaunch 文件的核心语法和使用技巧

ROS launch 文件是 ROS 项目中不可或缺的一部分,它能让你用一个命令启动和配置多个节点(Node),是管理复杂机器人系统的核心工具。

下面我将从核心语法实用技巧一个综合示例三个方面来详细讲解。


一、核心语法 (XML 标签)

Launch 文件本质上是一个 XML 文件,通过不同的标签来定义启动规则。

1. <launch>

这是所有 launch 文件的根标签,所有其他标签都必须包含在其中。

<launch><!-- 其他所有标签都在这里 -->
</launch>
2. <node>

最重要、最常用的标签,用于启动一个 ROS 节点。

<node pkg="package_name" type="executable_name" name="node_name" output="screen" respawn="true"><!-- 参数、重映射等可以放在这里 -->
</node>
  • pkg="package_name": 节点所属的功能包名称。
  • type="executable_name": 在功能包中编译生成的可执行文件名称。
  • name="node_name": 节点启动后在 ROS 网络中的唯一名称。如果省略,会使用可执行文件名作为默认名称,并可能加上随机后缀以保证唯一性。
  • output="screen": (可选)将节点的标准输出(如 printf, ROS_INFO)打印到终端屏幕上。默认是输出到日志文件 (~/.ros/log/)。调试时极其有用!
  • respawn="true": (可选)如果节点意外崩溃,自动重启它。默认为 false
3. <param><rosparam>

用于设置 ROS 参数服务器(Parameter Server)上的参数。

  • <param>: 设置单个参数

    <!-- 设置一个字符串参数 -->
    <param name="my_param_name" type="str" value="hello_world" />
    <!-- 设置一个整型参数 -->
    <param name="scan_rate" type="int" value="10" />
    <!-- 设置一个布尔型参数 -->
    <param name="use_simulation" type="bool" value="true" />
    

    name 可以是全局的 (/my_param),也可以是相对于节点的私有参数 (my_private_param,如果放在 <node> 标签内)。

  • <rosparam>: 从 YAML 文件加载多个参数
    这是管理大量参数的最佳实践

    <!-- 从 YAML 文件加载参数 -->
    <rosparam command="load" file="$(find my_pkg)/config/my_params.yaml" />
    

    对应的 my_params.yaml 文件内容:

    # config/my_params.yaml
    controller:p_gain: 1.2d_gain: 0.5
    sensor_topic: "/scan"
    
4. <arg>

定义一个可以在启动时从命令行传入的参数(Argument)。这让 launch 文件变得非常灵活和可复用。

<!-- 1. 在 launch 文件中声明一个 arg -->
<arg name="use_gui" default="true" />
<arg name="model_name" doc="The name of the robot model to load."/><!-- 2. 在 launch 文件中使用这个 arg -->
<param name="robot_description" textfile="$(find my_robot_pkg)/urdf/$(arg model_name).urdf" /><node name="rviz" type="rviz" pkg="rviz" if="$(arg use_gui)" />
  • name: 参数名。
  • default: 默认值。如果命令行不提供,则使用此值。
  • value: 强制设定一个值,无法从命令行覆盖。
  • doc: 参数的说明文档,方便他人理解。

在命令行中这样使用:
roslaunch my_pkg my_launch.launch use_gui:=false model_name:=waffle

5. <include>

用于在一个 launch 文件中包含另一个 launch 文件,是实现模块化设计的关键。

<include file="$(find other_pkg)/launch/other.launch"><!-- 可以向被包含的文件传递 arg --><arg name="some_arg_in_other_launch" value="a_specific_value" />
</include>
6. <remap>

重映射话题(Topic)、服务(Service)或动作(Action)的名称。当你想连接两个本来话题名称不匹配的节点时,这个功能非常强大。

<node pkg="move_base" type="move_base" name="move_base"><!-- 将 move_base 订阅的 /scan 话题重映射到 /my_robot/laser/scan --><remap from="/scan" to="/my_robot/laser/scan" /><!-- 将 move_base 发布的 cmd_vel 话题重映射到 /cmd_vel_raw --><remap from="cmd_vel" to="/cmd_vel_raw" />
</node>
7. <group>

将一组节点和配置放在一个命名空间(namespace)下,避免名称冲突,非常适合多机器人系统。

<group ns="robot1"><node pkg="demo_nodes_cpp" type="talker" name="my_talker"/><!-- 这个节点的话题会是 /robot1/chatter -->
</group><group ns="robot2"><node pkg="demo_nodes_cpp" type="talker" name="my_talker"/><!-- 这个节点的话题会是 /robot2/chatter -->
</group>

二、实用技巧与最佳实践 (Tips & Tricks)

  1. 使用 $(find ...) 替代硬编码路径
    永远不要在 launch 文件中写绝对路径 (/home/user/catkin_ws/...)。使用 $(find package_name) 可以自动找到功能包的路径,让你的项目在任何电脑上都能运行。

    <!-- 正确做法 -->
    <param name="robot_description" textfile="$(find my_robot_pkg)/urdf/my_robot.urdf" /><!-- 错误做法 -->
    <param name="robot_description" textfile="/home/user/catkin_ws/src/my_robot_pkg/urdf/my_robot.urdf" />
    
  2. 条件启动 (ifunless)
    可以根据 <arg> 的值来决定是否启动某个节点或加载某段配置。

    <arg name="run_simulation" default="true" /><!-- 如果 run_simulation 是 true,则启动 Gazebo -->
    <include file="$(find gazebo_ros)/launch/empty_world.launch" if="$(arg run_simulation)" /><!-- 如果 run_simulation 不是 true (即 false),则启动真实机器人驱动 -->
    <node pkg="real_robot_driver" type="driver" name="driver_node" unless="$(arg run_simulation)" />
    
  3. 使用 YAML 管理复杂参数
    如前所述,当参数超过 3-4 个时,就应该把它们放到 YAML 文件中,用 <rosparam> 加载。这让 launch 文件保持整洁,参数也更易于管理和修改。

  4. 使用 launch-prefix 进行调试
    如果你想用 GDB 或 Valgrind 等工具调试某个节点,可以使用 launch-prefix 属性,而无需修改代码。

    <!-- 使用 GDB 调试 my_node -->
    <node pkg="my_pkg" type="my_node" name="my_node_to_debug"launch-prefix="gdb -ex run --args" /><!-- 使用终端窗口运行节点,方便交互 -->
    <node pkg="my_pkg" type="my_interactive_node" name="interactive_node"launch-prefix="xterm -e" />
    
  5. 创建匿名名称 $(anon name)
    有时你需要启动一个节点的多个实例,但又不关心它们的具体名称。$(anon ...) 会生成一个唯一的名称。

    <!-- 每次启动都会生成一个类似 logger_167888... 的唯一名称 -->
    <node pkg="rosout" type="rosout" name="$(anon logger)" />
    
  6. 善用命名空间 ns
    对于大型项目或多机器人系统,使用 <group ns="..."></group> 或在 <node><include> 标签中直接使用 ns="..." 属性,可以有效隔离不同模块或机器人,避免话题和服务名称冲突。


三、综合示例

假设我们有一个项目,需要启动一个模拟器(Gazebo)、加载机器人模型、启动一个激光雷达驱动和一个控制节点。

目录结构:

my_robot_pkg/
├── launch/
│   ├── main.launch
│   └── include/
│       └── lidar.launch
├── config/
│   └── controller.yaml
└── urdf/└── my_robot.urdf

1. config/controller.yaml (控制器参数)

pid:p: 1.0i: 0.1d: 0.05
max_velocity: 2.5

2. launch/include/lidar.launch (激光雷达的独立 launch 文件)

<launch><arg name="topic_name" default="/scan"/><arg name="frame_id" default="laser_link"/><node pkg="laser_driver_pkg" type="laser_node" name="lidar_node"><param name="scan_topic" value="$(arg topic_name)" /><param name="frame_id" value="$(arg frame_id)" /></node>
</launch>

3. launch/main.launch (主 launch 文件)

<launch><!-- ============== 定义可配置参数 ============== --><arg name="use_sim" default="true" doc="Set to false to run on real hardware"/><arg name="world_name" default="empty.world" doc="Gazebo world file to load"/><arg name="laser_topic" default="/scan"/><!-- ============== 启动模拟环境 (如果需要) ============== --><group if="$(arg use_sim)"><!-- 设置使用仿真时间 --><param name="/use_sim_time" value="true" /><!-- 启动 Gazebo --><include file="$(find gazebo_ros)/launch/empty_world.launch"><arg name="world_name" value="$(find my_robot_pkg)/worlds/$(arg world_name)"/><arg name="paused" value="false"/><arg name="use_sim_time" value="true"/><arg name="gui" value="true"/></include><!-- 加载机器人模型到参数服务器 --><param name="robot_description" textfile="$(find my_robot_pkg)/urdf/my_robot.urdf" /><!-- 在 Gazebo 中生成机器人 --><node name="spawn_urdf" pkg="gazebo_ros" type="spawn_model" args="-param robot_description -urdf -model my_robot" /></group><!-- ============== 加载通用节点 ============== --><!-- 加载控制器参数 --><rosparam command="load" file="$(find my_robot_pkg)/config/controller.yaml" /><!-- 启动控制器节点,并将输出打印到屏幕 --><node pkg="my_robot_pkg" type="controller_node" name="robot_controller" output="screen" /><!-- 包含激光雷达的 launch 文件,并传递参数 --><include file="$(find my_robot_pkg)/launch/include/lidar.launch"><arg name="topic_name" value="$(arg laser_topic)"/></include></launch>

如何运行:

  • 使用默认配置启动:

    roslaunch my_robot_pkg main.launch
    
  • 自定义参数启动(例如,不使用仿真,并修改激光话题名):

    roslaunch my_robot_pkg main.launch use_sim:=false laser_topic:=/real_robot/scan
    

这个例子展示了如何结合使用 <arg>, <param>, <rosparam>, <include>, if, 和 $(find) 来创建一个结构清晰、可复用、易于维护的启动系统。掌握这些,你就能应对绝大多数 ROS 项目的启动需求了。

http://www.xdnf.cn/news/15912.html

相关文章:

  • Linux内核设计与实现 - 第5章 系统调用
  • docker构建springboot镜像
  • 数据结构之图
  • 【办公类-107-02】20250719视频MP4转gif(削减MB)
  • MyBatis分页神器PageHelper深度解析
  • 深入解析文件操作(上)- 二进制文件和文本文件,流的概念,文件的打开和关闭
  • 计算机网络1.1:计算机网络在信息时代的作用
  • Redis常见线上问题
  • Javascript进程和线程通信
  • VIT速览
  • Nestjs框架: RxJS 核心方法实践与错误处理详解
  • XSS漏洞----基于Dom的xss
  • 混沌趋势指标原理及交易展示
  • python爬虫之获取渲染代码
  • Python 数据分析模板在工程实践中的问题诊断与系统性解决方案
  • 探索量子计算与法律理论的交叉领域
  • Zephyr环境搭建 - Board GD32A503
  • 力扣 hot100 Day49
  • 数据集下载网站
  • XSS漏洞知识总结
  • [spring6: AspectMetadata AspectInstanceFactory]-源码解析
  • PCIe RAS学习专题(3):AER内核处理流程梳理
  • 消息队列:数字化通信的高效纽带
  • 1009 - 数组逆序
  • Spring监听器
  • 2.4 组件间通信Props(父传子)
  • Rust Web 全栈开发(九):增加教师管理功能
  • 【SVM smote】MAP - Charting Student Math Misunderstandings
  • Custom SRP - Custom Render Pipeline
  • RabbitMQ01——基础概念、docker配置rabbitmq、内部执行流程、五种消息类型、测试第一种消息类型