4. 移动机器人导航项目:地图构建(SLAM)、定位与路径规划、导航栈配置
4.1 导航系统整体架构与核心模块
移动机器人导航的本质是回答三个递进问题:“我在哪里?”(定位)、“周围环境长什么样?”(建图)、“如何安全到达目标?”(路径规划)。在 ROS2 中,这些问题由 SLAM 建图模块、AMCL 自适应蒙特卡洛定位、Nav2 导航栈 协同解决。三者通过 TF 树、里程计话题、激光雷达扫描话题和地图话题紧密耦合,构成一个完整的闭环系统。
上图展示了导航系统的数据流:激光雷达与里程计数据同时送入 SLAM 模块完成建图;建图完成后,map_server 加载静态地图,AMCL 结合地图与实时传感器数据输出机器人位姿;Nav2 栈接收目标点后,在代价地图上规划全局路径并跟踪局部轨迹,最终将速度指令发送给底盘。RViz2 作为交互窗口,用于设置初始位姿、发布目标点并监控各模块状态。
4.2 SLAM 建图:从传感器数据到栅格地图
SLAM(Simultaneous Localization and Mapping)在建图过程中同时估计机器人位姿与环境地图。ROS2 中最常用的方案是 slam_toolbox,它基于扫描匹配与图优化,适合结构化室内环境。启动建图的核心命令如下:
ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py
ros2 launch slam_toolbox online_async_launch.py
ros2 run teleop_twist_keyboard teleop_twist_keyboard
建图过程中,需要缓慢移动机器人覆盖整个环境,避免急转弯和快速移动导致扫描匹配失败。建图完成后,使用 map_saver_cli 保存地图:
ros2 run nav2_map_server map_saver_cli -f ~/map/my_house
该命令生成 my_house.pgm(图像文件)和 my_house.yaml(元数据文件)。YAML 文件中的关键参数包括:
| 参数 | 含义 | 典型值 |
|---|---|---|
| resolution | 每像素对应米数 | 0.05 |
| origin | 地图左下角在世界坐标系中的位姿 | [-10.0, -10.0, 0.0] |
| occupied_thresh | 像素被占用的概率阈值 | 0.65 |
| free_thresh | 像素为自由空间的概率阈值 | 0.25 |
4.3 AMCL 定位:粒子滤波的工程实践
AMCL(Adaptive Monte Carlo Localization)使用粒子群表示机器人位姿的概率分布。每个粒子代表一个可能的位姿 (x, y, θ),通过运动模型预测、激光观测更新和重采样三个步骤迭代收敛。启动定位前,需要先启动 map_server 加载地图:
ros2 launch nav2_bringup localization_launch.py map:=~/map/my_house.yaml
AMCL 的关键参数直接影响定位精度与鲁棒性:
min_particles/max_particles:粒子数量范围,室内场景建议 500~2000,粒子越多越精确但 CPU 开销越大。update_min_d:触发重采样的最小位移(米),建议 0.2~0.5。update_min_a:触发重采样的最小旋转(弧度),建议 0.2~0.5。laser_likelihood_max_dist:激光匹配的最大距离,超过该距离的测量被忽略,防止动态物体干扰。
在 RViz2 中,使用 2D Pose Estimate 按钮手动指定初始位姿。若初始位姿偏差过大(超过 1 米或 30°),粒子群可能无法收敛到正确位置,表现为定位漂移或地图与激光点云错位。此时应重新设置初始位姿,或使用 ros2 service call /relocalize 触发全局重定位。
4.4 Nav2 导航栈配置与路径规划
Nav2 是 ROS2 的官方导航框架,其核心是 行为树(Behavior Tree) 驱动的任务调度。启动导航的完整命令为:
ros2 launch nav2_bringup navigation_launch.py map:=~/map/my_house.yaml
导航栈的核心配置集中在 nav2_params.yaml 中,主要包含以下部分:
planner_server:
ros__parameters:
planner_plugins: ["GridBased"]
GridBased:
plugin: "nav2_navfn_planner/NavfnPlanner"
tolerance: 0.5
controller_server:
ros__parameters:
controller_plugins: ["FollowPath"]
FollowPath:
plugin: "nav2_regulated_pure_pursuit_controller/RegulatedPurePursuitController"
desired_linear_vel: 0.3
max_linear_accel: 0.5
local_costmap:
local_costmap:
ros__parameters:
robot_radius: 0.22
inflation_radius: 0.55
update_frequency: 5.0
路径规划分为两层:全局规划(NavfnPlanner)在静态地图上计算从起点到目标点的最优路径;局部规划(RegulatedPurePursuitController)则基于实时代价地图,避开动态障碍物并跟踪全局路径。代价地图中的 inflation_radius 决定障碍物周围膨胀区域的大小,该值过小会导致机器人贴近墙壁,过大则可能无法通过狭窄通道。
robot_radius 设置为 0,导致规划路径穿过实际无法通行的缝隙。务必根据机器人真实尺寸设置该参数,并留出至少 5~10 cm 的安全余量。
4.5 综合案例:从建图到自主导航的完整流程
以下是一个典型的室内巡检机器人部署流程,假设使用 TurtleBot3 仿真环境:
- 启动仿真环境:
ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py - SLAM 建图: 启动 slam_toolbox,手动遥控机器人遍历环境,保存地图。
- 启动定位: 加载地图并启动 AMCL,在 RViz2 中给出初始位姿。
- 启动导航: 启动 Nav2 导航栈,等待
/amcl_pose话题输出稳定。 - 发布目标点: 在 RViz2 中使用 Nav2 Goal 按钮点击目标位置,观察机器人规划路径并执行。
- 监控与调参: 观察
/plan话题的全局路径是否合理,/local_plan是否平滑,必要时调整代价地图参数。
实际部署中,若机器人到达目标点后停止位置偏差较大,可检查 goal_checker 的 xy_goal_tolerance 参数(默认 0.25 m)。若机器人频繁陷入“抖动-恢复-再抖动”的循环,通常是因为局部代价地图更新频率过低或膨胀半径过小,导致规划路径反复变化。
4.6 误区与复盘:导航系统调试要点
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 地图与激光点云错位 | 初始位姿不准 / TF 树断裂 | 重新设置 2D Pose Estimate;检查 ros2 run tf2_tools view_frames |
| 规划路径穿墙 | 代价地图膨胀半径过小 | 增大 inflation_radius 至 0.5~0.7 m |
| 机器人到达目标后旋转不停 | 角度容差过小 | 增大 yaw_goal_tolerance 至 0.1~0.2 rad |
| 定位丢失(粒子发散) | 环境特征稀疏 / 动态物体过多 | 增加粒子数量;在特征丰富区域重新初始化 |
复盘导航系统调试过程,最重要的经验是:先确认 TF 树正确,再检查定位收敛,最后才调路径规划参数。TF 树是导航系统的“坐标系骨架”,任何模块的坐标系错位都会导致灾难性后果。建议在调试初期使用 ros2 run tf2_ros tf2_echo map base_link 持续监控坐标变换,确保 map→odom→base_link 链路稳定输出。
此外,导航性能的瓶颈往往不在算法本身,而在传感器质量与底盘响应。激光雷达的扫描频率、里程计的打滑程度、底盘的加减速能力,都会直接影响导航效果。在仿真环境中调试成功的参数,迁移到真实机器人时通常需要重新标定,尤其是 max_linear_accel 和 max_rotational_accel 必须与底盘实际能力匹配,否则会导致跟踪超调或震荡。