datacontainerbase.h
Go to the documentation of this file.
1 #ifndef VELODYNE_POINTCLOUD_DATACONTAINERBASE_H
2 #define VELODYNE_POINTCLOUD_DATACONTAINERBASE_H
3 // Copyright (C) 2012, 2019 Austin Robot Technology, Jack O'Quin, Joshua Whitley, Sebastian Pütz
4 // All rights reserved.
5 //
6 // Software License Agreement (BSD License 2.0)
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions
10 // are met:
11 //
12 // * Redistributions of source code must retain the above copyright
13 // notice, this list of conditions and the following disclaimer.
14 // * Redistributions in binary form must reproduce the above
15 // copyright notice, this list of conditions and the following
16 // disclaimer in the documentation and/or other materials provided
17 // with the distribution.
18 // * Neither the name of {copyright_holder} nor the names of its
19 // contributors may be used to endorse or promote products derived
20 // from this software without specific prior written permission.
21 //
22 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 // POSSIBILITY OF SUCH DAMAGE.
34 
36 #include <geometry_msgs/TransformStamped.h>
37 #include <velodyne_msgs/VelodyneScan.h>
39 #include <Eigen/Dense>
40 #include <memory>
41 #include <string>
42 #include <algorithm>
43 #include <cstdarg>
44 
46 {
48 {
49 public:
50  DataContainerBase(const double max_range, const double min_range, const std::string& target_frame,
51  const std::string& fixed_frame, const unsigned int init_width, const unsigned int init_height,
52  const bool is_dense, const unsigned int scans_per_packet, int fields, ...)
53  : config_(max_range, min_range, target_frame, fixed_frame, init_width, init_height, is_dense, scans_per_packet)
54  {
55  va_list vl;
56  cloud.fields.clear();
57  cloud.fields.reserve(fields);
58  va_start(vl, fields);
59  int offset = 0;
60  for (int i = 0; i < fields; ++i)
61  {
62  // Create the corresponding PointField
63  std::string name(va_arg(vl, char*));
64  int count(va_arg(vl, int));
65  int datatype(va_arg(vl, int));
66  offset = addPointField(cloud, name, count, datatype, offset);
67  }
68  va_end(vl);
69  cloud.point_step = offset;
70  cloud.row_step = init_width * cloud.point_step;
71  }
72 
73  struct Config
74  {
75  double max_range;
76  double min_range;
77  std::string target_frame;
78  std::string fixed_frame;
79  unsigned int init_width;
80  unsigned int init_height;
81  bool is_dense;
82  unsigned int scans_per_packet;
83 
84  Config(double max_range, double min_range, std::string target_frame, std::string fixed_frame,
85  unsigned int init_width, unsigned int init_height, bool is_dense, unsigned int scans_per_packet)
94  {
95  ROS_INFO_STREAM("Initialized container with "
96  << "min_range: " << min_range << ", max_range: " << max_range
97  << ", target_frame: " << target_frame << ", fixed_frame: " << fixed_frame
98  << ", init_width: " << init_width << ", init_height: " << init_height
99  << ", is_dense: " << is_dense << ", scans_per_packet: " << scans_per_packet);
100  }
101  };
102 
103  virtual void setup(const velodyne_msgs::VelodyneScan::ConstPtr& scan_msg)
104  {
105  sensor_frame = scan_msg->header.frame_id;
107 
108  cloud.header.stamp = scan_msg->header.stamp;
109  cloud.data.resize(scan_msg->packets.size() * config_.scans_per_packet * cloud.point_step);
110  cloud.width = config_.init_width;
111  cloud.height = config_.init_height;
112  cloud.is_dense = static_cast<uint8_t>(config_.is_dense);
113  }
114 
115  virtual void addPoint(float x, float y, float z, const uint16_t ring, const uint16_t azimuth, const float distance,
116  const float intensity, const float time) = 0;
117  virtual void newLine() = 0;
118 
119  const sensor_msgs::PointCloud2& finishCloud()
120  {
121  cloud.data.resize(cloud.point_step * cloud.width * cloud.height);
122  cloud.row_step = cloud.point_step * cloud.width;
123 
124  if (!config_.target_frame.empty())
125  {
126  cloud.header.frame_id = config_.target_frame;
127  }
128  else if (!config_.fixed_frame.empty())
129  {
130  cloud.header.frame_id = config_.fixed_frame;
131  }
132  else
133  {
134  cloud.header.frame_id = sensor_frame;
135  }
136 
137  ROS_DEBUG_STREAM("Prepared cloud width" << cloud.height * cloud.width
138  << " Velodyne points, time: " << cloud.header.stamp);
139  return cloud;
140  }
141 
143  {
144  // check if sensor frame is already known, if not don't prepare tf buffer until setup was called
145  if (sensor_frame.empty())
146  {
147  return;
148  }
149 
150  // avoid doing transformation when sensor_frame equals target frame and no ego motion compensation is perfomed
152  {
153  // when the string is empty the points will not be transformed later on
154  config_.target_frame = "";
155  return;
156  }
157 
158  // only use somewhat resource intensive tf listener when transformations are necessary
159  if (!config_.fixed_frame.empty() || !config_.target_frame.empty())
160  {
161  if (!tf_buffer)
162  {
163  tf_buffer = std::make_shared<tf2_ros::Buffer>();
164  tf_listener = std::make_shared<tf2_ros::TransformListener>(*tf_buffer);
165  }
166  }
167  else
168  {
169  tf_listener.reset();
170  tf_buffer.reset();
171  }
172  }
173 
174  void configure(const double max_range, const double min_range, const std::string fixed_frame,
175  const std::string target_frame)
176  {
177  config_.max_range = max_range;
178  config_.min_range = min_range;
179  config_.fixed_frame = fixed_frame;
180  config_.target_frame = target_frame;
181 
183  }
184 
185  sensor_msgs::PointCloud2 cloud;
186 
187  inline bool calculateTransformMatrix(Eigen::Affine3f& matrix, const std::string& target_frame,
188  const std::string& source_frame, const ros::Time& time)
189  {
190  if (!tf_buffer)
191  {
192  ROS_ERROR("tf buffer was not initialized yet");
193  return false;
194  }
195 
196  geometry_msgs::TransformStamped msg;
197  try
198  {
199  msg = tf_buffer->lookupTransform(target_frame, source_frame, time, ros::Duration(0.2));
200  }
201  catch (tf2::LookupException& e)
202  {
203  ROS_ERROR("%s", e.what());
204  return false;
205  }
206  catch (tf2::ExtrapolationException& e)
207  {
208  ROS_ERROR("%s", e.what());
209  return false;
210  }
211 
212  const geometry_msgs::Quaternion& quaternion = msg.transform.rotation;
213  Eigen::Quaternionf rotation(quaternion.w, quaternion.x, quaternion.y, quaternion.z);
214 
215  const geometry_msgs::Vector3& origin = msg.transform.translation;
216  Eigen::Translation3f translation(origin.x, origin.y, origin.z);
217 
218  matrix = translation * rotation;
219  return true;
220  }
221 
222  inline bool computeTransformToTarget(const ros::Time &scan_time)
223  {
224  if (config_.target_frame.empty())
225  {
226  // no need to calculate transform -> success
227  return true;
228  }
229  std::string& source_frame = config_.fixed_frame.empty() ? sensor_frame : config_.fixed_frame;
230  return calculateTransformMatrix(tf_matrix_to_target, config_.target_frame, source_frame, scan_time);
231  }
232 
233  inline bool computeTransformToFixed(const ros::Time &packet_time)
234  {
235  if (config_.fixed_frame.empty())
236  {
237  // no need to calculate transform -> success
238  return true;
239  }
240  std::string &source_frame = sensor_frame;
241  return calculateTransformMatrix(tf_matrix_to_fixed, config_.fixed_frame, source_frame, packet_time);
242  }
243 
244  inline void transformPoint(float& x, float& y, float& z)
245  {
246  Eigen::Vector3f p = Eigen::Vector3f(x, y, z);
247  if (!config_.fixed_frame.empty())
248  {
249  p = tf_matrix_to_fixed * p;
250  }
251  if (!config_.target_frame.empty())
252  {
253  p = tf_matrix_to_target * p;
254  }
255  x = p.x();
256  y = p.y();
257  z = p.z();
258  }
259 
260  inline bool pointInRange(float range)
261  {
262  return (range >= config_.min_range && range <= config_.max_range);
263  }
264 
265 protected:
267  std::shared_ptr<tf2_ros::TransformListener> tf_listener;
268  std::shared_ptr<tf2_ros::Buffer> tf_buffer;
269  Eigen::Affine3f tf_matrix_to_fixed;
270  Eigen::Affine3f tf_matrix_to_target;
271  std::string sensor_frame;
272 };
273 } /* namespace velodyne_rawdata */
274 #endif // VELODYNE_POINTCLOUD_DATACONTAINERBASE_H
velodyne_rawdata::DataContainerBase::Config::fixed_frame
std::string fixed_frame
world fixed frame for ego motion compenstation
Definition: datacontainerbase.h:78
point_cloud2_iterator.h
msg
msg
velodyne_rawdata::DataContainerBase::Config::min_range
double min_range
minimum range to publish
Definition: datacontainerbase.h:76
velodyne_rawdata::DataContainerBase::computeTransformToFixed
bool computeTransformToFixed(const ros::Time &packet_time)
Definition: datacontainerbase.h:233
velodyne_rawdata::DataContainerBase::tf_buffer
std::shared_ptr< tf2_ros::Buffer > tf_buffer
Definition: datacontainerbase.h:268
velodyne_rawdata::DataContainerBase::Config::init_height
unsigned int init_height
Definition: datacontainerbase.h:80
velodyne_rawdata::DataContainerBase::transformPoint
void transformPoint(float &x, float &y, float &z)
Definition: datacontainerbase.h:244
velodyne_rawdata::DataContainerBase
Definition: datacontainerbase.h:47
velodyne_rawdata::DataContainerBase::manage_tf_buffer
void manage_tf_buffer()
Definition: datacontainerbase.h:142
velodyne_rawdata::DataContainerBase::Config::target_frame
std::string target_frame
output frame of final point cloud
Definition: datacontainerbase.h:77
velodyne_rawdata::DataContainerBase::finishCloud
const sensor_msgs::PointCloud2 & finishCloud()
Definition: datacontainerbase.h:119
ROS_DEBUG_STREAM
#define ROS_DEBUG_STREAM(args)
velodyne_rawdata::DataContainerBase::tf_matrix_to_target
Eigen::Affine3f tf_matrix_to_target
Definition: datacontainerbase.h:270
velodyne_rawdata::DataContainerBase::addPoint
virtual void addPoint(float x, float y, float z, const uint16_t ring, const uint16_t azimuth, const float distance, const float intensity, const float time)=0
velodyne_rawdata::DataContainerBase::cloud
sensor_msgs::PointCloud2 cloud
Definition: datacontainerbase.h:185
velodyne_rawdata::DataContainerBase::Config::is_dense
bool is_dense
Definition: datacontainerbase.h:81
velodyne_rawdata::DataContainerBase::sensor_frame
std::string sensor_frame
Definition: datacontainerbase.h:271
velodyne_rawdata::DataContainerBase::tf_matrix_to_fixed
Eigen::Affine3f tf_matrix_to_fixed
Definition: datacontainerbase.h:269
velodyne_rawdata::DataContainerBase::Config::max_range
double max_range
maximum range to publish
Definition: datacontainerbase.h:75
tf2::ExtrapolationException
velodyne_rawdata
Definition: datacontainerbase.h:45
velodyne_rawdata::DataContainerBase::Config
Definition: datacontainerbase.h:73
tf2::LookupException
ROS_INFO_STREAM
#define ROS_INFO_STREAM(args)
velodyne_rawdata::DataContainerBase::pointInRange
bool pointInRange(float range)
Definition: datacontainerbase.h:260
transform_listener.h
velodyne_rawdata::DataContainerBase::Config::init_width
unsigned int init_width
Definition: datacontainerbase.h:79
ros::Time
velodyne_rawdata::DataContainerBase::config_
Config config_
Definition: datacontainerbase.h:266
velodyne_rawdata::DataContainerBase::calculateTransformMatrix
bool calculateTransformMatrix(Eigen::Affine3f &matrix, const std::string &target_frame, const std::string &source_frame, const ros::Time &time)
Definition: datacontainerbase.h:187
velodyne_rawdata::DataContainerBase::Config::scans_per_packet
unsigned int scans_per_packet
Definition: datacontainerbase.h:82
ROS_ERROR
#define ROS_ERROR(...)
datatype
const char * datatype()
velodyne_rawdata::DataContainerBase::DataContainerBase
DataContainerBase(const double max_range, const double min_range, const std::string &target_frame, const std::string &fixed_frame, const unsigned int init_width, const unsigned int init_height, const bool is_dense, const unsigned int scans_per_packet, int fields,...)
Definition: datacontainerbase.h:50
velodyne_rawdata::DataContainerBase::tf_listener
std::shared_ptr< tf2_ros::TransformListener > tf_listener
Definition: datacontainerbase.h:267
velodyne_rawdata::DataContainerBase::configure
void configure(const double max_range, const double min_range, const std::string fixed_frame, const std::string target_frame)
Definition: datacontainerbase.h:174
velodyne_rawdata::DataContainerBase::computeTransformToTarget
bool computeTransformToTarget(const ros::Time &scan_time)
Definition: datacontainerbase.h:222
velodyne_rawdata::DataContainerBase::setup
virtual void setup(const velodyne_msgs::VelodyneScan::ConstPtr &scan_msg)
Definition: datacontainerbase.h:103
ros::Duration
velodyne_rawdata::DataContainerBase::Config::Config
Config(double max_range, double min_range, std::string target_frame, std::string fixed_frame, unsigned int init_width, unsigned int init_height, bool is_dense, unsigned int scans_per_packet)
Definition: datacontainerbase.h:84
velodyne_rawdata::DataContainerBase::newLine
virtual void newLine()=0


velodyne_pointcloud
Author(s): Jack O'Quin, Piyush Khandelwal, Jesse Vera, Sebastian Pütz
autogenerated on Tue May 2 2023 02:28:04