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))
136  base_frame = "/cart_frame";
137 
138  if (!nh.getParam("/laserscan_virtualizer/cloud_topic", cloud_topic))
139  cloud_topic = "/cloud_pcd";
140 
141  nh.getParam("/laserscan_virtualizer/output_laser_topic", output_laser_topic);
142  nh.getParam("/laserscan_virtualizer/virtual_laser_scan", virtual_laser_scan);
143 
144  this->virtual_laser_scan_parser();
145 
146  point_cloud_subscriber_ = node_.subscribe<sensor_msgs::PointCloud2>(cloud_topic.c_str(), 1, boost::bind(&LaserscanVirtualizer::pointCloudCallback, this, _1));
147  cloud_frame = "";
148 }
149 
150 void LaserscanVirtualizer::pointCloudCallback(const sensor_msgs::PointCloud2::ConstPtr &pcl_in)
151 {
152  if (cloud_frame.empty())
153  {
154  cloud_frame = (*pcl_in).header.frame_id;
155  transform_.resize(output_frames.size());
156  for (int i = 0; i < output_frames.size(); i++)
157  if (tfListener_.waitForTransform(output_frames[i], cloud_frame, ros::Time(0), ros::Duration(2.0)))
158  tfListener_.lookupTransform(output_frames[i], cloud_frame, ros::Time(0), transform_[i]);
159  }
160 
161  for (int i = 0; i < output_frames.size(); i++)
162  {
163  myPointCloud pcl_out, tmpPcl;
164  pcl::PCLPointCloud2 tmpPcl2;
165 
166  pcl_conversions::toPCL(*pcl_in, tmpPcl2);
167  pcl::fromPCLPointCloud2(tmpPcl2, tmpPcl);
168 
169  // Initialize the header of the temporary pointcloud, needed to rototranslate the three points that define our plane
170  // It shall be equal to the input point cloud's one, changing only the 'frame_id'
171  string tmpFrame = output_frames[i];
172  pcl_out.header = tmpPcl.header;
173 
174  // Ask tf to rototranslate the velodyne pointcloud to base_frame reference
175  pcl_ros::transformPointCloud(tmpPcl, pcl_out, transform_[i]);
176  pcl_out.header.frame_id = tmpFrame;
177 
178  // Transform the pcl into eigen matrix
179  Eigen::MatrixXf tmpEigenMatrix;
180  pcl::toPCLPointCloud2(pcl_out, tmpPcl2);
181  pcl::getPointCloudAsEigen(tmpPcl2, tmpEigenMatrix);
182 
183  // Extract the points close to the z=0 plane, convert them into a laser-scan message and publish it
184  pointcloud_to_laserscan(tmpEigenMatrix, pcl_out.header, i);
185  }
186 }
187 
188 void LaserscanVirtualizer::pointcloud_to_laserscan(Eigen::MatrixXf points, pcl::PCLHeader scan_header, int pub_index) //pcl::PCLPointCloud2 *merged_cloud)
189 {
190  sensor_msgs::LaserScanPtr output(new sensor_msgs::LaserScan());
191  output->header = pcl_conversions::fromPCL(scan_header);
192  output->angle_min = this->angle_min;
193  output->angle_max = this->angle_max;
194  output->angle_increment = this->angle_increment;
195  output->time_increment = this->time_increment;
196  output->scan_time = this->scan_time;
197  output->range_min = this->range_min;
198  output->range_max = this->range_max;
199 
200  uint32_t ranges_size = std::ceil((output->angle_max - output->angle_min) / output->angle_increment);
201  output->ranges.assign(ranges_size, output->range_max + 1.0);
202 
203  for (int i = 0; i < points.cols(); i++)
204  {
205  const float &x = points(0, i);
206  const float &y = points(1, i);
207  const float &z = points(2, i);
208 
209  if (std::isnan(x) || std::isnan(y) || std::isnan(z))
210  {
211  ROS_DEBUG("rejected for nan in point(%f, %f, %f)\n", x, y, z);
212  continue;
213  }
214 
215  pcl::PointXYZ p;
216  p.x = x;
217  p.y = y;
218  p.z = z;
219 
220  double range_sq = pow(y, 2) + pow(x, 2);
221  double range_min_sq_ = output->range_min * output->range_min;
222  if (range_sq < range_min_sq_)
223  {
224  ROS_DEBUG("rejected for range %f below minimum value %f. Point: (%f, %f, %f)", range_sq, range_min_sq_, x, y, z);
225  continue;
226  }
227 
228  double angle = atan2(y, x);
229  if (angle < output->angle_min || angle > output->angle_max)
230  {
231  ROS_DEBUG("rejected for angle %f not in range (%f, %f)\n", angle, output->angle_min, output->angle_max);
232  continue;
233  }
234  int index = (angle - output->angle_min) / output->angle_increment;
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 }
LaserscanVirtualizer::reconfigureCallback
void reconfigureCallback(laserscan_virtualizerConfig &config, uint32_t level)
Definition: laserscan_virtualizer.cpp:58
pcl
LaserscanVirtualizer::virtual_laser_scan
string virtual_laser_scan
Definition: laserscan_virtualizer.cpp:55
LaserscanVirtualizer::point_cloud_subscriber_
ros::Subscriber point_cloud_subscriber_
Definition: laserscan_virtualizer.cpp:37
LaserscanVirtualizer::cloud_topic
string cloud_topic
Definition: laserscan_virtualizer.cpp:53
LaserscanVirtualizer::angle_increment
double angle_increment
Definition: laserscan_virtualizer.cpp:45
angle
TFSIMD_FORCE_INLINE tfScalar angle(const Quaternion &q1, const Quaternion &q2)
LaserscanVirtualizer::cloud_frame
string cloud_frame
Definition: laserscan_virtualizer.cpp:51
ros::init
ROSCPP_DECL void init(const M_string &remappings, const std::string &name, uint32_t options=0)
LaserscanVirtualizer::virtual_scan_publishers
vector< ros::Publisher > virtual_scan_publishers
Definition: laserscan_virtualizer.cpp:38
LaserscanVirtualizer::output_laser_topic
string output_laser_topic
Definition: laserscan_virtualizer.cpp:54
ros::NodeHandle::getParam
bool getParam(const std::string &key, bool &b) const
ros.h
LaserscanVirtualizer::pointcloud_to_laserscan
void pointcloud_to_laserscan(Eigen::MatrixXf points, pcl::PCLHeader scan_header, int pub_index)
Definition: laserscan_virtualizer.cpp:188
pcl_conversions::toPCL
void toPCL(const pcl_msgs::ModelCoefficients &mc, pcl::ModelCoefficients &pcl_mc)
myPointCloud
pcl::PointCloud< pcl::PointXYZ > myPointCloud
Definition: laserscan_virtualizer.cpp:17
LaserscanVirtualizer
Definition: laserscan_virtualizer.cpp:23
LaserscanVirtualizer::transform_
vector< tf::StampedTransform > transform_
Definition: laserscan_virtualizer.cpp:35
LaserscanVirtualizer::pointCloudCallback
void pointCloudCallback(const sensor_msgs::PointCloud2::ConstPtr &pcl_in)
Definition: laserscan_virtualizer.cpp:150
transforms.h
point_cloud.h
f
f
laser_geometry.h
pcl_conversions::fromPCL
void fromPCL(const pcl::ModelCoefficients &pcl_mc, pcl_msgs::ModelCoefficients &mc)
shutdown
ROSCONSOLE_DECL void shutdown()
ROS_DEBUG
#define ROS_DEBUG(...)
LaserscanVirtualizer::angle_max
double angle_max
Definition: laserscan_virtualizer.cpp:44
LaserscanVirtualizer::node_
ros::NodeHandle node_
Definition: laserscan_virtualizer.cpp:33
LaserscanVirtualizer::angle_min
double angle_min
Definition: laserscan_virtualizer.cpp:43
LaserscanVirtualizer::time_increment
double time_increment
Definition: laserscan_virtualizer.cpp:46
LaserscanVirtualizer::tfListener_
tf::TransformListener tfListener_
Definition: laserscan_virtualizer.cpp:34
LaserscanVirtualizer::output_frames
vector< string > output_frames
Definition: laserscan_virtualizer.cpp:39
transform_listener.h
point_cloud_conversion.h
pcl_ros::transformPointCloud
void transformPointCloud(const Eigen::Matrix4f &transform, const sensor_msgs::PointCloud2 &in, sensor_msgs::PointCloud2 &out)
LaserscanVirtualizer::virtual_laser_scan_parser
void virtual_laser_scan_parser()
Definition: laserscan_virtualizer.cpp:69
ros::Time
LaserscanVirtualizer::range_max
double range_max
Definition: laserscan_virtualizer.cpp:49
std
LaserscanVirtualizer::base_frame
string base_frame
Definition: laserscan_virtualizer.cpp:52
tf::TransformListener
LaserscanVirtualizer::range_min
double range_min
Definition: laserscan_virtualizer.cpp:48
main
int main(int argc, char **argv)
Definition: laserscan_virtualizer.cpp:243
ros::spin
ROSCPP_DECL void spin()
ROS_INFO
#define ROS_INFO(...)
LaserscanVirtualizer::LaserscanVirtualizer
LaserscanVirtualizer()
Definition: laserscan_virtualizer.cpp:130
ros::Duration
LaserscanVirtualizer::scan_time
double scan_time
Definition: laserscan_virtualizer.cpp:47
ros::NodeHandle
ros::Subscriber
ros::Time::now
static Time now()


ira_laser_tools
Author(s):
autogenerated on Wed Mar 2 2022 00:28:44