Advertisement
Guest User

laser_scan_matcher_odom.cpp

a guest
Jan 29th, 2012
1,418
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 22.32 KB | None | 0 0
  1. /*
  2.  * Copyright (c) 2011, Ivan Dryanovski, William Morris
  3.  * All rights reserved.
  4.  *
  5.  * *** Modified also to publish horizontal velocities:                       ***
  6.  * *** WARNING: This is not the original laser_scan_matcher from CCNY,       ***
  7.  * *** it's been slightly modified in a dirty fashion.                       ***
  8.  *
  9.  * Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions are met:
  11.  *
  12.  *     * Redistributions of source code must retain the above copyright
  13.  *       notice, this list of conditions and the following disclaimer.
  14.  *     * Redistributions in binary form must reproduce the above copyright
  15.  *       notice, this list of conditions and the following disclaimer in the
  16.  *       documentation and/or other materials provided with the distribution.
  17.  *     * Neither the name of the CCNY Robotics Lab nor the names of its
  18.  *       contributors may be used to endorse or promote products derived from
  19.  *       this software without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  22.  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  25.  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  26.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  27.  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  28.  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  29.  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  30.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  31.  * POSSIBILITY OF SUCH DAMAGE.
  32.  */
  33.  
  34. /*  This package uses Canonical Scan Matcher [1], written by
  35.  *  Andrea Censi
  36.  *
  37.  *  [1] A. Censi, "An ICP variant using a point-to-line metric"
  38.  *  Proceedings of the IEEE International Conference
  39.  *  on Robotics and Automation (ICRA), 2008
  40.  */
  41.  
  42. #include "laser_scan_matcher/laser_scan_matcher.h"
  43.  
  44. namespace scan_tools
  45. {
  46.  
  47. LaserScanMatcher::LaserScanMatcher(ros::NodeHandle nh, ros::NodeHandle nh_private):
  48.           nh_(nh),
  49.           nh_private_(nh_private)
  50. {
  51.     ROS_INFO("Starting LaserScanMatcher");
  52.  
  53.     // **** init parameters
  54.  
  55.     initParams();
  56.  
  57.     // **** state variables
  58.  
  59.     initialized_   = false;
  60.     received_imu_  = false;
  61.     received_odom_ = false;
  62.  
  63.     w2b_.setIdentity();
  64.  
  65.     v_x_ = 0;
  66.     v_y_ = 0;
  67.     v_a_ = 0;
  68.  
  69.     vel_x_ = 0;
  70.     vel_y_ = 0;
  71.     vel_a_ = 0;
  72.     last_vel_x_ = 0;
  73.     last_vel_y_ = 0;
  74.     last_vel_a_ = 0;
  75.  
  76.     input_.laser[0] = 0.0;
  77.     input_.laser[1] = 0.0;
  78.     input_.laser[2] = 0.0;
  79.  
  80.     // *** subscribers
  81.  
  82.     if (use_cloud_input_)
  83.     {
  84.         cloud_subscriber_ = nh_.subscribe(
  85.                 cloud_topic_, 1, &LaserScanMatcher::cloudCallback, this);
  86.  
  87.     }
  88.     else
  89.     {
  90.         scan_subscriber_ = nh_.subscribe(
  91.                 scan_topic_, 1, &LaserScanMatcher::scanCallback, this);
  92.     }
  93.  
  94.     if (use_imu_)
  95.     {
  96.         imu_subscriber_ = nh_.subscribe(
  97.                 imu_topic_, 1, &LaserScanMatcher::imuCallback, this);
  98.     }
  99.  
  100.     if (use_odom_)
  101.     {
  102.         odom_subscriber_ = nh_.subscribe(
  103.                 odom_topic_, 1, &LaserScanMatcher::odomCallback, this);
  104.     }
  105.  
  106.     // **** pose publisher
  107.     if (publish_pose_)
  108.     {
  109.         pose_publisher_  = nh_.advertise<geometry_msgs::Pose2D>(
  110.                 pose_topic_, 5);
  111.     }
  112.  
  113.     if (publish_vel_)
  114.     {
  115.         vel_publisher_ = nh_.advertise<nav_msgs::Odometry>(odom_topic_, 5);
  116.     }
  117. }
  118.  
  119. LaserScanMatcher::~LaserScanMatcher()
  120. {
  121.  
  122. }
  123.  
  124. void LaserScanMatcher::initParams()
  125. {
  126.     if (!nh_private_.getParam ("base_frame", base_frame_))
  127.         base_frame_ = "base_link";
  128.     if (!nh_private_.getParam ("fixed_frame", fixed_frame_))
  129.         fixed_frame_ = "world";
  130.  
  131.     // **** input type - laser scan, or point clouds?
  132.     // if false, will subscrive to LaserScan msgs on /scan.
  133.     // if true, will subscrive to PointCloud2 msgs on /cloud
  134.  
  135.     if (!nh_private_.getParam ("use_cloud_input", use_cloud_input_))
  136.         use_cloud_input_= false;
  137.  
  138.     if (use_cloud_input_)
  139.     {
  140.         if (!nh_private_.getParam ("cloud_range_min", cloud_range_min_))
  141.             cloud_range_min_ = 0.1;
  142.         if (!nh_private_.getParam ("cloud_range_max", cloud_range_max_))
  143.             cloud_range_max_ = 50.0;
  144.  
  145.         input_.min_reading = cloud_range_min_;
  146.         input_.max_reading = cloud_range_max_;
  147.     }
  148.  
  149.     // **** What predictions are available to speed up the ICP?
  150.     // 1) imu - [theta] from imu yaw angle - /odom topic
  151.     // 2) odom - [x, y, theta] from wheel odometry - /imu topic
  152.     // 3) alpha_beta - [x, y, theta] from simple tracking filter - no topic req.
  153.     // If more than one is enabled, priority is imu > odom > alpha_beta
  154.  
  155.     if (!nh_private_.getParam ("use_imu", use_imu_))
  156.         use_imu_ = true;
  157.     if (!nh_private_.getParam ("use_odom", use_odom_))
  158.         use_odom_ = true;
  159.     if (!nh_private_.getParam ("use_alpha_beta", use_alpha_beta_))
  160.         use_alpha_beta_ = false;
  161.     if (!nh_private_.getParam ("publish_vel", publish_vel_))
  162.         publish_vel_ = true;
  163.  
  164.     // **** How to publish the output?
  165.     // tf (fixed_frame->base_frame),
  166.     // pose message (pose of base frame in the fixed frame)
  167.  
  168.     if (!nh_private_.getParam ("publish_tf", publish_tf_))
  169.         publish_tf_ = true;
  170.     if (!nh_private_.getParam ("publish_pose", publish_pose_))
  171.         publish_pose_ = true;
  172.  
  173.     if (!nh_private_.getParam ("alpha", alpha_))
  174.         alpha_ = 1.0;
  175.     if (!nh_private_.getParam ("beta", beta_))
  176.         beta_ = 0.8;
  177.  
  178.     // **** CSM parameters - comments copied from algos.h (by Andrea Censi)
  179.  
  180.     // Maximum angular displacement between scans
  181.     if (!nh_private_.getParam ("max_angular_correction_deg", input_.max_angular_correction_deg))
  182.         input_.max_angular_correction_deg = 45.0;
  183.  
  184.     // Maximum translation between scans (m)
  185.     if (!nh_private_.getParam ("max_linear_correction", input_.max_linear_correction))
  186.         input_.max_linear_correction = 0.50;
  187.  
  188.     // Maximum ICP cycle iterations
  189.     if (!nh_private_.getParam ("max_iterations", input_.max_iterations))
  190.         input_.max_iterations = 10;
  191.  
  192.     // A threshold for stopping (m)
  193.     if (!nh_private_.getParam ("epsilon_xy", input_.epsilon_xy))
  194.         input_.epsilon_xy = 0.000001;
  195.  
  196.     // A threshold for stopping (rad)
  197.     if (!nh_private_.getParam ("epsilon_theta", input_.epsilon_theta))
  198.         input_.epsilon_theta = 0.000001;
  199.  
  200.     // Maximum distance for a correspondence to be valid
  201.     if (!nh_private_.getParam ("max_correspondence_dist", input_.max_correspondence_dist))
  202.         input_.max_correspondence_dist = 0.3;
  203.  
  204.     // Noise in the scan (m)
  205.     if (!nh_private_.getParam ("sigma", input_.sigma))
  206.         input_.sigma = 0.010;
  207.  
  208.     // Use smart tricks for finding correspondences.
  209.     if (!nh_private_.getParam ("use_corr_tricks", input_.use_corr_tricks))
  210.         input_.use_corr_tricks = 1;
  211.  
  212.     // Restart: Restart if error is over threshold
  213.     if (!nh_private_.getParam ("restart", input_.restart))
  214.         input_.restart = 0;
  215.  
  216.     // Restart: Threshold for restarting
  217.     if (!nh_private_.getParam ("restart_threshold_mean_error", input_.restart_threshold_mean_error))
  218.         input_.restart_threshold_mean_error = 0.01;
  219.  
  220.     // Restart: displacement for restarting. (m)
  221.     if (!nh_private_.getParam ("restart_dt", input_.restart_dt))
  222.         input_.restart_dt = 1.0;
  223.  
  224.     // Restart: displacement for restarting. (rad)
  225.     if (!nh_private_.getParam ("restart_dtheta", input_.restart_dtheta))
  226.         input_.restart_dtheta = 0.1;
  227.  
  228.     // Max distance for staying in the same clustering
  229.     if (!nh_private_.getParam ("clustering_threshold", input_.clustering_threshold))
  230.         input_.clustering_threshold = 0.25;
  231.  
  232.     // Number of neighbour rays used to estimate the orientation
  233.     if (!nh_private_.getParam ("orientation_neighbourhood", input_.orientation_neighbourhood))
  234.         input_.orientation_neighbourhood = 20;
  235.  
  236.     // If 0, it's vanilla ICP
  237.     if (!nh_private_.getParam ("use_point_to_line_distance", input_.use_point_to_line_distance))
  238.         input_.use_point_to_line_distance = 1;
  239.  
  240.     // Discard correspondences based on the angles
  241.     if (!nh_private_.getParam ("do_alpha_test", input_.do_alpha_test))
  242.         input_.do_alpha_test = 0;
  243.  
  244.     // Discard correspondences based on the angles - threshold angle, in degrees
  245.     if (!nh_private_.getParam ("do_alpha_test_thresholdDeg", input_.do_alpha_test_thresholdDeg))
  246.         input_.do_alpha_test_thresholdDeg = 20.0;
  247.  
  248.     // Percentage of correspondences to consider: if 0.9,
  249.     // always discard the top 10% of correspondences with more error
  250.     if (!nh_private_.getParam ("outliers_maxPerc", input_.outliers_maxPerc))
  251.         input_.outliers_maxPerc = 0.90;
  252.  
  253.     // Parameters describing a simple adaptive algorithm for discarding.
  254.     //  1) Order the errors.
  255.     //  2) Choose the percentile according to outliers_adaptive_order.
  256.     //     (if it is 0.7, get the 70% percentile)
  257.     //  3) Define an adaptive threshold multiplying outliers_adaptive_mult
  258.     //     with the value of the error at the chosen percentile.
  259.     //  4) Discard correspondences over the threshold.
  260.     //  This is useful to be conservative; yet remove the biggest errors.
  261.     if (!nh_private_.getParam ("outliers_adaptive_order", input_.outliers_adaptive_order))
  262.         input_.outliers_adaptive_order = 0.7;
  263.  
  264.     if (!nh_private_.getParam ("outliers_adaptive_mult", input_.outliers_adaptive_mult))
  265.         input_.outliers_adaptive_mult = 2.0;
  266.  
  267.     //If you already have a guess of the solution, you can compute the polar angle
  268.     //  of the points of one scan in the new position. If the polar angle is not a monotone
  269.     //  function of the readings index, it means that the surface is not visible in the
  270.     //  next position. If it is not visible, then we don't use it for matching.
  271.     if (!nh_private_.getParam ("do_visibility_test", input_.do_visibility_test))
  272.         input_.do_visibility_test = 0;
  273.  
  274.     // no two points in laser_sens can have the same corr.
  275.     if (!nh_private_.getParam ("outliers_remove_doubles", input_.outliers_remove_doubles))
  276.         input_.outliers_remove_doubles = 1;
  277.  
  278.     // If 1, computes the covariance of ICP using the method http://purl.org/censi/2006/icpcov
  279.     if (!nh_private_.getParam ("do_compute_covariance", input_.do_compute_covariance))
  280.         input_.do_compute_covariance = 0;
  281.  
  282.     // Checks that find_correspondences_tricks gives the right answer
  283.     if (!nh_private_.getParam ("debug_verify_tricks", input_.debug_verify_tricks))
  284.         input_.debug_verify_tricks = 0;
  285.  
  286.     // If 1, the field 'true_alpha' (or 'alpha') in the first scan is used to compute the
  287.     // incidence beta, and the factor (1/cos^2(beta)) used to weight the correspondence.");
  288.     if (!nh_private_.getParam ("use_ml_weights", input_.use_ml_weights))
  289.         input_.use_ml_weights = 0;
  290.  
  291.     // If 1, the field 'readings_sigma' in the second scan is used to weight the
  292.     // correspondence by 1/sigma^2
  293.     if (!nh_private_.getParam ("use_sigma_weights", input_.use_sigma_weights))
  294.         input_.use_sigma_weights = 0;
  295. }
  296.  
  297. void LaserScanMatcher::imuCallback (const sensor_msgs::ImuPtr& imu_msg)
  298. {
  299.     boost::mutex::scoped_lock(mutex_);
  300.     latest_imu_yaw_ = getYawFromQuaternion(imu_msg->orientation);
  301.     if (!received_imu_)
  302.     {
  303.         last_imu_yaw_ = getYawFromQuaternion(imu_msg->orientation);
  304.         received_imu_ = true;
  305.     }
  306. }
  307.  
  308. void LaserScanMatcher::odomCallback (const nav_msgs::Odometry::ConstPtr& odom_msg)
  309. {
  310.     boost::mutex::scoped_lock(mutex_);
  311.     latest_odom_ = *odom_msg;
  312.     if (!received_odom_)
  313.     {
  314.         last_odom_ = *odom_msg;
  315.         received_odom_ = true;
  316.     }
  317. }
  318.  
  319. void LaserScanMatcher::cloudCallback (const PointCloudT::ConstPtr& cloud)
  320. {
  321.     // **** if first scan, cache the tf from base to the scanner
  322.  
  323.     if (!initialized_)
  324.     {
  325.         // cache the static tf from base to laser
  326.         if (!getBaseToLaserTf(cloud->header.frame_id))
  327.         {
  328.             ROS_WARN("ScanMatcher: Skipping scan");
  329.             return;
  330.         }
  331.  
  332.         PointCloudToLDP(cloud, prev_ldp_scan_);
  333.         last_icp_time_ = cloud->header.stamp;
  334.         last_imu_yaw_ = latest_imu_yaw_;
  335.         last_odom_ = latest_odom_;
  336.         initialized_ = true;
  337.     }
  338.  
  339.     LDP curr_ldp_scan;
  340.     PointCloudToLDP(cloud, curr_ldp_scan);
  341.     processScan(curr_ldp_scan, cloud->header.stamp);
  342. }
  343.  
  344. void LaserScanMatcher::scanCallback (const sensor_msgs::LaserScan::ConstPtr& scan_msg)
  345. {
  346.     // **** if first scan, cache the tf from base to the scanner
  347.  
  348.     if (!initialized_)
  349.     {
  350.         createCache(scan_msg);    // caches the sin and cos of all angles
  351.  
  352.         // cache the static tf from base to laser
  353.         if (!getBaseToLaserTf(scan_msg->header.frame_id))
  354.         {
  355.             ROS_WARN("ScanMatcher: Skipping scan");
  356.             return;
  357.         }
  358.  
  359.         laserScanToLDP(scan_msg, prev_ldp_scan_);
  360.         last_icp_time_ = scan_msg->header.stamp;
  361.         last_imu_yaw_ = latest_imu_yaw_;
  362.         last_odom_ = latest_odom_;
  363.         initialized_ = true;
  364.     }
  365.  
  366.     LDP curr_ldp_scan;
  367.     laserScanToLDP(scan_msg, curr_ldp_scan);
  368.     processScan(curr_ldp_scan, scan_msg->header.stamp);
  369. }
  370.  
  371. void LaserScanMatcher::processScan(LDP& curr_ldp_scan, const ros::Time& time)
  372. {
  373.     struct timeval start, end;    // used for timing
  374.     gettimeofday(&start, NULL);
  375.  
  376.     // CSM is used in the following way:
  377.     // The scans are always in the laser frame
  378.     // The reference scan (prevLDPcan_) has a pose of 0
  379.     // The new scan (currLDPScan) has a pose equal to the movement
  380.     // of the laser in the laser frame since the last scan
  381.     // The computed correction is then propagated using the tf machinery
  382.  
  383.     prev_ldp_scan_->odometry[0] = 0;
  384.     prev_ldp_scan_->odometry[1] = 0;
  385.     prev_ldp_scan_->odometry[2] = 0;
  386.  
  387.     prev_ldp_scan_->estimate[0] = 0;
  388.     prev_ldp_scan_->estimate[1] = 0;
  389.     prev_ldp_scan_->estimate[2] = 0;
  390.  
  391.     prev_ldp_scan_->true_pose[0] = 0;
  392.     prev_ldp_scan_->true_pose[1] = 0;
  393.     prev_ldp_scan_->true_pose[2] = 0;
  394.  
  395.     input_.laser_ref  = prev_ldp_scan_;
  396.     input_.laser_sens = curr_ldp_scan;
  397.  
  398.     // **** estimated change since last scan
  399.  
  400.     ros::Time new_icp_time = ros::Time::now();
  401.     ros::Duration dur = new_icp_time - last_icp_time_;
  402.     double dt = dur.toSec();
  403.  
  404.     double pr_ch_x, pr_ch_y, pr_ch_a;
  405.     getPrediction(pr_ch_x, pr_ch_y, pr_ch_a, dt);
  406.  
  407.     // the predicted change of the laser's position, in the base frame
  408.  
  409.     tf::Transform pr_ch;
  410.     createTfFromXYTheta(pr_ch_x, pr_ch_y, pr_ch_a, pr_ch);
  411.  
  412.     // the predicted change of the laser's position, in the laser frame
  413.  
  414.     tf::Transform pr_ch_l;
  415.     pr_ch_l = laser_to_base_ * pr_ch * base_to_laser_;
  416.  
  417.     input_.first_guess[0] = pr_ch_l.getOrigin().getX();
  418.     input_.first_guess[1] = pr_ch_l.getOrigin().getY();
  419.     input_.first_guess[2] = getYawFromQuaternion(pr_ch_l.getRotation());
  420.  
  421.     /*
  422.   printf("%f, %f, %f\n", input_.first_guess[0],  
  423.                          input_.first_guess[1],
  424.                          input_.first_guess[2]);
  425.      */
  426.     // *** scan match - using point to line icp from CSM
  427.  
  428.     sm_icp(&input_, &output_);
  429.  
  430.     if (output_.valid)
  431.     {
  432.         // the correction of the laser's position, in the laser frame
  433.  
  434.         //printf("%f, %f, %f\n", output_.x[0], output_.x[1], output_.x[2]);
  435.  
  436.         tf::Transform corr_ch_l;
  437.         createTfFromXYTheta(output_.x[0], output_.x[1], output_.x[2], corr_ch_l);
  438.  
  439.         // the correction of the base's position, in the world frame
  440.  
  441.         tf::Transform corr_ch = base_to_laser_ * corr_ch_l * laser_to_base_;
  442.  
  443.         if(use_alpha_beta_ || publish_vel_)
  444.         {
  445.             tf::Transform w2b_new = w2b_ * corr_ch;
  446.  
  447.             double dx = w2b_new.getOrigin().getX() - w2b_.getOrigin().getX();
  448.             double dy = w2b_new.getOrigin().getY() - w2b_.getOrigin().getY();
  449.             double da = getYawFromQuaternion(w2b_new.getRotation()) -
  450.                     getYawFromQuaternion(w2b_.getRotation());
  451.  
  452.             double r_x = dx - pr_ch_x;
  453.             double r_y = dy - pr_ch_y;
  454.             double r_a = da - pr_ch_a;
  455.  
  456.             double x = w2b_.getOrigin().getX();
  457.             double y = w2b_.getOrigin().getY();
  458.             double a = getYawFromQuaternion(w2b_.getRotation());
  459.  
  460.             double x_new  = (x + pr_ch_x) + alpha_ * r_x;
  461.             double y_new  = (y + pr_ch_y) + alpha_ * r_y;
  462.             double a_new  = (a + pr_ch_a) + alpha_ * r_a;
  463.  
  464.             createTfFromXYTheta(x_new, y_new, a_new, w2b_);
  465.  
  466.             if (dt != 0.0)
  467.             {
  468.                 v_x_ = v_x_ + (beta_ / dt) * r_x;
  469.                 v_y_ = v_y_ + (beta_ / dt) * r_y;
  470.                 v_a_ = v_a_ + (beta_ / dt) * r_a;
  471.  
  472.                 //TODO
  473.                 //Low-pass filter, 4.9Hz cutoff first order Butterworth
  474.                 //Warning: non-linear phase, be careful in control applications
  475.                 //http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html
  476.                 double vx_raw = dx / dt / 1.031426266;
  477.                 double vy_raw = dy / dt / 1.031426266;
  478.                 double va_raw = da / dt / 1.031426266;
  479.  
  480.                 vel_x_ = vx_raw + last_vel_x_ - 0.9390625058 * vel_x_;
  481.                 vel_y_ = vy_raw + last_vel_y_ - 0.9390625058 * vel_y_;
  482.                 vel_a_ = va_raw + last_vel_a_ - 0.9390625058 * vel_a_;
  483.  
  484.                 last_vel_x_ = vx_raw;
  485.                 last_vel_y_ = vy_raw;
  486.                 last_vel_a_ = va_raw;
  487.             }
  488.         }
  489.         else
  490.         {
  491.             w2b_ = w2b_ * corr_ch;
  492.         }
  493.  
  494.         // **** publish
  495.  
  496.         if (publish_pose_)
  497.         {
  498.             geometry_msgs::Pose2D::Ptr pose_msg;
  499.             pose_msg = boost::make_shared<geometry_msgs::Pose2D>();
  500.             pose_msg->x = w2b_.getOrigin().getX();
  501.             pose_msg->y = w2b_.getOrigin().getY();
  502.             pose_msg->theta = getYawFromQuaternion(w2b_.getRotation());
  503.             pose_publisher_.publish(pose_msg);
  504.         }
  505.         if (publish_tf_)
  506.         {
  507.             tf::StampedTransform transform_msg (w2b_, time, fixed_frame_, base_frame_);
  508.             tf_broadcaster_.sendTransform (transform_msg);
  509.         }
  510.         if (publish_vel_)
  511.         {
  512.             vel_msg_.header.stamp = time;
  513.             vel_msg_.header.frame_id = base_frame_;
  514.  
  515.             vel_msg_.pose.pose.orientation.x = 0;
  516.             vel_msg_.pose.pose.orientation.y = 0;
  517.             vel_msg_.pose.pose.orientation.z = 0;
  518.             vel_msg_.pose.pose.orientation.w = 1;
  519.  
  520.             vel_msg_.twist.twist.linear.x = vel_x_;
  521.             vel_msg_.twist.twist.linear.y = vel_y_;
  522.             vel_msg_.twist.twist.angular.z = vel_a_;
  523.  
  524.             vel_publisher_.publish(vel_msg_);
  525.         }
  526.     }
  527.     else
  528.     {
  529.         ROS_WARN("Error in scan matching");
  530.  
  531.         v_x_ = 0.0;
  532.         v_y_ = 0.0;
  533.         v_a_ = 0.0;
  534.     }
  535.  
  536.     // **** swap old and new
  537.  
  538.     ld_free(prev_ldp_scan_);
  539.     prev_ldp_scan_ = curr_ldp_scan;
  540.     last_icp_time_ = new_icp_time;
  541.  
  542.     // **** statistics
  543.  
  544.     gettimeofday(&end, NULL);
  545.     double dur_total = ((end.tv_sec   * 1000000 + end.tv_usec  ) -
  546.             (start.tv_sec * 1000000 + start.tv_usec)) / 1000.0;
  547.     ROS_DEBUG("scan matcher total duration: %.1f ms", dur_total);
  548. }
  549.  
  550. void LaserScanMatcher::PointCloudToLDP(const PointCloudT::ConstPtr& cloud,
  551.         LDP& ldp)
  552. {
  553.     unsigned int n = cloud->width * cloud->height ;
  554.     ldp = ld_alloc_new(n);
  555.  
  556.     for (unsigned int i = 0; i < n; i++)
  557.     {
  558.         // calculate position in laser frame
  559.  
  560.         if (is_nan(cloud->points[i].x) || is_nan(cloud->points[i].y))
  561.         {
  562.             ROS_WARN("Laser Scan Matcher: Cloud input contains NaN values. \
  563.                Please use a filtered cloud input.");
  564.         }
  565.         else
  566.         {
  567.             double r = sqrt(cloud->points[i].x * cloud->points[i].x +
  568.                     cloud->points[i].y * cloud->points[i].y);
  569.  
  570.             if (r > cloud_range_min_ && r < cloud_range_max_)
  571.             {
  572.                 ldp->valid[i] = 1;
  573.                 ldp->readings[i] = r;
  574.             }
  575.             else
  576.             {
  577.                 ldp->valid[i] = 0;
  578.                 ldp->readings[i] = -1;  // for invalid range
  579.             }
  580.         }
  581.  
  582.         ldp->theta[i] = atan2(cloud->points[i].y, cloud->points[i].x);
  583.         ldp->cluster[i]  = -1;
  584.     }
  585.  
  586.     ldp->min_theta = ldp->theta[0];
  587.     ldp->max_theta = ldp->theta[n-1];
  588.  
  589.     ldp->odometry[0] = 0.0;
  590.     ldp->odometry[1] = 0.0;
  591.     ldp->odometry[2] = 0.0;
  592.  
  593.     ldp->true_pose[0] = 0.0;
  594.     ldp->true_pose[1] = 0.0;
  595.     ldp->true_pose[2] = 0.0;
  596. }
  597.  
  598. void LaserScanMatcher::laserScanToLDP(const sensor_msgs::LaserScan::ConstPtr& scan_msg,
  599.         LDP& ldp)
  600. {
  601.     unsigned int n = scan_msg->ranges.size();
  602.     ldp = ld_alloc_new(n);
  603.  
  604.     for (unsigned int i = 0; i < n; i++)
  605.     {
  606.         // calculate position in laser frame
  607.  
  608.         double r = scan_msg->ranges[i];
  609.  
  610.         if (r > scan_msg->range_min && r < scan_msg->range_max)
  611.         {
  612.             // fill in laser scan data
  613.  
  614.             ldp->valid[i] = 1;
  615.             ldp->readings[i] = r;
  616.         }
  617.         else
  618.         {
  619.             ldp->valid[i] = 0;
  620.             ldp->readings[i] = -1;  // for invalid range
  621.         }
  622.  
  623.         ldp->theta[i]    = scan_msg->angle_min + i * scan_msg->angle_increment;
  624.  
  625.         ldp->cluster[i]  = -1;
  626.     }
  627.  
  628.     ldp->min_theta = ldp->theta[0];
  629.     ldp->max_theta = ldp->theta[n-1];
  630.  
  631.     ldp->odometry[0] = 0.0;
  632.     ldp->odometry[1] = 0.0;
  633.     ldp->odometry[2] = 0.0;
  634.  
  635.     ldp->true_pose[0] = 0.0;
  636.     ldp->true_pose[1] = 0.0;
  637.     ldp->true_pose[2] = 0.0;
  638. }
  639.  
  640. void LaserScanMatcher::createCache (const sensor_msgs::LaserScan::ConstPtr& scan_msg)
  641. {
  642.     a_cos_.clear();
  643.     a_sin_.clear();
  644.  
  645.     for (unsigned int i = 0; i < scan_msg->ranges.size(); ++i)
  646.     {
  647.         double angle = scan_msg->angle_min + i * scan_msg->angle_increment;
  648.         a_cos_.push_back(cos(angle));
  649.         a_sin_.push_back(sin(angle));
  650.     }
  651.  
  652.     input_.min_reading = scan_msg->range_min;
  653.     input_.max_reading = scan_msg->range_max;
  654. }
  655.  
  656. bool LaserScanMatcher::getBaseToLaserTf (const std::string& frame_id)
  657. {
  658.     ros::Time t = ros::Time::now();
  659.  
  660.     tf::StampedTransform base_to_laser_tf;
  661.     try
  662.     {
  663.         tf_listener_.waitForTransform(
  664.                 base_frame_, frame_id, t, ros::Duration(1.0));
  665.         tf_listener_.lookupTransform (
  666.                 base_frame_, frame_id, t, base_to_laser_tf);
  667.     }
  668.     catch (tf::TransformException ex)
  669.     {
  670.         ROS_WARN("ScanMatcher: Could not get initial laser transform(%s)", ex.what());
  671.         return false;
  672.     }
  673.     base_to_laser_ = base_to_laser_tf;
  674.     laser_to_base_ = base_to_laser_.inverse();
  675.  
  676.     return true;
  677. }
  678.  
  679. // returns the predicted change in pose (in fixed frame)
  680. // since the last time we did icp
  681. void LaserScanMatcher::getPrediction(double& pr_ch_x, double& pr_ch_y,
  682.         double& pr_ch_a, double dt)
  683. {
  684.     boost::mutex::scoped_lock(mutex_);
  685.  
  686.     // **** base case - no input available, use zero-motion model
  687.     pr_ch_x = 0.0;
  688.     pr_ch_y = 0.0;
  689.     pr_ch_a = 0.0;
  690.  
  691.     // **** use alpha-beta tracking (const. vel. model)
  692.     if (use_alpha_beta_)
  693.     {
  694.         // estmate change in fixed frame, using fixed velocity
  695.         pr_ch_x = v_x_ * dt;     // in fixed frame
  696.         pr_ch_y = v_y_ * dt;
  697.         pr_ch_a = v_a_ * dt;
  698.     }
  699.  
  700.     // **** use wheel odometry
  701.     if (use_odom_ && received_odom_)
  702.     {
  703.         pr_ch_x = latest_odom_.pose.pose.position.x -
  704.                 last_odom_.pose.pose.position.x;
  705.  
  706.         pr_ch_y = latest_odom_.pose.pose.position.y -
  707.                 last_odom_.pose.pose.position.y;
  708.  
  709.         pr_ch_a = getYawFromQuaternion(latest_odom_.pose.pose.orientation) -
  710.                 getYawFromQuaternion(last_odom_.pose.pose.orientation);
  711.  
  712.         last_odom_ = latest_odom_;
  713.     }
  714.  
  715.     // **** use imu
  716.     if (use_imu_ && received_imu_)
  717.     {
  718.         pr_ch_a = latest_imu_yaw_ - last_imu_yaw_;
  719.         last_imu_yaw_ = latest_imu_yaw_;
  720.     }
  721. }
  722.  
  723. double LaserScanMatcher::getYawFromQuaternion(
  724.         const tf::Quaternion& quaternion)
  725. {
  726.     double temp, yaw;
  727.     btMatrix3x3 m(quaternion);
  728.     m.getRPY(temp, temp, yaw);
  729.     return yaw;
  730. }
  731.  
  732. double LaserScanMatcher::getYawFromQuaternion(
  733.         const geometry_msgs::Quaternion& quaternion)
  734. {
  735.     tf::Quaternion q;
  736.     tf::quaternionMsgToTF(quaternion, q);
  737.     return getYawFromQuaternion(q);
  738. }
  739.  
  740. void LaserScanMatcher::createTfFromXYTheta(
  741.         double x, double y, double theta, tf::Transform& t)
  742. {
  743.     t.setOrigin(btVector3(x, y, 0.0));
  744.     tf::Quaternion q;
  745.     q.setRPY(0.0, 0.0, theta);
  746.     t.setRotation(q);
  747. }
  748.  
  749. } //namespace
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement