【UAV】无人机区域覆盖规划实战:最优路径与自定义策略【含matlab代码】 无人机区域覆盖规划实战最优路径与自定义策略摘要在精准农业、测绘、搜救等场景中无人机需要高效地扫描整个目标区域。覆盖规划Coverage Planning旨在寻找一条最优路径使无人机在最短时间内、以最小能耗完成对给定区域的全面覆盖。本文基于 MATLAB UAV Toolbox 的uavCoveragePlanner和uavCoverageSpace对象详细讲解如何对复杂地理区域进行覆盖路径规划。我们将从定义感兴趣区域ROI开始将其分解为凸子区域自动生成扫掠路径并演示如何自定义扫掠方向以优化连接距离最终导出路径用于实际飞行。1. 背景与问题描述覆盖规划的核心是给定一个二维地理区域无人机需沿平行航线类似“割草机”路径扫过整个区域。典型的覆盖路径包含直线扫掠和转弯动作。频繁的转弯会增加飞行时间和能耗因此优化扫掠方向以最小化转弯次数是提升效率的关键。对于简单凸区域最优扫掠方向通常垂直于区域的长轴。但实际中的凹多边形区域如农田、不规则地块若采用统一方向会在狭窄凹陷处产生大量无效转弯甚至使无人机飞越区域边界。一种常见的次优做法是使用凸包Convex Hull但这会导致无人机在非目标区域飞行增加碰撞风险或进入禁飞区。更优的策略是将凹区域分解为多个凸子区域对每个子区域独立选择最佳扫掠方向再通过连接路径串联整个任务。MATLAB 的coverageDecomposition函数和uavCoveragePlanner对象正是为此设计。2. 定义感兴趣区域ROI首先我们创建地理坐标轴并加载底图卫星图设定经纬度范围并计算区域的几何中心用于后续坐标转换。参考高度设为 400 米无人机飞行高度。gaxgeoaxes(Basemapsatellite);latlimits[44.313544.3534];lonlimits[-72.0227-71.9544];geolimits(latlimits,lonlimits);geocenter[mean(latlimits),mean(lonlimits),0];% 参考点经纬高refHeight400;% 覆盖飞行高度hold on;2.1 交互式或预定义方式选取区域您可以通过两种方式定义区域多边形预定义加载predefinedROI.mat文件其中包含多边形的顶点、起飞点和降落点。交互式在地图上点击选取起飞点、多边形顶点和降落点。本例默认使用预定义方式若您想手动选取可将interactiveROI设为true。interactiveROIfalse;% 设为 true 则进入交互模式load predefinedROI.mat;% 加载预定义数据包含 takeoffLat, takeoffLon, landLat, landLon, llapointshelperPlotTakeoffROILanding(gax,takeoffLat,takeoffLon,landLat,landLon,llapoints);llapoints是一个 N×2 的矩阵存储多边形顶点的经纬度坐标。辅助函数helperPlotTakeoffROILanding会在图上标记起飞点▲、降落点●和多边形轮廓。若使用交互模式则调用以下函数依次选取ifinteractiveROI[visLimitsLat,visLimitsLon]geolimits;[takeoffLat,takeoffLon]helperTakeoffSelectionFcn(gax,visLimitsLat,visLimitsLon);[llapoints,xyzpoints]helperPolygonSelectionFcn(gax,visLimitsLat,visLimitsLon,geocenter);[landLat,landLon]helperLandSelectionFcn(gax,visLimitsLat,visLimitsLon);end提示交互式选择时多边形需按顺序点击顶点按 Enter 结束。得到的数据会保存在变量中。3. 将感兴趣区域分解为凸子区域复杂凹多边形不能直接应用扫掠规划必须先分解。MATLAB 提供coverageDecomposition函数基于局部 East-North 坐标系将多边形拆分为若干凸多边形。首先将经纬度顶点转换为局部 ENU 坐标以geocenter为参考原点然后调用分解函数% 将 llapoints 转换为 ENU 坐标忽略高度仅用 XYxyzpointslla2enu([llapoints,refHeight*ones(size(llapoints,1),1)],geocenter,flat);subAreasENcoverageDecomposition(xyzpoints(:,1:2));% 返回元胞数组每个元素是凸多边形顶点EN坐标接着将各子区域的坐标转回经纬度LLA并存储于subAreasLLA中subAreasLLAcell(1,numel(subAreasEN));fori1:numel(subAreasEN)altituderefHeight*ones(size(subAreasEN{i},1),1);localENU[subAreasEN{i}(:,1),subAreasEN{i}(:,2),altitude];subAreaenu2lla(localENU,geocenter,flat);subAreasLLA{i}subArea(:,1:2);end此时原始凹区域被划分成多个凸子区域如图中不同颜色所示每个子区域可单独规划扫掠路径。4. 创建覆盖空间与路径规划4.1 定义覆盖空间uavCoverageSpace覆盖空间对象封装了待覆盖的多边形、传感器有效宽度、重叠率等参数。关键参数Polygons子区域的多边形顶点经纬度。UnitWidth相邻平行扫掠线之间的间距本例设为 100 米与传感器覆盖宽度相关。Sidelap相邻扫描带之间的重叠率0 表示无重叠。ReferenceHeight飞行高度400 米用于确保坐标一致性。UseLocalCoordinates设为false表示使用经纬度坐标。ReferenceLocation参考点地理中心用于内部坐标转换。csuavCoverageSpace(PolygonssubAreasLLA,...UnitWidth100,...Sidelap0,...ReferenceHeightrefHeight,...UseLocalCoordinatesfalse,...ReferenceLocationgeocenter);调用show方法将覆盖空间可视化在地理坐标轴上各子区域以不同颜色区分axcs.show(Parentgax,LineWidth1.25);4.2 创建覆盖规划器并生成路径uavCoveragePlanner负责计算扫掠路径。我们只需指定起飞点和降落点经纬度 高度本例高度设为 0但实际会被覆盖空间的高度覆盖cpuavCoveragePlanner(cs);[wpts,solnInfo]plan(cp,[takeoffLat,takeoffLon,0],[landLat,landLon,0]);返回的wpts是路径航点矩阵每行 [lat, lon, alt]solnInfo包含路径的详细信息如各子区域顺序、转弯点、总连接距离等。将路径绘制在地图上path1geoplot(gax,wpts(:,1),wpts(:,2),LineWidth1.5);hold off;查看总连接距离包括从起飞点到第一个子区域、子区域间、以及最后一个子区域到降落点的距离connectionDistancePath1solnInfo.TransitionCost% 输出6.2648e03约 6265 米注意默认情况下规划器会尝试最小化转弯次数但子区域间的连接顺序是启发式或简单贪心得到的可能并非全局最优。接下来的自定义将优化连接距离。5. 自定义扫掠策略以优化路径5.1 调整特定子区域的扫掠角度根据应用需求您可能希望扫掠方向与某种特征如作物行、地形走向对齐。我们可以使用setCoveragePattern方法为特定子区域指定扫掠角度相对于正东方向逆时针为正。例如将第 2 和第 3 个子区域的扫掠角度设为 90 度即南北方向cs.setCoveragePattern(2,SweepAngle90);cs.setCoveragePattern(3,SweepAngle90);角度改变后规划器会重新计算该子区域内部的平行航线。5.2 改变起始子区域以减少连接距离通过观察子区域 3 更靠近起飞点且飞行结束后离降落点也较近。我们可以强制规划器从第 3 个子区域开始扫描以缩短起飞到第一块区域的空飞距离。在规划器的求解参数中设置StartingAreacp.SolverParameters.StartingArea3;5.3 重新规划并比较优化效果调用plan重新生成路径[wpts,custSoln]plan(cp,[takeoffLat,takeoffLon,0],[landLat,landLon,0]);删除旧路径绘制新路径delete(path1);hold on;h2geoplot(gax,wpts(:,1),wpts(:,2),LineWidth1.5);hold off;检查新的连接距离connectionDistancePath2custSoln.TransitionCost% 输出3.7921e03约 3792 米相比默认路径的 6265 米自定义后连接距离减少了近 40%大幅提升了效率。5.4 穷举求解器可选若希望获得子区域间连接顺序的全局最优解可将求解器设置为Exhaustive穷举它会尝试所有可能顺序但计算时间随子区域数量指数增长。适用于子区域数量较少≤8的情况。cp.SolverExhaustive;6. 导出航点用于地面站软件规划完成后可将航点导出为标准格式如.waypoints文件以便导入 QGroundControl 或 Mission Planner 等地面控制软件直接用于实际飞行。exportWaypointsPlan(cp,custSoln,customCoverage.waypoints);该文件包含了每个航点的经纬度、高度以及期望的速度或停留时间等信息。7. 仿真验证可选您还可以将生成的航点导入uavMission对象结合uavScenario进行动力学仿真验证飞行轨迹的可行性评估能耗、时间等指标。具体可参考文档Execute Coverage Plan Using UAV Mission。8. 总结与扩展本教程完整演示了以下流程定义地理区域交互或预定义将凹区域分解为凸子区域创建覆盖空间并自动规划初始扫掠路径自定义子区域扫掠角度和起始顺序优化连接距离导出航点用于实际任务。通过合理设置扫掠方向和子区域顺序您可以显著提高无人机任务效率降低能耗。MATLAB 提供的工具链覆盖了从规划到仿真的完整环节非常适合算法快速验证与部署。下一步可以做什么对多个不相连的区域进行覆盖规划结合障碍物和禁飞区约束使用真实传感器模型生成覆盖过程中的感知数据。参考资料MATLAB UAV Toolbox - Coverage PlanninguavCoveragePlanner 文档uavCoverageSpace 文档完整代码整合版为了方便您直接运行以下提供本示例的完整代码默认使用预定义数据%% 1. 设置地图与区域gaxgeoaxes(Basemapsatellite);latlimits[44.313544.3534];lonlimits[-72.0227-71.9544];geolimits(latlimits,lonlimits);geocenter[mean(latlimits),mean(lonlimits),0];refHeight400;hold on;%% 2. 加载预定义区域interactiveROIfalse;load predefinedROI.mat;helperPlotTakeoffROILanding(gax,takeoffLat,takeoffLon,landLat,landLon,llapoints);% 若交互取消注释下面代码% if interactiveROI% [visLimitsLat, visLimitsLon] geolimits;% [takeoffLat, takeoffLon] helperTakeoffSelectionFcn(gax, visLimitsLat, visLimitsLon);% [llapoints, xyzpoints] helperPolygonSelectionFcn(gax, visLimitsLat, visLimitsLon, geocenter);% [landLat, landLon] helperLandSelectionFcn(gax, visLimitsLat, visLimitsLon);% end%% 3. 分解为凸子区域xyzpointslla2enu([llapoints,refHeight*ones(size(llapoints,1),1)],geocenter,flat);subAreasENcoverageDecomposition(xyzpoints(:,1:2));subAreasLLAcell(1,numel(subAreasEN));fori1:numel(subAreasEN)altituderefHeight*ones(size(subAreasEN{i},1),1);localENU[subAreasEN{i}(:,1),subAreasEN{i}(:,2),altitude];subAreaenu2lla(localENU,geocenter,flat);subAreasLLA{i}subArea(:,1:2);end%% 4. 创建覆盖空间与规划器csuavCoverageSpace(PolygonssubAreasLLA,UnitWidth100,Sidelap0,...ReferenceHeightrefHeight,UseLocalCoordinatesfalse,...ReferenceLocationgeocenter);cs.show(Parentgax,LineWidth1.25);cpuavCoveragePlanner(cs);[wpts,solnInfo]plan(cp,[takeoffLat,takeoffLon,0],[landLat,landLon,0]);path1geoplot(gax,wpts(:,1),wpts(:,2),LineWidth1.5);connection1solnInfo.TransitionCost;fprintf(默认路径连接距离%.2f 米\n, connection1);%% 5. 自定义扫掠方向和起始区域cs.setCoveragePattern(2,SweepAngle90);cs.setCoveragePattern(3,SweepAngle90);cp.SolverParameters.StartingArea3;[wpts2,custSoln]plan(cp,[takeoffLat,takeoffLon,0],[landLat,landLon,0]);delete(path1);hold on;geoplot(gax,wpts2(:,1),wpts2(:,2),LineWidth1.5);hold off;connection2custSoln.TransitionCost;fprintf(优化后路径连接距离%.2f 米\n, connection2);%% 6. 导出航点exportWaypointsPlan(cp,custSoln,customCoverage.waypoints);运行以上脚本您将看到地图上显示两个路径对比并在命令窗口输出优化前后的连接距离。希望这篇博客能帮助您掌握无人机覆盖规划的完整流程。如有疑问欢迎在评论区交流讨论