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
00027
00028
00029 CLaserOdometry2D::CLaserOdometry2D()
00030 {
00031 ROS_INFO("Initializing RF2O node...");
00032
00033
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
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
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
00070 ROS_INFO("Got first Laser Scan .... Configuring node");
00071 width = last_scan.ranges.size();
00072 cols = width;
00073 fovh = fabs(last_scan.angle_max - last_scan.angle_min);
00074 ctf_levels = 5;
00075 iter_irls = 5;
00076
00077
00078
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
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
00105 laser_pose = LaserPoseOnTheRobot;
00106 laser_oldpose = LaserPoseOnTheRobot;
00107
00108
00109
00110 range_wf.setSize(1, width);
00111
00112
00113 transformations.resize(ctf_levels);
00114 for (unsigned int i = 0; i < ctf_levels; i++)
00115 transformations[i].resize(3, 3);
00116
00117
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;
00174 num_valid_range = 0;
00175
00176
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
00191
00192
00193 m_clock.Tic();
00194 createImagePyramid();
00195
00196
00197 for (unsigned int i=0; i<ctf_levels; i++)
00198 {
00199
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
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
00218 calculateCoord();
00219
00220
00221 findNullPoints();
00222
00223
00224 calculaterangeDerivativesSurface();
00225
00226
00227
00228
00229
00230 computeWeights();
00231
00232
00233 if (num_valid_range > 3)
00234 {
00235 solveSystemNonLinear();
00236
00237 }
00238
00239
00240 filterLevelSolution();
00241 }
00242
00243 m_runtime = 1000*m_clock.Tac();
00244 ROS_INFO("Time odometry (ms): %f", m_runtime);
00245
00246
00247 PoseUpdate();
00248 new_scan_available = false;
00249 }
00250
00251
00252 void CLaserOdometry2D::createImagePyramid()
00253 {
00254 const float max_range_dif = 0.3f;
00255
00256
00257 range_old.swap(range);
00258 xx_old.swap(xx);
00259 yy_old.swap(yy);
00260
00261
00262
00263
00264 unsigned int pyr_levels = round(log2(round(float(width)/float(cols)))) + ctf_levels;
00265
00266
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
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
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
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
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
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
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
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
00447
00448
00449 rtita.resize(1,cols_i);
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
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
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
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
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
00527 weights.assign(0.f);
00528
00529
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
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
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
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
00582
00583
00584 for (unsigned int u = 1; u < cols_i-1; u++)
00585 if (null(u) == 0)
00586 {
00587
00588 const float tw = weights(u);
00589 const float tita = -0.5*fovh + u/kdtita;
00590
00591
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
00601 MatrixXf AtA, AtB;
00602 AtA.multiply_AtA(A);
00603 AtB.multiply_AtB(A,B);
00604 Var = AtA.ldlt().solve(AtB);
00605
00606
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
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
00624
00625
00626 for (unsigned int u = 1; u < cols_i-1; u++)
00627 if (null(u) == 0)
00628 {
00629
00630 const float tw = weights(u);
00631 const float tita = -0.5*fovh + u/kdtita;
00632
00633
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
00643 MatrixXf AtA, AtB;
00644 AtA.multiply_AtA(A);
00645 AtB.multiply_AtB(A,B);
00646 Var = AtA.ldlt().solve(AtB);
00647
00648
00649 MatrixXf res(num_valid_range,1);
00650 res = A*Var - B;
00651
00652
00653
00655
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
00665
00666
00667 const float k = 10.f/aver_dt;
00668
00669
00670
00671
00672
00673
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
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
00693 AtA.multiply_AtA(Aw);
00694 AtB.multiply_AtB(Aw,Bw);
00695 Var = AtA.ldlt().solve(AtB);
00696 res = A*Var - B;
00697
00699
00700
00701
00702
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
00713 laser_pose = ini_pose;
00714 laser_oldpose = ini_pose;
00715
00716
00717 createImagePyramid();
00718
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
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
00748 const float uwarp = kdtita*(tita_w + 0.5*fovh);
00749
00750
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
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
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
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
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
00821
00822 CMatrixFloat31 kai_loc_sub;
00823
00824
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
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
00849 }
00850
00851
00852 Matrix<float,3,1> kai_loc_fil = Bii.inverse().colPivHouseholderQr().solve(kai_b_fil);
00853
00854
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
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
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
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
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
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
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
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
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
00947
00948
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
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
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
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
00988 odom_broadcaster.sendTransform(odom_trans);
00989
00990
00991
00992 nav_msgs::Odometry odom;
00993 odom.header.stamp = ros::Time::now();
00994 odom.header.frame_id = odom_frame_id;
00995
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
01001 odom.child_frame_id = base_frame_id;
01002 odom.twist.twist.linear.x = lin_speed;
01003 odom.twist.twist.linear.y = 0.0;
01004 odom.twist.twist.angular.z = ang_speed;
01005
01006 odom_pub.publish(odom);
01007 }
01008
01009
01010
01011
01012
01013
01014
01015 void CLaserOdometry2D::LaserCallBack(const sensor_msgs::LaserScan::ConstPtr& new_scan)
01016 {
01017
01018 last_scan = *new_scan;
01019
01020
01021 if (first_laser_scan)
01022 {
01023 Init();
01024 first_laser_scan = false;
01025 }
01026 else
01027 {
01028
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
01037
01038 int main(int argc, char** argv)
01039 {
01040 ros::init(argc, argv, "RF2O_LaserOdom");
01041
01042 CLaserOdometry2D myLaserOdom;
01043
01044
01045
01046 ROS_INFO("initialization complete...Looping");
01047 ros::Rate loop_rate(myLaserOdom.freq);
01048 while (ros::ok())
01049 {
01050 ros::spinOnce();
01051
01052 if( myLaserOdom.is_initialized() && myLaserOdom.scan_available() )
01053 {
01054
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 }