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);
219 RCLCPP_ERROR(logger_,
"Mesh filter not yet initialized!");
226 mesh_filter_->removeMesh(handle);
234 RCLCPP_ERROR(logger_,
"Internal error. Mesh filter handle %u not found", h);
237 transform = it->second;
243const bool HOST_IS_BIG_ENDIAN = []() {
247 char c[
sizeof(uint32_t)];
248 } bint = { 0x01020304 };
249 return bint.c[0] == 1;
253void DepthImageOctomapUpdater::depthImageCallback(
const sensor_msgs::msg::Image::ConstSharedPtr& depth_msg,
254 const sensor_msgs::msg::CameraInfo::ConstSharedPtr& info_msg)
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();
260 if (max_update_rate_ > 0)
263 if (node_->now() - last_update_time_ <= rclcpp::Duration::from_seconds(1.0 / max_update_rate_))
265 last_update_time_ = node_->now();
269 if (image_callback_count_ < 1000)
271 if (image_callback_count_ > 0)
273 const double dt_start = (
start - last_depth_callback_start_).seconds();
274 if (image_callback_count_ < 2)
276 average_callback_dt_ = dt_start;
280 average_callback_dt_ = ((image_callback_count_ - 1) * average_callback_dt_ + dt_start) /
281 static_cast<double>(image_callback_count_);
289 image_callback_count_ = 2;
291 last_depth_callback_start_ =
start;
292 ++image_callback_count_;
294 if (
monitor_->getMapFrame().empty())
295 monitor_->setMapFrame(depth_msg->header.frame_id);
298 tf2::Stamped<tf2::Transform> map_h_sensor;
299 if (
monitor_->getMapFrame() == depth_msg->header.frame_id)
301 map_h_sensor.setIdentity();
308 static const double TEST_DT = 0.005;
310 static_cast<int>((0.5 + average_callback_dt_ / TEST_DT) * std::max(1, (
static_cast<int>(queue_size_) / 2)));
313 for (
int t = 0; t < nt; ++t)
317 tf2::fromMsg(tf_buffer_->lookupTransform(
monitor_->getMapFrame(), depth_msg->header.frame_id,
318 depth_msg->header.stamp),
323 catch (tf2::TransformException& ex)
325 std::chrono::duration<double, std::nano> tmp_duration(TEST_DT);
326 static const rclcpp::Duration D(tmp_duration);
328 std::this_thread::sleep_for(D.to_chrono<std::chrono::seconds>());
331 static const unsigned int MAX_TF_COUNTER = 1000;
335 if (good_tf_ > MAX_TF_COUNTER)
337 const unsigned int div = MAX_TF_COUNTER / 10;
345 if (failed_tf_ > good_tf_)
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
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
363 if (failed_tf_ > MAX_TF_COUNTER)
365 const unsigned int div = MAX_TF_COUNTER / 10;
379 if (depth_msg->is_bigendian && !HOST_IS_BIG_ENDIAN)
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
387 const int w = depth_msg->width;
388 const int h = depth_msg->height;
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]);
395 const bool is_u_short = depth_msg->encoding == sensor_msgs::image_encodings::TYPE_16UC1;
398 mesh_filter_->filter(&depth_msg->data[0], GL_UNSIGNED_SHORT);
402 if (depth_msg->encoding != sensor_msgs::image_encodings::TYPE_32FC1)
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
411 mesh_filter_->filter(&depth_msg->data[0], GL_FLOAT);
417 const double px = info_msg->k[2];
418 const double py = info_msg->k[5];
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])
426 K0_ = info_msg->k[0];
427 K4_ = info_msg->k[4];
433 if (isnan(px) || isnan(py) || isnan(inv_fx_) || isnan(inv_fy_))
437 if (
static_cast<int>(x_cache_.size()) < w)
439 if (
static_cast<int>(y_cache_.size()) < h)
442 for (
int x = 0; x < w; ++x)
443 x_cache_[x] = (x - px) * inv_fx_;
445 for (
int y = 0; y < h; ++y)
446 y_cache_[y] = (y - py) * inv_fy_;
449 const octomap::point3d sensor_origin(map_h_sensor.getOrigin().getX(), map_h_sensor.getOrigin().getY(),
450 map_h_sensor.getOrigin().getZ());
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;
458 std::size_t img_size = h * w;
459 if (filtered_labels_.size() < img_size)
460 filtered_labels_.resize(img_size);
463 const unsigned int* labels_row = &filtered_labels_[0];
464 mesh_filter_->getFilteredLabels(&filtered_labels_[0]);
469 sensor_msgs::msg::Image debug_msg;
470 debug_msg.header = depth_msg->header;
471 debug_msg.height = h;
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);
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);
491 sensor_msgs::msg::Image label_msg;
492 label_msg.header = depth_msg->header;
493 label_msg.height = h;
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]));
501 pub_filtered_label_image_.publish(label_msg, *info_msg);
504 if (!filtered_cloud_topic_.empty())
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));
516 static std::vector<float> filtered_data;
517 if (filtered_data.size() < img_size)
518 filtered_data.resize(img_size);
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)
525 msg_data[i] =
static_cast<unsigned short>(filtered_data[i] * 1000 + 0.5);
527 pub_filtered_depth_image_.publish(filtered_msg, *info_msg);
535 const int h_bound = h - skip_vertical_pixels_;
536 const int w_bound = w - skip_horizontal_pixels_;
540 const uint16_t* input_row =
reinterpret_cast<const uint16_t*
>(&depth_msg->data[0]);
542 for (
int y = skip_vertical_pixels_; y < h_bound; ++y, labels_row += w, input_row += w)
544 for (
int x = skip_horizontal_pixels_; x < w_bound; ++x)
549 float zz =
static_cast<float>(input_row[x]) * 1e-3;
550 float yy = y_cache_[y] * zz;
551 float xx = x_cache_[x] * zz;
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()));
559 float zz = input_row[x] * 1e-3;
560 float yy = y_cache_[y] * zz;
561 float xx = x_cache_[x] * zz;
563 tf2::Vector3 point_tf = map_h_sensor * tf2::Vector3(xx, yy, zz);
565 model_cells.insert(
tree_->coordToKey(point_tf.getX(), point_tf.getY(), point_tf.getZ()));
572 const float* input_row =
reinterpret_cast<const float*
>(&depth_msg->data[0]);
574 for (
int y = skip_vertical_pixels_; y < h_bound; ++y, labels_row += w, input_row += w)
576 for (
int x = skip_horizontal_pixels_; x < w_bound; ++x)
580 float zz = input_row[x];
581 float yy = y_cache_[y] * zz;
582 float xx = x_cache_[x] * zz;
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()));
589 float zz = input_row[x];
590 float yy = y_cache_[y] * zz;
591 float xx = x_cache_[x] * zz;
593 tf2::Vector3 point_tf = map_h_sensor * tf2::Vector3(xx, yy, zz);
595 model_cells.insert(
tree_->coordToKey(point_tf.getX(), point_tf.getY(), point_tf.getZ()));
604 RCLCPP_ERROR(logger_,
"Internal error while parsing depth data");
610 for (
const octomap::OcTreeKey& model_cell : model_cells)
611 occupied_cells.erase(model_cell);
618 for (
const octomap::OcTreeKey& occupied_cell : occupied_cells)
619 tree_->updateNode(occupied_cell,
true);
623 RCLCPP_ERROR(logger_,
"Internal error while updating octree");
625 tree_->unlockWrite();
626 tree_->triggerUpdateCallback();
629 free_space_updater_->pushLazyUpdate(occupied_cells_ptr, model_cells_ptr, sensor_origin);
631 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()