42 #include <boost/algorithm/string/replace.hpp> 43 #include <log4cxx/logger.h> 48 DriverNodelet::~DriverNodelet ()
51 init_thread_.interrupt();
55 close_diagnostics_ =
true;
56 diagnostics_thread_.join();
65 void DriverNodelet::onInit ()
69 init_thread_ = boost::thread(boost::bind(&DriverNodelet::onInitImpl,
this));
72 void DriverNodelet::onInitImpl ()
89 rgb_frame_counter_ = depth_frame_counter_ = ir_frame_counter_ = 0;
90 publish_rgb_ = publish_ir_ = publish_depth_ =
true;
94 param_nh.
param(
"debug" , libfreenect_debug_,
false);
102 reconfigure_server_->setCallback(boost::bind(&DriverNodelet::configCb,
this, _1, _2));
105 param_nh.
param(
"rgb_frame_id", rgb_frame_id_,
string(
"/openni_rgb_optical_frame"));
106 param_nh.
param(
"depth_frame_id", depth_frame_id_,
string(
"/openni_depth_optical_frame"));
107 NODELET_INFO(
"rgb_frame_id = '%s' ", rgb_frame_id_.c_str());
108 NODELET_INFO(
"depth_frame_id = '%s' ", depth_frame_id_.c_str());
118 std::string serial_number = device_->getSerialNumber();
119 std::string rgb_name, ir_name;
120 if (serial_number.empty())
127 rgb_name =
"rgb_" + serial_number;
128 ir_name =
"depth_" + serial_number;
131 std::string rgb_info_url, ir_info_url;
132 param_nh.
param(
"rgb_camera_info_url", rgb_info_url, std::string());
133 param_nh.
param(
"depth_camera_info_url", ir_info_url, std::string());
135 double diagnostics_max_frequency, diagnostics_min_frequency;
136 double diagnostics_tolerance, diagnostics_window_time;
137 param_nh.
param(
"enable_rgb_diagnostics", enable_rgb_diagnostics_,
false);
138 param_nh.
param(
"enable_ir_diagnostics", enable_ir_diagnostics_,
false);
139 param_nh.
param(
"enable_depth_diagnostics", enable_depth_diagnostics_,
false);
140 param_nh.
param(
"diagnostics_max_frequency", diagnostics_max_frequency, 30.0);
141 param_nh.
param(
"diagnostics_min_frequency", diagnostics_min_frequency, 30.0);
142 param_nh.
param(
"diagnostics_tolerance", diagnostics_tolerance, 0.05);
143 param_nh.
param(
"diagnostics_window_time", diagnostics_window_time, 5.0);
146 log4cxx::LoggerPtr logger_ccp = log4cxx::Logger::getLogger(
"ros.camera_calibration_parsers");
147 log4cxx::LoggerPtr logger_cim = log4cxx::Logger::getLogger(
"ros.camera_info_manager");
148 logger_ccp->setLevel(log4cxx::Level::getFatal());
149 logger_cim->setLevel(log4cxx::Level::getWarn());
154 log4cxx::LoggerPtr logger_its = log4cxx::Logger::getLogger(
"ros.image_transport.sync");
155 logger_its->setLevel(log4cxx::Level::getError());
159 rgb_info_manager_ = boost::make_shared<camera_info_manager::CameraInfoManager>(rgb_nh, rgb_name, rgb_info_url);
160 ir_info_manager_ = boost::make_shared<camera_info_manager::CameraInfoManager>(ir_nh, ir_name, ir_info_url);
162 if (!rgb_info_manager_->isCalibrated())
163 NODELET_WARN(
"Using default parameters for RGB camera calibration.");
164 if (!ir_info_manager_->isCalibrated())
165 NODELET_WARN(
"Using default parameters for IR camera calibration.");
173 boost::lock_guard<boost::mutex> lock(connect_mutex_);
176 pub_freq_max_ = diagnostics_max_frequency;
177 pub_freq_min_ = diagnostics_min_frequency;
181 std::string hardware_id = std::string(device_->getProductName()) +
"-" +
182 std::string(device_->getSerialNumber());
183 diagnostic_updater_->setHardwareID(hardware_id);
186 if (device_->hasImageStream())
190 pub_rgb_ = rgb_it.
advertiseCamera(
"image_raw", 1, itssc, itssc, rssc, rssc);
191 if (enable_rgb_diagnostics_) {
192 pub_rgb_freq_.reset(
new TopicDiagnostic(
"RGB Image", *diagnostic_updater_,
194 diagnostics_tolerance, diagnostics_window_time)));
198 if (device_->hasIRStream())
202 pub_ir_ = ir_it.
advertiseCamera(
"image_raw", 1, itssc, itssc, rssc, rssc);
203 if (enable_ir_diagnostics_) {
204 pub_ir_freq_.reset(
new TopicDiagnostic(
"IR Image", *diagnostic_updater_,
206 diagnostics_tolerance, diagnostics_window_time)));
210 if (device_->hasDepthStream())
214 pub_depth_ = depth_it.
advertiseCamera(
"image_raw", 1, itssc, itssc, rssc, rssc);
215 if (enable_depth_diagnostics_) {
216 pub_depth_freq_.reset(
new TopicDiagnostic(
"Depth Image", *diagnostic_updater_,
218 diagnostics_tolerance, diagnostics_window_time)));
221 pub_projector_info_ = projector_nh.
advertise<sensor_msgs::CameraInfo>(
"camera_info", 1, rssc, rssc);
223 if (device_->isDepthRegistrationSupported()) {
224 pub_depth_registered_ = depth_registered_it.
advertiseCamera(
"image_raw", 1, itssc, itssc, rssc, rssc);
230 close_diagnostics_ =
false;
231 diagnostics_thread_ = boost::thread(boost::bind(&DriverNodelet::updateDiagnostics,
this));
234 param_nh.
param<
double>(
"time_out", time_out_, 5.0);
240 device_->publishersAreReady();
243 void DriverNodelet::updateDiagnostics() {
244 while (!close_diagnostics_) {
245 diagnostic_updater_->update();
246 boost::this_thread::sleep(boost::posix_time::milliseconds(10));
250 void DriverNodelet::setupDevice ()
256 if (libfreenect_debug_)
264 NODELET_INFO (
"No devices connected.... waiting for devices to be connected");
265 boost::this_thread::sleep(boost::posix_time::seconds(3));
270 for (
unsigned deviceIdx = 0; deviceIdx < driver.
getNumberDevices (); ++deviceIdx)
272 NODELET_INFO(
"%u. device on bus %03u:%02u is a %s (%03x) from %s (%03x) with serial id \'%s\'",
281 if (!getPrivateNodeHandle().getParam(
"device_id", device_id))
283 NODELET_WARN (
"~device_id is not set! Using first device.");
286 else if (device_id.find (
'@') != string::npos)
288 size_t pos = device_id.find (
'@');
289 unsigned bus = atoi (device_id.substr (0, pos).c_str ());
290 unsigned address = atoi (device_id.substr (pos + 1, device_id.length () - pos - 1).c_str ());
291 NODELET_INFO (
"Searching for device with bus@address = %d@%d", bus, address);
294 else if (device_id[0] ==
'#')
296 unsigned index = atoi (device_id.c_str() + 1);
297 NODELET_INFO (
"Searching for device with index = %d", index);
302 NODELET_INFO (
"Searching for device with serial number = '%s'", device_id.c_str ());
310 NODELET_INFO (
"No matching device found.... waiting for devices. Reason: %s", e.what ());
311 boost::this_thread::sleep(boost::posix_time::seconds(3));
316 NODELET_FATAL (
"Could not retrieve device. Reason: %s", e.what ());
322 NODELET_INFO (
"Opened '%s' on bus %d:%d with serial number '%s'", device_->getProductName (),
323 device_->getBus (), device_->getAddress (), device_->getSerialNumber ());
325 device_->registerImageCallback(&DriverNodelet::rgbCb, *
this);
326 device_->registerDepthCallback(&DriverNodelet::depthCb, *
this);
327 device_->registerIRCallback (&DriverNodelet::irCb, *
this);
330 void DriverNodelet::rgbConnectCb()
333 boost::lock_guard<boost::mutex> lock(connect_mutex_);
335 bool need_rgb = pub_rgb_.getNumSubscribers() > 0;
338 if (need_rgb && !device_->isImageStreamRunning())
341 if (device_->isIRStreamRunning())
343 NODELET_ERROR(
"Cannot stream RGB and IR at the same time. Streaming RGB only.");
344 device_->stopIRStream();
347 device_->startImageStream();
348 startSynchronization();
351 else if (!need_rgb && device_->isImageStreamRunning())
353 stopSynchronization();
354 device_->stopImageStream();
357 bool need_ir = pub_ir_.getNumSubscribers() > 0;
358 if (need_ir && !device_->isIRStreamRunning())
360 device_->startIRStream();
367 void DriverNodelet::depthConnectCb()
370 boost::lock_guard<boost::mutex> lock(connect_mutex_);
374 device_->isDepthRegistered() ? pub_depth_registered_.getNumSubscribers() > 0 : pub_depth_.getNumSubscribers() > 0;
378 if (need_depth && !device_->isDepthStreamRunning())
380 device_->startDepthStream();
381 startSynchronization();
385 else if (!need_depth && device_->isDepthStreamRunning())
387 stopSynchronization();
388 device_->stopDepthStream();
393 void DriverNodelet::irConnectCb()
395 boost::lock_guard<boost::mutex> lock(connect_mutex_);
396 bool need_ir = pub_ir_.getNumSubscribers() > 0;
398 if (need_ir && !device_->isIRStreamRunning())
401 if (device_->isImageStreamRunning())
403 NODELET_ERROR(
"Cannot stream RGB and IR at the same time. Streaming RGB only.");
407 device_->startIRStream();
413 device_->stopIRStream();
420 void DriverNodelet::checkFrameCounters()
422 if (max(rgb_frame_counter_, max(depth_frame_counter_, ir_frame_counter_)) > config_.data_skip) {
424 rgb_frame_counter_ = 0;
425 depth_frame_counter_ = 0;
426 ir_frame_counter_ = 0;
430 publish_depth_ =
true;
438 rgb_time_stamp_ = time;
440 bool publish =
false;
442 boost::unique_lock<boost::mutex> counter_lock(counter_mutex_);
443 rgb_frame_counter_++;
444 checkFrameCounters();
445 publish = publish_rgb_;
448 rgb_frame_counter_ = 0;
452 publishRgbImage(image, time);
454 publish_rgb_ =
false;
457 void DriverNodelet::depthCb(
const ImageBuffer& depth_image,
void* cookie)
460 depth_time_stamp_ = time;
462 bool publish =
false;
464 boost::unique_lock<boost::mutex> counter_lock(counter_mutex_);
465 depth_frame_counter_++;
466 checkFrameCounters();
467 publish = publish_depth_;
470 depth_frame_counter_ = 0;
474 publishDepthImage(depth_image, time);
476 publish_depth_ =
false;
479 void DriverNodelet::irCb(
const ImageBuffer& ir_image,
void* cookie)
482 ir_time_stamp_ = time;
484 bool publish =
false;
486 boost::unique_lock<boost::mutex> counter_lock(counter_mutex_);
488 checkFrameCounters();
489 publish = publish_ir_;
492 ir_frame_counter_ = 0;
496 publishIrImage(ir_image, time);
503 sensor_msgs::ImagePtr rgb_msg = boost::make_shared<sensor_msgs::Image >();
504 rgb_msg->header.stamp = time;
505 rgb_msg->header.frame_id = rgb_frame_id_;
506 rgb_msg->height = image.
metadata.height;
507 rgb_msg->width = image.
metadata.width;
508 switch(image.
metadata.video_format) {
509 case FREENECT_VIDEO_RGB:
511 rgb_msg->step = rgb_msg->width * 3;
513 case FREENECT_VIDEO_BAYER:
515 rgb_msg->step = rgb_msg->width;
517 case FREENECT_VIDEO_YUV_RGB:
519 rgb_msg->step = rgb_msg->width * 2;
522 NODELET_ERROR(
"Unknown RGB image format received from libfreenect");
526 rgb_msg->data.resize(rgb_msg->height * rgb_msg->step);
527 fillImage(image, reinterpret_cast<void*>(&rgb_msg->data[0]));
529 pub_rgb_.publish(rgb_msg, getRgbCameraInfo(image, time));
530 if (enable_rgb_diagnostics_)
531 pub_rgb_freq_->tick();
539 sensor_msgs::ImagePtr depth_msg = boost::make_shared<sensor_msgs::Image>();
540 depth_msg->header.stamp = time;
542 depth_msg->height = depth.
metadata.height;
543 depth_msg->width = depth.
metadata.width;
544 depth_msg->step = depth_msg->width *
sizeof(short);
545 depth_msg->data.resize(depth_msg->height * depth_msg->step);
547 fillImage(depth, reinterpret_cast<void*>(&depth_msg->data[0]));
549 if (z_offset_mm_ != 0)
551 uint16_t*
data =
reinterpret_cast<uint16_t*
>(&depth_msg->data[0]);
552 for (
unsigned int i = 0; i < depth_msg->width * depth_msg->height; ++i)
554 data[i] += z_offset_mm_;
560 depth_msg->header.frame_id = rgb_frame_id_;
561 pub_depth_registered_.publish(depth_msg, getRgbCameraInfo(depth, time));
566 depth_msg->header.frame_id = depth_frame_id_;
567 pub_depth_.publish(depth_msg, getDepthCameraInfo(depth, time));
569 if (enable_depth_diagnostics_)
570 pub_depth_freq_->tick();
573 if (pub_projector_info_.getNumSubscribers() > 0)
575 pub_projector_info_.publish(getProjectorCameraInfo(depth, time));
581 sensor_msgs::ImagePtr ir_msg = boost::make_shared<sensor_msgs::Image>();
582 ir_msg->header.stamp = time;
583 ir_msg->header.frame_id = depth_frame_id_;
585 ir_msg->height = ir.
metadata.height;
587 ir_msg->step = ir_msg->width *
sizeof(uint16_t);
588 ir_msg->data.resize(ir_msg->height * ir_msg->step);
590 fillImage(ir, reinterpret_cast<void*>(&ir_msg->data[0]));
592 pub_ir_.publish(ir_msg, getIrCameraInfo(ir, time));
594 if (enable_ir_diagnostics_)
595 pub_ir_freq_->tick();
598 sensor_msgs::CameraInfoPtr DriverNodelet::getDefaultCameraInfo(
int width,
int height,
double f)
const 600 sensor_msgs::CameraInfoPtr info = boost::make_shared<sensor_msgs::CameraInfo>();
603 info->height = height;
606 info->D.resize(5, 0.0);
611 info->K[0] = info->K[4] = f;
612 info->K[2] = (width / 2) - 0.5;
615 info->K[5] = (width * (3./8.)) - 0.5;
620 info->R[0] = info->R[4] = info->R[8] = 1.0;
624 info->P[0] = info->P[5] = f;
625 info->P[2] = info->K[2];
626 info->P[6] = info->K[5];
635 sensor_msgs::CameraInfoPtr info;
637 if (rgb_info_manager_->isCalibrated())
639 info = boost::make_shared<sensor_msgs::CameraInfo>(rgb_info_manager_->getCameraInfo());
648 info->header.stamp = time;
649 info->header.frame_id = rgb_frame_id_;
654 sensor_msgs::CameraInfoPtr DriverNodelet::getIrCameraInfo(
656 sensor_msgs::CameraInfoPtr info;
658 if (ir_info_manager_->isCalibrated())
660 info = boost::make_shared<sensor_msgs::CameraInfo>(ir_info_manager_->getCameraInfo());
669 info->header.stamp = time;
670 info->header.frame_id = depth_frame_id_;
675 sensor_msgs::CameraInfoPtr DriverNodelet::getDepthCameraInfo(
681 sensor_msgs::CameraInfoPtr info = getIrCameraInfo(image, time);
682 info->K[2] -= depth_ir_offset_x_;
683 info->K[5] -= depth_ir_offset_y_;
684 info->P[2] -= depth_ir_offset_x_;
685 info->P[6] -= depth_ir_offset_y_;
691 sensor_msgs::CameraInfoPtr DriverNodelet::getProjectorCameraInfo(
696 sensor_msgs::CameraInfoPtr info = getDepthCameraInfo(image, time);
698 info->P[3] = -device_->getBaseline() * info->P[0];
702 void DriverNodelet::configCb(
Config &config, uint32_t level)
704 depth_ir_offset_x_ = config.depth_ir_offset_x;
705 depth_ir_offset_y_ = config.depth_ir_offset_y;
706 z_offset_mm_ = config.z_offset_mm;
709 OutputMode old_image_mode, image_mode, compatible_image_mode;
710 if (device_->hasImageStream ())
712 old_image_mode = device_->getImageOutputMode ();
715 image_mode = mapConfigMode2OutputMode (config.image_mode);
717 if (!device_->findCompatibleImageMode (image_mode, compatible_image_mode))
719 OutputMode default_mode = device_->getDefaultImageMode();
720 NODELET_WARN(
"Could not find any compatible image output mode for %d. " 721 "Falling back to default image output mode %d.",
725 config.image_mode = mapMode2ConfigMode(default_mode);
726 image_mode = compatible_image_mode = default_mode;
730 OutputMode old_depth_mode, depth_mode, compatible_depth_mode;
731 old_depth_mode = device_->getDepthOutputMode();
732 depth_mode = mapConfigMode2OutputMode (config.depth_mode);
733 if (!device_->findCompatibleDepthMode (depth_mode, compatible_depth_mode))
735 OutputMode default_mode = device_->getDefaultDepthMode();
736 NODELET_WARN(
"Could not find any compatible depth output mode for %d. " 737 "Falling back to default depth output mode %d.",
741 config.depth_mode = mapMode2ConfigMode(default_mode);
742 depth_mode = compatible_depth_mode = default_mode;
746 if ( (device_->hasImageStream () && compatible_image_mode != old_image_mode) ||
747 compatible_depth_mode != old_depth_mode)
750 stopSynchronization();
752 if (device_->hasImageStream () && compatible_image_mode != old_image_mode)
753 device_->setImageOutputMode (compatible_image_mode);
755 if (compatible_depth_mode != old_depth_mode)
756 device_->setDepthOutputMode (compatible_depth_mode);
758 startSynchronization ();
762 if (device_->isDepthRegistered () && !config.depth_registration)
764 device_->setDepthRegistration (
false);
766 else if (!device_->isDepthRegistered () && config.depth_registration)
768 device_->setDepthRegistration (
true);
775 void DriverNodelet::startSynchronization()
777 if (device_->isSynchronizationSupported() &&
778 !device_->isSynchronized() &&
779 device_->isImageStreamRunning() &&
780 device_->isDepthStreamRunning() )
782 device_->setSynchronization(
true);
786 void DriverNodelet::stopSynchronization()
788 if (device_->isSynchronizationSupported() &&
789 device_->isSynchronized())
791 device_->setSynchronization(
false);
795 void DriverNodelet::updateModeMaps ()
799 output_mode = FREENECT_RESOLUTION_HIGH;
800 mode2config_map_[output_mode] = Freenect_SXGA;
801 config2mode_map_[Freenect_SXGA] = output_mode;
803 output_mode = FREENECT_RESOLUTION_MEDIUM;
804 mode2config_map_[output_mode] = Freenect_VGA;
805 config2mode_map_[Freenect_VGA] = output_mode;
808 int DriverNodelet::mapMode2ConfigMode (
const OutputMode& output_mode)
const 810 std::map<OutputMode, int>::const_iterator it = mode2config_map_.find (output_mode);
812 if (it == mode2config_map_.end ())
821 OutputMode DriverNodelet::mapConfigMode2OutputMode (
int mode)
const 823 std::map<int, OutputMode>::const_iterator it = config2mode_map_.find (mode);
824 if (it == config2mode_map_.end ())
835 bool timed_out =
false;
836 if (!rgb_time_stamp_.isZero() && device_->isImageStreamRunning()) {
838 timed_out = timed_out || duration.
toSec() > time_out_;
840 if (!depth_time_stamp_.isZero() && device_->isDepthStreamRunning()) {
842 timed_out = timed_out || duration.
toSec() > time_out_;
844 if (!ir_time_stamp_.isZero() && device_->isIRStreamRunning()) {
846 timed_out = timed_out || duration.
toSec() > time_out_;
850 ROS_INFO(
"Device timed out. Flushing device.");
851 device_->flushDeviceStreams();
const std::string BAYER_GRBG8
unsigned getAddress(unsigned device_idx)
void fillImage(const ImageBuffer &buffer, void *data)
boost::function< void(const SingleSubscriberPublisher &)> SubscriberStatusCallback
#define NODELET_ERROR(...)
boost::shared_ptr< FreenectDevice > getDeviceByIndex(unsigned device_idx)
ROSCONSOLE_DECL void notifyLoggerLevelsChanged()
#define NODELET_WARN(...)
boost::function< void(const SingleSubscriberPublisher &)> SubscriberStatusCallback
boost::shared_ptr< FreenectDevice > getDeviceByAddress(unsigned bus, unsigned address)
freenect_resolution OutputMode
unsigned getBus(unsigned device_idx)
CameraPublisher advertiseCamera(const std::string &base_topic, uint32_t queue_size, bool latch=false)
Holds an image buffer with all the metadata required to transmit the image over ROS channels...
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
dynamic_reconfigure::Server< Config > ReconfigureServer
const std::string PLUMB_BOB
unsigned getVendorID(unsigned device_idx)
const std::string TYPE_16UC1
Timer createTimer(Rate r, Handler h, Obj o, bool oneshot=false, bool autostart=true) const
unsigned getProductID(unsigned device_idx)
boost::shared_ptr< FreenectDevice > getDeviceBySerialNumber(std::string serial)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
const char * getSerialNumber(unsigned device_idx)
const char * getVendorName(unsigned device_idx)
#define NODELET_INFO(...)
const char * getProductName(unsigned device_idx)
#define NODELET_FATAL(...)
unsigned getNumberDevices()
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
freenect_frame_mode metadata