laser_icp_alg_node.cpp
Go to the documentation of this file.
00001 #include "laser_icp_alg_node.h"
00002 
00003 LaserIcpAlgNode::LaserIcpAlgNode(void) :
00004   algorithm_base::IriBaseAlgorithm<LaserIcpAlgorithm>()
00005 {
00006   ROS_INFO("Laser ICP: Warming up..");
00007   //init class attributes if necessary
00008   //this->loop_rate_ = 2;//in [Hz]
00009 
00010   // [init publishers]
00011 
00012   // [init subscribers]
00013 
00014   // [init services]
00015   this->get_relative_pose_server_ = this->public_node_handle_.advertiseService("get_relative_pose", &LaserIcpAlgNode::get_relative_poseCallback, this);
00016 
00017   // [init clients]
00018 
00019   // [init action servers]
00020 
00021   // [init action clients]
00022 
00023   // **** init parameters
00024 
00025   initParams();
00026 
00027   // **** state variables
00028 
00029   input_.laser[0] = 0.0;
00030   input_.laser[1] = 0.0;
00031   input_.laser[2] = 0.0;
00032 
00033 }
00034 
00035 LaserIcpAlgNode::~LaserIcpAlgNode(void)
00036 {
00037   // [free dynamic memory]
00038 }
00039 
00040 void LaserIcpAlgNode::mainNodeThread(void)
00041 {
00042   // [fill msg structures]
00043 
00044   // [fill srv structure and make request to the server]
00045 
00046   // [fill action structure and make request to the action server]
00047 
00048   // [publish messages]
00049 }
00050 
00051 /*  [subscriber callbacks] */
00052 
00053 /*  [service callbacks] */
00054 bool LaserIcpAlgNode::get_relative_poseCallback(
00055                     iri_laser_icp::GetRelativePose::Request &req,
00056                     iri_laser_icp::GetRelativePose::Response &res)
00057 {
00058   ROS_DEBUG("Laser ICP: New Request");
00059 
00060   //use appropiate mutex to shared variables if necessary
00061   //this->alg_.lock();
00062   //this->get_relative_pose_mutex_.enter();
00063 
00064 //   if(this->alg_.isRunning())
00065 //   {
00066     //ROS_INFO("LaserIcpAlgNode::get_relative_poseCallback: Processin New Request!");
00067 
00068     //do operations with req and output on res
00069     input_.min_reading = std::max(float(min_laser_range_), std::min(req.scan_ref.range_min,req.scan_sens.range_min));
00070     input_.max_reading = std::min(float(max_laser_range_), std::max(req.scan_ref.range_max,req.scan_sens.range_max));
00071     laserScanToLDP(req.scan_ref, ref_ldp_scan_);
00072     laserScanToLDP(req.scan_sens, sens_ldp_scan_);
00073     
00074     // first guess given
00075     input_.first_guess[0] = req.prior_d.position.x;
00076     input_.first_guess[1] = req.prior_d.position.y;
00077     if (req.prior_d.orientation.x != 0 || req.prior_d.orientation.y != 0 || req.prior_d.orientation.z != 0 || req.prior_d.orientation.w != 0)
00078       input_.first_guess[2] = tf::getYaw(req.prior_d.orientation);
00079     else
00080       input_.first_guess[2] = 0;
00081       
00082     processScans();
00083 
00084     // output_
00085 
00086     //       struct sm_result {
00087     //   /** 1 if the result is valid */
00088     //   int valid;
00089       
00090     //   /** Scan matching result (x,y,theta) */
00091     //   double x[3];
00092       
00093     //   /** Number of iterations done */
00094     //   int iterations;
00095     //   * Number of valid correspondence in the end 
00096     //   int nvalid;
00097     //   /** Total correspondence error */
00098     //   double error;
00099       
00100     //   /** Fields used for covariance computation */
00101     //   #ifndef RUBY
00102     //     gsl_matrix *cov_x_m;  
00103     //     gsl_matrix *dx_dy1_m;
00104     //     gsl_matrix *dx_dy2_m;
00105     //   #endif
00106     // };
00107 
00108 //     #include <gsl/gsl_matrix.h>
00109  
00110 // int print_matrix(FILE *f, const gsl_matrix *m)
00111 // {
00112 //         int status, n = 0;
00113  
00114 //         for (size_t i = 0; i < m->size1; i++) {
00115 //                 for (size_t j = 0; j < m->size2; j++) {
00116 //                         if ((status = fprintf(f, "%g ", gsl_matrix_get(m, i, j))) < 0)
00117 //                                 return -1;
00118 //                         n += status;
00119 //                 }
00120  
00121 //                 if ((status = fprintf(f, "\n")) < 0)
00122 //                         return -1;
00123 //                 n += status;
00124 //         }
00125  
00126 //         return n;
00127 // }
00128 
00129 
00130     if (output_.valid)
00131     {
00132       res.pose_rel.pose.pose.position.x = output_.x[0];
00133       res.pose_rel.pose.pose.position.y = output_.x[1];
00134       res.pose_rel.pose.pose.orientation = tf::createQuaternionMsgFromYaw(output_.x[2]);
00135 
00136       res.pose_rel.pose.covariance[0]  = gsl_matrix_get(output_.cov_x_m, 0, 0);
00137       res.pose_rel.pose.covariance[1]  = gsl_matrix_get(output_.cov_x_m, 0, 1);
00138       res.pose_rel.pose.covariance[5]  = gsl_matrix_get(output_.cov_x_m, 0, 2);
00139       res.pose_rel.pose.covariance[6]  = gsl_matrix_get(output_.cov_x_m, 1, 0);
00140       res.pose_rel.pose.covariance[7]  = gsl_matrix_get(output_.cov_x_m, 1, 1);
00141       res.pose_rel.pose.covariance[11] = gsl_matrix_get(output_.cov_x_m, 1, 2);
00142       res.pose_rel.pose.covariance[30] = gsl_matrix_get(output_.cov_x_m, 2, 0);
00143       res.pose_rel.pose.covariance[31] = gsl_matrix_get(output_.cov_x_m, 2, 1);
00144       res.pose_rel.pose.covariance[35] = gsl_matrix_get(output_.cov_x_m, 2, 2);
00145 
00146       res.success = true;
00147     }
00148     else
00149     {
00150       res.pose_rel.pose.pose.position.x = 0;
00151       res.pose_rel.pose.pose.position.y = 0;
00152       res.pose_rel.pose.pose.orientation = tf::createQuaternionMsgFromYaw(0);
00153 
00154       res.pose_rel.pose.covariance[0]  = 0;
00155       res.pose_rel.pose.covariance[1]  = 0;
00156       res.pose_rel.pose.covariance[5]  = 0;
00157       res.pose_rel.pose.covariance[6]  = 0;
00158       res.pose_rel.pose.covariance[7]  = 0;
00159       res.pose_rel.pose.covariance[11] = 0;
00160       res.pose_rel.pose.covariance[30] = 0;
00161       res.pose_rel.pose.covariance[31] = 0;
00162       res.pose_rel.pose.covariance[35] = 0;
00163 
00164       res.success = false;
00165     }
00166 
00167 //   }
00168 //   else
00169 //   {
00170 //     ROS_INFO("LaserIcpAlgNode::get_relative_poseCallback: ERROR: alg is not on run mode yet.");
00171 //   }
00172 
00173   //unlock previously blocked shared variables
00174   //this->alg_.unlock();
00175   //this->get_relative_pose_mutex_.exit();
00176 
00177   return true;
00178 }
00179 
00180 /*  [action callbacks] */
00181 
00182 /*  [action requests] */
00183 
00184 void LaserIcpAlgNode::node_config_update(Config &config, uint32_t level)
00185 {
00186   this->alg_.lock();
00187 
00188   this->alg_.unlock();
00189 }
00190 
00191 void LaserIcpAlgNode::addNodeDiagnostics(void)
00192 {
00193 }
00194 
00195 /* main function */
00196 int main(int argc,char *argv[])
00197 {
00198   return algorithm_base::main<LaserIcpAlgNode>(argc, argv, "laser_icp_alg_node");
00199 }
00200 
00201 
00202 void LaserIcpAlgNode::initParams()
00203 {
00204 
00205   if (!private_node_handle_.getParam ("min_laser_range", min_laser_range_))
00206     min_laser_range_ = 0.0;
00207 
00208   if (!private_node_handle_.getParam ("max_laser_range", max_laser_range_))
00209     max_laser_range_ = 1.0e10;
00210   
00211   if (!private_node_handle_.getParam ("use_alpha_beta", use_alpha_beta_))
00212     use_alpha_beta_ = false;
00213 
00214   if (!private_node_handle_.getParam ("alpha", alpha_))
00215     alpha_ = 1.0;
00216   
00217   if (!private_node_handle_.getParam ("beta", beta_))
00218     beta_ = 0.8;
00219 
00220  // **** CSM parameters - comments copied from algos.h (by Andrea Censi)
00221 
00222   // Maximum angular displacement between scans
00223   if (!private_node_handle_.getParam ("max_angular_correction_deg", input_.max_angular_correction_deg))
00224     input_.max_angular_correction_deg = 45.0;
00225 
00226   // Maximum translation between scans (m)
00227   if (!private_node_handle_.getParam ("max_linear_correction", input_.max_linear_correction))
00228     input_.max_linear_correction = 0.50;
00229 
00230   // Maximum ICP cycle iterations
00231   if (!private_node_handle_.getParam ("max_iterations", input_.max_iterations))
00232     input_.max_iterations = 10;
00233 
00234   // A threshold for stopping (m)
00235   if (!private_node_handle_.getParam ("epsilon_xy", input_.epsilon_xy))
00236     input_.epsilon_xy = 0.000001;
00237 
00238   // A threshold for stopping (rad)
00239   if (!private_node_handle_.getParam ("epsilon_theta", input_.epsilon_theta))
00240     input_.epsilon_theta = 0.000001;
00241 
00242   // Maximum distance for a correspondence to be valid
00243   if (!private_node_handle_.getParam ("max_correspondence_dist", input_.max_correspondence_dist))
00244     input_.max_correspondence_dist = 0.3;
00245 
00246   // Noise in the scan (m)
00247   if (!private_node_handle_.getParam ("sigma", input_.sigma))
00248     input_.sigma = 0.010;
00249 
00250   // Use smart tricks for finding correspondences.cov
00251   if (!private_node_handle_.getParam ("use_corr_tricks", input_.use_corr_tricks))
00252     input_.use_corr_tricks = 1;
00253 
00254   // Restart: Restart if error is over threshold
00255   if (!private_node_handle_.getParam ("restart", input_.restart))
00256     input_.restart = 0;
00257 
00258   // Restart: Threshold for restarting
00259   if (!private_node_handle_.getParam ("restart_threshold_mean_error", input_.restart_threshold_mean_error))
00260     input_.restart_threshold_mean_error = 0.01;
00261 
00262   // Restart: displacement for restarting. (m)
00263   if (!private_node_handle_.getParam ("restart_dt", input_.restart_dt))
00264     input_.restart_dt = 1.0;
00265 
00266   // Restart: displacement for restarting. (rad)
00267   if (!private_node_handle_.getParam ("restart_dtheta", input_.restart_dtheta))
00268     input_.restart_dtheta = 0.1;
00269 
00270   // Max distance for staying in the same clustering
00271   if (!private_node_handle_.getParam ("clustering_threshold", input_.clustering_threshold))
00272     input_.clustering_threshold = 0.25;
00273 
00274   // Number of neighbour rays used to estimate the orientation
00275   if (!private_node_handle_.getParam ("orientation_neighbourhood", input_.orientation_neighbourhood))
00276     input_.orientation_neighbourhood = 20;
00277 
00278   // If 0, it's vanilla ICP
00279   if (!private_node_handle_.getParam ("use_point_to_line_distance", input_.use_point_to_line_distance))
00280     input_.use_point_to_line_distance = 1;
00281 
00282   // Discard correspondences based on the angles
00283   if (!private_node_handle_.getParam ("do_alpha_test", input_.do_alpha_test))
00284     input_.do_alpha_test = 0;
00285 
00286   // Discard correspondences based on the angles - threshold angle, in degrees
00287   if (!private_node_handle_.getParam ("do_alpha_test_thresholdDeg", input_.do_alpha_test_thresholdDeg))
00288     input_.do_alpha_test_thresholdDeg = 20.0;
00289 
00290   // Percentage of correspondences to consider: if 0.9,
00291   // always discard the top 10% of correspondences with more error
00292   if (!private_node_handle_.getParam ("outliers_maxPerc", input_.outliers_maxPerc))
00293     input_.outliers_maxPerc = 0.90;
00294 
00295   // Parameters describing a simple adaptive algorithm for discarding.
00296   //  1) Order the errors.
00297   //  2) Choose the percentile according to outliers_adaptive_order.
00298   //     (if it is 0.7, get the 70% percentile)
00299   //  3) Define an adaptive threshold multiplying outliers_adaptive_mult
00300   //     with the value of the error at the chosen percentile.
00301   //  4) Discard correspondences over the threshold.
00302   //  This is useful to be conservative; yet remove the biggest errors.
00303   if (!private_node_handle_.getParam ("outliers_adaptive_order", input_.outliers_adaptive_order))
00304     input_.outliers_adaptive_order = 0.7;
00305 
00306   if (!private_node_handle_.getParam ("outliers_adaptive_mult", input_.outliers_adaptive_mult))
00307     input_.outliers_adaptive_mult = 2.0;
00308 
00309   //If you already have a guess of the solution, you can compute the polar angle
00310   //  of the points of one scan in the new position. If the polar angle is not a monotone
00311   //  function of the readings index, it means that the surface is not visible in the
00312   //  next position. If it is not visible, then we don't use it for matching.
00313   if (!private_node_handle_.getParam ("do_visibility_test", input_.do_visibility_test))
00314     input_.do_visibility_test = 0;
00315 
00316   // no two points in laser_sens can have the same corr.
00317   if (!private_node_handle_.getParam ("outliers_remove_doubles", input_.outliers_remove_doubles))
00318     input_.outliers_remove_doubles = 1;
00319 
00320   // If 1, computes the covariance of ICP using the method http://purl.org/censi/2006/icpcov
00321   if (!private_node_handle_.getParam ("do_compute_covariance", input_.do_compute_covariance))
00322     input_.do_compute_covariance = 0;
00323 
00324   // Checks that find_correspondences_tricks gives the right answer
00325   if (!private_node_handle_.getParam ("debug_verify_tricks", input_.debug_verify_tricks))
00326     input_.debug_verify_tricks = 0;
00327 
00328   // If 1, the field 'true_alpha' (or 'alpha') in the first scan is used to compute the
00329   // incidence beta, and the factor (1/cos^2(beta)) used to weight the correspondence.");
00330   if (!private_node_handle_.getParam ("use_ml_weights", input_.use_ml_weights))
00331     input_.use_ml_weights = 0;
00332 
00333   // If 1, the field 'readings_sigma' in the second scan is used to weight the
00334   // correspondence by 1/sigma^2
00335   if (!private_node_handle_.getParam ("use_sigma_weights", input_.use_sigma_weights))
00336     input_.use_sigma_weights = 0;
00337 }
00338 
00339 
00340 void LaserIcpAlgNode::processScans()
00341 {
00342   struct timeval start, end;    // used for timing
00343   gettimeofday(&start, NULL);
00344 
00345   //ROS_INFO("ProcessScans");
00346 
00347   ref_ldp_scan_->odometry[0] = 0;
00348   ref_ldp_scan_->odometry[1] = 0;
00349   ref_ldp_scan_->odometry[2] = 0;
00350 
00351   ref_ldp_scan_->estimate[0] = 0;
00352   ref_ldp_scan_->estimate[1] = 0;
00353   ref_ldp_scan_->estimate[2] = 0;
00354 
00355   ref_ldp_scan_->true_pose[0] = 0;
00356   ref_ldp_scan_->true_pose[1] = 0;
00357   ref_ldp_scan_->true_pose[2] = 0;
00358 
00359   input_.laser_ref  = ref_ldp_scan_;
00360   input_.laser_sens = sens_ldp_scan_;
00361 
00362   // *** scan match - using point to line icp from CSM
00363 
00364   sm_icp(&input_, &output_);
00365 
00366   ROS_DEBUG("Laser ICP:ProcessScans: output valid? %d", output_.valid);
00367 
00368   if (output_.valid)
00369   {
00370     // the correction of the laser's position, in the laser frame
00371 
00372     ROS_INFO_XYT("", output_.x[0], output_.x[1], output_.x[2]);
00373     //ROS_DEBUG("Laser ICP: it: %d, valid: %d, error: %f", output_.iterations, output_.nvalid, output_.error);
00374     //ROS_INFO("Laser ICP: Covariance matrix X (%lu,%lu)",output_.cov_x_m->size1,output_.cov_x_m->size2);
00375     //gsl_matrix_fprintf(stdout,output_.cov_x_m,"%f");
00376     //ROS_INFO("Laser ICP: Covariance matrix DX DY1 (%lu,%lu)",output_.dx_dy1_m->size1,output_.dx_dy1_m->size2);
00377     //gsl_matrix_fprintf(stdout,output_.dx_dy1_m,"%f");
00378     //ROS_INFO("Laser ICP: Covariance matrix DX DY2 (%lu,%lu)",output_.dx_dy2_m->size1,output_.dx_dy2_m->size2);
00379     //gsl_matrix_fprintf(stdout,output_.dx_dy2_m,"%f");
00380     //ROS_INFO("Laser ICP END");
00381 
00382   }
00383   else
00384   {
00385     ROS_ERROR("Laser ICP: Output invalid. Error in scan matching");
00386   }
00387 
00388   // **** swap old and new
00389 
00390   ld_free(ref_ldp_scan_);
00391   ld_free(sens_ldp_scan_);
00392 
00393   // **** statistics
00394 
00395   gettimeofday(&end, NULL);
00396   double dur_total = ((end.tv_sec   * 1000000 + end.tv_usec  ) -
00397                       (start.tv_sec * 1000000 + start.tv_usec)) / 1000.0;
00398   ROS_DEBUG("Laser ICP: matching duration: %.1f ms", dur_total);
00399 }
00400 
00401 void LaserIcpAlgNode::laserScanToLDP(const sensor_msgs::LaserScan& scan_msg,
00402                                             LDP& ldp)
00403 {
00404   unsigned int n = scan_msg.ranges.size();
00405   ldp = ld_alloc_new(n);
00406 
00407   for (unsigned int i = 0; i < n; i++)
00408   {
00409     // calculate position in laser frame
00410 
00411     double r = scan_msg.ranges[i];
00412 
00413     if (r > scan_msg.range_min && r < scan_msg.range_max)
00414     {
00415       // fill in laser scan data
00416 
00417       ldp->valid[i] = 1;
00418       ldp->readings[i] = r;
00419     }
00420     else
00421     {
00422       ldp->valid[i] = 0;
00423       ldp->readings[i] = -1;  // for invalid range
00424       //ROS_INFO("ICP: scan %i is invalid (range)",i);
00425     }
00426 
00427     ldp->theta[i]    = scan_msg.angle_min + i * scan_msg.angle_increment;
00428 
00429     ldp->cluster[i]  = -1;
00430   }
00431 
00432   ldp->min_theta = ldp->theta[0];
00433   ldp->max_theta = ldp->theta[n-1];
00434 
00435   ldp->odometry[0] = 0.0;
00436   ldp->odometry[1] = 0.0;
00437   ldp->odometry[2] = 0.0;
00438 
00439   ldp->true_pose[0] = 0.0;
00440   ldp->true_pose[1] = 0.0;
00441   ldp->true_pose[2] = 0.0;
00442 }
00443 
00444 void LaserIcpAlgNode::ROS_INFO_XYT(const std::string & str,const float & x,const float & y,const float & th)
00445 {
00446   ROS_DEBUG("Laser ICP: %s",str.c_str());
00447   ROS_DEBUG("\033[31mx:\033[0m%f \033[32my:\033[0m%f \033[34mth:\033[0m%f ",
00448            x,y,th);
00449 }
00450 


iri_laser_icp
Author(s): Marti
autogenerated on Fri Dec 6 2013 21:20:17