laserscan_virtualizer.cpp
Go to the documentation of this file.
1 #include <ros/ros.h>
2 #include <string.h>
4 #include <pcl_ros/transforms.h>
6 #include <pcl/conversions.h>
7 #include <pcl/point_cloud.h>
8 #include <pcl/point_types.h>
9 #include <pcl/io/pcd_io.h>
11 #include "sensor_msgs/LaserScan.h"
12 #include <pcl_ros/point_cloud.h>
13 #include <Eigen/Dense>
14 #include <dynamic_reconfigure/server.h>
15 #include <ira_laser_tools/laserscan_virtualizerConfig.h>
16 
17 typedef pcl::PointCloud<pcl::PointXYZ> myPointCloud;
18 
19 using namespace std;
20 using namespace pcl;
21 using namespace laserscan_virtualizer;
22 
24 {
25  public:
27  void scanCallback(const sensor_msgs::LaserScan::ConstPtr& scan, std::string topic);
28  void pointcloud_to_laserscan(Eigen::MatrixXf points, pcl::PCLHeader scan_header, int pub_index);
29  void pointCloudCallback(const sensor_msgs::PointCloud2::ConstPtr& pcl_in);
30  void reconfigureCallback(laserscan_virtualizerConfig &config, uint32_t level);
31 
32  private:
35  vector<tf::StampedTransform> transform_;
36 
38  vector<ros::Publisher> virtual_scan_publishers;
39  vector<string> output_frames;
40 
41  void virtual_laser_scan_parser();
42 
43  double angle_min;
44  double angle_max;
47  double scan_time;
48  double range_min;
49  double range_max;
50 
51  string cloud_frame;
52  string base_frame;
53  string cloud_topic;
56 };
57 
58 void LaserscanVirtualizer::reconfigureCallback(laserscan_virtualizerConfig &config, uint32_t level)
59 {
60  this->angle_min = config.angle_min;
61  this->angle_max = config.angle_max;
62  this->angle_increment = config.angle_increment;
63  this->time_increment = config.time_increment;
64  this->scan_time = config.scan_time;
65  this->range_min = config.range_min;
66  this->range_max = config.range_max;
67 }
68 
70 {
71  // LaserScan frames to use for virtualization
72  istringstream iss(virtual_laser_scan);
73  vector<string> tokens;
74  copy(istream_iterator<string>(iss), istream_iterator<string>(), back_inserter<vector<string> >(tokens));
75 
76  vector<string> tmp_output_frames;
77 
78  for(int i=0;i<tokens.size();++i)
79  {
80  ros::Time beg = ros::Time::now();
81  if(tfListener_.waitForTransform (base_frame, tokens[i] ,ros::Time(0),ros::Duration(1.0))) // Check if TF knows the transform from this frame reference to base_frame reference
82  {
83  cout << "Elapsed: " << ros::Time::now() - beg << endl;
84  cout << "Adding: " << tokens[i] << endl;
85  tmp_output_frames.push_back(tokens[i]);
86  }
87  else
88  cout << "Can't transform: '" << tokens[i] + "' to '" << base_frame << "'" << endl;
89  }
90 
91  // Sort and remove duplicates
92  sort(tmp_output_frames.begin(),tmp_output_frames.end());
93  std::vector<string>::iterator last = std::unique(tmp_output_frames.begin(), tmp_output_frames.end());
94  tmp_output_frames.erase(last, tmp_output_frames.end());
95 
96  // Do not re-advertize if the topics are the same
97  if( (tmp_output_frames.size() != output_frames.size()) || !equal(tmp_output_frames.begin(),tmp_output_frames.end(),output_frames.begin()) )
98  {
99  // Shutdown previous publishers
100  for(int i=0; i<virtual_scan_publishers.size(); ++i)
101  virtual_scan_publishers[i].shutdown();
102 
103  cloud_frame = "";
104 
105  output_frames = tmp_output_frames;
106  if(output_frames.size() > 0)
107  {
108  virtual_scan_publishers.resize(output_frames.size());
109  ROS_INFO("Publishing: %ld virtual scans", virtual_scan_publishers.size() );
110  cout << "Advertising topics: " << endl;
111  for(int i=0; i<output_frames.size(); ++i)
112  {
113  if (output_laser_topic.empty())
114  {
115  virtual_scan_publishers[i] = node_.advertise<sensor_msgs::LaserScan> (output_frames[i].c_str(), 1);
116  cout << "\t\t" << output_frames[i] << " on topic " << output_frames[i].c_str() << endl;
117  }
118  else
119  {
120  virtual_scan_publishers[i] = node_.advertise<sensor_msgs::LaserScan> (output_laser_topic.c_str(), 1);
121  cout << "\t\t" << output_frames[i] << " on topic " << output_laser_topic.c_str() << endl;
122  }
123  }
124  }
125  else
126  ROS_INFO("Not publishing to any topic.");
127  }
128 }
129 
131 {
132  ros::NodeHandle nh("~");
133 
134  //Setting class parameters
135  if(!nh.getParam("/laserscan_virtualizer/base_frame", base_frame)) base_frame = "/cart_frame";
136  if(!nh.getParam("/laserscan_virtualizer/cloud_topic", cloud_topic)) cloud_topic = "/cloud_pcd";
137  nh.getParam("/laserscan_virtualizer/output_laser_topic", output_laser_topic);
138  nh.getParam("/laserscan_virtualizer/virtual_laser_scan", virtual_laser_scan);
139 
140  this->virtual_laser_scan_parser();
141 
142  point_cloud_subscriber_ = node_.subscribe<sensor_msgs::PointCloud2> (cloud_topic.c_str(), 1, boost::bind(&LaserscanVirtualizer::pointCloudCallback,this, _1));
143  cloud_frame = "";
144 }
145 
146 void LaserscanVirtualizer::pointCloudCallback(const sensor_msgs::PointCloud2::ConstPtr& pcl_in)
147 {
148  if(cloud_frame.empty())
149  {
150  cloud_frame = (*pcl_in).header.frame_id;
151  transform_.resize(output_frames.size());
152  for(int i=0; i<output_frames.size(); ++i)
153  if(tfListener_.waitForTransform (output_frames[i] , cloud_frame, ros::Time(0),ros::Duration(2.0)))
154  tfListener_.lookupTransform (output_frames[i] , cloud_frame, ros::Time(0), transform_[i]);
155  }
156 
157  for(int i=0; i<output_frames.size(); ++i)
158  {
159  myPointCloud pcl_out, tmpPcl;
160  pcl::PCLPointCloud2 tmpPcl2;
161 
162  pcl_conversions::toPCL(*pcl_in, tmpPcl2);
163  pcl::fromPCLPointCloud2(tmpPcl2,tmpPcl);
164 
165  // Initialize the header of the temporary pointcloud, needed to rototranslate the three points that define our plane
166  // It shall be equal to the input point cloud's one, changing only the 'frame_id'
167  string tmpFrame = output_frames[i] ;
168  pcl_out.header = tmpPcl.header;
169 
170  // Ask tf to rototranslate the velodyne pointcloud to base_frame reference
171  pcl_ros::transformPointCloud(tmpPcl, pcl_out, transform_[i]);
172  pcl_out.header.frame_id = tmpFrame;
173 
174  // Transform the pcl into eigen matrix
175  Eigen::MatrixXf tmpEigenMatrix;
176  pcl::toPCLPointCloud2(pcl_out, tmpPcl2);
177  pcl::getPointCloudAsEigen(tmpPcl2,tmpEigenMatrix);
178 
179  // Extract the points close to the z=0 plane, convert them into a laser-scan message and publish it
180  pointcloud_to_laserscan(tmpEigenMatrix, pcl_out.header, i);
181  }
182 }
183 
184 
185 void LaserscanVirtualizer::pointcloud_to_laserscan(Eigen::MatrixXf points, pcl::PCLHeader scan_header, int pub_index) //pcl::PCLPointCloud2 *merged_cloud)
186 {
187  sensor_msgs::LaserScanPtr output(new sensor_msgs::LaserScan());
188  output->header = pcl_conversions::fromPCL(scan_header);
189  output->angle_min = this->angle_min;
190  output->angle_max = this->angle_max;
191  output->angle_increment = this->angle_increment;
192  output->time_increment = this->time_increment;
193  output->scan_time = this->scan_time;
194  output->range_min = this->range_min;
195  output->range_max = this->range_max;
196 
197  uint32_t ranges_size = std::ceil((output->angle_max - output->angle_min) / output->angle_increment);
198  output->ranges.assign(ranges_size, output->range_max + 1.0);
199 
200  for(int i=0; i<points.cols(); i++)
201  {
202  const float &x = points(0,i);
203  const float &y = points(1,i);
204  const float &z = points(2,i);
205 
206  if ( std::isnan(x) || std::isnan(y) || std::isnan(z) )
207  {
208  ROS_DEBUG("rejected for nan in point(%f, %f, %f)\n", x, y, z);
209  continue;
210  }
211 
212  if ( std::abs(z) > 0.01 )
213  continue;
214 
215  pcl::PointXYZ p;
216  p.x=x;
217  p.y=y;
218  p.z=z;
219 
220  double range_sq = y*y+x*x;
221  double range_min_sq_ = output->range_min * output->range_min;
222  if (range_sq < range_min_sq_) {
223  ROS_DEBUG("rejected for range %f below minimum value %f. Point: (%f, %f, %f)", range_sq, range_min_sq_, x, y, z);
224  continue;
225  }
226 
227  double angle = atan2(y, x);
228  if (angle < output->angle_min || angle > output->angle_max)
229  {
230  ROS_DEBUG("rejected for angle %f not in range (%f, %f)\n", angle, output->angle_min, output->angle_max);
231  continue;
232  }
233  int index = (angle - output->angle_min) / output->angle_increment;
234 
235 
236  if (output->ranges[index] * output->ranges[index] > range_sq)
237  output->ranges[index] = sqrt(range_sq);
238  }
239 
240  virtual_scan_publishers[pub_index].publish(output);
241 }
242 
243 int main(int argc, char** argv)
244 {
245  ros::init(argc, argv, "laserscan_virtualizer");
246 
247  LaserscanVirtualizer _laser_merger;
248 
249  dynamic_reconfigure::Server<laserscan_virtualizerConfig> server;
250  dynamic_reconfigure::Server<laserscan_virtualizerConfig>::CallbackType f;
251 
252  f = boost::bind(&LaserscanVirtualizer::reconfigureCallback,&_laser_merger, _1, _2);
253  server.setCallback(f);
254 
255  ros::spin();
256 
257  return 0;
258 }
vector< string > output_frames
f
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
void pointCloudCallback(const sensor_msgs::PointCloud2::ConstPtr &pcl_in)
tf::TransformListener tfListener_
void pointcloud_to_laserscan(Eigen::MatrixXf points, pcl::PCLHeader scan_header, int pub_index)
TFSIMD_FORCE_INLINE const tfScalar & y() const
TFSIMD_FORCE_INLINE tfScalar angle(const Quaternion &q1, const Quaternion &q2)
ROSCPP_DECL void spin(Spinner &spinner)
void fromPCL(const pcl::uint64_t &pcl_stamp, ros::Time &stamp)
#define ROS_INFO(...)
vector< tf::StampedTransform > transform_
TFSIMD_FORCE_INLINE const tfScalar & x() const
TFSIMD_FORCE_INLINE const tfScalar & z() const
void transformPointCloud(const pcl::PointCloud< PointT > &cloud_in, pcl::PointCloud< PointT > &cloud_out, const tf::Transform &transform)
bool getParam(const std::string &key, std::string &s) const
static Time now()
void reconfigureCallback(laserscan_virtualizerConfig &config, uint32_t level)
int main(int argc, char **argv)
ros::Subscriber point_cloud_subscriber_
pcl::PointCloud< pcl::PointXYZ > myPointCloud
vector< ros::Publisher > virtual_scan_publishers
void toPCL(const ros::Time &stamp, pcl::uint64_t &pcl_stamp)
#define ROS_DEBUG(...)


ira_laser_tools
Author(s):
autogenerated on Wed Jun 5 2019 21:41:53