00001 #ifndef NDT_FUSER_HMT_HH
00002 #define NDT_FUSER_HMT_HH
00003
00004 #include <ndt_viz.h>
00005 #include <ndt_map_hmt.h>
00006 #include <ndt_map.h>
00007 #include <ndt_matcher_d2d_2d.h>
00008 #include <ndt_matcher_d2d.h>
00009 #include <pointcloud_utils.h>
00010
00011 #include <Eigen/Eigen>
00012 #include <pcl/point_cloud.h>
00013
00014
00015
00016 namespace lslgeneric {
00022 template <typename PointT>
00023 class NDTFuserHMT{
00024 public:
00025 Eigen::Affine3d Tnow, Tlast_fuse, Todom;
00026
00027 lslgeneric::NDTMap<PointT> *map;
00028 bool checkConsistency;
00029 double max_translation_norm, max_rotation_norm;
00030 double sensor_range;
00031 bool be2D, doMultires, fuseIncomplete, beHMT;
00032 int ctr;
00033 std::string prefix;
00034 std::string hmt_map_dir;
00035 NDTViz<PointT> *viewer;
00036 FILE *fAddTimes, *fRegTimes;
00037
00038 NDTFuserHMT(double map_resolution, double map_size_x_, double map_size_y_, double map_size_z_, double sensor_range_ = 3,
00039 bool visualize_=false, bool be2D_=false, bool doMultires_=false, bool fuseIncomplete_=false, int max_itr=30,
00040 std::string prefix_="", bool beHMT_=true, std::string hmt_map_dir_="map", bool _step_control=true){
00041 isInit = false;
00042 resolution = map_resolution;
00043 sensor_pose.setIdentity();
00044 checkConsistency = false;
00045 visualize = true;
00046 translation_fuse_delta = 0.05;
00047 rotation_fuse_delta = 0.01;
00048 max_translation_norm = 1.;
00049 max_rotation_norm = M_PI/4;
00050 map_size_x = map_size_x_;
00051 map_size_y = map_size_y_;
00052 map_size_z = map_size_z_;
00053 visualize = visualize_;
00054 be2D = be2D_;
00055 sensor_range = sensor_range_;
00056 prefix = prefix_;
00057 doMultires = doMultires_;
00058 ctr =0;
00059 viewer = new NDTViz<PointT>(visualize);
00060 localMapSize<<sensor_range_,sensor_range_,map_size_z_;
00061 fuseIncomplete = fuseIncomplete_;
00062 matcher.ITR_MAX = max_itr;
00063 matcher2D.ITR_MAX = max_itr;
00064 matcher.step_control=_step_control;
00065 matcher2D.step_control=_step_control;
00066 beHMT = beHMT_;
00067 hmt_map_dir=hmt_map_dir_;
00068
00069
00070 char fname[1000];
00071 snprintf(fname,999,"%s_addTime.txt",prefix.c_str());
00072 fAddTimes = fopen(fname,"w");
00073
00074 std::cout<<"MAP: resolution: "<<resolution<<" size "<<map_size_x<<" "<<map_size_y<<" "<<map_size_z<<" sr "<<sensor_range<<std::endl;
00075 }
00076 ~NDTFuserHMT()
00077 {
00078 delete map;
00079 delete viewer;
00080 if(fAddTimes!=NULL) fclose(fAddTimes);
00081 if(fRegTimes!=NULL) fclose(fRegTimes);
00082 }
00083
00084 double getDoubleTime()
00085 {
00086 struct timeval time;
00087 gettimeofday(&time,NULL);
00088 return time.tv_sec + time.tv_usec * 1e-6;
00089 }
00090 void setSensorPose(Eigen::Affine3d spose){
00091 sensor_pose = spose;
00092 }
00093
00094 bool wasInit()
00095 {
00096 return isInit;
00097 }
00098
00099 bool saveMap() {
00100 if(!isInit) return false;
00101 if(map == NULL) return false;
00102 if(beHMT) {
00103 lslgeneric::NDTMapHMT<PointT> *map_hmt = dynamic_cast<lslgeneric::NDTMapHMT<PointT>*> (map);
00104 if(map_hmt==NULL) return false;
00105 return (map_hmt->writeTo()==0);
00106 } else {
00107 char fname[1000];
00108 snprintf(fname,999,"%s/%s_map.jff",hmt_map_dir.c_str(),prefix.c_str());
00109 return (map->writeToJFF(fname) == 0);
00110 }
00111 }
00112
00116 void initialize(Eigen::Affine3d initPos, pcl::PointCloud<PointT> &cloud, bool preLoad=false){
00118 lslgeneric::transformPointCloudInPlace(sensor_pose, cloud);
00119 lslgeneric::transformPointCloudInPlace(initPos, cloud);
00120 Tnow = initPos;
00121
00122
00123 if(beHMT) {
00124 map = new lslgeneric::NDTMapHMT<PointT>(resolution,
00125 Tnow.translation()(0),Tnow.translation()(1),Tnow.translation()(2),
00126 map_size_x,map_size_y,map_size_z,sensor_range,hmt_map_dir,true);
00127 if(preLoad) {
00128 lslgeneric::NDTMapHMT<PointT> *map_hmt = dynamic_cast<lslgeneric::NDTMapHMT<PointT>*> (map);
00129 std::cout<<"Trying to pre-load maps at "<<initPos.translation()<<std::endl;
00130 map_hmt->tryLoadPosition(initPos.translation());
00131 }
00132 } else {
00133 map = new lslgeneric::NDTMap<PointT>(new lslgeneric::LazyGrid<PointT>(resolution));
00134 map->initialize(Tnow.translation()(0),Tnow.translation()(1),Tnow.translation()(2),map_size_x,map_size_y,map_size_z);
00135 }
00136
00137 map->addPointCloud(Tnow.translation(),cloud, 0.1, 100.0, 0.1);
00138
00139
00140 map->computeNDTCells(CELL_UPDATE_MODE_SAMPLE_VARIANCE, 1e5, 255, Tnow.translation(), 0.1);
00141 isInit = true;
00142 Tlast_fuse = Tnow;
00143 Todom = Tnow;
00144 if(visualize)
00145 {
00146 viewer->plotNDTSAccordingToOccupancy(-1,map);
00147 viewer->plotLocalNDTMap(cloud,resolution);
00148 viewer->addTrajectoryPoint(Tnow.translation()(0),Tnow.translation()(1),Tnow.translation()(2),1,0,0);
00149 viewer->addTrajectoryPoint(Todom.translation()(0),Todom.translation()(1),Todom.translation()(2),0,1,0);
00150 viewer->displayTrajectory();
00151 viewer->repaint();
00152 }
00153 }
00154
00159 Eigen::Affine3d update(Eigen::Affine3d Tmotion, pcl::PointCloud<PointT> &cloud){
00160 if(!isInit){
00161 fprintf(stderr,"NDT-FuserHMT: Call Initialize first!!\n");
00162 return Tnow;
00163 }
00164 Todom = Todom * Tmotion;
00165 double t0=0,t1=0,t2=0,t3=0,t4=0,t5=0,t6=0;
00167 lslgeneric::transformPointCloudInPlace(sensor_pose, cloud);
00168 t0 = getDoubleTime();
00170 lslgeneric::NDTMap<PointT> ndlocal(new lslgeneric::LazyGrid<PointT>(resolution));
00171 ndlocal.guessSize(0,0,0,sensor_range,sensor_range,map_size_z);
00172 ndlocal.loadPointCloud(cloud,sensor_range);
00173 ndlocal.computeNDTCells(CELL_UPDATE_MODE_SAMPLE_VARIANCE);
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192 t1 = getDoubleTime();
00193 Eigen::Affine3d Tinit = Tnow * Tmotion;
00194 if(doMultires) {
00195
00196 lslgeneric::NDTMap<PointT> ndlocalLow(new lslgeneric::LazyGrid<PointT>(3*resolution));
00197 ndlocalLow.guessSize(0,0,0,sensor_range,sensor_range,map_size_z);
00198 ndlocalLow.loadPointCloud(cloud,sensor_range);
00199 ndlocalLow.computeNDTCells(CELL_UPDATE_MODE_SAMPLE_VARIANCE);
00200
00201 lslgeneric::NDTMap<PointT> mapLow(new lslgeneric::LazyGrid<PointT>(3*resolution));
00202
00203 double cx,cy,cz;
00204 if(!map->getCentroid(cx, cy, cz)){
00205 fprintf(stderr,"Centroid NOT Given-abort!\n");
00206 }
00207 mapLow.initialize(cx,cy,cz,3*map_size_x,3*map_size_y,map_size_z);
00208
00209 std::vector<lslgeneric::NDTCell<PointT>*> ndts;
00210 ndts = map->getAllCells();
00211
00212 for(int i=0; i<ndts.size(); i++)
00213 {
00214 NDTCell<PointT> *cell = ndts[i];
00215 if(cell!=NULL)
00216 {
00217 if(cell->hasGaussian_)
00218 {
00219 Eigen::Vector3d m = cell->getMean();
00220 Eigen::Matrix3d cov = cell->getCov();
00221 unsigned int nump = cell->getN();
00222 mapLow.addDistributionToCell(cov, m,nump);
00223 }
00224 }
00225 delete cell;
00226 }
00227
00228 if(matcher2D.match( mapLow, ndlocalLow,Tinit,true)){
00229
00230 t2 = getDoubleTime();
00231
00232 } else {
00233 Tinit = Tnow * Tmotion;
00234 }
00235 }
00236
00237 if(be2D) {
00238 t2 = getDoubleTime();
00239 if(matcher2D.match( *map, ndlocal,Tinit,true) || fuseIncomplete){
00240 t3 = getDoubleTime();
00241 Eigen::Affine3d diff = (Tnow * Tmotion).inverse() * Tinit;
00242 if((diff.translation().norm() > max_translation_norm ||
00243 diff.rotation().eulerAngles(0,1,2).norm() > max_rotation_norm) && checkConsistency){
00244 fprintf(stderr,"**** NDTFuserHMT -- ALMOST DEFINATELY A REGISTRATION FAILURE *****\n");
00245 Tnow = Tnow * Tmotion;
00246 }else{
00247 Tnow = Tinit;
00248 lslgeneric::transformPointCloudInPlace(Tnow, cloud);
00249 Eigen::Affine3d spose = Tnow*sensor_pose;
00250 Eigen::Affine3d diff_fuse = Tlast_fuse.inverse()*Tnow;
00251 if(diff_fuse.translation().norm() > translation_fuse_delta ||
00252 diff_fuse.rotation().eulerAngles(0,1,2).norm() > rotation_fuse_delta)
00253 {
00254
00255 t4 = getDoubleTime();
00256 map->addPointCloudMeanUpdate(spose.translation(),cloud,localMapSize, 1e5, 1250, map_size_z/2, 0.06);
00257 t5 = getDoubleTime();
00258
00259
00260
00261
00262
00263 Tlast_fuse = Tnow;
00264 if(visualize)
00265 {
00266 if(ctr%20==0) {
00267 viewer->plotNDTSAccordingToOccupancy(-1,map);
00268 viewer->plotLocalNDTMap(cloud,resolution);
00269 }
00270 viewer->addTrajectoryPoint(Tnow.translation()(0),Tnow.translation()(1),Tnow.translation()(2),1,0,0);
00271 viewer->addTrajectoryPoint(Todom.translation()(0),Todom.translation()(1),Todom.translation()(2),0,1,0);
00272 viewer->displayTrajectory();
00273 viewer->repaint();
00274 }
00275 ctr++;
00276 }
00277 }
00278 }else{
00279 t3 = getDoubleTime();
00280 Tnow = Tnow * Tmotion;
00281 }
00282
00283 }
00284 else
00285 {
00286
00287 t2 = getDoubleTime();
00288 if(matcher.match( *map, ndlocal,Tinit,true) || fuseIncomplete){
00289 t3 = getDoubleTime();
00290 Eigen::Affine3d diff = (Tnow * Tmotion).inverse() * Tinit;
00291
00292 if((diff.translation().norm() > max_translation_norm ||
00293 diff.rotation().eulerAngles(0,1,2).norm() > max_rotation_norm) && checkConsistency){
00294 fprintf(stderr,"**** NDTFuserHMT -- ALMOST DEFINATELY A REGISTRATION FAILURE *****\n");
00295 Tnow = Tnow * Tmotion;
00296
00297
00298
00299 }else{
00300 Tnow = Tinit;
00301
00302 lslgeneric::transformPointCloudInPlace(Tnow, cloud);
00303 Eigen::Affine3d spose = Tnow*sensor_pose;
00304 Eigen::Affine3d diff_fuse = Tlast_fuse.inverse()*Tnow;
00305 if(diff_fuse.translation().norm() > translation_fuse_delta ||
00306 diff_fuse.rotation().eulerAngles(0,1,2).norm() > rotation_fuse_delta)
00307 {
00308
00309 t4 = getDoubleTime();
00310 map->addPointCloudMeanUpdate(spose.translation(),cloud,localMapSize, 1e5, 1250, map_size_z/2, 0.06);
00311 t5 = getDoubleTime();
00312
00313
00314
00315
00316
00317 Tlast_fuse = Tnow;
00318 if(visualize)
00319 {
00320 viewer->plotNDTSAccordingToOccupancy(-1,map);
00321 viewer->plotLocalNDTMap(cloud,resolution);
00322 }
00323 ctr++;
00324 }
00325 }
00326 }else{
00327 t3 = getDoubleTime();
00328 Tnow = Tnow * Tmotion;
00329 }
00330 }
00331
00332 t6 = getDoubleTime();
00333 if(fAddTimes!=NULL) {
00334 fprintf(fAddTimes,"%lf %lf %lf\n",t3-t2,t5-t4,t6-t0);
00335 fflush(fAddTimes);
00336 }
00337
00338 return Tnow;
00339 }
00340
00341 private:
00342 bool isInit;
00343
00344 double resolution;
00345 double map_size;
00346
00347 double translation_fuse_delta, rotation_fuse_delta;
00348 double map_size_x;
00349 double map_size_y;
00350 double map_size_z;
00351 bool visualize;
00352
00353 Eigen::Affine3d sensor_pose;
00354 lslgeneric::NDTMatcherD2D<PointT,PointT> matcher;
00355 lslgeneric::NDTMatcherD2D_2D<PointT,PointT> matcher2D;
00356 Eigen::Vector3d localMapSize;
00357
00358 public:
00359 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
00360
00361 };
00362 }
00363 #endif