ThreadLocalize.cpp
Go to the documentation of this file.
00001 /*
00002  * ThreadLocalize.cpp
00003  *
00004  *  Created on: 28.10.2014
00005  *      Author: phil
00006  */
00007 
00008 #include "ThreadLocalize.h"
00009 
00010 #include "SlamNode.h"
00011 #include "ThreadMapping.h"
00012 
00013 #include "obcore/math/linalg/linalg.h"
00014 #include "obcore/base/Logger.h"
00015 #include "obvision/registration/ransacMatching/RansacMatching.h"
00016 #include "obvision/registration/ransacMatching/RandomNormalMatching.h"
00017 
00018 #include <boost/bind.hpp>
00019 
00020 #include <cstring>
00021 #include <unistd.h>
00022 
00023 #include <geometry_msgs/PoseStamped.h>
00024 #include <tf/tf.h>
00025 
00026 namespace ohm_tsd_slam
00027 {
00028 
00029 ThreadLocalize::ThreadLocalize(obvious::TsdGrid* grid, ThreadMapping* mapper, ros::NodeHandle* nh, std::string nameSpace,
00030     const double xOffset, const double yOffset):
00031                     ThreadSLAM(*grid),
00032                     _nh(nh),
00033                     _mapper(*mapper),
00034                     _sensor(NULL),
00035                     _initialized(false),
00036                     _gridWidth(grid->getCellsX() * grid->getCellSize()),
00037                     _gridHeight(grid->getCellsY() * grid->getCellSize()),
00038                     _gridOffSetX(-1.0 * (grid->getCellsX() * grid->getCellSize() * 0.5 + xOffset)),
00039                     _gridOffSetY(-1.0 * (grid->getCellsY()* grid->getCellSize() * 0.5 + yOffset)),
00040                     _xOffset(xOffset),
00041                     _yOffset(yOffset),
00042                     _nameSpace(nameSpace)
00043 {
00044   ros::NodeHandle prvNh("~");
00045 
00046   /*** Read parameters from ros parameter server. Use namespace if provided ***/
00047   std::string::iterator it = _nameSpace.end() - 1;
00048     if (*it != '/' && _nameSpace.size() > 0)   //slash at the end required
00049       _nameSpace += "/";
00050 
00051   //pose
00052   std::string poseTopic;
00053   prvNh.param(_nameSpace + "pose_topic", poseTopic, std::string("default_ns/pose"));
00054   poseTopic = _nameSpace + poseTopic;
00055 
00056   //frames
00057   std::string tfBaseFrameId;
00058   prvNh.param("tf_base_frame", tfBaseFrameId, std::string("/map"));
00059 
00060   std::string tfChildFrameId;
00061   prvNh.param(_nameSpace + "tf_child_frame", tfChildFrameId, std::string("default_ns/laser"));
00062 
00063   double distFilterMax = 0.0;
00064   double distFilterMin = 0.0;
00065   int icpIterations = 0;
00066 
00067   //ICP Options
00068   prvNh.param<double>(_nameSpace + "dist_filter_min", distFilterMin, DIST_FILT_MIN);
00069   prvNh.param<double>(_nameSpace + "dist_filter_max", distFilterMax, DIST_FILT_MAX);
00070   prvNh.param<int>(_nameSpace + "icp_iterations", icpIterations, ICP_ITERATIONS);
00071 
00072   //Maximum allowed offset between to aligned scans
00073   prvNh.param<double>("reg_trs_max", _trnsMax, TRNS_THRESH);
00074   prvNh.param<double>("reg_sin_rot_max", _rotMax, ROT_THRESH);
00075 
00076   //ransac options
00077   int paramInt = 0;
00078   prvNh.param<int>(nameSpace + "ransac_trials", paramInt, RANSAC_TRIALS);
00079   _ranTrials = static_cast<unsigned int>(paramInt);
00080   prvNh.param<double>(nameSpace + "ransac_eps_thresh", _ranEpsThresh, RANSAC_EPS_THRESH);
00081   prvNh.param<int>(nameSpace + "ransac_ctrlset_size", paramInt, RANSAC_CTRL_SET_SIZE);
00082   _ranSizeCtrlSet = static_cast<unsigned int>(paramInt);
00083   prvNh.param<double>(_nameSpace + "ransac_phi_max", _ranPhiMax, 30.0);
00084 
00085   int iVar = 0;
00086   prvNh.param<int>(_nameSpace + "registration_mode", iVar, ICP);
00087   _regMode = static_cast<EnumRegModes>(iVar);
00088 
00089   _modelCoords  = NULL;
00090   _modelNormals = NULL;
00091   _maskM        = NULL;
00092   _rayCaster    = NULL;
00093   _scene        = NULL;
00094   _maskS        = NULL;
00095 
00097   _lastPose         = new obvious::Matrix(3, 3);
00098   _rayCaster        = new obvious::RayCastPolar2D();
00099   _assigner         = new obvious::FlannPairAssignment(2);
00100   _filterDist       = new obvious::DistanceFilter(distFilterMax, distFilterMin, icpIterations - 10);
00101   _filterReciprocal = new obvious::ReciprocalFilter();
00102   _estimator        = new obvious::ClosedFormEstimator2D();
00103 
00104   //configure ICP
00105   _filterBounds = new obvious::OutOfBoundsFilter2D(grid->getMinX(), grid->getMaxX(), grid->getMinY(), grid->getMaxY());
00106   _assigner->addPreFilter(_filterBounds);
00107   _assigner->addPostFilter(_filterDist);
00108   _assigner->addPostFilter(_filterReciprocal);
00109   _icp = new obvious::Icp(_assigner, _estimator);
00110   _icp->setMaxRMS(0.0);
00111   _icp->setMaxIterations(icpIterations);
00112   _icp->setConvergenceCounter(icpIterations);
00113 
00114   _posePub = _nh->advertise<geometry_msgs::PoseStamped>(poseTopic, 1);
00115   _poseStamped.header.frame_id = tfBaseFrameId;
00116   _tf.frame_id_                = tfBaseFrameId;
00117   _tf.child_frame_id_          = _nameSpace + tfChildFrameId;
00118 }
00119 
00120 ThreadLocalize::~ThreadLocalize()
00121 {
00122   delete _sensor;
00123   for(std::deque<sensor_msgs::LaserScan*>::iterator iter = _laserData.begin(); iter < _laserData.end(); iter++)
00124     delete *iter;
00125   _stayActive = false;
00126   _thread->join();
00127   _laserData.clear();
00128 }
00129 
00130 void ThreadLocalize::laserCallBack(const sensor_msgs::LaserScan& scan)
00131 {
00132   if(!_initialized)
00133   {
00134     ROS_INFO_STREAM("Localizer(" << _nameSpace << ") received first scan. Initialize node...\n");
00135     this->init(scan);
00136     ROS_INFO_STREAM("Localizer(" << _nameSpace << ") initialized -> running...\n");
00137     return;
00138   }
00139   sensor_msgs::LaserScan* scanCopy = new sensor_msgs::LaserScan;
00140   *scanCopy = scan;
00141   _dataMutex.lock();
00142   _laserData.push_front(scanCopy);
00143   _dataMutex.unlock();
00144   this->unblock();
00145 }
00146 
00147 void ThreadLocalize::eventLoop(void)
00148 {
00149   _sleepCond.wait(_sleepMutex);
00150   while(_stayActive)
00151   {
00152 
00153     if(!_laserData.size())
00154     {
00155       _sleepCond.wait(_sleepMutex);
00156     }
00157 
00158     _dataMutex.lock();
00159     _sensor->setRealMeasurementData(_laserData.front()->ranges);
00160     _sensor->setStandardMask();
00161 
00162     for(std::deque<sensor_msgs::LaserScan*>::iterator iter = _laserData.begin(); iter < _laserData.end(); iter++)
00163       delete *iter;
00164     _laserData.clear();
00165     _dataMutex.unlock();
00166 
00167     const unsigned int measurementSize = _sensor->getRealMeasurementSize();
00168 
00169     if(!_scene)   //first call, initialize buffers
00170     {
00171       _scene        = new double[measurementSize * 2];
00172       _maskS        = new bool[measurementSize];
00173       _modelCoords  = new double[measurementSize * 2];
00174       _modelNormals = new double[measurementSize * 2];
00175       _maskM        = new bool[measurementSize];
00176       *_lastPose    = _sensor->getTransformation();
00177     }
00178 
00179     // reconstruction
00180     unsigned int validModelPoints = _rayCaster->calcCoordsFromCurrentViewMask(&_grid, _sensor, _modelCoords, _modelNormals, _maskM);
00181     if(validModelPoints == 0)
00182     {
00183       ROS_ERROR_STREAM("Localizer(" << _nameSpace <<") error! Raycasting found no coordinates!\n");
00184       continue;
00185     }
00186 
00187     //get current scan
00188     const unsigned int validScenePoints = _sensor->dataToCartesianVectorMask(_scene, _maskS);
00189     //_sensor->dataToCartesianVector(_scene);
00190 
00196     obvious::Matrix M(measurementSize, 2, _modelCoords);
00197     obvious::Matrix N(measurementSize, 2, _modelNormals);
00198     obvious::Matrix Mvalid = maskMatrix(&M, _maskM, measurementSize, validModelPoints);
00199     obvious::Matrix Nvalid = maskMatrix(&N, _maskM, measurementSize, validModelPoints);
00200     obvious::Matrix S(measurementSize, 2, _scene);
00201     obvious::Matrix Svalid = maskMatrix(&S, _maskS, measurementSize, validScenePoints);
00202     obvious::Matrix T(3, 3);
00203 
00205     bool experimental = false;
00206     switch(_regMode)
00207     {
00208     case ICP:
00209       experimental = false;
00210       break;
00211     case EXP:
00212       experimental = true;
00213       break;
00214     default:
00215       ROS_ERROR_STREAM("Unknown registration mode " << _regMode << " use default" << std::endl);
00216       experimental = false;
00217       break;
00218     }
00219 
00220     T = doRegistration(_sensor, &M, &Mvalid, &N, &Nvalid, &S, &Svalid, experimental);  //3x3 Transformation Matrix
00221 
00223     _tf.stamp_ = ros::Time::now();
00224     const bool regErrorT = isRegistrationError(&T, _trnsMax, _rotMax);
00225     if(regErrorT)
00226     {
00227       ROS_ERROR_STREAM("Localizer(" << _nameSpace << ") registration error! \n");
00228       sendNanTransform();
00229     }
00230     else //transformation valid -> transform sensor and publish new sensor pose
00231     {
00232       _sensor->transform(&T);
00233       obvious::Matrix curPose = _sensor->getTransformation();
00234       sendTransform(&curPose);
00236       if(this->isPoseChangeSignificant(_lastPose, &curPose))
00237       {
00238         *_lastPose = curPose;
00239         _mapper.queuePush(_sensor);
00240       }
00241     }
00242   }
00243 }
00244 
00245 void ThreadLocalize::init(const sensor_msgs::LaserScan& scan)
00246 {
00247   double localXoffset         = 0.0;
00248   double localYoffset         = 0.0;
00249   double localYawOffset       = 0.0;
00250   double maxRange             = 0.0;
00251   double minRange             = 0.0;
00252   double lowReflectivityRange = 0.0;
00253   double footPrintWidth       = 0.0;
00254   double footPrintHeight      = 0.0;
00255   double footPrintXoffset     = 0.0;
00256 
00257   ros::NodeHandle prvNh("~");
00258 
00259   prvNh.param<double>(_nameSpace + "local_offset_x"        ,localXoffset        ,0.0);
00260   prvNh.param<double>(_nameSpace + "local_offset_y"        ,localYoffset        ,0.0);
00261   prvNh.param<double>(_nameSpace + "local_offset_yaw"      ,localYawOffset      ,0.0);
00262   prvNh.param<double>(_nameSpace + "max_range"             ,maxRange            ,30.0);
00263   prvNh.param<double>(_nameSpace + "min_range"             ,minRange            ,0.001);
00264   prvNh.param<double>(_nameSpace + "low_reflectivity_range",lowReflectivityRange,2.0);
00265   prvNh.param<double>(_nameSpace + "footprint_width"       ,footPrintWidth      ,1.0);
00266   prvNh.param<double>(_nameSpace + "footprint_height"      ,footPrintHeight     ,1.0);
00267   prvNh.param<double>(_nameSpace + "footprint_x_offset"    ,footPrintXoffset    ,0.28);
00268 
00269   const double phi    = localYawOffset;
00270     const double startX = _gridWidth * 0.5 + _xOffset + localXoffset;
00271     const double startY = _gridWidth * 0.5 + _yOffset + localYoffset;
00272   double tf[9]  = {std::cos(phi), -std::sin(phi), startX,
00273       std::sin(phi),  std::cos(phi), startY,
00274       0,              0,      1};
00275   obvious::Matrix Tinit(3, 3);
00276   Tinit.setData(tf);
00277 
00278   _sensor = new obvious::SensorPolar2D(scan.ranges.size(), scan.angle_increment, scan.angle_min, maxRange, minRange, lowReflectivityRange);
00279   _sensor->setRealMeasurementData(scan.ranges, 1.0);
00280 
00281   _sensor->setStandardMask();
00282   _sensor->transform(&Tinit);
00283   obfloat t[2] = {startX + footPrintXoffset, startY};
00284   if(!_grid.freeFootprint(t, footPrintWidth, footPrintHeight))
00285     ROS_ERROR_STREAM("Localizer(" << _nameSpace << ") warning! Footprint could not be freed!\n");
00286   if(!_mapper.initialized())
00287     _mapper.initPush(_sensor);
00288   _initialized = true;
00289   this->unblock();
00290 }
00291 
00292 obvious::Matrix ThreadLocalize::doRegistration(obvious::SensorPolar2D* sensor,
00293     obvious::Matrix* M,
00294     obvious::Matrix* Mvalid,
00295     obvious::Matrix* N,
00296     obvious::Matrix* Nvalid,
00297     obvious::Matrix* S,
00298     obvious::Matrix* Svalid,
00299     const bool experimental
00300 )
00301 {
00302 //  const unsigned int measurementSize = sensor->getRealMeasurementSize();
00303   obvious::Matrix T44(4, 4);
00304   T44.setIdentity();
00305 
00306   // RANSAC pre-registration (rough)
00307   if(experimental)
00308   {
00309 //    const unsigned int factor = 4;//_ransacReduceFactor;
00310 //    const unsigned int reducedSize = measurementSize / factor; // e.g.: 1080 -> 270  toDo: this could result in wrong calculations..round?
00311 //    obvious::Matrix Sreduced(reducedSize, 2);
00312 //    obvious::Matrix Mreduced(reducedSize, 2);
00313 //    bool* maskSRed = new bool[reducedSize];
00314 //    bool* maskMRed = new bool[reducedSize];
00315     //if(0)// factor != 1)
00316 
00317 //    reduceResolution(_maskS, S, maskSRed, &Sreduced, measurementSize, reducedSize, factor);
00318 //    reduceResolution(_maskM, M, maskMRed, &Mreduced, measurementSize, reducedSize, factor);
00319 
00320     //std::cout << __PRETTY_FUNCTION__ << " trials " << _ranTrials << " epsthresh " << _ranEpsThresh << " sizectrlset " << _ranSizeCtrlSet << std::endl;
00321     obvious::RandomNormalMatching ransac(_ranTrials, _ranEpsThresh, _ranSizeCtrlSet);
00322     //if(factor == 1)
00323     obvious::Matrix T = ransac.match(M, _maskM, N, S, _maskS, obvious::deg2rad(_ranPhiMax), _trnsMax, sensor->getAngularResolution());
00324     //    else
00325     //    std::cout << __PRETTY_FUNCTION__ << " here?" << std::endl;
00326     //    obvious::Matrix T = ransac.match(&Mreduced, maskMRed, N, &Sreduced, maskSRed, obvious::deg2rad(45.0),
00327     //          _trnsMax, sensor->getAngularResolution() * (double) factor);
00328     //    std::cout << __PRETTY_FUNCTION__ << " not.." << std::endl;
00329     T44(0, 0) = T(0, 0);
00330     T44(0, 1) = T(0, 1);
00331     T44(0, 3) = T(0, 2);
00332     T44(1, 0) = T(1, 0);
00333     T44(1, 1) = T(1, 1);
00334     T44(1, 3) = T(1, 2);
00335   }
00336   _icp->reset();
00337   obvious::Matrix P = sensor->getTransformation();
00338   _filterBounds->setPose(&P);
00339 
00340   _icp->setModel(Mvalid, Nvalid);
00341   _icp->setScene(Svalid);
00342   double rms = 0.0;
00343   unsigned int pairs = 0;
00344   unsigned int it = 0;
00345   _icp->iterate(&rms, &pairs, &it, &T44);
00346   obvious::Matrix T = _icp->getFinalTransformation();
00347   return T;
00348 }
00349 
00350 bool ThreadLocalize::isRegistrationError(obvious::Matrix* T, const double trnsMax, const double rotMax)
00351 {
00352   const double deltaX = (*T)(0, 2);
00353   const double deltaY = (*T)(1, 2);
00354   const double trnsAbs = std::sqrt(deltaX * deltaX + deltaY * deltaY);
00355   const double deltaPhi = this->calcAngle(T);
00356   return (trnsAbs > trnsMax) || (std::abs(std::sin(deltaPhi)) > rotMax);
00357 }
00358 
00359 void ThreadLocalize::sendTransform(obvious::Matrix* T)
00360 {
00361   const double curTheta = this->calcAngle(T);
00362   const double posX = (*T)(0, 2) + _gridOffSetX;
00363   const double posY = (*T)(1, 2) + _gridOffSetY;
00364   _poseStamped.header.stamp = ros::Time::now();
00365   _poseStamped.pose.position.x = posX;
00366   _poseStamped.pose.position.y = posY;
00367   _poseStamped.pose.position.z = 0.0;
00368   tf::Quaternion quat;
00369   quat.setEuler(0.0, 0.0, curTheta);
00370   _poseStamped.pose.orientation.w = quat.w();
00371   _poseStamped.pose.orientation.x = quat.x();
00372   _poseStamped.pose.orientation.y = quat.y();
00373   _poseStamped.pose.orientation.z = quat.z();
00374 
00375   _tf.stamp_ = ros::Time::now();
00376   _tf.setOrigin(tf::Vector3(posX, posY, 0.0));
00377   _tf.setRotation(quat);
00378 
00379   _posePub.publish(_poseStamped);
00380   _tfBroadcaster.sendTransform(_tf);
00381 }
00382 
00383 void ThreadLocalize::sendNanTransform()
00384 {
00385   _poseStamped.header.stamp = ros::Time::now();
00386   _poseStamped.pose.position.x = NAN;
00387   _poseStamped.pose.position.y = NAN;
00388   _poseStamped.pose.position.z = NAN;
00389   tf::Quaternion quat;
00390   quat.setEuler(NAN, NAN, NAN);
00391   _poseStamped.pose.orientation.w = quat.w();
00392   _poseStamped.pose.orientation.x = quat.x();
00393   _poseStamped.pose.orientation.y = quat.y();
00394   _poseStamped.pose.orientation.z = quat.z();
00395 
00396   _tf.stamp_ = ros::Time::now();
00397   _tf.setOrigin(tf::Vector3(NAN, NAN, NAN));
00398   _tf.setRotation(quat);
00399 
00400   _posePub.publish(_poseStamped);
00401   _tfBroadcaster.sendTransform(_tf);
00402 }
00403 
00404 double ThreadLocalize::calcAngle(obvious::Matrix* T)
00405 {
00406   double angle          = 0.0;
00407   const double ARCSIN   = asin((*T)(1,0));
00408   const double ARCSINEG = asin((*T)(0,1));
00409   const double ARCOS    = acos((*T)(0,0));
00410   if((ARCSIN > 0.0) && (ARCSINEG < 0.0))
00411     angle = ARCOS;
00412   else if((ARCSIN < 0.0) && (ARCSINEG > 0.0))
00413     angle = 2.0 * M_PI - ARCOS;
00414   return(angle);
00415 }
00416 
00417 bool ThreadLocalize::isPoseChangeSignificant(obvious::Matrix* lastPose, obvious::Matrix* curPose)
00418 {
00419   const double deltaX   = (*curPose)(0, 2) - (*lastPose)(0, 2);
00420   const double deltaY   = (*curPose)(1, 2) - (*lastPose)(1, 2);
00421   double deltaPhi       = this->calcAngle(curPose) - this->calcAngle(lastPose);
00422   deltaPhi              = fabs(sin(deltaPhi));
00423   const double trnsAbs  = sqrt(deltaX * deltaX + deltaY * deltaY);
00424   return (deltaPhi > ROT_MIN) || (trnsAbs > TRNS_MIN);
00425 }
00426 
00427 obvious::Matrix ThreadLocalize::maskMatrix(obvious::Matrix* Mat, bool* mask, unsigned int maskSize, unsigned int validPoints)
00428 {
00429   assert(Mat->getRows() == maskSize);
00430   assert(Mat->getCols() == 2);
00431   obvious::Matrix retMat(validPoints, 2);
00432   unsigned int cnt = 0;
00433   for(unsigned int i = 0; i < maskSize; i++)
00434   {
00435     if(mask[i])
00436     {
00437       retMat(cnt, 0) = (*Mat)(i, 0);
00438       retMat(cnt, 1) = (*Mat)(i, 1);
00439       cnt++;
00440     }
00441   }
00442   return retMat;
00443 }
00444 
00445 //toDo: maybe obsolete with pca matching, definitely not nice
00446 void ThreadLocalize::reduceResolution(bool* const maskIn, const obvious::Matrix* matIn, bool* const maskOut, obvious::Matrix* matOut,
00447     const unsigned int pointsIn, const unsigned int pointsOut, const unsigned int reductionFactor)
00448 {
00449   assert(pointsIn > pointsOut);
00450   //fixme we only support scan with even number of points like 1080. if a scan has 1081 points is not usable for subsampling here!
00451   const unsigned int factor = pointsIn / pointsOut;
00452   assert(factor == reductionFactor);
00453 
00454   unsigned int cnt = 0;
00455   for(unsigned int i = 0; i < pointsIn; i++)
00456   {
00457     if(!(i % factor)) // i % factor == 0
00458     {
00459       cnt++;
00460       if (maskIn[i]) {
00461         maskOut[i/factor] = true;
00462         (*matOut)(i/factor, 0) = (*matIn)(i, 0);
00463         (*matOut)(i/factor, 1) = (*matIn)(i, 1);
00464       }
00465       else
00466       {
00467         maskOut[i/factor] = false;
00468       }
00469     }
00470   }
00471   assert(cnt == pointsOut);
00472 }
00473 
00474 } /* namespace ohm_tsd_slam */


ohm_tsd_slam
Author(s): Philipp Koch, Stefan May, Markus Kühn
autogenerated on Thu Jun 6 2019 17:41:12