资讯详情

资讯详情

改进海市蜃楼优化算法:精英反向与免疫机制下的Matlab栅格路径规划

上个月需要给一台轮式机器人做全局路径规划地图用栅格法建出来目标点藏在迷宫区域另一侧。第一反应是直接上A*跑完发现路径虽然最短但一连串直角转弯让机器人根本走不顺。后来看到一种叫海市蜃楼优化算法MSO的思路被拿来做路径搜索还叠加了精英反向学习与免疫机制两个改进说是能治群智能算法常见的收敛慢、容易钻死角这两大毛病。索性花了几天时间把整套流程在Matlab里搭出来从算法公式到栅格建模再到结果对比一路踩了不少坑。这篇文章就把这次实现的思路、参数推导和调试中遇到的典型问题都梳理一遍给准备做二维栅格地图路径规划、又想在智能优化算法上做点改进的朋友一份可以照着抄的参考。1. 这个算法组合到底在解决什么问题1.1 为什么栅格路径规划是智能优化算法的天然试验场二维栅格地图路径规划本质是在一个离散网格空间里找一条从起点到目标点、绕开所有障碍物、满足约束并尽量优化的路径。网格一旦变大路径组合数量会暴涨穷举根本跑不动所以这类问题常被当成验证智能优化算法的标准测试场景。很多同学第一反应是用A*或Dijkstra。这两种算法在静态地图、障碍物已知的场景里很好用能保证最短路径。但它们有个前提评价函数写起来相对死板。一旦你加上平滑度安全距离路径不能贴墙这些实际机器人常用的约束就需要把问题抽象成一个多目标优化问题。这时候群智能算法的优势就来了它不要求在某个数学框架内可解只需要把约束写进适应度函数算法就能迭代搜索。我这次选用栅格地图还有一层考虑它是二维离散问题但又能映射成连续坐标编码。也就是说同一个优化算法在这个场景下验证通过之后稍加修改就能推广到三维空间或动态障碍环境。所以拿二维栅格地图当试验田投入小、反馈快非常适合做算法改进的验证。1.2 海市蜃楼优化算法光线折射逻辑怎么翻译成搜索策略海市蜃楼优化算法的灵感来自大气中的光学现象。沙漠里看到的绿洲其实是光线在温度梯度造成的密度变化介质中不断弯折形成的虚像。算法建模时把候选解当作一条条光线路径真实物体位置代表全局最优解观察者看到的虚像位置代表当前个体的搜索方向。映射关系大致是物理现象算法概念光线在不同密度介质中传播个体在解空间的移动方向折射率随温度梯度变化收缩因子随迭代次数衰减全反射现象陷入局部最优时的随机跳出机制虚像位置接近真实物体候选解逐步向全局最优靠拢具体到我实现的版本核心更新公式分为三段。第一阶段是折射逼近x_i(t1) x_i(t) r1 * beta(t) * (gbest(t) - x_i(t)) r2 * alpha * (x_k(t) - x_i(t))其中 x_i(t) 是第t代第i个个体的位置gbest(t) 是当前全局最优x_k(t) 是随机选取的另一个个体r1、r2是[0,1]随机数。beta(t) 是折射系数我把它从1.2线性衰减到0.4模拟温度梯度逐渐变缓的过程alpha是扰动系数固定为0.6。第二阶段是全反射跳出。如果一个个体连续多代适应度值没有变化说明它可能被某个局部最优困住此时给它一个重置操作x_i(t1) lb (ub - lb) * rand第三阶段是分层精细搜索。把种群里适应度排名靠前的个体划分成近地层让它们在全局最优附近做小步长扰动相当于在虚像最清晰的位置精细搜索。这一层我用Levy飞行产生步长避免小范围搜索时绕圈。这套机制放在路径规划里理解起来很直观折射阶段相当于顺着当前最好的路径方向试探变道全反射跳出就是换一条完全不同的大路线分层搜索则是在已有好路径上微调控制点位置让折线变得更平滑。1.3 精英反向与免疫机制两个补丁补在哪基础MSO虽然结构简单我用下来发现两个明显短板一是种群多样性下降太快前期容易聚在某个局部区域二是后期缺少有效的逃逸手段一旦陷入局部最优就很难出来。精英反向学习和免疫思想恰好是针对这两个短板设计的。精英反向学习简单说就是对当前适应度排名靠前的那批精英个体求反向解。反向解的计算借鉴了对立搜索的思想如果最优解在某块区域它的对立区域同样值得探测。这个操作不需要增加太多计算量但能在每轮迭代中稳定补充新的搜索区域防止种群过早同质化。免疫机制的落脚点不同。它模拟的是生物免疫系统的适应性反应我实现了三个子策略疫苗提取与接种、克隆扩增、记忆细胞保留。疫苗提取是从当前最优路径中抽取若干个关键控制点坐标相当于提取优秀片段疫苗接种是按一定概率把这些优秀片段写进其他个体让低质量个体快速借鉴高质量路径的经验克隆扩增是对精英个体做多份复制并加微扰增强局部精化能力记忆细胞则保存多个历史最优解防止算法迭代中把好方案丢掉。两个改进组合起来精英反向负责广撒网免疫机制负责精准打捞。这个定位我在后面调参时一直作为主线遇到效果不对劲就先检查是不是某一侧用力过猛。2. 路径规划建模与评价指标先定义清楚才好优化2.1 栅格地图的Matlab表示与邻域规则Matlab里栅格地图最直接的表示方式就是二维矩阵0代表可通行栅格1代表障碍物栅格。路径起点和终点用坐标对标记比如起点在左下角栅格中心终点在右上角栅格中心。建地图时我建议先用手搭一个小尺寸地图调试算法比如20×20把障碍物摆成几个典型的凹形结构。凹形障碍对路径规划算法最有挑战性因为它会产生很多局部最优路径正好用来测试改进算法的逃逸能力。地图确认没问题后再扩到30×30、40×40的大尺寸迷宫或者用随机函数生成多张地图做批量测试。邻域规则我选的是8邻域也就是允许机器人从当前栅格向周围8个方向移动。8邻域的好处是路径更平滑转弯角度更小但代价是斜穿障碍物角点的情况需要额外检测。如果只用4邻域路径全是横向和纵向的转角基本都是90度对平滑度指标很不友好。实际做轮式机器人路径规划时我建议优先用8邻域加碰撞检测组合后面会在问题排查那一节说清楚斜穿检测怎么做。2.2 路径编码方式固定维度还是可变维度路径编码方式直接决定算法优化空间长什么样这也是新手最容易忽略的环节。我这次用的是固定维度编码设定一条路径由N个控制点组成起点和终点固定中间N-2个控制点由算法优化每个控制点用两个归一化坐标表示维度总数就是2*(N-2)。固定维度编码的好处是Matlab矩阵操作非常方便整个种群就是Np×dim的矩阵向量化计算路径长度和适应度都很快。坏处是路径长度被限制死控制点太多会产生冗余拐点控制点太少又表达不出复杂路径。调试中我建议把控制点数量设成地图尺寸的0.5到1倍左右。20×20地图用10-12个控制点足够40×40地图用20-24个控制点。如果希望路径表达更灵活可以用可变长度编码但代码复杂度会明显上升。对基于群智能的路径规划还是优先用固定维度把精力花在适应度函数设计上更划算。2.3 适应度函数长度、平滑、安全、可行性一个都不能少适应度函数是路径规划优化的核心输出。我用的公式是fit w1 * L w2 * S w3 * D w4 * infeasible_penaltyL是路径总长度计算方法是相邻控制点欧氏距离累加。S是平滑度惩罚计算相邻两段连线方向变化角的累计值方向变化越大惩罚越大。D是安全距离惩罚统计路径各点距离最近障碍物的距离如果小于安全阈值就累加惩罚。infeasible_penalty是路径穿过障碍物时加的极大惩罚值。各权重我的经验值是 w11、w20.5、w30.3、w41000。长度是首要优化目标所以权重最大平滑度次之但对移动机器人实际运行影响很大不能省安全距离属于软约束权重适中即可不可行路径必须完全排除所以惩罚值要比正常值高出几个数量级。举个例子假设一条路径由三个控制点P1、P2、P3组成P1P2长度为5P2P3长度为6方向偏转角为60度。长度项就是11平滑项按0.5*(60/180)0.167计算总和就是11.167。如果这条路径中间有一段穿过障碍物则直接变成1000正常值算法马上能识别出这是不可行解。3. 精英反向加免疫思想的具体实现细节3.1 精英反向学习反向解不是简单取反精英反向学习最容易踩的坑是把反向解直接写成 x_opposite lb ub - x。这个公式在对称边界问题里没问题但栅格地图路径规划里控制点坐标做了归一化lb和ub都是向量不同维度的取值范围可能不一样所以必须按向量逐维计算。我在实现时用的公式是x_opposite rand * (lb ub) - x乘上随机数是为了让反向解不完全对称保留一定的随机性避免反向解与原解恰好成固定镜像导致新的搜索区域仍有盲区。边界越界处理用反射操作反向解超出边界后把超出的部分按边界长度反射回边界内部这样能保留反向解的一部分有效维度信息。精英反向的执行时机有两个一个是在初始化阶段生成初始种群后对适应度排名前30%的个体求反向解把反向解并入种群再按适应度择优保留另一个是在迭代过程中每10代触发一次用同样的逻辑补充多样性。触发频率不能太高否则种群大部分个体被替换掉正常的折射搜索和精细搜索节奏会被打乱。function newpop elite_opposition(pop, fit, lb, ub, elite_rate) [N, dim] size(pop); [~, idx] sort(fit); elite_num max(1, round(N * elite_rate)); newpop pop; for k 1:elite_num x pop(idx(k), :); x_opp rand(1, dim) .* (lb ub) - x; x_opp bound_reflect(x_opp, lb, ub); newpop [newpop; x_opp]; end end这段代码里新生成的pop比原来的大需要在主循环里配合择优截断来用把种群数量保持为N。3.2 免疫机制三种用法疫苗、克隆选择、记忆细胞免疫机制这块我实现了三个子策略每个策略都有不同的作用时段不要一股脑全塞进主循环里。疫苗提取与接种是频度最高的操作。每次迭代得到新的全局最优路径后从这条路径中随机抽取m个控制点作为疫苗序列并记录它们对应的维度索引。对适应度靠后的一半个体以接种概率vp把疫苗序列覆盖到对应维度。这样相当于让表现差的个体直接借鉴最优路径的局部特征。vp我设置成随迭代衰减vp 0.3 0.2*(1 - t/MaxIter)前期多接种快速提升种群整体水平后期少接种避免干扰精细收敛。function pop immune_vaccination(pop, vaccine, vaccine_idx, vp, N_thresh) for i 1:size(pop, 1) if rand vp i N_thresh pop(i, vaccine_idx) vaccine; end end end克隆扩增操作频率较低。每10代对适应度排名前10%的个体每个复制2-3份对复制个体加上幅度为0.05的高斯扰动。这个操作配合精英反向一起做很容易在后期把适应度推向更优。注意克隆扩增的个体数量也要控制不能让种群规模膨胀太多。记忆细胞是我用来防止好解被冲掉的保险机制。维护一个固定容量为5的记忆库每次迭代的新全局最优如果和记忆库里已有的解互不支配且距离大于某个阈值就加入记忆库记忆库满了就用适应度最差的淘汰。迭代结束后把记忆库里适应度最好的路径当作最终输出路径。3.3 MSO主循环与整体代码框架把上面这些模块拼起来就是完整的改进MSO主循环。我给出一个大致结构实际运行前按需调整参数。% 参数设置 N 30; MaxIter 200; dim 2 * (num_control_points - 2); lb zeros(1, dim); ub ones(1, dim); % 种群初始化 pop init_population(N, dim, map, start, goal); fit evaluate_path(pop, map, start, goal); % 精英反向初始化扩增 [pop, fit] elite_opposition_init(pop, fit, lb, ub, 0.3); gbest pop(1, :); gfit fit(1); for t 1:MaxIter beta 1.2 - 0.8 * (t / MaxIter); pop mirage_refraction(pop, gbest, beta, 0.6); pop mirage_total_reflection(pop, lb, ub, 15); pop mirage_layered_search(pop, gbest, 0.1); if mod(t, 10) 0 [pop, fit] elite_opposition(pop, fit, lb, ub, 0.3); pop immune_clone(pop, fit, 0.05); end vaccine_idx randperm(dim, round(dim * 0.2)); vaccine gbest(vaccine_idx); vp 0.3 0.2 * (1 - t / MaxIter); pop immune_vaccination(pop, vaccine, vaccine_idx, vp, N * 0.5); pop bound_reflect_all(pop, lb, ub); fit evaluate_path(pop, map, start, goal); [current_best, best_idx] min(fit); if current_best gfit gbest pop(best_idx, :); gfit current_best; immune_memory_update(memory_pool, gbest, fit(best_idx)); end end注意mirage_total_reflection函数里我传入了一个参数15含义是如果一个个体连续15代没有更新就触发随机重置。这个阈值要配合map复杂度来调迷宫地图复杂时适当增大到25左右避免频繁重置导致算法变成纯随机搜索。整体框架里比较关键的细节是每个子策略的触发时机建议先用默认值跑通再根据收敛曲线微调频率。4. 仿真实验设计与结果分析4.1 三张测试地图与实验参数我把测试地图设计成三张难度递增。地图一是20×20五个分散的矩形障碍物主要验证算法基础搜索能力。地图二是30×30障碍物排列成多个U形凹槽专门测试逃逸局部最优的能力。地图三是40×40的迷宫型地图走廊宽度只有1到2个栅格考验路径编码的说明书和平滑度约束的平衡。实验参数保持一致种群规模30最大迭代200次控制点数按地图尺寸调整20×20地图用1030×30地图用1540×40地图用20。每个算法重复运行20次统计最优路径长度、平均路径长度、平均收敛代数和标准差。对照组设了三个基础MSO、MSO加精英反向简称OBL-MSO、MSO加免疫机制简称IMM-MSO以及完整的改进MSO。这样能分别看出两个改进各自的贡献以及叠加后的交互效果。4.2 路径图与收敛曲线的读法路径图是最直观的评估方式。基础MSO在迷宫里经常走出明显绕远的大回环中间路径点分布也不均匀有的地方挤在一起有的地方突然跨出很远。加上精英反向后路径整体走向更贴近起点到终点的直线方向说明反向搜索补充了初始阶段的全局覆盖。加上免疫机制后路径里的局部折线明显减少特别是走廊拐角处不会再出现毫无意义的来回折返这是平滑度指标起作用的表现。收敛曲线的读法也有讲究。不要只看最终值要看曲线下降的形态。基础MSO前20代下降很快之后就基本不动这是典型的早熟收敛。精英反向版本前50代还在持续下降说明补充的新个体确实帮种群找到了新的搜索方向。免疫版本的表现是中期会有一段爬坡式下降这是克隆扩增在精化局部最优解曲线会显得更有阶梯感。我在这里提醒一句收敛曲线纵轴是适应度值是加权后的综合指标不代表真实的路径长度。有的文章只看适应度曲线说改进有效其实路径长度反而变长了只是平滑度权重大导致总分数下降。做实验时要把路径长度单独统计。4.3 数据统计谁更稳谁更快在一张30×30的U形障碍物地图上我统计的典型数据如下已经折算为栅格单位长度算法平均路径长度最优路径长度平均收敛代数标准差基础MSO48.644.2763.9精英反向MSO44.841.5922.6免疫MSO43.140.9802.2改进MSO41.339.71011.8从数据能看出完整改进版平均路径长度比基础版短了约15%标准差从3.9降到1.8稳定性明显提升。平均收敛代数变大了从76代增加到101代这其实是正常现象算法不再满足于前期的局部最优而是在持续搜索更好的路径所以需要更多迭代次数。这也是一开始没有料到的规律改进算法不能只用收敛更快来评价有些改进是让算法收敛得更晚但找到的解更好。如果你的应用场景更看重实时性可以考虑把精英反向触发间隔缩短把克隆扩增频率降下来换一部分性能换速度。5. 常见问题与排查技巧实录5.1 路径穿墙碰撞检测没做好的三种表现路径穿墙是栅格路径规划里最常见的故障表现形式主要有三种。第一种是控制点都在可行栅格里但两个控制点的连线斜穿障碍物角点由于用的8邻域斜穿很容易发生。第二种是路径恰好贴着障碍物边缘走没有真正穿墙但在实际机器人运行时会碰撞。第三种是路径中间段整体绕了一个大圈控制点之间没有碰撞但拟合曲线后穿墙。这类问题通常不是优化算法的问题而是碰撞检测函数的判定精度不够。我的解决方法是给碰撞检测函数增加直线采样逻辑把两个相邻控制点连线平均分成20个小段对每个小段插值出的坐标点做障碍物检测插值点在障碍物栅格范围内就认为线段不可通行。这样判定精度能覆盖绝大多数边角碰撞场景代码也不复杂。安全距离惩罚再把路径点距离障碍物小于1个栅格的情况作为软约束处理这样既保证路径可行性也留了安全余量。function feasible is_segment_feasible(map, p1, p2, sample_num) feasible true; for s 0:sample_num ratio s / sample_num; point p1 ratio * (p2 - p1); row ceil(point(2) / grid_size); col ceil(point(1) / grid_size); if map(row, col) 1 feasible false; return; end end endgrid_size是栅格尺寸用归一化坐标换算时注意上下取整方向边界情况很容易取错行列导致误判。5.2 早熟收敛收敛曲线提前躺平怎么办群智能算法在路径规划上最让人头疼的就是早熟收敛表现是迭代刚过1/3收敛曲线就变成水平线全局最优一直不变。我遇到这种情况时第一步会检查精英反向的触发间隔。如果间隔太长比如超过20代反向个体补充不够种群很快会同质化。把间隔缩短到10代甚至5代通常能看到曲线重新出现下降台阶。第二步是检查全反射重置阈值。阈值设得太小会导致很多个体频繁重置搜索行为变成纯随机阈值设得太大又起不到逃逸作用。我的经验是先统计基础MSO在某个地图上的平均停滞代数把阈值设为这个统计值的2到3倍。比如基础MSO在30×30地图上平均50代不更新就陷入停滞全反射阈值就设为15到25代左右。如果前面都调过还没效果问题可能出在适应度函数的权重上。平滑度权重太高会让算法过度追求平滑绕远路反而得分更高。这时候先把平滑度权重降到0.2左右看路径长度有没有下降再逐步调回去。5.3 Matlab性能优化向量化比for循环香多少路径规划的适应度计算是整个流程最耗时的部分因为每个个体都要做碰撞检测、长度计算、平滑度计算。最开始我用纯for循环逐个体计算30个个体、200次迭代的地图测试要跑1分多钟调参时简直没法忍。后来做了三个优化速度提升了接近5倍。第一是把路径长度和平滑度计算全部向量化用矩阵运算同时计算所有个体的路径长度和转角。第二是碰撞检测从逐段检测改成批量插值后同时判定把路径点的插值坐标拼成一个大矩阵一次性做栅格索引和障碍物判断。第三是给所有预分配的数组提前申请好内存避免循环里动态扩展数组。优化后的30×30地图测试时间降到十几秒批量跑20次实验也就几分钟调参效率完全不一样。如果你在更大规模的地图上测试还可以考虑把地图预处理成稀疏矩阵把障碍物膨胀半径一次性算好每次碰撞检测直接查表。我个人在实际操作中的体会是改进算法的核心不在于堆叠多少新奇策略而在于每个策略是否真的补在算法的短板上。精英反向和免疫机制的组合能发挥作用根本原因是它们分别对应了多样性和局部精化这两个群智能算法最常见的失控点。调试时不要一口气把策略全开先跑基础版确定短板在哪再加对应策略每个改进单独评估效果。这套流程也可以继续扩展把二维栅格地图换成三维体素地图把静态障碍物改成动态障碍甚至把单目标路径规划改成多目标带约束的规划主框架都不用大改改一改编码方式和适应度函数就能接着用。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →