stereo_nodelet.cpp
Go to the documentation of this file.
00001 /*
00002 This code was developed by the National Robotics Engineering Center (NREC), part of the Robotics Institute at Carnegie Mellon University.
00003 Its development was funded by DARPA under the LS3 program and submitted for public release on June 7th, 2012.
00004 Release was granted on August, 21st 2012 with Distribution Statement "A" (Approved for Public Release, Distribution Unlimited).
00005 
00006 This software is released under a BSD license:
00007 
00008 Copyright (c) 2012, Carnegie Mellon University. All rights reserved.
00009 
00010 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
00011 
00012 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
00013 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
00014 Neither the name of the Carnegie Mellon University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
00015 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00016 */
00017 
00018 
00019 
00031 // ROS and associated nodelet interface and PLUGINLIB declaration header
00032 #include "ros/ros.h"
00033 #include <pluginlib/class_list_macros.h>
00034 #include <nodelet/nodelet.h>
00035 
00036 #include "pointgrey_camera_driver/PointGreyCamera.h" // The actual standalone library for the PointGreys
00037 
00038 #include <image_transport/image_transport.h> // ROS library that allows sending compressed images
00039 #include <camera_info_manager/camera_info_manager.h> // ROS library that publishes CameraInfo topics
00040 #include <sensor_msgs/CameraInfo.h> // ROS message header for CameraInfo
00041 #include <std_msgs/Float64.h>
00042 
00043 #include <wfov_camera_msgs/WFOVImage.h>
00044 #include <image_exposure_msgs/ExposureSequence.h> // Message type for configuring gain and white balance.
00045 
00046 #include <diagnostic_updater/diagnostic_updater.h> // Headers for publishing diagnostic messages.
00047 #include <diagnostic_updater/publisher.h>
00048 
00049 #include <boost/thread.hpp> // Needed for the nodelet to launch the reading thread.
00050 
00051 #include <dynamic_reconfigure/server.h> // Needed for the dynamic_reconfigure gui service to run
00052 
00053 namespace pointgrey_camera_driver
00054 {
00055 
00056 class PointGreyStereoCameraNodelet: public nodelet::Nodelet
00057 {
00058 public:
00059   PointGreyStereoCameraNodelet() {}
00060 
00061   ~PointGreyStereoCameraNodelet()
00062   {
00063     pubThread_->interrupt();
00064     pubThread_->join();
00065     cleanUp();
00066   }
00067 
00068 private:
00076   void paramCallback(pointgrey_camera_driver::PointGreyConfig &config, uint32_t level)
00077   {
00078 
00079     // Stereo is only active in this mode (16 bits, 8 for each image)
00080     config.video_mode = "format7_mode3";
00081 
00082     try
00083     {
00084       NODELET_DEBUG("Dynamic reconfigure callback with level: %d", level);
00085       pg_.setNewConfiguration(config, level);
00086 
00087       // Store needed parameters for the metadata message
00088       gain_ = config.gain;
00089       wb_blue_ = config.white_balance_blue;
00090       wb_red_ = config.white_balance_red;
00091 
00092 
00093       // Store CameraInfo binning information
00094       if(config.video_mode == "640x480_mono8" || config.video_mode == "format7_mode1")
00095       {
00096         binning_x_ = 2;
00097         binning_y_ = 2;
00098       }
00099       else if(config.video_mode == "format7_mode2")
00100       {
00101         binning_x_ = 0;
00102         binning_y_ = 2;
00103       }
00104       else
00105       {
00106         binning_x_ = 0;
00107         binning_y_ = 0;
00108       }
00109 
00110       // Store CameraInfo RegionOfInterest information
00111       if(config.video_mode == "format7_mode0" || config.video_mode == "format7_mode1" || config.video_mode == "format7_mode2")
00112       {
00113         roi_x_offset_ = config.format7_x_offset;
00114         roi_y_offset_ = config.format7_y_offset;
00115         roi_width_ = config.format7_roi_width;
00116         roi_height_ = config.format7_roi_height;
00117         do_rectify_ = true; // Set to true if an ROI is used.
00118       }
00119       else
00120       {
00121         // Zeros mean the full resolution was captured.
00122         roi_x_offset_ = 0;
00123         roi_y_offset_ = 0;
00124         roi_height_ = 0;
00125         roi_width_ = 0;
00126         do_rectify_ = false; // Set to false if the whole image is captured.
00127       }
00128     }
00129     catch(std::runtime_error& e)
00130     {
00131       NODELET_ERROR("Reconfigure Callback failed with error: %s", e.what());
00132     }
00133   }
00134 
00140   void onInit()
00141   {
00142     // Get nodeHandles
00143     ros::NodeHandle &nh = getMTNodeHandle();
00144     ros::NodeHandle &pnh = getMTPrivateNodeHandle();
00145     std::string firstcam;
00146     pnh.param<std::string>("first_namespace", firstcam, "left");
00147     ros::NodeHandle lnh(getMTNodeHandle(), firstcam);
00148     std::string secondcam;
00149     pnh.param<std::string>("second_namespace", secondcam, "right");
00150     ros::NodeHandle rnh(getMTNodeHandle(), secondcam);
00151 
00152     // Get a serial number through ros
00153     int serialParam;
00154     pnh.param<int>("serial", serialParam, 0);
00155     uint32_t serial = (uint32_t)serialParam;
00156     // Get the location of our camera config yamls
00157     std::string camera_info_url;
00158     pnh.param<std::string>("camera_info_url", camera_info_url, "");
00159     std::string second_info_url;
00160     pnh.param<std::string>("second_info_url", second_info_url, "");
00161     // Get the desired frame_id, set to 'camera' if not found
00162     pnh.param<std::string>("frame_id", frame_id_, "camera");
00163     pnh.param<std::string>("second_frame_id", second_frame_id_, frame_id_); // Default to left frame_id per stereo API
00164     // Set the timeout for grabbing images from the network
00165     double timeout;
00166     pnh.param("timeout", timeout, 1.0);
00167 
00168     // Try connecting to the camera
00169     volatile bool connected = false;
00170     while(!connected && ros::ok())
00171     {
00172       try
00173       {
00174         NODELET_INFO("Connecting to camera serial: %u", serial);
00175         pg_.setDesiredCamera(serial);
00176         NODELET_DEBUG("Actually connecting to camera.");
00177         pg_.connect();
00178         connected = true;
00179         NODELET_DEBUG("Setting timeout to: %f.", timeout);
00180         pg_.setTimeout(timeout);
00181       }
00182       catch(std::runtime_error& e)
00183       {
00184         NODELET_ERROR("%s", e.what());
00185         ros::Duration(1.0).sleep(); // sleep for one second each time
00186       }
00187     }
00188 
00189     // Start up the dynamic_reconfigure service, note that this needs to stick around after this function ends
00190     srv_ = boost::make_shared <dynamic_reconfigure::Server<pointgrey_camera_driver::PointGreyConfig> > (pnh);
00191     dynamic_reconfigure::Server<pointgrey_camera_driver::PointGreyConfig>::CallbackType f =  boost::bind(&pointgrey_camera_driver::PointGreyStereoCameraNodelet::paramCallback, this, _1, _2);
00192     srv_->setCallback(f);
00193 
00194     // Start the camera info manager and attempt to load any configurations
00195     std::stringstream cinfo_name;
00196     cinfo_name << serial;
00197     cinfo_.reset(new camera_info_manager::CameraInfoManager(lnh, cinfo_name.str(), camera_info_url));
00198     rcinfo_.reset(new camera_info_manager::CameraInfoManager(rnh, cinfo_name.str(), second_info_url));
00199     /*if (cinfo_->validateURL(camera_info_url)){ // Load CameraInfo (if any) from the URL.  Will ROS_ERROR if bad.
00200       cinfo_->loadCameraInfo(camera_info_url);
00201     }*/
00202     ci_.reset(new sensor_msgs::CameraInfo(cinfo_->getCameraInfo()));
00203     ci_->header.frame_id = frame_id_;
00204     rci_.reset(new sensor_msgs::CameraInfo(rcinfo_->getCameraInfo()));
00205     rci_->header.frame_id = second_frame_id_;
00206 
00207     // Publish topics using ImageTransport through camera_info_manager (gives cool things like compression)
00208     it_.reset(new image_transport::ImageTransport(lnh));
00209     it_pub_ = it_->advertiseCamera("image_raw", 5);
00210     rit_.reset(new image_transport::ImageTransport(rnh));
00211     rit_pub_ = rit_->advertiseCamera("image_raw", 5);
00212 
00213     // Set up diagnostics
00214     updater_.setHardwareID("pointgrey_camera " + serial);
00215 
00217     temp_pub_ = nh.advertise<std_msgs::Float64>("temp", 5);
00218 
00219     // Subscribe to gain and white balance changes
00220     sub_ = nh.subscribe("image_exposure_sequence", 10, &pointgrey_camera_driver::PointGreyStereoCameraNodelet::gainWBCallback, this);
00221 
00222     volatile bool started = false;
00223     while(!started)
00224     {
00225       try
00226       {
00227         NODELET_DEBUG("Starting camera capture.");
00228         pg_.start();
00229         started = true;
00230         // Start the thread to loop through and publish messages
00231         pubThread_ = boost::shared_ptr< boost::thread > (new boost::thread(boost::bind(&pointgrey_camera_driver::PointGreyStereoCameraNodelet::devicePoll, this)));
00232       }
00233       catch(std::runtime_error& e)
00234       {
00235         NODELET_ERROR("%s", e.what());
00236         ros::Duration(1.0).sleep(); // sleep for one second each time
00237       }
00238     }
00239   }
00240 
00246   void cleanUp()
00247   {
00248     try
00249     {
00250       NODELET_DEBUG("Stopping camera capture.");
00251       pg_.stop();
00252       NODELET_DEBUG("Disconnecting from camera.");
00253       pg_.disconnect();
00254     }
00255     catch(std::runtime_error& e)
00256     {
00257       NODELET_ERROR("%s", e.what());
00258     }
00259   }
00260 
00266   void devicePoll()
00267   {
00268     while(!boost::this_thread::interruption_requested())   // Block until we need to stop this thread.
00269     {
00270       try
00271       {
00272         sensor_msgs::ImagePtr image(new sensor_msgs::Image);
00273         sensor_msgs::ImagePtr second_image(new sensor_msgs::Image);
00274         pg_.grabStereoImage(*image, frame_id_, *second_image, second_frame_id_);
00275 
00276         ros::Time time = ros::Time::now();
00277         image->header.stamp = time;
00278         second_image->header.stamp = time;
00279         ci_->header.stamp = time;
00280         rci_->header.stamp = time;
00281         ci_->binning_x = binning_x_;
00282         rci_->binning_x = binning_x_;
00283         ci_->binning_y = binning_y_;
00284         rci_->binning_y = binning_y_;
00285         ci_->roi.x_offset = roi_x_offset_;
00286         rci_->roi.x_offset = roi_x_offset_;
00287         ci_->roi.y_offset = roi_y_offset_;
00288         rci_->roi.y_offset = roi_y_offset_;
00289         ci_->roi.height = roi_height_;
00290         rci_->roi.height = roi_height_;
00291         ci_->roi.width = roi_width_;
00292         rci_->roi.width = roi_width_;
00293         ci_->roi.do_rectify = do_rectify_;
00294         rci_->roi.do_rectify = do_rectify_;
00295 
00296         it_pub_.publish(image, ci_);
00297         rit_pub_.publish(second_image, rci_);
00298         std_msgs::Float64 temp;
00299         temp.data = pg_.getCameraTemperature();
00300         temp_pub_.publish(temp);
00301       }
00302       catch(CameraTimeoutException& e)
00303       {
00304         NODELET_WARN("%s", e.what());
00305       }
00306       catch(std::runtime_error& e)
00307       {
00308         NODELET_ERROR("%s", e.what());
00309         try
00310         {
00311           // Something terrible has happened, so let's just disconnect and reconnect to see if we can recover.
00312           pg_.disconnect();
00313           ros::Duration(1.0).sleep(); // sleep for one second each time
00314           pg_.connect();
00315           pg_.start();
00316         }
00317         catch(std::runtime_error& e2)
00318         {
00319           NODELET_ERROR("%s", e2.what());
00320         }
00321       }
00322       // Update diagnostics
00323       updater_.update();
00324     }
00325   }
00326 
00327   void gainWBCallback(const image_exposure_msgs::ExposureSequence &msg)
00328   {
00329     try
00330     {
00331       NODELET_DEBUG("Gain callback:  Setting gain to %f and white balances to %u, %u", msg.gain, msg.white_balance_blue, msg.white_balance_red);
00332       gain_ = msg.gain;
00333       pg_.setGain(gain_);
00334       wb_blue_ = msg.white_balance_blue;
00335       wb_red_ = msg.white_balance_red;
00336       pg_.setBRWhiteBalance(false, wb_blue_, wb_red_);
00337     }
00338     catch(std::runtime_error& e)
00339     {
00340       NODELET_ERROR("gainWBCallback failed with error: %s", e.what());
00341     }
00342   }
00343 
00344   boost::shared_ptr<dynamic_reconfigure::Server<pointgrey_camera_driver::PointGreyConfig> > srv_; 
00345   boost::shared_ptr<image_transport::ImageTransport> it_; 
00346   boost::shared_ptr<camera_info_manager::CameraInfoManager> cinfo_; 
00347   image_transport::CameraPublisher it_pub_; 
00348   ros::Publisher temp_pub_; 
00349   ros::Subscriber sub_; 
00350 
00351   diagnostic_updater::Updater updater_; 
00352   double min_freq_;
00353   double max_freq_;
00354 
00355   PointGreyCamera pg_; 
00356   sensor_msgs::CameraInfoPtr ci_; 
00357   std::string frame_id_; 
00358   boost::shared_ptr<boost::thread> pubThread_; 
00359 
00360   double gain_;
00361   uint16_t wb_blue_;
00362   uint16_t wb_red_;
00363 
00364   // For stereo cameras
00365   std::string second_frame_id_; 
00366   boost::shared_ptr<image_transport::ImageTransport> rit_; 
00367   boost::shared_ptr<camera_info_manager::CameraInfoManager> rcinfo_; 
00368   image_transport::CameraPublisher rit_pub_; 
00369   sensor_msgs::CameraInfoPtr rci_; 
00370 
00371   // Parameters for cameraInfo
00372   size_t binning_x_; 
00373   size_t binning_y_; 
00374   size_t roi_x_offset_; 
00375   size_t roi_y_offset_; 
00376   size_t roi_height_; 
00377   size_t roi_width_; 
00378   bool do_rectify_; 
00379 };
00380 
00381 PLUGINLIB_DECLARE_CLASS(pointgrey_camera_driver, PointGreyStereoCameraNodelet, pointgrey_camera_driver::PointGreyStereoCameraNodelet, nodelet::Nodelet);  // Needed for Nodelet declaration
00382 }


pointgrey_camera_driver
Author(s): Chad Rockey
autogenerated on Fri Oct 6 2017 02:35:31