00001
00002
00003
00004
00005
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
00047 std::string::iterator it = _nameSpace.end() - 1;
00048 if (*it != '/' && _nameSpace.size() > 0)
00049 _nameSpace += "/";
00050
00051
00052 std::string poseTopic;
00053 prvNh.param(_nameSpace + "pose_topic", poseTopic, std::string("default_ns/pose"));
00054 poseTopic = _nameSpace + poseTopic;
00055
00056
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
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
00073 prvNh.param<double>("reg_trs_max", _trnsMax, TRNS_THRESH);
00074 prvNh.param<double>("reg_sin_rot_max", _rotMax, ROT_THRESH);
00075
00076
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
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)
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
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
00188 const unsigned int validScenePoints = _sensor->dataToCartesianVectorMask(_scene, _maskS);
00189
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);
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
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
00303 obvious::Matrix T44(4, 4);
00304 T44.setIdentity();
00305
00306
00307 if(experimental)
00308 {
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321 obvious::RandomNormalMatching ransac(_ranTrials, _ranEpsThresh, _ranSizeCtrlSet);
00322
00323 obvious::Matrix T = ransac.match(M, _maskM, N, S, _maskS, obvious::deg2rad(_ranPhiMax), _trnsMax, sensor->getAngularResolution());
00324
00325
00326
00327
00328
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
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
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))
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 }