00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #ifndef __OccGridMapUtil_h_
00030 #define __OccGridMapUtil_h_
00031
00032 #include <cmath>
00033
00034 #include "../scan/DataPointContainer.h"
00035 #include "../util/UtilFunctions.h"
00036
00037 namespace hectorslam {
00038
00039 template<typename ConcreteOccGridMap, typename ConcreteCacheMethod>
00040 class OccGridMapUtil
00041 {
00042 public:
00043
00044 OccGridMapUtil(const ConcreteOccGridMap* gridMap)
00045 : concreteGridMap(gridMap)
00046 , size(0)
00047 {
00048 mapObstacleThreshold = gridMap->getObstacleThreshold();
00049 cacheMethod.setMapSize(gridMap->getMapDimensions());
00050 }
00051
00052 ~OccGridMapUtil()
00053 {}
00054
00055 public:
00056
00057 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
00058
00059 inline Eigen::Vector3f getWorldCoordsPose(const Eigen::Vector3f& mapPose) const { return concreteGridMap->getWorldCoordsPose(mapPose); };
00060 inline Eigen::Vector3f getMapCoordsPose(const Eigen::Vector3f& worldPose) const { return concreteGridMap->getMapCoordsPose(worldPose); };
00061
00062 inline Eigen::Vector2f getWorldCoordsPoint(const Eigen::Vector2f& mapPoint) const { return concreteGridMap->getWorldCoords(mapPoint); };
00063
00064 void getCompleteHessianDerivs(const Eigen::Vector3f& pose, const DataContainer& dataPoints, Eigen::Matrix3f& H, Eigen::Vector3f& dTr)
00065 {
00066 int size = dataPoints.getSize();
00067
00068 Eigen::Affine2f transform(getTransformForState(pose));
00069
00070 float sinRot = sin(pose[2]);
00071 float cosRot = cos(pose[2]);
00072
00073 H = Eigen::Matrix3f::Zero();
00074 dTr = Eigen::Vector3f::Zero();
00075
00076 for (int i = 0; i < size; ++i) {
00077
00078 const Eigen::Vector2f& currPoint (dataPoints.getVecEntry(i));
00079
00080 Eigen::Vector3f transformedPointData(interpMapValueWithDerivatives(transform * currPoint));
00081
00082 float funVal = 1.0f - transformedPointData[0];
00083
00084 dTr[0] += transformedPointData[1] * funVal;
00085 dTr[1] += transformedPointData[2] * funVal;
00086
00087 float rotDeriv = ((-sinRot * currPoint.x() - cosRot * currPoint.y()) * transformedPointData[1] + (cosRot * currPoint.x() - sinRot * currPoint.y()) * transformedPointData[2]);
00088
00089 dTr[2] += rotDeriv * funVal;
00090
00091 H(0, 0) += util::sqr(transformedPointData[1]);
00092 H(1, 1) += util::sqr(transformedPointData[2]);
00093 H(2, 2) += util::sqr(rotDeriv);
00094
00095 H(0, 1) += transformedPointData[1] * transformedPointData[2];
00096 H(0, 2) += transformedPointData[1] * rotDeriv;
00097 H(1, 2) += transformedPointData[2] * rotDeriv;
00098 }
00099
00100 H(1, 0) = H(0, 1);
00101 H(2, 0) = H(0, 2);
00102 H(2, 1) = H(1, 2);
00103
00104 }
00105
00106 Eigen::Matrix3f getCovarianceForPose(const Eigen::Vector3f& mapPose, const DataContainer& dataPoints)
00107 {
00108
00109 float deltaTransX = 1.5f;
00110 float deltaTransY = 1.5f;
00111 float deltaAng = 0.05f;
00112
00113 float x = mapPose[0];
00114 float y = mapPose[1];
00115 float ang = mapPose[2];
00116
00117 Eigen::Matrix<float, 3, 7> sigmaPoints;
00118
00119 sigmaPoints.block<3, 1>(0, 0) = Eigen::Vector3f(x + deltaTransX, y, ang);
00120 sigmaPoints.block<3, 1>(0, 1) = Eigen::Vector3f(x - deltaTransX, y, ang);
00121 sigmaPoints.block<3, 1>(0, 2) = Eigen::Vector3f(x, y + deltaTransY, ang);
00122 sigmaPoints.block<3, 1>(0, 3) = Eigen::Vector3f(x, y - deltaTransY, ang);
00123 sigmaPoints.block<3, 1>(0, 4) = Eigen::Vector3f(x, y, ang + deltaAng);
00124 sigmaPoints.block<3, 1>(0, 5) = Eigen::Vector3f(x, y, ang - deltaAng);
00125 sigmaPoints.block<3, 1>(0, 6) = mapPose;
00126
00127 Eigen::Matrix<float, 7, 1> likelihoods;
00128
00129 likelihoods[0] = getLikelihoodForState(Eigen::Vector3f(x + deltaTransX, y, ang), dataPoints);
00130 likelihoods[1] = getLikelihoodForState(Eigen::Vector3f(x - deltaTransX, y, ang), dataPoints);
00131 likelihoods[2] = getLikelihoodForState(Eigen::Vector3f(x, y + deltaTransY, ang), dataPoints);
00132 likelihoods[3] = getLikelihoodForState(Eigen::Vector3f(x, y - deltaTransY, ang), dataPoints);
00133 likelihoods[4] = getLikelihoodForState(Eigen::Vector3f(x, y, ang + deltaAng), dataPoints);
00134 likelihoods[5] = getLikelihoodForState(Eigen::Vector3f(x, y, ang - deltaAng), dataPoints);
00135 likelihoods[6] = getLikelihoodForState(Eigen::Vector3f(x, y, ang), dataPoints);
00136
00137 float invLhNormalizer = 1 / likelihoods.sum();
00138
00139 std::cout << "\n lhs:\n" << likelihoods;
00140
00141 Eigen::Vector3f mean(Eigen::Vector3f::Zero());
00142
00143 for (int i = 0; i < 7; ++i) {
00144 mean += (sigmaPoints.block<3, 1>(0, i) * likelihoods[i]);
00145 }
00146
00147 mean *= invLhNormalizer;
00148
00149 Eigen::Matrix3f covMatrixMap(Eigen::Matrix3f::Zero());
00150
00151 for (int i = 0; i < 7; ++i) {
00152 Eigen::Vector3f sigPointMinusMean(sigmaPoints.block<3, 1>(0, i) - mean);
00153 covMatrixMap += (likelihoods[i] * invLhNormalizer) * (sigPointMinusMean * (sigPointMinusMean.transpose()));
00154 }
00155
00156 return covMatrixMap;
00157
00158
00159
00160 }
00161
00162 Eigen::Matrix3f getCovMatrixWorldCoords(const Eigen::Matrix3f& covMatMap)
00163 {
00164
00165
00166
00167 Eigen::Matrix3f covMatWorld;
00168
00169 float scaleTrans = concreteGridMap->getCellLength();
00170 float scaleTransSq = util::sqr(scaleTrans);
00171
00172 covMatWorld(0, 0) = covMatMap(0, 0) * scaleTransSq;
00173 covMatWorld(1, 1) = covMatMap(1, 1) * scaleTransSq;
00174
00175 covMatWorld(1, 0) = covMatMap(1, 0) * scaleTransSq;
00176 covMatWorld(0, 1) = covMatWorld(1, 0);
00177
00178 covMatWorld(2, 0) = covMatMap(2, 0) * scaleTrans;
00179 covMatWorld(0, 2) = covMatWorld(2, 0);
00180
00181 covMatWorld(2, 1) = covMatMap(2, 1) * scaleTrans;
00182 covMatWorld(1, 2) = covMatWorld(2, 1);
00183
00184 covMatWorld(2, 2) = covMatMap(2, 2);
00185
00186 return covMatWorld;
00187 }
00188
00189 float getLikelihoodForState(const Eigen::Vector3f& state, const DataContainer& dataPoints)
00190 {
00191 float resid = getResidualForState(state, dataPoints);
00192
00193 return getLikelihoodForResidual(resid, dataPoints.getSize());
00194 }
00195
00196 float getLikelihoodForResidual(float residual, int numDataPoints)
00197 {
00198 float numDataPointsA = static_cast<int>(numDataPoints);
00199 float sizef = static_cast<float>(numDataPointsA);
00200
00201 return 1 - (residual / sizef);
00202 }
00203
00204 float getResidualForState(const Eigen::Vector3f& state, const DataContainer& dataPoints)
00205 {
00206 int size = dataPoints.getSize();
00207
00208 int stepSize = 1;
00209 float residual = 0.0f;
00210
00211
00212 Eigen::Affine2f transform(getTransformForState(state));
00213
00214 for (int i = 0; i < size; i += stepSize) {
00215
00216 float funval = 1.0f - interpMapValue(transform * dataPoints.getVecEntry(i));
00217 residual += funval;
00218 }
00219
00220 return residual;
00221 }
00222
00223 float getUnfilteredGridPoint(Eigen::Vector2i& gridCoords) const
00224 {
00225 return (concreteGridMap->getGridProbabilityMap(gridCoords.x(), gridCoords.y()));
00226 }
00227
00228 float getUnfilteredGridPoint(int index) const
00229 {
00230 return (concreteGridMap->getGridProbabilityMap(index));
00231 }
00232
00233 float interpMapValue(const Eigen::Vector2f& coords)
00234 {
00235
00236 if (concreteGridMap->pointOutOfMapBounds(coords)){
00237 return 0.0f;
00238 }
00239
00240
00241 Eigen::Vector2i indMin(coords.cast<int>());
00242
00243
00244 Eigen::Vector2f factors(coords - indMin.cast<float>());
00245
00246 int sizeX = concreteGridMap->getSizeX();
00247
00248 int index = indMin[1] * sizeX + indMin[0];
00249
00250
00251
00252 if (!cacheMethod.containsCachedData(index, intensities[0])) {
00253 intensities[0] = getUnfilteredGridPoint(index);
00254 cacheMethod.cacheData(index, intensities[0]);
00255 }
00256
00257 ++index;
00258
00259 if (!cacheMethod.containsCachedData(index, intensities[1])) {
00260 intensities[1] = getUnfilteredGridPoint(index);
00261 cacheMethod.cacheData(index, intensities[1]);
00262 }
00263
00264 index += sizeX-1;
00265
00266 if (!cacheMethod.containsCachedData(index, intensities[2])) {
00267 intensities[2] = getUnfilteredGridPoint(index);
00268 cacheMethod.cacheData(index, intensities[2]);
00269 }
00270
00271 ++index;
00272
00273 if (!cacheMethod.containsCachedData(index, intensities[3])) {
00274 intensities[3] = getUnfilteredGridPoint(index);
00275 cacheMethod.cacheData(index, intensities[3]);
00276 }
00277
00278 float xFacInv = (1.0f - factors[0]);
00279 float yFacInv = (1.0f - factors[1]);
00280
00281 return
00282 ((intensities[0] * xFacInv + intensities[1] * factors[0]) * (yFacInv)) +
00283 ((intensities[2] * xFacInv + intensities[3] * factors[0]) * (factors[1]));
00284
00285 }
00286
00287 Eigen::Vector3f interpMapValueWithDerivatives(const Eigen::Vector2f& coords)
00288 {
00289
00290 if (concreteGridMap->pointOutOfMapBounds(coords)){
00291 return Eigen::Vector3f(0.0f, 0.0f, 0.0f);
00292 }
00293
00294
00295 Eigen::Vector2i indMin(coords.cast<int>());
00296
00297
00298 Eigen::Vector2f factors(coords - indMin.cast<float>());
00299
00300 int sizeX = concreteGridMap->getSizeX();
00301
00302 int index = indMin[1] * sizeX + indMin[0];
00303
00304
00305
00306 if (!cacheMethod.containsCachedData(index, intensities[0])) {
00307 intensities[0] = getUnfilteredGridPoint(index);
00308 cacheMethod.cacheData(index, intensities[0]);
00309 }
00310
00311 ++index;
00312
00313 if (!cacheMethod.containsCachedData(index, intensities[1])) {
00314 intensities[1] = getUnfilteredGridPoint(index);
00315 cacheMethod.cacheData(index, intensities[1]);
00316 }
00317
00318 index += sizeX-1;
00319
00320 if (!cacheMethod.containsCachedData(index, intensities[2])) {
00321 intensities[2] = getUnfilteredGridPoint(index);
00322 cacheMethod.cacheData(index, intensities[2]);
00323 }
00324
00325 ++index;
00326
00327 if (!cacheMethod.containsCachedData(index, intensities[3])) {
00328 intensities[3] = getUnfilteredGridPoint(index);
00329 cacheMethod.cacheData(index, intensities[3]);
00330 }
00331
00332 float dx1 = intensities[0] - intensities[1];
00333 float dx2 = intensities[2] - intensities[3];
00334
00335 float dy1 = intensities[0] - intensities[2];
00336 float dy2 = intensities[1] - intensities[3];
00337
00338 float xFacInv = (1.0f - factors[0]);
00339 float yFacInv = (1.0f - factors[1]);
00340
00341 return Eigen::Vector3f(
00342 ((intensities[0] * xFacInv + intensities[1] * factors[0]) * (yFacInv)) +
00343 ((intensities[2] * xFacInv + intensities[3] * factors[0]) * (factors[1])),
00344 -((dx1 * xFacInv) + (dx2 * factors[0])),
00345 -((dy1 * yFacInv) + (dy2 * factors[1]))
00346 );
00347 }
00348
00349 Eigen::Affine2f getTransformForState(const Eigen::Vector3f& transVector) const
00350 {
00351 return Eigen::Translation2f(transVector[0], transVector[1]) * Eigen::Rotation2Df(transVector[2]);
00352 }
00353
00354 Eigen::Translation2f getTranslationForState(const Eigen::Vector3f& transVector) const
00355 {
00356 return Eigen::Translation2f(transVector[0], transVector[1]);
00357 }
00358
00359 void resetCachedData()
00360 {
00361 cacheMethod.resetCache();
00362 }
00363
00364 void resetSamplePoints()
00365 {
00366 samplePoints.clear();
00367 }
00368
00369 const std::vector<Eigen::Vector3f>& getSamplePoints() const
00370 {
00371 return samplePoints;
00372 }
00373
00374 protected:
00375
00376 Eigen::Vector4f intensities;
00377
00378 ConcreteCacheMethod cacheMethod;
00379
00380 const ConcreteOccGridMap* concreteGridMap;
00381
00382 std::vector<Eigen::Vector3f> samplePoints;
00383
00384 int size;
00385
00386 float mapObstacleThreshold;
00387 };
00388
00389 }
00390
00391
00392 #endif