21 #include <sensor_msgs/CompressedImage.h> 22 #include <sensor_msgs/Image.h> 23 #include <sensor_msgs/PointCloud2.h> 26 #include <ifm3d_ros_msgs/Config.h> 27 #include <ifm3d_ros_msgs/Dump.h> 28 #include <ifm3d_ros_msgs/Extrinsics.h> 29 #include <ifm3d_ros_msgs/SoftOff.h> 30 #include <ifm3d_ros_msgs/SoftOn.h> 31 #include <ifm3d_ros_msgs/Trigger.h> 33 #include <ifm3d/contrib/nlohmann/json.hpp> 37 const std_msgs::Header& header,
const std::string& logger)
39 static constexpr
auto max_pixel_format =
static_cast<std::size_t
>(ifm3d::pixel_format::FORMAT_32F3);
40 static auto image_format_info = [] {
41 auto image_format_info = std::array<std::string, max_pixel_format + 1>{};
44 using namespace ifm3d;
46 image_format_info[
static_cast<std::size_t
>(pixel_format::FORMAT_8U)] =
TYPE_8UC1;
47 image_format_info[
static_cast<std::size_t
>(pixel_format::FORMAT_8S)] =
TYPE_8SC1;
48 image_format_info[
static_cast<std::size_t
>(pixel_format::FORMAT_16U)] =
TYPE_16UC1;
49 image_format_info[
static_cast<std::size_t
>(pixel_format::FORMAT_16S)] =
TYPE_16SC1;
50 image_format_info[
static_cast<std::size_t
>(pixel_format::FORMAT_32U)] =
"32UC1";
51 image_format_info[
static_cast<std::size_t
>(pixel_format::FORMAT_32S)] =
TYPE_32SC1;
52 image_format_info[
static_cast<std::size_t
>(pixel_format::FORMAT_32F)] =
TYPE_32FC1;
53 image_format_info[
static_cast<std::size_t
>(pixel_format::FORMAT_64U)] =
"64UC1";
54 image_format_info[
static_cast<std::size_t
>(pixel_format::FORMAT_64F)] =
TYPE_64FC1;
55 image_format_info[
static_cast<std::size_t
>(pixel_format::FORMAT_16U2)] =
TYPE_16UC2;
56 image_format_info[
static_cast<std::size_t
>(pixel_format::FORMAT_32F3)] =
TYPE_32FC3;
59 return image_format_info;
62 const auto format =
static_cast<std::size_t
>(image.dataFormat());
64 sensor_msgs::Image result{};
65 result.header = header;
66 result.height = image.height();
67 result.width = image.width();
68 result.is_bigendian = 0;
70 if (image.begin<std::uint8_t>() == image.end<std::uint8_t>())
75 if (format >= max_pixel_format)
77 ROS_ERROR_NAMED(logger,
"Pixel format out of range (%ld >= %ld)", format, max_pixel_format);
81 result.encoding = image_format_info.at(format);
83 result.data.insert(result.data.end(), image.ptr<>(0), std::next(image.ptr<>(0), result.step * result.height));
85 if (result.encoding.empty())
87 ROS_WARN_NAMED(logger,
"Can't handle encoding %ld (32U == %ld, 64U == %ld)", format,
88 static_cast<std::size_t>(ifm3d::pixel_format::FORMAT_32U),
89 static_cast<std::size_t>(ifm3d::pixel_format::FORMAT_64U));
96 sensor_msgs::Image
ifm3d_to_ros_image(ifm3d::Image&& image,
const std_msgs::Header& header,
const std::string& logger)
104 const std_msgs::Header& header,
105 const std::string& format,
106 const std::string& logger)
108 sensor_msgs::CompressedImage result{};
109 result.header = header;
110 result.format = format;
113 const auto dataFormat = image.dataFormat();
114 if (dataFormat != ifm3d::pixel_format::FORMAT_8S && dataFormat != ifm3d::pixel_format::FORMAT_8U)
116 ROS_ERROR_NAMED(logger,
"Invalid data format for %s data (%ld)", format.c_str(),
117 static_cast<std::size_t
>(dataFormat));
122 result.data.insert(result.data.end(), image.ptr<>(0), std::next(image.ptr<>(0), image.width() * image.height()));
127 const std::string& format,
const std::string& logger)
134 const std_msgs::Header& header,
const std::string& logger)
136 sensor_msgs::PointCloud2 result{};
137 result.header = header;
138 result.height = image.height();
139 result.width = image.width();
140 result.is_bigendian =
false;
142 if (image.begin<std::uint8_t>() == image.end<std::uint8_t>())
147 if (image.dataFormat() != ifm3d::pixel_format::FORMAT_32F3 && image.dataFormat() != ifm3d::pixel_format::FORMAT_32F)
149 ROS_ERROR_NAMED(logger,
"Unsupported pixel format %ld for point cloud",
150 static_cast<std::size_t>(image.dataFormat()));
154 sensor_msgs::PointField x_field{};
157 x_field.datatype = sensor_msgs::PointField::FLOAT32;
160 sensor_msgs::PointField y_field{};
163 y_field.datatype = sensor_msgs::PointField::FLOAT32;
166 sensor_msgs::PointField z_field{};
169 z_field.datatype = sensor_msgs::PointField::FLOAT32;
178 result.point_step = result.fields.size() *
sizeof(float);
179 result.row_step = result.point_step * result.width;
180 result.is_dense =
true;
181 result.data.insert(result.data.end(), image.ptr<>(0), std::next(image.ptr<>(0), result.row_step * result.height));
187 const std::string& logger)
197 std::string nn = this->
getName();
200 this->np_ = getMTPrivateNodeHandle();
212 std::string frame_id_base;
214 if ((nn.size() > 0) && (nn.at(0) ==
'/'))
216 frame_id_base = nn.substr(1);
223 this->np_.param(
"ip", this->camera_ip_, ifm3d::DEFAULT_IP);
224 NODELET_INFO(
"IP default: %s, current %s", ifm3d::DEFAULT_IP.c_str(), this->camera_ip_.c_str());
226 this->np_.param(
"xmlrpc_port", xmlrpc_port, (
int)ifm3d::DEFAULT_XMLRPC_PORT);
227 this->np_.param(
"pcic_port", pcic_port, (
int)ifm3d::DEFAULT_PCIC_PORT);
228 NODELET_INFO(
"pcic port check: current %d, default %d", pcic_port, ifm3d::DEFAULT_PCIC_PORT);
230 this->np_.param(
"password", this->password_, ifm3d::DEFAULT_PASSWORD);
231 this->np_.param(
"schema_mask", schema_mask, (
int)ifm3d::DEFAULT_SCHEMA_MASK);
232 this->np_.param(
"timeout_millis", this->timeout_millis_, 500);
233 this->np_.param(
"timeout_tolerance_secs", this->timeout_tolerance_secs_, 5.0);
234 this->np_.param(
"assume_sw_triggered", this->assume_sw_triggered_,
false);
235 this->np_.param(
"soft_on_timeout_millis", this->soft_on_timeout_millis_, 500);
236 this->np_.param(
"soft_on_timeout_tolerance_secs", this->soft_on_timeout_tolerance_secs_, 5.0);
237 this->np_.param(
"soft_off_timeout_millis", this->soft_off_timeout_millis_, 500);
238 this->np_.param(
"soft_off_timeout_tolerance_secs", this->soft_off_timeout_tolerance_secs_, 600.0);
239 this->np_.param(
"frame_latency_thresh", this->frame_latency_thresh_, 60.0
f);
240 this->np_.param(
"frame_id_base", frame_id_base, frame_id_base);
242 this->xmlrpc_port_ =
static_cast<std::uint16_t
>(xmlrpc_port);
243 this->schema_mask_ =
static_cast<std::uint16_t
>(schema_mask);
244 this->pcic_port_ =
static_cast<std::uint16_t
>(pcic_port);
248 this->frame_id_ = frame_id_base +
"_link";
249 this->optical_frame_id_ = frame_id_base +
"_optical_link";
254 this->cloud_pub_ = this->np_.advertise<sensor_msgs::PointCloud2>(
"cloud", 1);
255 this->distance_pub_ = this->it_->advertise(
"distance", 1);
256 this->distance_noise_pub_ = this->it_->advertise(
"distance_noise", 1);
257 this->amplitude_pub_ = this->it_->advertise(
"amplitude", 1);
258 this->raw_amplitude_pub_ = this->it_->advertise(
"raw_amplitude", 1);
259 this->conf_pub_ = this->it_->advertise(
"confidence", 1);
260 this->gray_image_pub_ = this->it_->advertise(
"gray_image", 1);
261 this->rgb_image_pub_ = this->np_.advertise<sensor_msgs::CompressedImage>(
"rgb_image/compressed", 1);
264 this->uvec_pub_ = this->np_.advertise<sensor_msgs::Image>(
"unit_vectors", 1,
true);
266 this->extrinsics_pub_ = this->np_.advertise<ifm3d_ros_msgs::Extrinsics>(
"extrinsics", 1);
271 this->dump_srv_ = this->np_.advertiseService<ifm3d_ros_msgs::Dump::Request, ifm3d_ros_msgs::Dump::Response>(
272 "Dump", std::bind(&CameraNodelet::Dump,
this, std::placeholders::_1, std::placeholders::_2));
274 this->config_srv_ = this->np_.advertiseService<ifm3d_ros_msgs::Config::Request, ifm3d_ros_msgs::Config::Response>(
275 "Config", std::bind(&CameraNodelet::Config,
this, std::placeholders::_1, std::placeholders::_2));
277 this->trigger_srv_ = this->np_.advertiseService<ifm3d_ros_msgs::Trigger::Request, ifm3d_ros_msgs::Trigger::Response>(
278 "Trigger", std::bind(&CameraNodelet::Trigger,
this, std::placeholders::_1, std::placeholders::_2));
280 this->soft_off_srv_ = this->np_.advertiseService<ifm3d_ros_msgs::SoftOff::Request, ifm3d_ros_msgs::SoftOff::Response>(
281 "SoftOff", std::bind(&CameraNodelet::SoftOff,
this, std::placeholders::_1, std::placeholders::_2));
283 this->soft_on_srv_ = this->np_.advertiseService<ifm3d_ros_msgs::SoftOn::Request, ifm3d_ros_msgs::SoftOn::Response>(
284 "SoftOn", std::bind(&CameraNodelet::SoftOn,
this, std::placeholders::_1, std::placeholders::_2));
286 NODELET_DEBUG_STREAM(
"after advertise service");
290 this->publoop_timer_ = this->np_.createTimer(
297 std::lock_guard<std::mutex> lock(this->mutex_);
302 json j = this->cam_->ToJSON();
303 res.config = j.dump();
305 catch (
const ifm3d::error_t& ex)
307 res.status = ex.code();
310 catch (
const std::exception& std_ex)
330 std::lock_guard<std::mutex> lock(this->mutex_);
336 this->cam_->FromJSON(json::parse(req.json));
338 catch (
const ifm3d::error_t& ex)
340 res.status = ex.code();
343 catch (
const std::exception& std_ex)
346 res.msg = std_ex.what();
351 res.msg =
"Unknown error in `Config'";
364 std::lock_guard<std::mutex> lock(this->mutex_);
366 res.msg =
"Software trigger is currently not implemented";
370 this->fg_->SWTrigger();
372 catch (
const ifm3d::error_t& ex)
374 res.status = ex.code();
377 NODELET_WARN_STREAM(
"Triggering a camera head is currently not implemented - will follow");
385 std::lock_guard<std::mutex> lock(this->mutex_);
392 port_arg =
static_cast<int>(this->pcic_port_) % 50010;
395 this->cam_->FromJSONStr(
"{\"ports\":{\"port" + std::to_string(port_arg) +
"\": {\"state\": \"IDLE\"}}}");
397 this->assume_sw_triggered_ =
false;
398 this->timeout_millis_ = this->soft_on_timeout_millis_;
399 this->timeout_tolerance_secs_ = this->soft_on_timeout_tolerance_secs_;
401 catch (
const ifm3d::error_t& ex)
403 res.status = ex.code();
408 NODELET_WARN_STREAM(
"The concept of applications is not available for the O3R - we use IDLE and RUN states instead");
409 res.msg =
"{\"ports\":{\"port" + std::to_string(port_arg) +
"\": {\"state\": \"IDLE\"}}}";
418 std::lock_guard<std::mutex> lock(this->mutex_);
424 port_arg =
static_cast<int>(this->pcic_port_) % 50010;
443 this->cam_->FromJSONStr(
"{\"ports\":{\"port" + std::to_string(port_arg) +
"\": {\"state\": \"RUN\"}}}");
445 this->assume_sw_triggered_ =
false;
446 this->timeout_millis_ = this->soft_on_timeout_millis_;
447 this->timeout_tolerance_secs_ = this->soft_on_timeout_tolerance_secs_;
449 catch (
const ifm3d::error_t& ex)
451 res.status = ex.code();
456 NODELET_WARN_STREAM(
"The concept of applications is not available for the O3R - we use IDLE and RUN states instead");
457 res.msg =
"{\"ports\":{\"port" + std::to_string(port_arg) +
"\": {\"state\": \"RUN\"}}}";
464 std::lock_guard<std::mutex> lock(this->mutex_);
475 this->cam_ = ifm3d::CameraBase::MakeShared(this->camera_ip_, this->xmlrpc_port_);
479 this->fg_ = std::make_shared<ifm3d::FrameGrabber>(this->cam_, mask, this->pcic_port_);
480 NODELET_INFO(
"Nodelet arguments: %d, %d", (
int)mask, (
int)this->pcic_port_);
483 this->im_ = std::make_shared<ifm3d::StlImageBuffer>();
487 catch (
const ifm3d::error_t& ex)
502 std::lock_guard<std::mutex> lock(this->mutex_);
507 retval = this->fg_->WaitForFrame(this->im_.get(), this->timeout_millis_);
509 catch (
const ifm3d::error_t& ex)
520 std::unique_lock<std::mutex> lock(this->mutex_, std::defer_lock);
527 while (
ros::ok() && (!this->InitStructures(ifm3d::IMG_UVEC, this->pcic_port_)))
533 ifm3d::Image confidence_img;
534 ifm3d::Image distance_img;
535 ifm3d::Image distance_noise_img;
536 ifm3d::Image amplitude_img;
537 ifm3d::Image xyz_img;
538 ifm3d::Image raw_amplitude_img;
539 ifm3d::Image gray_img;
540 ifm3d::Image rgb_img;
543 std::vector<float> extrinsics(6);
549 bool got_uvec =
false;
553 if (!this->AcquireFrame())
555 if (!this->assume_sw_triggered_)
564 if ((
ros::Time::now() - last_frame).toSec() > this->timeout_tolerance_secs_)
567 while (!this->InitStructures(got_uvec ? this->schema_mask_ : ifm3d::IMG_UVEC, this->pcic_port_))
582 std_msgs::Header head = std_msgs::Header();
583 head.frame_id = this->frame_id_;
584 head.stamp =
ros::Time(std::chrono::duration_cast<std::chrono::duration<
double, std::ratio<1>>>(
585 this->im_->TimeStamp().time_since_epoch())
593 std_msgs::Header optical_head = std_msgs::Header();
594 optical_head.stamp = head.stamp;
595 optical_head.frame_id = this->optical_frame_id_;
606 this->uvec_pub_.publish(uvec_msg);
608 NODELET_INFO(
"Got unit vectors, restarting framegrabber with mask: %d", (
int)this->schema_mask_);
610 while (!this->InitStructures(this->schema_mask_, this->pcic_port_))
616 NODELET_INFO_STREAM(
"Start streaming data");
629 xyz_img = this->im_->XYZImage();
630 confidence_img = this->im_->ConfidenceImage();
631 distance_img = this->im_->DistanceImage();
632 distance_noise_img = this->im_->DistanceNoiseImage();
633 amplitude_img = this->im_->AmplitudeImage();
634 raw_amplitude_img = this->im_->RawAmplitudeImage();
635 gray_img = this->im_->GrayImage();
636 extrinsics = this->im_->Extrinsics();
637 rgb_img = this->im_->JPEGImage();
639 catch (
const ifm3d::error_t& ex)
643 catch (
const std::exception& std_ex)
655 NODELET_DEBUG_STREAM(
"start publishing");
658 NODELET_DEBUG_STREAM(
"after publishing confidence image");
660 if ((this->schema_mask_ & ifm3d::IMG_CART) == ifm3d::IMG_CART)
663 NODELET_DEBUG_STREAM(
"after publishing xyz image");
666 if ((this->schema_mask_ & ifm3d::IMG_RDIS) == ifm3d::IMG_RDIS)
669 NODELET_DEBUG_STREAM(
"after publishing distance image");
672 if ((this->schema_mask_ & ifm3d::IMG_DIS_NOISE) == ifm3d::IMG_DIS_NOISE)
675 NODELET_DEBUG_STREAM(
"after publishing distance noise image");
678 if ((this->schema_mask_ & ifm3d::IMG_AMP) == ifm3d::IMG_AMP)
681 NODELET_DEBUG_STREAM(
"after publishing amplitude image");
684 if ((this->schema_mask_ & ifm3d::IMG_RAMP) == ifm3d::IMG_RAMP)
687 NODELET_DEBUG_STREAM(
"Raw amplitude image publisher is a dummy publisher - data will be added soon");
688 NODELET_DEBUG_STREAM(
"after publishing raw amplitude image");
691 if ((this->schema_mask_ & ifm3d::IMG_GRAY) == ifm3d::IMG_GRAY)
694 NODELET_DEBUG_STREAM(
"Gray image publisher is a dummy publisher - data will be added soon");
695 NODELET_DEBUG_STREAM(
"after publishing gray image");
700 if (rgb_img.height() * rgb_img.width() > 0)
703 NODELET_DEBUG_STREAM(
"after publishing rgb image");
709 NODELET_DEBUG_STREAM(
"start publishing extrinsics");
710 ifm3d_ros_msgs::Extrinsics extrinsics_msg;
711 extrinsics_msg.header = optical_head;
714 extrinsics_msg.tx = extrinsics.at(0);
715 extrinsics_msg.ty = extrinsics.at(1);
716 extrinsics_msg.tz = extrinsics.at(2);
717 extrinsics_msg.rot_x = extrinsics.at(3);
718 extrinsics_msg.rot_y = extrinsics.at(4);
719 extrinsics_msg.rot_z = extrinsics.at(5);
721 catch (
const std::out_of_range& ex)
725 this->extrinsics_pub_.publish(extrinsics_msg);
#define NODELET_INFO_STREAM(...)
#define NODELET_INFO_ONCE(...)
#define NODELET_WARN(...)
sensor_msgs::CompressedImage ifm3d_to_ros_compressed_image(ifm3d::Image &image, const std_msgs::Header &header, const std::string &format, const std::string &logger)
#define ROS_WARN_NAMED(name,...)
bool Dump(ifm3d_ros_msgs::Dump::Request &req, ifm3d_ros_msgs::Dump::Response &res)
ROSCONSOLE_CONSOLE_IMPL_DECL std::string getName(void *handle)
const std::string TYPE_8UC1
#define NODELET_WARN_STREAM(...)
bool Trigger(ifm3d_ros_msgs::Trigger::Request &req, ifm3d_ros_msgs::Trigger::Response &res)
sensor_msgs::Image ifm3d_to_ros_image(ifm3d::Image &image, const std_msgs::Header &header, const std::string &logger)
bool SoftOff(ifm3d_ros_msgs::SoftOff::Request &req, ifm3d_ros_msgs::SoftOff::Response &res)
bool InitStructures(std::uint16_t mask, std::uint16_t pcic_port)
const std::string TYPE_32FC1
sensor_msgs::PointCloud2 ifm3d_to_ros_cloud(ifm3d::Image &image, const std_msgs::Header &header, const std::string &logger)
bool SoftOn(ifm3d_ros_msgs::SoftOn::Request &req, ifm3d_ros_msgs::SoftOn::Response &res)
const std::string TYPE_16UC1
const std::string TYPE_8SC1
#define NODELET_DEBUG_STREAM(...)
const std::string TYPE_16UC2
const std::string TYPE_64FC1
#define NODELET_INFO(...)
#define ROS_ERROR_NAMED(name,...)
const std::string TYPE_32FC3
static int bitDepth(const std::string &encoding)
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
const std::string TYPE_32SC1
bool Config(ifm3d_ros_msgs::Config::Request &req, ifm3d_ros_msgs::Config::Response &res)
const std::string TYPE_16SC1