scan_unifier_node.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright 2017 Fraunhofer Institute for Manufacturing Engineering and Automation (IPA)
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *   http://www.apache.org/licenses/LICENSE-2.0
00009 
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016  
00017 
00018 #include <cob_scan_unifier/scan_unifier_node.h>
00019 
00020 // Constructor
00021 ScanUnifierNode::ScanUnifierNode()
00022 {
00023   ROS_DEBUG("Init scan_unifier");
00024 
00025   // Create node handles
00026   nh_ = ros::NodeHandle();
00027   pnh_ = ros::NodeHandle("~");
00028 
00029   // Publisher
00030   topicPub_LaserUnified_ = nh_.advertise<sensor_msgs::LaserScan>("scan_unified", 1);
00031 
00032   getParams();
00033   synchronizer2_ = NULL;
00034   synchronizer3_ = NULL;
00035   synchronizer4_ = NULL;
00036 
00037   // Subscribe to Laserscan topics
00038 
00039   for(int i = 0; i < config_.number_input_scans; i++)
00040   {
00041     message_filter_subscribers_.push_back(new message_filters::Subscriber<sensor_msgs::LaserScan>(nh_, config_.input_scan_topics.at(i), 1));
00042   }
00043 
00044 
00045   // Initialize message_filters::Synchronizer with the right constructor for the choosen number of inputs.
00046 
00047   switch (config_.number_input_scans)
00048   {
00049     case 2:
00050     {
00051       typedef message_filters::sync_policies::ApproximateTime<sensor_msgs::LaserScan, sensor_msgs::LaserScan> SyncPolicy;
00052       synchronizer2_ = new message_filters::Synchronizer<SyncPolicy>(SyncPolicy(2), *message_filter_subscribers_.at(0),
00053                                                                                     *message_filter_subscribers_.at(1));
00054       // Set the InterMessageLowerBound to double the period of the laser scans publishing ( 1/{(1/2)*f_laserscans} ).
00055       synchronizer2_->setInterMessageLowerBound(0, ros::Duration(0.167));
00056       synchronizer2_->setInterMessageLowerBound(1, ros::Duration(0.167));
00057       synchronizer2_->registerCallback(boost::bind(&ScanUnifierNode::messageFilterCallback, this, _1, _2));
00058       break;
00059     }
00060     case 3:
00061     {
00062       typedef message_filters::sync_policies::ApproximateTime<sensor_msgs::LaserScan, sensor_msgs::LaserScan, sensor_msgs::LaserScan> SyncPolicy;
00063       synchronizer3_ = new message_filters::Synchronizer<SyncPolicy>(SyncPolicy(3), *message_filter_subscribers_.at(0),
00064                                                                                     *message_filter_subscribers_.at(1),
00065                                                                                     *message_filter_subscribers_.at(2));
00066       synchronizer3_->setInterMessageLowerBound(0, ros::Duration(0.167));
00067       synchronizer3_->setInterMessageLowerBound(1, ros::Duration(0.167));
00068       synchronizer3_->setInterMessageLowerBound(2, ros::Duration(0.167));
00069       synchronizer3_->registerCallback(boost::bind(&ScanUnifierNode::messageFilterCallback, this, _1, _2, _3));
00070       break;
00071     }
00072     case 4:
00073     {
00074       typedef message_filters::sync_policies::ApproximateTime<sensor_msgs::LaserScan, sensor_msgs::LaserScan, sensor_msgs::LaserScan, sensor_msgs::LaserScan> SyncPolicy;
00075       synchronizer4_ = new message_filters::Synchronizer<SyncPolicy>(SyncPolicy(4), *message_filter_subscribers_.at(0),
00076                                                                                     *message_filter_subscribers_.at(1),
00077                                                                                     *message_filter_subscribers_.at(2),
00078                                                                                     *message_filter_subscribers_.at(3));
00079       synchronizer4_->setInterMessageLowerBound(0, ros::Duration(0.167));
00080       synchronizer4_->setInterMessageLowerBound(1, ros::Duration(0.167));
00081       synchronizer4_->setInterMessageLowerBound(2, ros::Duration(0.167));
00082       synchronizer4_->setInterMessageLowerBound(3, ros::Duration(0.167));
00083       synchronizer4_->registerCallback(boost::bind(&ScanUnifierNode::messageFilterCallback, this, _1, _2, _3, _4));
00084       break;
00085     }
00086     default:
00087       ROS_ERROR_STREAM(config_.number_input_scans << " topics have been set as input, but scan_unifier doesn't support this.");
00088       return;
00089   }
00090 
00091   ros::Duration(1.0).sleep();
00092 }
00093 
00094 // Destructor
00095 
00096 ScanUnifierNode::~ScanUnifierNode()
00097 {
00098   if(synchronizer2_ != NULL)
00099     delete(synchronizer2_);
00100   if(synchronizer3_ != NULL)
00101     delete(synchronizer3_);
00102   if(synchronizer4_ != NULL)
00103     delete(synchronizer4_);
00104 }
00105 
00113 void ScanUnifierNode::getParams()
00114 {
00115   std::vector<std::string> topicList;
00116 
00117   if (pnh_.getParam("input_scans", topicList))
00118   {
00119     config_.input_scan_topics = topicList;
00120     config_.number_input_scans = config_.input_scan_topics.size();
00121   }
00122   else
00123   {
00124     config_.number_input_scans = 0;
00125     ROS_ERROR("No parameter input_scans on parameter server!! Scan unifier can not subscribe to any scan topic!");
00126   }
00127 
00128   if(!pnh_.hasParam("frame"))
00129   {
00130     ROS_WARN("No parameter frame on parameter server. Using default value [base_link].");
00131   }
00132   pnh_.param<std::string>("frame", frame_, "base_link");
00133 }
00134 
00135 
00136 void ScanUnifierNode::messageFilterCallback(const sensor_msgs::LaserScan::ConstPtr& scan1, const sensor_msgs::LaserScan::ConstPtr& scan2)
00137 {
00138   std::vector<sensor_msgs::LaserScan::ConstPtr> current_scans;
00139   current_scans.push_back(scan1);
00140   current_scans.push_back(scan2);
00141 
00142   sensor_msgs::LaserScan unified_scan = sensor_msgs::LaserScan();
00143   if (!unifyLaserScans(current_scans, unified_scan))
00144   {
00145     return;
00146   }
00147 
00148   ROS_DEBUG("Publishing unified scan.");
00149   topicPub_LaserUnified_.publish(unified_scan);
00150 }
00151 
00152 void ScanUnifierNode::messageFilterCallback(const sensor_msgs::LaserScan::ConstPtr& scan1,
00153                                             const sensor_msgs::LaserScan::ConstPtr& scan2,
00154                                             const sensor_msgs::LaserScan::ConstPtr& scan3)
00155 {
00156   std::vector<sensor_msgs::LaserScan::ConstPtr> current_scans;
00157   current_scans.push_back(scan1);
00158   current_scans.push_back(scan2);
00159   current_scans.push_back(scan3);
00160 
00161   sensor_msgs::LaserScan unified_scan = sensor_msgs::LaserScan();
00162   if (!unifyLaserScans(current_scans, unified_scan))
00163   {
00164     return;
00165   }
00166 
00167   ROS_DEBUG("Publishing unified scan.");
00168   topicPub_LaserUnified_.publish(unified_scan);
00169 }
00170 
00171 void ScanUnifierNode::messageFilterCallback(const sensor_msgs::LaserScan::ConstPtr& scan1,
00172                                             const sensor_msgs::LaserScan::ConstPtr& scan2,
00173                                             const sensor_msgs::LaserScan::ConstPtr& scan3,
00174                                             const sensor_msgs::LaserScan::ConstPtr& scan4)
00175 {
00176   std::vector<sensor_msgs::LaserScan::ConstPtr> current_scans;
00177   current_scans.push_back(scan1);
00178   current_scans.push_back(scan2);
00179   current_scans.push_back(scan3);
00180   current_scans.push_back(scan4);
00181 
00182   sensor_msgs::LaserScan unified_scan = sensor_msgs::LaserScan();
00183   if (!unifyLaserScans(current_scans, unified_scan))
00184   {
00185     return;
00186   }
00187 
00188   ROS_DEBUG("Publishing unified scan.");
00189   topicPub_LaserUnified_.publish(unified_scan);
00190 }
00191 
00200 bool ScanUnifierNode::unifyLaserScans(std::vector<sensor_msgs::LaserScan::ConstPtr> current_scans, sensor_msgs::LaserScan &unified_scan)
00201 {
00202   std::vector<sensor_msgs::PointCloud> vec_cloud;
00203   vec_cloud.assign(config_.number_input_scans, sensor_msgs::PointCloud());
00204 
00205   if(!current_scans.empty())
00206   {
00207     ROS_DEBUG("start converting");
00208     for(int i=0; i < config_.number_input_scans; i++)
00209     {
00210       vec_cloud.at(i).header.stamp = current_scans.at(i)->header.stamp;
00211       ROS_DEBUG_STREAM("Converting scans to point clouds at index: " << i << ", at time: " << current_scans.at(i)->header.stamp << " now: " << ros::Time::now());
00212       try
00213       {
00214         if (!listener_.waitForTransform(frame_, current_scans.at(i)->header.frame_id,
00215                                         current_scans.at(i)->header.stamp, ros::Duration(1.0)))
00216         {
00217           ROS_WARN_STREAM("Scan unifier skipped scan with " << current_scans.at(i)->header.stamp << " stamp, because of missing tf transform.");
00218           return false;
00219         }
00220 
00221         ROS_DEBUG("now project to point_cloud");
00222         projector_.transformLaserScanToPointCloud(frame_,*current_scans.at(i), vec_cloud.at(i), listener_);
00223       }
00224       catch(tf::TransformException &ex){
00225         ROS_ERROR("%s",ex.what());
00226       }
00227     }
00228     ROS_DEBUG("Creating message header");
00229     unified_scan.header = current_scans.at(0)->header;
00230     unified_scan.header.frame_id = frame_;
00231     unified_scan.angle_increment = M_PI/180.0/2.0;
00232     unified_scan.angle_min = -M_PI + unified_scan.angle_increment*0.01;
00233     unified_scan.angle_max =  M_PI - unified_scan.angle_increment*0.01;
00234     unified_scan.time_increment = 0.0;
00235     unified_scan.scan_time = current_scans.at(0)->scan_time;
00236     unified_scan.range_min = current_scans.at(0)->range_min;
00237     unified_scan.range_max = current_scans.at(0)->range_max;
00238     //default values (ranges: range_max, intensities: 0) are used to better reflect the driver behavior
00239     //there "phantom" data has values > range_max
00240     //but those values are removed during projection to pointcloud
00241     unified_scan.ranges.resize(round((unified_scan.angle_max - unified_scan.angle_min) / unified_scan.angle_increment) + 1, unified_scan.range_max);
00242     unified_scan.intensities.resize(round((unified_scan.angle_max - unified_scan.angle_min) / unified_scan.angle_increment) + 1, 0.0);
00243 
00244     // now unify all Scans
00245     ROS_DEBUG("unify scans");
00246     for(int j = 0; j < config_.number_input_scans; j++)
00247     {
00248       for (unsigned int i = 0; i < vec_cloud.at(j).points.size(); i++)
00249       {
00250         const float &x = vec_cloud.at(j).points[i].x;
00251         const float &y = vec_cloud.at(j).points[i].y;
00252         const float &z = vec_cloud.at(j).points[i].z;
00253         //ROS_INFO("Point %f %f %f", x, y, z);
00254         if ( std::isnan(x) || std::isnan(y) || std::isnan(z) )
00255         {
00256           ROS_DEBUG("rejected for nan in point(%f, %f, %f)\n", x, y, z);
00257           continue;
00258         }
00259         double angle = atan2(y, x);// + M_PI/2;
00260         if (angle < unified_scan.angle_min || angle > unified_scan.angle_max)
00261         {
00262           ROS_DEBUG("rejected for angle %f not in range (%f, %f)\n", angle, unified_scan.angle_min, unified_scan.angle_max);
00263           continue;
00264         }
00265         int index = std::floor(0.5 + (angle - unified_scan.angle_min) / unified_scan.angle_increment);
00266         if(index<0 || index>=unified_scan.ranges.size()) continue;
00267 
00268         double range_sq = y*y+x*x;
00269         //printf ("index xyz( %f %f %f) angle %f index %d range %f\n", x, y, z, angle, index, sqrt(range_sq));
00270         if( (sqrt(range_sq) <= unified_scan.ranges.at(index)) )
00271         {
00272           // use the nearest reflection point of all scans for unified scan
00273           unified_scan.ranges.at(index) = sqrt(range_sq);
00274           // get respective intensity from point cloud intensity-channel (index 0)
00275           unified_scan.intensities.at(index) = vec_cloud.at(j).channels.at(0).values.at(i);
00276         }
00277       }
00278     }
00279   }
00280 
00281   return true;
00282 }
00283 
00284 int main(int argc, char** argv)
00285 {
00286   ROS_DEBUG("scan unifier: start scan unifier node");
00287   ros::init(argc, argv, "cob_scan_unifier_node");
00288 
00289   ScanUnifierNode scan_unifier_node;
00290 
00291   ros::spin();
00292 
00293   return 0;
00294 }


cob_scan_unifier
Author(s): Florian Mirus
autogenerated on Sat Jun 8 2019 21:02:20