moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
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
40#include <moveit_msgs/srv/load_map.hpp>
41#include <moveit_msgs/srv/save_map.hpp>
42#include <rclcpp/clock.hpp>
43#include <rclcpp/logger.hpp>
44#include <rclcpp/logging.hpp>
45#include <rclcpp/node.hpp>
46#include <memory>
47#include <string>
48#include <utility>
49#include <vector>
51
53{
54
55OccupancyMapMonitor::OccupancyMapMonitor(const rclcpp::Node::SharedPtr& node, double map_resolution)
56 : OccupancyMapMonitor{ std::make_unique<OccupancyMapMonitorMiddlewareHandle>(node, map_resolution, ""), nullptr }
57{
58}
59
60OccupancyMapMonitor::OccupancyMapMonitor(const rclcpp::Node::SharedPtr& node,
61 const std::shared_ptr<tf2_ros::Buffer>& tf_buffer,
62 const std::string& map_frame, double map_resolution)
63 : OccupancyMapMonitor{ std::make_unique<OccupancyMapMonitorMiddlewareHandle>(node, map_resolution, map_frame),
64 tf_buffer }
65{
66}
67
68OccupancyMapMonitor::OccupancyMapMonitor(std::unique_ptr<MiddlewareHandle> middleware_handle,
69 const std::shared_ptr<tf2_ros::Buffer>& tf_buffer)
70 : middleware_handle_{ std::move(middleware_handle) }
71 , tf_buffer_{ tf_buffer }
72 , parameters_{ 0.0, "", {} }
73 , debug_info_{ false }
74 , mesh_handle_count_{ 0 }
75 , active_{ false }
76 , logger_(moveit::getLogger("moveit.ros.occupancy_map_monitor"))
77{
78 if (middleware_handle_ == nullptr)
79 {
80 throw std::invalid_argument("OccupancyMapMonitor cannot be constructed with nullptr MiddlewareHandle");
81 }
82
83 // Get the parameters
84 parameters_ = middleware_handle_->getParameters();
85
86 RCLCPP_DEBUG(logger_, "Using resolution = %lf m for building octomap", parameters_.map_resolution);
87
88 if (tf_buffer_ != nullptr && parameters_.map_frame.empty())
89 {
90 RCLCPP_WARN(logger_, "No target frame specified for Octomap. No transforms will be applied to received data.");
91 }
92 if (tf_buffer_ == nullptr && !parameters_.map_frame.empty())
93 {
94 RCLCPP_WARN(logger_, "Target frame specified but no TF instance (buffer) specified."
95 "No transforms will be applied to received data.");
96 }
97
98 tree_ = std::make_shared<collision_detection::OccMapTree>(parameters_.map_resolution);
99 tree_const_ = tree_;
100
101 for (const auto& [sensor_name, sensor_type] : parameters_.sensor_plugins)
102 {
103 auto occupancy_map_updater = middleware_handle_->loadOccupancyMapUpdater(sensor_type);
104
105 // Verify the updater was loaded
106 if (occupancy_map_updater == nullptr)
107 {
108 RCLCPP_ERROR_STREAM(logger_, "Failed to load sensor: `" << sensor_name << "` of type: `" << sensor_type << '`');
109 continue;
110 }
111
112 // Pass a pointer to the monitor to the updater
113 occupancy_map_updater->setMonitor(this);
114
115 // This part is done in the middleware handle because it needs the node
116 middleware_handle_->initializeOccupancyMapUpdater(occupancy_map_updater);
117
118 // Load the params in the updater
119 if (!occupancy_map_updater->setParams(sensor_name))
120 {
121 RCLCPP_ERROR_STREAM(logger_, "Failed to configure updater of type " << occupancy_map_updater->getType());
122 continue;
123 }
124
125 // Add the successfully initialized updater
126 addUpdater(occupancy_map_updater);
127 }
128
129 /* advertise a service for loading octomaps from disk */
130 auto save_map_service_callback = [this](const std::shared_ptr<rmw_request_id_t>& request_header,
131 const std::shared_ptr<moveit_msgs::srv::SaveMap::Request>& request,
132 const std::shared_ptr<moveit_msgs::srv::SaveMap::Response>& response) -> bool {
133 return saveMapCallback(request_header, request, response);
134 };
135
136 auto load_map_service_callback = [this](const std::shared_ptr<rmw_request_id_t>& request_header,
137 const std::shared_ptr<moveit_msgs::srv::LoadMap::Request>& request,
138 const std::shared_ptr<moveit_msgs::srv::LoadMap::Response>& response) -> bool {
139 return loadMapCallback(request_header, request, response);
140 };
141
142 middleware_handle_->createSaveMapService(save_map_service_callback);
143 middleware_handle_->createLoadMapService(load_map_service_callback);
144}
145
146void OccupancyMapMonitor::addUpdater(const OccupancyMapUpdaterPtr& updater)
147{
148 if (updater)
149 {
150 map_updaters_.push_back(updater);
151 updater->publishDebugInformation(debug_info_);
152 if (map_updaters_.size() > 1)
153 {
154 mesh_handles_.resize(map_updaters_.size());
155 // when we had one updater only, we passed directly the transform cache callback to that updater
156 if (map_updaters_.size() == 2)
157 {
158 map_updaters_[0]->setTransformCacheCallback(
159 [this](const std::string& frame, const rclcpp::Time& stamp, ShapeTransformCache& cache) {
160 return getShapeTransformCache(0, frame, stamp, cache);
161 });
162 map_updaters_[1]->setTransformCacheCallback(
163 [this](const std::string& frame, const rclcpp::Time& stamp, ShapeTransformCache& cache) {
164 return getShapeTransformCache(1, frame, stamp, cache);
165 });
166 }
167 else
168 {
169 map_updaters_.back()->setTransformCacheCallback(
170 [this, i = map_updaters_.size() - 1](const std::string& frame, const rclcpp::Time& stamp,
171 ShapeTransformCache& cache) {
172 return getShapeTransformCache(i, frame, stamp, cache);
173 });
174 }
175 }
176 else
177 {
178 updater->setTransformCacheCallback(transform_cache_callback_);
179 }
180 }
181 else
182 {
183 RCLCPP_ERROR(logger_, "nullptr updater was specified");
184 }
185}
186
188{
189 debug_info_ = flag;
190 for (OccupancyMapUpdaterPtr& map_updater : map_updaters_)
191 map_updater->publishDebugInformation(debug_info_);
192}
193
194void OccupancyMapMonitor::setMapFrame(const std::string& frame)
195{
196 std::lock_guard<std::mutex> _(parameters_lock_); // we lock since an updater could specify a new frame for us
197 parameters_.map_frame = frame;
198}
199
200ShapeHandle OccupancyMapMonitor::excludeShape(const shapes::ShapeConstPtr& shape)
201{
202 // if we have just one updater, remove the additional level of indirection
203 if (map_updaters_.size() == 1)
204 return map_updaters_[0]->excludeShape(shape);
205
206 ShapeHandle h = 0;
207 for (std::size_t i = 0; i < map_updaters_.size(); ++i)
208 {
209 ShapeHandle mh = map_updaters_[i]->excludeShape(shape);
210 if (mh)
211 {
212 if (h == 0)
213 h = ++mesh_handle_count_;
214 mesh_handles_[i][h] = mh;
215 }
216 }
217 return h;
218}
219
221{
222 // if we have just one updater, remove the additional level of indirection
223 if (map_updaters_.size() == 1)
224 {
225 map_updaters_[0]->forgetShape(handle);
226 return;
227 }
228
229 for (std::size_t i = 0; i < map_updaters_.size(); ++i)
230 {
231 std::map<ShapeHandle, ShapeHandle>::const_iterator it = mesh_handles_[i].find(handle);
232 if (it == mesh_handles_[i].end())
233 continue;
234 map_updaters_[i]->forgetShape(it->second);
235 }
236}
237
239{
240 // if we have just one updater, we connect it directly to the transform provider
241 if (map_updaters_.size() == 1)
242 {
243 map_updaters_[0]->setTransformCacheCallback(transform_callback);
244 }
245 else
246 {
247 transform_cache_callback_ = transform_callback;
248 }
249}
250
251bool OccupancyMapMonitor::getShapeTransformCache(std::size_t index, const std::string& target_frame,
252 const rclcpp::Time& target_time, ShapeTransformCache& cache) const
253{
254 if (transform_cache_callback_)
255 {
256 ShapeTransformCache temp_cache;
257 if (transform_cache_callback_(target_frame, target_time, temp_cache))
258 {
259 for (std::pair<const ShapeHandle, Eigen::Isometry3d>& it : temp_cache)
260 {
261 std::map<ShapeHandle, ShapeHandle>::const_iterator jt = mesh_handles_[index].find(it.first);
262 if (jt == mesh_handles_[index].end())
263 {
264 rclcpp::Clock steady_clock(RCL_STEADY_TIME);
265#pragma GCC diagnostic push
266#pragma GCC diagnostic ignored "-Wold-style-cast"
267 RCLCPP_ERROR_THROTTLE(logger_, steady_clock, 1000, "Incorrect mapping of mesh handles");
268#pragma GCC diagnostic pop
269 return false;
270 }
271 else
272 {
273 cache[jt->second] = it.second;
274 }
275 }
276 return true;
277 }
278 else
279 {
280 return false;
281 }
282 }
283 else
284 {
285 return false;
286 }
287}
288
289bool OccupancyMapMonitor::saveMapCallback(const std::shared_ptr<rmw_request_id_t>& /* unused */,
290 const std::shared_ptr<moveit_msgs::srv::SaveMap::Request>& request,
291 const std::shared_ptr<moveit_msgs::srv::SaveMap::Response>& response)
292{
293 RCLCPP_INFO(logger_, "Writing map to %s", request->filename.c_str());
294 tree_->lockRead();
295 try
296 {
297 response->success = tree_->writeBinary(request->filename);
298 }
299 catch (...)
300 {
301 response->success = false;
302 }
303 tree_->unlockRead();
304 return true;
305}
306
307bool OccupancyMapMonitor::loadMapCallback(const std::shared_ptr<rmw_request_id_t>& /* unused */,
308 const std::shared_ptr<moveit_msgs::srv::LoadMap::Request>& request,
309 const std::shared_ptr<moveit_msgs::srv::LoadMap::Response>& response)
310{
311 RCLCPP_INFO(logger_, "Reading map from %s", request->filename.c_str());
312
313 /* load the octree from disk */
314 tree_->lockWrite();
315 try
316 {
317 response->success = tree_->readBinary(request->filename);
318 }
319 catch (...)
320 {
321 RCLCPP_ERROR(logger_, "Failed to load map from file");
322 response->success = false;
323 }
324 tree_->unlockWrite();
325
326 if (response->success)
327 tree_->triggerUpdateCallback();
328
329 return true;
330}
331
333{
334 active_ = true;
335 /* initialize all of the occupancy map updaters */
336 for (OccupancyMapUpdaterPtr& map_updater : map_updaters_)
337 map_updater->start();
338}
339
341{
342 active_ = false;
343 for (OccupancyMapUpdaterPtr& map_updater : map_updaters_)
344 map_updater->stop();
345}
346
351} // namespace occupancy_map_monitor
This class contains the ros interfaces for OccupancyMapMontior.
void startMonitor()
start the monitor (will begin updating the octomap
void setTransformCacheCallback(const TransformCacheProvider &transform_cache_callback)
Sets the transform cache callback.
void publishDebugInformation(bool flag)
Set the debug flag on the updaters.
OccupancyMapMonitor(std::unique_ptr< MiddlewareHandle > middleware_handle, const std::shared_ptr< tf2_ros::Buffer > &tf_buffer)
Occupancy map monitor constructor with the MiddlewareHandle.
void stopMonitor()
Stops the monitor, this also stops the updaters.
ShapeHandle excludeShape(const shapes::ShapeConstPtr &shape)
Add this shape to the set of shapes to be filtered out from the octomap.
void addUpdater(const OccupancyMapUpdaterPtr &updater)
Adds an OccupancyMapUpdater to be monitored.
void setMapFrame(const std::string &frame)
Sets the map frame.
void forgetShape(ShapeHandle handle)
Forget about this shape handle and the shapes it corresponds to.
rclcpp::Logger getLogger(const std::string &name)
Creates a namespaced logger.
Definition logger.cpp:106
std::map< ShapeHandle, Eigen::Isometry3d, std::less< ShapeHandle >, Eigen::aligned_allocator< std::pair< const ShapeHandle, Eigen::Isometry3d > > > ShapeTransformCache
std::function< bool(const std::string &, const rclcpp::Time &, ShapeTransformCache &)> TransformCacheProvider