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