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 #include "laser_height_estimation/laser_height_estimation.h"
00038 
00039 namespace mav
00040 {
00041 
00042 LaserHeightEstimation::LaserHeightEstimation(ros::NodeHandle nh, ros::NodeHandle nh_private):
00043   nh_(nh),
00044   nh_private_(nh_private),
00045   first_time_(true)
00046 {
00047   ROS_INFO("Starting LaserHeightEstimation");
00048 
00049   initialized_  = false;
00050   floor_height_ = 0.0;
00051   prev_height_  = 0.0;
00052 
00053   world_to_base_.setIdentity();
00054 
00055   ros::NodeHandle nh_mav (nh_, "mav");
00056 
00057   
00058 
00059   if (!nh_private_.getParam ("fixed_frame", world_frame_))
00060       world_frame_ = "/world";
00061   if (!nh_private_.getParam ("base_frame", base_frame_))
00062     base_frame_ = "base_link";
00063   if (!nh_private_.getParam ("footprint_frame", footprint_frame_))
00064     footprint_frame_ = "base_footprint";
00065   if (!nh_private_.getParam ("min_values", min_values_))
00066     min_values_ = 5;
00067   if (!nh_private_.getParam ("max_stdev", max_stdev_))
00068     max_stdev_ = 0.10;
00069   if (!nh_private_.getParam ("max_height_jump", max_height_jump_))
00070     max_height_jump_ = 0.25;
00071   if (!nh_private_.getParam ("use_imu", use_imu_))
00072     use_imu_ = true;
00073   if (!nh_private_.getParam ("use_segmentation", use_segmentation_))
00074     use_segmentation_ = true;
00075   if (!nh_private_.getParam ("bin_size", bin_size_))
00076     bin_size_ = 0.02;
00077 
00078   
00079 
00080   height_to_base_publisher_ = nh_mav.advertise<mav_msgs::Height>(
00081     "height_to_base", 5);
00082   height_to_footprint_publisher_ = nh_mav.advertise<mav_msgs::Height>(
00083     "height_to_footprint", 5);
00084   floor_publisher_ = nh_mav.advertise<mav_msgs::Height>(
00085     "floor_height", 5);
00086 
00087   
00088 
00089   scan_subscriber_ = nh_.subscribe(
00090     "scan", 5, &LaserHeightEstimation::scanCallback, this);
00091   if (use_imu_)
00092   {
00093     imu_subscriber_ = nh_.subscribe(
00094       "imu/data", 5, &LaserHeightEstimation::imuCallback, this);
00095   }
00096 }
00097 
00098 LaserHeightEstimation::~LaserHeightEstimation()
00099 {
00100   ROS_INFO("Destroying LaserHeightEstimation");
00101 }
00102 
00103 void LaserHeightEstimation::imuCallback (const sensor_msgs::ImuPtr& imu_msg)
00104 {
00105   mutex_.lock();
00106 
00107   tf::Quaternion q;
00108   tf::quaternionMsgToTF(imu_msg->orientation, q);   
00109   world_to_base_.setRotation(q);
00110 
00111   mutex_.unlock();
00112 }
00113 
00114 void LaserHeightEstimation::scanCallback (const sensor_msgs::LaserScanPtr& scan_msg)
00115 {
00116   if (!initialized_)
00117   {
00118     
00119     
00120     if (!setBaseToLaserTf(scan_msg)) return;
00121 
00122     initialized_ = true;
00123     last_update_time_ = scan_msg->header.stamp;
00124 
00125     return;
00126   }
00127 
00128   
00129 
00130   if(!use_imu_)
00131   {
00132     tf::StampedTransform world_to_base_tf;
00133 
00134     try
00135     {
00136       tf_listener_.waitForTransform (
00137         world_frame_, base_frame_, scan_msg->header.stamp, ros::Duration(0.5));
00138       tf_listener_.lookupTransform (
00139         world_frame_, base_frame_, scan_msg->header.stamp, world_to_base_tf);
00140     }
00141     catch (tf::TransformException ex)
00142     {
00143       
00144       ROS_WARN ("TF unavailable, skipping scan (%s)", ex.what());
00145       return;
00146     }
00147     world_to_base_.setRotation( world_to_base_tf.getRotation());
00148   }
00149 
00150   mutex_.lock();
00151 
00152   tf::Transform rotated_laser     = world_to_base_ * base_to_laser_;
00153   tf::Transform rotated_footprint = world_to_base_ * base_to_footprint_;
00154 
00155   mutex_.unlock();
00156 
00157   
00158 
00159   std::vector<double> values;
00160   for(unsigned int i = 0; i < scan_msg->ranges.size(); i++)
00161   {
00162     if (scan_msg->ranges[i] > scan_msg->range_min && scan_msg->ranges[i] < scan_msg->range_max)
00163     {
00164       double angle = scan_msg->angle_min + i * scan_msg->angle_increment;
00165       tf::Vector3 v(cos(angle)*scan_msg->ranges[i], sin(angle)*scan_msg->ranges[i], 0.0);
00166       tf::Vector3 p = rotated_laser * v;
00167       values.push_back(p.getZ());
00168     }
00169   }
00170 
00171   
00172 
00173   if (!values.empty() && use_segmentation_)
00174   {
00175     std::vector<double> values_seg;
00176     
00177     histogramSegmentation(values, values_seg);
00178     values = values_seg;
00179   }
00180 
00181   
00182 
00183   if ((int)values.size() < min_values_)
00184   {
00185     ROS_WARN("Not enough valid values to determine height, skipping (%d collected, %d needed)",
00186       values.size(), min_values_);
00187     return;
00188   }
00189 
00190   
00191 
00192   double mean_value, stdev_value;
00193   getStats(values, mean_value, stdev_value);
00194 
00195   if (stdev_value > max_stdev_)
00196   {
00197     ROS_WARN("Stdev of height readings too big to determine height, skipping (stdev is %f, max is %f)",
00198       stdev_value, max_stdev_);
00199     return;
00200   }
00201 
00202   
00203 
00204   double height_to_base = 0.0 - mean_value + floor_height_;
00205   double height_to_footprint = rotated_footprint.getOrigin().getZ() - mean_value + floor_height_;
00206 
00207   
00208 
00209   
00210   if (first_time_)
00211   {
00212     first_time_ = false;
00213     prev_height_ = height_to_base;
00214   }
00215 
00216   double height_jump = prev_height_ - height_to_base;
00217 
00218   if (fabs(height_jump) > max_height_jump_)
00219   {
00220     ROS_WARN("Laser height estimation: floor discontinuity detected");
00221     floor_height_ += height_jump;
00222     height_to_base += height_jump;
00223     height_to_footprint += height_jump;
00224   }
00225 
00226   double dt = (scan_msg->header.stamp - last_update_time_).toSec();
00227 
00228   double climb = (height_to_base - prev_height_)/dt;
00229   prev_height_ = height_to_base;
00230   last_update_time_ = scan_msg->header.stamp;
00231 
00232   
00233 
00234   mav_msgs::HeightPtr height_to_base_msg;
00235   height_to_base_msg = boost::make_shared<mav_msgs::Height>();
00236   height_to_base_msg->height = height_to_base;
00237   height_to_base_msg->height_variance = stdev_value;
00238   height_to_base_msg->climb = climb;
00239   height_to_base_msg->header.stamp = scan_msg->header.stamp;
00240   height_to_base_msg->header.frame_id = scan_msg->header.frame_id;  
00241   height_to_base_publisher_.publish(height_to_base_msg);
00242 
00243   mav_msgs::HeightPtr height_to_footprint_msg;
00244   height_to_footprint_msg = boost::make_shared<mav_msgs::Height>();
00245   height_to_footprint_msg->height = height_to_footprint;
00246   height_to_footprint_msg->height_variance = stdev_value;
00247   height_to_footprint_msg->climb = climb;
00248   height_to_footprint_msg->header.stamp = scan_msg->header.stamp;
00249   height_to_footprint_msg->header.frame_id = scan_msg->header.frame_id; 
00250   height_to_footprint_publisher_.publish(height_to_footprint_msg);
00251 
00252   mav_msgs::HeightPtr floor_msg;
00253   floor_msg = boost::make_shared<mav_msgs::Height>();
00254   floor_msg->height = floor_height_;
00255   floor_msg->header.stamp = scan_msg->header.stamp;
00256   floor_msg->header.frame_id = scan_msg->header.frame_id; 
00257   floor_publisher_.publish(floor_msg);
00258 }
00259 
00260 bool LaserHeightEstimation::setBaseToLaserTf(const sensor_msgs::LaserScanPtr& scan_msg)
00261 {
00262   ros::Time time = scan_msg->header.stamp;
00263 
00264   
00265 
00266   tf::StampedTransform base_to_laser_tf;
00267   try
00268   {
00269     tf_listener_.waitForTransform(
00270       base_frame_, scan_msg->header.frame_id, time, ros::Duration(3.0));
00271 
00272     tf_listener_.lookupTransform (
00273       base_frame_, scan_msg->header.frame_id, time, base_to_laser_tf);
00274   }
00275   catch (tf::TransformException ex)
00276   {
00277     
00278     ROS_WARN("%s: Transform unavailable, skipping scan (%s)", ros::this_node::getName().c_str(), ex.what());
00279     return false;
00280   }
00281 
00282   base_to_laser_ = base_to_laser_tf;
00283 
00284   
00285 
00286   tf::StampedTransform base_to_footprint_tf;
00287   try
00288   {
00289     tf_listener_.waitForTransform(
00290       base_frame_, footprint_frame_, time, ros::Duration(3.0));
00291 
00292     tf_listener_.lookupTransform (
00293       base_frame_, footprint_frame_, time, base_to_footprint_tf);
00294   }
00295   catch (tf::TransformException ex)
00296   {
00297     
00298     ROS_WARN("%s: Transform unavailable, skipping scan (%s)", ros::this_node::getName().c_str(), ex.what());
00299     return false;
00300   }
00301 
00302   base_to_footprint_ = base_to_footprint_tf;
00303 
00304   return true;
00305 }
00306 
00307 void LaserHeightEstimation::getStats(const std::vector<double> values, double& ave, double& stdev)
00308 {
00309   double sum   = 0.0;
00310   double sumsq = 0.0;
00311 
00312   for (size_t i = 0; i < values.size(); ++i)
00313     sum += values[i];
00314 
00315   ave = sum/values.size();
00316 
00317   for (size_t i = 0; i < values.size(); ++i)
00318     sumsq += (values[i] - ave) * (values[i] - ave);
00319 
00320   stdev = sqrt(sumsq/values.size());
00321 }
00322 
00323 void LaserHeightEstimation::histogramSegmentation(
00324   const std::vector<double>& input,
00325   std::vector<double>& output)
00326 {
00327   
00328 
00329   double min_value = input[0];
00330   double max_value = input[0];
00331   for (unsigned int i = 0; i < input.size(); ++i)
00332   {
00333     if (input[i] < min_value) min_value = input[i];
00334     if (input[i] > max_value) max_value = input[i];
00335   }  
00336 
00337   
00338 
00339   int n_bins = (max_value - min_value) / bin_size_ + 1;
00340   std::vector<int> bins;
00341   bins.resize(n_bins);
00342 
00343   for (unsigned int i = 0; i < bins.size(); ++i)
00344     bins[i] = 0; 
00345 
00346   for (unsigned int i = 0; i < input.size(); ++i)
00347   { 
00348     unsigned int bin_idx = (input[i] - min_value) / bin_size_;
00349     bins[bin_idx]++;
00350   } 
00351 
00352   
00353 
00354   unsigned int best_bin_idx = 0;
00355   int best_bin_count = 0;
00356   for (unsigned int i = 0; i < bins.size(); ++i)
00357   { 
00358     if (bins[i] > best_bin_count)
00359     {
00360       best_bin_count = bins[i];
00361       best_bin_idx = i;
00362     }
00363   }
00364 
00365   
00366  
00367   output.clear();
00368   for (unsigned int i = 0; i < input.size(); ++i)
00369   {
00370     unsigned int bin_idx = (input[i] - min_value) / bin_size_;
00371     if (bin_idx == best_bin_idx)
00372       output.push_back(input[i]);
00373   }
00374 }
00375 
00376 void LaserHeightEstimation::kMeansSegmentation(
00377   const std::vector<double>& input,
00378   std::vector<double>& output)
00379 {
00380   
00381 
00382   double mean_a = input[0];
00383   double mean_b = input[input.size() - 1];
00384   int count_a, count_b;
00385 
00386   std::vector<bool> mask;
00387   mask.resize(input.size());
00388   for(unsigned int i = 0; i < mask.size()-1; ++i) 
00389     mask[i] = true;
00390   mask[mask.size()-1] = false;
00391   
00392   
00393 
00394   bool converged = false;
00395   while (!converged)
00396   {
00397     converged = kMeansSegmentation(
00398       input, mask, mean_a, mean_b, count_a, count_b);
00399   }
00400 
00401   if (std::abs(mean_a - mean_b) > max_height_jump_)
00402     ROS_WARN("Floor discontinuity in clusters");
00403 
00404   
00405 
00406   if (count_a >= count_b)
00407   {
00408     for (unsigned int i = 0; i < input.size(); ++i)
00409       if (mask[i]) output.push_back(input[i]);
00410   }
00411   else
00412   {
00413     for (unsigned int i = 0; i < input.size(); ++i)
00414       if (!mask[i]) output.push_back(input[i]);
00415   }
00416 }
00417 
00418 bool LaserHeightEstimation::kMeansSegmentation(
00419   const std::vector<double>& input,
00420   std::vector<bool>& mask,
00421   double& mean_a, double& mean_b,
00422   int& count_a, int& count_b)
00423 {
00424   
00425   
00426   
00427   bool converged = true;
00428   double sum_a = 0.0;
00429   double sum_b = 0.0;
00430   count_a = 0;
00431   count_b = 0;
00432 
00433   for (unsigned int i = 0; i < input.size(); ++i)
00434   {
00435     double da2 = (input[i] - mean_a) * (input[i] - mean_a);
00436     double db2 = (input[i] - mean_b) * (input[i] - mean_b);
00437 
00438     if (da2 <= db2)
00439     {
00440       
00441       if (!mask[i]) converged = false;
00442       mask[i] = true;
00443       sum_a += input[i];
00444       ++count_a;
00445     }
00446     else
00447     {
00448       
00449       if (mask[i]) converged = false;
00450       mask[i] = false;
00451       sum_b += input[i];
00452       ++count_b;
00453     }
00454   }
00455 
00456   
00457 
00458   if (count_a == 0 || count_b == 0) return true;
00459 
00460   mean_a = sum_a / (double)count_a;
00461   mean_b = sum_b / (double)count_b;
00462 
00463   return converged;
00464 }
00465 
00466 
00467 };