移动机器人导航与定位:ROS2下的建图、定位与路径规划

发布时间:2026/9/18 6:51:16
移动机器人导航与定位:ROS2下的建图、定位与路径规划 简介面向机器人技术学习者与研究者的技术综述文档系统梳理移动机器人导航与定位领域的关键技术与研究框架。PDF全文围绕导航、定位、路径规划、实时控制四大核心模块展开明确区分自主与半自主导航、绝对与相对定位、静态与动态路径规划、开环与闭环控制等概念并覆盖工业、服务、医疗等应用场景。文中还引入“我现在何处我要往何处去要如何到该处去”三个基本问题阐述车体定位、多传感器信息融合、障碍识别与路径规划等核心环节的研究目标。资源共1个PDF文件压缩包仅205KB轻量便携属于早期学术文献适合快速把握移动机器人导航定位基本体系的入门读者。已有517人学习下载可用于课程报告、技术调研或知识扫盲参考。1. 移动机器人导航与定位三个问题一次讲清“移动机器人导航与定位技术”是个容易被低估的领域。很多人以为装好激光雷达、跑通 ROS2 导航就算完成结果一上真机地图对不齐、定位跳变、路径来回抽动问题几乎全出在最底层的“我在哪”上。移动机器人导航与定位实际上只回答三个问题我在哪、去哪里、怎么安全到达。定位解决第一问建图解决环境表示全局路径规划与局部避障解决后两问。三个环节必须闭合成环定位一旦漂移路径规划和避障都会基于错误位姿做判断动作越果断跑偏越快。这篇按定位、地图、导航、验证的顺序给出一套能在 ROS2 环境里落地的方案、参数和边界条件。适合正从仿真转真机或者被漂移和碰撞反复折磨的机器人工程师。2. 定位层从惯性导航到 ROS2 滤波融合先回答“我在哪”2.1 为什么单靠里程计会漂轮式里程计与惯性导航的互补关系轮式里程计通过轮子转速和转向角积分出位移短时间精度尚可时间一长打滑、轮胎半径误差、地面不平等都会让累积误差越来越明显。IMU 提供高频加速度和角速度直接积分能解算姿态和速度但静止时的加速度计噪声和陀螺零偏会让位置误差随时间发散。惯性导航的优点在短时高频缺点在长时漂移。卡尔曼滤波与惯性导航的结合正是用运动模型做“预测”用外部位姿观测做“更新”把两者的强项拼起来。移动机器人定位的常见做法是用轮式里程计或视觉/激光里程计作为预测源用 IMU 姿态修正航向用激光雷达匹配、GNSS 或 UWB 观测修正位置。这样既保留高频输出又不会让误差无限累积。要注意的是这里的“卡尔曼滤波”在机器人领域一般指扩展卡尔曼滤波因为轮式里程计和 IMU 的模型都包含姿态旋转项直接套线性卡尔曼会丢项。EKF 的核心思想是在当前状态点求雅可比把非线性系统近似成线性系统再按标准更新流程迭代。2.2 用 ROS2 的 robot_localization 做多传感器 EKF 融合ROS2 环境里最常用的就是robot_localization包。它提供ekf_node和ukf_node可以同时接入里程计、IMU、GNSS、UWB 等消息输出一个融合后的 odometry。下面是一个 2D 差速机器人的基本配置按 YAML 方式组织。# ekf.yaml -- ROS2 robot_localization 常见配置 frequency: 50.0 sensor_timeout: 0.2 two_d_mode: true differential: false odom0: /odom odom0_config: [true, true, false, false, false, true, false, false, false, false, false, false, false, false, false] odom0_queue_size: 10 imu0: /imu/data imu0_config: [false, false, false, true, true, true, false, false, false, true, true, false, false, false, false] imu0_queue_size: 10 process_noise_covariance: [0.05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.06, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.03, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.03, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.04, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.02]odom0_config和imu0_config都是 15 维布尔向量固定顺序是 x、y、z、roll、pitch、yaw、vx、vy、vz、vroll、vpitch、vyaw、ax、ay、az。这里对/odom只启用了 x、y 和 yaw其余维度交给 IMU 的姿态观测。two_d_mode: true会把 z、roll、pitch 直接置零适合室内地面机器人。differential: false表示允许 IMU 直接提供绝对朝向如果机器人没有磁力计或方向观测建议改成true这样算法只取角速度做相对更新避免室外磁干扰把航向拉飞。process_noise_covariance对角线上的值代表运动模型的噪声大小调得越大滤波器越愿意相信传感器观测输出跳动会变明显调得太小滤波结果会拖尾滞后。最常见的坑是 IMU 的时间戳没有同步到/odom的时钟域导致sensor_timeout一直触发丢弃。启动后要用ros2 topic echo /odometry/filtered观察协方差是否收敛协方差不再持续增大说明融合状态正常。2.3 粒子滤波与 AMCL已知地图下的重定位兜底EKF 适合预测连续位姿但无法处理“机器人到底在地图哪个位置”这种多峰分布问题。粒子滤波通过一组带权重的假设位姿逼近真实后验分布可以同时保留多个可能位置再靠激光匹配和重采样收敛到高概率区域。ROS2 的nav2_amcl模块就是自适应蒙特卡洛定位的实现适合在已知栅格地图上做重定位和长期定位。AMCL 的参数需要结合底盘噪声和激光特性调整下表的几个参数是上线前必调的。参数常用范围作用调参要点min_particles / max_particles500 / 2000粒子数上下限粒子太少容易丢定位太多会占 CPUupdate_min_d / update_min_a0.2 m / 0.5 rad最小移动/旋转阈值小于阈值不触发激光更新避免原地空转resample_interval1每几次激光更新重采样数值大收敛慢数值小粒子容易退化laser_min_range / laser_max_range0.1 / 10.0激光有效距离过滤掉雷达罩和远距离噪点odom_alpha1 ~ odom_alpha50.05 ~ 0.2里程计噪声模型对应旋转/平移误差需按底盘实测调整启动 AMCL 的常见方式是通过nav2_bringup的 localization launch也可以单独执行ros2 run nav2_amcl amcl。它订阅/map、/scan、/odom和 TF输出map - odom的坐标变换。如果 TF 树不完整AMCL 会在启动后一直“等待有效数据”。排查顺序是先看ros2 run tf2_echo map odom是否有输出再看激光话题时间戳是否滞后。2.4 激光配准与退化环境NDT、ICP 和复合定位当机器人使用 3D 雷达或对长距离定位有更高要求时点云配准比 2D 激光匹配更常用。NDT 和 ICP 都能把当前帧点云对齐到已有地图差异在于 NDT 先把参考点云栅格化成正态分布匹配时更快ICP 直接找最近点精度高但容易陷局部极值。常见做法是把 NDT 作为里程计因子和 IMU、轮式里程计一起送进 EKF。nav2 导航使用 3d 雷达时通常需要先把点云降维成 2D LaserScan 或直接在代价地图 obstacle layer 订阅 PointCloud2。这个降维过程要小心高度过滤区间设得太宽会把车身附近的坡道误判为障碍物设得太窄又会漏掉低矮路肩。退化环境是定位失效的高发地。长走廊两侧平行点云匹配在走廊方向没有约束NDT 会给出一个看似平滑但实际漂移的结果。电梯口、空旷停车场、隧道里也一样。遇到这类场景只用激光雷达是不够的至少需要一路航向观测IMU 的 yaw 或磁力计提供绝对航向再加一路里程计约束平移。预算允许时UWB 或二维码定位可以提供绝对坐标修正和 EKF 融合后能明显抑制退化漂移。上真机前我一般会在退化场景先录制 bag离线回放不同定位策略确认协方差不会在走廊中段突然爆掉再决定是否改动传感器配置。3. 建图与地图表示从栅格地图到八叉树地图导航的选型3.1 栅格地图的概率更新与八叉树地图导航的优势2D 占用栅格地图把环境切成长方形格子每个格子保存被占用的概率或对数几率。激光命中时格子概率增加激光穿过的自由空间概率降低。这个更新过程用对数几率的加法实现l l l_measurement输出概率为p 1 / (1 exp(-l))。直接用概率乘法会很快饱和到 0 或 1丢失不确定性信息。下面的 Python 片段演示了这个等效更新过程。# 简化的八叉树/栅格概率更新 import math def logit(p): return math.log(p / (1 - p)) def sigmoid(l): return 1.0 / (1.0 math.exp(-l)) node_log_odds 0.0 # 初始未知概率 0.5 hit 0.7 # 激光命中时观测概率 miss 0.4 # 激光穿过的观测概率 node_log_odds logit(hit) # 命中一次 print(sigmoid(node_log_odds)) # 约 0.7 node_log_odds logit(miss) # 之后被一次穿透观测覆盖 print(sigmoid(node_log_odds)) # 低于 0.7体现证据叠加这段代码里hit代表某次激光打到物体表面miss代表激光束穿过的空白区域。八叉树地图导航的核心优势是用递归八叉树存储稀疏 3D 空间分辨率可调且支持概率更新内存占用远小于等分辨率的 3D 栅格数组。对地面机器人2D 栅格地图已经够用对无人机或需要跨越坡道、限高杆的移动机器人3D 八叉树地图是更合理的导航地图。ROS 生态中octomap_server会把 3D 点云增量构建成八叉树并提供 OctoMap 话题。需要注意Nav2 原生规划器默认在 2D 代价地图上工作八叉树地图要接入 Nav2 通常得先把障碍物投影到 2D 层面或者在局部规划器里直接查体素占用。3.2 建图方案选型GMapping、Cartographer 与 SLAM ToolboxROS2 环境下主流建图链路有三种选型取决于场景大小、传感器质量和是否需要回环。GMapping 是粒子滤波加激光匹配的经典方法适合几十平米内的小场景计算快但缺少显式回环检测在长走廊或多次往返时地图容易裂开。Cartographer 使用子图与回环约束能构建大场景且支持 2D 和 3D 点云代价是配置项多调参周期长。SLAM Toolbox 把图优化和栅格地图结合支持在线建图和长期定位复用是目前 ROS2 里最省心的一个选择。方案核心思想推荐场景主要短板GMapping粒子滤波 scan matching小面积、简单室内回环差地图容易错位Cartographer子图 回环检测大面积、复杂结构参数多计算和内存消耗大SLAM Toolbox图优化 栅格建图长期建图、定位复用对激光帧率敏感需要好数据启动 SLAM Toolbox 的常见命令如下更适合实时建图的是 online_async 模式建图过程中不会因为扫描匹配把界面卡住。ros2 launch slam_toolbox online_async_launch.py slam_params_file:my_mapper_params.yaml参数文件里需要关注mode: mapping、min_laser_range、max_laser_range、map_update_interval和use_scan_matching。map_update_interval控制多久发布一次地图太频繁会拖垮 RVIZ太稀疏会让人看不到实时效果。建图时机器人转速要慢角速度超过 0.5 rad/s 时激光点云会变形SLAM 工具能处理一部分但超了阈值仍然会出现重影。这个教训在真机调试中几乎都会遇到。3.3 Nav2 地图与代价地图层的配置从地图到避障约束Nav2 的地图加载由map_server完成地图文件是栅格图加一个 YAML 描述文件。occupied_thresh和free_thresh决定灰度值如何映射到占用状态origin和resolution必须和建图时一致否则导航直接把人放到地图外。代价地图则分为 static layer、obstacle layer 和 inflation layer。static layer 负责静态地图obstacle layer 负责实时传感器障碍物inflation layer 负责把障碍物向外膨胀生成有梯度的代价区域。下面的costmap_common.yaml是接 2D 激光雷达的最小配置。obstacle_layer: enabled: true obstacle_range: 3.0 raytrace_range: 3.5 observation_sources: scan scan: data_type: LaserScan topic: /scan marking: true clearing: false lethal_cost_threshold: 100 track_unknown_space: false inflation_layer: enabled: true cost_scaling_factor: 3.0 inflation_radius: 0.8 static_layer: enabled: true map_topic: /mapobstacle_range是传感器能确认障碍物的最大距离raytrace_range是传感器能清除自由空间的射线距离。marking表示把命中点标为障碍clearing表示允许穿过的点被清空。对于 3D 雷达把observation_sources改成 PointCloud2 类型即可但必须先做高度裁剪。常见做法是保留雷达安装高度以上 0.2 米到以下 0.3 米之间的点云其余点云滤掉。不做这个过滤地面点、车顶扫描线都会被算成障碍物导航会频繁急停。4. 导航层全局路径与局部避障的工程化调参4.1 全局规划器选型NavFn、SmacPlanner 与混合 A*Nav2 中全局路径规划器有 NavFn 和 SmacPlanner 两类。NavFn 是基于网格的 A* / Dijkstra 实现简单稳定适合差速底盘和自由空间较大的环境。SmacPlanner 提供更接近业务的插件SmacPlanner2D对应 2D 网格 A*SmacPlannerHybrid是混合 A*支持阿克曼最小转弯半径约束SmacPlannerStateLattice适合差速和全向底盘的状态栅格搜索。对于阿克曼底盘直接用 NavFn 规划的路径往往有尖角底盘根本跟随不上必须用混合 A*。下面是一个 SmacPlanner2D 的配置片段。planner_server: ros__parameters: expected_planner_frequency: 1.0 planner_plugins: [GridBased] GridBased: plugin: nav2_smac_planner/SmacPlanner2D tolerance: 0.5 downsample_costmap: true allow_unknown: true smooth_path: true w_eucl_cost: 1.0 w_heuristic_cost: 0.5 w_costmap: 2.0tolerance是目标点被障碍物占据时允许搜索附近自由点的半径。downsample_costmap可以降低大地图上的搜索耗时但会丢失窄通道细节。w_costmap控制路径距离障碍物的偏好调太大路径会绕远但安全调太小路径贴墙走局部规划器稍一抖动就会刮蹭。实际调参时我一般先固定w_eucl_cost只调w_costmap观察全局路径是否在门洞、墙边出现来回折线。折线通常不是算法问题是代价地图在障碍物边缘分辨率不够。4.2 局部规划器DWA、TEB 与速度采样参数局部规划器负责把全局路径转成实时速度指令。DWBDWA 在 Nav2 中的实现在速度空间随机采样多组线速度与角速度用轨迹评价函数选一条最优。TEB 把一段轨迹建模成带时间戳的弹性带通过优化时间间隔获得平滑轨迹适合阿克曼底盘但参数不当会在窄通道里抖动。MPPI 则基于随机采样和代价函数滚动优化能自然处理多目标约束但计算量大调试也更复杂。下面的对比表可以辅助选型。局部规划器适用底盘优势常见问题DWB/DWA差速、全向模型简单、稳定轨迹不平滑阿克曼跟随困难TEB阿克曼、差速轨迹平滑、时间最优窄通道抖动靠墙易震荡MPPI任意多约束、可预测未来参数依赖高CPU 开销大DWB 的参数设计直接影响运动品质。一个最小可用的本地规划器配置如下。FollowPath: plugin: nav2_dwb_controller/DWBLocalPlanner max_vel_x: 0.5 min_vel_x: -0.1 max_vel_theta: 1.0 acc_lim_x: 2.5 acc_lim_theta: 3.2 xy_goal_tolerance: 0.2 yaw_goal_tolerance: 0.1 sim_time: 2.0 vx_samples: 20 vtheta_samples: 20 path_distance_bias: 4.0 goal_distance_bias: 1.5 occdist_scale: 0.02sim_time表示预测未来轨迹的时间窗口窗口越短制动反应越快但容易在高速时刹车距离不够窗口太长轨迹计算量大且遇到突然出现的障碍反应迟钝。path_distance_bias和goal_distance_bias的比值需要平衡。occdist_scale是障碍物代价权重设成 0 会导致机器人贴着障碍物走设得过大又会认为所有接近障碍的轨迹都不可行窄门过不去。TEB 里常见的关键参数是dt_ref、min_obstacle_dist和weight_obstacle。min_obstacle_dist代表轨迹上每一点到障碍物的最小允许距离小于这个值会被当作硬约束。4.3 膨胀层、无解区域与恢复行为导航失败的真正原因很多导航失败不是规划器的问题而是膨胀代价把可行空间吞噬了。inflation_radius是代价从障碍物向外衰减的最大半径cost_scaling_factor控制衰减曲线的陡峭程度。同一个 1 米宽的过道如果inflation_radius设为 0.8左右两侧各膨胀 0.4 米后过道中间的安全宽度只剩 0.2 米全局规划器很可能判定无解。此时机器人会在过道前反复重规划甚至触发恢复行为。判断这个问题的办法是在 RVIZ 里打开代价地图层看可行区域是否已经变成一条细线。Nav2 恢复行为默认是清理代价地图、原地旋转、后退一步。行为树里可以配置多次恢复的失败容忍度比如两次旋转失败后直接宣布导航失败。对移动机器人导航与定位的整体稳定性来说恢复行为只是兜底不是救火工具。若真机上频繁出现“恢复-规划-再恢复”的循环优先查两件事地图是否包含动态物体残留以及膨胀参数是否与车身实际宽度匹配。地图里的幽灵障碍物只要出现一次后续每次导航都会被当作硬墙。5. 最后一公里验证用离线回放和协方差判断定位是否可用5.1 真机前先回放 bag定位参数别在实物上盲目试最稳妥的验证方式不是把机器人推到现场直接跑导航而是先录制传感器数据再用 ROS2 bag 离线回放。录制时至少要包含/scan、/odom、/imu/data、/map、/tf和/tf_static机器人静止几秒后绕环境走一圈回到起点。然后离线启动定位节点把use_sim_time设为true用ros2 bag play --clock驱动时间轴。此时可以通过ros2 run tf2_tools view_frames检查 TF 树或者用ros2 run tf2_echo map odom观察map - odom的变换。map - odom的变换在机器人静止时应该稳定在平移微小抖动范围内。如果这个变换随时间明显漂移说明里程计或 IMU 的噪声参数不准或者外参标定有误。另一个容易忽略的环节是时间同步。机器人导航要求所有传感器消息时间戳对齐使用 ros2 bag 回放时尤其要注意/clock是否发布否则定位节点会因为时间戳跳变直接丢弃数据。5.2 用定位协方差做自动化判定EKF 融合后的PoseWithCovarianceStamped协方差能直接反映定位质量。协方差矩阵对角线代表 x、y、yaw 的不确定度膨胀到一定程度就该触发重定位而不是继续带着错误位姿导航。生产环境可以写一个简单监控脚本订阅位姿话题当 x 或 y 的方差超过设定阈值时发布一个/recover/trigger消息让机器人在原地旋转重新建粒子云。这个方法比依赖导航失败反馈更早一步能显著减少碰撞风险。在施工现场我一般设定机器人单方向平移方差超过 0.05 平方米或航向方差超过 0.1 平方弧度就执行重定位具体阈值按激光帧率会收紧或放宽。定位收敛状态还有一个直观判据静止时把 AMCL 粒子云显示在 RVIZ 里所有粒子应该在机器人真实位置附近聚成一个直径 0.3 米以内的团。若粒子呈线状分布多半是激光匹配在某个方向上没有约束此时检查周围环境是否过于空旷若粒子散开成几团说明初始位姿错得太远或地图有多层重影。处理办法是先手动给定初始位姿再验证移动过程协方差是否回落。稳定后再接规划器整套移动机器人导航与定位系统才有可能在真实场景里长期工作。本文还有配套的精品资源点击获取