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);
274 insertionOptions.maxDistanceInsertion;
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);
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());
#define IS_CLASS(ptrObj, class_name)
Evaluates to true if the given pointer to an object (derived from mrpt::utils::CSerializable) is of t...
#define CLASS_ID(T)
Access to runtime class ID for a defined class name.
#define LIK_LF_CACHE_INVALID
bool insertObservation(const mrpt::obs::CObservation *obs, const mrpt::poses::CPose3D *robotPose=NULL)
Insert the observation information into this map.
float maxOccupancyUpdateCertainty
A value in the range [0.5,1] used for updating cell with a bayesian approach (default 0....
float mapAltitude
The altitude (z-axis) of 2D scans (within a 0.01m tolerance) for they to be inserted in this map!
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,...
float maxDistanceInsertion
The largest distance at which cells will be updated (Default 15 meters)
void dumpToTextStream(mrpt::utils::CStream &out) const override
This method should clearly display all the contents of the structure in textual form,...
void loadFromConfigFile(const mrpt::utils::CConfigFileBase &source, const std::string §ion) override
This method load the options from a ".ini" file.
A class for storing an occupancy grid map.
TInsertionOptions insertionOptions
With this struct options are provided to the observation insertion process.
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....
std::pair< double, mrpt::math::TPoint2D > TPairLikelihoodIndex
Auxiliary private class.
@ lmLikelihoodField_Thrun
float idx2y(const size_t cy) const
float getCell(int x, int y) const
Read the real valued [0,1] contents of a cell, given its index.
uint32_t size_x
The size of the grid in cells.
float idx2x(const size_t cx) const
Transform a cell index into a coordinate value.
int16_t cellType
The type of the map cells:
float x_min
The limits of the grid in "units" (meters)
A cloud of points in 2D or 3D, which can be built from a sequence of laser scans or other sensors.
size_t size() const
Returns the number of stored points in the 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.
TInsertionOptions insertionOptions
The options used when inserting observations in the map.
A cloud of points in 2D or 3D, which can be built from a sequence of laser scans.
A "CObservation"-derived class that represents a 2D range scan measurement (typically from a laser sc...
float maxRange
The maximum range allowed by the device, in meters (e.g.
const POINTSMAP * buildAuxPointsMap(const void *options=nullptr) const
Returns a cached points map representing this laser scan, building it upon the first call.
mrpt::utils::ContainerReadOnlyProxyAccessor< std::vector< char > > validRange
It's false (=0) on no reflected rays, referenced to elements in scan.
float aperture
The "aperture" or field-of-view of the range finder, in radians (typically M_PI = 180 degrees).
mrpt::poses::CPose3D sensorPose
The 6D pose of the sensor on the robot at the moment of starting the scan.
bool rightToLeft
The scanning direction: true=counterclockwise; false=clockwise.
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...
mrpt::utils::ContainerReadOnlyProxyAccessor< std::vector< float > > scan
The range values of the scan, in meters.
Declares a class that represents any robot's observation.
virtual const mrpt::utils::TRuntimeClassId * GetRuntimeClass() const override
Returns information about the class of an object in runtime.
bool insertObservationInto(METRICMAP *theMap, const mrpt::poses::CPose3D *robotPose=nullptr) const
This method is equivalent to:
Declares a class derived from "CObservation" that encapsules a single range measurement,...
A class used to store a 2D pose, including the 2D coordinate point and a heading (phi) angle.
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...
const double & phi() const
Get the phi angle of the 2D pose (in radians)
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
double x() const
Common members of all points & poses classes.
This class allows loading and storing values and vectors of different types from a configuration text...
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 ....
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...
bool read_bool(const std::string §ion, const std::string &name, bool defaultValue, bool failIfNotFound=false) const
int read_int(const std::string §ion, const std::string &name, int defaultValue, bool failIfNotFound=false) const
float read_float(const std::string §ion, const std::string &name, float defaultValue, bool failIfNotFound=false) const
This base class is used to provide a unified interface to files,memory buffers,..Please see the deriv...
virtual int printf(const char *fmt,...) MRPT_printf_format_check(2
Writes a string to the stream in a textual form.
GLsizei const GLchar ** string
int round(const T value)
Returns the closer integer (int) to x.
This base provides a set of functions for maths stuff.
T square(const T x)
Inline function for the square of a number.
This namespace contains representation of robot actions and observations.
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values,...
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.
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
With this struct options are provided to the observation insertion process.
float minDistBetweenLaserPoints
The minimum distance between points (in 3D): If two points are too close, one of them is not inserted...
bool isPlanarMap
If set to true, only HORIZONTAL (in the XY plane) measurements will be inserted in the map (Default v...
float horizontalTolerance
The tolerance in rads in pitch & roll for a laser scan to be considered horizontal,...