33 double COccupancyGridMap2D::internal_computeObservationLikelihood(
42 if (!scan->
isPlanarScan(insertionOptions.horizontalTolerance))
44 if (insertionOptions.useMapAltitude &&
45 fabs(insertionOptions.mapAltitude - scan->
sensorPose.z()) > 0.01)
56 switch (likelihoodOptions.likelihoodMethod)
60 return computeObservationLikelihood_rayTracing(obs, takenFrom);
62 case lmMeanInformation:
63 return computeObservationLikelihood_MI(obs, takenFrom);
66 return computeObservationLikelihood_Consensus(obs, takenFrom);
68 case lmCellsDifference:
69 return computeObservationLikelihood_CellsDifference(obs, takenFrom);
71 case lmLikelihoodField_Thrun:
72 return computeObservationLikelihood_likelihoodField_Thrun(
75 case lmLikelihoodField_II:
76 return computeObservationLikelihood_likelihoodField_II(
80 return computeObservationLikelihood_ConsensusOWA(obs, takenFrom);
87 double COccupancyGridMap2D::computeObservationLikelihood_Consensus(
107 if (!o->
isPlanarScan(insertionOptions.horizontalTolerance))
124 const size_t n = compareMap->
size();
126 for (
size_t i = 0; i <
n; i += likelihoodOptions.consensus_takeEachRange)
129 compareMap->
getPoint(i, pointLocal);
132 int cx0 = x2idx(pointGlobal.
x);
133 int cy0 = y2idx(pointGlobal.
y);
135 likResult += 1 - getCell_nocheck(cx0, cy0);
138 if (Denom) likResult /= Denom;
140 pow(likResult, static_cast<double>(likelihoodOptions.consensus_pow));
142 return log(likResult);
148 double COccupancyGridMap2D::computeObservationLikelihood_ConsensusOWA(
151 double likResult = 0;
168 if (!o->
isPlanarScan(insertionOptions.horizontalTolerance))
185 const size_t n = compareMap->
size();
188 likelihoodOutputs.OWA_pairList.clear();
189 for (
size_t i = 0; i <
n; i++)
192 compareMap->
getPoint(i, pointLocal);
195 int cx0 = x2idx(pointGlobal.
x);
196 int cy0 = y2idx(pointGlobal.
y);
198 int cxMin = max(0, cx0 - Acells);
199 int cxMax =
min(static_cast<int>(size_x) - 1, cx0 + Acells);
200 int cyMin = max(0, cy0 - Acells);
201 int cyMax =
min(static_cast<int>(size_y) - 1, cy0 + Acells);
205 for (
int cx = cxMin; cx <= cxMax; cx++)
206 for (
int cy = cyMin; cy <= cyMax; cy++)
207 lik += 1 - getCell_nocheck(cx, cy);
209 int nCells = (cxMax - cxMin + 1) * (cyMax - cyMin + 1);
215 element.second = pointGlobal;
216 likelihoodOutputs.OWA_pairList.push_back(element);
222 likelihoodOutputs.OWA_pairList.begin(),
223 likelihoodOutputs.OWA_pairList.end());
226 size_t M = likelihoodOptions.OWA_weights.
size();
227 ASSERT_(likelihoodOutputs.OWA_pairList.size() >= M);
229 likelihoodOutputs.OWA_pairList.resize(M);
230 likelihoodOutputs.OWA_individualLikValues.resize(M);
232 for (
size_t k = 0; k < M; k++)
234 likelihoodOutputs.OWA_individualLikValues[k] =
235 likelihoodOutputs.OWA_pairList[k].first;
236 likResult += likelihoodOptions.OWA_weights[k] *
237 likelihoodOutputs.OWA_individualLikValues[k];
240 return log(likResult);
246 double COccupancyGridMap2D::computeObservationLikelihood_CellsDifference(
262 if (!o->
isPlanarScan(insertionOptions.horizontalTolerance))
267 takenFrom.
x() - 10, takenFrom.
x() + 10, takenFrom.
y() - 10,
268 takenFrom.
y() + 10, resolution);
273 compareGrid.insertionOptions.maxDistanceInsertion =
274 insertionOptions.maxDistanceInsertion;
275 compareGrid.insertionOptions.maxOccupancyUpdateCertainty = 0.95f;
279 Ax =
round((x_min - compareGrid.x_min) / resolution);
280 Ay =
round((y_min - compareGrid.y_min) / resolution);
282 int nCellsCompared = 0;
283 float cellsDifference = 0;
286 int x1 =
min(compareGrid.size_x, size_x + Ax);
287 int y1 =
min(compareGrid.size_y, size_y + Ay);
289 for (
int x = x0;
x < x1;
x += 1)
291 for (
int y = y0;
y < y1;
y += 1)
293 float xx = compareGrid.idx2x(
x);
294 float yy = compareGrid.idx2y(
y);
296 float c1 = getPos(xx, yy);
297 float c2 = compareGrid.getCell(
x,
y);
298 if (c2 < 0.45f || c2 > 0.55f)
301 if ((c1 > 0.5 && c2 < 0.5) || (c1 < 0.5 && c2 > 0.5))
306 ret = 1 - cellsDifference / (nCellsCompared);
314 double COccupancyGridMap2D::computeObservationLikelihood_MI(
323 updateInfoChangeOnly.enabled =
true;
324 insertionOptions.maxDistanceInsertion *=
325 likelihoodOptions.MI_ratio_max_distance;
328 updateInfoChangeOnly.cellsUpdated = 0;
329 updateInfoChangeOnly.I_change = 0;
330 updateInfoChangeOnly.laserRaysSkip = likelihoodOptions.MI_skip_rays;
334 insertObservation(obs, &poseRobot);
337 double newObservation_mean_I;
338 if (updateInfoChangeOnly.cellsUpdated)
339 newObservation_mean_I =
340 updateInfoChangeOnly.I_change / updateInfoChangeOnly.cellsUpdated;
342 newObservation_mean_I = 0;
345 updateInfoChangeOnly.enabled =
false;
346 insertionOptions.maxDistanceInsertion /=
347 likelihoodOptions.MI_ratio_max_distance;
350 pow(newObservation_mean_I,
351 static_cast<double>(likelihoodOptions.MI_exponent));
358 double COccupancyGridMap2D::computeObservationLikelihood_rayTracing(
375 if (!o->
isPlanarScan(insertionOptions.horizontalTolerance))
380 int decimation = likelihoodOptions.rayTracing_decimation;
397 double stdLaser = likelihoodOptions.rayTracing_stdHit;
398 double stdSqrt2 = sqrt(2.0f) * stdLaser;
406 for (
int j = 0; j < nRays; j += decimation)
409 r_sim = simulatedObs.
scan[j];
419 min((
float)fabs(r_sim - r_obs), 2.0f) / stdSqrt2));
420 ret += log(likelihood);
433 double COccupancyGridMap2D::computeObservationLikelihood_likelihoodField_Thrun(
451 if (!o->
isPlanarScan(insertionOptions.horizontalTolerance))
return -10;
461 ret = computeLikelihoodField_Thrun(
477 ret = computeLikelihoodField_Thrun(&pts, &takenFrom);
488 double COccupancyGridMap2D::computeObservationLikelihood_likelihoodField_II(
506 if (!o->
isPlanarScan(insertionOptions.horizontalTolerance))
513 ret = computeLikelihoodField_II(
526 double COccupancyGridMap2D::computeLikelihoodField_Thrun(
532 size_t N = pm->
size();
534 likelihoodOptions.LF_maxCorrsDistance /
537 bool Product_T_OrSum_F = !likelihoodOptions.LF_alternateAverageMethod;
547 float stdHit = likelihoodOptions.LF_stdHit;
548 float zHit = likelihoodOptions.LF_zHit;
549 float zRandom = likelihoodOptions.LF_zRandom;
550 float zRandomMaxRange = likelihoodOptions.LF_maxRange;
551 float zRandomTerm = zRandom / zRandomMaxRange;
552 float Q = -0.5f /
square(stdHit);
555 unsigned int size_x_1 = size_x - 1;
556 unsigned int size_y_1 = size_y - 1;
558 #define LIK_LF_CACHE_INVALID (66) 562 double maxCorrDist_sq =
square(likelihoodOptions.LF_maxCorrsDistance);
563 double minimumLik = zRandomTerm + zHit * exp(Q * maxCorrDist_sq);
565 float occupiedMinDist;
567 if (likelihoodOptions.enableLikelihoodCache)
570 if (precomputedLikelihoodToBeRecomputed)
575 precomputedLikelihood.clear();
577 precomputedLikelihoodToBeRecomputed =
false;
581 cellType thresholdCellValue = p2l(0.5f);
582 int decimation = likelihoodOptions.LF_decimation;
584 const double _resolution = this->resolution;
585 const double constDist2DiscrUnits = 100 / (_resolution * _resolution);
586 const double constDist2DiscrUnits_INV = 1.0 / constDist2DiscrUnits;
588 if (N < 10) decimation = 1;
593 for (
size_t j = 0; j < N; j += decimation)
595 occupiedMinDist = maxCorrDist_sq;
603 ::sincos(relativePose->
phi(), &ssin, &ccos);
605 ccos = cos(relativePose->
phi());
606 ssin = sin(relativePose->
phi());
609 relativePose->
x() + pointLocal.
x * ccos - pointLocal.
y * ssin;
611 relativePose->
y() + pointLocal.
x * ssin + pointLocal.
y * ccos;
619 int cx = x2idx(pointGlobal.
x);
620 int cy = y2idx(pointGlobal.
y);
624 if (static_cast<unsigned>(cx) >= size_x_1 ||
625 static_cast<unsigned>(cy) >= size_y_1)
629 thisLik = minimumLik;
634 if (likelihoodOptions.enableLikelihoodCache)
636 thisLik = precomputedLikelihood[cx + cy * size_x];
639 if (!likelihoodOptions.enableLikelihoodCache ||
646 int xx1 = max(0, cx - K);
647 int xx2 =
min(size_x_1, (
unsigned)(cx + K));
648 int yy1 = max(0, cy - K);
649 int yy2 =
min(size_y_1, (
unsigned)(cy + K));
654 &map[xx1 + yy1 * size_x];
655 unsigned incrAfterRow = size_x - ((xx2 - xx1) + 1);
657 signed int Ax0 = 10 * (xx1 - cx);
658 signed int Ay = 10 * (yy1 - cy);
661 maxCorrDist_sq * constDist2DiscrUnits);
663 for (
int yy = yy1; yy <= yy2; yy++)
666 square((
unsigned int)(Ay));
668 signed short Ax = Ax0;
671 for (
int xx = xx1; xx <= xx2; xx++)
673 if ((cell = *mapPtr++) < thresholdCellValue)
676 square((
unsigned int)(Ax)) + Ay2;
682 mapPtr += incrAfterRow;
687 occupiedMinDistInt * constDist2DiscrUnits_INV;
690 if (likelihoodOptions.LF_useSquareDist)
691 occupiedMinDist *= occupiedMinDist;
693 thisLik = zRandomTerm + zHit * exp(Q * occupiedMinDist);
695 if (likelihoodOptions.enableLikelihoodCache)
697 precomputedLikelihood[cx + cy * size_x] = thisLik;
702 if (Product_T_OrSum_F)
713 if (!Product_T_OrSum_F) ret = log(ret / M);
723 double COccupancyGridMap2D::computeLikelihoodField_II(
729 size_t N = pm->
size();
731 if (!N)
return 1e-100;
741 float zRandomTerm = 1.0f / likelihoodOptions.LF_maxRange;
742 float Q = -0.5f /
square(likelihoodOptions.LF_stdHit);
750 int maxRangeInCells =
751 (int)ceil(likelihoodOptions.LF_maxCorrsDistance / resolution);
757 for (j = 0; j < N; j += likelihoodOptions.LF_decimation)
764 pointGlobal = *relativePose + pointLocal;
773 cx0 = x2idx(pointGlobal.
x);
774 cy0 = y2idx(pointGlobal.
y);
778 cx_min = max(cx0 - maxRangeInCells, 0);
779 cx_max =
min(cx0 + maxRangeInCells, static_cast<int>(size_x));
780 cy_min = max(cy0 - maxRangeInCells, 0);
781 cy_max =
min(cy0 + maxRangeInCells, static_cast<int>(size_y));
788 for (cx = cx_min; cx <= cx_max; cx++)
790 for (cy = cy_min; cy <= cy_max; cy++)
792 float P_free = getCell(cx, cy);
794 exp(Q * (
square(idx2x(cx) - pointGlobal.
x) +
795 square(idx2y(cy) - pointGlobal.
y)));
797 lik += P_free * zRandomTerm + (1 - P_free) * termDist;
802 if (likelihoodOptions.LF_alternateAverageMethod)
805 ret += log(lik / ((cy_max - cy_min + 1) * (cx_max - cx_min + 1)));
810 if (likelihoodOptions.LF_alternateAverageMethod && nCells > 0)
811 ret = log(ret / nCells);
823 COccupancyGridMap2D::TLikelihoodOptions::TLikelihoodOptions()
824 : likelihoodMethod(lmLikelihoodField_Thrun),
831 LF_maxCorrsDistance(0.3f),
832 LF_useSquareDist(false),
833 LF_alternateAverageMethod(false),
837 MI_ratio_max_distance(1.5f),
839 rayTracing_useDistanceFilter(true),
840 rayTracing_decimation(10),
841 rayTracing_stdHit(1.0f),
843 consensus_takeEachRange(1),
845 OWA_weights(100, 1 / 100.0f),
847 enableLikelihoodCache(true)
858 iniFile.
read_enum(section,
"likelihoodMethod", likelihoodMethod);
860 enableLikelihoodCache = iniFile.
read_bool(
861 section,
"enableLikelihoodCache", enableLikelihoodCache);
863 LF_stdHit = iniFile.
read_float(section,
"LF_stdHit", LF_stdHit);
864 LF_zHit = iniFile.
read_float(section,
"LF_zHit", LF_zHit);
865 LF_zRandom = iniFile.
read_float(section,
"LF_zRandom", LF_zRandom);
866 LF_maxRange = iniFile.
read_float(section,
"LF_maxRange", LF_maxRange);
867 LF_decimation = iniFile.
read_int(section,
"LF_decimation", LF_decimation);
868 LF_maxCorrsDistance =
869 iniFile.
read_float(section,
"LF_maxCorrsDistance", LF_maxCorrsDistance);
871 iniFile.
read_bool(section,
"LF_useSquareDist", LF_useSquareDist);
872 LF_alternateAverageMethod = iniFile.
read_bool(
873 section,
"LF_alternateAverageMethod", LF_alternateAverageMethod);
875 MI_exponent = iniFile.
read_float(section,
"MI_exponent", MI_exponent);
876 MI_skip_rays = iniFile.
read_int(section,
"MI_skip_rays", MI_skip_rays);
878 section,
"MI_ratio_max_distance", MI_ratio_max_distance);
880 rayTracing_useDistanceFilter = iniFile.
read_bool(
881 section,
"rayTracing_useDistanceFilter", rayTracing_useDistanceFilter);
883 iniFile.
read_float(section,
"rayTracing_stdHit", rayTracing_stdHit);
885 consensus_takeEachRange = iniFile.
read_int(
886 section,
"consensus_takeEachRange", consensus_takeEachRange);
887 consensus_pow = iniFile.
read_float(section,
"consensus_pow", consensus_pow);
889 iniFile.
read_vector(section,
"OWA_weights", OWA_weights, OWA_weights);
899 "\n----------- [COccupancyGridMap2D::TLikelihoodOptions] ------------ " 902 out.
printf(
"likelihoodMethod = ");
903 switch (likelihoodMethod)
906 out.
printf(
"lmMeanInformation");
909 out.
printf(
"lmRayTracing");
912 out.
printf(
"lmConsensus");
915 out.
printf(
"lmCellsDifference");
918 out.
printf(
"lmLikelihoodField_Thrun");
921 out.
printf(
"lmLikelihoodField_II");
924 out.
printf(
"lmConsensusOWA");
933 "enableLikelihoodCache = %c\n",
934 enableLikelihoodCache ?
'Y' :
'N');
936 out.
printf(
"LF_stdHit = %f\n", LF_stdHit);
937 out.
printf(
"LF_zHit = %f\n", LF_zHit);
938 out.
printf(
"LF_zRandom = %f\n", LF_zRandom);
939 out.
printf(
"LF_maxRange = %f\n", LF_maxRange);
940 out.
printf(
"LF_decimation = %u\n", LF_decimation);
942 "LF_maxCorrsDistance = %f\n", LF_maxCorrsDistance);
944 "LF_useSquareDist = %c\n",
945 LF_useSquareDist ?
'Y' :
'N');
947 "LF_alternateAverageMethod = %c\n",
948 LF_alternateAverageMethod ?
'Y' :
'N');
949 out.
printf(
"MI_exponent = %f\n", MI_exponent);
950 out.
printf(
"MI_skip_rays = %u\n", MI_skip_rays);
952 "MI_ratio_max_distance = %f\n",
953 MI_ratio_max_distance);
955 "rayTracing_useDistanceFilter = %c\n",
956 rayTracing_useDistanceFilter ?
'Y' :
'N');
958 "rayTracing_decimation = %u\n",
959 rayTracing_decimation);
961 "rayTracing_stdHit = %f\n", rayTracing_stdHit);
963 "consensus_takeEachRange = %u\n",
964 consensus_takeEachRange);
966 "consensus_pow = %.02f\n", consensus_pow);
967 out.
printf(
"OWA_weights = [");
968 for (
size_t i = 0; i < OWA_weights.size(); i++)
970 if (i < 3 || i > (OWA_weights.size() - 3))
971 out.
printf(
"%.03f ", OWA_weights[i]);
972 else if (i == 3 && OWA_weights.size() > 6)
975 out.
printf(
"] (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...
bool read_bool(const std::string §ion, const std::string &name, bool defaultValue, bool failIfNotFound=false) const
Declares a class derived from "CObservation" that encapsules a single range measurement, and associated parameters.
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
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...
float read_float(const std::string §ion, const std::string &name, float defaultValue, bool failIfNotFound=false) const
const POINTSMAP * buildAuxPointsMap(const void *options=nullptr) const
Returns a cached points map representing this laser scan, building it upon the first call...
virtual const mrpt::utils::TRuntimeClassId * GetRuntimeClass() const override
Returns information about the class of an object in runtime.
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.
std::pair< double, mrpt::math::TPoint2D > TPairLikelihoodIndex
Auxiliary private class.
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...
This class allows loading and storing values and vectors of different types from a configuration text...
T square(const T x)
Inline function for the square of a number.
float maxRange
The maximum range allowed by the device, in meters (e.g.
int read_int(const std::string §ion, const std::string &name, int defaultValue, bool failIfNotFound=false) const
With this struct options are provided to the observation insertion process.
This base class is used to provide a unified interface to files,memory buffers,..Please see the deriv...
A cloud of points in 2D or 3D, which can be built from a sequence of laser scans or other sensors...
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.
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...
void read_vector(const std::string §ion, const std::string &name, const VECTOR_TYPE &defaultValue, VECTOR_TYPE &outValues, bool failIfNotFound=false) const
Reads a configuration parameter of type vector, stored in the file as a string: "[v1 v2 v3 ...
#define LIK_LF_CACHE_INVALID
void loadFromConfigFile(const mrpt::utils::CConfigFileBase &source, const std::string §ion) override
This method load the options from a ".ini" file.
This namespace contains representation of robot actions and observations.
mrpt::utils::ContainerReadOnlyProxyAccessor< std::vector< char > > validRange
It's false (=0) on no reflected rays, referenced to elements in scan.
GLsizei const GLchar ** string
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
ENUMTYPE read_enum(const std::string §ion, const std::string &name, const ENUMTYPE &defaultValue, bool failIfNotFound=false) const
Reads an "enum" value, where the value in the config file can be either a numerical value or the symb...
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...
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...
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).
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::utils::CSerializable) is of t...
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! ...
int round(const T value)
Returns the closer integer (int) to x.
TInsertionOptions insertionOptions
The options used when inserting observations in the map.
mrpt::utils::ContainerReadOnlyProxyAccessor< std::vector< float > > scan
The range values of the scan, in meters.
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.
int16_t cellType
The type of the map cells:
mrpt::poses::CPose3D sensorPose
The 6D pose of the sensor on the robot at the moment of starting the scan.
void dumpToTextStream(mrpt::utils::CStream &out) const override
This method should clearly display all the contents of the structure in textual form, sending it to a CStream.
virtual int printf(const char *fmt,...) MRPT_printf_format_check(2
Writes a string to the stream in a textual form.
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...