occupancy_map_monitor.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2011, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Willow Garage nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Ioan Sucan, Jon Binney */
36 
37 #include <ros/ros.h>
38 #include <moveit_msgs/SaveMap.h>
39 #include <moveit_msgs/LoadMap.h>
42 #include <XmlRpcException.h>
43 
44 namespace occupancy_map_monitor
45 {
46 static const std::string LOGNAME = "occupancy_map_monitor";
47 
48 OccupancyMapMonitor::OccupancyMapMonitor(double map_resolution)
49  : map_resolution_(map_resolution), debug_info_(false), mesh_handle_count_(0), nh_("~"), active_(false)
50 {
51  initialize();
52 }
53 
54 OccupancyMapMonitor::OccupancyMapMonitor(const std::shared_ptr<tf2_ros::Buffer>& tf_buffer,
55  const std::string& map_frame, double map_resolution)
56  : tf_buffer_(tf_buffer)
57  , map_frame_(map_frame)
58  , map_resolution_(map_resolution)
59  , debug_info_(false)
60  , mesh_handle_count_(0)
61  , nh_("~")
62 {
63  initialize();
64 }
65 
66 OccupancyMapMonitor::OccupancyMapMonitor(const std::shared_ptr<tf2_ros::Buffer>& tf_buffer, ros::NodeHandle& nh,
67  const std::string& map_frame, double map_resolution)
68  : tf_buffer_(tf_buffer)
69  , map_frame_(map_frame)
70  , map_resolution_(map_resolution)
71  , debug_info_(false)
72  , mesh_handle_count_(0)
73  , nh_(nh)
74 {
75  initialize();
76 }
77 
78 void OccupancyMapMonitor::initialize()
79 {
80  /* load params from param server */
81  if (map_resolution_ <= std::numeric_limits<double>::epsilon())
82  {
83  if (!nh_.getParam("octomap_resolution", map_resolution_))
84  {
85  map_resolution_ = 0.1;
86  ROS_WARN_NAMED(LOGNAME, "Resolution not specified for Octomap. Assuming resolution = %g instead", map_resolution_);
87  }
88  }
89  ROS_DEBUG_NAMED(LOGNAME, "Using resolution = %lf m for building octomap", map_resolution_);
90 
91  if (map_frame_.empty())
92  if (!nh_.getParam("octomap_frame", map_frame_))
93  if (tf_buffer_)
94  ROS_WARN_NAMED(LOGNAME, "No target frame specified for Octomap. "
95  "No transforms will be applied to received data.");
96 
97  if (!tf_buffer_ && !map_frame_.empty())
98  ROS_WARN_STREAM_NAMED(LOGNAME, "Target frame \"" << map_frame_
99  << "\" specified but no TF instance (buffer) specified. "
100  "No transforms will be applied to received data.");
101 
102  tree_ = std::make_shared<collision_detection::OccMapTree>(map_resolution_);
103  tree_const_ = tree_;
104 
105  XmlRpc::XmlRpcValue sensor_list;
106  if (nh_.getParam("sensors", sensor_list))
107  {
108  try
109  {
111  for (int32_t i = 0; i < sensor_list.size(); ++i)
112  {
113  if (sensor_list[i].getType() != XmlRpc::XmlRpcValue::TypeStruct)
114  {
115  ROS_ERROR_NAMED(LOGNAME, "Params for octomap updater %d not a struct; ignoring.", i);
116  continue;
117  }
118 
119  if (!sensor_list[i].hasMember("sensor_plugin"))
120  {
121  ROS_ERROR_NAMED(LOGNAME, "No sensor plugin specified for octomap updater %d; ignoring.", i);
122  continue;
123  }
124 
125  std::string sensor_plugin = std::string(sensor_list[i]["sensor_plugin"]);
126  if (sensor_plugin.empty() || sensor_plugin[0] == '~')
127  {
128  ROS_INFO_STREAM_NAMED(LOGNAME, "Skipping octomap updater plugin '" << sensor_plugin << "'");
129  continue;
130  }
131 
132  if (!updater_plugin_loader_)
133  {
134  try
135  {
136  updater_plugin_loader_ = std::make_unique<pluginlib::ClassLoader<OccupancyMapUpdater>>(
137  "moveit_ros_perception", "occupancy_map_monitor::OccupancyMapUpdater");
138  }
140  {
141  ROS_FATAL_STREAM_NAMED(LOGNAME, "Exception while creating octomap updater plugin loader " << ex.what());
142  }
143  }
144 
145  OccupancyMapUpdaterPtr up;
146  try
147  {
148  up = updater_plugin_loader_->createUniqueInstance(sensor_plugin);
149  up->setMonitor(this);
150  }
152  {
153  ROS_ERROR_STREAM_NAMED(LOGNAME, "Exception while loading octomap updater '"
154  << sensor_plugin << "': " << ex.what() << std::endl);
155  }
156  if (up)
157  {
158  /* pass the params struct directly in to the updater */
159  if (!up->setParams(sensor_list[i]))
160  {
161  ROS_ERROR_STREAM_NAMED(LOGNAME, "Failed to configure updater of type " << up->getType());
162  continue;
163  }
164 
165  if (!up->initialize())
166  {
167  ROS_ERROR_NAMED(LOGNAME, "Unable to initialize map updater of type %s (plugin %s)", up->getType().c_str(),
168  sensor_plugin.c_str());
169  continue;
170  }
171 
172  addUpdater(up);
173  }
174  }
175  else
176  ROS_ERROR_NAMED(LOGNAME, "List of sensors must be an array!");
177  }
178  catch (XmlRpc::XmlRpcException& ex)
179  {
180  ROS_ERROR_STREAM_NAMED(LOGNAME, "XmlRpc Exception: " << ex.getMessage());
181  }
182  }
183  else
184  ROS_INFO_NAMED(LOGNAME, "No 3D sensor plugin(s) defined for octomap updates");
185 
186  /* advertise a service for loading octomaps from disk */
187  save_map_srv_ = nh_.advertiseService("save_map", &OccupancyMapMonitor::saveMapCallback, this);
188  load_map_srv_ = nh_.advertiseService("load_map", &OccupancyMapMonitor::loadMapCallback, this);
189 }
190 
191 void OccupancyMapMonitor::addUpdater(const OccupancyMapUpdaterPtr& updater)
192 {
193  if (updater)
194  {
195  map_updaters_.push_back(updater);
196  updater->publishDebugInformation(debug_info_);
197  if (map_updaters_.size() > 1)
198  {
199  mesh_handles_.resize(map_updaters_.size());
200  // when we had one updater only, we passed the transform cache callback directly to that updater
201  if (map_updaters_.size() == 2)
202  {
203  map_updaters_[0]->setTransformCacheCallback(
204  [this](const std::string& frame, const ros::Time& stamp, ShapeTransformCache& cache) {
205  return getShapeTransformCache(0, frame, stamp, cache);
206  });
207  map_updaters_[1]->setTransformCacheCallback(
208  [this](const std::string& frame, const ros::Time& stamp, ShapeTransformCache& cache) {
209  return getShapeTransformCache(1, frame, stamp, cache);
210  });
211  }
212  else
213  map_updaters_.back()->setTransformCacheCallback(
214  [this, i = map_updaters_.size() - 1](const std::string& frame, const ros::Time& stamp,
215  ShapeTransformCache& cache) {
216  return getShapeTransformCache(i, frame, stamp, cache);
217  });
218  }
219  else
220  updater->setTransformCacheCallback(transform_cache_callback_);
221  }
222  else
223  ROS_ERROR_NAMED(LOGNAME, "NULL updater was specified");
224 }
225 
226 void OccupancyMapMonitor::publishDebugInformation(bool flag)
227 {
228  debug_info_ = flag;
229  for (OccupancyMapUpdaterPtr& map_updater : map_updaters_)
230  map_updater->publishDebugInformation(debug_info_);
231 }
232 
233 void OccupancyMapMonitor::setMapFrame(const std::string& frame)
234 {
235  boost::mutex::scoped_lock _(parameters_lock_); // we lock since an updater could specify a new frame for us
236  map_frame_ = frame;
237 }
238 
239 ShapeHandle OccupancyMapMonitor::excludeShape(const shapes::ShapeConstPtr& shape)
240 {
241  // if we have just one updater, remove the additional level of indirection
242  if (map_updaters_.size() == 1)
243  return map_updaters_[0]->excludeShape(shape);
244 
245  ShapeHandle h = 0;
246  for (std::size_t i = 0; i < map_updaters_.size(); ++i)
247  {
248  ShapeHandle mh = map_updaters_[i]->excludeShape(shape);
249  if (mh)
250  {
251  if (h == 0)
252  h = ++mesh_handle_count_;
253  mesh_handles_[i][h] = mh;
254  }
255  }
256  return h;
257 }
258 
259 void OccupancyMapMonitor::forgetShape(ShapeHandle handle)
260 {
261  // if we have just one updater, remove the additional level of indirection
262  if (map_updaters_.size() == 1)
263  {
264  map_updaters_[0]->forgetShape(handle);
265  return;
266  }
267 
268  for (std::size_t i = 0; i < map_updaters_.size(); ++i)
269  {
270  std::map<ShapeHandle, ShapeHandle>::const_iterator it = mesh_handles_[i].find(handle);
271  if (it == mesh_handles_[i].end())
272  continue;
273  map_updaters_[i]->forgetShape(it->second);
274  }
275 }
276 
277 void OccupancyMapMonitor::setTransformCacheCallback(const TransformCacheProvider& transform_callback)
278 {
279  // if we have just one updater, we connect it directly to the transform provider
280  if (map_updaters_.size() == 1)
281  map_updaters_[0]->setTransformCacheCallback(transform_callback);
282  else
283  transform_cache_callback_ = transform_callback;
284 }
285 
286 bool OccupancyMapMonitor::getShapeTransformCache(std::size_t index, const std::string& target_frame,
287  const ros::Time& target_time, ShapeTransformCache& cache) const
288 {
289  if (transform_cache_callback_)
290  {
292  if (transform_cache_callback_(target_frame, target_time, temp_cache))
293  {
294  for (std::pair<const ShapeHandle, Eigen::Isometry3d>& it : temp_cache)
295  {
296  std::map<ShapeHandle, ShapeHandle>::const_iterator jt = mesh_handles_[index].find(it.first);
297  if (jt == mesh_handles_[index].end())
298  {
299  ROS_ERROR_THROTTLE_NAMED(1, LOGNAME, "Incorrect mapping of mesh handles");
300  return false;
301  }
302  else
303  cache[jt->second] = it.second;
304  }
305  return true;
306  }
307  else
308  return false;
309  }
310  else
311  return false;
312 }
313 
314 bool OccupancyMapMonitor::saveMapCallback(moveit_msgs::SaveMap::Request& request,
315  moveit_msgs::SaveMap::Response& response)
316 {
317  ROS_INFO_STREAM_NAMED(LOGNAME, "Writing map to " << request.filename);
318  tree_->lockRead();
319  try
320  {
321  response.success = tree_->writeBinary(request.filename);
322  }
323  catch (...)
324  {
325  response.success = false;
326  }
327  tree_->unlockRead();
328  return true;
329 }
330 
331 bool OccupancyMapMonitor::loadMapCallback(moveit_msgs::LoadMap::Request& request,
332  moveit_msgs::LoadMap::Response& response)
333 {
334  ROS_INFO_STREAM_NAMED(LOGNAME, "Reading map from " << request.filename);
335 
336  /* load the octree from disk */
337  tree_->lockWrite();
338  try
339  {
340  response.success = tree_->readBinary(request.filename);
341  }
342  catch (...)
343  {
344  ROS_ERROR_NAMED(LOGNAME, "Failed to load map from file");
345  response.success = false;
346  }
347  tree_->unlockWrite();
348 
349  if (response.success)
350  tree_->triggerUpdateCallback();
351 
352  return true;
353 }
354 
355 void OccupancyMapMonitor::startMonitor()
356 {
357  active_ = true;
358  /* initialize all of the occupancy map updaters */
359  for (OccupancyMapUpdaterPtr& map_updater : map_updaters_)
360  map_updater->start();
361 }
362 
363 void OccupancyMapMonitor::stopMonitor()
364 {
365  active_ = false;
366  for (OccupancyMapUpdaterPtr& map_updater : map_updaters_)
367  map_updater->stop();
368 }
369 
370 OccupancyMapMonitor::~OccupancyMapMonitor()
371 {
372  stopMonitor();
373 }
374 } // namespace occupancy_map_monitor
XmlRpc::XmlRpcValue::size
int size() const
response
const std::string response
ROS_ERROR_THROTTLE_NAMED
#define ROS_ERROR_THROTTLE_NAMED(period, name,...)
initialize
bool initialize(MeshCollisionTraversalNode< BV > &node, BVHModel< BV > &model1, Transform3< typename BV::S > &tf1, BVHModel< BV > &model2, Transform3< typename BV::S > &tf2, const CollisionRequest< typename BV::S > &request, CollisionResult< typename BV::S > &result, bool use_refit, bool refit_bottomup)
occupancy_map_monitor::ShapeTransformCache
std::map< ShapeHandle, Eigen::Isometry3d, std::less< ShapeHandle >, Eigen::aligned_allocator< std::pair< const ShapeHandle, Eigen::Isometry3d > > > ShapeTransformCache
Definition: occupancy_map_updater.h:81
XmlRpc::XmlRpcException::getMessage
const std::string & getMessage() const
ros.h
occupancy_map_monitor.h
ROS_ERROR_NAMED
#define ROS_ERROR_NAMED(name,...)
XmlRpc::XmlRpcValue::TypeStruct
TypeStruct
pluginlib::PluginlibException
ROS_INFO_NAMED
#define ROS_INFO_NAMED(name,...)
ROS_FATAL_STREAM_NAMED
#define ROS_FATAL_STREAM_NAMED(name, args)
ROS_DEBUG_NAMED
#define ROS_DEBUG_NAMED(name,...)
ROS_ERROR_STREAM_NAMED
#define ROS_ERROR_STREAM_NAMED(name, args)
occupancy_map_monitor::TransformCacheProvider
boost::function< bool(const std::string &, const ros::Time &, ShapeTransformCache &)> TransformCacheProvider
Definition: occupancy_map_updater.h:82
XmlRpc::XmlRpcValue::getType
const Type & getType() const
ROS_WARN_STREAM_NAMED
#define ROS_WARN_STREAM_NAMED(name, args)
XmlRpc::XmlRpcValue::TypeArray
TypeArray
XmlRpc::XmlRpcException
occupancy_map_monitor::ShapeHandle
unsigned int ShapeHandle
Definition: occupancy_map_updater.h:79
ros::Time
tf_buffer
tf2_ros::Buffer * tf_buffer
ROS_WARN_NAMED
#define ROS_WARN_NAMED(name,...)
index
unsigned int index
occupancy_map_monitor::LOGNAME
static const std::string LOGNAME
Definition: occupancy_map_monitor.cpp:78
ROS_INFO_STREAM_NAMED
#define ROS_INFO_STREAM_NAMED(name, args)
occupancy_map_monitor
Definition: occupancy_map_monitor.h:54
occupancy_map_monitor::OccupancyMapMonitor::OccupancyMapMonitor
OccupancyMapMonitor(const std::shared_ptr< tf2_ros::Buffer > &tf_buffer, const std::string &map_frame="", double map_resolution=0.0)
Definition: occupancy_map_monitor.cpp:86
shapes::ShapeConstPtr
std::shared_ptr< const Shape > ShapeConstPtr
XmlRpcException.h
occupancy_map.h
XmlRpc::XmlRpcValue
ros::NodeHandle


occupancy_map_monitor
Author(s): Ioan Sucan , Jon Binney , Suat Gedikli
autogenerated on Sat Apr 27 2024 02:25:59