40#include <rclcpp/qos.hpp>
41#include <rclcpp/version.h>
42#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
44#if __has_include(<tf2/LinearMath/Vector3.hpp>)
45#include <tf2/LinearMath/Vector3.hpp>
47#include <tf2/LinearMath/Vector3.h>
49#if __has_include(<tf2/LinearMath/Transform.hpp>)
50#include <tf2/LinearMath/Transform.hpp>
52#include <tf2/LinearMath/Transform.h>
54#include <geometric_shapes/shape_operations.h>
55#include <sensor_msgs/image_encodings.hpp>
66 , image_topic_(
"depth")
68 , near_clipping_plane_distance_(0.3)
69 , far_clipping_plane_distance_(5.0)
70 , shadow_threshold_(0.04)
72 , padding_offset_(0.02)
74 , skip_vertical_pixels_(4)
75 , skip_horizontal_pixels_(6)
76 , image_callback_count_(0)
77 , average_callback_dt_(0.0)
91 sub_depth_image_.shutdown();
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_);
112 catch (
const rclcpp::exceptions::InvalidParameterTypeException& e)
114 RCLCPP_ERROR_STREAM(logger_, e.what() <<
'\n');
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_);
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_);
139 tf_buffer_ =
monitor_->getTFClient();
140 free_space_updater_ = std::make_unique<LazyFreeSpaceUpdater>(
tree_);
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(
157 pub_model_depth_image_ = model_depth_transport_->advertiseCamera(
"model_depth", 1);
159 std::string prefix =
"";
163 pub_model_depth_image_ = model_depth_transport_->advertiseCamera(prefix +
"model_depth", 1);
164 if (!filtered_cloud_topic_.empty())
166 pub_filtered_depth_image_ = filtered_depth_transport_->advertiseCamera(prefix + filtered_cloud_topic_, 1);
170 pub_filtered_depth_image_ = filtered_depth_transport_->advertiseCamera(prefix +
"filtered_depth", 1);
173 pub_filtered_label_image_ = filtered_label_transport_->advertiseCamera(prefix +
"filtered_label", 1);
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);
184 "raw", rclcpp::SensorDataQoS());
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);
193 "raw", rmw_qos_profile_sensor_data);
199 sub_depth_image_.shutdown();
207 if (shape->type == shapes::MESH)
209 h = mesh_filter_->addMesh(
static_cast<const shapes::Mesh&
>(*shape));
213 std::unique_ptr<shapes::Mesh> m(shapes::createMeshFromShape(shape.get()));
215 h = mesh_filter_->addMesh(*m);
220 RCLCPP_ERROR(logger_,
"Mesh filter not yet initialized!");
228 mesh_filter_->removeMesh(handle);
236 RCLCPP_ERROR(logger_,
"Internal error. Mesh filter handle %u not found", h);
239 transform = it->second;
245const bool HOST_IS_BIG_ENDIAN = []() {
249 char c[
sizeof(uint32_t)];
250 } bint = { 0x01020304 };
251 return bint.c[0] == 1;
255void DepthImageOctomapUpdater::depthImageCallback(
const sensor_msgs::msg::Image::ConstSharedPtr& depth_msg,
256 const sensor_msgs::msg::CameraInfo::ConstSharedPtr& info_msg)
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();
262 if (max_update_rate_ > 0)
265 if (node_->now() - last_update_time_ <= rclcpp::Duration::from_seconds(1.0 / max_update_rate_))
267 last_update_time_ = node_->now();
271 if (image_callback_count_ < 1000)
273 if (image_callback_count_ > 0)
275 const double dt_start = (
start - last_depth_callback_start_).seconds();
276 if (image_callback_count_ < 2)
278 average_callback_dt_ = dt_start;
282 average_callback_dt_ = ((image_callback_count_ - 1) * average_callback_dt_ + dt_start) /
283 static_cast<double>(image_callback_count_);
291 image_callback_count_ = 2;
293 last_depth_callback_start_ =
start;
294 ++image_callback_count_;
296 if (
monitor_->getMapFrame().empty())
297 monitor_->setMapFrame(depth_msg->header.frame_id);
300 tf2::Stamped<tf2::Transform> map_h_sensor;
301 if (
monitor_->getMapFrame() == depth_msg->header.frame_id)
303 map_h_sensor.setIdentity();
310 static const double TEST_DT = 0.005;
312 static_cast<int>((0.5 + average_callback_dt_ / TEST_DT) * std::max(1, (
static_cast<int>(queue_size_) / 2)));
315 for (
int t = 0; t < nt; ++t)
319 tf2::fromMsg(tf_buffer_->lookupTransform(
monitor_->getMapFrame(), depth_msg->header.frame_id,
320 depth_msg->header.stamp),
325 catch (tf2::TransformException& ex)
327 std::chrono::duration<double, std::nano> tmp_duration(TEST_DT);
328 static const rclcpp::Duration D(tmp_duration);
330 std::this_thread::sleep_for(D.to_chrono<std::chrono::seconds>());
333 static const unsigned int MAX_TF_COUNTER = 1000;
337 if (good_tf_ > MAX_TF_COUNTER)
339 const unsigned int div = MAX_TF_COUNTER / 10;
347 if (failed_tf_ > good_tf_)
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
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
365 if (failed_tf_ > MAX_TF_COUNTER)
367 const unsigned int div = MAX_TF_COUNTER / 10;
383 if (depth_msg->is_bigendian && !HOST_IS_BIG_ENDIAN)
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
391 const int w = depth_msg->width;
392 const int h = depth_msg->height;
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]);
399 const bool is_u_short = depth_msg->encoding == sensor_msgs::image_encodings::TYPE_16UC1;
402 mesh_filter_->filter(&depth_msg->data[0], GL_UNSIGNED_SHORT);
406 if (depth_msg->encoding != sensor_msgs::image_encodings::TYPE_32FC1)
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
415 mesh_filter_->filter(&depth_msg->data[0], GL_FLOAT);
421 const double px = info_msg->k[2];
422 const double py = info_msg->k[5];
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])
430 K0_ = info_msg->k[0];
431 K4_ = info_msg->k[4];
437 if (isnan(px) || isnan(py) || isnan(inv_fx_) || isnan(inv_fy_))
441 if (
static_cast<int>(x_cache_.size()) < w)
443 if (
static_cast<int>(y_cache_.size()) < h)
446 for (
int x = 0; x < w; ++x)
447 x_cache_[x] = (x - px) * inv_fx_;
449 for (
int y = 0; y < h; ++y)
450 y_cache_[y] = (y - py) * inv_fy_;
453 const octomap::point3d sensor_origin(map_h_sensor.getOrigin().getX(), map_h_sensor.getOrigin().getY(),
454 map_h_sensor.getOrigin().getZ());
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;
462 std::size_t img_size = h * w;
463 if (filtered_labels_.size() < img_size)
464 filtered_labels_.resize(img_size);
467 const unsigned int* labels_row = &filtered_labels_[0];
468 mesh_filter_->getFilteredLabels(&filtered_labels_[0]);
473 sensor_msgs::msg::Image debug_msg;
474 debug_msg.header = depth_msg->header;
475 debug_msg.height = h;
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);
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);
495 sensor_msgs::msg::Image label_msg;
496 label_msg.header = depth_msg->header;
497 label_msg.height = h;
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]));
505 pub_filtered_label_image_.publish(label_msg, *info_msg);
508 if (!filtered_cloud_topic_.empty())
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));
520 static std::vector<float> filtered_data;
521 if (filtered_data.size() < img_size)
522 filtered_data.resize(img_size);
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)
529 msg_data[i] =
static_cast<unsigned short>(filtered_data[i] * 1000 + 0.5);
531 pub_filtered_depth_image_.publish(filtered_msg, *info_msg);
539 const int h_bound = h - skip_vertical_pixels_;
540 const int w_bound = w - skip_horizontal_pixels_;
544 const uint16_t* input_row =
reinterpret_cast<const uint16_t*
>(&depth_msg->data[0]);
546 for (
int y = skip_vertical_pixels_; y < h_bound; ++y, labels_row += w, input_row += w)
548 for (
int x = skip_horizontal_pixels_; x < w_bound; ++x)
553 float zz =
static_cast<float>(input_row[x]) * 1e-3;
554 float yy = y_cache_[y] * zz;
555 float xx = x_cache_[x] * zz;
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()));
563 float zz = input_row[x] * 1e-3;
564 float yy = y_cache_[y] * zz;
565 float xx = x_cache_[x] * zz;
567 tf2::Vector3 point_tf = map_h_sensor * tf2::Vector3(xx, yy, zz);
569 model_cells.insert(
tree_->coordToKey(point_tf.getX(), point_tf.getY(), point_tf.getZ()));
576 const float* input_row =
reinterpret_cast<const float*
>(&depth_msg->data[0]);
578 for (
int y = skip_vertical_pixels_; y < h_bound; ++y, labels_row += w, input_row += w)
580 for (
int x = skip_horizontal_pixels_; x < w_bound; ++x)
584 float zz = input_row[x];
585 float yy = y_cache_[y] * zz;
586 float xx = x_cache_[x] * zz;
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()));
593 float zz = input_row[x];
594 float yy = y_cache_[y] * zz;
595 float xx = x_cache_[x] * zz;
597 tf2::Vector3 point_tf = map_h_sensor * tf2::Vector3(xx, yy, zz);
599 model_cells.insert(
tree_->coordToKey(point_tf.getX(), point_tf.getY(), point_tf.getZ()));
608 RCLCPP_ERROR(logger_,
"Internal error while parsing depth data");
614 for (
const octomap::OcTreeKey& model_cell : model_cells)
615 occupied_cells.erase(model_cell);
622 for (
const octomap::OcTreeKey& occupied_cell : occupied_cells)
623 tree_->updateNode(occupied_cell,
true);
627 RCLCPP_ERROR(logger_,
"Internal error while updating octree");
629 tree_->unlockWrite();
630 tree_->triggerUpdateCallback();
633 free_space_updater_->pushLazyUpdate(occupied_cells_ptr, model_cells_ptr, sensor_origin);
635 RCLCPP_DEBUG(logger_,
"Processed depth image in %lf ms", (node_->now() -
start).seconds() * 1000.0);
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)
void forgetShape(ShapeHandle handle) override
DepthImageOctomapUpdater()
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
~DepthImageOctomapUpdater() 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...
OccupancyMapMonitor * monitor_
collision_detection::OccMapTreePtr tree_
ShapeTransformCache transform_cache_
bool updateTransformCache(const std::string &target_frame, const rclcpp::Time &target_time)
OccupancyMapUpdater(const std::string &type)
Main namespace for MoveIt.
rclcpp::Logger getLogger()