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);
273 insertionOptions.maxDistanceInsertion;
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);
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());
#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...
#define CLASS_ID(T)
Access to runtime class ID for a defined class name.
#define LIK_LF_CACHE_INVALID
This class allows loading and storing values and vectors of different types from a configuration text...
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(std::ostream &out) const override
This method should clearly display all the contents of the structure in textual form,...
void loadFromConfigFile(const mrpt::config::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....
@ lmLikelihoodField_Thrun
std::pair< double, mrpt::math::TPoint2D > TPairLikelihoodIndex
Auxiliary private class.
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.
int16_t cellType
The type of the map cells:
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.
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.
float aperture
The "aperture" or field-of-view of the range finder, in radians (typically M_PI = 180 degrees).
mrpt::containers::ContainerReadOnlyProxyAccessor< mrpt::aligned_std_vector< char > > validRange
It's false (=0) on no reflected rays, referenced to elements in scan.
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::containers::ContainerReadOnlyProxyAccessor< mrpt::aligned_std_vector< float > > scan
The range values of the scan, in meters.
Declares a class that represents any robot's observation.
bool insertObservationInto(METRICMAP *theMap, const mrpt::poses::CPose3D *robotPose=nullptr) const
This method is equivalent to:
virtual const mrpt::rtti::TRuntimeClassId * GetRuntimeClass() const override
Returns information about the class of an object in runtime.
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.
#define ASSERT_(f)
Defines an assertion mechanism.
GLsizei const GLchar ** string
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
int round(const T value)
Returns the closer integer (int) to x.
This base provides a set of functions for maths stuff.
This namespace contains representation of robot actions and observations.
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
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.
T square(const T x)
Inline function for the square of a number.
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,...
string iniFile(myDataDir+string("benchmark-options.ini"))