stereo_camera.cpp
Go to the documentation of this file.
00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 #include <avt_vimba_camera/stereo_camera.h>
00034 #include <driver_base/SensorLevels.h>
00035 
00036 namespace avt_vimba_camera {
00037 
00038 StereoCamera::StereoCamera(ros::NodeHandle nh, ros::NodeHandle nhp)
00039 :nh_(nh), nhp_(nhp), it_(nh), left_cam_("left"), right_cam_("right"),
00040  desired_freq_(7.5), left_init_(false), right_init_(false), check_timer_(io_, boost::posix_time::seconds(1)), sync_timer_(io_, boost::posix_time::seconds(0.1)) {
00041 
00042   // Get the parameters
00043   nhp_.param("left_ip", left_ip_, std::string(""));
00044   nhp_.param("right_ip", right_ip_, std::string(""));
00045   nhp_.param("left_guid", left_guid_, std::string(""));
00046   nhp_.param("right_guid", right_guid_, std::string(""));
00047   nhp_.param("left_camera_info_url", left_camera_info_url_, std::string(""));
00048   nhp_.param("right_camera_info_url", right_camera_info_url_, std::string(""));
00049   nhp_.param("show_debug_prints", show_debug_prints_, false);
00050   nhp_.param("r_imgs_buffer_size", imgs_buffer_size_, 3);
00051   nhp_.param("max_sec_diff", max_sec_diff_, 0.05);
00052   nhp_.param("sync_timer_step", sync_timer_step_, 0.1); // Should be less than 1/(frame rate)
00053 }
00054 
00055 StereoCamera::~StereoCamera() {
00056   left_cam_.stop();
00057   right_cam_.stop();
00058   updater_.broadcast(0, "Device is closed.");
00059   left_pub_.shutdown();
00060   right_pub_.shutdown();
00061 }
00062 
00063 void StereoCamera::run() {
00064   // TODO use nodelets with getMTNodeHandle()
00065   // Start Vimba & list all available cameras
00066   api_.start();
00067 
00068   // Set the image publishers before the streaming
00069   left_pub_  = it_.advertiseCamera("/stereo_down/left/image_raw",  1);
00070   right_pub_ = it_.advertiseCamera("/stereo_down/right/image_raw", 1);
00071 
00072   // Set the frame callbacks
00073   left_cam_.setCallback(boost::bind(&avt_vimba_camera::StereoCamera::leftFrameCallback, this, _1));
00074   right_cam_.setCallback(boost::bind(&avt_vimba_camera::StereoCamera::rightFrameCallback, this, _1));
00075 
00076   // Publish a hardware message to know & track the state of the cam
00077   updater_.setHardwareID("Stereo-"+left_guid_+"-"+right_guid_);
00078   updater_.broadcast(0, "Device is closed.");
00079   double min_freq = 2.0;
00080   double max_freq = 20.0;
00081   diagnostic_updater::FrequencyStatusParam freq_params(&min_freq, &max_freq, 0.1, 10);
00082   double min_stamp = 0.001;
00083   double max_stamp = 1.0;
00084   diagnostic_updater::TimeStampStatusParam stamp_params(min_stamp, max_stamp);
00085   // pub_freq_ = new diagnostic_updater::TopicDiagnostic("Stereo Image Pair", updater_, freq_params, stamp_params);
00086   updater_.update();
00087 
00088   // Set camera info managers
00089   left_info_man_  = boost::shared_ptr<camera_info_manager::CameraInfoManager>(new camera_info_manager::CameraInfoManager(ros::NodeHandle(nhp_, "left"),"left_optical",left_camera_info_url_));
00090   right_info_man_ = boost::shared_ptr<camera_info_manager::CameraInfoManager>(new camera_info_manager::CameraInfoManager(ros::NodeHandle(nhp_, "right"),"right_optical",right_camera_info_url_));
00091 
00092   pub_left_temp_ = nhp_.advertise<std_msgs::Float64>("left_temp", 1, true);
00093   pub_right_temp_ = nhp_.advertise<std_msgs::Float64>("right_temp", 1, true);
00094 
00095   // Start dynamic_reconfigure & run configure()
00096   reconfigure_server_.setCallback(boost::bind(&StereoCamera::configure, this, _1, _2));
00097 
00098   // Timers
00099   sync_timer_.async_wait( boost::bind(&StereoCamera::syncCallback, this) );
00100   check_timer_.async_wait( boost::bind(&StereoCamera::checkCallback, this) );
00101   io_.run();
00102 
00103 }
00104 
00105 void StereoCamera::leftFrameCallback(const FramePtr& vimba_frame_ptr) {
00106   left_init_ = true;
00107   ros::Time ros_time = ros::Time::now();
00108   l_last_time_ = ros_time.toSec();
00109   if(left_pub_.getNumSubscribers() > 0){
00110     sensor_msgs::Image img;
00111     if (api_.frameToImage(vimba_frame_ptr, img)){
00112       // Publish
00113       sensor_msgs::CameraInfo lci = left_info_man_->getCameraInfo();
00114       lci.header.stamp = ros_time;
00115       img.header.stamp = ros_time;
00116       img.header.frame_id = lci.header.frame_id;
00117       if (right_pub_.getNumSubscribers() == 0) {
00118         left_pub_.publish(img, lci);
00119       }
00120       else {
00121         // If there is left subscribers, sync and publish
00122         mutex::scoped_lock lock(l_sync_mutex_);
00123         if (l_imgs_buffer_.size() >= imgs_buffer_size_) {
00124           l_imgs_buffer_.erase(l_imgs_buffer_.begin(), l_imgs_buffer_.begin() + 1);
00125         }
00126         l_imgs_buffer_.push_back(img);
00127       }
00128     }
00129     else {
00130       ROS_WARN_STREAM("Function frameToImage returned 0. No image published.");
00131     }
00132   }
00133 
00134   // Publish temp
00135   if (pub_left_temp_.getNumSubscribers() > 0) {
00136     std_msgs::Float64 msg;
00137     msg.data = left_cam_.getDeviceTemp();
00138     pub_left_temp_.publish(msg);
00139   }
00140 
00141   updater_.update();
00142 }
00143 
00144 void StereoCamera::rightFrameCallback(const FramePtr& vimba_frame_ptr) {
00145   right_init_ = true;
00146   ros::Time ros_time = ros::Time::now();
00147   r_last_time_ = ros_time.toSec();
00148   if(right_pub_.getNumSubscribers() > 0){
00149     sensor_msgs::Image img;
00150     if (api_.frameToImage(vimba_frame_ptr, img)){
00151       // Publish
00152       sensor_msgs::CameraInfo rci = right_info_man_->getCameraInfo();
00153       rci.header.stamp = ros_time;
00154       img.header.stamp = ros_time;
00155       img.header.frame_id = rci.header.frame_id;
00156 
00157       // If no left subscribers, publish it
00158       if (left_pub_.getNumSubscribers() == 0) {
00159         right_pub_.publish(img, rci);
00160       }
00161       else {
00162         // If there is left subscribers, sync and publish
00163         mutex::scoped_lock lock(r_sync_mutex_);
00164         if (r_imgs_buffer_.size() >= imgs_buffer_size_) {
00165           r_imgs_buffer_.erase(r_imgs_buffer_.begin(), r_imgs_buffer_.begin() + 1);
00166         }
00167         r_imgs_buffer_.push_back(img);
00168       }
00169     }
00170     else {
00171       ROS_WARN_STREAM("Function frameToImage returned 0. No image published.");
00172     }
00173   }
00174 
00175   // Publish temp
00176   if (pub_right_temp_.getNumSubscribers() > 0) {
00177     std_msgs::Float64 msg;
00178     msg.data = right_cam_.getDeviceTemp();
00179     pub_right_temp_.publish(msg);
00180   }
00181 }
00182 
00183 void StereoCamera::syncCallback() {
00184   // Sync
00185   if(left_pub_.getNumSubscribers() > 0 && right_pub_.getNumSubscribers() > 0) {
00186     // Copy vectors to release the lock
00187     std::vector<sensor_msgs::Image> l_imgs_buffer, r_imgs_buffer;
00188     {
00189       mutex::scoped_lock l_lock(l_sync_mutex_);
00190       mutex::scoped_lock r_lock(r_sync_mutex_);
00191       l_imgs_buffer = l_imgs_buffer_;
00192       r_imgs_buffer = r_imgs_buffer_;
00193     }
00194 
00195     // Check buffers size
00196     if (l_imgs_buffer.size() == 0 || r_imgs_buffer.size() == 0) {
00197       sync_timer_.expires_at(sync_timer_.expires_at() + boost::posix_time::seconds(sync_timer_step_));
00198       sync_timer_.async_wait(boost::bind(&StereoCamera::syncCallback, this));
00199       return;
00200     }
00201 
00202     // Ge the camera info
00203     sensor_msgs::CameraInfo lci = left_info_man_->getCameraInfo();
00204     sensor_msgs::CameraInfo rci = right_info_man_->getCameraInfo();
00205 
00206     bool synced = false;
00207     for (uint i=0; i<l_imgs_buffer.size(); i++) {
00208       double l_stamp = l_imgs_buffer[i].header.stamp.toSec();
00209 
00210       for (uint j=0; j<r_imgs_buffer.size(); j++) {
00211         double r_stamp = r_imgs_buffer[j].header.stamp.toSec();
00212 
00213         if (fabs(l_stamp - r_stamp) < max_sec_diff_) {
00214           // Publish the synced images
00215           r_imgs_buffer[j].header.stamp = l_imgs_buffer[i].header.stamp;
00216           lci.header.stamp = l_imgs_buffer[i].header.stamp;
00217           rci.header.stamp = l_imgs_buffer[i].header.stamp;
00218           left_pub_.publish(l_imgs_buffer[i], lci);
00219           right_pub_.publish(r_imgs_buffer[j], rci);
00220 
00221           // Remove the images from the vectors
00222           {
00223             mutex::scoped_lock l_lock(l_sync_mutex_);
00224             l_imgs_buffer_.erase(l_imgs_buffer_.begin(), l_imgs_buffer_.begin() + i + 1);
00225           }
00226           {
00227             mutex::scoped_lock r_lock(r_sync_mutex_);
00228             r_imgs_buffer_.erase(r_imgs_buffer_.begin(), r_imgs_buffer_.begin() + j + 1);
00229           }
00230 
00231           synced = true;
00232           break;
00233         }
00234       }
00235       if (synced) break;
00236     }
00237   }
00238 
00239   sync_timer_.expires_at(sync_timer_.expires_at() + boost::posix_time::seconds(sync_timer_step_));
00240   sync_timer_.async_wait(boost::bind(&StereoCamera::syncCallback, this));
00241 }
00242 
00252 void StereoCamera::configure(StereoConfig& newconfig, uint32_t level) {
00253   // Left camera is considered MASTER and right SLAVE
00254   try {
00255     // The camera already stops & starts acquisition
00256     // so there's no problem on changing any feature.
00257     if (!left_cam_.isOpened()) {
00258       left_cam_.start(left_ip_, left_guid_, show_debug_prints_);
00259     }
00260     if (!right_cam_.isOpened()) {
00261       right_cam_.start(right_ip_, right_guid_, show_debug_prints_);
00262       if (left_cam_.isOpened() && right_cam_.isOpened()){
00263         left_cam_.resetTimestamp();
00264         right_cam_.resetTimestamp();
00265       }
00266     }
00267     Config left_config, right_config;
00268     copyConfig(newconfig, left_config, right_config);
00269     left_cam_.updateConfig(left_config);
00270     right_cam_.updateConfig(right_config);
00271     updateCameraInfo(newconfig);
00272   } catch (const std::exception& e) {
00273     ROS_ERROR_STREAM("Error reconfiguring avt_vimba_camera node : " << e.what());
00274   }
00275 }
00276 
00277 void StereoCamera::copyConfig(StereoConfig& sc, Config& lc, Config& rc) {
00278   // left camera
00279   lc.frame_id = sc.left_frame_id;
00280   lc.trig_timestamp_topic = sc.left_trig_timestamp_topic;
00281   lc.acquisition_mode = sc.left_acquisition_mode;
00282   lc.acquisition_rate = sc.left_acquisition_rate;
00283   lc.trigger_source = sc.left_trigger_source;
00284   lc.trigger_mode = sc.left_trigger_mode;
00285   lc.trigger_selector = sc.left_trigger_selector;
00286   lc.trigger_activation = sc.left_trigger_activation;
00287   lc.trigger_delay = sc.left_trigger_delay;
00288   lc.exposure = sc.exposure;
00289   lc.exposure_auto = sc.exposure_auto;
00290   lc.exposure_auto_alg = sc.exposure_auto_alg;
00291   lc.exposure_auto_tol = sc.exposure_auto_tol;
00292   lc.exposure_auto_max = sc.exposure_auto_max;
00293   lc.exposure_auto_min = sc.exposure_auto_min;
00294   lc.exposure_auto_outliers = sc.exposure_auto_outliers;
00295   lc.exposure_auto_rate = sc.exposure_auto_rate;
00296   lc.exposure_auto_target = sc.exposure_auto_target;
00297   lc.gain = sc.gain;
00298   lc.gain_auto = sc.gain_auto;
00299   lc.gain_auto_tol = sc.gain_auto_tol;
00300   lc.gain_auto_max = sc.gain_auto_max;
00301   lc.gain_auto_min = sc.gain_auto_min;
00302   lc.gain_auto_outliers = sc.gain_auto_outliers;
00303   lc.gain_auto_rate = sc.gain_auto_rate;
00304   lc.gain_auto_target = sc.gain_auto_target;
00305   lc.balance_ratio_abs = sc.balance_ratio_abs;
00306   lc.balance_ratio_selector = sc.balance_ratio_selector;
00307   lc.whitebalance_auto = sc.whitebalance_auto;
00308   lc.whitebalance_auto_tol = sc.whitebalance_auto_tol;
00309   lc.whitebalance_auto_rate = sc.whitebalance_auto_rate;
00310   lc.binning_x = sc.binning_x;
00311   lc.binning_y = sc.binning_y;
00312   lc.decimation_x = sc.decimation_x;
00313   lc.decimation_y = sc.decimation_y;
00314   lc.width = sc.width;
00315   lc.height = sc.height;
00316   lc.roi_width = sc.roi_width;
00317   lc.roi_height = sc.roi_height;
00318   lc.roi_offset_x = sc.roi_offset_x;
00319   lc.roi_offset_y = sc.roi_offset_y;
00320   lc.pixel_format = sc.pixel_format;
00321   lc.stream_bytes_per_second = sc.stream_bytes_per_second;
00322   lc.ptp_mode = sc.left_ptp_mode;
00323   lc.sync_in_selector = sc.left_sync_in_selector;
00324   lc.sync_out_polarity = sc.left_sync_out_polarity;
00325   lc.sync_out_selector = sc.left_sync_out_selector;
00326   lc.sync_out_source = sc.left_sync_out_source;
00327   // right camera
00328   rc.frame_id = sc.right_frame_id;
00329   rc.trig_timestamp_topic = sc.right_trig_timestamp_topic;
00330   rc.acquisition_mode = sc.right_acquisition_mode;
00331   rc.acquisition_rate = sc.right_acquisition_rate;
00332   rc.trigger_source = sc.right_trigger_source;
00333   rc.trigger_mode = sc.right_trigger_mode;
00334   rc.trigger_selector = sc.right_trigger_selector;
00335   rc.trigger_activation = sc.right_trigger_activation;
00336   rc.trigger_delay = sc.right_trigger_delay;
00337   rc.exposure = sc.exposure;
00338   rc.exposure_auto = sc.exposure_auto;
00339   rc.exposure_auto_alg = sc.exposure_auto_alg;
00340   rc.exposure_auto_tol = sc.exposure_auto_tol;
00341   rc.exposure_auto_max = sc.exposure_auto_max;
00342   rc.exposure_auto_min = sc.exposure_auto_min;
00343   rc.exposure_auto_outliers = sc.exposure_auto_outliers;
00344   rc.exposure_auto_rate = sc.exposure_auto_rate;
00345   rc.exposure_auto_target = sc.exposure_auto_target;
00346   rc.gain = sc.gain;
00347   rc.gain_auto = sc.gain_auto;
00348   rc.gain_auto_tol = sc.gain_auto_tol;
00349   rc.gain_auto_max = sc.gain_auto_max;
00350   rc.gain_auto_min = sc.gain_auto_min;
00351   rc.gain_auto_outliers = sc.gain_auto_outliers;
00352   rc.gain_auto_rate = sc.gain_auto_rate;
00353   rc.gain_auto_target = sc.gain_auto_target;
00354   rc.balance_ratio_abs = sc.balance_ratio_abs;
00355   rc.balance_ratio_selector = sc.balance_ratio_selector;
00356   rc.whitebalance_auto = sc.whitebalance_auto;
00357   rc.whitebalance_auto_tol = sc.whitebalance_auto_tol;
00358   rc.whitebalance_auto_rate = sc.whitebalance_auto_rate;
00359   rc.binning_x = sc.binning_x;
00360   rc.binning_y = sc.binning_y;
00361   rc.decimation_x = sc.decimation_x;
00362   rc.decimation_y = sc.decimation_y;
00363   rc.width = sc.width;
00364   rc.height = sc.height;
00365   rc.roi_width = sc.roi_width;
00366   rc.roi_height = sc.roi_height;
00367   rc.roi_offset_x = sc.roi_offset_x;
00368   rc.roi_offset_y = sc.roi_offset_y;
00369   rc.pixel_format = sc.pixel_format;
00370   rc.stream_bytes_per_second = sc.stream_bytes_per_second;
00371   rc.ptp_mode = sc.right_ptp_mode;
00372   rc.sync_in_selector = sc.right_sync_in_selector;
00373   rc.sync_out_polarity = sc.right_sync_out_polarity;
00374   rc.sync_out_selector = sc.right_sync_out_selector;
00375   rc.sync_out_source = sc.right_sync_out_source;
00376 }
00377 
00378 void StereoCamera::updateCameraInfo(const StereoConfig& config) {
00379   // Get camera_info from the manager
00380   sensor_msgs::CameraInfo left_ci = left_info_man_->getCameraInfo();
00381   sensor_msgs::CameraInfo right_ci = right_info_man_->getCameraInfo();
00382 
00383   // Set the frame id
00384   left_ci.header.frame_id = config.left_frame_id;
00385   right_ci.header.frame_id = config.right_frame_id;
00386 
00387   // Set the operational parameters in CameraInfo (binning, ROI)
00388   int binning_or_decimation_x = std::max(config.binning_x, config.decimation_x);
00389   int binning_or_decimation_y = std::max(config.binning_y, config.decimation_y);
00390 
00391   left_ci.height    = config.height/binning_or_decimation_x;
00392   left_ci.width     = config.width/binning_or_decimation_y;
00393   left_ci.binning_x = 1;
00394   left_ci.binning_y = 1;
00395 
00396   right_ci.height    = config.height/binning_or_decimation_x;
00397   right_ci.width     = config.width/binning_or_decimation_y;
00398   right_ci.binning_x = 1;
00399   right_ci.binning_y = 1;
00400 
00401   // ROI in CameraInfo is in unbinned coordinates, need to scale up
00402   left_ci.roi.x_offset = config.roi_offset_x/binning_or_decimation_x;
00403   left_ci.roi.y_offset = config.roi_offset_y/binning_or_decimation_y;
00404   left_ci.roi.height   = config.roi_height/binning_or_decimation_x;
00405   left_ci.roi.width    = config.roi_width/binning_or_decimation_y;
00406 
00407   right_ci.roi.x_offset = config.roi_offset_x/binning_or_decimation_x;
00408   right_ci.roi.y_offset = config.roi_offset_y/binning_or_decimation_y;
00409   right_ci.roi.height   = config.roi_height/binning_or_decimation_x;
00410   right_ci.roi.width    = config.roi_width/binning_or_decimation_y;
00411 
00412   std::string left_camera_info_url, right_camera_info_url;
00413   nhp_.getParamCached("left_camera_info_url", left_camera_info_url);
00414   nhp_.getParamCached("right_camera_info_url", right_camera_info_url);
00415 
00416   // set the new URL and load CameraInfo (if any) from it
00417   if (left_camera_info_url != left_camera_info_url_) {
00418     left_info_man_->setCameraName(config.left_frame_id);
00419     if (left_info_man_->validateURL(left_camera_info_url)) {
00420       left_info_man_->loadCameraInfo(left_camera_info_url);
00421       left_ci = left_info_man_->getCameraInfo();
00422     } else {
00423       ROS_WARN_STREAM("Camera info URL not valid: " << left_camera_info_url);
00424     }
00425   }
00426 
00427   if (right_camera_info_url != right_camera_info_url_) {
00428     right_info_man_->setCameraName(config.right_frame_id);
00429     if (right_info_man_->validateURL(right_camera_info_url)) {
00430       right_info_man_->loadCameraInfo(right_camera_info_url);
00431       right_ci = right_info_man_->getCameraInfo();
00432     } else {
00433       ROS_WARN_STREAM("Camera info URL not valid: " << right_camera_info_url);
00434     }
00435   }
00436 
00437   bool lRoiMatchesCalibration = (left_ci.height == config.roi_height
00438                               && left_ci.width == config.roi_width);
00439   bool lResolutionMatchesCalibration = (left_ci.width == config.width
00440                                    && left_ci.height == config.height);
00441   // check
00442   left_ci.roi.do_rectify = lRoiMatchesCalibration || lResolutionMatchesCalibration;
00443 
00444   bool rRoiMatchesCalibration = (right_ci.height == config.roi_height
00445                               && right_ci.width == config.roi_width);
00446   bool rResolutionMatchesCalibration = (right_ci.width == config.width
00447                                    && right_ci.height == config.height);
00448   // check
00449   right_ci.roi.do_rectify = rRoiMatchesCalibration || rResolutionMatchesCalibration;
00450 
00451   // push the changes to manager
00452   left_info_man_->setCameraInfo(left_ci);
00453   right_info_man_->setCameraInfo(right_ci);
00454 }
00455 
00456 
00457 void StereoCamera::checkCallback() {
00458   if (left_init_) {
00459     double now = ros::Time::now().toSec();
00460     if (now - l_last_time_ > 10/desired_freq_) {
00461       ROS_WARN("Left camera not publishing. Reseting...");
00462       left_init_ = false;
00463       left_cam_.stop();
00464       ROS_INFO("DBGL 1");
00465       ros::WallDuration(2.0).sleep();
00466       ROS_INFO("DBGL 2");
00467       left_cam_.start(left_ip_, left_guid_, show_debug_prints_);
00468       ROS_INFO("Left camera reset!");
00469     }
00470   }
00471   if (right_init_) {
00472     double now = ros::Time::now().toSec();
00473     if (now - r_last_time_ > 10/desired_freq_) {
00474       ROS_WARN("Right camera not publishing. Reseting...");
00475       right_init_ = false;
00476       right_cam_.stop();
00477       ROS_INFO("DBGR 1");
00478       ros::WallDuration(2.0).sleep();
00479       ROS_INFO("DBGR 2");
00480       right_cam_.start(right_ip_, right_guid_, show_debug_prints_);
00481       ROS_INFO("Right camera reset!");
00482     }
00483   }
00484 
00485   check_timer_.expires_at(check_timer_.expires_at() + boost::posix_time::seconds(1));
00486   check_timer_.async_wait(boost::bind(&StereoCamera::checkCallback, this));
00487 }
00488 
00489 };


avt_vimba_camera
Author(s): Miquel Massot , Allied Vision Technologies
autogenerated on Thu Jun 6 2019 18:23:39