gazebo_octomap_plugin.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2015 Fadri Furrer, ASL, ETH Zurich, Switzerland
3  * Copyright 2015 Michael Burri, ASL, ETH Zurich, Switzerland
4  * Copyright 2015 Mina Kamel, ASL, ETH Zurich, Switzerland
5  * Copyright 2015 Janosch Nikolic, ASL, ETH Zurich, Switzerland
6  * Copyright 2015 Markus Achtelik, ASL, ETH Zurich, Switzerland
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13 
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
22 
24 #include <gazebo/common/Time.hh>
25 #include <gazebo/common/CommonTypes.hh>
26 #include <gazebo/math/Vector3.hh>
27 
28 namespace gazebo {
29 
31  delete octomap_;
32  octomap_ = NULL;
33 }
34 
35 void OctomapFromGazeboWorld::Load(physics::WorldPtr _parent,
36  sdf::ElementPtr _sdf) {
37  if (kPrintOnPluginLoad) {
38  gzdbg << __FUNCTION__ << "() called." << std::endl;
39  }
40 
41  world_ = _parent;
42 
43  std::string service_name = "world/get_octomap";
44  std::string octomap_pub_topic = "world/octomap";
45  getSdfParam<std::string>(_sdf, "octomapPubTopic", octomap_pub_topic,
46  octomap_pub_topic);
47  getSdfParam<std::string>(_sdf, "octomapServiceName", service_name,
48  service_name);
49 
50  gzlog << "Advertising service: " << service_name << std::endl;
52  service_name, &OctomapFromGazeboWorld::ServiceCallback, this);
54  node_handle_.advertise<octomap_msgs::Octomap>(octomap_pub_topic, 1, true);
55 }
56 
58  rotors_comm::Octomap::Request& req, rotors_comm::Octomap::Response& res) {
59  gzlog << "Creating octomap with origin at (" << req.bounding_box_origin.x
60  << ", " << req.bounding_box_origin.y << ", "
61  << req.bounding_box_origin.z << "), and bounding box lengths ("
62  << req.bounding_box_lengths.x << ", " << req.bounding_box_lengths.y
63  << ", " << req.bounding_box_lengths.z
64  << "), and leaf size: " << req.leaf_size << ".\n";
65  CreateOctomap(req);
66  if (req.filename != "") {
67  if (octomap_) {
68  std::string path = req.filename;
69  octomap_->writeBinary(path);
70  gzlog << std::endl << "Octree saved as " << path << std::endl;
71  } else {
72  ROS_ERROR("The octree is NULL. Will not save that.");
73  }
74  }
75  common::Time now = world_->GetSimTime();
76  res.map.header.frame_id = "world";
77  res.map.header.stamp = ros::Time(now.sec, now.nsec);
78 
79  if (!octomap_msgs::binaryMapToMsg(*octomap_, res.map)) {
80  ROS_ERROR("Error serializing OctoMap");
81  }
82 
83  if (req.publish_octomap) {
84  gzlog << "Publishing Octomap." << std::endl;
85  octomap_publisher_.publish(res.map);
86  }
87 
88  common::SphericalCoordinatesPtr sphericalCoordinates = world_->GetSphericalCoordinates();
89  ignition::ignition::math::Vector3d origin_cartesian(0.0, 0.0, 0.0);
90  ignition::ignition::math::Vector3d origin_spherical = sphericalCoordinates->
91  SphericalFromLocal(origin_cartesian);
92 
93  res.origin_latitude = origin_spherical.X();
94  res.origin_longitude = origin_spherical.Y();
95  res.origin_altitude = origin_spherical.Z();
96  return true;
97 }
98 
100  const ignition::math::Vector3d & seed_point, const ignition::math::Vector3d & bounding_box_origin,
101  const ignition::math::Vector3d & bounding_box_lengths, const double leaf_size) {
102  octomap::OcTreeNode* seed =
103  octomap_->search(seed_point.x, seed_point.y, seed_point.z);
104  // do nothing if point occupied
105  if (seed != NULL && seed->getOccupancy()) return;
106 
107  std::stack<octoignition::math::Vector3d > to_check;
108  to_check.push(octoignition::math::Vector3d (seed_point.x, seed_point.y, seed_point.z));
109 
110  while (to_check.size() > 0) {
111  octoignition::math::Vector3d p = to_check.top();
112 
113  if ((p.x() > bounding_box_origin.x - bounding_box_lengths.x / 2) &&
114  (p.x() < bounding_box_origin.x + bounding_box_lengths.x / 2) &&
115  (p.y() > bounding_box_origin.y - bounding_box_lengths.y / 2) &&
116  (p.y() < bounding_box_origin.y + bounding_box_lengths.y / 2) &&
117  (p.z() > bounding_box_origin.z - bounding_box_lengths.z / 2) &&
118  (p.z() < bounding_box_origin.z + bounding_box_lengths.z / 2) &&
119  (!octomap_->search(p))) {
120  octomap_->setNodeValue(p, 0);
121  to_check.pop();
122  to_check.push(octoignition::math::Vector3d (p.x() + leaf_size, p.y(), p.z()));
123  to_check.push(octoignition::math::Vector3d (p.x() - leaf_size, p.y(), p.z()));
124  to_check.push(octoignition::math::Vector3d (p.x(), p.y() + leaf_size, p.z()));
125  to_check.push(octoignition::math::Vector3d (p.x(), p.y() - leaf_size, p.z()));
126  to_check.push(octoignition::math::Vector3d (p.x(), p.y(), p.z() + leaf_size));
127  to_check.push(octoignition::math::Vector3d (p.x(), p.y(), p.z() - leaf_size));
128 
129  } else {
130  to_check.pop();
131  }
132  }
133 }
134 
135 bool OctomapFromGazeboWorld::CheckIfInterest(const ignition::math::Vector3d & central_point,
136  gazebo::physics::RayShapePtr ray,
137  const double leaf_size) {
138  ignition::math::Vector3d start_point = central_point;
139  ignition::math::Vector3d end_point = central_point;
140 
141  double dist;
142  std::string entity_name;
143 
144  start_point.x += leaf_size / 2;
145  end_point.x -= leaf_size / 2;
146  ray->SetPoints(start_point, end_point);
147  ray->GetIntersection(dist, entity_name);
148 
149  if (dist <= leaf_size) return true;
150 
151  start_point = central_point;
152  end_point = central_point;
153  start_point.y += leaf_size / 2;
154  end_point.y -= leaf_size / 2;
155  ray->SetPoints(start_point, end_point);
156  ray->GetIntersection(dist, entity_name);
157 
158  if (dist <= leaf_size) return true;
159 
160  start_point = central_point;
161  end_point = central_point;
162  start_point.z += leaf_size / 2;
163  end_point.z -= leaf_size / 2;
164  ray->SetPoints(start_point, end_point);
165  ray->GetIntersection(dist, entity_name);
166 
167  if (dist <= leaf_size) return true;
168 
169  return false;
170 }
171 
173  const rotors_comm::Octomap::Request& msg) {
174  const double epsilon = 0.00001;
175  const int far_away = 100000;
176  ignition::math::Vector3d bounding_box_origin(msg.bounding_box_origin.x,
177  msg.bounding_box_origin.y,
178  msg.bounding_box_origin.z);
179  // epsilion prevents undefiened behaviour if a point is inserted exactly
180  // between two octomap cells
181  ignition::math::Vector3d bounding_box_lengths(msg.bounding_box_lengths.x + epsilon,
182  msg.bounding_box_lengths.y + epsilon,
183  msg.bounding_box_lengths.z + epsilon);
184  double leaf_size = msg.leaf_size;
185  octomap_ = new octomap::OcTree(leaf_size);
186  octomap_->clear();
187  octomap_->setProbHit(0.7);
188  octomap_->setProbMiss(0.4);
192 
193  gazebo::physics::PhysicsEnginePtr engine = world_->PhysicsEngine();
194  engine->InitForThread();
195  gazebo::physics::RayShapePtr ray =
196  boost::dynamic_pointer_cast<gazebo::physics::RayShape>(
197  engine->CreateShape("ray", gazebo::physics::CollisionPtr()));
198 
199  std::cout << "Rasterizing world and checking collisions" << std::endl;
200 
201  for (double x =
202  leaf_size / 2 + bounding_box_origin.x - bounding_box_lengths.x / 2;
203  x < bounding_box_origin.x + bounding_box_lengths.x / 2; x += leaf_size) {
204  int progress =
205  round(100 * (x + bounding_box_lengths.x / 2 - bounding_box_origin.x) /
206  bounding_box_lengths.x);
207  std::cout << "\rPlacing model edges into octomap... " << progress
208  << "% ";
209 
210  for (double y =
211  leaf_size / 2 + bounding_box_origin.y - bounding_box_lengths.y / 2;
212  y < bounding_box_origin.y + bounding_box_lengths.y / 2;
213  y += leaf_size) {
214  for (double z = leaf_size / 2 + bounding_box_origin.z -
215  bounding_box_lengths.z / 2;
216  z < bounding_box_origin.z + bounding_box_lengths.z / 2;
217  z += leaf_size) {
218  ignition::math::Vector3d point(x, y, z);
219  if (CheckIfInterest(point, ray, leaf_size)) {
220  octomap_->setNodeValue(x, y, z, 1);
221  }
222  }
223  }
224  }
225  octomap_->prune();
227 
228  // flood fill from top and bottom
229  std::cout << "\rFlood filling freespace... ";
230  FloodFill(ignition::math::Vector3d (bounding_box_origin.x + leaf_size / 2,
231  bounding_box_origin.y + leaf_size / 2,
232  bounding_box_origin.z + bounding_box_lengths.z / 2 -
233  leaf_size / 2),
234  bounding_box_origin, bounding_box_lengths, leaf_size);
235  FloodFill(ignition::math::Vector3d (bounding_box_origin.x + leaf_size / 2,
236  bounding_box_origin.y + leaf_size / 2,
237  bounding_box_origin.z - bounding_box_lengths.z / 2 +
238  leaf_size / 2),
239  bounding_box_origin, bounding_box_lengths, leaf_size);
240 
241  octomap_->prune();
243 
244  // set unknown to filled
245  for (double x =
246  leaf_size / 2 + bounding_box_origin.x - bounding_box_lengths.x / 2;
247  x < bounding_box_origin.x + bounding_box_lengths.x / 2; x += leaf_size) {
248  int progress =
249  round(100 * (x + bounding_box_lengths.x / 2 - bounding_box_origin.x) /
250  bounding_box_lengths.x);
251  std::cout << "\rFilling closed spaces... " << progress << "% ";
252 
253  for (double y =
254  leaf_size / 2 + bounding_box_origin.y - bounding_box_lengths.y / 2;
255  y < bounding_box_origin.y + bounding_box_lengths.y / 2;
256  y += leaf_size) {
257  for (double z = leaf_size / 2 + bounding_box_origin.z -
258  bounding_box_lengths.z / 2;
259  z < bounding_box_origin.z + bounding_box_lengths.z / 2;
260  z += leaf_size) {
261  octomap::OcTreeNode* seed = octomap_->search(x, y, z);
262  if (!seed) octomap_->setNodeValue(x, y, z, 1);
263  }
264  }
265  }
266 
267  octomap_->prune();
269 
270  std::cout << "\rOctomap generation completed " << std::endl;
271 }
272 
273 // Register this plugin with the simulator
275 
276 } // namespace gazebo
bool ServiceCallback(rotors_comm::Octomap::Request &req, rotors_comm::Octomap::Response &res)
void setClampingThresMax(double thresProb)
double getOccupancy() const
void FloodFill(const ignition::math::Vector3d &seed_point, const ignition::math::Vector3d &bounding_box_origin, const ignition::math::Vector3d &bounding_box_lengths, const double leaf_size)
GZ_REGISTER_WORLD_PLUGIN(GazeboRosInterfacePlugin)
void Load(physics::WorldPtr _parent, sdf::ElementPtr _sdf)
Load the plugin.
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
virtual OcTreeNode * setNodeValue(const OcTreeKey &key, float log_odds_value, bool lazy_eval=false)
static bool binaryMapToMsg(const OctomapT &octomap, Octomap &msg)
void publish(const boost::shared_ptr< M > &message) const
OcTreeNode * search(double x, double y, double z, unsigned int depth=0) const
void CreateOctomap(const rotors_comm::Octomap::Request &msg)
Creates octomap by floodfilling freespace.
bool writeBinary(const std::string &filename)
double epsilon
static const bool kPrintOnPluginLoad
Definition: common.h:41
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
void setOccupancyThres(double prob)
#define ROS_ERROR(...)
bool CheckIfInterest(const ignition::math::Vector3d &central_point, gazebo::physics::RayShapePtr ray, const double leaf_size)
void setClampingThresMin(double thresProb)
Octomap plugin for Gazebo.


rotors_gazebo_plugins
Author(s): Fadri Furrer, Michael Burri, Mina Kamel, Janosch Nikolic, Markus Achtelik
autogenerated on Mon Feb 28 2022 23:39:03