4. 移动机器人导航项目:地图构建(SLAM)、定位与路径规划、导航栈配置

4.1 导航系统整体架构与核心模块

移动机器人导航的本质是回答三个递进问题:“我在哪里?”(定位)、“周围环境长什么样?”(建图)、“如何安全到达目标?”(路径规划)。在 ROS2 中,这些问题由 SLAM 建图模块、AMCL 自适应蒙特卡洛定位、Nav2 导航栈 协同解决。三者通过 TF 树、里程计话题、激光雷达扫描话题和地图话题紧密耦合,构成一个完整的闭环系统。

传感器层 /scan (激光雷达) /odom (轮式里程计) SLAM 建图 slam_toolbox / cartographer 输出:栅格地图 (PGM/YAML) + 机器人轨迹 map_server 加载静态地图 AMCL 定位 粒子滤波 /amcl_pose Nav2 导航栈 Planner 全局路径 Controller 局部轨迹跟踪 BT Navigator 行为树调度 全局/局部代价地图 恢复行为 (Recovery) 底盘驱动 /cmd_vel 差速 / 全向 / 阿克曼 RViz2 可视化调试 2D Pose Estimate TF: map→odom→base_link

上图展示了导航系统的数据流:激光雷达与里程计数据同时送入 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
建图技巧: 建图时保持机器人线速度 0.2~0.3 m/s,角速度不超过 0.5 rad/s。遇到走廊尽头时,先原地旋转 360° 让激光雷达充分扫描,再继续前进,可显著减少地图漂移。

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 仿真环境:

  1. 启动仿真环境: ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py
  2. SLAM 建图: 启动 slam_toolbox,手动遥控机器人遍历环境,保存地图。
  3. 启动定位: 加载地图并启动 AMCL,在 RViz2 中给出初始位姿。
  4. 启动导航: 启动 Nav2 导航栈,等待 /amcl_pose 话题输出稳定。
  5. 发布目标点: 在 RViz2 中使用 Nav2 Goal 按钮点击目标位置,观察机器人规划路径并执行。
  6. 监控与调参: 观察 /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 必须与底盘实际能力匹配,否则会导致跟踪超调或震荡。