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 // image_transport 7+ (rclcpp >= 30, currently Rolling only) requires a
123 // NodeInterfaces-compatible reference; earlier versions on Humble (3.x),
124 // Jazzy (5.x), and Kilted (6.x) still take a rclcpp::Node::SharedPtr.
125 // For Rolling, L-turtle, and newer
126#if RCLCPP_VERSION_GTE(30, 0, 0)
127 input_depth_transport_ = std::make_unique<image_transport::ImageTransport>(*node_);
128 model_depth_transport_ = std::make_unique<image_transport::ImageTransport>(*node_);
129 filtered_depth_transport_ = std::make_unique<image_transport::ImageTransport>(*node_);
130 filtered_label_transport_ = std::make_unique<image_transport::ImageTransport>(*node_);
131 // For Kilted and older
132#else
133 input_depth_transport_ = std::make_unique<image_transport::ImageTransport>(node_);
134 model_depth_transport_ = std::make_unique<image_transport::ImageTransport>(node_);
135 filtered_depth_transport_ = std::make_unique<image_transport::ImageTransport>(node_);
136 filtered_label_transport_ = std::make_unique<image_transport::ImageTransport>(node_);
137#endif
138
139 tf_buffer_ = monitor_->getTFClient();
140 free_space_updater_ = std::make_unique<LazyFreeSpaceUpdater>(tree_);
141
142 // create our mesh filter
143 mesh_filter_ = std::make_unique<mesh_filter::MeshFilter<mesh_filter::StereoCameraModel>>(
145 mesh_filter_->parameters().setDepthRange(near_clipping_plane_distance_, far_clipping_plane_distance_);
146 mesh_filter_->setShadowThreshold(shadow_threshold_);
147 mesh_filter_->setPaddingOffset(padding_offset_);
148 mesh_filter_->setPaddingScale(padding_scale_);
149 mesh_filter_->setTransformCallback(
150 [this](mesh_filter::MeshHandle mesh, Eigen::Isometry3d& tf) { return getShapeTransform(mesh, tf); });
151
152 return true;
153}
154
156{
157 pub_model_depth_image_ = model_depth_transport_->advertiseCamera("model_depth", 1);
158
159 std::string prefix = "";
160 if (!ns_.empty())
161 prefix = ns_ + "/";
162
163 pub_model_depth_image_ = model_depth_transport_->advertiseCamera(prefix + "model_depth", 1);
164 if (!filtered_cloud_topic_.empty())
165 {
166 pub_filtered_depth_image_ = filtered_depth_transport_->advertiseCamera(prefix + filtered_cloud_topic_, 1);
167 }
168 else
169 {
170 pub_filtered_depth_image_ = filtered_depth_transport_->advertiseCamera(prefix + "filtered_depth", 1);
171 }
172
173 pub_filtered_label_image_ = filtered_label_transport_->advertiseCamera(prefix + "filtered_label", 1);
174
175 sub_depth_image_ =
176// For Rolling, L-turtle, and newer
177#if RCLCPP_VERSION_GTE(30, 0, 0)
178 image_transport::create_camera_subscription(
179 *node_, image_topic_,
180 [this](const sensor_msgs::msg::Image::ConstSharedPtr& depth_msg,
181 const sensor_msgs::msg::CameraInfo::ConstSharedPtr& info_msg) {
182 return depthImageCallback(depth_msg, info_msg);
183 },
184 "raw", rclcpp::SensorDataQoS());
185// For Kilted and older
186#else
187 image_transport::create_camera_subscription(
188 node_.get(), image_topic_,
189 [this](const sensor_msgs::msg::Image::ConstSharedPtr& depth_msg,
190 const sensor_msgs::msg::CameraInfo::ConstSharedPtr& info_msg) {
191 return depthImageCallback(depth_msg, info_msg);
192 },
193 "raw", rmw_qos_profile_sensor_data);
194#endif
195}
196
198{
199 sub_depth_image_.shutdown();
200}
201
203{
205 if (mesh_filter_)
206 {
207 if (shape->type == shapes::MESH)
208 {
209 h = mesh_filter_->addMesh(static_cast<const shapes::Mesh&>(*shape));
210 }
211 else
212 {
213 std::unique_ptr<shapes::Mesh> m(shapes::createMeshFromShape(shape.get()));
214 if (m)
215 h = mesh_filter_->addMesh(*m);
216 }
217 }
218 else
219 {
220 RCLCPP_ERROR(logger_, "Mesh filter not yet initialized!");
221 }
222 return h;
223}
224
226{
227 if (mesh_filter_)
228 mesh_filter_->removeMesh(handle);
229}
230
231bool DepthImageOctomapUpdater::getShapeTransform(mesh_filter::MeshHandle h, Eigen::Isometry3d& transform) const
232{
233 ShapeTransformCache::const_iterator it = transform_cache_.find(h);
234 if (it == transform_cache_.end())
235 {
236 RCLCPP_ERROR(logger_, "Internal error. Mesh filter handle %u not found", h);
237 return false;
238 }
239 transform = it->second;
240 return true;
241}
242
243namespace
244{
245const bool HOST_IS_BIG_ENDIAN = []() {
246 union
247 {
248 uint32_t i;
249 char c[sizeof(uint32_t)];
250 } bint = { 0x01020304 };
251 return bint.c[0] == 1;
252}();
253} // namespace
254
255void DepthImageOctomapUpdater::depthImageCallback(const sensor_msgs::msg::Image::ConstSharedPtr& depth_msg,
256 const sensor_msgs::msg::CameraInfo::ConstSharedPtr& info_msg)
257{
258 RCLCPP_DEBUG(logger_, "Received a new depth image message (frame = '%s', encoding='%s')",
259 depth_msg->header.frame_id.c_str(), depth_msg->encoding.c_str());
260 rclcpp::Time start = node_->now();
261
262 if (max_update_rate_ > 0)
263 {
264 // ensure we are not updating the octomap representation too often
265 if (node_->now() - last_update_time_ <= rclcpp::Duration::from_seconds(1.0 / max_update_rate_))
266 return;
267 last_update_time_ = node_->now();
268 }
269
270 // measure the frequency at which we receive updates
271 if (image_callback_count_ < 1000)
272 {
273 if (image_callback_count_ > 0)
274 {
275 const double dt_start = (start - last_depth_callback_start_).seconds();
276 if (image_callback_count_ < 2)
277 {
278 average_callback_dt_ = dt_start;
279 }
280 else
281 {
282 average_callback_dt_ = ((image_callback_count_ - 1) * average_callback_dt_ + dt_start) /
283 static_cast<double>(image_callback_count_);
284 }
285 }
286 }
287 else
288 {
289 // every 1000 updates we reset the counter almost to the beginning (use 2 so we don't have so much of a ripple in
290 // the measured average)
291 image_callback_count_ = 2;
292 }
293 last_depth_callback_start_ = start;
294 ++image_callback_count_;
295
296 if (monitor_->getMapFrame().empty())
297 monitor_->setMapFrame(depth_msg->header.frame_id);
298
299 /* get transform for cloud into map frame */
300 tf2::Stamped<tf2::Transform> map_h_sensor;
301 if (monitor_->getMapFrame() == depth_msg->header.frame_id)
302 {
303 map_h_sensor.setIdentity();
304 }
305 else
306 {
307 if (tf_buffer_)
308 {
309 // wait at most 50ms
310 static const double TEST_DT = 0.005;
311 const int nt =
312 static_cast<int>((0.5 + average_callback_dt_ / TEST_DT) * std::max(1, (static_cast<int>(queue_size_) / 2)));
313 bool found = false;
314 std::string err;
315 for (int t = 0; t < nt; ++t)
316 {
317 try
318 {
319 tf2::fromMsg(tf_buffer_->lookupTransform(monitor_->getMapFrame(), depth_msg->header.frame_id,
320 depth_msg->header.stamp),
321 map_h_sensor);
322 found = true;
323 break;
324 }
325 catch (tf2::TransformException& ex)
326 {
327 std::chrono::duration<double, std::nano> tmp_duration(TEST_DT);
328 static const rclcpp::Duration D(tmp_duration);
329 err = ex.what();
330 std::this_thread::sleep_for(D.to_chrono<std::chrono::seconds>());
331 }
332 }
333 static const unsigned int MAX_TF_COUNTER = 1000; // so we avoid int overflow
334 if (found)
335 {
336 good_tf_++;
337 if (good_tf_ > MAX_TF_COUNTER)
338 {
339 const unsigned int div = MAX_TF_COUNTER / 10;
340 good_tf_ /= div;
341 failed_tf_ /= div;
342 }
343 }
344 else
345 {
346 failed_tf_++;
347 if (failed_tf_ > good_tf_)
348 {
349#pragma GCC diagnostic push
350#pragma GCC diagnostic ignored "-Wold-style-cast"
351 RCLCPP_WARN_THROTTLE(logger_, *node_->get_clock(), 1000,
352 "More than half of the image messages discarded due to TF being unavailable (%u%%). "
353 "Transform error of sensor data: %s; quitting callback.",
354 (100 * failed_tf_) / (good_tf_ + failed_tf_), err.c_str());
355#pragma GCC diagnostic pop
356 }
357 else
358 {
359#pragma GCC diagnostic push
360#pragma GCC diagnostic ignored "-Wold-style-cast"
361 RCLCPP_DEBUG_THROTTLE(logger_, *node_->get_clock(), 1000,
362 "Transform error of sensor data: %s; quitting callback", err.c_str());
363#pragma GCC diagnostic pop
364 }
365 if (failed_tf_ > MAX_TF_COUNTER)
366 {
367 const unsigned int div = MAX_TF_COUNTER / 10;
368 good_tf_ /= div;
369 failed_tf_ /= div;
370 }
371 return;
372 }
373 }
374 else
375 {
376 return;
377 }
378 }
379
380 if (!updateTransformCache(depth_msg->header.frame_id, depth_msg->header.stamp))
381 return;
382
383 if (depth_msg->is_bigendian && !HOST_IS_BIG_ENDIAN)
384 {
385#pragma GCC diagnostic push
386#pragma GCC diagnostic ignored "-Wold-style-cast"
387 RCLCPP_ERROR_THROTTLE(logger_, *node_->get_clock(), 1000, "endian problem: received image data does not match host");
388#pragma GCC diagnostic pop
389 }
390
391 const int w = depth_msg->width;
392 const int h = depth_msg->height;
393
394 // call the mesh filter
395 mesh_filter::StereoCameraModel::Parameters& params = mesh_filter_->parameters();
396 params.setCameraParameters(info_msg->k[0], info_msg->k[4], info_msg->k[2], info_msg->k[5]);
397 params.setImageSize(w, h);
398
399 const bool is_u_short = depth_msg->encoding == sensor_msgs::image_encodings::TYPE_16UC1;
400 if (is_u_short)
401 {
402 mesh_filter_->filter(&depth_msg->data[0], GL_UNSIGNED_SHORT);
403 }
404 else
405 {
406 if (depth_msg->encoding != sensor_msgs::image_encodings::TYPE_32FC1)
407 {
408#pragma GCC diagnostic push
409#pragma GCC diagnostic ignored "-Wold-style-cast"
410 RCLCPP_ERROR_THROTTLE(logger_, *node_->get_clock(), 1000, "Unexpected encoding type: '%s'. Ignoring input.",
411 depth_msg->encoding.c_str());
412#pragma GCC diagnostic pop
413 return;
414 }
415 mesh_filter_->filter(&depth_msg->data[0], GL_FLOAT);
416 }
417
418 // the mesh filter runs in background; compute extra things in the meantime
419
420 // Use correct principal point from calibration
421 const double px = info_msg->k[2];
422 const double py = info_msg->k[5];
423
424 // if the camera parameters have changed at all, recompute the cache we had
425 if (w >= static_cast<int>(x_cache_.size()) || h >= static_cast<int>(y_cache_.size()) || K2_ != px || K5_ != py ||
426 K0_ != info_msg->k[0] || K4_ != info_msg->k[4])
427 {
428 K2_ = px;
429 K5_ = py;
430 K0_ = info_msg->k[0];
431 K4_ = info_msg->k[4];
432
433 inv_fx_ = 1.0 / K0_;
434 inv_fy_ = 1.0 / K4_;
435
436 // if there are any NaNs, discard data
437 if (isnan(px) || isnan(py) || isnan(inv_fx_) || isnan(inv_fy_))
438 return;
439
440 // Pre-compute some constants
441 if (static_cast<int>(x_cache_.size()) < w)
442 x_cache_.resize(w);
443 if (static_cast<int>(y_cache_.size()) < h)
444 y_cache_.resize(h);
445
446 for (int x = 0; x < w; ++x)
447 x_cache_[x] = (x - px) * inv_fx_;
448
449 for (int y = 0; y < h; ++y)
450 y_cache_[y] = (y - py) * inv_fy_;
451 }
452
453 const octomap::point3d sensor_origin(map_h_sensor.getOrigin().getX(), map_h_sensor.getOrigin().getY(),
454 map_h_sensor.getOrigin().getZ());
455
456 octomap::KeySet* occupied_cells_ptr = new octomap::KeySet();
457 octomap::KeySet* model_cells_ptr = new octomap::KeySet();
458 octomap::KeySet& occupied_cells = *occupied_cells_ptr;
459 octomap::KeySet& model_cells = *model_cells_ptr;
460
461 // allocate memory if needed
462 std::size_t img_size = h * w;
463 if (filtered_labels_.size() < img_size)
464 filtered_labels_.resize(img_size);
465
466 // get the labels of the filtered data
467 const unsigned int* labels_row = &filtered_labels_[0];
468 mesh_filter_->getFilteredLabels(&filtered_labels_[0]);
469
470 // publish debug information if needed
471 if (debug_info_)
472 {
473 sensor_msgs::msg::Image debug_msg;
474 debug_msg.header = depth_msg->header;
475 debug_msg.height = h;
476 debug_msg.width = w;
477 debug_msg.is_bigendian = HOST_IS_BIG_ENDIAN;
478 debug_msg.encoding = sensor_msgs::image_encodings::TYPE_32FC1;
479 debug_msg.step = w * sizeof(float);
480 debug_msg.data.resize(img_size * sizeof(float));
481 mesh_filter_->getModelDepth(reinterpret_cast<float*>(&debug_msg.data[0]));
482 pub_model_depth_image_.publish(debug_msg, *info_msg);
483
484 sensor_msgs::msg::Image filtered_depth_msg;
485 filtered_depth_msg.header = depth_msg->header;
486 filtered_depth_msg.height = h;
487 filtered_depth_msg.width = w;
488 filtered_depth_msg.is_bigendian = HOST_IS_BIG_ENDIAN;
489 filtered_depth_msg.encoding = sensor_msgs::image_encodings::TYPE_32FC1;
490 filtered_depth_msg.step = w * sizeof(float);
491 filtered_depth_msg.data.resize(img_size * sizeof(float));
492 mesh_filter_->getFilteredDepth(reinterpret_cast<float*>(&filtered_depth_msg.data[0]));
493 pub_filtered_depth_image_.publish(filtered_depth_msg, *info_msg);
494
495 sensor_msgs::msg::Image label_msg;
496 label_msg.header = depth_msg->header;
497 label_msg.height = h;
498 label_msg.width = w;
499 label_msg.is_bigendian = HOST_IS_BIG_ENDIAN;
500 label_msg.encoding = sensor_msgs::image_encodings::RGBA8;
501 label_msg.step = w * sizeof(unsigned int);
502 label_msg.data.resize(img_size * sizeof(unsigned int));
503 mesh_filter_->getFilteredLabels(reinterpret_cast<unsigned int*>(&label_msg.data[0]));
504
505 pub_filtered_label_image_.publish(label_msg, *info_msg);
506 }
507
508 if (!filtered_cloud_topic_.empty())
509 {
510 sensor_msgs::msg::Image filtered_msg;
511 filtered_msg.header = depth_msg->header;
512 filtered_msg.height = h;
513 filtered_msg.width = w;
514 filtered_msg.is_bigendian = HOST_IS_BIG_ENDIAN;
515 filtered_msg.encoding = sensor_msgs::image_encodings::TYPE_16UC1;
516 filtered_msg.step = w * sizeof(unsigned short);
517 filtered_msg.data.resize(img_size * sizeof(unsigned short));
518
519 // reuse float buffer across callbacks
520 static std::vector<float> filtered_data;
521 if (filtered_data.size() < img_size)
522 filtered_data.resize(img_size);
523
524 mesh_filter_->getFilteredDepth(reinterpret_cast<float*>(&filtered_data[0]));
525 unsigned short* msg_data = reinterpret_cast<unsigned short*>(&filtered_msg.data[0]);
526 for (std::size_t i = 0; i < img_size; ++i)
527 {
528 // rescale depth to millimeter to work with `unsigned short`
529 msg_data[i] = static_cast<unsigned short>(filtered_data[i] * 1000 + 0.5);
530 }
531 pub_filtered_depth_image_.publish(filtered_msg, *info_msg);
532 }
533
534 // figure out occupied cells and model cells
535 tree_->lockRead();
536
537 try
538 {
539 const int h_bound = h - skip_vertical_pixels_;
540 const int w_bound = w - skip_horizontal_pixels_;
541
542 if (is_u_short)
543 {
544 const uint16_t* input_row = reinterpret_cast<const uint16_t*>(&depth_msg->data[0]);
545
546 for (int y = skip_vertical_pixels_; y < h_bound; ++y, labels_row += w, input_row += w)
547 {
548 for (int x = skip_horizontal_pixels_; x < w_bound; ++x)
549 {
550 // not filtered
551 if (labels_row[x] == mesh_filter::MeshFilterBase::BACKGROUND)
552 {
553 float zz = static_cast<float>(input_row[x]) * 1e-3; // scale from mm to m
554 float yy = y_cache_[y] * zz;
555 float xx = x_cache_[x] * zz;
556 /* transform to map frame */
557 tf2::Vector3 point_tf = map_h_sensor * tf2::Vector3(xx, yy, zz);
558 occupied_cells.insert(tree_->coordToKey(point_tf.getX(), point_tf.getY(), point_tf.getZ()));
559 }
560 // on far plane or a model point -> remove
561 else if (labels_row[x] >= mesh_filter::MeshFilterBase::FAR_CLIP)
562 {
563 float zz = input_row[x] * 1e-3;
564 float yy = y_cache_[y] * zz;
565 float xx = x_cache_[x] * zz;
566 /* transform to map frame */
567 tf2::Vector3 point_tf = map_h_sensor * tf2::Vector3(xx, yy, zz);
568 // add to the list of model cells
569 model_cells.insert(tree_->coordToKey(point_tf.getX(), point_tf.getY(), point_tf.getZ()));
570 }
571 }
572 }
573 }
574 else
575 {
576 const float* input_row = reinterpret_cast<const float*>(&depth_msg->data[0]);
577
578 for (int y = skip_vertical_pixels_; y < h_bound; ++y, labels_row += w, input_row += w)
579 {
580 for (int x = skip_horizontal_pixels_; x < w_bound; ++x)
581 {
582 if (labels_row[x] == mesh_filter::MeshFilterBase::BACKGROUND)
583 {
584 float zz = input_row[x];
585 float yy = y_cache_[y] * zz;
586 float xx = x_cache_[x] * zz;
587 /* transform to map frame */
588 tf2::Vector3 point_tf = map_h_sensor * tf2::Vector3(xx, yy, zz);
589 occupied_cells.insert(tree_->coordToKey(point_tf.getX(), point_tf.getY(), point_tf.getZ()));
590 }
591 else if (labels_row[x] >= mesh_filter::MeshFilterBase::FAR_CLIP)
592 {
593 float zz = input_row[x];
594 float yy = y_cache_[y] * zz;
595 float xx = x_cache_[x] * zz;
596 /* transform to map frame */
597 tf2::Vector3 point_tf = map_h_sensor * tf2::Vector3(xx, yy, zz);
598 // add to the list of model cells
599 model_cells.insert(tree_->coordToKey(point_tf.getX(), point_tf.getY(), point_tf.getZ()));
600 }
601 }
602 }
603 }
604 }
605 catch (...)
606 {
607 tree_->unlockRead();
608 RCLCPP_ERROR(logger_, "Internal error while parsing depth data");
609 return;
610 }
611 tree_->unlockRead();
612
613 /* cells that overlap with the model are not occupied */
614 for (const octomap::OcTreeKey& model_cell : model_cells)
615 occupied_cells.erase(model_cell);
616
617 // mark occupied cells
618 tree_->lockWrite();
619 try
620 {
621 /* now mark all occupied cells */
622 for (const octomap::OcTreeKey& occupied_cell : occupied_cells)
623 tree_->updateNode(occupied_cell, true);
624 }
625 catch (...)
626 {
627 RCLCPP_ERROR(logger_, "Internal error while updating octree");
628 }
629 tree_->unlockWrite();
630 tree_->triggerUpdateCallback();
631
632 // at this point we still have not freed the space
633 free_space_updater_->pushLazyUpdate(occupied_cells_ptr, model_cells_ptr, sensor_origin);
634
635 RCLCPP_DEBUG(logger_, "Processed depth image in %lf ms", (node_->now() - start).seconds() * 1000.0);
636}
637} // namespace occupancy_map_monitor
std::function< bool(MeshHandle, Eigen::Isometry3d &)> TransformCallback
void setImageSize(unsigned width, unsigned height)
sets the image size
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...
bool updateTransformCache(const std::string &target_frame, const rclcpp::Time &target_time)
unsigned int MeshHandle
Main namespace for MoveIt.