Main Content

Optimally Survey and Customize Coverage of Region of Interest

This example shows how to survey a geographical region of interest with a UAV using the uavCoveragePlanner object.


Coverage planning is the process of finding an optimal path plan for a UAV to survey the entire region of a given geographical area. Coverage planning is useful in many applications such as precision agriculture, surveying, and image mapping. This example focuses on the surveying applications.

To survey a region, a UAV typically flies in one direction and uses sharp right-angle turns to alternate the direction. This path involves braking and accelerating as the UAV does multiple turns in a sweep path while intermittently sweeping across a region in a straight line. To conserve battery energy and prolong the duration of flight, you can choose an optimal sweep direction to minimize the number of turns. Although you can define a sweep direction for simple convex regions, most real-world applications involve complex concave regions of interest where a uniform sweep path leads to excessive turns in narrower regions and a longer flight time. Such a path also makes keeping the UAV within a region of interest difficult. Resorting to the convex hull is also a suboptimal strategy, as the UAV spends more time outside of its region of interest and has a higher chance of flying into an obstacle or a no-fly zone. In such cases, a good option is to decompose the area into convex subareas. You can then optimally choose a coverage strategy that is best for each subregion and later connect the paths together for the complete mission.

Define Region of Interest

To begin coverage planning, first you must define the region of interest as a polygon or set of polygons. First create the geographic axis, set the latitude and longitude limits, and calculate the mean of the limits to get the geocenter of the viewed area. Set the reference height to 400 meters.

gax = geoaxes(Basemap="satellite");
latlimits = [44.3135 44.3534];
lonlimits = [-72.0227 -71.9544];
geocenter = [mean(latlimits) mean(lonlimits) 0];
refHeight = 400;
hold on

You can define the vertices of the polygon interactively by selecting points on the map, or you can use predefined vertices stored in predefinedROI.mat to define the polygon, takeoff location, and landing location. By default, this example uses the predefined points. To define the polygon interactively, set interactiveROI to true. Set interactiveROI to false and then load predefinedROI. Then use the helper function to plot and label the predefined takeoff, landing, and polygon vertices. If you choose to select this data interactively, set interactiveROI to true and use this image as a reference for selecting the points.

interactiveROI = false;
load predefinedROI.mat

To interactively define a region for surveying, set the interactiveROI flag to true. Then define a takeoff location, polygon and landing location using the helperTakeoffSelectionFcn, helperPolygonSelectionFcn, and helperLandSelectionFcn helper functions, respectively. To select the takeoff position, select a point on the geographic axis as the takeoff location, then define a polygon by clicking around a region of interest. You can stop drawing the polygon by clicking Enter. Last, specify a landing location for the UAV on the map.

    [visLimitsLat,visLimitsLon] = geolimits; % Cache visual limits
    [takeoffLat,takeoffLon] = helperTakeoffSelectionFcn(gax,visLimitsLat,visLimitsLon);
    [llapoints,xyzpoints] = helperPolygonSelectionFcn(gax,visLimitsLat,visLimitsLon,geocenter);
    [landLat,landLon] = helperLandSelectionFcn(gax,visLimitsLat,visLimitsLon);

Divide Region of Interest into Subregions

To optimally survey a complex area, you must first decompose the region into simpler convex areas.

Decompose the geometry in local East-North coordinates using the coverageDecomposition function. Create a cell array for each of the new polygon vertices in geodetic coordinates.

subAreasEN = coverageDecomposition(xyzpoints(:,1:2));
subAreasLLA = cell(1,numel(subAreasEN));

Append the reference height to the local East-North-Up coordinates and convert those coordinates to geodetic coordinates using the lla2enu function with the reference location set to the geocenter of the geographic axis.

for i = 1:1:numel(subAreasEN)
    altitude = refHeight*ones(size(subAreasEN{i},1),1);
    localENU = [subAreasEN{i}(:,1) subAreasEN{i}(:,2) altitude];
    subArea = enu2lla(localENU,geocenter,"flat");
    subAreasLLA{i} = subArea(:,1:2);

Create Coverage Space and Plan Path for Region

To plan the coverage path, you must create a coverage space using the polygons that represent the region of interest. Once you have the coverage space, you can create the coverage planner. Aim to optimally survey each subregion by minimizing the number of turns and then minimize the connection distance between subregions. The connection distance is the distance that the UAV must traverse to reach the next polygon to survey. Create a coverage space defined by the polygon subregions and the sensor footprint parameters of the UAV. Specify the spacing between adjacent parallel sweeps of the UAV as 100 meters and specify zero sidelap between the sensor readings of an adjacent parallel sweep of the UAV. See the uavCoverageSpace object for more information about these arguments and how to tune them. Set the global reference altitude for the coverage mission to 400 meters. Specify that the coverage space uses geodetic coordinates and specify the geocenter of the geographic axes as the reference location.

cs = uavCoverageSpace(Polygons=subAreasLLA, ...
                      UnitWidth=100, ...
                      Sidelap=0, ...
                      ReferenceHeight=refHeight, ...
                      UseLocalCoordinates=false, ...

Show the coverage space on the geographic axes.

ax =,LineWidth=1.25);

Create the coverage planner for the coverage space and plan the coverage path starting from the specified takeoff location and ending at the specified landing location.

cp = uavCoveragePlanner(cs);
[wpts,solnInfo] = plan(cp,[takeoffLat takeoffLon 0],[landLat landLon 0]); 

Show the coverage path on the coverage space.

path1 = geoplot(gax,wpts(:,1),wpts(:,2),LineWidth=1.5);
hold off

Check the transition cost in meters. Note that in addition to the distance between polygons, this distance includes the distances from the takeoff location to the first polygon and from the last polygon to the landing location.

connectionDistancePath1 = solnInfo.TransitionCost
connectionDistancePath1 = 6.2648e+03

Customize Survey Path

Although the planner automatically determines the sweep pattern in each subregion, you have the option to customize the pattern to improve performance for different applications. For example, visual features can be more distinguishable in the limited view of a camera sensor along a specific direction or you might want to survey crops or vegetation planted at a certain orientation.

Use the setCoveragePattern object function of the uavCoverageSpace object to change the sweep angle for the first and second polygon to 90 degrees.


Additionally, on visual inspection, polygon 3 seems like a better candidate to begin the coverage mission, as it enables the UAV to begin and end the mission closer to the takeoff and landing regions, respectively. Reducing those distances minimizes the connection distance outside of the coverage mission.

Set the starting area in the coverage planner solver parameters to 3 to survey polygon 3 first.

cp.SolverParameters.StartingArea = 3;

Plan the coverage path again using the updated coverage space.

[wpts,custSoln] = plan(cp,[takeoffLat takeoffLon 0],[landLat landLon 0]);

Remove the previous path from the geographic axes and plot the new coverage path.

hold on
h2 = geoplot(gax,wpts(:,1),wpts(:,2),LineWidth=1.5);
hold off

Check the transition cost of this coverage path in meters.

connectionDistancePath2 = custSoln.TransitionCost
connectionDistancePath2 = 3.7921e+03

Note that the changes result in a lower connection distance. For a distance-optimal solution or to optimally connect nonadjacent polygons, set the Solver property of the coverage planner to "Exhaustive".

Using the uavCoveragePlanner and uavCoverageSpace objects, you planned a coverage path for a UAV to optimally survey the desired region. This example showed how to plan the coverage path for surveying interconnected regions. As a next step, you can plan a coverage path to survey two separate regions and use the exhaustive planner algorithm to improve optimality at the cost of solving time.

Next Steps

You can deploy the coverage mission to a UAV by exporting the waypoints to a ground control plan format using the exportWaypointsPlan object function. You can load this file into ground control software such as QGroundControl or Ardupilot Mission Planner.


You can also validate trajectory-tracking and guidance algorithms by importing the coverage waypoints into a uavMission object and simulate the UAV in a uavScenario. For more information about this workflow, see Execute Coverage Plan Using UAV Mission.

See Also

| |

Related Topics