Part 2: Objective functions
One of the main problems in the Coverage Path Planning problem is to define the objective function. The objective function defines how good is our optimizer solving our problem. By default, objective functions are defined as minimization problems.
Fields2Cover defines different objective functions for each module: Decomp (Decomposition), HG (Headland Generator), SG (Swath Generator), RP (Route Planner) and PP (Path Planner).
Decomp objective functions
There is none yet
HG objective functions
Remaining area
Compute the percentage of main field over the total field. The cost is a value between [0, 1], and it is defined as a maximization problem.
F2CCells total_field(F2CCell(F2CLinearRing(
{F2CPoint(-2,-2), F2CPoint(6,-2), F2CPoint(6,6), F2CPoint(-2,6), F2CPoint(-2,-2)})));
F2CCells field(F2CCell(F2CLinearRing(
{F2CPoint(0,0), F2CPoint(4,0), F2CPoint(4,4), F2CPoint(0,4), F2CPoint(0,0)})));
f2c::obj::RemArea rem_area;
std::cout << "The remaining area is "
<< rem_area.computeCost(total_field, field) << std::endl;
std::cout << "The remaining area with sign is "
<< rem_area.computeCostWithMinimizingSign(total_field, field) <<std::endl;
total_field = f2c.Cells(f2c.Cell(f2c.LinearRing(f2c.VectorPoint([
f2c.Point(-2,-2), f2c.Point(6,-2), f2c.Point(6,6),
f2c.Point(-2,6), f2c.Point(-2,-2)]))));
field = f2c.Cells(f2c.Cell(f2c.LinearRing(f2c.VectorPoint([
f2c.Point(0,0), f2c.Point(4,0), f2c.Point(4,4),
f2c.Point(0,4), f2c.Point(0,0)]))));
rem_area = f2c.OBJ_RemArea();
print("The remaining area is ",
rem_area.computeCost(total_field, field), ", and with sign is ",
rem_area.computeCostWithMinimizingSign(total_field, field));
SG objective functions
Field coverage
Compute the percentage of the field covered by the swaths. The cost is a value between [0, 1], and it is defined as a maximization problem.
Note
Right now, it only works with same width swaths.
double width {2.0};
F2CSwath swath1(F2CLineString({F2CPoint(0.0, 1.0), F2CPoint(4.0, 1.0)}), width);
F2CSwath swath2(F2CLineString({F2CPoint(0.0, 3.0), F2CPoint(4.0, 3.0)}), width);
F2CSwath swath3(F2CLineString({F2CPoint(0.0, 2.0), F2CPoint(4.0, 2.0)}), width);
f2c::obj::FieldCoverage field_cov;
std::cout << "The field coverage with swath1 is "
<< field_cov.computeCost(field, F2CSwaths({swath1})) << " and with all of the swaths "
<< field_cov.computeCost(field, F2CSwaths({swath1, swath2, swath3})) <<std::endl;
width = 2.0;
swath1 = f2c.Swath(f2c.LineString(f2c.VectorPoint([
f2c.Point(0.0, 1.0), f2c.Point(4.0, 1.0)])), width);
swath2 = f2c.Swath(f2c.LineString(f2c.VectorPoint([
f2c.Point(0.0, 3.0), f2c.Point(4.0, 3.0)])), width);
swath3 = f2c.Swath(f2c.LineString(f2c.VectorPoint([
f2c.Point(0.0, 2.0), f2c.Point(4.0, 2.0)])), width);
swaths1 = f2c.Swaths();
swaths1.push_back(swath1);
swaths3 = f2c.Swaths();
[swaths3.push_back(s) for s in [swath1, swath2, swath3]];
field_cov = f2c.OBJ_FieldCoverage();
print("The field coverage with swath1 is ",
field_cov.computeCost(field, swaths1), " and with all of the swaths ",
field_cov.computeCost(field, swaths3));
If we want to create an algorithm that reduce this objective function, use computeCostWithMinimizingSign()
function instead, as it considers that it is a maximization problem:
std::cout << "The field coverage with sign for all of the swaths is "
<< field_cov.computeCostWithMinimizingSign(field, F2CSwaths({swath1, swath2, swath3})) <<std::endl;
print("The field coverage with sign for all of the swaths is ",
field_cov.computeCostWithMinimizingSign(field, swaths3));
The field coverage with sign for all of the swaths is -1
Number of swaths
Compute the number of swaths needed to cover the field. Turning between swaths is a slow and non-productive process of covering a field. If the number of swaths are reduced, the number of turns too, and consequently, the time needed to cover the field.
f2c::obj::NSwath n_swaths;
std::cout << "The number of swaths with swath1 is "
<< n_swaths.computeCost(F2CSwaths({swath1})) << " and with all of the swaths "
<< n_swaths.computeCost(field, F2CSwaths({swath1, swath2, swath3})) <<std::endl;
n_swaths = f2c.OBJ_NSwath();
print("The number of swaths with swath1 is ",
n_swaths.computeCost(swaths1), " and with all of the swaths ",
n_swaths.computeCost(field, swaths3));
The number of swaths with swath1 is 1 and with all of the swaths 3
A fast approximation of this function can be computed (using cite jin2010optimal) as:
f2c::obj::NSwathModified n_swaths_mod;
std::cout << "The number of swaths with swath1 is "
<< n_swaths_mod.computeCost(F2CSwaths({swath1})) << " and with all of the swaths "
<< n_swaths_mod.computeCost(field, F2CSwaths({swath1, swath2, swath3})) <<std::endl;
n_swaths_mod = f2c.OBJ_NSwathModified();
print("The number of swaths with swath1 is ",
n_swaths_mod.computeCost(swaths1), " and with all of the swaths ",
n_swaths_mod.computeCost(field, swaths3));
The number of swaths with swath1 is 1 and with all of the swaths 3
Overlap
Compute the percentage of the overlapping area in relation with the area of the field.
f2c::obj::Overlaps overlaps;
std::cout << "The field overlapping with swath1 is "
<< overlaps.computeCost(field, F2CSwaths({swath1})) << " and with all of the swaths "
<< overlaps.computeCost(field, F2CSwaths({swath1, swath2, swath3})) <<std::endl;
overlaps = f2c.OBJ_Overlaps();
print("The field overlapping with swath1 is ",
overlaps.computeCost(field, swaths1), " and with all of the swaths ",
overlaps.computeCost(field, swaths3));
The field overlapping with swath1 is 0 and with all of the swaths 0.5
Swath Length
Compute the sum of the length of each swath.
f2c::obj::SwathLength swath_length;
std::cout << "The swath length with swath1 is "
<< swath_length.computeCost(F2CSwaths({swath1})) << " and with all of the swaths "
<< swath_length.computeCost(field, F2CSwaths({swath1, swath2, swath3})) <<std::endl;
swath_length = f2c.OBJ_SwathLength();
print("The swath length with swath1 is "
swath_length.computeCost(field, swaths1), " and with all of the swaths ",
swath_length.computeCost(field, swaths3));
The swath length with swath1 is 4 and with all of the swaths 12
RP objective functions
Distance with turns
Compute the complete distance of the path, including turns. This objective function actually computes each turn needed, so we will need to define the way to compute the turns.
1F2CSwaths swaths_path({
2 F2CSwath(F2CLineString({F2CPoint(0.0, 0.0), F2CPoint(0.0, 1.0)})),
3 F2CSwath(F2CLineString({F2CPoint(1.0, 1.0), F2CPoint(1.0, 0.0)}))});
4F2CRobot robot(3.0, 39.0);
5robot.setMinTurningRadius(0.5);
6
7f2c::obj::CompleteTurnPathObj<f2c::pp::DubinsCurves> complete_length(robot);
8
9std::cout << "The complete length is: " << complete_length.computeCost(swaths_path) <<
10 " =~= " << 1 + 1 + M_PI/2.0 << std::endl;
1line1 = f2c.LineString(f2c.VectorPoint([f2c.Point(0.0, 0.0), f2c.Point(0.0, 1.0)]));
2swath1 = f2c.Swath(line1);
3line2 = f2c.LineString(f2c.VectorPoint([f2c.Point(1.0, 1.0), f2c.Point(1.0, 0.0)]));
4swath2 = f2c.Swath(line2);
5swaths_path = f2c.Swaths();
6swaths_path.push_back(swath1);
7swaths_path.push_back(swath2);
8robot = f2c.Robot(2.0, 3.0);
9robot.setMinTurningRadius(0.5);
10complete_length = f2c.OBJ_CompleteTurnPathObj_Dubins(robot);
11print("The complete length is: ", complete_length.computeCost(swaths_path),
12 " =~= ", 1 + 1 + math.pi/2.0);
The complete length is: 3.57166 =~= 3.5708
On line 7, we define the cost function with the class to compute the turns. In this case, f2c::pp::DubinsCurves
.
Direct distance without turns
Compute an approximation of the distance of the path, replacing turns by straight lines. This is faster than computing the turns and doesn’t require to provide a class to compute the turns.
f2c::obj::DirectDistPathObj direct_dist;
std::cout << "The aproximated length is: " <<
direct_dist.computeCost(swaths_path) << std::endl;
direct_dist = f2c.OBJ_DirectDistPathObj();
print("The aproximated length is: ", direct_dist.computeCost(swaths_path));
The aproximated length is: 3
PP objective functions
Path length
Compute the length of the path
F2CPath path;
path.appendSwath(swaths_path.at(0), 1);
path.appendSwath(swaths_path.at(1), 1);
f2c::obj::PathLength path_length;
std::cout << "The path length is: " <<
path_length.computeCost(path) << std::endl;
path = f2c.Path()
path.appendSwath(swaths_path.at(0), 1);
path.appendSwath(swaths_path.at(1), 1);
path_length = f2c.OBJ_PathLength();
print("The path length is: ", path_length.computeCost(path));
The path length is: 3