1. 从“寻路”到“寻优”:路径规划算法的核心价值
我们每天都在做路径规划。早上出门,打开手机地图,输入目的地,软件会瞬间为你规划出几条路线,并告诉你哪条最快、哪条最省油、哪条红绿灯最少。这背后,就是路径规划算法在默默工作。但路径规划的价值远不止于此。从仓库里AGV小车的穿梭,到无人机在复杂空域的自主飞行;从游戏里NPC如何绕过障碍物找到玩家,到物流公司如何为上千辆卡车安排最优的配送顺序——这些场景的核心,都是路径规划算法。
简单来说,路径规划就是在一个有障碍物的空间里,为移动的智能体(可以是机器人、车辆、甚至是一个虚拟点)找到一条从起点到终点的可行路径。但“可行”只是最低要求,我们真正追求的是“最优”。这个“优”的标准因场景而异:可能是距离最短、时间最少、能耗最低、安全性最高,或者是综合了多种因素的复杂指标。因此,路径规划算法从来不是一套固定的公式,而是一个庞大的工具箱,里面装满了针对不同问题、不同约束条件的专用工具。
作为一名在机器人导航和智能调度领域摸爬滚打了十多年的工程师,我处理过从简单的二维栅格地图寻路,到考虑动态交通流、车辆动力学约束的三维时空联合规划。我发现,很多初学者甚至一些有经验的开发者,在面对具体问题时,常常会陷入“算法选择困难症”:A*听起来很万能,RRT好像很高级,Dijkstra是不是过时了?其实,没有最好的算法,只有最合适的算法。理解每种算法的“脾气秉性”、能力边界和适用场景,比死记硬背公式重要得多。这篇文章,我就结合自己的实战经验,为你系统性地拆解主流路径规划算法的内核,帮你建立起清晰的认知框架,让你在面对具体需求时,能快速、准确地找到那把对的“钥匙”。
2. 环境建模:算法施展拳脚的舞台
在讨论任何算法之前,我们必须先搭建舞台——也就是对真实世界进行数学抽象,这个过程叫做环境建模。模型建得好不好,直接决定了后续规划的效率和质量。一个粗糙的模型会让再精巧的算法也步履维艰,而一个过细的模型又会带来不必要的计算负担。常见的环境建模方法主要有以下几种,它们各有优劣,适用于不同的场景。
2.1 栅格法:最直观的“像素化”世界
这是最经典、最易于理解和实现的方法。我们把整个环境划分成均匀的网格,就像一张像素图片。每个格子(Cell)只有两种状态:空闲(可通行)或占用(障碍物)。机器人或车辆被看作一个点,或者占据若干个格子的物体。
核心原理与实现:假设我们有一个10x10米的房间,将其划分为0.1米见方的格子,就会得到一个100x100的二维数组。数组中的每个元素存储一个值,比如0表示空闲,1表示障碍物。规划时,算法就在这个0和1组成的矩阵里寻找通路。
实战心得与避坑指南:
- 分辨率选择是门艺术:格子太大,会丢失环境细节,可能导致规划出的路径过于贴近障碍物,甚至因为“锯齿状”路径而无法被实际机器人执行(机器人有体积,不是质点)。格子太小,地图数据量会呈平方级增长,严重拖慢搜索速度。我的经验法则是,格子的边长至少要比机器人的半径(或半宽)大20%-30%,以确保安全裕度。
- “膨胀”障碍物是关键操作:由于机器人有物理尺寸,我们不能只把障碍物本身标记为占用,还需要在其周围进行“膨胀”操作。例如,机器人半径为0.3米,我们就需要把所有障碍物向外“画”出一个0.3米的圈,这个圈内的格子也标记为占用。这样,规划时把机器人视为质点,找到的路径就是绝对安全的。很多初学者忘记这一步,导致仿真完美,实物一跑就撞。
- 存储与搜索优化:对于大规模栅格地图,直接使用二维数组可能内存效率低下。可以使用稀疏数据结构(如只记录障碍物位置),或者采用四叉树、八叉树(用于三维)进行分层管理,加速空闲区域的查询。
2.2 可视图法:连接“安全点”的直线网络
当环境中的障碍物可以用多边形(如矩形、凸多边形)精确描述时,可视图法非常高效。其核心思想是:如果路径是由一系列直线段组成,那么只要这些线段不与任何障碍物相交,路径就是安全的。因此,我们把所有障碍物的顶点(多边形角点)以及起点、终点作为图的节点,然后连接所有彼此“可见”(连线不穿越障碍物)的节点,形成一张图。路径规划就变成了在这张图上寻找最短路径。
核心原理与实现:算法首先需要计算所有顶点之间的可见性。这是一个计算几何问题,可以通过射线投射等方法判断连线是否与任何障碍物边相交。构建好可视性图后,就可以运用图搜索算法(如Dijkstra)来寻找最短路径。
优缺点与适用场景:
- 优点:路径长度是精确的几何最短路径(在给定的顶点集合下),路径非常平滑,由直线段组成,非常适合轮式机器人。
- 缺点:构建可视性图的计算复杂度较高,为O(n³)(n为顶点数)。当障碍物形状复杂、顶点众多时,图会变得非常庞大。此外,路径必须经过顶点,这可能导致路径不是全局最优(可能存在不经过顶点的更短路径)。
- 适用场景:适用于障碍物数量不多、形状规则(多为凸多边形)的静态结构化环境,比如室内房间、仓库货架间。
2.3 拓扑法:抓住环境的“骨架”
拓扑法不关心环境的精确几何形状,而是关注其连通性。它像抽象出一张地铁线路图,只关心有哪些“站点”(关键位置点,如门、走廊交点)以及它们之间如何连接,而不关心站间轨道的具体弯曲程度。
核心原理与实现:通常通过“骨架化”或“路线图”方法来实现。例如,对栅格地图进行细化,提取出环境的中心线(骨架),骨架的交点和端点成为节点。或者,在自由空间中随机采样点,并连接彼此邻近且连线不碰撞的点,形成一张随机路线图(PRM)。
优缺点与适用场景:
- 优点:表示非常紧凑,特别适合大规模环境。规划速度快,因为搜索空间(图的规模)远小于几何空间。高层任务规划(如“去厨房拿杯水”)常基于拓扑地图。
- 缺点:丢失了精确的几何信息,因此基于拓扑图规划出的路径通常只是一个“序列”,需要底层控制器结合局部地图进行跟踪。无法直接用于需要精确避障或考虑动力学约束的场景。
- 适用场景:大规模室内外导航(如商场、校园)、多层级的路径规划系统(顶层用拓扑图做粗规划,底层用几何地图做细规划和避障)。
2.4 选择与融合:没有银弹
在实际项目中,我很少只使用单一的环境模型。更常见的做法是分层或融合。例如,在自动驾驶中,顶层路径规划可能使用车道级的拓扑图(高精地图),决定走哪条车道;中层轨迹规划则使用连续的几何空间,考虑车辆动力学,生成平滑的轨迹;底层控制再处理实时障碍物(用栅格或点云表示)。理解每种模型的本质,才能灵活地将它们组合起来,应对复杂的现实问题。
3. 全局规划算法:纵观全局的“战略家”
全局规划器掌握环境的完整先验信息(一张已知的地图),它的任务是找出从起点到终点的最优或次优路径。这类算法是路径规划的基石。
3.1 Dijkstra算法:稳扎稳打的“老将”
Dijkstra算法是图搜索中最经典的算法之一。它解决的是在带权重的图中,找到从单一源点到所有其他节点的最短路径问题。
算法流程拆解:
- 初始化:创建一个集合
S,用于存放已找到最短路径的节点。为所有节点分配一个“最短距离估计值”:起点设为0,其他节点设为无穷大。所有节点的前驱节点设为空。 - 循环:当
S未包含所有节点时,执行: a. 从不在S中的节点里,选出当前“最短距离估计值”最小的节点u。 b. 将节点u加入S。 c. 松弛操作:对于u的每一个邻居节点v,检查如果通过u到达v的距离(即u的距离 + 边(u,v)的权重)小于v当前的距离估计值,则更新v的距离估计值为这个更小的值,并记录u为v的前驱节点。 - 结束:当终点被加入
S时,算法可以提前终止。通过回溯前驱节点,即可得到从起点到终点的最短路径。
为什么它有效?Dijkstra算法采用了贪心策略:每次都选择当前已知的、距离起点最近的未处理节点。可以证明,当一个节点被加入S时,它到起点的距离就已经是最短距离,不会再被更新。这是因为所有边的权重都必须为非负值。
实战中的注意事项:
- 复杂度:使用优先队列(最小堆)优化后,时间复杂度为O((V+E)logV),其中V是节点数,E是边数。对于栅格地图这样每个节点只有4或8个邻居的图,效率尚可。但对于节点非常多的图,它会比较慢,因为它“一视同仁”地向所有方向探索。
- 权重设计:算法的威力很大程度上取决于边的权重设计。权重可以是距离、时间、能耗,甚至是风险系数。例如,在越野路径规划中,平坦草地权重为1,泥泞地权重为5,陡坡权重为10,算法会自动找出综合代价最低的路径。
- 提前终止:实际应用中,我们通常只关心到特定终点的路径。因此,一旦终点被从优先队列中弹出(即其最短路径已确定),算法就可以立即停止,无需计算所有节点的最短路径。
3.2 A*算法:有“方向感”的智慧搜索
A*算法是对Dijkstra算法的革命性改进,它通过引入一个启发式函数,让搜索变得有方向性,从而极大地提高了效率。它是游戏AI和机器人学中应用最广泛的路径规划算法。
核心思想:A*为每个节点n维护一个代价函数:f(n) = g(n) + h(n)。
g(n):从起点到节点n的实际代价(与Dijkstra中的距离相同)。h(n):从节点n到终点的估计代价,这就是启发式函数。
算法总是优先扩展f(n)值最小的节点。g(n)保证了路径的最优性(不走冤枉路),h(n)则引导搜索朝向终点的方向,避免了像Dijkstra那样盲目地向四周扩散。
启发式函数h(n)的设计艺术: 启发式函数是A*的灵魂,它必须满足两个条件:
- 可采纳性:
h(n)必须永远不大于从n到终点的实际最小代价。这保证了A*找到的路径是最优的。 - 一致性(单调性):对于任意节点n和其后继节点n’,有
h(n) <= cost(n, n') + h(n')。这保证了算法的高效性。
常用启发式函数:
- 曼哈顿距离:适用于只能朝上下左右四个方向移动的栅格(四连通)。
h(n) = |x_n - x_goal| + |y_n - y_goal|。 - 欧几里得距离:适用于可以朝任意方向移动的栅格(八连通)或连续空间。
h(n) = sqrt((x_n - x_goal)² + (y_n - y_goal)²)。这是最常用的启发函数。 - 对角线距离:用于八连通栅格的更精确估计。
为什么A*比Dijkstra快得多?我们可以看一个极端例子:在一个空旷的栅格地图中,从左上角寻路到右下角。Dijkstra会像一个不断扩大的圆盘一样均匀探索,而A*由于有h(n)的引导,其探索区域更像一个指向终点的椭圆,访问的节点数少得多。
代码实现中的关键技巧:
# 伪代码结构示意 open_set = PriorityQueue() # 优先队列,按f值排序 open_set.put(start, f(start)) came_from = {} # 记录路径 g_score = {node: inf for node in all_nodes} g_score[start] = 0 f_score = {node: inf for node in all_nodes} f_score[start] = h(start) while not open_set.empty(): current = open_set.get() if current == goal: return reconstruct_path(came_from, current) for neighbor in get_neighbors(current): tentative_g_score = g_score[current] + cost(current, neighbor) if tentative_g_score < g_score[neighbor]: # 找到一条到neighbor的更优路径 came_from[neighbor] = current g_score[neighbor] = tentative_g_score f_score[neighbor] = g_score[neighbor] + h(neighbor) if neighbor not in open_set: open_set.put(neighbor, f_score[neighbor])避坑指南与性能调优:
- 启发函数的选择至关重要:
h(n)越接近真实代价,A的效率越高。如果h(n) = 0,A就退化成了Dijkstra;如果h(n)恰好等于真实代价,A*将沿着最优路径直线前进,效率最高。但h(n)绝不能大于真实代价,否则会破坏最优性。 - 处理平局情况:当多个节点
f值相同时,优先队列的弹出顺序会影响搜索效率。一个常见的技巧是优先处理h值更小的节点,这能进一步引导搜索。 - 内存与速度的权衡:A需要维护
open_set和closed_set(或通过g_score判断)。对于超大规模地图,内存可能成为瓶颈。此时可以考虑迭代加深A(IDA*) 等变种,它们用时间换空间。 - 非网格环境的应用:A*同样可以应用于可视性图或拓扑图,只需定义好节点、邻居关系和代价函数即可。
3.3 D与DLite:应对变化的“动态规划师”
现实世界是动态的。当机器人沿着A规划好的路径行进时,地图上可能突然出现未知障碍物(比如一把突然挪到路上的椅子)。重新从当前位置调用A进行全局规划固然可以,但效率低下,因为它丢弃了之前所有的计算成果。D*(Dynamic A*)及其优化版本D* Lite算法就是为了解决这个问题而生。
核心思想——反向搜索与代价传播: 与A从起点正向搜索到终点不同,D系列算法采用反向搜索。它最初假设环境是已知的,从目标点开始向起点搜索,计算出每个节点到目标点的最优代价。当机器人在行进中探测到某条边的代价发生变化时(例如,发现新的障碍物),D*不会重新规划整条路径,而是局部地、高效地更新受影响的节点代价,并重新计算出一条新的最优路径。这个过程就像在水面投下一颗石子,涟漪(代价更新)只传播到必要的范围。
DLite的简化理解*: D* Lite算法比原始D*更简洁高效,是目前动态环境重规划的实际标准。它维护两个估计值:
g(s):与A*类似,表示从起点到s的代价估计。rhs(s):一个基于节点s的邻居的、更易维护的g(s)估计值。如果g(s) == rhs(s),则称节点s是“一致的”。
当发现某条边(u, v)的代价增加时(例如,v变成障碍物),算法会更新v的rhs值(因为从u到v的路径不再可行),然后将v及其受影响的前驱节点加入一个优先队列。算法不断从队列中取出最关键的节点进行处理,通过局部传播更新,使受影响的节点恢复“一致”状态,从而快速得到新的路径。
适用场景: D* Lite非常适合在部分未知或动态变化的环境中进行的在线重规划,例如机器人探索未知区域、自动驾驶车辆在动态交通流中行驶。它的计算开销远小于每次变化都重新运行A*。
4. 局部规划与反应式算法:应对未知的“战术家”
全局规划依赖于一张先验地图。但在真实世界中,地图往往不完整,并且充满了动态、未预料到的障碍物(如行人、其他移动车辆)。局部规划器(或反应式控制器)的作用,就是基于机器人实时传感器(激光雷达、摄像头、超声波)的数据,在全局路径的指导下,进行实时避障和微调。
4.1 动态窗口法:兼顾动力学与安全的实时避障
动态窗口法是一种非常经典且实用的局部规划方法,它直接考虑了机器人的运动学(速度、加速度限制)和动力学约束,在速度空间中进行搜索,直接生成安全的控制指令(线速度和角速度)。
算法原理三步走:
- 采样速度空间:在机器人当前可达的线速度
v和角速度ω范围内,按照一定分辨率进行离散采样,形成一系列(v, ω)对。这个范围由机器人的最大加减速度决定,构成了一个“动态窗口”。 - 轨迹模拟与评价:对每一个速度对
(v, ω),假设机器人以此速度匀速运动一段短时间(如0.5-1秒),模拟出未来一段轨迹。然后,用一个评价函数给这条轨迹打分。评价函数通常包括:- 朝向目标程度:轨迹末端方向与目标点方向的偏差。
- 速度:倾向于选择更快的速度。
- 安全距离:轨迹上离最近障碍物的距离。这是最重要的安全项。
- 与全局路径的贴合度:轨迹末端与全局参考路径的距离。
- 选择最优指令:选择评价函数得分最高的
(v, ω)对,发送给机器人的底层电机控制器执行。然后,在下一个控制周期(通常是几十毫秒),重复整个过程。
为什么DWA如此有效?因为它将规划与控制紧密结合。它不是在几何空间找一条路径,而是在控制指令空间中直接寻找最优解。同时,由于模拟的轨迹很短,且基于当前传感器数据,它能很好地处理动态障碍物。评价函数的设计非常灵活,可以根据不同任务调整权重。
实操中的调参经验:
- 模拟时间:太短,机器人“目光短浅”,可能陷入局部最优(如面对U型障碍);太长,计算量大,且基于当前数据的预测会不准确。通常设置在0.5-2秒之间,与机器人的最大速度匹配。
- 评价函数权重:这是调参的核心。在拥挤环境中,应大幅提高“安全距离”的权重;在开阔地带追求速度时,则提高“速度”权重。需要大量实地测试来找到平衡点。
- 振荡问题:机器人在狭窄通道或对称障碍前可能左右摇摆。可以通过在评价函数中加入“平滑性”惩罚(与前一个周期的速度变化量)来缓解。
4.2 人工势场法:被“力”驱动的直观方法
人工势场法的思想非常直观:将目标点视为吸引机器人的“引力场”,将障碍物视为排斥机器人的“斥力场”。机器人处在一个虚拟的合力场中,像一个小球一样沿着合力的方向(负梯度方向)运动。
数学模型:
- 引力场:
U_att(q) = 0.5 * k_att * ρ^2(q, q_goal), 其中k_att是引力增益,ρ是机器人当前位置q到目标点q_goal的距离。引力F_att = -∇U_att = -k_att * (q - q_goal)。 - 斥力场:
U_rep(q) = 0.5 * k_rep * (1/ρ(q, q_obs) - 1/ρ0)^2, 如果ρ(q, q_obs) <= ρ0,否则为0。其中ρ0是障碍物的影响半径,k_rep是斥力增益。斥力F_rep = -∇U_rep。 - 合力:
F_total = F_att + Σ F_rep。机器人沿着F_total的方向移动。
优点与致命缺陷:
- 优点:概念简单,计算量小,反应速度快,易于实现。
- 缺陷——局部极小值问题:这是势场法的阿喀琉斯之踵。当引力和斥力在某一点达到平衡时,合力为零,机器人会停滞不前。例如,在对称的走廊里,目标在正前方,左右墙的斥力相等,引力向前,可能导致机器人在走廊入口就停止。或者,当目标点在一个障碍物后面时,机器人可能永远无法到达。
解决方案与变种:
- 随机扰动:当检测到机器人速度接近零时,给它一个随机的小推力,帮助它逃出局部极小点。
- 导航函数:一种经过特殊设计的势场,能保证只有一个全局极小值(在目标点),但构造复杂。
- 与其他方法结合:通常不单独使用势场法作为规划器,而是作为局部避障的辅助手段,或者与全局规划器结合,由全局规划器提供一条粗略路径,势场法负责局部跟踪和避障。
4.3 向量场直方图与障碍物膨胀
VFH及其变种(VFH+, VFH*)是另一种高效的反应式方法,特别适用于基于激光雷达的机器人。
核心思想:VFH将机器人周围的障碍物信息(来自激光雷达的扫描数据)转换到极坐标直方图中。直方图的每个扇区代表一个角度,其值代表该方向上的障碍物密度。然后,算法在直方图中寻找一个足够宽的、障碍物密度低的“山谷”,这个山谷的方向就是机器人应该前进的方向。同时,它会考虑当前机器人的运动方向,以保持运动的平滑性。
与DWA的对比:
- DWA在速度空间搜索,直接输出控制指令,天然考虑动力学。
- VFH在角度空间搜索,输出的是一个期望的行驶方向,需要再配合一个速度控制器。VFH计算通常更快,但在处理复杂动力学约束方面不如DWA直接。
障碍物膨胀的再强调:无论是DWA还是VFH,在计算到障碍物的距离时,必须使用膨胀后的障碍物。传感器检测到的是障碍物的边缘,但规划时需要的是机器人的轮廓与障碍物边缘的距离。这一步的疏忽是导致实物测试碰撞的最常见原因之一。通常的做法是在传感器数据层或代价地图层,直接对障碍物进行膨胀处理。
5. 采样规划算法:解决高维与复杂约束的“探险家”
当规划空间维度很高(如机械臂有6个以上关节),或者路径需要满足复杂的微分约束(如车辆不能横向移动)时,基于图搜索的方法(如A*)会面临“维度灾难”——搜索空间太大。采样规划算法通过随机采样的方式来探索空间,不求最优解,但求快速找到一条可行解。
5.1 快速探索随机树:从起点生长一棵树
RRT的基本思想非常直观:从起点开始,随机地向空间中的点生长一棵树,直到树的某个分支触及终点附近。
基本RRT算法步骤:
- 初始化树
T,仅包含起点q_start。 - 循环直到满足终止条件(如达到最大迭代次数,或找到路径): a.随机采样:在自由空间中随机生成一个点
q_rand。 b.最近邻查找:在树T中找到距离q_rand最近的节点q_near。 c.扩展:从q_near朝着q_rand的方向,以固定步长ε生长一段,得到一个新点q_new。检查q_near到q_new的连线是否与障碍物碰撞。 d.添加节点:如果无碰撞,则将q_new加入树T,并将q_near设为q_new的父节点。 - 当
q_new进入终点区域时,算法成功。通过从终点回溯到起点,即可得到路径。
为什么RRT有效?它的随机采样特性使其能快速探索高维空间。虽然单次扩展是随机的,但整体上,树会以概率1的方式逐渐充满整个自由空间。
RRT的局限性:
- 不是最优的:找到的路径通常曲折、不光滑。
- 效率不稳定:由于随机性,规划时间方差较大。
- 对狭窄通道不友好:在狭窄通道口,随机采样点很难恰好落在通道内,导致树难以通过。
5.2 RRT*:渐进最优的改进
RRT*在RRT的基础上增加了两个关键步骤,使其能找到渐进最优(随着采样点增加,路径代价无限接近最优)的路径。
两大核心改进:
- 重新选择父节点:在成功添加
q_new后,RRT*不会简单地将其父节点定为q_near。它会在q_new附近的一个邻域内(例如半径为r的球内)寻找树T中所有的节点,检查如果以这些节点中的某一个作为q_new的父节点,是否能得到一条从起点到q_new代价更低的路径。如果是,就重新连接(重选父节点)。 - 重布线:在重新选择父节点后,RRT*还会考虑
q_new是否能成为其邻域内其他节点的更好父节点。即,对于邻域内的每个节点q_nearby,检查如果让q_nearby以q_new为父节点,是否能降低从起点到q_nearby的代价。如果是,就断开q_nearby与原父节点的连接,重新连接到q_new上。
效果:这两个操作使得树的结构不断被优化,路径代价随着迭代次数增加而不断降低。最终得到的路径比基本RRT平滑、高效得多。
5.3 应用于车辆路径规划:满足微分约束
标准的RRT/RRT在几何空间中工作,生成的路径可能无法被车辆执行(例如,要求车辆瞬间侧向移动)。为了解决这个问题,产生了运动学RRT等变种。
关键修改:
- 状态空间:节点的状态不再是
(x, y),而是(x, y, θ, v, ...),包含了位置、朝向、速度等。 - 距离度量:最近邻查找不能再用简单的欧氏距离,而需要使用能反映状态差异的度量,例如结合位置差和角度差。
- 扩展(Steering):这是最核心的改动。不能简单地从
q_near向q_rand画一条直线。需要调用一个局部规划器或控制系统模拟器。例如,给定当前状态q_near(位置、朝向、速度)和一个控制输入(加速度, 前轮转角),通过积分车辆运动学模型(如自行车模型)一段时间,得到一条可行的轨迹片段,其末端状态就是q_new。这个q_new是动力学可行的。 - 代价函数:路径的代价不再是几何长度,可能是时间、能耗或舒适度(与加速度、曲率相关)。
通过这样的改造,RRT*就能在满足车辆非完整约束(不能侧移)和动力学约束的情况下,规划出可行的轨迹。这在自动驾驶的复杂场景规划中非常有用。
6. 算法选型与工程实践指南
面对琳琅满目的算法,如何选择?我总结了一个简单的决策流程和实战心得。
选型决策树:
- 环境是否完全已知、静态?
- 是-> 使用全局规划器。
- 需要最优路径吗?是 ->A*(如果图规模不大)。需要处理任意代价函数?是 ->Dijkstra。环境是规则多边形?考虑可视图法。
- 否(有未知或动态部分)-> 需要全局+局部结合。
- 是-> 使用全局规划器。
- 规划空间维度高或有复杂运动约束吗?(如机械臂、车辆)
- 是-> 优先考虑采样规划器(RRT*)。
- 否(如地面移动机器人栅格导航)-> 继续。
- 对实时性要求极高,且环境动态性强吗?
- 是->局部规划器作为主控制器(如DWA),并可能需要一个轻量级的全局规划器(如D* Lite)提供粗略指导。
- 否-> 可以使用A*进行周期性重规划。
工程实践中的关键点:
- 分层规划架构是主流:几乎没有单一算法能解决所有问题。一个典型的机器人导航栈(如ROS中的Navigation Stack)就采用了分层架构:全局规划层(A*)生成一条粗略路径;局部规划层(DWA/TEB)负责跟踪全局路径并实时避障;底层控制器执行速度指令。感知模块不断更新代价地图,D* Lite的思想可以融入全局规划器的重规划模块中。
- 代价地图的艺术:规划算法依赖于代价地图。如何将传感器数据(激光、视觉、深度)融合成一张稳定、准确的代价地图,本身就是一个大课题。常见做法是多层代价地图:静态层(先验地图)、障碍层(实时传感器)、膨胀层。每个层有不同的衰减模型和更新策略。
- 平滑与优化:无论是A*在栅格上找出的“锯齿”路径,还是RRT生成的“随机”路径,通常都不够平滑,不适合机器人直接跟踪。后处理步骤必不可少,例如:
- 简单平滑:使用梯度下降法或二次规划,在保持避障的前提下,最小化路径的曲率和长度。
- 轨迹优化:对于有时间要求的,可以使用时间弹性带(TEB)等方法,将路径点与时间关联,同时优化路径形状和速度剖面,使其动力学可行。
- 仿真与实物的鸿沟:在仿真中完美的算法,在实物上可能失败。原因包括:传感器噪声、执行器误差、延迟、地面打滑、机器人模型不精确等。必须进行充分的实物测试,并在算法中增加鲁棒性设计,如增加安全裕度、加入状态估计滤波器(如卡尔曼滤波)、设计恢复行为(如被困时原地旋转重新建图)。
路径规划是一个理论与实践紧密结合的领域。理解算法的核心思想是基础,但真正的能力体现在能够根据具体机器人平台、传感器特性、任务需求和环境特点,将这些算法进行裁剪、组合和调优。没有一劳永逸的解决方案,只有不断迭代和适配的过程。希望这篇总结能为你提供一个清晰的路线图,当你在实践中遇到具体问题时,知道该从哪个工具箱里拿起哪件工具,并明白如何使用和打磨它。