openni2_driver.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2013, Willow Garage, Inc.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of the Willow Garage, Inc. nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  *
00029  *      Author: Julius Kammerl (jkammerl@willowgarage.com)
00030  */
00031 
00032 #include "openni2_camera/openni2_driver.h"
00033 #include "openni2_camera/openni2_exception.h"
00034 
00035 #include <sensor_msgs/image_encodings.h>
00036 #include <sensor_msgs/distortion_models.h>
00037 
00038 #include <boost/date_time/posix_time/posix_time.hpp>
00039 #include <boost/thread/thread.hpp>
00040 
00041 namespace openni2_wrapper
00042 {
00043 
00044 OpenNI2Driver::OpenNI2Driver(ros::NodeHandle& n, ros::NodeHandle& pnh) :
00045     nh_(n),
00046     pnh_(pnh),
00047     device_manager_(OpenNI2DeviceManager::getSingelton()),
00048     config_init_(false),
00049     data_skip_ir_counter_(0),
00050     data_skip_color_counter_(0),
00051     data_skip_depth_counter_ (0),
00052     ir_subscribers_(false),
00053     color_subscribers_(false),
00054     depth_subscribers_(false),
00055     depth_raw_subscribers_(false),
00056     enable_reconnect_(false)
00057 {
00058 
00059   genVideoModeTableMap();
00060 
00061   readConfigFromParameterServer();
00062 
00063   initDevice();
00064 
00065   // Initialize dynamic reconfigure
00066   reconfigure_server_.reset(new ReconfigureServer(pnh_));
00067   reconfigure_server_->setCallback(boost::bind(&OpenNI2Driver::configCb, this, _1, _2));
00068 
00069   while (!config_init_)
00070   {
00071     ROS_DEBUG("Waiting for dynamic reconfigure configuration.");
00072     boost::this_thread::sleep(boost::posix_time::milliseconds(100));
00073   }
00074   ROS_DEBUG("Dynamic reconfigure configuration received.");
00075 
00076   advertiseROSTopics();
00077 
00078   if( enable_reconnect_ )
00079   {
00080     ROS_WARN_STREAM("Reconnect has been enabled, only one camera "
00081                     << "should be plugged into each bus");
00082     timer_ = nh_.createTimer(ros::Duration(1.0), &OpenNI2Driver::monitorConnection, this);
00083   }
00084   else
00085   {
00086     ROS_WARN_STREAM("Reconnect has been disabled");
00087   }
00088 }
00089 
00090 void OpenNI2Driver::advertiseROSTopics()
00091 {
00092 
00093   // Allow remapping namespaces rgb, ir, depth, depth_registered
00094   ros::NodeHandle color_nh(nh_, "rgb");
00095   image_transport::ImageTransport color_it(color_nh);
00096   ros::NodeHandle ir_nh(nh_, "ir");
00097   image_transport::ImageTransport ir_it(ir_nh);
00098   ros::NodeHandle depth_nh(nh_, "depth");
00099   image_transport::ImageTransport depth_it(depth_nh);
00100   ros::NodeHandle depth_raw_nh(nh_, "depth");
00101   image_transport::ImageTransport depth_raw_it(depth_raw_nh);
00102   ros::NodeHandle projector_nh(nh_, "projector");
00103   // Advertise all published topics
00104 
00105   // Prevent connection callbacks from executing until we've set all the publishers. Otherwise
00106   // connectCb() can fire while we're advertising (say) "depth/image_raw", but before we actually
00107   // assign to pub_depth_raw_. Then pub_depth_raw_.getNumSubscribers() returns 0, and we fail to start
00108   // the depth generator.
00109   boost::lock_guard<boost::mutex> lock(connect_mutex_);
00110 
00111   // Asus Xtion PRO does not have an RGB camera
00112   if (device_->hasColorSensor())
00113   {
00114     image_transport::SubscriberStatusCallback itssc = boost::bind(&OpenNI2Driver::colorConnectCb, this);
00115     ros::SubscriberStatusCallback rssc = boost::bind(&OpenNI2Driver::colorConnectCb, this);
00116     pub_color_ = color_it.advertiseCamera("image", 1, itssc, itssc, rssc, rssc);
00117   }
00118 
00119   if (device_->hasIRSensor())
00120   {
00121     image_transport::SubscriberStatusCallback itssc = boost::bind(&OpenNI2Driver::irConnectCb, this);
00122     ros::SubscriberStatusCallback rssc = boost::bind(&OpenNI2Driver::irConnectCb, this);
00123     pub_ir_ = ir_it.advertiseCamera("image", 1, itssc, itssc, rssc, rssc);
00124   }
00125 
00126   if (device_->hasDepthSensor())
00127   {
00128     image_transport::SubscriberStatusCallback itssc = boost::bind(&OpenNI2Driver::depthConnectCb, this);
00129     ros::SubscriberStatusCallback rssc = boost::bind(&OpenNI2Driver::depthConnectCb, this);
00130     pub_depth_raw_ = depth_it.advertiseCamera("image_raw", 1, itssc, itssc, rssc, rssc);
00131     pub_depth_ = depth_raw_it.advertiseCamera("image", 1, itssc, itssc, rssc, rssc);
00132     pub_projector_info_ = projector_nh.advertise<sensor_msgs::CameraInfo>("camera_info", 1, rssc, rssc);
00133   }
00134 
00136 
00137   // Pixel offset between depth and IR images.
00138   // By default assume offset of (5,4) from 9x7 correlation window.
00139   // NOTE: These are now (temporarily?) dynamically reconfigurable, to allow tweaking.
00140   //param_nh.param("depth_ir_offset_x", depth_ir_offset_x_, 5.0);
00141   //param_nh.param("depth_ir_offset_y", depth_ir_offset_y_, 4.0);
00142 
00143   // The camera names are set to [rgb|depth]_[serial#], e.g. depth_B00367707227042B.
00144   // camera_info_manager substitutes this for ${NAME} in the URL.
00145   std::string serial_number = device_->getStringID();
00146   std::string color_name, ir_name;
00147 
00148   color_name = "rgb_"   + serial_number;
00149   ir_name  = "depth_" + serial_number;
00150 
00151   // Load the saved calibrations, if they exist
00152   color_info_manager_ = boost::make_shared<camera_info_manager::CameraInfoManager>(color_nh, color_name, color_info_url_);
00153   ir_info_manager_  = boost::make_shared<camera_info_manager::CameraInfoManager>(ir_nh,  ir_name,  ir_info_url_);
00154 
00155   get_serial_server = nh_.advertiseService("get_serial", &OpenNI2Driver::getSerialCb,this);
00156 
00157 }
00158 
00159 bool OpenNI2Driver::getSerialCb(openni2_camera::GetSerialRequest& req, openni2_camera::GetSerialResponse& res) {
00160   res.serial = device_manager_->getSerial(device_->getUri());
00161   return true;
00162 }
00163 
00164 void OpenNI2Driver::configCb(Config &config, uint32_t level)
00165 {
00166   bool stream_reset = false;
00167 
00168   depth_ir_offset_x_ = config.depth_ir_offset_x;
00169   depth_ir_offset_y_ = config.depth_ir_offset_y;
00170   z_offset_mm_ = config.z_offset_mm;
00171   z_scaling_ = config.z_scaling;
00172 
00173   ir_time_offset_ = ros::Duration(config.ir_time_offset);
00174   color_time_offset_ = ros::Duration(config.color_time_offset);
00175   depth_time_offset_ = ros::Duration(config.depth_time_offset);
00176 
00177   if (lookupVideoModeFromDynConfig(config.ir_mode, ir_video_mode_)<0)
00178   {
00179     ROS_ERROR("Undefined IR video mode received from dynamic reconfigure");
00180     exit(-1);
00181   }
00182 
00183   if (lookupVideoModeFromDynConfig(config.color_mode, color_video_mode_)<0)
00184   {
00185     ROS_ERROR("Undefined color video mode received from dynamic reconfigure");
00186     exit(-1);
00187   }
00188 
00189   if (lookupVideoModeFromDynConfig(config.depth_mode, depth_video_mode_)<0)
00190   {
00191     ROS_ERROR("Undefined depth video mode received from dynamic reconfigure");
00192     exit(-1);
00193   }
00194 
00195   // assign pixel format
00196 
00197   ir_video_mode_.pixel_format_ = PIXEL_FORMAT_GRAY16;
00198   color_video_mode_.pixel_format_ = PIXEL_FORMAT_RGB888;
00199   depth_video_mode_.pixel_format_ = PIXEL_FORMAT_DEPTH_1_MM;
00200 
00201   color_depth_synchronization_ = config.color_depth_synchronization;
00202   depth_registration_ = config.depth_registration;
00203 
00204   auto_exposure_ = config.auto_exposure;
00205   auto_white_balance_ = config.auto_white_balance;
00206   exposure_ = config.exposure;
00207 
00208   use_device_time_ = config.use_device_time;
00209 
00210   data_skip_ = config.data_skip+1;
00211 
00212   applyConfigToOpenNIDevice();
00213 
00214   config_init_ = true;
00215 
00216   old_config_ = config;
00217 }
00218 
00219 void OpenNI2Driver::setIRVideoMode(const OpenNI2VideoMode& ir_video_mode)
00220 {
00221   if (device_->isIRVideoModeSupported(ir_video_mode))
00222   {
00223     if (ir_video_mode != device_->getIRVideoMode())
00224     {
00225       device_->setIRVideoMode(ir_video_mode);
00226     }
00227 
00228   }
00229   else
00230   {
00231     ROS_ERROR_STREAM("Unsupported IR video mode - " << ir_video_mode);
00232   }
00233 }
00234 void OpenNI2Driver::setColorVideoMode(const OpenNI2VideoMode& color_video_mode)
00235 {
00236   if (device_->isColorVideoModeSupported(color_video_mode))
00237   {
00238     if (color_video_mode != device_->getColorVideoMode())
00239     {
00240       device_->setColorVideoMode(color_video_mode);
00241     }
00242   }
00243   else
00244   {
00245     ROS_ERROR_STREAM("Unsupported color video mode - " << color_video_mode);
00246   }
00247 }
00248 void OpenNI2Driver::setDepthVideoMode(const OpenNI2VideoMode& depth_video_mode)
00249 {
00250   if (device_->isDepthVideoModeSupported(depth_video_mode))
00251   {
00252     if (depth_video_mode != device_->getDepthVideoMode())
00253     {
00254       device_->setDepthVideoMode(depth_video_mode);
00255     }
00256   }
00257   else
00258   {
00259     ROS_ERROR_STREAM("Unsupported depth video mode - " << depth_video_mode);
00260   }
00261 }
00262 
00263 void OpenNI2Driver::applyConfigToOpenNIDevice()
00264 {
00265 
00266   data_skip_ir_counter_ = 0;
00267   data_skip_color_counter_= 0;
00268   data_skip_depth_counter_ = 0;
00269 
00270   setIRVideoMode(ir_video_mode_);
00271   setColorVideoMode(color_video_mode_);
00272   setDepthVideoMode(depth_video_mode_);
00273 
00274   if (device_->isImageRegistrationModeSupported())
00275   {
00276     try
00277     {
00278       if (!config_init_ || (old_config_.depth_registration != depth_registration_))
00279         device_->setImageRegistrationMode(depth_registration_);
00280     }
00281     catch (const OpenNI2Exception& exception)
00282     {
00283       ROS_ERROR("Could not set image registration. Reason: %s", exception.what());
00284     }
00285   }
00286 
00287   try
00288   {
00289     if (!config_init_ || (old_config_.color_depth_synchronization != color_depth_synchronization_))
00290       device_->setDepthColorSync(color_depth_synchronization_);
00291   }
00292   catch (const OpenNI2Exception& exception)
00293   {
00294     ROS_ERROR("Could not set color depth synchronization. Reason: %s", exception.what());
00295   }
00296 
00297   try
00298   {
00299     if (!config_init_ || (old_config_.auto_exposure != auto_exposure_))
00300       device_->setAutoExposure(auto_exposure_);
00301   }
00302   catch (const OpenNI2Exception& exception)
00303   {
00304     ROS_ERROR("Could not set auto exposure. Reason: %s", exception.what());
00305   }
00306 
00307   try
00308   {
00309     if (!config_init_ || (old_config_.auto_white_balance != auto_white_balance_))
00310       device_->setAutoWhiteBalance(auto_white_balance_);
00311   }
00312   catch (const OpenNI2Exception& exception)
00313   {
00314     ROS_ERROR("Could not set auto white balance. Reason: %s", exception.what());
00315   }
00316 
00317 
00318   // Workaound for https://github.com/ros-drivers/openni2_camera/issues/51
00319   // This is only needed when any of the 3 setting change.  For simplicity
00320   // this check is always performed and exposure set.
00321   if( (!auto_exposure_ && !auto_white_balance_) && exposure_ != 0 )
00322   {
00323     ROS_INFO_STREAM("Forcing exposure set, when auto exposure/white balance disabled");
00324     forceSetExposure();
00325   }
00326   else
00327   {
00328     // Setting the exposure the old way, although this should not have an effect
00329     try
00330     {
00331       if (!config_init_ || (old_config_.exposure != exposure_))
00332         device_->setExposure(exposure_);
00333     }
00334     catch (const OpenNI2Exception& exception)
00335     {
00336       ROS_ERROR("Could not set exposure. Reason: %s", exception.what());
00337     }
00338   }
00339 
00340   device_->setUseDeviceTimer(use_device_time_);
00341 }
00342 
00343 
00344 
00345 void OpenNI2Driver::forceSetExposure()
00346 {
00347   int current_exposure_ = device_->getExposure();
00348   try
00349   {
00350     if( current_exposure_ == exposure_ )
00351     {
00352       if( exposure_ < 254 )
00353       {
00354         device_->setExposure(exposure_ + 1);
00355       }
00356       else
00357       {
00358         device_->setExposure(exposure_ - 1);
00359       }
00360     }
00361     device_->setExposure(exposure_);
00362   }
00363   catch (const OpenNI2Exception& exception)
00364   {
00365     ROS_ERROR("Could not set exposure. Reason: %s", exception.what());
00366   }
00367 }
00368 
00369 void OpenNI2Driver::colorConnectCb()
00370 {
00371   if( !device_ )
00372   {
00373     ROS_WARN_STREAM("Callback in " << __FUNCTION__ <<  "failed due to null device");
00374     return;
00375   }
00376   boost::lock_guard<boost::mutex> lock(connect_mutex_);
00377 
00378   color_subscribers_ = pub_color_.getNumSubscribers() > 0;
00379 
00380   if (color_subscribers_ && !device_->isColorStreamStarted())
00381   {
00382     // Can't stream IR and RGB at the same time. Give RGB preference.
00383     if (device_->isIRStreamStarted())
00384     {
00385       ROS_ERROR("Cannot stream RGB and IR at the same time. Streaming RGB only.");
00386       ROS_INFO("Stopping IR stream.");
00387       device_->stopIRStream();
00388     }
00389 
00390     device_->setColorFrameCallback(boost::bind(&OpenNI2Driver::newColorFrameCallback, this, _1));
00391 
00392     ROS_INFO("Starting color stream.");
00393     device_->startColorStream();
00394 
00395     // Workaound for https://github.com/ros-drivers/openni2_camera/issues/51
00396     if( exposure_ != 0 )
00397     {
00398       ROS_INFO_STREAM("Exposure is set to " << exposure_ << ", forcing on color stream start");
00399         //delay for stream to start, before setting exposure
00400       boost::this_thread::sleep(boost::posix_time::milliseconds(100));
00401       forceSetExposure();
00402     }
00403 
00404   }
00405   else if (!color_subscribers_ && device_->isColorStreamStarted())
00406   {
00407     ROS_INFO("Stopping color stream.");
00408     device_->stopColorStream();
00409 
00410     // Start IR if it's been blocked on RGB subscribers
00411     bool need_ir = pub_ir_.getNumSubscribers() > 0;
00412     if (need_ir && !device_->isIRStreamStarted())
00413     {
00414       device_->setIRFrameCallback(boost::bind(&OpenNI2Driver::newIRFrameCallback, this, _1));
00415 
00416       ROS_INFO("Starting IR stream.");
00417       device_->startIRStream();
00418     }
00419   }
00420 }
00421 
00422 void OpenNI2Driver::depthConnectCb()
00423 {
00424   if( !device_ )
00425   {
00426     ROS_WARN_STREAM("Callback in " << __FUNCTION__ <<  "failed due to null device");
00427     return;
00428   }
00429   boost::lock_guard<boost::mutex> lock(connect_mutex_);
00430 
00431   depth_subscribers_ = pub_depth_.getNumSubscribers() > 0;
00432   depth_raw_subscribers_ = pub_depth_raw_.getNumSubscribers() > 0;
00433   projector_info_subscribers_ = pub_projector_info_.getNumSubscribers() > 0;
00434 
00435   bool need_depth = depth_subscribers_ || depth_raw_subscribers_;
00436 
00437   if (need_depth && !device_->isDepthStreamStarted())
00438   {
00439     device_->setDepthFrameCallback(boost::bind(&OpenNI2Driver::newDepthFrameCallback, this, _1));
00440 
00441     ROS_INFO("Starting depth stream.");
00442     device_->startDepthStream();
00443   }
00444   else if (!need_depth && device_->isDepthStreamStarted())
00445   {
00446     ROS_INFO("Stopping depth stream.");
00447     device_->stopDepthStream();
00448   }
00449 }
00450 
00451 void OpenNI2Driver::irConnectCb()
00452 {
00453   if( !device_ )
00454   {
00455     ROS_WARN_STREAM("Callback in " << __FUNCTION__ <<  "failed due to null device");
00456     return;
00457   }
00458   boost::lock_guard<boost::mutex> lock(connect_mutex_);
00459 
00460   ir_subscribers_ = pub_ir_.getNumSubscribers() > 0;
00461 
00462   if (ir_subscribers_ && !device_->isIRStreamStarted())
00463   {
00464     // Can't stream IR and RGB at the same time
00465     if (device_->isColorStreamStarted())
00466     {
00467       ROS_ERROR("Cannot stream RGB and IR at the same time. Streaming RGB only.");
00468     }
00469     else
00470     {
00471       device_->setIRFrameCallback(boost::bind(&OpenNI2Driver::newIRFrameCallback, this, _1));
00472 
00473       ROS_INFO("Starting IR stream.");
00474       device_->startIRStream();
00475     }
00476   }
00477   else if (!ir_subscribers_ && device_->isIRStreamStarted())
00478   {
00479     ROS_INFO("Stopping IR stream.");
00480     device_->stopIRStream();
00481   }
00482 }
00483 
00484 void OpenNI2Driver::newIRFrameCallback(sensor_msgs::ImagePtr image)
00485 {
00486   if ((++data_skip_ir_counter_)%data_skip_==0)
00487   {
00488     data_skip_ir_counter_ = 0;
00489 
00490     if (ir_subscribers_)
00491     {
00492       image->header.frame_id = ir_frame_id_;
00493       image->header.stamp = image->header.stamp + ir_time_offset_;
00494 
00495       pub_ir_.publish(image, getIRCameraInfo(image->width, image->height, image->header.stamp));
00496     }
00497   }
00498 }
00499 
00500 void OpenNI2Driver::newColorFrameCallback(sensor_msgs::ImagePtr image)
00501 {
00502   if ((++data_skip_color_counter_)%data_skip_==0)
00503   {
00504     data_skip_color_counter_ = 0;
00505 
00506     if (color_subscribers_)
00507     {
00508       image->header.frame_id = color_frame_id_;
00509       image->header.stamp = image->header.stamp + color_time_offset_;
00510 
00511       pub_color_.publish(image, getColorCameraInfo(image->width, image->height, image->header.stamp));
00512     }
00513   }
00514 }
00515 
00516 void OpenNI2Driver::newDepthFrameCallback(sensor_msgs::ImagePtr image)
00517 {
00518   if ((++data_skip_depth_counter_)%data_skip_==0)
00519   {
00520 
00521     data_skip_depth_counter_ = 0;
00522 
00523     if (depth_raw_subscribers_||depth_subscribers_||projector_info_subscribers_)
00524     {
00525       image->header.stamp = image->header.stamp + depth_time_offset_;
00526 
00527       if (z_offset_mm_ != 0)
00528       {
00529         uint16_t* data = reinterpret_cast<uint16_t*>(&image->data[0]);
00530         for (unsigned int i = 0; i < image->width * image->height; ++i)
00531           if (data[i] != 0)
00532                 data[i] += z_offset_mm_;
00533       }
00534 
00535       if (fabs(z_scaling_ - 1.0) > 1e-6)
00536       {
00537         uint16_t* data = reinterpret_cast<uint16_t*>(&image->data[0]);
00538         for (unsigned int i = 0; i < image->width * image->height; ++i)
00539           if (data[i] != 0)
00540                 data[i] = static_cast<uint16_t>(data[i] * z_scaling_);
00541       }
00542 
00543       sensor_msgs::CameraInfoPtr cam_info;
00544 
00545       if (depth_registration_)
00546       {
00547         image->header.frame_id = color_frame_id_;
00548         cam_info = getColorCameraInfo(image->width,image->height, image->header.stamp);
00549       } else
00550       {
00551         image->header.frame_id = depth_frame_id_;
00552         cam_info = getDepthCameraInfo(image->width,image->height, image->header.stamp);
00553       }
00554 
00555       if (depth_raw_subscribers_)
00556       {
00557         pub_depth_raw_.publish(image, cam_info);
00558       }
00559 
00560       if (depth_subscribers_ )
00561       {
00562         sensor_msgs::ImageConstPtr floating_point_image = rawToFloatingPointConversion(image);
00563         pub_depth_.publish(floating_point_image, cam_info);
00564       }
00565 
00566       // Projector "info" probably only useful for working with disparity images
00567       if (projector_info_subscribers_)
00568       {
00569         pub_projector_info_.publish(getProjectorCameraInfo(image->width, image->height, image->header.stamp));
00570       }
00571     }
00572   }
00573 }
00574 
00575 // Methods to get calibration parameters for the various cameras
00576 sensor_msgs::CameraInfoPtr OpenNI2Driver::getDefaultCameraInfo(int width, int height, double f) const
00577 {
00578   sensor_msgs::CameraInfoPtr info = boost::make_shared<sensor_msgs::CameraInfo>();
00579 
00580   info->width  = width;
00581   info->height = height;
00582 
00583   // No distortion
00584   info->D.resize(5, 0.0);
00585   info->distortion_model = sensor_msgs::distortion_models::PLUMB_BOB;
00586 
00587   // Simple camera matrix: square pixels (fx = fy), principal point at center
00588   info->K.assign(0.0);
00589   info->K[0] = info->K[4] = f;
00590   info->K[2] = (width / 2) - 0.5;
00591   // Aspect ratio for the camera center on Kinect (and other devices?) is 4/3
00592   // This formula keeps the principal point the same in VGA and SXGA modes
00593   info->K[5] = (width * (3./8.)) - 0.5;
00594   info->K[8] = 1.0;
00595 
00596   // No separate rectified image plane, so R = I
00597   info->R.assign(0.0);
00598   info->R[0] = info->R[4] = info->R[8] = 1.0;
00599 
00600   // Then P=K(I|0) = (K|0)
00601   info->P.assign(0.0);
00602   info->P[0]  = info->P[5] = f; // fx, fy
00603   info->P[2]  = info->K[2];     // cx
00604   info->P[6]  = info->K[5];     // cy
00605   info->P[10] = 1.0;
00606 
00607   return info;
00608 }
00609 
00611 sensor_msgs::CameraInfoPtr OpenNI2Driver::getColorCameraInfo(int width, int height, ros::Time time) const
00612 {
00613   sensor_msgs::CameraInfoPtr info;
00614 
00615   if (color_info_manager_->isCalibrated())
00616   {
00617     info = boost::make_shared<sensor_msgs::CameraInfo>(color_info_manager_->getCameraInfo());
00618     if ( info->width != width )
00619     {
00620       // Use uncalibrated values
00621       ROS_WARN_ONCE("Image resolution doesn't match calibration of the RGB camera. Using default parameters.");
00622       info = getDefaultCameraInfo(width, height, device_->getColorFocalLength(height));
00623     }
00624   }
00625   else
00626   {
00627     // If uncalibrated, fill in default values
00628     info = getDefaultCameraInfo(width, height, device_->getColorFocalLength(height));
00629   }
00630 
00631   // Fill in header
00632   info->header.stamp    = time;
00633   info->header.frame_id = color_frame_id_;
00634 
00635   return info;
00636 }
00637 
00638 
00639 sensor_msgs::CameraInfoPtr OpenNI2Driver::getIRCameraInfo(int width, int height, ros::Time time) const
00640 {
00641   sensor_msgs::CameraInfoPtr info;
00642 
00643   if (ir_info_manager_->isCalibrated())
00644   {
00645     info = boost::make_shared<sensor_msgs::CameraInfo>(ir_info_manager_->getCameraInfo());
00646     if ( info->width != width )
00647     {
00648       // Use uncalibrated values
00649       ROS_WARN_ONCE("Image resolution doesn't match calibration of the IR camera. Using default parameters.");
00650       info = getDefaultCameraInfo(width, height, device_->getIRFocalLength(height));
00651     }
00652   }
00653   else
00654   {
00655     // If uncalibrated, fill in default values
00656     info = getDefaultCameraInfo(width, height, device_->getDepthFocalLength(height));
00657   }
00658 
00659   // Fill in header
00660   info->header.stamp    = time;
00661   info->header.frame_id = depth_frame_id_;
00662 
00663   return info;
00664 }
00665 
00666 sensor_msgs::CameraInfoPtr OpenNI2Driver::getDepthCameraInfo(int width, int height, ros::Time time) const
00667 {
00668   // The depth image has essentially the same intrinsics as the IR image, BUT the
00669   // principal point is offset by half the size of the hardware correlation window
00670   // (probably 9x9 or 9x7 in 640x480 mode). See http://www.ros.org/wiki/kinect_calibration/technical
00671 
00672   double scaling = (double)width / 640;
00673 
00674   sensor_msgs::CameraInfoPtr info = getIRCameraInfo(width, height, time);
00675   info->K[2] -= depth_ir_offset_x_*scaling; // cx
00676   info->K[5] -= depth_ir_offset_y_*scaling; // cy
00677   info->P[2] -= depth_ir_offset_x_*scaling; // cx
00678   info->P[6] -= depth_ir_offset_y_*scaling; // cy
00679 
00681   return info;
00682 }
00683 
00684 sensor_msgs::CameraInfoPtr OpenNI2Driver::getProjectorCameraInfo(int width, int height, ros::Time time) const
00685 {
00686   // The projector info is simply the depth info with the baseline encoded in the P matrix.
00687   // It's only purpose is to be the "right" camera info to the depth camera's "left" for
00688   // processing disparity images.
00689   sensor_msgs::CameraInfoPtr info = getDepthCameraInfo(width, height, time);
00690   // Tx = -baseline * fx
00691   info->P[3] = -device_->getBaseline() * info->P[0];
00692   return info;
00693 }
00694 
00695 void OpenNI2Driver::readConfigFromParameterServer()
00696 {
00697   if (!pnh_.getParam("device_id", device_id_))
00698   {
00699     ROS_WARN ("~device_id is not set! Using first device.");
00700     device_id_ = "#1";
00701   }
00702 
00703   // Camera TF frames
00704   pnh_.param("ir_frame_id", ir_frame_id_, std::string("/openni_ir_optical_frame"));
00705   pnh_.param("rgb_frame_id", color_frame_id_, std::string("/openni_rgb_optical_frame"));
00706   pnh_.param("depth_frame_id", depth_frame_id_, std::string("/openni_depth_optical_frame"));
00707 
00708   ROS_DEBUG("ir_frame_id = '%s' ", ir_frame_id_.c_str());
00709   ROS_DEBUG("rgb_frame_id = '%s' ", color_frame_id_.c_str());
00710   ROS_DEBUG("depth_frame_id = '%s' ", depth_frame_id_.c_str());
00711 
00712   pnh_.param("rgb_camera_info_url", color_info_url_, std::string());
00713   pnh_.param("depth_camera_info_url", ir_info_url_, std::string());
00714 
00715   pnh_.param("enable_reconnect", enable_reconnect_, true);
00716 
00717 }
00718 
00719 std::string OpenNI2Driver::resolveDeviceURI(const std::string& device_id) throw(OpenNI2Exception)
00720 {
00721   // retrieve available device URIs, they look like this: "1d27/0601@1/5"
00722   // which is <vendor ID>/<product ID>@<bus number>/<device number>
00723   boost::shared_ptr<std::vector<std::string> > available_device_URIs =
00724     device_manager_->getConnectedDeviceURIs();
00725 
00726   // look for '#<number>' format
00727   if (device_id.size() > 1 && device_id[0] == '#')
00728   {
00729     std::istringstream device_number_str(device_id.substr(1));
00730     int device_number;
00731     device_number_str >> device_number;
00732     int device_index = device_number - 1; // #1 refers to first device
00733     if (device_index >= available_device_URIs->size() || device_index < 0)
00734     {
00735       THROW_OPENNI_EXCEPTION(
00736           "Invalid device number %i, there are %zu devices connected.",
00737           device_number, available_device_URIs->size());
00738     }
00739     else
00740     {
00741       return available_device_URIs->at(device_index);
00742     }
00743   }
00744   // look for '<bus>@<number>' format
00745   //   <bus>    is usb bus id, typically start at 1
00746   //   <number> is the device number, for consistency with openni_camera, these start at 1
00747   //               although 0 specifies "any device on this bus"
00748   else if (device_id.size() > 1 && device_id.find('@') != std::string::npos && device_id.find('/') == std::string::npos)
00749   {
00750     // get index of @ character
00751     size_t index = device_id.find('@');
00752     if (index <= 0)
00753     {
00754       THROW_OPENNI_EXCEPTION(
00755         "%s is not a valid device URI, you must give the bus number before the @.",
00756         device_id.c_str());
00757     }
00758     if (index >= device_id.size() - 1)
00759     {
00760       THROW_OPENNI_EXCEPTION(
00761         "%s is not a valid device URI, you must give the device number after the @, specify 0 for any device on this bus",
00762         device_id.c_str());
00763     }
00764 
00765     // pull out device number on bus
00766     std::istringstream device_number_str(device_id.substr(index+1));
00767     int device_number;
00768     device_number_str >> device_number;
00769 
00770     // reorder to @<bus>
00771     std::string bus = device_id.substr(0, index);
00772     bus.insert(0, "@");
00773 
00774     for (size_t i = 0; i < available_device_URIs->size(); ++i)
00775     {
00776       std::string s = (*available_device_URIs)[i];
00777       if (s.find(bus) != std::string::npos)
00778       {
00779         // this matches our bus, check device number
00780         std::ostringstream ss;
00781         ss << bus << '/' << device_number;
00782         if (device_number == 0 || s.find(ss.str()) != std::string::npos)
00783           return s;
00784       }
00785     }
00786 
00787     THROW_OPENNI_EXCEPTION("Device not found %s", device_id.c_str());
00788   }
00789   else
00790   {
00791     // check if the device id given matches a serial number of a connected device
00792     for(std::vector<std::string>::const_iterator it = available_device_URIs->begin();
00793         it != available_device_URIs->end(); ++it)
00794     {
00795       try {
00796         std::string serial = device_manager_->getSerial(*it);
00797         if (serial.size() > 0 && device_id == serial)
00798           return *it;
00799       }
00800       catch (const OpenNI2Exception& exception)
00801       {
00802         ROS_WARN("Could not query serial number of device \"%s\":", exception.what());
00803       }
00804     }
00805 
00806     // everything else is treated as part of the device_URI
00807     bool match_found = false;
00808     std::string matched_uri;
00809     for (size_t i = 0; i < available_device_URIs->size(); ++i)
00810     {
00811       std::string s = (*available_device_URIs)[i];
00812       if (s.find(device_id) != std::string::npos)
00813       {
00814         if (!match_found)
00815         {
00816           matched_uri = s;
00817           match_found = true;
00818         }
00819         else
00820         {
00821           // more than one match
00822           THROW_OPENNI_EXCEPTION("Two devices match the given device id '%s': %s and %s.", device_id.c_str(), matched_uri.c_str(), s.c_str());
00823         }
00824       }
00825     }
00826     if (match_found)
00827       return matched_uri;
00828     else
00829       return "INVALID";
00830   }
00831 }
00832 
00833 void OpenNI2Driver::initDevice()
00834 {
00835   while (ros::ok() && !device_)
00836   {
00837     try
00838     {
00839       std::string device_URI = resolveDeviceURI(device_id_);
00840       device_ = device_manager_->getDevice(device_URI);
00841       bus_id_ = extractBusID(device_->getUri() );
00842     }
00843     catch (const OpenNI2Exception& exception)
00844     {
00845       if (!device_)
00846       {
00847         ROS_INFO("No matching device found.... waiting for devices. Reason: %s", exception.what());
00848         boost::this_thread::sleep(boost::posix_time::seconds(3));
00849         continue;
00850       }
00851       else
00852       {
00853         ROS_ERROR("Could not retrieve device. Reason: %s", exception.what());
00854         exit(-1);
00855       }
00856     }
00857   }
00858 
00859   while (ros::ok() && !device_->isValid())
00860   {
00861     ROS_DEBUG("Waiting for device initialization..");
00862     boost::this_thread::sleep(boost::posix_time::milliseconds(100));
00863   }
00864 
00865 }
00866 
00867 
00868 int OpenNI2Driver::extractBusID(const std::string& uri) const
00869 {
00870   // URI format is <vendor ID>/<product ID>@<bus number>/<device number>
00871   unsigned first = uri.find('@');
00872   unsigned last = uri.find('/', first);
00873   std::string bus_id = uri.substr (first+1,last-first-1);
00874   int rtn = atoi(bus_id.c_str());
00875   return rtn;
00876 }
00877 
00878 
00879 bool OpenNI2Driver::isConnected() const
00880 {
00881   // TODO: The current isConnected logic assumes that there is only one sensor
00882   // on the bus of interest.  In the future, we could compare serial numbers
00883   // to make certain the same camera as been re-connected.
00884   boost::shared_ptr<std::vector<std::string> > list =
00885       device_manager_->getConnectedDeviceURIs();
00886   for (std::size_t i = 0; i != list->size(); ++i)
00887   {
00888     int uri_bus_id = extractBusID( list->at(i) );
00889     if( uri_bus_id == bus_id_ )
00890     {
00891       return true;
00892     }
00893   }
00894   return false;
00895 }
00896 
00897 void OpenNI2Driver::monitorConnection(const ros::TimerEvent &event)
00898 {
00899   // If the connection is lost, clean up the device.  If connected
00900   // and the devices is not initialized, then initialize.
00901   if( isConnected() )
00902   {
00903     if( !device_ )
00904     {
00905       ROS_INFO_STREAM("Detected re-connect...attempting reinit");
00906       try
00907       {
00908         {
00909         boost::lock_guard<boost::mutex> lock(connect_mutex_);
00910         std::string device_URI = resolveDeviceURI(device_id_);
00911         device_ = device_manager_->getDevice(device_URI);
00912         bus_id_ = extractBusID(device_->getUri() );
00913         while (ros::ok() && !device_->isValid())
00914         {
00915           ROS_INFO("Waiting for device initialization, before configuring and restarting publishers");
00916           boost::this_thread::sleep(boost::posix_time::milliseconds(100));
00917         }
00918         }
00919         ROS_INFO_STREAM("Re-applying configuration to camera on re-init");
00920         config_init_ = false;
00921         applyConfigToOpenNIDevice();
00922 
00923         // The color stream must be started in order to adjust the exposure white
00924         // balance.
00925         ROS_INFO_STREAM("Starting color stream to adjust camera");
00926         colorConnectCb();
00927 
00928         // If auto exposure/white balance is disabled, then the rbg image won't
00929         // be adjusted properly.  This is a work around for now, but the final
00930         // implimentation should only allow reconnection when auto exposure and
00931         // white balance are disabled, and FIXED exposure is used instead.
00932         if((!auto_exposure_ && !auto_white_balance_ ) && exposure_ == 0)
00933         {
00934           ROS_WARN_STREAM("Reconnection should not be enabled if auto expousre"
00935                           << "/white balance are disabled.  Temporarily working"
00936                           << " around this issue");
00937           ROS_WARN_STREAM("Toggling exposure and white balance to auto on re-connect"
00938                           << ", otherwise image will be very dark");
00939           device_->setAutoExposure(true);
00940           device_->setAutoWhiteBalance(true);
00941           ROS_INFO_STREAM("Waiting for color camera to come up and adjust");
00942           // It takes about 2.5 seconds for the camera to adjust
00943           boost::this_thread::sleep(boost::posix_time::milliseconds(2500));
00944           ROS_WARN_STREAM("Resetting auto exposure and white balance to previous values");
00945           device_->setAutoExposure(auto_exposure_);
00946           device_->setAutoWhiteBalance(auto_white_balance_);
00947         }
00948 
00949         ROS_INFO_STREAM("Restarting publishers, if needed");
00950         irConnectCb();
00951         depthConnectCb();
00952         ROS_INFO_STREAM("Done re-initializing cameras");
00953       }
00954 
00955       catch (const OpenNI2Exception& exception)
00956       {
00957         if (!device_)
00958         {
00959           ROS_INFO_STREAM("Failed to re-initialize device on bus: " << bus_id_
00960                           << ", reason: " << exception.what());
00961         }
00962       }
00963     }
00964   }
00965   else if( device_ )
00966   {
00967     ROS_WARN_STREAM("Detected loss of connection.  Stopping all streams and resetting device");
00968     device_->stopAllStreams();
00969     device_.reset();
00970   }
00971 }
00972 
00973 
00974 void OpenNI2Driver::genVideoModeTableMap()
00975 {
00976   /*
00977    * #  Video modes defined by dynamic reconfigure:
00978 output_mode_enum = gen.enum([  gen.const(  "SXGA_30Hz", int_t, 1,  "1280x1024@30Hz"),
00979                                gen.const(  "SXGA_15Hz", int_t, 2,  "1280x1024@15Hz"),
00980                                gen.const(   "XGA_30Hz", int_t, 3,  "1280x720@30Hz"),
00981                                gen.const(   "XGA_15Hz", int_t, 4,  "1280x720@15Hz"),
00982                                gen.const(   "VGA_30Hz", int_t, 5,  "640x480@30Hz"),
00983                                gen.const(   "VGA_25Hz", int_t, 6,  "640x480@25Hz"),
00984                                gen.const(  "QVGA_25Hz", int_t, 7,  "320x240@25Hz"),
00985                                gen.const(  "QVGA_30Hz", int_t, 8,  "320x240@30Hz"),
00986                                gen.const(  "QVGA_60Hz", int_t, 9,  "320x240@60Hz"),
00987                                gen.const( "QQVGA_25Hz", int_t, 10, "160x120@25Hz"),
00988                                gen.const( "QQVGA_30Hz", int_t, 11, "160x120@30Hz"),
00989                                gen.const( "QQVGA_60Hz", int_t, 12, "160x120@60Hz")],
00990                                "output mode")
00991   */
00992 
00993   video_modes_lookup_.clear();
00994 
00995   OpenNI2VideoMode video_mode;
00996 
00997   // SXGA_30Hz
00998   video_mode.x_resolution_ = 1280;
00999   video_mode.y_resolution_ = 1024;
01000   video_mode.frame_rate_ = 30;
01001 
01002   video_modes_lookup_[1] = video_mode;
01003 
01004   // SXGA_15Hz
01005   video_mode.x_resolution_ = 1280;
01006   video_mode.y_resolution_ = 1024;
01007   video_mode.frame_rate_ = 15;
01008 
01009   video_modes_lookup_[2] = video_mode;
01010 
01011   // XGA_30Hz
01012   video_mode.x_resolution_ = 1280;
01013   video_mode.y_resolution_ = 720;
01014   video_mode.frame_rate_ = 30;
01015 
01016   video_modes_lookup_[3] = video_mode;
01017 
01018   // XGA_15Hz
01019   video_mode.x_resolution_ = 1280;
01020   video_mode.y_resolution_ = 720;
01021   video_mode.frame_rate_ = 15;
01022 
01023   video_modes_lookup_[4] = video_mode;
01024 
01025   // VGA_30Hz
01026   video_mode.x_resolution_ = 640;
01027   video_mode.y_resolution_ = 480;
01028   video_mode.frame_rate_ = 30;
01029 
01030   video_modes_lookup_[5] = video_mode;
01031 
01032   // VGA_25Hz
01033   video_mode.x_resolution_ = 640;
01034   video_mode.y_resolution_ = 480;
01035   video_mode.frame_rate_ = 25;
01036 
01037   video_modes_lookup_[6] = video_mode;
01038 
01039   // QVGA_25Hz
01040   video_mode.x_resolution_ = 320;
01041   video_mode.y_resolution_ = 240;
01042   video_mode.frame_rate_ = 25;
01043 
01044   video_modes_lookup_[7] = video_mode;
01045 
01046   // QVGA_30Hz
01047   video_mode.x_resolution_ = 320;
01048   video_mode.y_resolution_ = 240;
01049   video_mode.frame_rate_ = 30;
01050 
01051   video_modes_lookup_[8] = video_mode;
01052 
01053   // QVGA_60Hz
01054   video_mode.x_resolution_ = 320;
01055   video_mode.y_resolution_ = 240;
01056   video_mode.frame_rate_ = 60;
01057 
01058   video_modes_lookup_[9] = video_mode;
01059 
01060   // QQVGA_25Hz
01061   video_mode.x_resolution_ = 160;
01062   video_mode.y_resolution_ = 120;
01063   video_mode.frame_rate_ = 25;
01064 
01065   video_modes_lookup_[10] = video_mode;
01066 
01067   // QQVGA_30Hz
01068   video_mode.x_resolution_ = 160;
01069   video_mode.y_resolution_ = 120;
01070   video_mode.frame_rate_ = 30;
01071 
01072   video_modes_lookup_[11] = video_mode;
01073 
01074   // QQVGA_60Hz
01075   video_mode.x_resolution_ = 160;
01076   video_mode.y_resolution_ = 120;
01077   video_mode.frame_rate_ = 60;
01078 
01079   video_modes_lookup_[12] = video_mode;
01080 
01081 }
01082 
01083 int OpenNI2Driver::lookupVideoModeFromDynConfig(int mode_nr, OpenNI2VideoMode& video_mode)
01084 {
01085   int ret = -1;
01086 
01087   std::map<int, OpenNI2VideoMode>::const_iterator it;
01088 
01089   it = video_modes_lookup_.find(mode_nr);
01090 
01091   if (it!=video_modes_lookup_.end())
01092   {
01093     video_mode = it->second;
01094     ret = 0;
01095   }
01096 
01097   return ret;
01098 }
01099 
01100 sensor_msgs::ImageConstPtr OpenNI2Driver::rawToFloatingPointConversion(sensor_msgs::ImageConstPtr raw_image)
01101 {
01102   static const float bad_point = std::numeric_limits<float>::quiet_NaN ();
01103 
01104   sensor_msgs::ImagePtr new_image = boost::make_shared<sensor_msgs::Image>();
01105 
01106   new_image->header = raw_image->header;
01107   new_image->width = raw_image->width;
01108   new_image->height = raw_image->height;
01109   new_image->is_bigendian = 0;
01110   new_image->encoding = sensor_msgs::image_encodings::TYPE_32FC1;
01111   new_image->step = sizeof(float)*raw_image->width;
01112 
01113   std::size_t data_size = new_image->width*new_image->height;
01114   new_image->data.resize(data_size*sizeof(float));
01115 
01116   const unsigned short* in_ptr = reinterpret_cast<const unsigned short*>(&raw_image->data[0]);
01117   float* out_ptr = reinterpret_cast<float*>(&new_image->data[0]);
01118 
01119   for (std::size_t i = 0; i<data_size; ++i, ++in_ptr, ++out_ptr)
01120   {
01121     if (*in_ptr==0 || *in_ptr==0x7FF)
01122     {
01123       *out_ptr = bad_point;
01124     } else
01125     {
01126       *out_ptr = static_cast<float>(*in_ptr)/1000.0f;
01127     }
01128   }
01129 
01130   return new_image;
01131 }
01132 
01133 }


openni2_camera
Author(s): Julius Kammerl
autogenerated on Thu Jun 6 2019 21:28:42