Grid3d.cpp
Go to the documentation of this file.
1 
18 #include "Grid3d.h"
19 
20 #include <pcl/kdtree/kdtree_flann.h>
22 
23 namespace amcl3d
24 {
25 Grid3d::Grid3d(const double sensor_dev) : sensor_dev_(sensor_dev)
26 {
27 }
28 
30 {
31 }
32 
33 bool Grid3d::open(const std::string& map_path)
34 {
36  if (!loadOctomap(map_path))
37  return false;
38 
41 
43  std::string grid_path;
44  if (map_path.compare(map_path.length() - 3, 3, ".bt") == 0)
45  grid_path = map_path.substr(0, map_path.find(".bt")) + ".grid";
46  if (map_path.compare(map_path.length() - 3, 3, ".ot") == 0)
47  grid_path = map_path.substr(0, map_path.find(".ot")) + ".grid";
48 
49  if (loadGrid(grid_path))
50  return true;
51 
53  computeGrid();
54 
56  saveGrid(grid_path);
57 
58  return true;
59 }
60 
61 bool Grid3d::buildGridSliceMsg(const float z, nav_msgs::OccupancyGrid& msg) const
62 {
63  if (!grid_)
64  return false;
65 
66  if (z < 0 || z > max_z_)
67  return false;
68 
69  msg.header.frame_id = "grid3d";
70  msg.info.map_load_time = ros::Time::now();
71  msg.info.resolution = resolution_;
72  msg.info.width = grid_size_x_;
73  msg.info.height = grid_size_y_;
74  msg.info.origin.position.x = 0.;
75  msg.info.origin.position.y = 0.;
76  msg.info.origin.position.z = static_cast<double>(z);
77  msg.info.origin.orientation.x = 0.;
78  msg.info.origin.orientation.y = 0.;
79  msg.info.origin.orientation.z = 0.;
80  msg.info.origin.orientation.w = 1.;
81  msg.data.resize(grid_size_x_ * grid_size_y_);
82 
84  const uint32_t offset = static_cast<uint32_t>(z * one_div_res_) * grid_size_x_ * grid_size_y_;
85  const uint32_t end = offset + grid_size_x_ * grid_size_y_;
86  float max_prob = -1.0;
87  for (uint32_t i = offset; i < end; ++i)
88  if (grid_[i].prob > max_prob)
89  max_prob = grid_[i].prob;
90 
92  if (max_prob < 0.000001f)
93  max_prob = 0.000001f;
94  max_prob = 100.f / max_prob;
95  for (uint32_t i = 0; i < grid_size_x_ * grid_size_y_; ++i)
96  msg.data[i] = static_cast<int8_t>(grid_[i + offset].prob * max_prob);
97 
98  return true;
99 }
100 
101 bool Grid3d::buildMapPointCloudMsg(sensor_msgs::PointCloud2& msg) const
102 {
103  if (!cloud_)
104  return false;
105 
106  pcl::toROSMsg(*cloud_, msg);
107 
108  msg.header.frame_id = "grid3d";
109 
110  return true;
111 }
112 
113 void Grid3d::buildGrid3d2WorldTf(const std::string& global_frame_id, tf::StampedTransform& tf) const
114 {
115  tf::Transform grid3d_2_world_tf;
116  grid3d_2_world_tf.setOrigin(tf::Vector3(min_oct_x_, min_oct_y_, min_oct_z_));
117  grid3d_2_world_tf.setRotation(tf::Quaternion(0, 0, 0, 1));
118 
119  tf = tf::StampedTransform(grid3d_2_world_tf, ros::Time::now(), global_frame_id, "grid3d");
120 }
121 
122 float Grid3d::computeCloudWeight(const std::vector<pcl::PointXYZ>& points, const float tx, const float ty,
123  const float tz, const float a) const
124 {
125  float weight = 0.;
126  int n = 0;
127 
128  pcl::PointXYZ new_point;
129 
130  const auto sa = sin(a);
131  const auto ca = cos(a);
132 
133  if (!grid_)
134  return 0;
135 
136  for (uint32_t i = 0; i < points.size(); ++i)
137  {
138  const auto& p = points[i];
139 
140  new_point.x = ca * p.x - sa * p.y + tx;
141  new_point.y = sa * p.x + ca * p.y + ty;
142  new_point.z = p.z + tz;
143 
144  if (new_point.x >= 0.f && new_point.y >= 0.f && new_point.z >= 0.f && new_point.x < max_x_ &&
145  new_point.y < max_y_ && new_point.z < max_z_)
146  {
147  weight += grid_[point2grid(new_point.x, new_point.y, new_point.z)].prob;
148  n += 1;
149  }
150  }
151  return (n <= 10) ? 0 : weight / n;
152 }
153 
154 bool Grid3d::isIntoMap(const float x, const float y, const float z) const
155 {
156  return (x >= 0.f && y >= 0.f && z >= 0.f && x <= max_x_ && y <= max_y_ && z <= max_z_);
157 }
158 
159 void Grid3d::getMinOctomap(float& x, float& y, float& z) const
160 {
161  x = min_oct_x_;
162  y = min_oct_y_;
163  z = min_oct_z_;
164 }
165 
166 bool Grid3d::loadOctomap(const std::string& map_path)
167 {
168  if (map_path.length() <= 3)
169  return false;
170 
171  if (map_path.compare(map_path.length() - 3, 3, ".bt") == 0)
172  {
173  octomap_.reset(new octomap::OcTree(0.1));
174  }
175  else if (map_path.compare(map_path.length() - 3, 3, ".ot") == 0)
176  {
177  octomap_.reset(dynamic_cast<octomap::OcTree*>(octomap::AbstractOcTree::read(map_path)));
178  }
179 
180  if (!octomap_)
181  {
182  ROS_ERROR("[%s] Error: NULL octomap!!", ros::this_node::getName().data());
183  return false;
184  }
185 
186  if (!octomap_->readBinary(map_path) || octomap_->size() <= 1)
187  return false;
188 
189  ROS_INFO("[%s] Octomap loaded", ros::this_node::getName().data());
190 
191  // Get map parameters
192  double min_x, min_y, min_z, max_x, max_y, max_z;
193  octomap_->getMetricMin(min_x, min_y, min_z);
194  octomap_->getMetricMax(max_x, max_y, max_z);
195  max_x_ = static_cast<float>(max_x - min_x);
196  max_y_ = static_cast<float>(max_y - min_y);
197  max_z_ = static_cast<float>(max_z - min_z);
198  min_oct_x_ = static_cast<float>(min_x);
199  min_oct_y_ = static_cast<float>(min_y);
200  min_oct_z_ = static_cast<float>(min_z);
201  resolution_ = static_cast<float>(octomap_->getResolution());
202  one_div_res_ = 1.0f / resolution_;
203 
204  ROS_INFO("[%s]"
205  "\n Map size:"
206  "\n X: %lf to %lf"
207  "\n Y: %lf to %lf"
208  "\n Z: %lf to %lf"
209  "\n Res: %lf",
210  ros::this_node::getName().data(), min_x, max_x, min_y, max_y, min_z, max_z, resolution_);
211 
212  return true;
213 }
214 
216 {
219  cloud_.reset(new pcl::PointCloud<pcl::PointXYZ>());
220  cloud_->width = static_cast<uint32_t>(octomap_->size());
221  cloud_->height = 1;
222  cloud_->points.resize(cloud_->width * cloud_->height);
223 
224  uint32_t i = 0;
225  for (octomap::OcTree::leaf_iterator it = octomap_->begin_leafs(); it != octomap_->end_leafs(); ++it)
226  {
227  if (it != nullptr && octomap_->isNodeOccupied(*it))
228  {
229  cloud_->points[i].x = static_cast<float>(it.getX()) - min_oct_x_;
230  cloud_->points[i].y = static_cast<float>(it.getY()) - min_oct_y_;
231  cloud_->points[i].z = static_cast<float>(it.getZ()) - min_oct_z_;
232  ++i;
233  }
234  }
235  cloud_->width = i;
236  cloud_->points.resize(i);
237 }
238 
239 bool Grid3d::saveGrid(const std::string& grid_path)
240 {
241  auto pf = fopen(grid_path.c_str(), "wb");
242  if (!pf)
243  {
244  ROS_ERROR("[%s] Error opening file %s for writing", ros::this_node::getName().data(), grid_path.c_str());
245  return false;
246  }
247 
249  fwrite(&grid_size_, sizeof(uint32_t), 1, pf);
250  fwrite(&grid_size_x_, sizeof(uint32_t), 1, pf);
251  fwrite(&grid_size_y_, sizeof(uint32_t), 1, pf);
252  fwrite(&grid_size_z_, sizeof(uint32_t), 1, pf);
253  fwrite(&sensor_dev_, sizeof(double), 1, pf);
254 
256  fwrite(grid_.get(), sizeof(GridCell), grid_size_, pf);
257 
258  fclose(pf);
259 
260  ROS_INFO("[%s] Grid map successfully saved on %s", ros::this_node::getName().data(), grid_path.c_str());
261 
262  return true;
263 }
264 
265 bool Grid3d::loadGrid(const std::string& grid_path)
266 {
267  auto pf = fopen(grid_path.c_str(), "rb");
268  if (!pf)
269  {
270  ROS_ERROR("[%s] Error opening file %s for reading", ros::this_node::getName().data(), grid_path.c_str());
271  return false;
272  }
273 
275  double sensor_dev;
276  fread(&grid_size_, sizeof(uint32_t), 1, pf);
277  fread(&grid_size_x_, sizeof(uint32_t), 1, pf);
278  fread(&grid_size_y_, sizeof(uint32_t), 1, pf);
279  fread(&grid_size_z_, sizeof(uint32_t), 1, pf);
280  fread(&sensor_dev, sizeof(double), 1, pf);
281 
282  if (std::fabs(sensor_dev - sensor_dev_) >= std::numeric_limits<double>::epsilon())
283  {
284  ROS_ERROR("[%s] Loaded sensorDev is different", ros::this_node::getName().data());
285  return false;
286  }
287 
290 
292  grid_.reset(new GridCell[grid_size_]);
293  fread(grid_.get(), sizeof(GridCell), grid_size_, pf);
294 
295  fclose(pf);
296 
297  ROS_INFO("[%s] Grid map successfully loaded from %s", ros::this_node::getName().data(), grid_path.c_str());
298 
299  return true;
300 }
301 
303 {
304  ROS_INFO("[%s] Computing 3D occupancy grid. This will take some time...", ros::this_node::getName().data());
305 
307  grid_size_x_ = static_cast<uint32_t>(max_x_ * one_div_res_);
308  grid_size_y_ = static_cast<uint32_t>(max_y_ * one_div_res_);
309  grid_size_z_ = static_cast<uint32_t>(max_z_ * one_div_res_);
313 
314  grid_.reset(new GridCell[grid_size_]);
315 
317  pcl::KdTreeFLANN<pcl::PointXYZ> kdtree;
318  kdtree.setInputCloud(cloud_);
319 
321  const float gauss_const1 = static_cast<float>(1. / (sensor_dev_ * sqrt(2 * M_PI)));
322  const float gauss_const2 = static_cast<float>(1. / (2. * sensor_dev_ * sensor_dev_));
323  uint32_t index;
324  float dist;
325  pcl::PointXYZ search_point;
326  std::vector<int> point_idx_nkn_search(1);
327  std::vector<float> point_nkn_squared_distance(1);
328  for (uint32_t iz = 0; iz < grid_size_z_; ++iz)
329  for (uint32_t iy = 0; iy < grid_size_y_; ++iy)
330  for (uint32_t ix = 0; ix < grid_size_x_; ++ix)
331  {
332  search_point.x = ix * resolution_;
333  search_point.y = iy * resolution_;
334  search_point.z = iz * resolution_;
335  index = ix + iy * grid_step_y_ + iz * grid_step_z_;
336 
337  if (kdtree.nearestKSearch(search_point, 1, point_idx_nkn_search, point_nkn_squared_distance) > 0)
338  {
339  dist = point_nkn_squared_distance[0];
340  grid_[index].dist = dist;
341  grid_[index].prob = gauss_const1 * expf(-dist * dist * gauss_const2);
342  }
343  else
344  {
345  grid_[index].dist = -1.0;
346  grid_[index].prob = 0.0;
347  }
348  }
349 
350  ROS_INFO("[%s] Computing 3D occupancy grid done!", ros::this_node::getName().data());
351 }
352 
353 inline uint32_t Grid3d::point2grid(const float x, const float y, const float z) const
354 {
355  return static_cast<uint32_t>(x * one_div_res_) + static_cast<uint32_t>(y * one_div_res_) * grid_step_y_ +
356  static_cast<uint32_t>(z * one_div_res_) * grid_step_z_;
357 }
358 
359 } // namespace amcl3d
bool isIntoMap(const float x, const float y, const float z) const
Definition: Grid3d.cpp:154
virtual ~Grid3d()
Definition: Grid3d.cpp:29
TFSIMD_FORCE_INLINE void setRotation(const Quaternion &q)
bool loadGrid(const std::string &grid_path)
Definition: Grid3d.cpp:265
uint32_t point2grid(const float x, const float y, const float z) const
Definition: Grid3d.cpp:353
f
static AbstractOcTree * read(const std::string &filename)
bool open(const std::string &map_path)
Definition: Grid3d.cpp:33
ROSCPP_DECL const std::string & getName()
std::unique_ptr< octomap::OcTree > octomap_
Octomap parameters.
Definition: Grid3d.h:60
std::unique_ptr< GridCell[]> grid_
Definition: Grid3d.h:76
#define M_PI
float max_x_
Definition: Grid3d.h:61
uint32_t grid_step_y_
Definition: Grid3d.h:78
void computeGrid()
Definition: Grid3d.cpp:302
bool buildGridSliceMsg(const float z, nav_msgs::OccupancyGrid &msg) const
Definition: Grid3d.cpp:61
bool loadOctomap(const std::string &map_path)
Definition: Grid3d.cpp:166
bool saveGrid(const std::string &grid_path)
Definition: Grid3d.cpp:239
float computeCloudWeight(const std::vector< pcl::PointXYZ > &points, const float tx, const float ty, const float tz, const float a) const
Definition: Grid3d.cpp:122
float min_oct_y_
Definition: Grid3d.h:62
uint32_t grid_size_
Definition: Grid3d.h:77
Include Grid.hpp.
Definition: Grid3d.cpp:23
uint32_t grid_size_y_
Definition: Grid3d.h:77
uint32_t grid_step_z_
Definition: Grid3d.h:78
3D probabilistic grid cell
Definition: Grid3d.h:69
#define ROS_INFO(...)
float min_oct_z_
Definition: Grid3d.h:62
float max_y_
Definition: Grid3d.h:61
bool buildMapPointCloudMsg(sensor_msgs::PointCloud2 &msg) const
Definition: Grid3d.cpp:101
uint32_t grid_size_x_
Definition: Grid3d.h:77
float one_div_res_
Definition: Grid3d.h:63
void buildGrid3d2WorldTf(const std::string &global_frame_id, tf::StampedTransform &tf) const
Definition: Grid3d.cpp:113
void computePointCloud()
Definition: Grid3d.cpp:215
uint32_t grid_size_z_
Definition: Grid3d.h:77
void getMinOctomap(float &x, float &y, float &z) const
Definition: Grid3d.cpp:159
void toROSMsg(const sensor_msgs::PointCloud2 &cloud, sensor_msgs::Image &image)
static Time now()
Grid3d(const double sensor_dev)
Definition: Grid3d.cpp:25
float max_z_
Definition: Grid3d.h:61
pcl::PointCloud< pcl::PointXYZ >::Ptr cloud_
3D point cloud representation of the map
Definition: Grid3d.h:66
#define ROS_ERROR(...)
double sensor_dev_
Init parameter.
Definition: Grid3d.h:57
TFSIMD_FORCE_INLINE void setOrigin(const Vector3 &origin)
float min_oct_x_
Definition: Grid3d.h:62
float resolution_
Definition: Grid3d.h:63


amcl3d
Author(s): Francisco J.Perez-Grau
autogenerated on Sun Sep 15 2019 04:08:05