00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <cstdint>
00018 #include <functional>
00019 #include <memory>
00020 #include <mutex>
00021 #include <sstream>
00022 #include <stdexcept>
00023 #include <string>
00024 #include <vector>
00025 #include <cv_bridge/cv_bridge.h>
00026 #include <image_transport/image_transport.h>
00027 #include <opencv2/opencv.hpp>
00028 #include <pcl_conversions/pcl_conversions.h>
00029 #include <pcl_ros/point_cloud.h>
00030 #include <ros/ros.h>
00031 #include <sensor_msgs/Image.h>
00032 #include <sensor_msgs/image_encodings.h>
00033 #include <o3d3xx_camera.h>
00034 #include <o3d3xx_framegrabber.h>
00035 #include <o3d3xx_image.h>
00036 #include <o3d3xx/Config.h>
00037 #include <o3d3xx/Dump.h>
00038 #include <o3d3xx/GetVersion.h>
00039 #include <o3d3xx/Rm.h>
00040 #include <o3d3xx/Extrinsics.h>
00041 #include <o3d3xx/Trigger.h>
00042
00043 class O3D3xxNode
00044 {
00045 public:
00046 O3D3xxNode()
00047 : schema_mask_(o3d3xx::DEFAULT_SCHEMA_MASK),
00048 timeout_millis_(500),
00049 timeout_tolerance_secs_(5.0),
00050 publish_viz_images_(false),
00051 assume_sw_triggered_(false),
00052 spinner_(new ros::AsyncSpinner(1))
00053 {
00054 std::string camera_ip;
00055 int xmlrpc_port;
00056 std::string password;
00057 int schema_mask;
00058 std::string frame_id_base;
00059
00060 ros::NodeHandle nh;
00061 ros::NodeHandle np("~");
00062
00063 np.param("ip", camera_ip, o3d3xx::DEFAULT_IP);
00064 np.param("xmlrpc_port", xmlrpc_port, (int) o3d3xx::DEFAULT_XMLRPC_PORT);
00065 np.param("password", password, o3d3xx::DEFAULT_PASSWORD);
00066 np.param("schema_mask", schema_mask, (int) o3d3xx::DEFAULT_SCHEMA_MASK);
00067 np.param("timeout_millis", this->timeout_millis_, 500);
00068 np.param("timeout_tolerance_secs", this->timeout_tolerance_secs_, 5.0);
00069 np.param("publish_viz_images", this->publish_viz_images_, false);
00070 np.param("assume_sw_triggered", this->assume_sw_triggered_, false);
00071 np.param("frame_id_base", frame_id_base,
00072 std::string(ros::this_node::getName()).substr(1));
00073
00074 this->schema_mask_ = static_cast<std::uint16_t>(schema_mask);
00075
00076 this->frame_id_ = frame_id_base + "_link";
00077 this->optical_frame_id_ = frame_id_base + "_optical_link";
00078
00079
00080
00081
00082 this->cam_ =
00083 std::make_shared<o3d3xx::Camera>(camera_ip, xmlrpc_port, password);
00084
00085
00086
00087
00088 this->fg_ =
00089 std::make_shared<o3d3xx::FrameGrabber>(this->cam_, o3d3xx::IMG_UVEC);
00090
00091
00092
00093
00094 this->cloud_pub_ =
00095 nh.advertise<pcl::PointCloud<o3d3xx::PointT> >("cloud", 1);
00096
00097 image_transport::ImageTransport it(nh);
00098 this->depth_pub_ = it.advertise("depth", 1);
00099 this->depth_viz_pub_ = it.advertise("depth_viz", 1);
00100 this->amplitude_pub_ = it.advertise("amplitude", 1);
00101 this->raw_amplitude_pub_ = it.advertise("raw_amplitude", 1);
00102 this->conf_pub_ = it.advertise("confidence", 1);
00103 this->good_bad_pub_ = it.advertise("good_bad_pixels", 1);
00104 this->xyz_image_pub_ = it.advertise("xyz_image", 1);
00105
00106
00107
00108
00109 this->uvec_pub_ =
00110 nh.advertise<sensor_msgs::Image>("unit_vectors", 1, true);
00111
00112 this->extrinsics_pub_ = nh.advertise<o3d3xx::Extrinsics>("extrinsics", 1);
00113
00114
00115
00116
00117 this->version_srv_ =
00118 nh.advertiseService<o3d3xx::GetVersion::Request,
00119 o3d3xx::GetVersion::Response>
00120 ("GetVersion", std::bind(&O3D3xxNode::GetVersion, this,
00121 std::placeholders::_1,
00122 std::placeholders::_2));
00123
00124 this->dump_srv_ =
00125 nh.advertiseService<o3d3xx::Dump::Request, o3d3xx::Dump::Response>
00126 ("Dump", std::bind(&O3D3xxNode::Dump, this,
00127 std::placeholders::_1,
00128 std::placeholders::_2));
00129
00130 this->config_srv_ =
00131 nh.advertiseService<o3d3xx::Config::Request, o3d3xx::Config::Response>
00132 ("Config", std::bind(&O3D3xxNode::Config, this,
00133 std::placeholders::_1,
00134 std::placeholders::_2));
00135
00136 this->rm_srv_ =
00137 nh.advertiseService<o3d3xx::Rm::Request, o3d3xx::Rm::Response>
00138 ("Rm", std::bind(&O3D3xxNode::Rm, this,
00139 std::placeholders::_1,
00140 std::placeholders::_2));
00141
00142 this->trigger_srv_ =
00143 nh.advertiseService<o3d3xx::Trigger::Request, o3d3xx::Trigger::Response>
00144 ("Trigger", std::bind(&O3D3xxNode::Trigger, this,
00145 std::placeholders::_1,
00146 std::placeholders::_2));
00147 }
00148
00152 void Run()
00153 {
00154 std::unique_lock<std::mutex> fg_lock(this->fg_mutex_, std::defer_lock);
00155 this->spinner_->start();
00156
00157 o3d3xx::ImageBuffer::Ptr buff =
00158 std::make_shared<o3d3xx::ImageBuffer>();
00159
00160 pcl::PointCloud<o3d3xx::PointT>::Ptr
00161 cloud(new pcl::PointCloud<o3d3xx::PointT>());
00162
00163 cv::Mat confidence_img;
00164 cv::Mat depth_img;
00165 cv::Mat depth_viz_img;
00166 double min, max;
00167
00168 std::vector<float> extrinsics(6);
00169
00170 ros::Time last_frame = ros::Time::now();
00171
00172 bool got_uvec = false;
00173
00174 while (ros::ok())
00175 {
00176 fg_lock.lock();
00177 if (!this->fg_->WaitForFrame(buff.get(), this->timeout_millis_))
00178 {
00179 fg_lock.unlock();
00180 if (! this->assume_sw_triggered_)
00181 {
00182 ROS_WARN("Timeout waiting for camera!");
00183 }
00184 else
00185 {
00186 ros::Duration(.001).sleep();
00187 }
00188
00189 if ((ros::Time::now() - last_frame).toSec() >
00190 this->timeout_tolerance_secs_)
00191 {
00192 ROS_WARN("Attempting to restart frame grabber...");
00193 fg_lock.lock();
00194 if (got_uvec)
00195 {
00196 this->fg_.reset(new o3d3xx::FrameGrabber(this->cam_,
00197 this->schema_mask_));
00198 }
00199 else
00200 {
00201 this->fg_.reset(new o3d3xx::FrameGrabber(this->cam_,
00202 o3d3xx::IMG_UVEC));
00203 }
00204 fg_lock.unlock();
00205 last_frame = ros::Time::now();
00206 }
00207 continue;
00208 }
00209 fg_lock.unlock();
00210
00211 std_msgs::Header head = std_msgs::Header();
00212 head.stamp = ros::Time::now();
00213 head.frame_id = this->frame_id_;
00214 last_frame = head.stamp;
00215
00216 std_msgs::Header optical_head = std_msgs::Header();
00217 optical_head.stamp = head.stamp;
00218 optical_head.frame_id = this->optical_frame_id_;
00219
00220
00221
00222 if (! got_uvec)
00223 {
00224 sensor_msgs::ImagePtr uvec_msg =
00225 cv_bridge::CvImage(optical_head,
00226 sensor_msgs::image_encodings::TYPE_32FC3,
00227 buff->UnitVectors()).toImageMsg();
00228 this->uvec_pub_.publish(uvec_msg);
00229
00230 ROS_INFO("Got unit vectors, restarting framegrabber with mask: %d",
00231 (int) this->schema_mask_);
00232
00233 fg_lock.lock();
00234 got_uvec = true;
00235 this->fg_.reset(new o3d3xx::FrameGrabber(this->cam_,
00236 this->schema_mask_));
00237 fg_lock.unlock();
00238
00239 continue;
00240 }
00241
00242
00243 pcl::copyPointCloud(*(buff->Cloud().get()), *cloud);
00244 cloud->header = pcl_conversions::toPCL(head);
00245 this->cloud_pub_.publish(cloud);
00246
00247 depth_img = buff->DepthImage();
00248 sensor_msgs::ImagePtr depth =
00249 cv_bridge::CvImage(optical_head,
00250 "mono16",
00251 depth_img).toImageMsg();
00252 this->depth_pub_.publish(depth);
00253
00254 sensor_msgs::ImagePtr amplitude =
00255 cv_bridge::CvImage(optical_head,
00256 "mono16",
00257 buff->AmplitudeImage()).toImageMsg();
00258 this->amplitude_pub_.publish(amplitude);
00259
00260 sensor_msgs::ImagePtr raw_amplitude =
00261 cv_bridge::CvImage(optical_head,
00262 "mono16",
00263 buff->RawAmplitudeImage()).toImageMsg();
00264 this->raw_amplitude_pub_.publish(raw_amplitude);
00265
00266 confidence_img = buff->ConfidenceImage();
00267 sensor_msgs::ImagePtr confidence =
00268 cv_bridge::CvImage(optical_head,
00269 "mono8",
00270 confidence_img).toImageMsg();
00271 this->conf_pub_.publish(confidence);
00272
00273 sensor_msgs::ImagePtr xyz_image_msg =
00274 cv_bridge::CvImage(head,
00275 sensor_msgs::image_encodings::TYPE_16SC3,
00276 buff->XYZImage()).toImageMsg();
00277 this->xyz_image_pub_.publish(xyz_image_msg);
00278
00279 extrinsics = buff->Extrinsics();
00280 o3d3xx::Extrinsics extrinsics_msg;
00281 extrinsics_msg.header = optical_head;
00282 try
00283 {
00284 extrinsics_msg.tx = extrinsics.at(0);
00285 extrinsics_msg.ty = extrinsics.at(1);
00286 extrinsics_msg.tz = extrinsics.at(2);
00287 extrinsics_msg.rot_x = extrinsics.at(3);
00288 extrinsics_msg.rot_y = extrinsics.at(4);
00289 extrinsics_msg.rot_z = extrinsics.at(5);
00290 }
00291 catch (const std::out_of_range& ex)
00292 {
00293 ROS_WARN("out-of-range error fetching extrinsics");
00294 }
00295 this->extrinsics_pub_.publish(extrinsics_msg);
00296
00297 if (this->publish_viz_images_)
00298 {
00299
00300 cv::minMaxIdx(depth_img, &min, &max);
00301 cv::convertScaleAbs(depth_img, depth_viz_img, 255 / max);
00302 cv::applyColorMap(depth_viz_img, depth_viz_img, cv::COLORMAP_JET);
00303 sensor_msgs::ImagePtr depth_viz =
00304 cv_bridge::CvImage(optical_head,
00305 "bgr8",
00306 depth_viz_img).toImageMsg();
00307 this->depth_viz_pub_.publish(depth_viz);
00308
00309
00310 cv::Mat good_bad_map = cv::Mat::ones(confidence_img.rows,
00311 confidence_img.cols,
00312 CV_8UC1);
00313 cv::bitwise_and(confidence_img, good_bad_map,
00314 good_bad_map);
00315 good_bad_map *= 255;
00316 sensor_msgs::ImagePtr good_bad =
00317 cv_bridge::CvImage(optical_head,
00318 "mono8",
00319 good_bad_map).toImageMsg();
00320 this->good_bad_pub_.publish(good_bad);
00321 }
00322 }
00323 }
00324
00331 bool GetVersion(o3d3xx::GetVersion::Request &req,
00332 o3d3xx::GetVersion::Response &res)
00333 {
00334 int major, minor, patch;
00335 o3d3xx::version(&major, &minor, &patch);
00336
00337 std::ostringstream ss;
00338 ss << O3D3XX_LIBRARY_NAME
00339 << ": " << major << "." << minor << "." << patch;
00340
00341 res.version = ss.str();
00342 return true;
00343 }
00344
00352 bool Trigger(o3d3xx::Trigger::Request &req,
00353 o3d3xx::Trigger::Response &res)
00354 {
00355 std::lock_guard<std::mutex> lock(this->fg_mutex_);
00356 res.status = 0;
00357
00358 try
00359 {
00360 this->fg_->SWTrigger();
00361 }
00362 catch (const o3d3xx::error_t& ex)
00363 {
00364 res.status = ex.code();
00365 }
00366
00367 return true;
00368 }
00369
00377 bool Dump(o3d3xx::Dump::Request &req,
00378 o3d3xx::Dump::Response &res)
00379 {
00380 std::lock_guard<std::mutex> lock(this->fg_mutex_);
00381 res.status = 0;
00382
00383 try
00384 {
00385 res.config = this->cam_->ToJSON();
00386 }
00387 catch (const o3d3xx::error_t& ex)
00388 {
00389 res.status = ex.code();
00390 }
00391
00392 this->fg_.reset(new o3d3xx::FrameGrabber(this->cam_, this->schema_mask_));
00393 return true;
00394 }
00395
00407 bool Config(o3d3xx::Config::Request &req,
00408 o3d3xx::Config::Response &res)
00409 {
00410 std::lock_guard<std::mutex> lock(this->fg_mutex_);
00411 res.status = 0;
00412 res.msg = "OK";
00413
00414 try
00415 {
00416 this->cam_->FromJSON(req.json);
00417 }
00418 catch (const o3d3xx::error_t& ex)
00419 {
00420 res.status = ex.code();
00421 res.msg = ex.what();
00422 }
00423 catch (const std::exception& std_ex)
00424 {
00425 res.status = -1;
00426 res.msg = std_ex.what();
00427 }
00428
00429 this->fg_.reset(new o3d3xx::FrameGrabber(this->cam_, this->schema_mask_));
00430 return true;
00431 }
00432
00439 bool Rm(o3d3xx::Rm::Request &req,
00440 o3d3xx::Rm::Response &res)
00441 {
00442 std::lock_guard<std::mutex> lock(this->fg_mutex_);
00443 res.status = 0;
00444 res.msg = "OK";
00445
00446 try
00447 {
00448 if (req.index > 0)
00449 {
00450 this->cam_->RequestSession();
00451 this->cam_->SetOperatingMode(o3d3xx::Camera::operating_mode::EDIT);
00452 o3d3xx::DeviceConfig::Ptr dev = this->cam_->GetDeviceConfig();
00453
00454 if (dev->ActiveApplication() != req.index)
00455 {
00456 this->cam_->DeleteApplication(req.index);
00457 }
00458 else
00459 {
00460 res.status = -1;
00461 res.msg = std::string("Cannot delete active application!");
00462 }
00463 }
00464 }
00465 catch (const o3d3xx::error_t& ex)
00466 {
00467 res.status = ex.code();
00468 res.msg = ex.what();
00469 }
00470 catch (const std::exception& std_ex)
00471 {
00472 res.status = -1;
00473 res.msg = std_ex.what();
00474 }
00475
00476 this->cam_->CancelSession();
00477 this->fg_.reset(new o3d3xx::FrameGrabber(this->cam_, this->schema_mask_));
00478 return true;
00479 }
00480
00481
00482 private:
00483 std::uint16_t schema_mask_;
00484 int timeout_millis_;
00485 double timeout_tolerance_secs_;
00486 bool publish_viz_images_;
00487 bool assume_sw_triggered_;
00488 std::unique_ptr<ros::AsyncSpinner> spinner_;
00489 o3d3xx::Camera::Ptr cam_;
00490 o3d3xx::FrameGrabber::Ptr fg_;
00491 std::mutex fg_mutex_;
00492
00493 std::string frame_id_;
00494 std::string optical_frame_id_;
00495
00496 ros::Publisher cloud_pub_;
00497 ros::Publisher uvec_pub_;
00498 ros::Publisher extrinsics_pub_;
00499 image_transport::Publisher depth_pub_;
00500 image_transport::Publisher depth_viz_pub_;
00501 image_transport::Publisher amplitude_pub_;
00502 image_transport::Publisher raw_amplitude_pub_;
00503 image_transport::Publisher conf_pub_;
00504 image_transport::Publisher good_bad_pub_;
00505 image_transport::Publisher xyz_image_pub_;
00506
00507 ros::ServiceServer version_srv_;
00508 ros::ServiceServer dump_srv_;
00509 ros::ServiceServer config_srv_;
00510 ros::ServiceServer rm_srv_;
00511 ros::ServiceServer trigger_srv_;
00512
00513 };
00514
00515 int main(int argc, char **argv)
00516 {
00517 o3d3xx::Logging::Init();
00518 ros::init(argc, argv, "o3d3xx");
00519 O3D3xxNode().Run();
00520 return 0;
00521 }