2. ROS2基础回顾与Nav2依赖:ROS2核心概念、TF树、URDF与Launch系统
各位同学,欢迎来到第二章。在正式开始折腾Nav2仿真之前,咱们得先把地基夯实。很多新手一上来就急着跑导航,结果遇到问题一脸懵,回头一看,原来是ROS2的基本功没打牢。
这一章,我会带你快速过一遍ROS2里跟Nav2最相关的几个核心概念。说白了,Nav2就是建立在ROS2这些基础组件上的一个复杂应用。你搞懂了节点、话题、动作、TF树这些玩意儿,后面排查问题才能有的放矢。
2.1 ROS2核心概念:节点、话题、服务、动作
ROS2的通信机制,我习惯把它理解成一个“消息工厂”。不同的零件(节点)通过不同的传送带(话题、服务、动作)来传递包裹(消息)。
2.1.1 节点(Node)
节点是ROS2中最基本的执行单元。一个机器人系统通常由几十上百个节点组成,每个节点负责一个特定的功能。比如,激光雷达驱动是一个节点,里程计发布是一个节点,Nav2的控制器又是一个节点。
2.1.2 话题(Topic)
话题是ROS2里最常用的通信方式,用于连续、单向的数据流。比如,激光雷达数据、里程计数据、速度指令,这些都是通过话题发布的。
- 发布者(Publisher):发送数据的节点。
- 订阅者(Subscriber):接收数据的节点。
- 消息类型(Message Type):定义了数据的结构,比如
sensor_msgs/msg/LaserScan。
在Nav2里,最重要的几个话题包括:
| 话题名称 | 消息类型 | 说明 |
|---|---|---|
/scan |
sensor_msgs/msg/LaserScan |
激光雷达数据,Nav2感知环境的核心输入 |
/odom |
nav_msgs/msg/Odometry |
里程计数据,提供机器人位姿估计 |
/cmd_vel |
geometry_msgs/msg/Twist |
速度指令,Nav2最终输出的控制命令 |
2.1.3 服务(Service)
服务用于短连接、有应答的通信。你发一个请求,服务器处理完给你一个响应。它适合那些不需要持续更新的操作,比如“加载地图”、“获取当前位姿”。
在Nav2中,服务常用于生命周期管理。比如,启动导航时,Nav2节点会通过服务请求来切换状态。
2.1.4 动作(Action)
动作是ROS2里最强大的通信机制,专门用于处理长时间执行的任务。它结合了话题和服务的特点:
- 客户端发送一个目标(Goal)。
- 服务端在执行过程中,持续发布反馈(Feedback)。
- 任务完成后,返回结果(Result)。
Nav2的核心——导航行为树,就是基于动作服务器实现的。你给Nav2一个导航目标,它会持续反馈当前状态(比如“正在规划路径”、“正在绕障”),最后告诉你“到达目标”或“任务失败”。
timeout参数一定要根据你的实际场景来调整,尤其是在仿真环境里,计算资源有限,很容易超时。
2.2 TF树与坐标变换
TF(Transform)树,是机器人学里最核心的概念之一。没有它,机器人就是个“瞎子”。它描述了机器人各个部件之间的空间关系。
你想想看,激光雷达扫描到的点,是在激光雷达坐标系下的。但机器人要导航,需要知道这些点相对于机器人底盘(base_link)的位置。TF树就是用来做这个转换的。
2.2.1 常见的坐标系
- map:世界坐标系,固定不变,是全局定位的基准。
- odom:里程计坐标系,用于局部一致性估计,会随时间漂移。
- base_link:机器人底盘坐标系,通常位于机器人中心。
- laser_link:激光雷达坐标系。
Nav2正常工作,必须保证以下TF变换是正确发布的:
map→odom:由定位模块(如AMCL)发布。odom→base_link:由里程计发布。base_link→laser_link:由机器人模型(URDF)发布。
base_link到laser_link的变换没有发布。你可以在终端用ros2 run tf2_tools view_frames命令来查看当前的TF树结构,这是排查定位问题的第一步。
2.2.2 TF树结构图
下面这张图,展示了Nav2仿真中一个典型的TF树结构。你可以看到,所有坐标系最终都关联到base_link上。
2.3 URDF/SDF模型基础
URDF(Unified Robot Description Format)和SDF(Simulation Description Format)都是用来描述机器人模型的。在Nav2仿真里,我们主要用URDF。
URDF文件定义了机器人的:
- 连杆(link):机器人的刚体部分,比如底盘、轮子、激光雷达外壳。
- 关节(joint):连接两个连杆的方式,比如固定关节、旋转关节。
- 几何与碰撞属性:用于可视化和物理仿真。
一个最简单的URDF文件长这样:
<robot name="my_robot">
<link name="base_link">
<visual>
<geometry>
<box size="0.5 0.4 0.2"/>
</geometry>
</visual>
</link>
<joint name="laser_joint" type="fixed">
<parent link="base_link"/>
<child link="laser_link"/>
<origin xyz="0.2 0 0.1" rpy="0 0 0"/>
</joint>
</robot>
origin标签里的xyz和rpy一定要仔细核对。我曾经因为把激光雷达的安装高度写错了,导致导航时机器人总是撞到低矮的障碍物。记住,URDF里的坐标关系,直接决定了TF树的正确性。
2.4 Launch文件系统
Launch文件是ROS2里启动多个节点的“总指挥”。你不需要一个一个地开终端去运行ros2 run,一个Launch文件就能搞定一切。
在Nav2仿真中,一个典型的Launch文件会做以下几件事:
- 启动机器人模型(URDF)发布节点。
- 启动Gazebo仿真环境。
- 启动Nav2的核心节点(导航行为树、控制器、规划器等)。
- 启动RViz2可视化界面。
一个简单的Launch文件示例:
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='robot_state_publisher',
executable='robot_state_publisher',
name='robot_state_publisher',
output='screen',
parameters=[{'robot_description': open('my_robot.urdf').read()}]
),
Node(
package='nav2_bringup',
executable='bringup_launch.py',
name='nav2_bringup',
output='screen'
),
])
robot_description这个参数,必须是一个字符串,而不是文件路径。我见过有人直接把文件路径传进去,结果节点启动后一直报错说找不到机器人模型。记住,要用open().read()把文件内容读成字符串。
好了,这一章的内容就到这里。这些基础概念,是后面所有仿真联调工作的基石。你花时间把它们搞透,后面遇到问题才能快速定位。下一章,我们就要开始搭建实际的仿真环境了。