32 double COccupancyGridMap2D::internal_computeObservationLikelihood(
41 if (!scan->
isPlanarScan(insertionOptions.horizontalTolerance))
43 if (insertionOptions.useMapAltitude &&
44 fabs(insertionOptions.mapAltitude - scan->
sensorPose.z()) > 0.01)
55 switch (likelihoodOptions.likelihoodMethod)
59 return computeObservationLikelihood_rayTracing(obs, takenFrom);
61 case lmMeanInformation:
62 return computeObservationLikelihood_MI(obs, takenFrom);
65 return computeObservationLikelihood_Consensus(obs, takenFrom);
67 case lmCellsDifference:
68 return computeObservationLikelihood_CellsDifference(obs, takenFrom);
70 case lmLikelihoodField_Thrun:
71 return computeObservationLikelihood_likelihoodField_Thrun(
74 case lmLikelihoodField_II:
75 return computeObservationLikelihood_likelihoodField_II(
79 return computeObservationLikelihood_ConsensusOWA(obs, takenFrom);
86 double COccupancyGridMap2D::computeObservationLikelihood_Consensus(
106 if (!o->
isPlanarScan(insertionOptions.horizontalTolerance))
123 const size_t n = compareMap->
size();
125 for (
size_t i = 0; i <
n; i += likelihoodOptions.consensus_takeEachRange)
128 compareMap->
getPoint(i, pointLocal);
131 int cx0 = x2idx(pointGlobal.
x);
132 int cy0 = y2idx(pointGlobal.
y);
134 likResult += 1 - getCell_nocheck(cx0, cy0);
137 if (Denom) likResult /= Denom;
139 pow(likResult, static_cast<double>(likelihoodOptions.consensus_pow));
141 return log(likResult);
147 double COccupancyGridMap2D::computeObservationLikelihood_ConsensusOWA(
150 double likResult = 0;
167 if (!o->
isPlanarScan(insertionOptions.horizontalTolerance))
184 const size_t n = compareMap->
size();
187 likelihoodOutputs.OWA_pairList.clear();
188 for (
size_t i = 0; i <
n; i++)
191 compareMap->
getPoint(i, pointLocal);
194 int cx0 = x2idx(pointGlobal.
x);
195 int cy0 = y2idx(pointGlobal.
y);
197 int cxMin = max(0, cx0 - Acells);
198 int cxMax =
min(static_cast<int>(size_x) - 1, cx0 + Acells);
199 int cyMin = max(0, cy0 - Acells);
200 int cyMax =
min(static_cast<int>(size_y) - 1, cy0 + Acells);
204 for (
int cx = cxMin; cx <= cxMax; cx++)
205 for (
int cy = cyMin; cy <= cyMax; cy++)
206 lik += 1 - getCell_nocheck(cx, cy);
208 int nCells = (cxMax - cxMin + 1) * (cyMax - cyMin + 1);
214 element.second = pointGlobal;
215 likelihoodOutputs.OWA_pairList.push_back(element);
221 likelihoodOutputs.OWA_pairList.begin(),
222 likelihoodOutputs.OWA_pairList.end());
225 size_t M = likelihoodOptions.OWA_weights.
size();
226 ASSERT_(likelihoodOutputs.OWA_pairList.size() >= M);
228 likelihoodOutputs.OWA_pairList.resize(M);
229 likelihoodOutputs.OWA_individualLikValues.resize(M);
231 for (
size_t k = 0; k < M; k++)
233 likelihoodOutputs.OWA_individualLikValues[k] =
234 likelihoodOutputs.OWA_pairList[k].first;
235 likResult += likelihoodOptions.OWA_weights[k] *
236 likelihoodOutputs.OWA_individualLikValues[k];
239 return log(likResult);
245 double COccupancyGridMap2D::computeObservationLikelihood_CellsDifference(
261 if (!o->
isPlanarScan(insertionOptions.horizontalTolerance))
266 takenFrom.
x() - 10, takenFrom.
x() + 10, takenFrom.
y() - 10,
267 takenFrom.
y() + 10, resolution);
272 compareGrid.insertionOptions.maxDistanceInsertion =
273 insertionOptions.maxDistanceInsertion;
274 compareGrid.insertionOptions.maxOccupancyUpdateCertainty = 0.95f;
278 Ax =
round((x_min - compareGrid.x_min) / resolution);
279 Ay =
round((y_min - compareGrid.y_min) / resolution);
281 int nCellsCompared = 0;
282 float cellsDifference = 0;
285 int x1 =
min(compareGrid.size_x, size_x + Ax);
286 int y1 =
min(compareGrid.size_y, size_y + Ay);
288 for (
int x = x0;
x < x1;
x += 1)
290 for (
int y = y0;
y < y1;
y += 1)
292 float xx = compareGrid.idx2x(
x);
293 float yy = compareGrid.idx2y(
y);
295 float c1 = getPos(xx, yy);
296 float c2 = compareGrid.getCell(
x,
y);
297 if (c2 < 0.45f || c2 > 0.55f)
300 if ((c1 > 0.5 && c2 < 0.5) || (c1 < 0.5 && c2 > 0.5))
305 ret = 1 - cellsDifference / (nCellsCompared);
313 double COccupancyGridMap2D::computeObservationLikelihood_MI(
322 updateInfoChangeOnly.enabled =
true;
323 insertionOptions.maxDistanceInsertion *=
324 likelihoodOptions.MI_ratio_max_distance;
327 updateInfoChangeOnly.cellsUpdated = 0;
328 updateInfoChangeOnly.I_change = 0;
329 updateInfoChangeOnly.laserRaysSkip = likelihoodOptions.MI_skip_rays;
333 insertObservation(obs, &poseRobot);
336 double newObservation_mean_I;
337 if (updateInfoChangeOnly.cellsUpdated)
338 newObservation_mean_I =
339 updateInfoChangeOnly.I_change / updateInfoChangeOnly.cellsUpdated;
341 newObservation_mean_I = 0;
344 updateInfoChangeOnly.enabled =
false;
345 insertionOptions.maxDistanceInsertion /=
346 likelihoodOptions.MI_ratio_max_distance;
349 pow(newObservation_mean_I,
350 static_cast<double>(likelihoodOptions.MI_exponent));
357 double COccupancyGridMap2D::computeObservationLikelihood_rayTracing(
374 if (!o->
isPlanarScan(insertionOptions.horizontalTolerance))
379 int decimation = likelihoodOptions.rayTracing_decimation;
396 double stdLaser = likelihoodOptions.rayTracing_stdHit;
397 double stdSqrt2 = sqrt(2.0f) * stdLaser;
405 for (
int j = 0; j < nRays; j += decimation)
408 r_sim = simulatedObs.
scan[j];
418 min((
float)fabs(r_sim - r_obs), 2.0f) / stdSqrt2));
419 ret += log(likelihood);
432 double COccupancyGridMap2D::computeObservationLikelihood_likelihoodField_Thrun(
450 if (!o->
isPlanarScan(insertionOptions.horizontalTolerance))
return -10;
460 ret = computeLikelihoodField_Thrun(
476 ret = computeLikelihoodField_Thrun(&pts, &takenFrom);
487 double COccupancyGridMap2D::computeObservationLikelihood_likelihoodField_II(
505 if (!o->
isPlanarScan(insertionOptions.horizontalTolerance))
512 ret = computeLikelihoodField_II(
525 double COccupancyGridMap2D::computeLikelihoodField_Thrun(
531 size_t N = pm->
size();
533 likelihoodOptions.LF_maxCorrsDistance /
536 bool Product_T_OrSum_F = !likelihoodOptions.LF_alternateAverageMethod;
546 float stdHit = likelihoodOptions.LF_stdHit;
547 float zHit = likelihoodOptions.LF_zHit;
548 float zRandom = likelihoodOptions.LF_zRandom;
549 float zRandomMaxRange = likelihoodOptions.LF_maxRange;
550 float zRandomTerm = zRandom / zRandomMaxRange;
551 float Q = -0.5f /
square(stdHit);
554 unsigned int size_x_1 = size_x - 1;
555 unsigned int size_y_1 = size_y - 1;
557 #define LIK_LF_CACHE_INVALID (66) 561 double maxCorrDist_sq =
square(likelihoodOptions.LF_maxCorrsDistance);
562 double minimumLik = zRandomTerm + zHit * exp(Q * maxCorrDist_sq);
564 float occupiedMinDist;
566 if (likelihoodOptions.enableLikelihoodCache)
569 if (precomputedLikelihoodToBeRecomputed)
574 precomputedLikelihood.clear();
576 precomputedLikelihoodToBeRecomputed =
false;
580 cellType thresholdCellValue = p2l(0.5f);
581 int decimation = likelihoodOptions.LF_decimation;
583 const double _resolution = this->resolution;
584 const double constDist2DiscrUnits = 100 / (_resolution * _resolution);
585 const double constDist2DiscrUnits_INV = 1.0 / constDist2DiscrUnits;
587 if (N < 10) decimation = 1;
592 for (
size_t j = 0; j < N; j += decimation)
594 occupiedMinDist = maxCorrDist_sq;
602 ::sincos(relativePose->
phi(), &ssin, &ccos);
604 ccos = cos(relativePose->
phi());
605 ssin = sin(relativePose->
phi());
608 relativePose->
x() + pointLocal.
x * ccos - pointLocal.
y * ssin;
610 relativePose->
y() + pointLocal.
x * ssin + pointLocal.
y * ccos;
618 int cx = x2idx(pointGlobal.
x);
619 int cy = y2idx(pointGlobal.
y);
623 if (static_cast<unsigned>(cx) >= size_x_1 ||
624 static_cast<unsigned>(cy) >= size_y_1)
628 thisLik = minimumLik;
633 if (likelihoodOptions.enableLikelihoodCache)
635 thisLik = precomputedLikelihood[cx + cy * size_x];
638 if (!likelihoodOptions.enableLikelihoodCache ||
645 int xx1 = max(0, cx - K);
646 int xx2 =
min(size_x_1, (
unsigned)(cx + K));
647 int yy1 = max(0, cy - K);
648 int yy2 =
min(size_y_1, (
unsigned)(cy + K));
653 &map[xx1 + yy1 * size_x];
654 unsigned incrAfterRow = size_x - ((xx2 - xx1) + 1);
656 signed int Ax0 = 10 * (xx1 - cx);
657 signed int Ay = 10 * (yy1 - cy);
659 unsigned int occupiedMinDistInt =
660 mrpt::round(maxCorrDist_sq * constDist2DiscrUnits);
662 for (
int yy = yy1; yy <= yy2; yy++)
665 square((
unsigned int)(Ay));
667 signed short Ax = Ax0;
670 for (
int xx = xx1; xx <= xx2; xx++)
672 if ((cell = *mapPtr++) < thresholdCellValue)
675 square((
unsigned int)(Ax)) + Ay2;
681 mapPtr += incrAfterRow;
686 occupiedMinDistInt * constDist2DiscrUnits_INV;
689 if (likelihoodOptions.LF_useSquareDist)
690 occupiedMinDist *= occupiedMinDist;
692 thisLik = zRandomTerm + zHit * exp(Q * occupiedMinDist);
694 if (likelihoodOptions.enableLikelihoodCache)
696 precomputedLikelihood[cx + cy * size_x] = thisLik;
701 if (Product_T_OrSum_F)
712 if (!Product_T_OrSum_F) ret = log(ret / M);
722 double COccupancyGridMap2D::computeLikelihoodField_II(
728 size_t N = pm->
size();
730 if (!N)
return 1e-100;
740 float zRandomTerm = 1.0f / likelihoodOptions.LF_maxRange;
741 float Q = -0.5f /
square(likelihoodOptions.LF_stdHit);
749 int maxRangeInCells =
750 (int)ceil(likelihoodOptions.LF_maxCorrsDistance / resolution);
756 for (j = 0; j < N; j += likelihoodOptions.LF_decimation)
763 pointGlobal = *relativePose + pointLocal;
772 cx0 = x2idx(pointGlobal.
x);
773 cy0 = y2idx(pointGlobal.
y);
777 cx_min = max(cx0 - maxRangeInCells, 0);
778 cx_max =
min(cx0 + maxRangeInCells, static_cast<int>(size_x));
779 cy_min = max(cy0 - maxRangeInCells, 0);
780 cy_max =
min(cy0 + maxRangeInCells, static_cast<int>(size_y));
787 for (cx = cx_min; cx <= cx_max; cx++)
789 for (cy = cy_min; cy <= cy_max; cy++)
791 float P_free = getCell(cx, cy);
793 exp(Q * (
square(idx2x(cx) - pointGlobal.
x) +
794 square(idx2y(cy) - pointGlobal.
y)));
796 lik += P_free * zRandomTerm + (1 - P_free) * termDist;
801 if (likelihoodOptions.LF_alternateAverageMethod)
804 ret += log(lik / ((cy_max - cy_min + 1) * (cx_max - cx_min + 1)));
809 if (likelihoodOptions.LF_alternateAverageMethod && nCells > 0)
810 ret = log(ret / nCells);
822 COccupancyGridMap2D::TLikelihoodOptions::TLikelihoodOptions()
823 : likelihoodMethod(lmLikelihoodField_Thrun),
830 LF_maxCorrsDistance(0.3f),
831 LF_useSquareDist(false),
832 LF_alternateAverageMethod(false),
836 MI_ratio_max_distance(1.5f),
838 rayTracing_useDistanceFilter(true),
839 rayTracing_decimation(10),
840 rayTracing_stdHit(1.0f),
842 consensus_takeEachRange(1),
844 OWA_weights(100, 1 / 100.0f),
846 enableLikelihoodCache(true)
857 iniFile.read_enum(section,
"likelihoodMethod", likelihoodMethod);
859 enableLikelihoodCache =
iniFile.read_bool(
860 section,
"enableLikelihoodCache", enableLikelihoodCache);
862 LF_stdHit =
iniFile.read_float(section,
"LF_stdHit", LF_stdHit);
863 LF_zHit =
iniFile.read_float(section,
"LF_zHit", LF_zHit);
864 LF_zRandom =
iniFile.read_float(section,
"LF_zRandom", LF_zRandom);
865 LF_maxRange =
iniFile.read_float(section,
"LF_maxRange", LF_maxRange);
866 LF_decimation =
iniFile.read_int(section,
"LF_decimation", LF_decimation);
867 LF_maxCorrsDistance =
868 iniFile.read_float(section,
"LF_maxCorrsDistance", LF_maxCorrsDistance);
870 iniFile.read_bool(section,
"LF_useSquareDist", LF_useSquareDist);
871 LF_alternateAverageMethod =
iniFile.read_bool(
872 section,
"LF_alternateAverageMethod", LF_alternateAverageMethod);
874 MI_exponent =
iniFile.read_float(section,
"MI_exponent", MI_exponent);
875 MI_skip_rays =
iniFile.read_int(section,
"MI_skip_rays", MI_skip_rays);
876 MI_ratio_max_distance =
iniFile.read_float(
877 section,
"MI_ratio_max_distance", MI_ratio_max_distance);
879 rayTracing_useDistanceFilter =
iniFile.read_bool(
880 section,
"rayTracing_useDistanceFilter", rayTracing_useDistanceFilter);
882 iniFile.read_float(section,
"rayTracing_stdHit", rayTracing_stdHit);
884 consensus_takeEachRange =
iniFile.read_int(
885 section,
"consensus_takeEachRange", consensus_takeEachRange);
886 consensus_pow =
iniFile.read_float(section,
"consensus_pow", consensus_pow);
888 iniFile.read_vector(section,
"OWA_weights", OWA_weights, OWA_weights);
895 std::ostream& out)
const 898 "\n----------- [COccupancyGridMap2D::TLikelihoodOptions] ------------ " 902 switch (likelihoodMethod)
932 "enableLikelihoodCache = %c\n",
933 enableLikelihoodCache ?
'Y' :
'N');
936 "LF_stdHit = %f\n", LF_stdHit);
938 "LF_zHit = %f\n", LF_zHit);
940 "LF_zRandom = %f\n", LF_zRandom);
942 "LF_maxRange = %f\n", LF_maxRange);
944 "LF_decimation = %u\n", LF_decimation);
946 "LF_maxCorrsDistance = %f\n", LF_maxCorrsDistance);
948 "LF_useSquareDist = %c\n",
949 LF_useSquareDist ?
'Y' :
'N');
951 "LF_alternateAverageMethod = %c\n",
952 LF_alternateAverageMethod ?
'Y' :
'N');
954 "MI_exponent = %f\n", MI_exponent);
956 "MI_skip_rays = %u\n", MI_skip_rays);
958 "MI_ratio_max_distance = %f\n",
959 MI_ratio_max_distance);
961 "rayTracing_useDistanceFilter = %c\n",
962 rayTracing_useDistanceFilter ?
'Y' :
'N');
964 "rayTracing_decimation = %u\n",
965 rayTracing_decimation);
967 "rayTracing_stdHit = %f\n", rayTracing_stdHit);
969 "consensus_takeEachRange = %u\n",
970 consensus_takeEachRange);
972 "consensus_pow = %.02f\n", consensus_pow);
974 for (
size_t i = 0; i < OWA_weights.size(); i++)
976 if (i < 3 || i > (OWA_weights.size() - 3))
978 else if (i == 3 && OWA_weights.size() > 6)
981 out <<
mrpt::format(
"] (size=%u)\n", (
unsigned)OWA_weights.size());
double x() const
Common members of all points & poses classes.
bool isPlanarMap
If set to true, only HORIZONTAL (in the XY plane) measurements will be inserted in the map (Default v...
Declares a class derived from "CObservation" that encapsules a single range measurement, and associated parameters.
bool internal_canComputeObservationLikelihood(const mrpt::obs::CObservation *obs) const override
Returns true if this map is able to compute a sensible likelihood function for this observation (i...
const POINTSMAP * buildAuxPointsMap(const void *options=nullptr) const
Returns a cached points map representing this laser scan, building it upon the first call...
int16_t cellType
The type of the map cells:
A cloud of points in 2D or 3D, which can be built from a sequence of laser scans. ...
TInsertionOptions insertionOptions
With this struct options are provided to the observation insertion process.
void keep_min(T &var, const K test_val)
If the second argument is below the first one, set the first argument to this lower value...
void composePoint(double lx, double ly, double &gx, double &gy) const
An alternative, slightly more efficient way of doing with G and L being 2D points and P this 2D pose...
mrpt::containers::ContainerReadOnlyProxyAccessor< mrpt::aligned_std_vector< char > > validRange
It's false (=0) on no reflected rays, referenced to elements in scan.
float maxRange
The maximum range allowed by the device, in meters (e.g.
T square(const T x)
Inline function for the square of a number.
#define ASSERT_(f)
Defines an assertion mechanism.
With this struct options are provided to the observation insertion process.
A cloud of points in 2D or 3D, which can be built from a sequence of laser scans or other sensors...
This class allows loading and storing values and vectors of different types from a configuration text...
This base provides a set of functions for maths stuff.
bool insertObservationInto(METRICMAP *theMap, const mrpt::poses::CPose3D *robotPose=nullptr) const
This method is equivalent to:
#define CLASS_ID(T)
Access to runtime class ID for a defined class name.
mrpt::containers::ContainerReadOnlyProxyAccessor< mrpt::aligned_std_vector< float > > scan
The range values of the scan, in meters.
bool isPlanarScan(const double tolerance=0) const
Return true if the laser scanner is "horizontal", so it has an absolute value of "pitch" and "roll" l...
std::pair< double, mrpt::math::TPoint2D > TPairLikelihoodIndex
Auxiliary private class.
#define LIK_LF_CACHE_INVALID
This namespace contains representation of robot actions and observations.
string iniFile(myDataDir+string("benchmark-options.ini"))
void loadFromConfigFile(const mrpt::config::CConfigFileBase &source, const std::string §ion) override
This method load the options from a ".ini" file.
GLsizei const GLchar ** string
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
A class for storing an occupancy grid map.
unsigned long getPoint(size_t index, float &x, float &y, float &z) const
Access to a given point from map, as a 2D point.
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
A "CObservation"-derived class that represents a 2D range scan measurement (typically from a laser sc...
virtual const mrpt::rtti::TRuntimeClassId * GetRuntimeClass() const override
Returns information about the class of an object in runtime.
A class used to store a 2D pose, including the 2D coordinate point and a heading (phi) angle...
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
Declares a class that represents any robot's observation.
float horizontalTolerance
The tolerance in rads in pitch & roll for a laser scan to be considered horizontal, then processed by calls to this class (default=0).
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
const double & phi() const
Get the phi angle of the 2D pose (in radians)
#define IS_CLASS(ptrObj, class_name)
Evaluates to true if the given pointer to an object (derived from mrpt::rtti::CObject) is of the give...
bool useMapAltitude
The parameter "mapAltitude" has effect while inserting observations in the grid only if this is true...
float horizontalTolerance
The tolerance in rads in pitch & roll for a laser scan to be considered horizontal, considered only when isPlanarMap=true (default=0).
float aperture
The "aperture" or field-of-view of the range finder, in radians (typically M_PI = 180 degrees)...
float mapAltitude
The altitude (z-axis) of 2D scans (within a 0.01m tolerance) for they to be inserted in this map! ...
TInsertionOptions insertionOptions
The options used when inserting observations in the map.
size_t size() const
Returns the number of stored points in the map.
bool insertObservation(const mrpt::obs::CObservation *obs, const mrpt::poses::CPose3D *robotPose=NULL)
Insert the observation information into this map.
mrpt::poses::CPose3D sensorPose
The 6D pose of the sensor on the robot at the moment of starting the scan.
void dumpToTextStream(std::ostream &out) const override
This method should clearly display all the contents of the structure in textual form, sending it to a std::ostream.
bool rightToLeft
The scanning direction: true=counterclockwise; false=clockwise.
float minDistBetweenLaserPoints
The minimum distance between points (in 3D): If two points are too close, one of them is not inserted...
int round(const T value)
Returns the closer integer (int) to x.