资讯动态

无人机三维动态避障融合算法:CTCM全局优化与DWA局部避障的MATLAB实现

发布时间:2026/10/19 9:18:10 来源:尧图企业网站定制
无人机三维动态避障从来都不是把二维算法简单加一个Z坐标就能搞定的事。二维场景里只需要管XY平面的碰撞换到三维地形起伏、动态威胁、无人机爬升率与转弯半径同时约束着路径全局搜索的计算量会成倍上涨。这两年我在做这类路径规划仿真时用得比较顺手的搭配是“全局群智能优化 局部动态窗口法”其中全局优化部分我实现了一个命名为CTCM的部落竞争与成员合作算法再用DWA作为局部动态避障与轨迹平滑执行的核心两者融合形成一套完整的三维动态避障路径规划方案。这篇文章就顺着这个思路从问题拆解、算法机制、代价模型一步步讲下来重点用MATLAB把关键代码和调参经验都摆出来适合正在做无人机航迹规划、机器人动态避障相关仿真的朋友参考。1. 为什么需要一套融合算法三维动态避障的问题拆解1.1 全局规划与局部避障的天然矛盾路径规划大体上分成全局规划和局部规划。全局规划希望在地图已知的条件下找一条从起点到终点的最优路径追求的是整体代价最小局部避障则是利用传感器实测量在毫秒级时间内避开突然出现的动态障碍物追求的是“不撞上且能过得去”。这两者天然存在矛盾全局路径计算量大、周期长无法应对快速变化的环境局部规划响应快但视野窄如果没有全局信息引导很容易被动态威胁逼进死胡同或者在复杂地形里原地打转。无人机三维场景把这种矛盾进一步放大了。飞行器不仅有XY平面的位移还有高度变化状态空间从二维的(x, y)变成三维的(x, y, z)如果再考虑航向角、俯仰角、爬升率那实际上是在一个高维状态空间里规划。静态地形可以先离线建模但其他无人机、飞鸟、临时禁飞区这些动态威胁无法在起飞前全部预知。因此需要一种“全局上有方向、局部上能应变”的混合架构让算法分工配合而不是互相替代。1.2 DWA与CTCM各自的短板DWA也就是动态窗口法最早常用于移动机器人局部避障。核心思想是在当前状态附近对速度空间采样根据机器人运动学约束生成一组模拟轨迹再用评价函数挑出一条最合适的轨迹执行。它的优点是实时性强、轨迹平滑、容易考虑动力学约束。缺点是它只看得到局部需要不断给定局部目标点如果全局目标信息很差DWA会很明显地被局部障碍牵制住甚至出现来回振荡。而CTCM这种部落竞争与成员合作算法属于群智能优化的范畴。简单理解就是在一个种群内划分多个部落部落之间竞争资源部落内部成员合作搜索最终在解空间里逼近全局最优。群智能算法擅长在复杂高维空间里找到近似最优路径比如处理三维地形上的能耗、安全、平滑多目标折中问题。但它也有短板迭代寻优耗时几乎不可能做到每个控制周期都重新规划如果动态障碍物突然出现在当前路径上纯CTCM没法及时修正。所以我的做法是把CTCM用来做全局航点序列优化生成一条兼顾静态地形和已知动态威胁趋势的参考路径把DWA放在执行层沿线跟踪CTCM给出的航点同时在传感器探测范围内做实时避障。两个算法各干各擅长的部分再通过航点重规划机制衔接起来。对比项DWACTCM/群智能搜索范围局部速度窗口全局解空间实时性高适合在线执行低适合离线/周期重规划动力学约束天然嵌入需要通过代价函数间接施加对初始路径依赖强弱复杂地形表现易陷入局部极小全局收敛能力强典型用途动态避障执行全局航点寻优2. CTCM算法核心机制拆解部落竞争与成员合作如何协同2.1 部落结构不是简单分群很多群智能算法把整个种群看作一个整体比如粒子群算法中每个粒子独立向个体最优和全局最优学习。CTCM的不同点在于引入“部落”这一中间层组织。整个候选解种群被划分为若干部落每个部落相当于是解空间里的一片“领地”有自己的部落首领、普通成员和共享记忆池。部落结构有三个好处。第一不同部落可以分别专注于解空间的不同区域降低所有个体同时涌向一个局部极值的概率。第二部落之间通过竞争机制交换信息保持种群整体的多样性。第三部落内部成员可以在小范围内高频交流作精细搜索类似于一个团队在局部攻坚。这种“大范围分群协调 小范围精细搜索”的结构比单一种群更容易平衡探索和开发。在三维路径规划里每个个体本身代表一条候选路径。我通常用一条航点序列表示个体比如一条路径由N个三维航点组成每个航点是(x, y, z)那么这个个体就是一个3×N的矩阵。一个部落里有若干个这样的个体部落首领就是当前适应度最好的那个个体。2.2 竞争机制优胜劣汰与领地重组部落竞争可以类比为“多个部落争夺同一片资源”。每一代计算完成后根据部落内个体的平均代价或最优个体代价排出名次。代价越低的部落说明它当前所在的解空间区域越有前景。排名末尾的部落不能继续保留原封不动的种群而是要被拆分或重组。我在实现中采用两种重组手段第一种是“吞并”把最弱部落中适应度较差的个体淘汰用最优部落中的部分优秀个体替换进去。这样可以快速把优质解基因传播到弱势部落同时保留弱势部落中少量有差异的个体防止搜索方向太单一。第二种是“重置”如果某个部落连续多代没有明显进步就把这个部落的大部分个体重新随机初始化只保留其首领的历史信息。这相当于强制让一部分搜索力量跳出当前区域避免整个种群围绕某个局部极值空转。竞争参数的设置需要小心竞争强度太大种群会过早收敛到最强部落的区域竞争太弱部落之间缺乏信息流通搜索效率会下降。我一般把一次迭代中参与重组的部落比例控制在20%~30%之间具体数值会在后文参数表里给出。2.3 成员合作局部精细搜索的关键部落内部成员之间的合作是CTCM比传统竞争型算法更精细的地方。每个成员在更新时会综合考虑三个参考方向自己的历史最优位置、所在部落首领的位置、全局最优位置。更新公式类似于粒子群的运动方程new_pos w * old_pos c1 * rand * (self_best - old_pos) c2 * rand * (tribe_best - old_pos) c3 * rand * (global_best - old_pos)其中w是惯性权重c1、c2、c3是学习因子。用rand制造随机扰动让个体不会完全重复地飞向最优解。与标准粒子群的区别是由于存在部落首领这一中间层个体不会直接“看到”全局最优的频率过高从而减少过早收敛的风险。除了这种矢量更新我还会在成员合作里加入一个小邻域扰动操作。对每个成员更新完后以一定概率在当前航点序列上叠加一个小幅高斯扰动只扰动部分航点然后重新计算代价。这有点像遗传算法里的变异但幅度更小目的是在当前区域内再精细搜索把路径代价压得更低。在三维路径规划场景中这种局部精细搜索尤其有用。地形高度场往往是连续变化的最优路径可能只在某个山坳里穿过粗粒度搜索容易错过。小扰动能反复微调航点的高度和水平位置让路径贴着地形的安全走廊通过。2.4 与DWA融合的关键环节CTCM生成的是离散航点序列直接把航点连接起来可能不平滑而且无法应对动态障碍。DWA的加入主要解决两个问题一是让航点之间的轨迹符合无人机动力学约束二是在跟踪过程中实时检测并绕开动态威胁。我的融合方式分成两层。第一层是“航点驱动DWA”。CTCM输出的航点序列经过B样条平滑后形成一条参考路径。DWA在执行时并不需要把整条参考路径作为目标而是沿着参考路径设置一个“滚动前视窗”每次只跟踪窗口内距离无人机最近的一个虚拟目标点。虚拟目标点随飞行推进不断更新这样DWA既保持了局部避障能力又不会偏离CTCM规划的全局通道。第二层是“DWA反馈参与CTCM评估”。在CTCM迭代过程中对每一条候选航点序列我都会用DWA模拟一小段跟踪过程看看按这条航点走会不会与已知动态障碍物冲突以及跟踪过程中的总代价是否增加。这个反馈让CTCM在选择全局路径时就能避开动态障碍的可能轨迹而不只是在静态地图上找最短路径。之所以强调“融合DWA”是因为DWA不是简单挂在外面的避障模块而是深度参与了CTCM的适应度评估和航点重规划过程。这样设计之后全局算法和局部算法才真正耦合在一起而不是各跑各的。3. 三维动态避障路径规划整体流程与代价模型3.1 三维环境与障碍物建模做三维路径规划第一步是确定空间表示方式。我常用的是高程栅格地图把飞行区域划分成均匀网格每个网格存储一个地形高度值水平范围用X、Y坐标表示。静态障碍物比如山峰、建筑物、塔架抽象成圆柱体或球体包络。动态障碍物则用运动模型描述常见的是匀速直线运动或带有正弦波动的运动比如obs_pos(t) obs_init obs_vel * t A * sin(omega * t)这样每次迭代时都能算出任意时刻障碍物的位置便于碰撞检测。无人机模型也要提前定义。路径规划层我一般把无人机看成一个点和若干运动学约束最大水平速度、最大爬升/下降率、最小转弯半径、最大俯仰角。这些约束会直接影响DWA的速度窗口范围也会作为CTCM代价函数中的惩罚项。三维空间里很多人会忽略“安全高度”的问题。与二维不同无人机不能贴着障碍物表面飞因为存在气流扰动、控制误差和定位误差。我在建模时会给每个障碍物设置一个安全膨胀半径同时在代价函数中对低于安全高度的路径施加惩罚。3.2 代价函数与约束条件设计三维路径规划本质上是一个多目标优化问题。CTCM在迭代时需要一个标量代价函数来衡量路径好坏。我用的代价函数由四部分组成J w1 * J_len w2 * J_safe w3 * J_alt w4 * J_smoothJ_len是路径总长度用所有航点之间的欧氏距离累加得到。路径越短飞行时间越少这是最基本的优化目标。J_safe是安全代价计算每个航点与最近障碍物之间的距离。如果距离小于安全半径则按指数函数增大代价越近越危险。这个项保证了CTCM选出的路径会主动远离障碍物而不是贴着边缘飞。J_alt是高度变化代价惩罚频繁爬升和下降。无人机改变高度比水平飞行更耗能而且容易引起姿态大幅变化所以对相邻航点的高度差设置惩罚项。J_smooth是平滑度代价用相邻三个航点之间的夹角来衡量。如果某个航点处的弯折太大说明路径在这里很“生硬”不适合无人机实际飞行。这个项配合后面的B样条平滑可以让轨迹更自然。除了代价函数还要设置硬约束路径不能穿过任何障碍物所有航点必须在飞行区域范围内任意相邻航点之间的距离不能超过无人机机动能力范围。在CTCM迭代时如果某个个体违反硬约束会直接给它一个很大的处置代价相当于在进化中淘汰它。3.3 融合规划整体流程把CTCM和DWA放到同一个流程里操作顺序非常重要。我整理的流程如下初始化地图、障碍物、起点、目标点以及无人机运动学参数。调用CTCM进行全局航点寻优。种群中每条个体代表一条航点序列按代价函数计算适应度。对CTCM输出的最优航点序列做B样条平滑得到参考路径。无人机沿参考路径飞行DWA每若干个控制周期执行一次根据当前状态与参考路径上的虚拟目标点在速度窗口内采样生成候选轨迹并评价。如果DWA检测到动态障碍物阻塞了局部前进方向且无法在有限时间内避让成功则触发在线重规划以当前无人机状态为新起点重新运行CTCM但迭代次数可以大幅减少只求生成一个可行的绕行方向。无人机到达目标点后输出完整轨迹并统计代价指标。流程里最关键的是第5步。实时重规划不能每次都跑完整的CTCM迭代否则计算时间无法接受。我一般把在线重规划的迭代次数限制在完整迭代的1/10到1/5并且把上一次的全局最优个体作为初始种群的一个成员让重规划能快速收敛到一个可行解而不是从零开始。4. MATLAB实现关键代码与参数配置4.1 工程文件结构动手写代码之前建议先把工程结构理清楚。我的MATLAB工程分为以下几个文件文件名称作用main_CTCM_DWA.m主程序负责初始化参数、调用各模块、输出结果terrain_3d.m三维地形生成与障碍物建模ccm_cost.m计算路径代价函数ctcm_optimize.mCTCM全局寻优主循环dwa_planner.mDWA局部避障与轨迹生成b_spline_smooth.mB样条平滑航点序列collision_check.m动态碰撞检测plot_result.m绘制三维路径与收敛曲线这种拆分的好处是每个函数的职责单一调试时可以单独测试某一部分。比如先单独运行terrain_3d.m生成了地图再跑dwa_planner.m验证避障行为最后才把CTCM接进去。4.2 CTCM全局寻优核心代码MATLAB实现CTCM时我习惯用结构体数组表示个体。下面是一个简化但可直接运行验证的核心框架% 初始化种群num_pop条个体每条个体有num_wp个航点 pop init_population(num_pop, num_wp, map_range); % 划分部落 tribe_size num_pop / num_tribes; for iter 1 : max_iter for t 1 : num_tribes idx (t-1)*tribe_size1 : t*tribe_size; % 计算部落内每个个体的代价 for i idx cost(i) ccm_cost(pop{i}, obs_static, obs_dynamic, uav); end % 找部落首领 [~, best_local_idx] min(cost(idx)); tribe_best{t} pop(idx(best_local_idx)); end % 找全局最优 [~, global_best_idx] min(cost); global_best pop{global_best_idx}; % 成员合作更新 for i 1 : num_pop self_best pop_best{i}; t ceil(i / tribe_size); new_pos w * pop{i}.seq ... c1 * rand(size(pop{i}.seq)) .* (self_best.seq - pop{i}.seq) ... c2 * rand(size(pop{i}.seq)) .* (tribe_best{t}.seq - pop{i}.seq) ... c3 * rand(size(pop{i}.seq)) .* (global_best.seq - pop{i}.seq); % 小邻域扰动 if rand mutation_rate perturb_idx randi([1, num_wp], 1, 3); new_pos(:, perturb_idx) new_pos(:, perturb_idx) sigma * randn(3, 3); end % 边界约束 new_pos clamp(new_pos, map_range); % 更新个体 new_cost ccm_cost(new_pos, obs_static, obs_dynamic, uav); if new_cost pop_best{i}.cost pop_best{i}.seq new_pos; pop_best{i}.cost new_cost; end pop{i}.seq new_pos; end % 部落竞争重置或吞并最弱部落 tribe_costs zeros(1, num_tribes); for t 1 : num_tribes idx (t-1)*tribe_size1 : t*tribe_size; tribe_costs(t) mean(cost(idx)); end [~, worst_tribe] max(tribe_costs); [~, best_tribe] min(tribe_costs); % 用最优部落的一半个体替换最弱部落的一半个体 replace_idx ... (worst_tribe-1)*tribe_size1 : worst_tribe*tribe_size; replace_idx replace_idx(randperm(tribe_size, floor(tribe_size/2))); source_idx (best_tribe-1)*tribe_size1 : best_tribe*tribe_size; source_idx source_idx(randperm(tribe_size, length(replace_idx))); for k 1 : length(replace_idx) pop{replace_idx(k)}.seq pop{source_idx(k)}.seq ... sigma * randn(size(pop{source_idx(k)}.seq)); end end这里有个细节个体不只是存航点序列还要存一个cost字段和自身历史最优。MATLAB结构体数组可以直接给个体添加字段代码里用pop{i}.seq访问航点矩阵。边界约束要用clamp函数把航点限制在map_range内防止个体飞出地图。部落竞争部分我选择用最优部落的一半个体替换最弱部落的一半个体替换后再加一点随机扰动避免完全复制。这种做法在收敛速度和多样性之间比较平衡。如果完全复制最弱部落很快失去独立性如果不替换种群多样性虽然好但收敛偏慢。4.3 DWA局部避障核心代码三维DWA不能照搬二维。我这里的实现思路是把速度空间分成水平速度v_xy、航向角psi和垂直爬升率v_z三个维度。采样时分别给出采样步长然后组合成候选轨迹。评价函数是典型的三项加权function best_control dwa_planner(state, ref_path, obs_dynamic, param) % 速度窗口由无人机动力学约束决定 vxy_min 0; vxy_max param.vmax; dpsi_max param.dpsi_max; % 最大航向角变化率 vz_min -param.climb_max; vz_max param.climb_max; % 采样分辨率 n_v 11; n_psi 21; n_vz 11; best_score inf; for i 1 : n_v for j 1 : n_psi for k 1 : n_vz % 当前时刻的候选控制量 vxy linspace(vxy_min, vxy_max, n_v)(i); dpsi linspace(-dpsi_max, dpsi_max, n_psi)(j); vz linspace(vz_min, vz_max, n_vz)(k); % 根据参考路径计算当前虚拟目标点 target get_virtual_target(ref_path, state, lookahead); % 模拟轨迹 traj_x []; traj_y []; traj_z []; sim_state state; for t 1 : horizon sim_state update_dynamics(sim_state, vxy, dpsi, vz, dt); traj_x(end1) sim_state.x; traj_y(end1) sim_state.y; traj_z(end1) sim_state.z; end % 碰撞检测 if collision_with_dynamic_obs(traj_x, traj_y, traj_z, obs_dynamic, safety_r) continue; end % 评价函数朝向目标 安全距离 速度 heading_score angle_to_target(traj_x(end), traj_y(end), traj_z(end), target); clearance_score min_clearance(traj_x, traj_y, traj_z, obs_dynamic); velocity_score 1 - vxy / param.vmax; score param.w_head * heading_score ... param.w_clear * clearance_score ... param.w_vel * velocity_score; if score best_score best_score score; best_control [vxy, dpsi, vz]; end end end end end代码里get_virtual_target函数根据参考路径和当前无人机位置取前视距离内的一个点作为目标。这样DWA不会直接瞄准最终目标点而是跟着参考路径走。如果DWA因为动态障碍物偏离了参考路径等障碍物过去后虚拟目标点会把它重新拉回来。三维DWA的采样次数是三层循环的乘积如果每个维度都取11个点那就是1331条轨迹对MATLAB来说稍微有点慢。实际调试中我会先降低采样分辨率比如5×9×5确定参数没问题后再加密。每条轨迹的模拟步数horizon也要控制一般在10~20步之间太长了计算量大太短了评价不出轨迹趋势。4.4 参数配置速查参数是整个融合算法里最容易被忽视又最影响结果的部分。很多朋友一上来就复制代码跑结果发现要么路径乱飞要么收敛极慢其实大多是参数没匹配上环境。我这里给出一组比较常用的初始参数基于一个1000m×1000m×200m的飞行区域参数推荐值说明种群规模40~60过小容易早熟过大会拖慢迭代部落数量4~6每个部落8~10个个体比较合适最大迭代次数200~300完整全局规划时使用在线重规划迭代次数20~50紧急避障时快速生成绕行路径航点数量20~30航点太少路径不够灵活太多维度剧增惯性权重w0.7~0.9前期大后期小可线性递减学习因子c1/c2/c31.2/1.2/0.8部落首领和自身历史权重稍高变异率0.1~0.2小邻域扰动的触发概率DWA前视距离15~30m根据无人机速度调整动态窗口采样次数11×21×11精度要求高时加密动态障碍物速度5~20 m/s超过无人机机动性时需要更大安全距离有个容易踩坑的地方DWA的三个评价权重w_head、w_clear、w_vel不同环境下差别很大。障碍物多的场景要把w_clear调高让安全优先开阔场景可以调高w_head和w_vel追求效率。你也可以用上一轮CTCM的目标函数作为外层优化把这几个权重一起优化不过这会引入更高的计算复杂度我一般只在离线调试阶段使用。4.5 可视化与结果分析MATLAB里画三维路径比较直观。用plot3绘制航点连线再用scatter3绘制动态障碍物在不同时刻的位置。动态障碍物运动时可以配合for循环和pause生成动画直观看到无人机避开障碍物的全过程。我习惯额外绘制两条曲线一条是CTCM迭代过程中的全局最优代价收敛曲线用来判断算法有没有收敛另一条是无人机沿路径飞行时的最小距离曲线用来确认每个时刻与障碍物的距离都大于安全半径。收敛曲线如果下降太慢说明参数设置有问题可以适当增大c1、c2或者增加部落数如果收敛时路径依然穿过障碍物说明安全权重w2太低或者安全半径设置得不够。在仿真对比中我一般会把CTCMDWA融合算法与纯CTCM、纯DWA、标准粒子群DWA做对照。对比指标主要是路径总长度、飞行时间、最小安全距离、到达成功率。融合算法通常不是路径最短的但成功率和安全距离是最稳定的。这也是为什么我在项目里坚持用融合方案无人机动态避障最重要的其实是“安全到达”而不是“飞得最短”。5. 高频问题与调试经验5.1 动态障碍物更新频率与仿真步长不匹配一个常见问题是动态障碍物位置每隔一阵子才更新一次而DWA每个控制周期都在采样判断结果就会出现“检测时没撞、实际飞行时已经撞上”的情况。解决办法是进行时间插值在障碍物两个更新时刻之间按线性插值计算中间时刻的位置碰撞检测时把整条轨迹的时间轴和障碍物位置对齐。比如DWA模拟轨迹用了10步每步dt0.1秒就把障碍物也按0.1秒间隔插值出10个位置再逐段检测。5.2 DWA权重难调导致轨迹抖动如果你发现无人机路径一直在左右摇摆可能是w_head和w_clear的平衡没做好。w_head太大会让无人机过于激进地向目标点转遇到小扰动就容易大幅摆动w_clear太大会让无人机避障时绕得太远导致后续路径偏出参考航线。我常用的办法是先固定w_vel然后手动调整w_head和w_clear把动态障碍物放在不同距离和方向上测试。调好后再用CTCM做一轮整体参数微调效率会高很多。5.3 CTCM收敛慢或者早熟收敛慢通常有两个原因一是航点数量太多解空间维度太高种群规模却不大二是部落竞争太弱各个部落都挤在相似的区域。解决办法可以先降维比如先用20个航点做全局寻优再增加航点细化或者把竞争强度调大让最弱部落在每轮迭代中都重新初始化一部分个体。早熟则相反往往是竞争太强多样性损失太快这时候要减少替换比例增大变异率。5.4 三维航点平滑后穿过障碍物B样条平滑会改变航点位置有可能把原本安全的路径推高或者拉偏导致穿过障碍物。所以平滑完之后必须再做一次碰撞检测。我通常不会盲目增加平滑次数而是在平滑代价和安全性之间取一个折中先正常平滑然后检测穿模路径段对穿模位置的附近航点做局部偏移微调再一次碰撞检测。这个过程虽然多一步但能省掉后面大量排查时间。5.5 问题速查表问题现象可能原因解决方案路径频繁穿越地形安全半径过小、高程栅格分辨率不够增大膨胀半径提高栅格精度DWA跟踪时偏离参考路径前视距离太短、w_head权重偏低增大前视距离提高w_headCTCM迭代代价下降停滞部落竞争不足、变异率过低提高竞争强度增大变异率在线重规划耗时过长迭代次数过高、航点数量过多降低迭代次数固定部分航点只重规划前进窗口内航点动态障碍物检测漏检仿真步长与障碍物更新不匹配对障碍物轨迹做时间插值后再检测三维路径不平滑航点间距不均匀或缺少平滑代价增加J_smooth权重使用B样条平滑5.5节内容其实也是经验总结可以并入。最后再分享一个小技巧CTCM和DWA融合时一定要在仿真环境里把“传感器探测半径”显式建模出来。很多人在做三维动态避障时默认无人机能看到整个地图这不符合实际。我把传感器模型写成圆形视场后动态障碍物一旦进入探测范围才触发DWA避障CTCM的在线重规划也只在探测到威胁时才启动。这个改动对路径质量的影响比想象中大也更接近真实无人机的运行逻辑。希望这篇分享能帮你少走一些弯路尤其是融合算法的骨架和调参思路照着搭一套能跑的MATLAB仿真并不难难的是在动态威胁中保持稳定。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑