measurement_buffer.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  *
3  * Software License Agreement
4  *
5  * Copyright (c) 2018, Simbe Robotics, Inc.
6  * All rights reserved.
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 Simbe Robotics, Inc. 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  *
35  * Author: Steve Macenski (steven.macenski@simberobotics.com)
36  *********************************************************************/
37 
39 
40 namespace buffer
41 {
42 
43 /*****************************************************************************/
44 MeasurementBuffer::MeasurementBuffer(const std::string& topic_name, \
45  const double& observation_keep_time, \
46  const double& expected_update_rate, \
47  const double& min_obstacle_height, \
48  const double& max_obstacle_height, \
49  const double& obstacle_range, \
51  const std::string& global_frame, \
52  const std::string& sensor_frame, \
53  const double& tf_tolerance, \
54  const double& min_d, \
55  const double& max_d, \
56  const double& vFOV, \
57  const double& vFOVPadding, \
58  const double& hFOV, \
59  const double& decay_acceleration, \
60  const bool& marking, \
61  const bool& clearing, \
62  const double& voxel_size, \
63  const bool& voxel_filter, \
64  const bool& enabled, \
65  const bool& clear_buffer_after_reading, \
66  const ModelType& model_type) :
67 /*****************************************************************************/
68  _tf(tf), _observation_keep_time(observation_keep_time),
69  _expected_update_rate(expected_update_rate),_last_updated(ros::Time::now()),
70  _global_frame(global_frame), _sensor_frame(sensor_frame),
71  _topic_name(topic_name), _min_obstacle_height(min_obstacle_height),
72  _max_obstacle_height(max_obstacle_height), _obstacle_range(obstacle_range),
73  _tf_tolerance(tf_tolerance), _min_z(min_d), _max_z(max_d),
74  _vertical_fov(vFOV), _vertical_fov_padding(vFOVPadding),
75  _horizontal_fov(hFOV), _decay_acceleration(decay_acceleration),
76  _marking(marking), _clearing(clearing), _voxel_size(voxel_size),
77  _voxel_filter(voxel_filter), _enabled(enabled),
78  _clear_buffer_after_reading(clear_buffer_after_reading),
79  _model_type(model_type)
80 {
81 }
82 
83 /*****************************************************************************/
85 /*****************************************************************************/
86 {
87 }
88 
89 /*****************************************************************************/
90 void MeasurementBuffer::BufferROSCloud(const sensor_msgs::PointCloud2& cloud)
91 /*****************************************************************************/
92 {
93  try
94  {
95  pcl::PCLPointCloud2 pcl_pc2;
96  pcl_conversions::toPCL(cloud, pcl_pc2);
97  pcl::PointCloud < pcl::PointXYZ > pcl_cloud;
98  pcl::fromPCLPointCloud2(pcl_pc2, pcl_cloud);
99  BufferPCLCloud(pcl_cloud);
100  }
101  catch (pcl::PCLException& ex)
102  {
103  ROS_ERROR("Failed to convert to pcl type, dropping observation: %s", \
104  ex.what());
105  return;
106  }
107 }
108 
109 /*****************************************************************************/
111  pcl::PointCloud<pcl::PointXYZ>& cloud)
112 /*****************************************************************************/
113 {
114  // add a new measurement to be populated
116 
117  const std::string origin_frame = \
118  _sensor_frame == "" ? cloud.header.frame_id : _sensor_frame;
119 
120  try
121  {
122  // transform into global frame
123  geometry_msgs::Quaternion orientation;
124  tf::Stamped<tf::Pose> local_pose, global_pose;
125  local_pose.setOrigin(tf::Vector3(0, 0, 0));
126  local_pose.setRotation(tf::Quaternion(0, 0, 0, 1));
127  local_pose.stamp_ = pcl_conversions::fromPCL(cloud.header).stamp;
128  local_pose.frame_id_ = origin_frame;
129 
131  local_pose.stamp_, ros::Duration(0.5));
132  _tf.transformPose(_global_frame, local_pose, global_pose);
133 
134  _observation_list.front()._origin.x = global_pose.getOrigin().getX();
135  _observation_list.front()._origin.y = global_pose.getOrigin().getY();
136  _observation_list.front()._origin.z = global_pose.getOrigin().getZ();
137 
138  tf::quaternionTFToMsg(global_pose.getRotation(), orientation);
139  _observation_list.front()._orientation = orientation;
140  _observation_list.front()._obstacle_range_in_m = _obstacle_range;
141  _observation_list.front()._min_z_in_m = _min_z;
142  _observation_list.front()._max_z_in_m = _max_z;
143  _observation_list.front()._vertical_fov_in_rad = _vertical_fov;
144  _observation_list.front()._vertical_fov_padding_in_m = _vertical_fov_padding;
145  _observation_list.front()._horizontal_fov_in_rad = _horizontal_fov;
146  _observation_list.front()._decay_acceleration = _decay_acceleration;
147  _observation_list.front()._clearing = _clearing;
148  _observation_list.front()._marking = _marking;
149  _observation_list.front()._model_type = _model_type;
150 
151  if (_clearing && !_marking)
152  {
153  // no need to buffer points
154  return;
155  }
156 
157  point_cloud_ptr cld_global(new pcl::PointCloud<pcl::PointXYZ>);
158 
159  pcl_ros::transformPointCloud(_global_frame, cloud, *cld_global, _tf);
160  cld_global->header.stamp = cloud.header.stamp;
161 
162  // if user wants to use a voxel filter
163  if ( _voxel_filter )
164  {
165  // remove nans because they show things down
166  point_cloud_ptr cld_no_nan(new pcl::PointCloud<pcl::PointXYZ>);
167  std::vector<int> indices;
168  pcl::removeNaNFromPointCloud(*cld_global, *cld_no_nan, indices);
169 
170  // minimize information needed to process
171  cld_global->clear();
172  pcl::ApproximateVoxelGrid<pcl::PointXYZ> sor1;
173  sor1.setInputCloud (cld_no_nan);
174  sor1.setLeafSize ((float)_voxel_size,
175  (float)_voxel_size,
176  (float)_voxel_size);
177  sor1.filter (*cld_global);
178  }
179 
180  // remove points that are below or above our height restrictions
181  pcl::PointCloud<pcl::PointXYZ>& obs_cloud = \
182  *(_observation_list.front()._cloud);
183  unsigned int cloud_size = cld_global->points.size();
184 
185  obs_cloud.points.resize(cloud_size);
186  unsigned int point_count = 0;
187  pcl::PointCloud<pcl::PointXYZ>::iterator it;
188  for (it = cld_global->begin(); it != cld_global->end(); ++it)
189  {
190  if (it->z <= _max_obstacle_height && it->z >= _min_obstacle_height)
191  {
192  obs_cloud.points.at(point_count++) = *it;
193  }
194  }
195 
196  // resize the cloud for the number of legal points
197  obs_cloud.points.resize(point_count);
198  obs_cloud.header.stamp = cloud.header.stamp;
199  obs_cloud.header.frame_id = cld_global->header.frame_id;
200  }
201  catch (tf::TransformException& ex)
202  {
203  // if fails, remove the empty observation
204  _observation_list.pop_front();
205  ROS_ERROR( \
206  "TF Exception for sensor frame: %s, cloud frame: %s, %s", \
207  _sensor_frame.c_str(), cloud.header.frame_id.c_str(), ex.what());
208  return;
209  }
210 
213 }
214 
215 /*****************************************************************************/
217  std::vector<observation::MeasurementReading>& observations)
218 /*****************************************************************************/
219 {
221 
222  for (readings_iter it = _observation_list.begin(); \
223  it != _observation_list.end(); ++it)
224  {
225  observations.push_back(*it);
226  }
227 }
228 
229 /*****************************************************************************/
231 /*****************************************************************************/
232 {
233  if (_observation_list.empty())
234  {
235  return;
236  }
237 
238  readings_iter it = _observation_list.begin();
240  {
241  _observation_list.erase(++it, _observation_list.end());
242  return;
243  }
244 
245  for (it = _observation_list.begin(); it != _observation_list.end(); ++it)
246  {
248  const ros::Duration time_diff = \
249  _last_updated - pcl_conversions::fromPCL(obs._cloud->header).stamp;
250 
251  if (time_diff > _observation_keep_time)
252  {
253  _observation_list.erase(it, _observation_list.end());
254  return;
255  }
256  }
257 }
258 
259 /*****************************************************************************/
261 /*****************************************************************************/
262 {
263  _observation_list.clear();
264 }
265 
266 /*****************************************************************************/
268 /*****************************************************************************/
269 {
271 }
272 
273 /*****************************************************************************/
275 /*****************************************************************************/
276 {
278  {
279  return true;
280  }
281 
282  const ros::Duration update_time = ros::Time::now() - _last_updated;
283  const bool current = update_time.toSec() <= _expected_update_rate.toSec();
284  if (!current)
285  {
286  ROS_WARN_THROTTLE(10.,
287  "%s buffer updated in %.2fs, it should be updated every %.2fs.",
288  _topic_name.c_str(), update_time.toSec(), _expected_update_rate.toSec());
289  }
290  return current;
291 }
292 
293 /*****************************************************************************/
295 /*****************************************************************************/
296 {
297  return _enabled;
298 }
299 
300 /*****************************************************************************/
301 void MeasurementBuffer::SetEnabled(const bool& enabled)
302 /*****************************************************************************/
303 {
304  _enabled = enabled;
305 }
306 
307 /*****************************************************************************/
309 /*****************************************************************************/
310 {
312 }
313 
314 /*****************************************************************************/
316 /*****************************************************************************/
317 {
318  _lock.lock();
319 }
320 
321 /*****************************************************************************/
323 /*****************************************************************************/
324 {
325  _lock.unlock();
326 }
327 
328 } // namespace buffer
329 
void GetReadings(std::vector< observation::MeasurementReading > &observations)
pcl::PointCloud< pcl::PointXYZ >::Ptr _cloud
#define ROS_WARN_THROTTLE(rate,...)
void BufferPCLCloud(const pcl::PointCloud< pcl::PointXYZ > &cloud)
pcl::PointCloud< pcl::PointXYZ >::Ptr point_cloud_ptr
bool UpdatedAtExpectedRate(void) const
void SetEnabled(const bool &enabled)
const ros::Duration _observation_keep_time
std::list< observation::MeasurementReading > _observation_list
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
void fromPCL(const pcl::uint64_t &pcl_stamp, ros::Time &stamp)
static void quaternionTFToMsg(const Quaternion &bt, geometry_msgs::Quaternion &msg)
boost::recursive_mutex _lock
tf::TransformListener & _tf
ros::Time stamp_
std::string frame_id_
void transformPose(const std::string &target_frame, const geometry_msgs::PoseStamped &stamped_in, geometry_msgs::PoseStamped &stamped_out) const
void transformPointCloud(const pcl::PointCloud< PointT > &cloud_in, pcl::PointCloud< PointT > &cloud_out, const tf::Transform &transform)
const ros::Duration _expected_update_rate
static Time now()
void BufferROSCloud(const sensor_msgs::PointCloud2 &cloud)
#define ROS_ERROR(...)
MeasurementBuffer(const std::string &topic_name, const double &observation_keep_time, const double &expected_update_rate, const double &min_obstacle_height, const double &max_obstacle_height, const double &obstacle_range, tf::TransformListener &tf, const std::string &global_frame, const std::string &sensor_frame, const double &tf_tolerance, const double &min_d, const double &max_d, const double &vFOV, const double &vFOVPadding, const double &hFOV, const double &decay_acceleration, const bool &marking, const bool &clearing, const double &voxel_size, const bool &voxel_filter, const bool &enabled, const bool &clear_buffer_after_reading, const ModelType &model_type)
std::list< observation::MeasurementReading >::iterator readings_iter
void toPCL(const ros::Time &stamp, pcl::uint64_t &pcl_stamp)


spatio_temporal_voxel_layer
Author(s):
autogenerated on Sat Dec 21 2019 04:06:19