moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
depth_image_octomap_updater.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, Suat Gedikli */
36
39#include <cmath>
40#include <rclcpp/qos.hpp>
41#include <rclcpp/version.h>
42#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
43// TODO: Remove conditional includes when released to all active distros.
44#if __has_include(<tf2/LinearMath/Vector3.hpp>)
45#include <tf2/LinearMath/Vector3.hpp>
46#else
47#include <tf2/LinearMath/Vector3.h>
48#endif
49#if __has_include(<tf2/LinearMath/Transform.hpp>)
50#include <tf2/LinearMath/Transform.hpp>
51#else
52#include <tf2/LinearMath/Transform.h>
53#endif
54#include <geometric_shapes/shape_operations.h>
55#include <sensor_msgs/image_encodings.hpp>
56#include <stdint.h>
58
59#include <memory>
60
62{
63
65 : OccupancyMapUpdater("DepthImageUpdater")
66 , image_topic_("depth")
67 , queue_size_(5)
68 , near_clipping_plane_distance_(0.3)
69 , far_clipping_plane_distance_(5.0)
70 , shadow_threshold_(0.04)
71 , padding_scale_(0.0)
72 , padding_offset_(0.02)
73 , max_update_rate_(0)
74 , skip_vertical_pixels_(4)
75 , skip_horizontal_pixels_(6)
76 , image_callback_count_(0)
77 , average_callback_dt_(0.0)
78 , good_tf_(5)
79 , // start optimistically, so we do not output warnings right from the beginning
80 failed_tf_(0)
81 , K0_(0.0)
82 , K2_(0.0)
83 , K4_(0.0)
84 , K5_(0.0)
85 , logger_(moveit::getLogger("moveit.ros.depth_image_octomap_updater"))
86{
87}
88
90{
91 sub_depth_image_.shutdown();
92}
93
94bool DepthImageOctomapUpdater::setParams(const std::string& name_space)
95{
96 try
97 {
98 node_->get_parameter(name_space + ".image_topic", image_topic_) &&
99 node_->get_parameter(name_space + ".queue_size", queue_size_) &&
100 node_->get_parameter(name_space + ".near_clipping_plane_distance", near_clipping_plane_distance_) &&
101 node_->get_parameter(name_space + ".far_clipping_plane_distance", far_clipping_plane_distance_) &&
102 node_->get_parameter(name_space + ".shadow_threshold", shadow_threshold_) &&
103 node_->get_parameter(name_space + ".padding_scale", padding_scale_) &&
104 node_->get_parameter(name_space + ".padding_offset", padding_offset_) &&
105 node_->get_parameter(name_space + ".max_update_rate", max_update_rate_) &&
106 node_->get_parameter(name_space + ".skip_vertical_pixels", skip_vertical_pixels_) &&
107 node_->get_parameter(name_space + ".skip_horizontal_pixels", skip_horizontal_pixels_) &&
108 node_->get_parameter(name_space + ".filtered_cloud_topic", filtered_cloud_topic_) &&
109 node_->get_parameter(name_space + ".ns", ns_);
110 return true;
111 }
112 catch (const rclcpp::exceptions::InvalidParameterTypeException& e)
113 {
114 RCLCPP_ERROR_STREAM(logger_, e.what() << '\n');
115 return false;
116 }
117}
118
119bool DepthImageOctomapUpdater::initialize(const rclcpp::Node::SharedPtr& node)
120{
121 node_ = node;
122 input_depth_transport_ = std::make_unique<image_transport::ImageTransport>(node_);
123 model_depth_transport_ = std::make_unique<image_transport::ImageTransport>(node_);
124 filtered_depth_transport_ = std::make_unique<image_transport::ImageTransport>(node_);
125 filtered_label_transport_ = std::make_unique<image_transport::ImageTransport>(node_);
126
127 tf_buffer_ = monitor_->getTFClient();
128 free_space_updater_ = std::make_unique<LazyFreeSpaceUpdater>(tree_);
129
130 // create our mesh filter
131 mesh_filter_ = std::make_unique<mesh_filter::MeshFilter<mesh_filter::StereoCameraModel>>(
133 mesh_filter_->parameters().setDepthRange(near_clipping_plane_distance_, far_clipping_plane_distance_);
134 mesh_filter_->setShadowThreshold(shadow_threshold_);
135 mesh_filter_->setPaddingOffset(padding_offset_);
136 mesh_filter_->setPaddingScale(padding_scale_);
137 mesh_filter_->setTransformCallback(
138 [this](mesh_filter::MeshHandle mesh, Eigen::Isometry3d& tf) { return getShapeTransform(mesh, tf); });
139
140 return true;
141}
142
144{
145 pub_model_depth_image_ = model_depth_transport_->advertiseCamera("model_depth", 1);
146
147 std::string prefix = "";
148 if (!ns_.empty())
149 prefix = ns_ + "/";
150
151 pub_model_depth_image_ = model_depth_transport_->advertiseCamera(prefix + "model_depth", 1);
152 if (!filtered_cloud_topic_.empty())
153 {
154 pub_filtered_depth_image_ = filtered_depth_transport_->advertiseCamera(prefix + filtered_cloud_topic_, 1);
155 }
156 else
157 {
158 pub_filtered_depth_image_ = filtered_depth_transport_->advertiseCamera(prefix + "filtered_depth", 1);
159 }
160
161 pub_filtered_label_image_ = filtered_label_transport_->advertiseCamera(prefix + "filtered_label", 1);
162
163 sub_depth_image_ =
164// For Rolling, L-turtle, and newer
165#if RCLCPP_VERSION_GTE(30, 0, 0)
166 image_transport::create_camera_subscription(
167 *node_, image_topic_,
168 [this](const sensor_msgs::msg::Image::ConstSharedPtr& depth_msg,
169 const sensor_msgs::msg::CameraInfo::ConstSharedPtr& info_msg) {
170 return depthImageCallback(depth_msg, info_msg);
171 },
172 "raw", rclcpp::SensorDataQoS());
173// For Kilted and older
174#else
175 image_transport::create_camera_subscription(
176 node_.get(), image_topic_,
177 [this](const sensor_msgs::msg::Image::ConstSharedPtr& depth_msg,
178 const sensor_msgs::msg::CameraInfo::ConstSharedPtr& info_msg) {
179 return depthImageCallback(depth_msg, info_msg);
180 },
181 "raw", rmw_qos_profile_sensor_data);
182#endif
183}
184
186{
187 sub_depth_image_.shutdown();
188}
189
191{
193 if (mesh_filter_)
194 {
195 if (shape->type == shapes::MESH)
196 {
197 h = mesh_filter_->addMesh(static_cast<const shapes::Mesh&>(*shape));
198 }
199 else
200 {
201 std::unique_ptr<shapes::Mesh> m(shapes::createMeshFromShape(shape.get()));
202 if (m)
203 h = mesh_filter_->addMesh(*m);
204 }
205 }
206 else
207 RCLCPP_ERROR(logger_, "Mesh filter not yet initialized!");
208 return h;
209}
210
212{
213 if (mesh_filter_)
214 mesh_filter_->removeMesh(handle);
215}
216
217bool DepthImageOctomapUpdater::getShapeTransform(mesh_filter::MeshHandle h, Eigen::Isometry3d& transform) const
218{
219 ShapeTransformCache::const_iterator it = transform_cache_.find(h);
220 if (it == transform_cache_.end())
221 {
222 RCLCPP_ERROR(logger_, "Internal error. Mesh filter handle %u not found", h);
223 return false;
224 }
225 transform = it->second;
226 return true;
227}
228
229namespace
230{
231const bool HOST_IS_BIG_ENDIAN = []() {
232 union
233 {
234 uint32_t i;
235 char c[sizeof(uint32_t)];
236 } bint = { 0x01020304 };
237 return bint.c[0] == 1;
238}();
239} // namespace
240
241void DepthImageOctomapUpdater::depthImageCallback(const sensor_msgs::msg::Image::ConstSharedPtr& depth_msg,
242 const sensor_msgs::msg::CameraInfo::ConstSharedPtr& info_msg)
243{
244 RCLCPP_DEBUG(logger_, "Received a new depth image message (frame = '%s', encoding='%s')",
245 depth_msg->header.frame_id.c_str(), depth_msg->encoding.c_str());
246 rclcpp::Time start = node_->now();
247
248 if (max_update_rate_ > 0)
249 {
250 // ensure we are not updating the octomap representation too often
251 if (node_->now() - last_update_time_ <= rclcpp::Duration::from_seconds(1.0 / max_update_rate_))
252 return;
253 last_update_time_ = node_->now();
254 }
255
256 // measure the frequency at which we receive updates
257 if (image_callback_count_ < 1000)
258 {
259 if (image_callback_count_ > 0)
260 {
261 const double dt_start = (start - last_depth_callback_start_).seconds();
262 if (image_callback_count_ < 2)
263 {
264 average_callback_dt_ = dt_start;
265 }
266 else
267 {
268 average_callback_dt_ = ((image_callback_count_ - 1) * average_callback_dt_ + dt_start) /
269 static_cast<double>(image_callback_count_);
270 }
271 }
272 }
273 else
274 {
275 // every 1000 updates we reset the counter almost to the beginning (use 2 so we don't have so much of a ripple in
276 // the measured average)
277 image_callback_count_ = 2;
278 }
279 last_depth_callback_start_ = start;
280 ++image_callback_count_;
281
282 if (monitor_->getMapFrame().empty())
283 monitor_->setMapFrame(depth_msg->header.frame_id);
284
285 /* get transform for cloud into map frame */
286 tf2::Stamped<tf2::Transform> map_h_sensor;
287 if (monitor_->getMapFrame() == depth_msg->header.frame_id)
288 {
289 map_h_sensor.setIdentity();
290 }
291 else
292 {
293 if (tf_buffer_)
294 {
295 // wait at most 50ms
296 static const double TEST_DT = 0.005;
297 const int nt =
298 static_cast<int>((0.5 + average_callback_dt_ / TEST_DT) * std::max(1, (static_cast<int>(queue_size_) / 2)));
299 bool found = false;
300 std::string err;
301 for (int t = 0; t < nt; ++t)
302 {
303 try
304 {
305 tf2::fromMsg(tf_buffer_->lookupTransform(monitor_->getMapFrame(), depth_msg->header.frame_id,
306 depth_msg->header.stamp),
307 map_h_sensor);
308 found = true;
309 break;
310 }
311 catch (tf2::TransformException& ex)
312 {
313 std::chrono::duration<double, std::nano> tmp_duration(TEST_DT);
314 static const rclcpp::Duration D(tmp_duration);
315 err = ex.what();
316 std::this_thread::sleep_for(D.to_chrono<std::chrono::seconds>());
317 }
318 }
319 static const unsigned int MAX_TF_COUNTER = 1000; // so we avoid int overflow
320 if (found)
321 {
322 good_tf_++;
323 if (good_tf_ > MAX_TF_COUNTER)
324 {
325 const unsigned int div = MAX_TF_COUNTER / 10;
326 good_tf_ /= div;
327 failed_tf_ /= div;
328 }
329 }
330 else
331 {
332 failed_tf_++;
333 if (failed_tf_ > good_tf_)
334 {
335#pragma GCC diagnostic push
336#pragma GCC diagnostic ignored "-Wold-style-cast"
337 RCLCPP_WARN_THROTTLE(logger_, *node_->get_clock(), 1000,
338 "More than half of the image messages discarded due to TF being unavailable (%u%%). "
339 "Transform error of sensor data: %s; quitting callback.",
340 (100 * failed_tf_) / (good_tf_ + failed_tf_), err.c_str());
341#pragma GCC diagnostic pop
342 }
343 else
344 {
345#pragma GCC diagnostic push
346#pragma GCC diagnostic ignored "-Wold-style-cast"
347 RCLCPP_DEBUG_THROTTLE(logger_, *node_->get_clock(), 1000,
348 "Transform error of sensor data: %s; quitting callback", err.c_str());
349#pragma GCC diagnostic pop
350 }
351 if (failed_tf_ > MAX_TF_COUNTER)
352 {
353 const unsigned int div = MAX_TF_COUNTER / 10;
354 good_tf_ /= div;
355 failed_tf_ /= div;
356 }
357 return;
358 }
359 }
360 else
361 return;
362 }
363
364 if (!updateTransformCache(depth_msg->header.frame_id, depth_msg->header.stamp))
365 return;
366
367 if (depth_msg->is_bigendian && !HOST_IS_BIG_ENDIAN)
368 {
369#pragma GCC diagnostic push
370#pragma GCC diagnostic ignored "-Wold-style-cast"
371 RCLCPP_ERROR_THROTTLE(logger_, *node_->get_clock(), 1000, "endian problem: received image data does not match host");
372#pragma GCC diagnostic pop
373 }
374
375 const int w = depth_msg->width;
376 const int h = depth_msg->height;
377
378 // call the mesh filter
379 mesh_filter::StereoCameraModel::Parameters& params = mesh_filter_->parameters();
380 params.setCameraParameters(info_msg->k[0], info_msg->k[4], info_msg->k[2], info_msg->k[5]);
381 params.setImageSize(w, h);
382
383 const bool is_u_short = depth_msg->encoding == sensor_msgs::image_encodings::TYPE_16UC1;
384 if (is_u_short)
385 {
386 mesh_filter_->filter(&depth_msg->data[0], GL_UNSIGNED_SHORT);
387 }
388 else
389 {
390 if (depth_msg->encoding != sensor_msgs::image_encodings::TYPE_32FC1)
391 {
392#pragma GCC diagnostic push
393#pragma GCC diagnostic ignored "-Wold-style-cast"
394 RCLCPP_ERROR_THROTTLE(logger_, *node_->get_clock(), 1000, "Unexpected encoding type: '%s'. Ignoring input.",
395 depth_msg->encoding.c_str());
396#pragma GCC diagnostic pop
397 return;
398 }
399 mesh_filter_->filter(&depth_msg->data[0], GL_FLOAT);
400 }
401
402 // the mesh filter runs in background; compute extra things in the meantime
403
404 // Use correct principal point from calibration
405 const double px = info_msg->k[2];
406 const double py = info_msg->k[5];
407
408 // if the camera parameters have changed at all, recompute the cache we had
409 if (w >= static_cast<int>(x_cache_.size()) || h >= static_cast<int>(y_cache_.size()) || K2_ != px || K5_ != py ||
410 K0_ != info_msg->k[0] || K4_ != info_msg->k[4])
411 {
412 K2_ = px;
413 K5_ = py;
414 K0_ = info_msg->k[0];
415 K4_ = info_msg->k[4];
416
417 inv_fx_ = 1.0 / K0_;
418 inv_fy_ = 1.0 / K4_;
419
420 // if there are any NaNs, discard data
421 if (isnan(px) || isnan(py) || isnan(inv_fx_) || isnan(inv_fy_))
422 return;
423
424 // Pre-compute some constants
425 if (static_cast<int>(x_cache_.size()) < w)
426 x_cache_.resize(w);
427 if (static_cast<int>(y_cache_.size()) < h)
428 y_cache_.resize(h);
429
430 for (int x = 0; x < w; ++x)
431 x_cache_[x] = (x - px) * inv_fx_;
432
433 for (int y = 0; y < h; ++y)
434 y_cache_[y] = (y - py) * inv_fy_;
435 }
436
437 const octomap::point3d sensor_origin(map_h_sensor.getOrigin().getX(), map_h_sensor.getOrigin().getY(),
438 map_h_sensor.getOrigin().getZ());
439
440 octomap::KeySet* occupied_cells_ptr = new octomap::KeySet();
441 octomap::KeySet* model_cells_ptr = new octomap::KeySet();
442 octomap::KeySet& occupied_cells = *occupied_cells_ptr;
443 octomap::KeySet& model_cells = *model_cells_ptr;
444
445 // allocate memory if needed
446 std::size_t img_size = h * w;
447 if (filtered_labels_.size() < img_size)
448 filtered_labels_.resize(img_size);
449
450 // get the labels of the filtered data
451 const unsigned int* labels_row = &filtered_labels_[0];
452 mesh_filter_->getFilteredLabels(&filtered_labels_[0]);
453
454 // publish debug information if needed
455 if (debug_info_)
456 {
457 sensor_msgs::msg::Image debug_msg;
458 debug_msg.header = depth_msg->header;
459 debug_msg.height = h;
460 debug_msg.width = w;
461 debug_msg.is_bigendian = HOST_IS_BIG_ENDIAN;
462 debug_msg.encoding = sensor_msgs::image_encodings::TYPE_32FC1;
463 debug_msg.step = w * sizeof(float);
464 debug_msg.data.resize(img_size * sizeof(float));
465 mesh_filter_->getModelDepth(reinterpret_cast<float*>(&debug_msg.data[0]));
466 pub_model_depth_image_.publish(debug_msg, *info_msg);
467
468 sensor_msgs::msg::Image filtered_depth_msg;
469 filtered_depth_msg.header = depth_msg->header;
470 filtered_depth_msg.height = h;
471 filtered_depth_msg.width = w;
472 filtered_depth_msg.is_bigendian = HOST_IS_BIG_ENDIAN;
473 filtered_depth_msg.encoding = sensor_msgs::image_encodings::TYPE_32FC1;
474 filtered_depth_msg.step = w * sizeof(float);
475 filtered_depth_msg.data.resize(img_size * sizeof(float));
476 mesh_filter_->getFilteredDepth(reinterpret_cast<float*>(&filtered_depth_msg.data[0]));
477 pub_filtered_depth_image_.publish(filtered_depth_msg, *info_msg);
478
479 sensor_msgs::msg::Image label_msg;
480 label_msg.header = depth_msg->header;
481 label_msg.height = h;
482 label_msg.width = w;
483 label_msg.is_bigendian = HOST_IS_BIG_ENDIAN;
484 label_msg.encoding = sensor_msgs::image_encodings::RGBA8;
485 label_msg.step = w * sizeof(unsigned int);
486 label_msg.data.resize(img_size * sizeof(unsigned int));
487 mesh_filter_->getFilteredLabels(reinterpret_cast<unsigned int*>(&label_msg.data[0]));
488
489 pub_filtered_label_image_.publish(label_msg, *info_msg);
490 }
491
492 if (!filtered_cloud_topic_.empty())
493 {
494 sensor_msgs::msg::Image filtered_msg;
495 filtered_msg.header = depth_msg->header;
496 filtered_msg.height = h;
497 filtered_msg.width = w;
498 filtered_msg.is_bigendian = HOST_IS_BIG_ENDIAN;
499 filtered_msg.encoding = sensor_msgs::image_encodings::TYPE_16UC1;
500 filtered_msg.step = w * sizeof(unsigned short);
501 filtered_msg.data.resize(img_size * sizeof(unsigned short));
502
503 // reuse float buffer across callbacks
504 static std::vector<float> filtered_data;
505 if (filtered_data.size() < img_size)
506 filtered_data.resize(img_size);
507
508 mesh_filter_->getFilteredDepth(reinterpret_cast<float*>(&filtered_data[0]));
509 unsigned short* msg_data = reinterpret_cast<unsigned short*>(&filtered_msg.data[0]);
510 for (std::size_t i = 0; i < img_size; ++i)
511 {
512 // rescale depth to millimeter to work with `unsigned short`
513 msg_data[i] = static_cast<unsigned short>(filtered_data[i] * 1000 + 0.5);
514 }
515 pub_filtered_depth_image_.publish(filtered_msg, *info_msg);
516 }
517
518 // figure out occupied cells and model cells
519 tree_->lockRead();
520
521 try
522 {
523 const int h_bound = h - skip_vertical_pixels_;
524 const int w_bound = w - skip_horizontal_pixels_;
525
526 if (is_u_short)
527 {
528 const uint16_t* input_row = reinterpret_cast<const uint16_t*>(&depth_msg->data[0]);
529
530 for (int y = skip_vertical_pixels_; y < h_bound; ++y, labels_row += w, input_row += w)
531 {
532 for (int x = skip_horizontal_pixels_; x < w_bound; ++x)
533 {
534 // not filtered
535 if (labels_row[x] == mesh_filter::MeshFilterBase::BACKGROUND)
536 {
537 float zz = static_cast<float>(input_row[x]) * 1e-3; // scale from mm to m
538 float yy = y_cache_[y] * zz;
539 float xx = x_cache_[x] * zz;
540 /* transform to map frame */
541 tf2::Vector3 point_tf = map_h_sensor * tf2::Vector3(xx, yy, zz);
542 occupied_cells.insert(tree_->coordToKey(point_tf.getX(), point_tf.getY(), point_tf.getZ()));
543 }
544 // on far plane or a model point -> remove
545 else if (labels_row[x] >= mesh_filter::MeshFilterBase::FAR_CLIP)
546 {
547 float zz = input_row[x] * 1e-3;
548 float yy = y_cache_[y] * zz;
549 float xx = x_cache_[x] * zz;
550 /* transform to map frame */
551 tf2::Vector3 point_tf = map_h_sensor * tf2::Vector3(xx, yy, zz);
552 // add to the list of model cells
553 model_cells.insert(tree_->coordToKey(point_tf.getX(), point_tf.getY(), point_tf.getZ()));
554 }
555 }
556 }
557 }
558 else
559 {
560 const float* input_row = reinterpret_cast<const float*>(&depth_msg->data[0]);
561
562 for (int y = skip_vertical_pixels_; y < h_bound; ++y, labels_row += w, input_row += w)
563 {
564 for (int x = skip_horizontal_pixels_; x < w_bound; ++x)
565 {
566 if (labels_row[x] == mesh_filter::MeshFilterBase::BACKGROUND)
567 {
568 float zz = input_row[x];
569 float yy = y_cache_[y] * zz;
570 float xx = x_cache_[x] * zz;
571 /* transform to map frame */
572 tf2::Vector3 point_tf = map_h_sensor * tf2::Vector3(xx, yy, zz);
573 occupied_cells.insert(tree_->coordToKey(point_tf.getX(), point_tf.getY(), point_tf.getZ()));
574 }
575 else if (labels_row[x] >= mesh_filter::MeshFilterBase::FAR_CLIP)
576 {
577 float zz = input_row[x];
578 float yy = y_cache_[y] * zz;
579 float xx = x_cache_[x] * zz;
580 /* transform to map frame */
581 tf2::Vector3 point_tf = map_h_sensor * tf2::Vector3(xx, yy, zz);
582 // add to the list of model cells
583 model_cells.insert(tree_->coordToKey(point_tf.getX(), point_tf.getY(), point_tf.getZ()));
584 }
585 }
586 }
587 }
588 }
589 catch (...)
590 {
591 tree_->unlockRead();
592 RCLCPP_ERROR(logger_, "Internal error while parsing depth data");
593 return;
594 }
595 tree_->unlockRead();
596
597 /* cells that overlap with the model are not occupied */
598 for (const octomap::OcTreeKey& model_cell : model_cells)
599 occupied_cells.erase(model_cell);
600
601 // mark occupied cells
602 tree_->lockWrite();
603 try
604 {
605 /* now mark all occupied cells */
606 for (const octomap::OcTreeKey& occupied_cell : occupied_cells)
607 tree_->updateNode(occupied_cell, true);
608 }
609 catch (...)
610 {
611 RCLCPP_ERROR(logger_, "Internal error while updating octree");
612 }
613 tree_->unlockWrite();
614 tree_->triggerUpdateCallback();
615
616 // at this point we still have not freed the space
617 free_space_updater_->pushLazyUpdate(occupied_cells_ptr, model_cells_ptr, sensor_origin);
618
619 RCLCPP_DEBUG(logger_, "Processed depth image in %lf ms", (node_->now() - start).seconds() * 1000.0);
620}
621} // namespace occupancy_map_monitor
std::function< bool(MeshHandle, Eigen::Isometry3d &)> TransformCallback
void setImageSize(unsigned width, unsigned height)
sets the image size
Parameters for Stereo-like devices.
void setCameraParameters(float fx, float fy, float cx, float cy)
sets the camera parameters of the pinhole camera where the disparities were obtained....
static const StereoCameraModel::Parameters & REGISTERED_PSDK_PARAMS
predefined sensor model for OpenNI compatible devices (e.g., PrimeSense, Kinect, Asus Xtion)
bool initialize(const rclcpp::Node::SharedPtr &node) override
Do any necessary setup (subscribe to ros topics, etc.). This call assumes setMonitor() and setParams(...
ShapeHandle excludeShape(const shapes::ShapeConstPtr &shape) override
bool setParams(const std::string &name_space) override
Set updater params using struct that comes from parsing a yaml string. This must be called after setM...
const std::shared_ptr< tf2_ros::Buffer > & getTFClient() const
Gets the tf client.
const std::string & getMapFrame() const
Gets the map frame (this is set either by the constor or a parameter).
void setMapFrame(const std::string &frame)
Sets the map frame.
Base class for classes which update the occupancy map.
bool updateTransformCache(const std::string &target_frame, const rclcpp::Time &target_time)
unsigned int MeshHandle
Main namespace for MoveIt.