00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include <laser_scan_matcher/laser_scan_matcher.h>
00039 #include <pcl_conversions/pcl_conversions.h>
00040 #include <boost/assign.hpp>
00041
00042 namespace scan_tools
00043 {
00044
00045 LaserScanMatcher::LaserScanMatcher(ros::NodeHandle nh, ros::NodeHandle nh_private):
00046 nh_(nh),
00047 nh_private_(nh_private),
00048 initialized_(false),
00049 received_imu_(false),
00050 received_odom_(false),
00051 received_vel_(false)
00052 {
00053 ROS_INFO("Starting LaserScanMatcher");
00054
00055
00056
00057 initParams();
00058
00059
00060
00061 f2b_.setIdentity();
00062 f2b_kf_.setIdentity();
00063 input_.laser[0] = 0.0;
00064 input_.laser[1] = 0.0;
00065 input_.laser[2] = 0.0;
00066
00067
00068 output_.cov_x_m = 0;
00069 output_.dx_dy1_m = 0;
00070 output_.dx_dy2_m = 0;
00071
00072
00073
00074 if (publish_pose_)
00075 {
00076 pose_publisher_ = nh_.advertise<geometry_msgs::Pose2D>(
00077 "pose2D", 5);
00078 }
00079
00080 if (publish_pose_stamped_)
00081 {
00082 pose_stamped_publisher_ = nh_.advertise<geometry_msgs::PoseStamped>(
00083 "pose_stamped", 5);
00084 }
00085
00086 if (publish_pose_with_covariance_)
00087 {
00088 pose_with_covariance_publisher_ = nh_.advertise<geometry_msgs::PoseWithCovariance>(
00089 "pose_with_covariance", 5);
00090 }
00091
00092 if (publish_pose_with_covariance_stamped_)
00093 {
00094 pose_with_covariance_stamped_publisher_ = nh_.advertise<geometry_msgs::PoseWithCovarianceStamped>(
00095 "pose_with_covariance_stamped", 5);
00096 }
00097
00098
00099
00100 if (use_cloud_input_)
00101 {
00102 cloud_subscriber_ = nh_.subscribe(
00103 "cloud", 1, &LaserScanMatcher::cloudCallback, this);
00104 }
00105 else
00106 {
00107 scan_subscriber_ = nh_.subscribe(
00108 "scan", 1, &LaserScanMatcher::scanCallback, this);
00109 }
00110
00111 if (use_imu_)
00112 {
00113 imu_subscriber_ = nh_.subscribe(
00114 "imu/data", 1, &LaserScanMatcher::imuCallback, this);
00115 }
00116 if (use_odom_)
00117 {
00118 odom_subscriber_ = nh_.subscribe(
00119 "odom", 1, &LaserScanMatcher::odomCallback, this);
00120 }
00121 if (use_vel_)
00122 {
00123 if (stamped_vel_)
00124 vel_subscriber_ = nh_.subscribe(
00125 "vel", 1, &LaserScanMatcher::velStmpCallback, this);
00126 else
00127 vel_subscriber_ = nh_.subscribe(
00128 "vel", 1, &LaserScanMatcher::velCallback, this);
00129 }
00130 }
00131
00132 LaserScanMatcher::~LaserScanMatcher()
00133 {
00134 ROS_INFO("Destroying LaserScanMatcher");
00135 }
00136
00137 void LaserScanMatcher::initParams()
00138 {
00139 if (!nh_private_.getParam ("base_frame", base_frame_))
00140 base_frame_ = "base_link";
00141 if (!nh_private_.getParam ("fixed_frame", fixed_frame_))
00142 fixed_frame_ = "world";
00143
00144
00145
00146
00147
00148 if (!nh_private_.getParam ("use_cloud_input", use_cloud_input_))
00149 use_cloud_input_= false;
00150
00151 if (use_cloud_input_)
00152 {
00153 if (!nh_private_.getParam ("cloud_range_min", cloud_range_min_))
00154 cloud_range_min_ = 0.1;
00155 if (!nh_private_.getParam ("cloud_range_max", cloud_range_max_))
00156 cloud_range_max_ = 50.0;
00157 if (!nh_private_.getParam ("cloud_res", cloud_res_))
00158 cloud_res_ = 0.05;
00159
00160 input_.min_reading = cloud_range_min_;
00161 input_.max_reading = cloud_range_max_;
00162 }
00163
00164
00165
00166
00167 if (!nh_private_.getParam ("kf_dist_linear", kf_dist_linear_))
00168 kf_dist_linear_ = 0.10;
00169 if (!nh_private_.getParam ("kf_dist_angular", kf_dist_angular_))
00170 kf_dist_angular_ = 10.0 * (M_PI / 180.0);
00171
00172 kf_dist_linear_sq_ = kf_dist_linear_ * kf_dist_linear_;
00173
00174
00175
00176
00177
00178
00179
00180 if (!nh_private_.getParam ("use_imu", use_imu_))
00181 use_imu_ = true;
00182 if (!nh_private_.getParam ("use_odom", use_odom_))
00183 use_odom_ = true;
00184 if (!nh_private_.getParam ("use_vel", use_vel_))
00185 use_vel_ = false;
00186
00187
00188
00189
00190 if (!nh_private_.getParam ("stamped_vel", stamped_vel_))
00191 stamped_vel_ = false;
00192
00193
00194
00195
00196
00197 if (!nh_private_.getParam ("publish_tf", publish_tf_))
00198 publish_tf_ = true;
00199 if (!nh_private_.getParam ("publish_pose", publish_pose_))
00200 publish_pose_ = true;
00201 if (!nh_private_.getParam ("publish_pose_stamped", publish_pose_stamped_))
00202 publish_pose_stamped_ = false;
00203 if (!nh_private_.getParam ("publish_pose_with_covariance", publish_pose_with_covariance_))
00204 publish_pose_with_covariance_ = false;
00205 if (!nh_private_.getParam ("publish_pose_with_covariance_stamped", publish_pose_with_covariance_stamped_))
00206 publish_pose_with_covariance_stamped_ = false;
00207
00208 if (!nh_private_.getParam("position_covariance", position_covariance_))
00209 {
00210 position_covariance_.resize(3);
00211 std::fill(position_covariance_.begin(), position_covariance_.end(), 1e-9);
00212 }
00213
00214 if (!nh_private_.getParam("orientation_covariance", orientation_covariance_))
00215 {
00216 orientation_covariance_.resize(3);
00217 std::fill(orientation_covariance_.begin(), orientation_covariance_.end(), 1e-9);
00218 }
00219
00220
00221
00222 if (!nh_private_.getParam ("max_angular_correction_deg", input_.max_angular_correction_deg))
00223 input_.max_angular_correction_deg = 45.0;
00224
00225
00226 if (!nh_private_.getParam ("max_linear_correction", input_.max_linear_correction))
00227 input_.max_linear_correction = 0.50;
00228
00229
00230 if (!nh_private_.getParam ("max_iterations", input_.max_iterations))
00231 input_.max_iterations = 10;
00232
00233
00234 if (!nh_private_.getParam ("epsilon_xy", input_.epsilon_xy))
00235 input_.epsilon_xy = 0.000001;
00236
00237
00238 if (!nh_private_.getParam ("epsilon_theta", input_.epsilon_theta))
00239 input_.epsilon_theta = 0.000001;
00240
00241
00242 if (!nh_private_.getParam ("max_correspondence_dist", input_.max_correspondence_dist))
00243 input_.max_correspondence_dist = 0.3;
00244
00245
00246 if (!nh_private_.getParam ("sigma", input_.sigma))
00247 input_.sigma = 0.010;
00248
00249
00250 if (!nh_private_.getParam ("use_corr_tricks", input_.use_corr_tricks))
00251 input_.use_corr_tricks = 1;
00252
00253
00254 if (!nh_private_.getParam ("restart", input_.restart))
00255 input_.restart = 0;
00256
00257
00258 if (!nh_private_.getParam ("restart_threshold_mean_error", input_.restart_threshold_mean_error))
00259 input_.restart_threshold_mean_error = 0.01;
00260
00261
00262 if (!nh_private_.getParam ("restart_dt", input_.restart_dt))
00263 input_.restart_dt = 1.0;
00264
00265
00266 if (!nh_private_.getParam ("restart_dtheta", input_.restart_dtheta))
00267 input_.restart_dtheta = 0.1;
00268
00269
00270 if (!nh_private_.getParam ("clustering_threshold", input_.clustering_threshold))
00271 input_.clustering_threshold = 0.25;
00272
00273
00274 if (!nh_private_.getParam ("orientation_neighbourhood", input_.orientation_neighbourhood))
00275 input_.orientation_neighbourhood = 20;
00276
00277
00278 if (!nh_private_.getParam ("use_point_to_line_distance", input_.use_point_to_line_distance))
00279 input_.use_point_to_line_distance = 1;
00280
00281
00282 if (!nh_private_.getParam ("do_alpha_test", input_.do_alpha_test))
00283 input_.do_alpha_test = 0;
00284
00285
00286 if (!nh_private_.getParam ("do_alpha_test_thresholdDeg", input_.do_alpha_test_thresholdDeg))
00287 input_.do_alpha_test_thresholdDeg = 20.0;
00288
00289
00290
00291 if (!nh_private_.getParam ("outliers_maxPerc", input_.outliers_maxPerc))
00292 input_.outliers_maxPerc = 0.90;
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 if (!nh_private_.getParam ("outliers_adaptive_order", input_.outliers_adaptive_order))
00303 input_.outliers_adaptive_order = 0.7;
00304
00305 if (!nh_private_.getParam ("outliers_adaptive_mult", input_.outliers_adaptive_mult))
00306 input_.outliers_adaptive_mult = 2.0;
00307
00308
00309
00310
00311
00312 if (!nh_private_.getParam ("do_visibility_test", input_.do_visibility_test))
00313 input_.do_visibility_test = 0;
00314
00315
00316 if (!nh_private_.getParam ("outliers_remove_doubles", input_.outliers_remove_doubles))
00317 input_.outliers_remove_doubles = 1;
00318
00319
00320 if (!nh_private_.getParam ("do_compute_covariance", input_.do_compute_covariance))
00321 input_.do_compute_covariance = 0;
00322
00323
00324 if (!nh_private_.getParam ("debug_verify_tricks", input_.debug_verify_tricks))
00325 input_.debug_verify_tricks = 0;
00326
00327
00328
00329 if (!nh_private_.getParam ("use_ml_weights", input_.use_ml_weights))
00330 input_.use_ml_weights = 0;
00331
00332
00333
00334 if (!nh_private_.getParam ("use_sigma_weights", input_.use_sigma_weights))
00335 input_.use_sigma_weights = 0;
00336 }
00337
00338 void LaserScanMatcher::imuCallback(const sensor_msgs::Imu::ConstPtr& imu_msg)
00339 {
00340 boost::mutex::scoped_lock(mutex_);
00341 latest_imu_msg_ = *imu_msg;
00342 if (!received_imu_)
00343 {
00344 last_used_imu_msg_ = *imu_msg;
00345 received_imu_ = true;
00346 }
00347 }
00348
00349 void LaserScanMatcher::odomCallback(const nav_msgs::Odometry::ConstPtr& odom_msg)
00350 {
00351 boost::mutex::scoped_lock(mutex_);
00352 latest_odom_msg_ = *odom_msg;
00353 if (!received_odom_)
00354 {
00355 last_used_odom_msg_ = *odom_msg;
00356 received_odom_ = true;
00357 }
00358 }
00359
00360 void LaserScanMatcher::velCallback(const geometry_msgs::Twist::ConstPtr& twist_msg)
00361 {
00362 boost::mutex::scoped_lock(mutex_);
00363 latest_vel_msg_ = *twist_msg;
00364
00365 received_vel_ = true;
00366 }
00367
00368 void LaserScanMatcher::velStmpCallback(const geometry_msgs::TwistStamped::ConstPtr& twist_msg)
00369 {
00370 boost::mutex::scoped_lock(mutex_);
00371 latest_vel_msg_ = twist_msg->twist;
00372
00373 received_vel_ = true;
00374 }
00375
00376 void LaserScanMatcher::cloudCallback (const PointCloudT::ConstPtr& cloud)
00377 {
00378
00379
00380 std_msgs::Header cloud_header = pcl_conversions::fromPCL(cloud->header);
00381
00382 if (!initialized_)
00383 {
00384
00385 if (!getBaseToLaserTf(cloud_header.frame_id))
00386 {
00387 ROS_WARN("Skipping scan");
00388 return;
00389 }
00390
00391 PointCloudToLDP(cloud, prev_ldp_scan_);
00392 last_icp_time_ = cloud_header.stamp;
00393 initialized_ = true;
00394 }
00395
00396 LDP curr_ldp_scan;
00397 PointCloudToLDP(cloud, curr_ldp_scan);
00398 processScan(curr_ldp_scan, cloud_header.stamp);
00399 }
00400
00401 void LaserScanMatcher::scanCallback (const sensor_msgs::LaserScan::ConstPtr& scan_msg)
00402 {
00403
00404
00405 if (!initialized_)
00406 {
00407 createCache(scan_msg);
00408
00409
00410 if (!getBaseToLaserTf(scan_msg->header.frame_id))
00411 {
00412 ROS_WARN("Skipping scan");
00413 return;
00414 }
00415
00416 laserScanToLDP(scan_msg, prev_ldp_scan_);
00417 last_icp_time_ = scan_msg->header.stamp;
00418 initialized_ = true;
00419 }
00420
00421 LDP curr_ldp_scan;
00422 laserScanToLDP(scan_msg, curr_ldp_scan);
00423 processScan(curr_ldp_scan, scan_msg->header.stamp);
00424 }
00425
00426 void LaserScanMatcher::processScan(LDP& curr_ldp_scan, const ros::Time& time)
00427 {
00428 ros::WallTime start = ros::WallTime::now();
00429
00430
00431
00432
00433
00434
00435
00436
00437 prev_ldp_scan_->odometry[0] = 0.0;
00438 prev_ldp_scan_->odometry[1] = 0.0;
00439 prev_ldp_scan_->odometry[2] = 0.0;
00440
00441 prev_ldp_scan_->estimate[0] = 0.0;
00442 prev_ldp_scan_->estimate[1] = 0.0;
00443 prev_ldp_scan_->estimate[2] = 0.0;
00444
00445 prev_ldp_scan_->true_pose[0] = 0.0;
00446 prev_ldp_scan_->true_pose[1] = 0.0;
00447 prev_ldp_scan_->true_pose[2] = 0.0;
00448
00449 input_.laser_ref = prev_ldp_scan_;
00450 input_.laser_sens = curr_ldp_scan;
00451
00452
00453
00454 double dt = (time - last_icp_time_).toSec();
00455 double pr_ch_x, pr_ch_y, pr_ch_a;
00456 getPrediction(pr_ch_x, pr_ch_y, pr_ch_a, dt);
00457
00458
00459
00460 tf::Transform pr_ch;
00461 createTfFromXYTheta(pr_ch_x, pr_ch_y, pr_ch_a, pr_ch);
00462
00463
00464
00465 pr_ch = pr_ch * (f2b_ * f2b_kf_.inverse());
00466
00467
00468
00469 tf::Transform pr_ch_l;
00470 pr_ch_l = laser_to_base_ * f2b_.inverse() * pr_ch * f2b_ * base_to_laser_ ;
00471
00472 input_.first_guess[0] = pr_ch_l.getOrigin().getX();
00473 input_.first_guess[1] = pr_ch_l.getOrigin().getY();
00474 input_.first_guess[2] = tf::getYaw(pr_ch_l.getRotation());
00475
00476
00477 if (output_.cov_x_m)
00478 {
00479 gsl_matrix_free(output_.cov_x_m);
00480 output_.cov_x_m = 0;
00481 }
00482 if (output_.dx_dy1_m)
00483 {
00484 gsl_matrix_free(output_.dx_dy1_m);
00485 output_.dx_dy1_m = 0;
00486 }
00487 if (output_.dx_dy2_m)
00488 {
00489 gsl_matrix_free(output_.dx_dy2_m);
00490 output_.dx_dy2_m = 0;
00491 }
00492
00493
00494
00495 sm_icp(&input_, &output_);
00496 tf::Transform corr_ch;
00497
00498 if (output_.valid)
00499 {
00500
00501
00502 tf::Transform corr_ch_l;
00503 createTfFromXYTheta(output_.x[0], output_.x[1], output_.x[2], corr_ch_l);
00504
00505
00506 corr_ch = base_to_laser_ * corr_ch_l * laser_to_base_;
00507
00508
00509 f2b_ = f2b_kf_ * corr_ch;
00510
00511
00512
00513 if (publish_pose_)
00514 {
00515
00516 geometry_msgs::Pose2D::Ptr pose_msg;
00517 pose_msg = boost::make_shared<geometry_msgs::Pose2D>();
00518 pose_msg->x = f2b_.getOrigin().getX();
00519 pose_msg->y = f2b_.getOrigin().getY();
00520 pose_msg->theta = tf::getYaw(f2b_.getRotation());
00521 pose_publisher_.publish(pose_msg);
00522 }
00523 if (publish_pose_stamped_)
00524 {
00525
00526 geometry_msgs::PoseStamped::Ptr pose_stamped_msg;
00527 pose_stamped_msg = boost::make_shared<geometry_msgs::PoseStamped>();
00528
00529 pose_stamped_msg->header.stamp = time;
00530 pose_stamped_msg->header.frame_id = fixed_frame_;
00531
00532 tf::poseTFToMsg(f2b_, pose_stamped_msg->pose);
00533
00534 pose_stamped_publisher_.publish(pose_stamped_msg);
00535 }
00536 if (publish_pose_with_covariance_)
00537 {
00538
00539 geometry_msgs::PoseWithCovariance::Ptr pose_with_covariance_msg;
00540 pose_with_covariance_msg = boost::make_shared<geometry_msgs::PoseWithCovariance>();
00541 tf::poseTFToMsg(f2b_, pose_with_covariance_msg->pose);
00542
00543 if (input_.do_compute_covariance)
00544 {
00545 pose_with_covariance_msg->covariance = boost::assign::list_of
00546 (gsl_matrix_get(output_.cov_x_m, 0, 0)) (0) (0) (0) (0) (0)
00547 (0) (gsl_matrix_get(output_.cov_x_m, 0, 1)) (0) (0) (0) (0)
00548 (0) (0) (static_cast<double>(position_covariance_[2])) (0) (0) (0)
00549 (0) (0) (0) (static_cast<double>(orientation_covariance_[0])) (0) (0)
00550 (0) (0) (0) (0) (static_cast<double>(orientation_covariance_[1])) (0)
00551 (0) (0) (0) (0) (0) (gsl_matrix_get(output_.cov_x_m, 0, 2));
00552 }
00553 else
00554 {
00555 pose_with_covariance_msg->covariance = boost::assign::list_of
00556 (static_cast<double>(position_covariance_[0])) (0) (0) (0) (0) (0)
00557 (0) (static_cast<double>(position_covariance_[1])) (0) (0) (0) (0)
00558 (0) (0) (static_cast<double>(position_covariance_[2])) (0) (0) (0)
00559 (0) (0) (0) (static_cast<double>(orientation_covariance_[0])) (0) (0)
00560 (0) (0) (0) (0) (static_cast<double>(orientation_covariance_[1])) (0)
00561 (0) (0) (0) (0) (0) (static_cast<double>(orientation_covariance_[2]));
00562 }
00563
00564 pose_with_covariance_publisher_.publish(pose_with_covariance_msg);
00565 }
00566 if (publish_pose_with_covariance_stamped_)
00567 {
00568
00569 geometry_msgs::PoseWithCovarianceStamped::Ptr pose_with_covariance_stamped_msg;
00570 pose_with_covariance_stamped_msg = boost::make_shared<geometry_msgs::PoseWithCovarianceStamped>();
00571
00572 pose_with_covariance_stamped_msg->header.stamp = time;
00573 pose_with_covariance_stamped_msg->header.frame_id = fixed_frame_;
00574
00575 tf::poseTFToMsg(f2b_, pose_with_covariance_stamped_msg->pose.pose);
00576
00577 if (input_.do_compute_covariance)
00578 {
00579 pose_with_covariance_stamped_msg->pose.covariance = boost::assign::list_of
00580 (gsl_matrix_get(output_.cov_x_m, 0, 0)) (0) (0) (0) (0) (0)
00581 (0) (gsl_matrix_get(output_.cov_x_m, 0, 1)) (0) (0) (0) (0)
00582 (0) (0) (static_cast<double>(position_covariance_[2])) (0) (0) (0)
00583 (0) (0) (0) (static_cast<double>(orientation_covariance_[0])) (0) (0)
00584 (0) (0) (0) (0) (static_cast<double>(orientation_covariance_[1])) (0)
00585 (0) (0) (0) (0) (0) (gsl_matrix_get(output_.cov_x_m, 0, 2));
00586 }
00587 else
00588 {
00589 pose_with_covariance_stamped_msg->pose.covariance = boost::assign::list_of
00590 (static_cast<double>(position_covariance_[0])) (0) (0) (0) (0) (0)
00591 (0) (static_cast<double>(position_covariance_[1])) (0) (0) (0) (0)
00592 (0) (0) (static_cast<double>(position_covariance_[2])) (0) (0) (0)
00593 (0) (0) (0) (static_cast<double>(orientation_covariance_[0])) (0) (0)
00594 (0) (0) (0) (0) (static_cast<double>(orientation_covariance_[1])) (0)
00595 (0) (0) (0) (0) (0) (static_cast<double>(orientation_covariance_[2]));
00596 }
00597
00598 pose_with_covariance_stamped_publisher_.publish(pose_with_covariance_stamped_msg);
00599 }
00600
00601 if (publish_tf_)
00602 {
00603 tf::StampedTransform transform_msg (f2b_, time, fixed_frame_, base_frame_);
00604 tf_broadcaster_.sendTransform (transform_msg);
00605 }
00606 }
00607 else
00608 {
00609 corr_ch.setIdentity();
00610 ROS_WARN("Error in scan matching");
00611 }
00612
00613
00614
00615 if (newKeyframeNeeded(corr_ch))
00616 {
00617
00618 ld_free(prev_ldp_scan_);
00619 prev_ldp_scan_ = curr_ldp_scan;
00620 f2b_kf_ = f2b_;
00621 }
00622 else
00623 {
00624 ld_free(curr_ldp_scan);
00625 }
00626
00627 last_icp_time_ = time;
00628
00629
00630
00631 double dur = (ros::WallTime::now() - start).toSec() * 1e3;
00632 ROS_DEBUG("Scan matcher total duration: %.1f ms", dur);
00633 }
00634
00635 bool LaserScanMatcher::newKeyframeNeeded(const tf::Transform& d)
00636 {
00637 if (fabs(tf::getYaw(d.getRotation())) > kf_dist_angular_) return true;
00638
00639 double x = d.getOrigin().getX();
00640 double y = d.getOrigin().getY();
00641 if (x*x + y*y > kf_dist_linear_sq_) return true;
00642
00643 return false;
00644 }
00645
00646 void LaserScanMatcher::PointCloudToLDP(const PointCloudT::ConstPtr& cloud,
00647 LDP& ldp)
00648 {
00649 double max_d2 = cloud_res_ * cloud_res_;
00650
00651 PointCloudT cloud_f;
00652
00653 cloud_f.points.push_back(cloud->points[0]);
00654
00655 for (unsigned int i = 1; i < cloud->points.size(); ++i)
00656 {
00657 const PointT& pa = cloud_f.points[cloud_f.points.size() - 1];
00658 const PointT& pb = cloud->points[i];
00659
00660 double dx = pa.x - pb.x;
00661 double dy = pa.y - pb.y;
00662 double d2 = dx*dx + dy*dy;
00663
00664 if (d2 > max_d2)
00665 {
00666 cloud_f.points.push_back(pb);
00667 }
00668 }
00669
00670 unsigned int n = cloud_f.points.size();
00671
00672 ldp = ld_alloc_new(n);
00673
00674 for (unsigned int i = 0; i < n; i++)
00675 {
00676
00677 if (is_nan(cloud_f.points[i].x) || is_nan(cloud_f.points[i].y))
00678 {
00679 ROS_WARN("Laser Scan Matcher: Cloud input contains NaN values. \
00680 Please use a filtered cloud input.");
00681 }
00682 else
00683 {
00684 double r = sqrt(cloud_f.points[i].x * cloud_f.points[i].x +
00685 cloud_f.points[i].y * cloud_f.points[i].y);
00686
00687 if (r > cloud_range_min_ && r < cloud_range_max_)
00688 {
00689 ldp->valid[i] = 1;
00690 ldp->readings[i] = r;
00691 }
00692 else
00693 {
00694 ldp->valid[i] = 0;
00695 ldp->readings[i] = -1;
00696 }
00697 }
00698
00699 ldp->theta[i] = atan2(cloud_f.points[i].y, cloud_f.points[i].x);
00700 ldp->cluster[i] = -1;
00701 }
00702
00703 ldp->min_theta = ldp->theta[0];
00704 ldp->max_theta = ldp->theta[n-1];
00705
00706 ldp->odometry[0] = 0.0;
00707 ldp->odometry[1] = 0.0;
00708 ldp->odometry[2] = 0.0;
00709
00710 ldp->true_pose[0] = 0.0;
00711 ldp->true_pose[1] = 0.0;
00712 ldp->true_pose[2] = 0.0;
00713 }
00714
00715 void LaserScanMatcher::laserScanToLDP(const sensor_msgs::LaserScan::ConstPtr& scan_msg,
00716 LDP& ldp)
00717 {
00718 unsigned int n = scan_msg->ranges.size();
00719 ldp = ld_alloc_new(n);
00720
00721 for (unsigned int i = 0; i < n; i++)
00722 {
00723
00724
00725 double r = scan_msg->ranges[i];
00726
00727 if (r > scan_msg->range_min && r < scan_msg->range_max)
00728 {
00729
00730
00731 ldp->valid[i] = 1;
00732 ldp->readings[i] = r;
00733 }
00734 else
00735 {
00736 ldp->valid[i] = 0;
00737 ldp->readings[i] = -1;
00738 }
00739
00740 ldp->theta[i] = scan_msg->angle_min + i * scan_msg->angle_increment;
00741
00742 ldp->cluster[i] = -1;
00743 }
00744
00745 ldp->min_theta = ldp->theta[0];
00746 ldp->max_theta = ldp->theta[n-1];
00747
00748 ldp->odometry[0] = 0.0;
00749 ldp->odometry[1] = 0.0;
00750 ldp->odometry[2] = 0.0;
00751
00752 ldp->true_pose[0] = 0.0;
00753 ldp->true_pose[1] = 0.0;
00754 ldp->true_pose[2] = 0.0;
00755 }
00756
00757 void LaserScanMatcher::createCache (const sensor_msgs::LaserScan::ConstPtr& scan_msg)
00758 {
00759 a_cos_.clear();
00760 a_sin_.clear();
00761
00762 for (unsigned int i = 0; i < scan_msg->ranges.size(); ++i)
00763 {
00764 double angle = scan_msg->angle_min + i * scan_msg->angle_increment;
00765 a_cos_.push_back(cos(angle));
00766 a_sin_.push_back(sin(angle));
00767 }
00768
00769 input_.min_reading = scan_msg->range_min;
00770 input_.max_reading = scan_msg->range_max;
00771 }
00772
00773 bool LaserScanMatcher::getBaseToLaserTf (const std::string& frame_id)
00774 {
00775 ros::Time t = ros::Time::now();
00776
00777 tf::StampedTransform base_to_laser_tf;
00778 try
00779 {
00780 tf_listener_.waitForTransform(
00781 base_frame_, frame_id, t, ros::Duration(1.0));
00782 tf_listener_.lookupTransform (
00783 base_frame_, frame_id, t, base_to_laser_tf);
00784 }
00785 catch (tf::TransformException ex)
00786 {
00787 ROS_WARN("Could not get initial transform from base to laser frame, %s", ex.what());
00788 return false;
00789 }
00790 base_to_laser_ = base_to_laser_tf;
00791 laser_to_base_ = base_to_laser_.inverse();
00792
00793 return true;
00794 }
00795
00796
00797
00798 void LaserScanMatcher::getPrediction(double& pr_ch_x, double& pr_ch_y,
00799 double& pr_ch_a, double dt)
00800 {
00801 boost::mutex::scoped_lock(mutex_);
00802
00803
00804 pr_ch_x = 0.0;
00805 pr_ch_y = 0.0;
00806 pr_ch_a = 0.0;
00807
00808
00809 if (use_vel_)
00810 {
00811 pr_ch_x = dt * latest_vel_msg_.linear.x;
00812 pr_ch_y = dt * latest_vel_msg_.linear.y;
00813 pr_ch_a = dt * latest_vel_msg_.angular.z;
00814
00815 if (pr_ch_a >= M_PI) pr_ch_a -= 2.0 * M_PI;
00816 else if (pr_ch_a < -M_PI) pr_ch_a += 2.0 * M_PI;
00817 }
00818
00819
00820 if (use_odom_ && received_odom_)
00821 {
00822 pr_ch_x = latest_odom_msg_.pose.pose.position.x -
00823 last_used_odom_msg_.pose.pose.position.x;
00824
00825 pr_ch_y = latest_odom_msg_.pose.pose.position.y -
00826 last_used_odom_msg_.pose.pose.position.y;
00827
00828 pr_ch_a = tf::getYaw(latest_odom_msg_.pose.pose.orientation) -
00829 tf::getYaw(last_used_odom_msg_.pose.pose.orientation);
00830
00831 if (pr_ch_a >= M_PI) pr_ch_a -= 2.0 * M_PI;
00832 else if (pr_ch_a < -M_PI) pr_ch_a += 2.0 * M_PI;
00833
00834 last_used_odom_msg_ = latest_odom_msg_;
00835 }
00836
00837
00838 if (use_imu_ && received_imu_)
00839 {
00840 pr_ch_a = tf::getYaw(latest_imu_msg_.orientation) -
00841 tf::getYaw(last_used_imu_msg_.orientation);
00842
00843 if (pr_ch_a >= M_PI) pr_ch_a -= 2.0 * M_PI;
00844 else if (pr_ch_a < -M_PI) pr_ch_a += 2.0 * M_PI;
00845
00846 last_used_imu_msg_ = latest_imu_msg_;
00847 }
00848 }
00849
00850 void LaserScanMatcher::createTfFromXYTheta(
00851 double x, double y, double theta, tf::Transform& t)
00852 {
00853 t.setOrigin(tf::Vector3(x, y, 0.0));
00854 tf::Quaternion q;
00855 q.setRPY(0.0, 0.0, theta);
00856 t.setRotation(q);
00857 }
00858
00859 }