spatio_temporal_voxel_grid.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 volume_grid
41 {
42 
43 /*****************************************************************************/
45  const double& background_value, \
46  const GlobalDecayModel& decay_model, \
47  const double& voxel_decay, const bool& pub_voxels) :
48  _background_value(background_value), \
49  _voxel_size(voxel_size), \
50  _decay_model(decay_model), \
51  _voxel_decay(voxel_decay), \
52  _pub_voxels(pub_voxels), \
53  _pc(new pcl::PointCloud<pcl::PointXYZ>), \
54  _cost_map(new std::unordered_map<occupany_cell, uint>)
55 /*****************************************************************************/
56 {
57  this->InitializeGrid();
58 }
59 
60 /*****************************************************************************/
62 /*****************************************************************************/
63 {
64  // pcl pointclouds free themselves
65  if (_cost_map)
66  {
67  delete _cost_map;
68  }
69 }
70 
71 /*****************************************************************************/
73 /*****************************************************************************/
74 {
75  // initialize the OpenVDB Grid volume
76  openvdb::initialize();
77 
78  // make it default to background value
79  _grid = openvdb::DoubleGrid::create( _background_value );
80 
81  // setup scale and tranform
82  openvdb::Mat4d m = openvdb::Mat4d::identity();
83  m.preScale(openvdb::Vec3d(_voxel_size, _voxel_size, _voxel_size));
84  m.preTranslate(openvdb::Vec3d(0, 0, 0));
85  m.preRotate(openvdb::math::Z_AXIS, 0);
86 
87  // setup transform and other metadata
88  _grid->setTransform(openvdb::math::Transform::createLinearTransform( m ));
89  _grid->setName("SpatioTemporalVoxelLayer");
90  _grid->insertMeta("Voxel Size", openvdb::FloatMetadata( _voxel_size ));
91  _grid->setGridClass(openvdb::GRID_LEVEL_SET);
92  return;
93 }
94 
95 /*****************************************************************************/
97  std::vector<observation::MeasurementReading>& clearing_readings)
98 /*****************************************************************************/
99 {
100  boost::unique_lock<boost::mutex> lock(_grid_lock);
101 
102  // accelerate the decay of voxels interior to the frustum
103  if(this->IsGridEmpty())
104  {
105  return;
106  }
107 
108  _pc->clear();
109  _cost_map->clear();
110 
111  std::vector<frustum_model> obs_frustums;
112 
113  if(clearing_readings.size() == 0)
114  {
115  TemporalClearAndGenerateCostmap(obs_frustums);
116  return;
117  }
118 
119  obs_frustums.reserve(clearing_readings.size());
120 
121  std::vector<observation::MeasurementReading>::const_iterator it = \
122  clearing_readings.begin();
123  for (it; it != clearing_readings.end(); ++it)
124  {
125  geometry::Frustum* frustum;
126  if (it->_model_type == DEPTH_CAMERA)
127  {
128  frustum = new geometry::DepthCameraFrustum(it->_vertical_fov_in_rad,
129  it->_horizontal_fov_in_rad,
130  it->_min_z_in_m,
131  it->_max_z_in_m);
132  }
133  else if (it->_model_type == THREE_DIMENSIONAL_LIDAR)
134  {
136  it->_vertical_fov_in_rad,
137  it->_vertical_fov_padding_in_m,
138  it->_horizontal_fov_in_rad,
139  it->_min_z_in_m,
140  it->_max_z_in_m);
141  }
142  else
143  {
144  // add else if statement for each implemented model
145  delete frustum;
146  continue;
147  }
148 
149  frustum->SetPosition(it->_origin);
150  frustum->SetOrientation(it->_orientation);
151  frustum->TransformModel();
152  obs_frustums.emplace_back(frustum, it->_decay_acceleration);
153  }
154  TemporalClearAndGenerateCostmap(obs_frustums);
155  return;
156 }
157 
158 /*****************************************************************************/
160  std::vector<frustum_model>& frustums)
161 /*****************************************************************************/
162 {
163  // sample time once for all clearing readings
164  const double cur_time = ros::WallTime::now().toSec();
165 
166  // check each point in the grid for inclusion in a frustum
167  openvdb::DoubleGrid::ValueOnCIter cit_grid = _grid->cbeginValueOn();
168  for (cit_grid; cit_grid.test(); ++cit_grid)
169  {
170  const openvdb::Coord pt_index(cit_grid.getCoord());
171 
172  std::vector<frustum_model>::iterator frustum_it = frustums.begin();
173  bool frustum_cycle = false;
174 
175  const double time_since_marking = cur_time - cit_grid.getValue();
176  const double base_duration_to_decay = GetTemporalClearingDuration( \
177  time_since_marking);
178 
179  for(frustum_it; frustum_it != frustums.end(); ++frustum_it)
180  {
181  if (!frustum_it->frustum)
182  {
183  continue;
184  }
185 
186  if ( frustum_it->frustum->IsInside(this->IndexToWorld(pt_index)) )
187  {
188  frustum_cycle = true;
189 
190  const double frustum_acceleration = GetFrustumAcceleration( \
191  time_since_marking, frustum_it->accel_factor);
192 
193  const double time_until_decay = base_duration_to_decay - \
194  frustum_acceleration;
195  if (time_until_decay < 0.)
196  {
197  // expired by acceleration
198  if(!this->ClearGridPoint(pt_index))
199  {
200  std::cout << "Failed to clear point." << std::endl;
201  }
202  }
203  else
204  {
205  const double updated_mark = cit_grid.getValue() -
206  frustum_acceleration;
207  if(!this->MarkGridPoint(pt_index, updated_mark))
208  {
209  std::cout << "Failed to update mark." << std::endl;
210  }
211  break;
212  }
213  }
214  }
215 
216  // if not inside any, check against nominal decay model
217  if(!frustum_cycle)
218  {
219  if (base_duration_to_decay < 0.)
220  {
221  // expired by temporal clearing
222  if(!this->ClearGridPoint(pt_index))
223  {
224  std::cout << "Failed to clear point." << std::endl;
225  }
226  continue;
227  }
228  }
229  // if here, we can add to costmap and PC2
231  }
232 }
233 
234 /*****************************************************************************/
236  openvdb::Coord& pt)
237 /*****************************************************************************/
238 {
239  // add pt to the pointcloud and costmap
240  openvdb::Vec3d pose_world = _grid->indexToWorld(pt);
241 
242  if (_pub_voxels)
243  {
244  _pc->push_back(pcl::PointXYZ(pose_world[0], pose_world[1], \
245  pose_world[2]));
246  }
247 
248  std::unordered_map<occupany_cell, uint>::iterator cell;
249  cell = _cost_map->find(occupany_cell(pose_world[0], pose_world[1]));
250  if (cell != _cost_map->end())
251  {
252  cell->second += 1;
253  }
254  else
255  {
256  _cost_map->insert(std::make_pair( \
257  occupany_cell(pose_world[0], pose_world[1]), 1));
258  }
259 }
260 
261 /*****************************************************************************/
263  std::vector<observation::MeasurementReading>& marking_readings)
264 /*****************************************************************************/
265 {
266  boost::unique_lock<boost::mutex> lock(_grid_lock);
267 
268  // mark the grid
269  if (marking_readings.size() > 0)
270  {
271  //tbb::parallel_do(marking_readings, *this); /*must do via merged trees*/
272  for (int i=0; i!= marking_readings.size(); i++)
273  {
274  (*this)(marking_readings.at(i));
275  }
276  }
277  return;
278 }
279 
280 /*****************************************************************************/
283 /*****************************************************************************/
284 {
285  if (obs._marking)
286  {
287  float mark_range_2 = obs._obstacle_range_in_m * obs._obstacle_range_in_m;
288  const double cur_time = ros::WallTime::now().toSec();
289 
290  pcl::PointCloud<pcl::PointXYZ>::const_iterator it;
291  for (it = obs._cloud->points.begin(); it < obs._cloud->points.end(); ++it)
292  {
293  float distance_2 = (it->x - obs._origin.x) * (it->x - obs._origin.x) \
294  + (it->y - obs._origin.y) * (it->y - obs._origin.y) \
295  + (it->z - obs._origin.z) * (it->z - obs._origin.z);
296  if (distance_2 > mark_range_2 || distance_2 < 0.0001)
297  {
298  continue;
299  }
300  openvdb::Vec3d mark_grid(this->WorldToIndex( \
301  openvdb::Vec3d(it->x, it->y, it->z)));
302 
303  if(!this->MarkGridPoint(openvdb::Coord(mark_grid[0], mark_grid[1], \
304  mark_grid[2]), cur_time))
305  {
306  std::cout << "Failed to mark point." << std::endl;
307  }
308  }
309  }
310  return;
311 }
312 
313 /*****************************************************************************/
314 std::unordered_map<occupany_cell, uint>*
316 /*****************************************************************************/
317 {
318  return _cost_map;
319 }
320 
321 /*****************************************************************************/
323 /*****************************************************************************/
324 {
325  // use configurable model to get desired decay time
326  if (_decay_model == LINEAR)
327  {
328  return _voxel_decay - time_delta;
329  }
330  else if (_decay_model == EXPONENTIAL)
331  {
332  return _voxel_decay * std::exp(-time_delta);
333  }
334  return _voxel_decay; // PERSISTENT
335 }
336 
337 /*****************************************************************************/
339  const double& time_delta, \
340  const double& acceleration_factor)
341 /*****************************************************************************/
342 {
343  const double acceleration = 1. / 6. * acceleration_factor * \
344  (time_delta * time_delta * time_delta);
345  return acceleration;
346 }
347 
348 /*****************************************************************************/
350  pcl::PointCloud<pcl::PointXYZ>::Ptr& pc)
351 /*****************************************************************************/
352 {
353  // return the pointcloud stored
354  pc = _pc;
355  return;
356 }
357 
358 /*****************************************************************************/
360 /*****************************************************************************/
361 {
362  boost::unique_lock<boost::mutex> lock(_grid_lock);
363 
364  // clear the voxel grid
365  try
366  {
367  _grid->clear();
368  if (this->IsGridEmpty())
369  {
370  return true;
371  }
372  }
373  catch (...)
374  {
375  std::cout << "Failed to reset costmap, please try again." << std::endl;
376  }
377  return false;
378 }
379 
380 /*****************************************************************************/
381 bool SpatioTemporalVoxelGrid::MarkGridPoint(const openvdb::Coord& pt, \
382  const double& value) const
383 /*****************************************************************************/
384 {
385  // marking the OpenVDB set
386  openvdb::DoubleGrid::Accessor accessor = _grid->getAccessor();
387 
388  accessor.setValueOn(pt, value);
389  return accessor.getValue(pt) == value;
390 }
391 
392 /*****************************************************************************/
393 bool SpatioTemporalVoxelGrid::ClearGridPoint(const openvdb::Coord& pt) const
394 /*****************************************************************************/
395 {
396  // clearing the OpenVDB set
397  openvdb::DoubleGrid::Accessor accessor = _grid->getAccessor();
398 
399  if (accessor.isValueOn(pt))
400  {
401  accessor.setValueOff(pt, _background_value);
402  }
403  return !accessor.isValueOn(pt);
404 }
405 
406 /*****************************************************************************/
408  openvdb::Coord& coord) const
409 /*****************************************************************************/
410 {
411  // Applies tranform stored in getTransform.
412  return _grid->indexToWorld(coord);
413 }
414 
415 /*****************************************************************************/
417  openvdb::Vec3d& vec) const
418 /*****************************************************************************/
419 {
420  // Applies inverse tranform stored in getTransform.
421  return _grid->worldToIndex(vec);
422 }
423 
424 /*****************************************************************************/
426 /*****************************************************************************/
427 {
428  // Returns grid's population status
429  return _grid->empty();
430 }
431 
432 /*****************************************************************************/
433 bool SpatioTemporalVoxelGrid::SaveGrid(const std::string& file_name, \
434  double& map_size_bytes)
435 /*****************************************************************************/
436 {
437  try
438  {
439  openvdb::io::File file(file_name + ".vdb");
440  openvdb::GridPtrVec grids = { _grid };
441  file.write(grids);
442  file.close();
443  map_size_bytes = _grid->memUsage();
444  return true;
445  }
446  catch (...)
447  {
448  map_size_bytes = 0.;
449  return false;
450  }
451  return false; // best offense is a good defense
452 }
453 
454 }; // end namespace
openvdb::Vec3d IndexToWorld(const openvdb::Coord &coord) const
bool SaveGrid(const std::string &file_name, double &map_size_bytes)
void TemporalClearAndGenerateCostmap(std::vector< frustum_model > &frustums)
pcl::PointCloud< pcl::PointXYZ >::Ptr _pc
virtual void SetPosition(const geometry_msgs::Point &origin)=0
sensor_msgs::PointCloud2 PointCloud
std::unordered_map< occupany_cell, uint > * _cost_map
double GetTemporalClearingDuration(const double &time_delta)
virtual void TransformModel(void)=0
void ClearFrustums(const std::vector< observation::MeasurementReading > &clearing_observations)
double GetFrustumAcceleration(const double &time_delta, const double &acceleration_factor)
bool ClearGridPoint(const openvdb::Coord &pt) const
std::unordered_map< occupany_cell, uint > * GetFlattenedCostmap()
void Mark(const std::vector< observation::MeasurementReading > &marking_observations)
SpatioTemporalVoxelGrid(const float &voxel_size, const double &background_value, const GlobalDecayModel &decay_model, const double &voxel_decay, const bool &pub_voxels)
openvdb::Vec3d WorldToIndex(const openvdb::Vec3d &coord) const
static WallTime now()
void GetOccupancyPointCloud(pcl::PointCloud< pcl::PointXYZ >::Ptr &pc)
void PopulateCostmapAndPointcloud(const openvdb::Coord &pt)
void operator()(const observation::MeasurementReading &obs) const
virtual void SetOrientation(const geometry_msgs::Quaternion &quat)=0
bool MarkGridPoint(const openvdb::Coord &pt, const double &value) const


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