ROS2 差速机器人栅格 A* 全局路径规划

1. 概述

本文实现一个面向差速移动机器人的全局路径规划模块:输入占用栅格地图 (nav_msgs/OccupancyGrid)与目标位置,输出一条安全、平滑、带时间参数的路径 (nav_msgs/Path),可直接交给下层控制器跟踪。

核心算法只依赖 NumPy,无需 ROS / 仿真器即可跑通离线仿真与 50 项单元测试。

在 OpenHUTB/ros2 仓库中,本模块属于规划层,与已合并的 ros2_pure_pursuit(路径跟踪控制层)、ros2_ekf_localization(状态估计层)互补, 三者构成 "定位 → 规划 → 控制" 的完整链路:

/odom + /imu ─► EKF 定位 ─► /odometry/filtered ─┐
                                                 ├─► A* 规划 ─► /plan ─► 纯追踪控制 ─► /cmd_vel
/map + /goal ──────────────────────────────────┘

整体流程:

/map (OccupancyGrid) ─┐
                      ├─► 膨胀(避障裕度) ─► A* 搜索 ─► 视线捷径 ─► 梯度平滑 ─► 梯形速度剖面 ─► /plan (Path)
/goal (PoseStamped) ──┤        ▲                                                        ▲
/robot_pose ──────────┘        └──────── 连通性预检 / 端点修复 / 超时保护 ─────────────┘

2. 方法

2.1 占用栅格与膨胀

栅格数组 grid[i, j] 中 i 为行(y 方向)、j 为列(x 方向),非零即占用。 规划前按机器人半径做方形结构元膨胀(切比雪夫距离),把机器人当作圆处理:

膨胀用两次可分离的最小值滤波实现,复杂度 且与半径无关:

  • 横向:
  • 纵向:

膨胀的必要性在第 5 节有定量验证:它直接决定通道是否还能通行。

2.2 A* 搜索

状态为栅格坐标,8 邻接代价为直行 1、对角 :

启发式按邻接方式自动选择,保证可采纳性( 不超过真实剩余代价), 因此 时 A* 给出最优解:

邻接 启发式 公式
8 邻接 octile
4 邻接 manhattan

工程细节:

  • 二叉堆 + 延迟删除:不维护 decrease-key 索引,节点重复弹出时跳过;
  • 平局打破: 相同时优先 小者(更接近目标),开阔地形上减少无谓扩展;
  • 严格穿角:对角步要求两侧格都是自由格。只禁止"两侧都占用"虽然栅格层面合法, 但连接两个格心的直线仍可能擦过占用格的一角,与后处理的连续空间碰撞检查语义不一致;
  • 有界搜索:max_expansions 超限立即终止,地图异常时不会打满 CPU;
  • 连通性预检:搜索前先做 4-邻接连通域标记,不连通直接返回明确原因。

2.3 路径后处理

栅格 A* 的输出被限制在 8 个方向上,转弯生硬、长度偏大,直接喂给移动机器人 会导致频繁加减速。这里做两级后处理。

一级:视线捷径(string pulling)——若两点间直线不穿越障碍,用直线段替换中间折点。 碰撞检查用超采样(采样间距为分辨率的 1/4),比标准 Bresenham 更保守, 能避免"斜着擦过格角"的漏检。

二级:梯度平滑——对剩余折点做迭代优化:

第一项把折线拉直,第二项只在点离障碍过近时产生斥力,把路径推离墙面。 梯度解析可求(无需自动微分),单步位移夹紧到 1 个分辨率以防发散。

平滑后逐段复核碰撞,若任一段被判碰撞则回退到捷径结果——保证输出永远安全。

2.4 时间参数化

几何路径转成可执行轨迹:

  1. 三点外接圆估计各点曲率 ;
  2. 曲率限速 ,避免转弯时侧向加速度超限;
  3. 沿弧长做前向 + 后向两遍扫描,用 保证加减速不超限 (后向扫描负责"提前刹车");
  4. 逐段按平均速度积分得到时间戳。

3. 安全设计

情况 处理
地图过期(/map 超时) 拒绝规划并告警,避免在过期地图上给出穿墙路径
起点缺失 拒绝规划(不拿目标当起点)
目标落在障碍内 BFS 找到最近自由格,并在日志中说明
起终点不连通 连通性预检直接失败,指出"分属不同自由区域"
不可采纳启发式 允许配置,但基准实验会显示其不再保证最优
参数非法(NaN / 非正 / 过大) 启动时校验,非法值回退默认并告警
地图异常(搜索不收敛) max_expansions 兜底,避免打满 CPU
平滑后路径可能碰撞 逐段复核,异常时回退到未经平滑的路径
地图未知区域 按占用处理(保守),不当作可通行区域

4. 运行步骤

4.1 安装依赖

pip3 install -r requirements.txt   # numpy / matplotlib

4.2 离线仿真(无需 ROS)

python3 sim/run_sim.py --map corridor --out results/corridor.png
python3 sim/run_sim.py --map maze     --out results/maze.png
python3 sim/run_sim.py --map random   --out results/random.png

4.3 基准矩阵

python3 sim/benchmark.py    # 输出 results/benchmark.md

4.4 ROS2 中部署

colcon build --packages-select ros2_astar_planner
source install/setup.bash
ros2 launch ros2_astar_planner plan.launch.py robot_radius:=0.20
话题 类型 方向 说明
/map nav_msgs/OccupancyGrid 订阅 栅格地图(未知区域按占用处理)
/goal geometry_msgs/PoseStamped 订阅 目标点
/robot_pose geometry_msgs/PoseStamped 订阅 机器人当前位姿(起点)
/plan nav_msgs/Path 发布 平滑并时间参数化后的路径
/plan_info std_msgs/String 发布 JSON 诊断信息

常用参数:robot_radius、inflation_extra、allow_diagonal、heuristic、 weight、v_max、a_max、plan_timeout、map_timeout、use_smoothing。

5. 实验结果

5.1 规划质量

三种地图(走廊 / 迷宫 / 随机障碍)× 五种搜索配置的完整数据见 src/ground/ros2_astar_planner/results/benchmark.md,关键结论:

结论 定量结果
最优性验证 A*(octile) 与 Dijkstra 代价完全一致(相对差 0.00%),证明启发式可采纳
搜索效率 A* 相比 Dijkstra 扩展节点减少 2.8% ~ 74.8%(走廊 74.8%、随机障碍 42.7%);迷宫因通道狭窄,启发式信息量低,收益仅 2.8%
加权 A* 的取舍 w=1.5 扩展节点最多减少 79.3%,代价最多劣化 3.2%
对角收益 8 邻接比 4 邻接代价低 0.5% ~ 19.0%(走廊 19.0%、随机障碍 15.5%;迷宫通道笔直,对角几乎无收益 0.5%)

5.2 走廊场景:路径与速度剖面

走廊场景规划结果

图中浅红色为机器人半径对应的膨胀层,蓝线为 A* 原始路径,红线为捷径 + 梯度平滑结果。 右侧为梯形速度剖面 与曲率 ;指标面板给出路径长度、扩展节点数、 折点/转角变化与加速度约束校验结果。

平滑把折点数从 53 降到 6、转角数从 11 降到 4,路径长度从 6.24 m 缩短到 5.95 m(4.6%)。

5.3 平滑前后对照

下图为关闭平滑的对照图:折线沿 8 个栅格方向折行,转角多、速度无法连续, 下游控制器需要频繁加减速。

未平滑对照

5.4 迷宫场景

迷宫场景规划结果

迷宫场景平滑后路径几乎不变(缩短 0.1%):通道狭窄时两点之间本就没有可直达的视线, 捷径算法找不到可替换的直段。这恰恰说明后处理不会为了缩短路径而牺牲避障安全。

5.5 随机障碍场景

随机障碍场景

5.6 通道宽度与机器人半径

用"一墙一门"地图(房间固定、端点在房间中央,连通性只由门宽决定), 固定机器人半径 0.20 m(膨胀 2 格)扫描门洞宽度:

门洞净宽 膨胀 1 格 (0.10 m) 膨胀 2 格 (0.20 m) 膨胀 3 格 (0.30 m)
0.10 m 不可通行 不可通行 不可通行
0.20 m 可通行 不可通行 不可通行
0.30 m 可通行 可通行 不可通行
0.40 m 以上 可通行 可通行 可通行

通道净宽必须大于 2×膨胀半径。膨胀层把门洞堵死时,规划器会如实返回 "起点与终点不连通",而不会给出一条穿墙的路径——这正是安全裕度必须与 地图分辨率一起考虑的原因。

6. 局限与展望

  • 8 邻接 A* 在大地图(>200×200)上扩展节点仍偏多,可用 JPS / 双向 A* 改进;
  • 膨胀是各向同性的方形结构元,未考虑机器人非圆形外形(如长方体车体的朝向约束);
  • 后处理是几何层面的,没有做动力学可行性检查(最小转弯半径);
  • 仅规划单段路径,未实现多段路网与全局重规划;
  • 离线仿真使用合成地图,尚未在 Gazebo / CARLA 中接入真实 /map 话题验证。

7. 自测

python3 tests/test_core.py   # 50 项单元测试
bash ci/run_ci.sh            # 语法/依赖/测试/仿真/基准 五阶段

8. 许可与署名

MIT License。

作者:李诚轩(学号 2535030014)