CLaserOdometry2D.cpp
Go to the documentation of this file.
00001 
00016 #include "rf2o_laser_odometry/CLaserOdometry2D.h"
00017 using namespace mrpt;
00018 using namespace mrpt::math;
00019 using namespace mrpt::utils;
00020 using namespace mrpt::poses;
00021 using namespace std;
00022 using namespace Eigen;
00023 
00024 
00025 // --------------------------------------------
00026 // CLaserOdometry2D
00027 //---------------------------------------------
00028 
00029 CLaserOdometry2D::CLaserOdometry2D()
00030 {       
00031     ROS_INFO("Initializing RF2O node...");
00032 
00033     //Read Parameters
00034     //----------------
00035     ros::NodeHandle pn("~");
00036     pn.param<std::string>("laser_scan_topic",laser_scan_topic,"/laser_scan");
00037     pn.param<std::string>("base_frame_id", base_frame_id, "/base_link");
00038     pn.param<std::string>("odom_frame_id", odom_frame_id, "/odom");
00039     pn.param<double>("freq",freq,10.0);
00040 
00041     //Publishers and Subscribers
00042     //--------------------------    
00043     odom_pub = pn.advertise<nav_msgs::Odometry>(odom_frame_id, 5);
00044     laser_sub = n.subscribe<sensor_msgs::LaserScan>(laser_scan_topic,1,&CLaserOdometry2D::LaserCallBack,this);
00045 
00046     //Init variables
00047     module_initialized = false;
00048     first_laser_scan = true;
00049 }
00050 
00051 
00052 CLaserOdometry2D::~CLaserOdometry2D()
00053 {
00054 }
00055 
00056 
00057 bool CLaserOdometry2D::is_initialized()
00058 {
00059     return module_initialized;
00060 }
00061 
00062 bool CLaserOdometry2D::scan_available()
00063 {
00064     return new_scan_available;
00065 }
00066 
00067 void CLaserOdometry2D::Init()
00068 {
00069     //Got an initial scan laser, obtain its parametes
00070     ROS_INFO("Got first Laser Scan .... Configuring node");
00071     width = last_scan.ranges.size();    // Num of samples (size) of the scan laser
00072     cols = width;                                               // Max reolution. Should be similar to the width parameter
00073     fovh = fabs(last_scan.angle_max - last_scan.angle_min); // Horizontal Laser's FOV
00074     ctf_levels = 5;                     // Coarse-to-Fine levels
00075     iter_irls = 5;                      //Num iterations to solve iterative reweighted least squares
00076 
00077     //Set laser pose on the robot (through tF)
00078     // This allow estimation of the odometry with respect to the robot base reference system.
00079     mrpt::poses::CPose3D LaserPoseOnTheRobot;
00080     tf::StampedTransform transform;
00081     try
00082     {
00083         tf_listener.lookupTransform("/base_link", last_scan.header.frame_id, ros::Time(0), transform);
00084     }
00085     catch (tf::TransformException &ex)
00086     {
00087         ROS_ERROR("%s",ex.what());
00088         ros::Duration(1.0).sleep();
00089     }
00090 
00091     //TF:transform -> mrpt::CPose3D (see mrpt-ros-bridge)
00092     const tf::Vector3 &t = transform.getOrigin();
00093     LaserPoseOnTheRobot.x() = t[0];
00094     LaserPoseOnTheRobot.y() = t[1];
00095     LaserPoseOnTheRobot.z() = t[2];
00096     const tf::Matrix3x3 &basis = transform.getBasis();
00097     mrpt::math::CMatrixDouble33 R;
00098     for(int r = 0; r < 3; r++)
00099         for(int c = 0; c < 3; c++)
00100             R(r,c) = basis[r][c];
00101     LaserPoseOnTheRobot.setRotationMatrix(R);
00102 
00103 
00104     //Set the initial pose
00105     laser_pose = LaserPoseOnTheRobot;
00106     laser_oldpose = LaserPoseOnTheRobot;
00107 
00108     // Init module
00109     //-------------
00110     range_wf.setSize(1, width);
00111 
00112     //Resize vectors according to levels
00113     transformations.resize(ctf_levels);
00114     for (unsigned int i = 0; i < ctf_levels; i++)
00115         transformations[i].resize(3, 3);
00116 
00117     //Resize pyramid
00118     unsigned int s, cols_i;
00119     const unsigned int pyr_levels = round(log2(round(float(width) / float(cols)))) + ctf_levels;
00120     range.resize(pyr_levels);
00121     range_old.resize(pyr_levels);
00122     range_inter.resize(pyr_levels);
00123     xx.resize(pyr_levels);
00124     xx_inter.resize(pyr_levels);
00125     xx_old.resize(pyr_levels);
00126     yy.resize(pyr_levels);
00127     yy_inter.resize(pyr_levels);
00128     yy_old.resize(pyr_levels);
00129     range_warped.resize(pyr_levels);
00130     xx_warped.resize(pyr_levels);
00131     yy_warped.resize(pyr_levels);
00132 
00133     for (unsigned int i = 0; i < pyr_levels; i++)
00134     {
00135         s = pow(2.f, int(i));
00136         cols_i = ceil(float(width) / float(s));
00137 
00138         range[i].resize(1, cols_i);
00139         range_inter[i].resize(1, cols_i);
00140         range_old[i].resize(1, cols_i);
00141         range[i].assign(0.0f);
00142         range_old[i].assign(0.0f);
00143         xx[i].resize(1, cols_i);
00144         xx_inter[i].resize(1, cols_i);
00145         xx_old[i].resize(1, cols_i);
00146         xx[i].assign(0.0f);
00147         xx_old[i].assign(0.0f);
00148         yy[i].resize(1, cols_i);
00149         yy_inter[i].resize(1, cols_i);
00150         yy_old[i].resize(1, cols_i);
00151         yy[i].assign(0.f);
00152         yy_old[i].assign(0.f);
00153 
00154         if (cols_i <= cols)
00155         {
00156             range_warped[i].resize(1, cols_i);
00157             xx_warped[i].resize(1, cols_i);
00158             yy_warped[i].resize(1, cols_i);
00159         }
00160     }
00161 
00162     dt.resize(1, cols);
00163     dtita.resize(1, cols);
00164     normx.resize(1, cols);
00165     normy.resize(1, cols);
00166     norm_ang.resize(1, cols);
00167     weights.setSize(1, cols);
00168     null.setSize(1, cols);
00169     null.assign(0);
00170     cov_odo.assign(0.f);
00171 
00172 
00173     fps = 1.f;          //In Hz
00174     num_valid_range = 0;
00175 
00176     //Compute gaussian mask
00177     g_mask[0] = 1.f / 16.f; g_mask[1] = 0.25f; g_mask[2] = 6.f / 16.f; g_mask[3] = g_mask[1]; g_mask[4] = g_mask[0];
00178 
00179     kai_abs.assign(0.f);
00180     kai_loc_old.assign(0.f);
00181 
00182     module_initialized = true;
00183     last_odom_time = ros::Time::now();
00184 }
00185 
00186 
00187 void CLaserOdometry2D::odometryCalculation()
00188 {
00189     //==================================================================================
00190     //                                          DIFERENTIAL  ODOMETRY  MULTILEVEL
00191     //==================================================================================
00192 
00193     m_clock.Tic();
00194     createImagePyramid();
00195 
00196     //Coarse-to-fine scheme
00197     for (unsigned int i=0; i<ctf_levels; i++)
00198     {
00199         //Previous computations
00200         transformations[i].setIdentity();
00201 
00202         level = i;
00203         unsigned int s = pow(2.f,int(ctf_levels-(i+1)));
00204         cols_i = ceil(float(cols)/float(s));
00205         image_level = ctf_levels - i + round(log2(round(float(width)/float(cols)))) - 1;
00206 
00207         //1. Perform warping
00208         if (i == 0)
00209         {
00210             range_warped[image_level] = range[image_level];
00211             xx_warped[image_level] = xx[image_level];
00212             yy_warped[image_level] = yy[image_level];
00213         }
00214         else
00215             performWarping();
00216 
00217         //2. Calculate inter coords
00218         calculateCoord();
00219 
00220         //3. Find null points
00221         findNullPoints();
00222 
00223         //4. Compute derivatives
00224         calculaterangeDerivativesSurface();
00225 
00226         //5. Compute normals
00227         //computeNormals();
00228 
00229         //6. Compute weights
00230         computeWeights();
00231 
00232         //7. Solve odometry
00233         if (num_valid_range > 3)
00234         {
00235             solveSystemNonLinear();
00236             //solveSystemOneLevel();    //without robust-function
00237         }
00238 
00239         //8. Filter solution
00240         filterLevelSolution();
00241     }
00242 
00243     m_runtime = 1000*m_clock.Tac();
00244     ROS_INFO("Time odometry (ms): %f", m_runtime);
00245 
00246     //Update poses
00247     PoseUpdate();
00248     new_scan_available = false;     //avoids the possibility to run twice on the same laser scan
00249 }
00250 
00251 
00252 void CLaserOdometry2D::createImagePyramid()
00253 {
00254         const float max_range_dif = 0.3f;
00255         
00256         //Push the frames back
00257         range_old.swap(range);
00258         xx_old.swap(xx);
00259         yy_old.swap(yy);
00260 
00261     //The number of levels of the pyramid does not match the number of levels used
00262     //in the odometry computation (because we sometimes want to finish with lower resolutions)
00263 
00264     unsigned int pyr_levels = round(log2(round(float(width)/float(cols)))) + ctf_levels;
00265 
00266     //Generate levels
00267     for (unsigned int i = 0; i<pyr_levels; i++)
00268     {
00269         unsigned int s = pow(2.f,int(i));
00270         cols_i = ceil(float(width)/float(s));
00271                 
00272                 const unsigned int i_1 = i-1;
00273 
00274                 //First level -> Filter (not downsampling);
00275         if (i == 0)
00276                 {
00277                         for (unsigned int u = 0; u < cols_i; u++)
00278             {   
00279                                 const float dcenter = range_wf(u);
00280                                         
00281                                 //Inner pixels
00282                 if ((u>1)&&(u<cols_i-2))
00283                 {               
00284                                         if (dcenter > 0.f)
00285                                         {       
00286                                                 float sum = 0.f;
00287                                                 float weight = 0.f;
00288 
00289                                                 for (int l=-2; l<3; l++)
00290                                                 {
00291                                                         const float abs_dif = abs(range_wf(u+l)-dcenter);
00292                                                         if (abs_dif < max_range_dif)
00293                                                         {
00294                                                                 const float aux_w = g_mask[2+l]*(max_range_dif - abs_dif);
00295                                                                 weight += aux_w;
00296                                                                 sum += aux_w*range_wf(u+l);
00297                                                         }
00298                                                 }
00299                                                 range[i](u) = sum/weight;
00300                                         }
00301                                         else
00302                                                 range[i](u) = 0.f;
00303 
00304                 }
00305 
00306                 //Boundary
00307                 else
00308                 {
00309                     if (dcenter > 0.f)
00310                                         {                                               
00311                                                 float sum = 0.f;
00312                                                 float weight = 0.f;
00313 
00314                                                 for (int l=-2; l<3; l++)        
00315                                                 {
00316                                                         const int indu = u+l;
00317                                                         if ((indu>=0)&&(indu<cols_i))
00318                                                         {
00319                                                                 const float abs_dif = abs(range_wf(indu)-dcenter);                                                                              
00320                                                                 if (abs_dif < max_range_dif)
00321                                                                 {
00322                                                                         const float aux_w = g_mask[2+l]*(max_range_dif - abs_dif);
00323                                                                         weight += aux_w;
00324                                                                         sum += aux_w*range_wf(indu);
00325                                                                 }
00326                                                         }
00327                                                 }
00328                                                 range[i](u) = sum/weight;
00329                                         }
00330                                         else
00331                                                 range[i](u) = 0.f;
00332 
00333                 }
00334             }
00335                 }
00336 
00337         //                              Downsampling
00338         //-----------------------------------------------------------------------------
00339         else
00340         {            
00341                         for (unsigned int u = 0; u < cols_i; u++)
00342             {
00343                 const int u2 = 2*u;             
00344                                 const float dcenter = range[i_1](u2);
00345                                         
00346                                 //Inner pixels
00347                 if ((u>0)&&(u<cols_i-1))
00348                 {               
00349                                         if (dcenter > 0.f)
00350                                         {       
00351                                                 float sum = 0.f;
00352                                                 float weight = 0.f;
00353 
00354                                                 for (int l=-2; l<3; l++)
00355                                                 {
00356                                                         const float abs_dif = abs(range[i_1](u2+l)-dcenter);
00357                                                         if (abs_dif < max_range_dif)
00358                                                         {
00359                                                                 const float aux_w = g_mask[2+l]*(max_range_dif - abs_dif);
00360                                                                 weight += aux_w;
00361                                                                 sum += aux_w*range[i_1](u2+l);
00362                                                         }
00363                                                 }
00364                                                 range[i](u) = sum/weight;
00365                                         }
00366                                         else
00367                                                 range[i](u) = 0.f;
00368 
00369                 }
00370 
00371                 //Boundary
00372                 else
00373                 {
00374                     if (dcenter > 0.f)
00375                                         {                                               
00376                                                 float sum = 0.f;
00377                                                 float weight = 0.f;
00378                                                 const unsigned int cols_i2 = range[i_1].cols();
00379 
00380 
00381                                                 for (int l=-2; l<3; l++)        
00382                                                 {
00383                                                         const int indu = u2+l;
00384                                                         if ((indu>=0)&&(indu<cols_i2))
00385                                                         {
00386                                                                 const float abs_dif = abs(range[i_1](indu)-dcenter);                                                                            
00387                                                                 if (abs_dif < max_range_dif)
00388                                                                 {
00389                                                                         const float aux_w = g_mask[2+l]*(max_range_dif - abs_dif);
00390                                                                         weight += aux_w;
00391                                                                         sum += aux_w*range[i_1](indu);
00392                                                                 }
00393                                                         }
00394                                                 }
00395                                                 range[i](u) = sum/weight;
00396                                         }
00397                                         else
00398                                                 range[i](u) = 0.f;
00399 
00400                 }
00401             }
00402         }
00403 
00404         //Calculate coordinates "xy" of the points
00405         for (unsigned int u = 0; u < cols_i; u++) 
00406                 {
00407             if (range[i](u) > 0.f)
00408                         {
00409                                 const float tita = -0.5*fovh + float(u)*fovh/float(cols_i-1);
00410                                 xx[i](u) = range[i](u)*cos(tita);
00411                                 yy[i](u) = range[i](u)*sin(tita);
00412                         }
00413                         else
00414                         {
00415                                 xx[i](u) = 0.f;
00416                                 yy[i](u) = 0.f;
00417                         }
00418                 }
00419     }
00420 }
00421 
00422 
00423 
00424 void CLaserOdometry2D::calculateCoord()
00425 {               
00426         for (unsigned int u = 0; u < cols_i; u++)
00427         {
00428                 if ((range_old[image_level](u) == 0.f) || (range_warped[image_level](u) == 0.f))
00429                 {
00430                         range_inter[image_level](u) = 0.f;
00431                         xx_inter[image_level](u) = 0.f;
00432                         yy_inter[image_level](u) = 0.f;
00433                 }
00434                 else
00435                 {
00436                         range_inter[image_level](u) = 0.5f*(range_old[image_level](u) + range_warped[image_level](u));
00437                         xx_inter[image_level](u) = 0.5f*(xx_old[image_level](u) + xx_warped[image_level](u));
00438                         yy_inter[image_level](u) = 0.5f*(yy_old[image_level](u) + yy_warped[image_level](u));
00439                 }
00440         }
00441 }
00442 
00443 
00444 void CLaserOdometry2D::calculaterangeDerivativesSurface()
00445 {       
00446         //The gradient size ir reserved at the maximum size (at the constructor)
00447 
00448     //Compute connectivity
00449         rtita.resize(1,cols_i);                 //Defined in a different way now, without inversion
00450     rtita.assign(1.f); 
00451 
00452         for (unsigned int u = 0; u < cols_i-1; u++)
00453     {
00454                 const float dist = square(xx_inter[image_level](u+1) - xx_inter[image_level](u))
00455                                                         + square(yy_inter[image_level](u+1) - yy_inter[image_level](u));
00456                 if (dist  > 0.f)
00457                         rtita(u) = sqrt(dist);
00458         }
00459 
00460     //Spatial derivatives
00461     for (unsigned int u = 1; u < cols_i-1; u++)
00462                 dtita(u) = (rtita(u-1)*(range_inter[image_level](u+1)-range_inter[image_level](u)) + rtita(u)*(range_inter[image_level](u) - range_inter[image_level](u-1)))/(rtita(u)+rtita(u-1));
00463 
00464         dtita(0) = dtita(1);
00465         dtita(cols_i-1) = dtita(cols_i-2);
00466 
00467         //Temporal derivative
00468         for (unsigned int u = 0; u < cols_i; u++)
00469                 dt(u) = fps*(range_warped[image_level](u) - range_old[image_level](u));
00470 
00471 
00472         //Apply median filter to the range derivatives
00473         //MatrixXf dtitamed = dtita, dtmed = dt;
00474         //vector<float> svector(3);
00475         //for (unsigned int u=1; u<cols_i-1; u++)
00476         //{
00477         //      svector.at(0) = dtita(u-1); svector.at(1) = dtita(u); svector.at(2) = dtita(u+1);
00478         //      std::sort(svector.begin(), svector.end());
00479         //      dtitamed(u) = svector.at(1);
00480 
00481         //      svector.at(0) = dt(u-1); svector.at(1) = dt(u); svector.at(2) = dt(u+1);
00482         //      std::sort(svector.begin(), svector.end());
00483         //      dtmed(u) = svector.at(1);
00484         //}
00485 
00486         //dtitamed(0) = dtitamed(1);
00487         //dtitamed(cols_i-1) = dtitamed(cols_i-2);
00488         //dtmed(0) = dtmed(1);
00489         //dtmed(cols_i-1) = dtmed(cols_i-2);
00490 
00491         //dtitamed.swap(dtita);
00492         //dtmed.swap(dt);
00493 }
00494 
00495 
00496 void CLaserOdometry2D::computeNormals()
00497 {
00498         normx.assign(0.f);
00499         normy.assign(0.f);
00500         norm_ang.assign(0.f);
00501 
00502         const float incr_tita = fovh/float(cols_i-1);
00503         for (unsigned int u=0; u<cols_i; u++)
00504         {
00505                 if (null(u) == 0.f)
00506                 {
00507                         const float tita = -0.5f*fovh + float(u)*incr_tita;
00508                         const float alfa = -atan2(2.f*dtita(u), 2.f*range[image_level](u)*incr_tita);
00509                         norm_ang(u) = tita + alfa;
00510                         if (norm_ang(u) < -M_PI)
00511                                 norm_ang(u) += 2.f*M_PI;
00512                         else if (norm_ang(u) < 0.f)
00513                                 norm_ang(u) += M_PI;
00514                         else if (norm_ang(u) > M_PI)
00515                                 norm_ang(u) -= M_PI;
00516 
00517                         normx(u) = cos(tita + alfa);
00518                         normy(u) = sin(tita + alfa);
00519                 }
00520         }
00521 }
00522 
00523 
00524 void CLaserOdometry2D::computeWeights()
00525 {
00526         //The maximum weight size is reserved at the constructor
00527         weights.assign(0.f);
00528         
00529         //Parameters for error_linearization
00530         const float kdtita = 1.f;
00531         const float kdt = kdtita/square(fps);
00532         const float k2d = 0.2f;
00533         
00534         for (unsigned int u = 1; u < cols_i-1; u++)
00535                 if (null(u) == 0)
00536                 {       
00537                         //                                                      Compute derivatives
00538                         //-----------------------------------------------------------------------
00539                         const float ini_dtita = range_old[image_level](u+1) - range_old[image_level](u-1);
00540                         const float final_dtita = range_warped[image_level](u+1) - range_warped[image_level](u-1);
00541 
00542                         const float dtitat = ini_dtita - final_dtita;
00543                         const float dtita2 = dtita(u+1) - dtita(u-1);
00544 
00545                         const float w_der = kdt*square(dt(u)) + kdtita*square(dtita(u)) + k2d*(abs(dtitat) + abs(dtita2));
00546 
00547                         weights(u) = sqrt(1.f/w_der);
00548                 }
00549 
00550         const float inv_max = 1.f/weights.maximum();
00551         weights = inv_max*weights;
00552 }
00553 
00554 
00555 void CLaserOdometry2D::findNullPoints()
00556 {
00557         //Size of null matrix is set to its maximum size (constructor)
00558         num_valid_range = 0;
00559 
00560         for (unsigned int u = 1; u < cols_i-1; u++)
00561         {
00562                 if (range_inter[image_level](u) == 0.f)
00563                         null(u) = 1;
00564                 else
00565                 {
00566                         num_valid_range++;
00567                         null(u) = 0;
00568                 }
00569         }
00570 }
00571 
00572 
00573 // Solves the system without considering any robust-function
00574 void CLaserOdometry2D::solveSystemOneLevel()
00575 {
00576         A.resize(num_valid_range,3);
00577         B.setSize(num_valid_range,1);
00578         unsigned int cont = 0;
00579         const float kdtita = (cols_i-1)/fovh;
00580 
00581         //Fill the matrix A and the vector B
00582         //The order of the variables will be (vx, vy, wz)
00583 
00584         for (unsigned int u = 1; u < cols_i-1; u++)
00585                 if (null(u) == 0)
00586                 {
00587                         // Precomputed expressions
00588                         const float tw = weights(u);
00589                         const float tita = -0.5*fovh + u/kdtita;
00590 
00591                         //Fill the matrix A
00592                         A(cont, 0) = tw*(cos(tita) + dtita(u)*kdtita*sin(tita)/range_inter[image_level](u));
00593                         A(cont, 1) = tw*(sin(tita) - dtita(u)*kdtita*cos(tita)/range_inter[image_level](u));
00594                         A(cont, 2) = tw*(-yy[image_level](u)*cos(tita) + xx[image_level](u)*sin(tita) - dtita(u)*kdtita);
00595                         B(cont,0) = tw*(-dt(u));
00596 
00597                         cont++;
00598                 }
00599         
00600         //Solve the linear system of equations using a minimum least squares method
00601         MatrixXf AtA, AtB;
00602         AtA.multiply_AtA(A);
00603         AtB.multiply_AtB(A,B);
00604         Var = AtA.ldlt().solve(AtB);
00605 
00606         //Covariance matrix calculation         Cov Order -> vx,vy,wz
00607         MatrixXf res(num_valid_range,1);
00608         res = A*Var - B;
00609         cov_odo = (1.f/float(num_valid_range-3))*AtA.inverse()*res.squaredNorm();
00610 
00611         kai_loc_level = Var;
00612 }
00613 
00614 
00615 // Solves the system by considering the Cauchy M-estimatorrobust-function
00616 void CLaserOdometry2D::solveSystemNonLinear()
00617 {
00618     A.resize(num_valid_range,3); Aw.resize(num_valid_range,3);
00619     B.setSize(num_valid_range,1); Bw.setSize(num_valid_range,1);
00620     unsigned int cont = 0;
00621     const float kdtita = float(cols_i-1)/fovh;
00622 
00623     //Fill the matrix A and the vector B
00624     //The order of the variables will be (vx, vy, wz)
00625 
00626     for (unsigned int u = 1; u < cols_i-1; u++)
00627         if (null(u) == 0)
00628         {
00629             // Precomputed expressions
00630             const float tw = weights(u);
00631             const float tita = -0.5*fovh + u/kdtita;
00632 
00633             //Fill the matrix A
00634             A(cont, 0) = tw*(cos(tita) + dtita(u)*kdtita*sin(tita)/range_inter[image_level](u));
00635             A(cont, 1) = tw*(sin(tita) - dtita(u)*kdtita*cos(tita)/range_inter[image_level](u));
00636             A(cont, 2) = tw*(-yy[image_level](u)*cos(tita) + xx[image_level](u)*sin(tita) - dtita(u)*kdtita);
00637             B(cont,0) = tw*(-dt(u));
00638 
00639             cont++;
00640         }
00641 
00642     //Solve the linear system of equations using a minimum least squares method
00643     MatrixXf AtA, AtB;
00644     AtA.multiply_AtA(A);
00645     AtB.multiply_AtB(A,B);
00646     Var = AtA.ldlt().solve(AtB);
00647 
00648     //Covariance matrix calculation     Cov Order -> vx,vy,wz
00649     MatrixXf res(num_valid_range,1);
00650     res = A*Var - B;
00651     //cout << endl << "max res: " << res.maxCoeff();
00652     //cout << endl << "min res: " << res.minCoeff();
00653 
00655     //Compute the average dt
00656     float aver_dt = 0.f, aver_res = 0.f; unsigned int ind = 0;
00657     for (unsigned int u = 1; u < cols_i-1; u++)
00658         if (null(u) == 0)
00659         {
00660             aver_dt += fabsf(dt(u));
00661             aver_res += fabsf(res(ind++));
00662         }
00663     aver_dt /= cont; aver_res /= cont;
00664 //    printf("\n Aver dt = %f, aver res = %f", aver_dt, aver_res);
00665 
00666 
00667     const float k = 10.f/aver_dt; //200
00668     //float energy = 0.f;
00669     //for (unsigned int i=0; i<res.rows(); i++)
00670     //  energy += log(1.f + square(k*res(i)));
00671     //printf("\n\nEnergy(0) = %f", energy);
00672 
00673     //Solve iterative reweighted least squares
00674     //===================================================================
00675     for (unsigned int i=1; i<=iter_irls; i++)
00676     {
00677         cont = 0;
00678 
00679         for (unsigned int u = 1; u < cols_i-1; u++)
00680             if (null(u) == 0)
00681             {
00682                 const float res_weight = sqrt(1.f/(1.f + square(k*res(cont))));
00683 
00684                 //Fill the matrix Aw
00685                 Aw(cont,0) = res_weight*A(cont,0);
00686                 Aw(cont,1) = res_weight*A(cont,1);
00687                 Aw(cont,2) = res_weight*A(cont,2);
00688                 Bw(cont) = res_weight*B(cont);
00689                 cont++;
00690             }
00691 
00692         //Solve the linear system of equations using a minimum least squares method
00693         AtA.multiply_AtA(Aw);
00694         AtB.multiply_AtB(Aw,Bw);
00695         Var = AtA.ldlt().solve(AtB);
00696         res = A*Var - B;
00697 
00699         //energy = 0.f;
00700         //for (unsigned int j=0; j<res.rows(); j++)
00701         //      energy += log(1.f + square(k*res(j)));
00702         //printf("\nEnergy(%d) = %f", i, energy);
00703     }
00704 
00705     cov_odo = (1.f/float(num_valid_range-3))*AtA.inverse()*res.squaredNorm();
00706     kai_loc_level = Var;
00707     std::cout << endl << "COV_ODO: " << cov_odo  << endl;
00708 }
00709 
00710 void CLaserOdometry2D::Reset(CPose3D ini_pose, CObservation2DRangeScan scan)
00711 {
00712         //Set the initial pose
00713         laser_pose = ini_pose;
00714         laser_oldpose = ini_pose;
00715 
00716     //readLaser(scan);
00717         createImagePyramid();
00718     //readLaser(scan);
00719         createImagePyramid();
00720 }
00721 
00722 
00723 void CLaserOdometry2D::performWarping()
00724 {
00725         Matrix3f acu_trans; 
00726         acu_trans.setIdentity();
00727         for (unsigned int i=1; i<=level; i++)
00728                 acu_trans = transformations[i-1]*acu_trans;
00729 
00730         MatrixXf wacu(1,cols_i);
00731         wacu.assign(0.f);
00732         range_warped[image_level].assign(0.f);
00733 
00734         const float cols_lim = float(cols_i-1);
00735         const float kdtita = cols_lim/fovh;
00736 
00737         for (unsigned int j = 0; j<cols_i; j++)
00738         {                               
00739                 if (range[image_level](j) > 0.f)
00740                 {
00741                         //Transform point to the warped reference frame
00742                         const float x_w = acu_trans(0,0)*xx[image_level](j) + acu_trans(0,1)*yy[image_level](j) + acu_trans(0,2);
00743                         const float y_w = acu_trans(1,0)*xx[image_level](j) + acu_trans(1,1)*yy[image_level](j) + acu_trans(1,2);
00744                         const float tita_w = atan2(y_w, x_w);
00745                         const float range_w = sqrt(x_w*x_w + y_w*y_w);
00746 
00747                         //Calculate warping
00748                         const float uwarp = kdtita*(tita_w + 0.5*fovh);
00749 
00750                         //The warped pixel (which is not integer in general) contributes to all the surrounding ones
00751                         if (( uwarp >= 0.f)&&( uwarp < cols_lim))
00752                         {
00753                                 const int uwarp_l = uwarp;
00754                                 const int uwarp_r = uwarp_l + 1;
00755                                 const float delta_r = float(uwarp_r) - uwarp;
00756                                 const float delta_l = uwarp - float(uwarp_l);
00757 
00758                                 //Very close pixel
00759                                 if (abs(round(uwarp) - uwarp) < 0.05f)
00760                                 {
00761                                         range_warped[image_level](round(uwarp)) += range_w;
00762                                         wacu(round(uwarp)) += 1.f;
00763                                 }
00764                                 else
00765                                 {
00766                                         const float w_r = square(delta_l);
00767                                         range_warped[image_level](uwarp_r) += w_r*range_w;
00768                                         wacu(uwarp_r) += w_r;
00769 
00770                                         const float w_l = square(delta_r);
00771                                         range_warped[image_level](uwarp_l) += w_l*range_w;
00772                                         wacu(uwarp_l) += w_l;
00773                                 }
00774                         }
00775                 }
00776         }
00777 
00778         //Scale the averaged range and compute coordinates
00779         for (unsigned int u = 0; u<cols_i; u++)
00780         {       
00781                 if (wacu(u) > 0.f)
00782                 {
00783                         const float tita = -0.5f*fovh + float(u)/kdtita;
00784                         range_warped[image_level](u) /= wacu(u);
00785                         xx_warped[image_level](u) = range_warped[image_level](u)*cos(tita);
00786                         yy_warped[image_level](u) = range_warped[image_level](u)*sin(tita);
00787                 }
00788                 else
00789                 {
00790                         range_warped[image_level](u) = 0.f;
00791                         xx_warped[image_level](u) = 0.f;
00792                         yy_warped[image_level](u) = 0.f;
00793                 }
00794         }
00795 }
00796 
00797 
00798 
00799 
00800 
00801 void CLaserOdometry2D::filterLevelSolution()
00802 {
00803         //              Calculate Eigenvalues and Eigenvectors
00804         //----------------------------------------------------------
00805         SelfAdjointEigenSolver<MatrixXf> eigensolver(cov_odo);
00806         if (eigensolver.info() != Success) 
00807         { 
00808                 printf("Eigensolver couldn't find a solution. Pose is not updated");
00809                 return;
00810         }
00811         
00812         //First, we have to describe both the new linear and angular speeds in the "eigenvector" basis
00813         //-------------------------------------------------------------------------------------------------
00814         Matrix<float,3,3> Bii;
00815         Matrix<float,3,1> kai_b;
00816         Bii = eigensolver.eigenvectors();
00817 
00818         kai_b = Bii.colPivHouseholderQr().solve(kai_loc_level);
00819 
00820         //Second, we have to describe both the old linear and angular speeds in the "eigenvector" basis too
00821         //-------------------------------------------------------------------------------------------------
00822         CMatrixFloat31 kai_loc_sub;
00823 
00824         //Important: we have to substract the solutions from previous levels
00825         Matrix3f acu_trans;
00826         acu_trans.setIdentity();
00827         for (unsigned int i=0; i<level; i++)
00828                 acu_trans = transformations[i]*acu_trans;
00829 
00830         kai_loc_sub(0) = -fps*acu_trans(0,2);
00831         kai_loc_sub(1) = -fps*acu_trans(1,2);
00832         if (acu_trans(0,0) > 1.f)
00833                 kai_loc_sub(2) = 0.f;
00834         else
00835                 kai_loc_sub(2) = -fps*acos(acu_trans(0,0))*sign(acu_trans(1,0));
00836         kai_loc_sub += kai_loc_old;
00837 
00838         Matrix<float,3,1> kai_b_old;
00839         kai_b_old = Bii.colPivHouseholderQr().solve(kai_loc_sub);
00840 
00841         //Filter speed
00842         const float cf = 15e3f*expf(-int(level)), df = 0.05f*expf(-int(level));
00843 
00844         Matrix<float,3,1> kai_b_fil;
00845         for (unsigned int i=0; i<3; i++)
00846         {
00847                         kai_b_fil(i,0) = (kai_b(i,0) + (cf*eigensolver.eigenvalues()(i,0) + df)*kai_b_old(i,0))/(1.f + cf*eigensolver.eigenvalues()(i,0) + df);
00848                         //kai_b_fil_f(i,0) = (1.f*kai_b(i,0) + 0.f*kai_b_old_f(i,0))/(1.0f + 0.f);
00849         }
00850 
00851         //Transform filtered speed to local reference frame and compute transformation
00852         Matrix<float,3,1> kai_loc_fil = Bii.inverse().colPivHouseholderQr().solve(kai_b_fil);
00853 
00854         //transformation
00855         const float incrx = kai_loc_fil(0)/fps;
00856         const float incry = kai_loc_fil(1)/fps;
00857         const float rot = kai_loc_fil(2)/fps;
00858         transformations[level](0,0) = cos(rot);
00859         transformations[level](0,1) = -sin(rot);
00860         transformations[level](1,0) = sin(rot);
00861         transformations[level](1,1) = cos(rot);
00862         transformations[level](0,2) = incrx;
00863         transformations[level](1,2) = incry;
00864 }
00865 
00866 
00867 void CLaserOdometry2D::PoseUpdate()
00868 {
00869         //First, compute the overall transformation
00870         //---------------------------------------------------
00871         Matrix3f acu_trans;
00872         acu_trans.setIdentity();
00873         for (unsigned int i=1; i<=ctf_levels; i++)
00874                 acu_trans = transformations[i-1]*acu_trans;
00875 
00876 
00877         //                              Compute kai_loc and kai_abs
00878         //--------------------------------------------------------
00879         kai_loc(0) = fps*acu_trans(0,2);
00880         kai_loc(1) = fps*acu_trans(1,2);
00881         if (acu_trans(0,0) > 1.f)
00882                 kai_loc(2) = 0.f;
00883         else
00884                 kai_loc(2) = fps*acos(acu_trans(0,0))*sign(acu_trans(1,0));
00885 
00886         //cout << endl << "Arc cos (incr tita): " << kai_loc(2);
00887 
00888         float phi = laser_pose.yaw();
00889 
00890         kai_abs(0) = kai_loc(0)*cos(phi) - kai_loc(1)*sin(phi);
00891         kai_abs(1) = kai_loc(0)*sin(phi) + kai_loc(1)*cos(phi);
00892         kai_abs(2) = kai_loc(2);
00893 
00894 
00895         //                                              Update poses
00896         //-------------------------------------------------------
00897         laser_oldpose = laser_pose;
00898         math::CMatrixDouble33 aux_acu = acu_trans;
00899         poses::CPose2D pose_aux_2D(acu_trans(0,2), acu_trans(1,2), kai_loc(2)/fps);
00900     laser_pose = laser_pose + pose_aux_2D;
00901 
00902 
00903 
00904         //                              Compute kai_loc_old
00905         //-------------------------------------------------------
00906         phi = laser_pose.yaw();
00907         kai_loc_old(0) = kai_abs(0)*cos(phi) + kai_abs(1)*sin(phi);
00908         kai_loc_old(1) = -kai_abs(0)*sin(phi) + kai_abs(1)*cos(phi);
00909         kai_loc_old(2) = kai_abs(2);
00910 
00911 
00912     ROS_INFO("LASERodom = [%f %f %f]",laser_pose.x(),laser_pose.y(),laser_pose.yaw());
00913 
00914 
00915     // GET ROBOT POSE from LASER POSE
00916     //------------------------------  
00917     mrpt::poses::CPose3D LaserPoseOnTheRobot_inv;
00918     tf::StampedTransform transform;
00919     try
00920     {
00921         tf_listener.lookupTransform(last_scan.header.frame_id, "/base_link", ros::Time(0), transform);
00922     }
00923     catch (tf::TransformException &ex)
00924     {
00925         ROS_ERROR("%s",ex.what());
00926         ros::Duration(1.0).sleep();
00927     }
00928 
00929     //TF:transform -> mrpt::CPose3D (see mrpt-ros-bridge)
00930     const tf::Vector3 &t = transform.getOrigin();
00931     LaserPoseOnTheRobot_inv.x() = t[0];
00932     LaserPoseOnTheRobot_inv.y() = t[1];
00933     LaserPoseOnTheRobot_inv.z() = t[2];
00934     const tf::Matrix3x3 &basis = transform.getBasis();
00935     mrpt::math::CMatrixDouble33 R;
00936     for(int r = 0; r < 3; r++)
00937         for(int c = 0; c < 3; c++)
00938             R(r,c) = basis[r][c];
00939     LaserPoseOnTheRobot_inv.setRotationMatrix(R);
00940 
00941     //Compose Transformations
00942     robot_pose = laser_pose + LaserPoseOnTheRobot_inv;
00943     ROS_INFO("BASEodom = [%f %f %f]",robot_pose.x(),robot_pose.y(),robot_pose.yaw());
00944 
00945 
00946     // Estimate linear/angular speeds (mandatory for base_local_planner)
00947     // last_scan -> the last scan received
00948     // last_odom_time -> The time of the previous scan lasser used to estimate the pose
00949     //-------------------------------------------------------------------------------------
00950     double time_inc_sec = (last_scan.header.stamp - last_odom_time).toSec();
00951     last_odom_time = last_scan.header.stamp;
00952     double lin_speed = acu_trans(0,2) / time_inc_sec;
00953     //double lin_speed = sqrt( square(robot_oldpose.x()-robot_pose.x()) + square(robot_oldpose.y()-robot_pose.y()) )/time_inc_sec;
00954     double ang_inc = robot_pose.yaw() - robot_oldpose.yaw();
00955     if (ang_inc > 3.14159)
00956         ang_inc -= 2*3.14159;
00957     if (ang_inc < -3.14159)
00958         ang_inc += 2*3.14159;
00959     double ang_speed = ang_inc/time_inc_sec;
00960     robot_oldpose = robot_pose;
00961 
00962     //filter speeds
00963     /*
00964     last_m_lin_speeds.push_back(lin_speed);
00965     if (last_m_lin_speeds.size()>4)
00966         last_m_lin_speeds.erase(last_m_lin_speeds.begin());
00967     double sum = std::accumulate(last_m_lin_speeds.begin(), last_m_lin_speeds.end(), 0.0);
00968     lin_speed = sum / last_m_lin_speeds.size();
00969 
00970     last_m_ang_speeds.push_back(ang_speed);
00971     if (last_m_ang_speeds.size()>4)
00972         last_m_ang_speeds.erase(last_m_ang_speeds.begin());
00973     double sum2 = std::accumulate(last_m_ang_speeds.begin(), last_m_ang_speeds.end(), 0.0);
00974     ang_speed = sum2 / last_m_ang_speeds.size();
00975     */
00976 
00977     //first, we'll publish the odometry over tf
00978     //---------------------------------------
00979     geometry_msgs::TransformStamped odom_trans;
00980     odom_trans.header.stamp = ros::Time::now();
00981     odom_trans.header.frame_id = odom_frame_id;
00982     odom_trans.child_frame_id = base_frame_id;
00983     odom_trans.transform.translation.x = robot_pose.x();
00984     odom_trans.transform.translation.y = robot_pose.y();
00985     odom_trans.transform.translation.z = 0.0;
00986     odom_trans.transform.rotation = tf::createQuaternionMsgFromYaw(robot_pose.yaw());
00987     //send the transform
00988     odom_broadcaster.sendTransform(odom_trans);
00989 
00990     //next, we'll publish the odometry message over ROS
00991     //-------------------------------------------------
00992     nav_msgs::Odometry odom;
00993     odom.header.stamp = ros::Time::now();
00994     odom.header.frame_id = odom_frame_id;
00995     //set the position
00996     odom.pose.pose.position.x = robot_pose.x();
00997     odom.pose.pose.position.y = robot_pose.y();
00998     odom.pose.pose.position.z = 0.0;
00999     odom.pose.pose.orientation = tf::createQuaternionMsgFromYaw(robot_pose.yaw());
01000     //set the velocity
01001     odom.child_frame_id = base_frame_id;
01002     odom.twist.twist.linear.x = lin_speed;    //linear speed
01003     odom.twist.twist.linear.y = 0.0;
01004     odom.twist.twist.angular.z = ang_speed;   //angular speed
01005     //publish the message
01006     odom_pub.publish(odom);
01007 }
01008 
01009 
01010 
01011 //-----------------------------------------------------------------------------------
01012 //                                   CALLBACKS
01013 //-----------------------------------------------------------------------------------
01014 
01015 void CLaserOdometry2D::LaserCallBack(const sensor_msgs::LaserScan::ConstPtr& new_scan)
01016 {
01017     //Keep in memory the last received laser_scan
01018     last_scan = *new_scan;
01019 
01020     //Initialize module on first scan
01021     if (first_laser_scan)
01022     {
01023         Init();
01024         first_laser_scan = false;
01025     }
01026     else
01027     {
01028         //copy laser scan to internal variable
01029         for (unsigned int i = 0; i<width; i++)
01030             range_wf(i) = new_scan->ranges[i];
01031         new_scan_available = true;
01032     }
01033 }
01034 
01035 //-----------------------------------------------------------------------------------
01036 //                                   MAIN
01037 //-----------------------------------------------------------------------------------
01038 int main(int argc, char** argv)
01039 {
01040     ros::init(argc, argv, "RF2O_LaserOdom");
01041 
01042     CLaserOdometry2D myLaserOdom;
01043 
01044     //Main Loop
01045     //----------
01046     ROS_INFO("initialization complete...Looping");
01047     ros::Rate loop_rate(myLaserOdom.freq);
01048     while (ros::ok())
01049     {
01050         ros::spinOnce();        //Check for new laser scans
01051 
01052         if( myLaserOdom.is_initialized() && myLaserOdom.scan_available() )
01053         {            
01054             //Process odometry estimation
01055             myLaserOdom.odometryCalculation();
01056         }
01057         else
01058         {
01059             ROS_WARN("Waiting for laser_scans....") ;
01060         }
01061 
01062         loop_rate.sleep();
01063     }
01064     return(0);
01065 }


rf2o_laser_odometry
Author(s): Mariano Jaimez , Javier G. Monroy
autogenerated on Thu Jun 6 2019 21:16:31