scan_unifier_node.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017 Fraunhofer Institute for Manufacturing Engineering and Automation (IPA)
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 
19 
20 // Constructor
22 {
23  ROS_DEBUG("Init scan_unifier");
24 
25  // Create node handles
26  nh_ = ros::NodeHandle();
27  pnh_ = ros::NodeHandle("~");
28 
29  // Publisher
30  topicPub_LaserUnified_ = nh_.advertise<sensor_msgs::LaserScan>("scan_unified", 1);
31 
32  getParams();
33  synchronizer2_ = NULL;
34  synchronizer3_ = NULL;
35  synchronizer4_ = NULL;
36 
37  // Subscribe to Laserscan topics
38 
39  for(int i = 0; i < config_.number_input_scans; i++)
40  {
43  }
44 
45 
46  // Initialize message_filters::Synchronizer with the right constructor for the choosen number of inputs.
47 
49  {
50  case 2:
51  {
54  SyncPolicy(2), *message_filter_subscribers_.front(), *message_filter_subscribers_[1]);
55  // Set the InterMessageLowerBound to double the period of the laser scans publishing ( 1/{(1/2)*f_laserscans} ).
56  synchronizer2_->setInterMessageLowerBound(0, ros::Duration(0.167));
57  synchronizer2_->setInterMessageLowerBound(1, ros::Duration(0.167));
59  break;
60  }
61  case 3:
62  {
65  SyncPolicy(3), *message_filter_subscribers_.front(), *message_filter_subscribers_[1],
67  synchronizer3_->setInterMessageLowerBound(0, ros::Duration(0.167));
68  synchronizer3_->setInterMessageLowerBound(1, ros::Duration(0.167));
69  synchronizer3_->setInterMessageLowerBound(2, ros::Duration(0.167));
71  break;
72  }
73  case 4:
74  {
77  SyncPolicy(4), *message_filter_subscribers_.front(), *message_filter_subscribers_[1],
78  *message_filter_subscribers_[2], *message_filter_subscribers_[3]);
79  synchronizer4_->setInterMessageLowerBound(0, ros::Duration(0.167));
80  synchronizer4_->setInterMessageLowerBound(1, ros::Duration(0.167));
81  synchronizer4_->setInterMessageLowerBound(2, ros::Duration(0.167));
82  synchronizer4_->setInterMessageLowerBound(3, ros::Duration(0.167));
83  synchronizer4_->registerCallback(boost::bind(&ScanUnifierNode::messageFilterCallback, this, _1, _2, _3, _4));
84  break;
85  }
86  default:
87  ROS_ERROR_STREAM(config_.number_input_scans << " topics have been set as input, but scan_unifier doesn't support this.");
88  return;
89  }
90 
91  ros::Duration(1.0).sleep();
92 }
93 
94 // Destructor
95 
97 {
98  if(synchronizer2_ != NULL)
99  delete(synchronizer2_);
100  if(synchronizer3_ != NULL)
101  delete(synchronizer3_);
102  if(synchronizer4_ != NULL)
103  delete(synchronizer4_);
104 }
105 
114 {
115  std::vector<std::string> topicList;
116 
117  if (pnh_.getParam("input_scans", topicList))
118  {
119  config_.input_scan_topics = topicList;
121  }
122  else
123  {
125  ROS_ERROR("No parameter input_scans on parameter server!! Scan unifier can not subscribe to any scan topic!");
126  }
127 
128  if(!pnh_.hasParam("frame"))
129  {
130  ROS_WARN("No parameter frame on parameter server. Using default value [base_link].");
131  }
132  pnh_.param<std::string>("frame", frame_, "base_link");
133 }
134 
135 
136 void ScanUnifierNode::messageFilterCallback(const sensor_msgs::LaserScan::ConstPtr& scan1, const sensor_msgs::LaserScan::ConstPtr& scan2)
137 {
138  std::vector<sensor_msgs::LaserScan::ConstPtr> current_scans;
139  current_scans.push_back(scan1);
140  current_scans.push_back(scan2);
141 
142  sensor_msgs::LaserScan unified_scan = sensor_msgs::LaserScan();
143  if (!unifyLaserScans(current_scans, unified_scan))
144  {
145  return;
146  }
147 
148  ROS_DEBUG("Publishing unified scan.");
149  topicPub_LaserUnified_.publish(unified_scan);
150 }
151 
152 void ScanUnifierNode::messageFilterCallback(const sensor_msgs::LaserScan::ConstPtr& scan1,
153  const sensor_msgs::LaserScan::ConstPtr& scan2,
154  const sensor_msgs::LaserScan::ConstPtr& scan3)
155 {
156  std::vector<sensor_msgs::LaserScan::ConstPtr> current_scans;
157  current_scans.push_back(scan1);
158  current_scans.push_back(scan2);
159  current_scans.push_back(scan3);
160 
161  sensor_msgs::LaserScan unified_scan = sensor_msgs::LaserScan();
162  if (!unifyLaserScans(current_scans, unified_scan))
163  {
164  return;
165  }
166 
167  ROS_DEBUG("Publishing unified scan.");
168  topicPub_LaserUnified_.publish(unified_scan);
169 }
170 
171 void ScanUnifierNode::messageFilterCallback(const sensor_msgs::LaserScan::ConstPtr& scan1,
172  const sensor_msgs::LaserScan::ConstPtr& scan2,
173  const sensor_msgs::LaserScan::ConstPtr& scan3,
174  const sensor_msgs::LaserScan::ConstPtr& scan4)
175 {
176  std::vector<sensor_msgs::LaserScan::ConstPtr> current_scans;
177  current_scans.push_back(scan1);
178  current_scans.push_back(scan2);
179  current_scans.push_back(scan3);
180  current_scans.push_back(scan4);
181 
182  sensor_msgs::LaserScan unified_scan = sensor_msgs::LaserScan();
183  if (!unifyLaserScans(current_scans, unified_scan))
184  {
185  return;
186  }
187 
188  ROS_DEBUG("Publishing unified scan.");
189  topicPub_LaserUnified_.publish(unified_scan);
190 }
191 
200 bool ScanUnifierNode::unifyLaserScans(const std::vector<sensor_msgs::LaserScan::ConstPtr>& current_scans,
201  sensor_msgs::LaserScan& unified_scan)
202 {
203  if (vec_cloud_.size() != config_.number_input_scans)
204  {
206  }
207 
208  if(!current_scans.empty())
209  {
210  ROS_DEBUG("start converting");
211  for(int i=0; i < config_.number_input_scans; i++)
212  {
213  vec_cloud_[i].header.stamp = current_scans[i]->header.stamp;
214  ROS_DEBUG_STREAM("Converting scans to point clouds at index: "
215  << i << ", at time: " << current_scans[i]->header.stamp << " now: " << ros::Time::now());
216  try
217  {
218  if (!listener_.waitForTransform(frame_, current_scans[i]->header.frame_id, current_scans[i]->header.stamp,
219  ros::Duration(1.0)))
220  {
221  ROS_WARN_STREAM("Scan unifier skipped scan with " << current_scans[i]->header.stamp
222  << " stamp, because of missing tf transform.");
223  return false;
224  }
225 
226  ROS_DEBUG("now project to point_cloud");
228  }
229  catch(tf::TransformException &ex){
230  ROS_ERROR("%s",ex.what());
231  }
232  }
233  ROS_DEBUG("Creating message header");
234  unified_scan.header = current_scans.front()->header;
235  unified_scan.header.frame_id = frame_;
236  unified_scan.angle_increment = M_PI/180.0/2.0;
237  unified_scan.angle_min = -M_PI + unified_scan.angle_increment*0.01;
238  unified_scan.angle_max = M_PI - unified_scan.angle_increment*0.01;
239  unified_scan.time_increment = 0.0;
240  unified_scan.scan_time = current_scans.front()->scan_time;
241  unified_scan.range_min = current_scans.front()->range_min;
242  unified_scan.range_max = current_scans.front()->range_max;
243  //default values (ranges: range_max, intensities: 0) are used to better reflect the driver behavior
244  //there "phantom" data has values > range_max
245  //but those values are removed during projection to pointcloud
246  unified_scan.ranges.resize(round((unified_scan.angle_max - unified_scan.angle_min) / unified_scan.angle_increment) + 1, unified_scan.range_max);
247  unified_scan.intensities.resize(round((unified_scan.angle_max - unified_scan.angle_min) / unified_scan.angle_increment) + 1, 0.0);
248 
249  // now unify all Scans
250  ROS_DEBUG("unify scans");
251  for(int j = 0; j < config_.number_input_scans; j++)
252  {
253  for (unsigned int i = 0; i < vec_cloud_[j].points.size(); i++)
254  {
255  const float& x = vec_cloud_[j].points[i].x;
256  const float& y = vec_cloud_[j].points[i].y;
257  const float& z = vec_cloud_[j].points[i].z;
258  //ROS_INFO("Point %f %f %f", x, y, z);
259  if ( std::isnan(x) || std::isnan(y) || std::isnan(z) )
260  {
261  ROS_DEBUG("rejected for nan in point(%f, %f, %f)\n", x, y, z);
262  continue;
263  }
264  double angle = atan2(y, x);// + M_PI/2;
265  if (angle < unified_scan.angle_min || angle > unified_scan.angle_max)
266  {
267  ROS_DEBUG("rejected for angle %f not in range (%f, %f)\n", angle, unified_scan.angle_min, unified_scan.angle_max);
268  continue;
269  }
270  int index = std::floor(0.5 + (angle - unified_scan.angle_min) / unified_scan.angle_increment);
271  if(index<0 || index>=unified_scan.ranges.size()) continue;
272 
273  double range_sq = y*y+x*x;
274  //printf ("index xyz( %f %f %f) angle %f index %d range %f\n", x, y, z, angle, index, sqrt(range_sq));
275  if ((sqrt(range_sq) <= unified_scan.ranges[index]))
276  {
277  // use the nearest reflection point of all scans for unified scan
278  unified_scan.ranges[index] = sqrt(range_sq);
279  // get respective intensity from point cloud intensity-channel (index 0)
280  unified_scan.intensities[index] = vec_cloud_[j].channels.front().values[i];
281  }
282  }
283  }
284  }
285 
286  return true;
287 }
288 
289 int main(int argc, char** argv)
290 {
291  ROS_DEBUG("scan unifier: start scan unifier node");
292  ros::init(argc, argv, "cob_scan_unifier_node");
293 
294  ScanUnifierNode scan_unifier_node;
295 
296  ros::spin();
297 
298  return 0;
299 }
void publish(const boost::shared_ptr< M > &message) const
config_struct config_
ros::NodeHandle nh_
bool sleep() const
std::vector< sensor_msgs::PointCloud > vec_cloud_
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
TFSIMD_FORCE_INLINE const tfScalar & y() const
#define ROS_WARN(...)
message_filters::Synchronizer< message_filters::sync_policies::ApproximateTime< sensor_msgs::LaserScan, sensor_msgs::LaserScan > > * synchronizer2_
TFSIMD_FORCE_INLINE tfScalar angle(const Quaternion &q1, const Quaternion &q2)
ROSCPP_DECL void spin(Spinner &spinner)
bool waitForTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, const ros::Duration &timeout, const ros::Duration &polling_sleep_duration=ros::Duration(0.01), std::string *error_msg=NULL) const
ros::NodeHandle pnh_
std::vector< message_filters::Subscriber< sensor_msgs::LaserScan > * > message_filter_subscribers_
std::string frame_
message_filters::Synchronizer< message_filters::sync_policies::ApproximateTime< sensor_msgs::LaserScan, sensor_msgs::LaserScan, sensor_msgs::LaserScan > > * synchronizer3_
Connection registerCallback(C &callback)
void messageFilterCallback(const sensor_msgs::LaserScan::ConstPtr &first_scanner, const sensor_msgs::LaserScan::ConstPtr &second_scanner)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
TFSIMD_FORCE_INLINE const tfScalar & x() const
tf::TransformListener listener_
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
bool unifyLaserScans(const std::vector< sensor_msgs::LaserScan::ConstPtr > &current_scans, sensor_msgs::LaserScan &unified_scan)
unifie the scan information from all laser scans in vec_laser_struct_
#define ROS_WARN_STREAM(args)
#define ROS_DEBUG_STREAM(args)
TFSIMD_FORCE_INLINE const tfScalar & z() const
void getParams()
function to load parameters from ros parameter server
int main(int argc, char **argv)
ros::Publisher topicPub_LaserUnified_
bool getParam(const std::string &key, std::string &s) const
INLINE Rall1d< T, V, S > atan2(const Rall1d< T, V, S > &y, const Rall1d< T, V, S > &x)
static Time now()
std::vector< std::string > input_scan_topics
void transformLaserScanToPointCloud(const std::string &target_frame, const sensor_msgs::LaserScan &scan_in, sensor_msgs::PointCloud &cloud_out, tf::Transformer &tf, double range_cutoff, int channel_options=channel_option::Default)
bool hasParam(const std::string &key) const
#define ROS_ERROR_STREAM(args)
laser_geometry::LaserProjection projector_
message_filters::Synchronizer< message_filters::sync_policies::ApproximateTime< sensor_msgs::LaserScan, sensor_msgs::LaserScan, sensor_msgs::LaserScan, sensor_msgs::LaserScan > > * synchronizer4_
#define ROS_ERROR(...)
#define ROS_DEBUG(...)


cob_scan_unifier
Author(s): Florian Mirus
autogenerated on Wed Apr 7 2021 02:11:48