capture.cpp
Go to the documentation of this file.
2 #include <nodelet/nodelet.h>
4 
6 
8 
9  // destructor
10  ROS_DEBUG("Capture destructor started");
11  ifstream file(dump_img_.c_str());
12  if (file)
13  if (remove(dump_img_.c_str()) != 0)
14  ROS_WARN_STREAM("Unable to remove dump image!");
15 
16  end_acquisition();
17  deinit_cameras();
18 
19  // pCam = nullptr;
20 
21  ROS_INFO_STREAM("Clearing camList...");
22  camList_.Clear();
23 
24  ROS_INFO_STREAM("Releasing camera pointers...");
25  cams.clear();
26 
27  ROS_INFO_STREAM("Releasing system instance...");
28  system_->ReleaseInstance();
29 
30  delete dynamicReCfgServer_;
31  // for boost thread
32  if (pubThread_) {
33  pubThread_->interrupt();
34  pubThread_->join();
35  }
36  // reset pubThread_
37  pubThread_.reset();
38  //reset it_
39  it_.reset();
40 
41 }
42 
44  //
45 }
46 
48  NODELET_INFO("Initializing nodelet");
49  nh_ = this->getNodeHandle();
50  nh_pvt_ = this->getPrivateNodeHandle();
51  //it_.reset(new image_transport::ImageTransport(nh_));
52  it_ = std::shared_ptr<image_transport::ImageTransport>(new image_transport::ImageTransport(nh_));
53  // set values to global class variables and register pub, sub to ros
55  init_array();
56  // calling capture::run() in a different thread
57  pubThread_.reset(new boost::thread(boost::bind(&acquisition::Capture::run, this)));
58  NODELET_INFO("onInit Initialized");
59 }
60 
62 
63  // this is all stuff in previous contructor
64  // except for nodehandles assigned in onInit()
65  int mem;
66  ifstream usb_mem("/sys/module/usbcore/parameters/usbfs_memory_mb");
67  if (usb_mem) {
68  usb_mem >> mem;
69  if (mem >= 1000)
70  ROS_INFO_STREAM("[ OK ] USB memory: "<<mem<<" MB");
71  else{
72  ROS_FATAL_STREAM(" USB memory on system too low ("<<mem<<" MB)! Must be at least 1000 MB. Run: \nsudo sh -c \"echo 1000 > /sys/module/usbcore/parameters/usbfs_memory_mb\"\n Terminating...");
73  ros::shutdown();
74  }
75  } else {
76  ROS_FATAL_STREAM("Could not check USB memory on system! Terminating...");
77  ros::shutdown();
78  }
79 
80  // default values for the parameters are set here. Should be removed eventually!!
81  exposure_time_ = 0 ; // default as 0 = auto exposure
82  soft_framerate_ = 20; //default soft framrate
83  gain_ = 0;
84  ext_ = ".bmp";
85  SOFT_FRAME_RATE_CTRL_ = false;
86  LIVE_ = false;
87  TIME_BENCHMARK_ = false;
89  EXTERNAL_TRIGGER_ = false;
90  EXPORT_TO_ROS_ = false;
91  PUBLISH_CAM_INFO_ = false;
92  SAVE_ = false;
93  SAVE_BIN_ = false;
94  nframes_ = -1;
95  FIXED_NUM_FRAMES_ = false;
96  MAX_RATE_SAVE_ = false;
98  skip_num_ = 20;
99  init_delay_ = 1;
100  master_fps_ = 20.0;
101  binning_ = 1;
104 
105  #ifdef trigger_msgs_FOUND
106  // Initialise the time variables for sync in with camera
107  latest_imu_trigger_time_ = ros::Time::now();
108  prev_imu_trigger_count_ = 0;
109  latest_imu_trigger_count_ = 0;
110  #endif
111 
112  first_image_received = false;
113 
114  dump_img_ = "dump" + ext_;
115 
116  grab_time_ = 0;
117  save_time_ = 0;
118  toMat_time_ = 0;
119  save_mat_time_ = 0;
121  achieved_time_ = 0;
122 
123  // decimation_ = 1;
124 
125  CAM_ = 0;
126 
127  // default flag values
128 
129  MANUAL_TRIGGER_ = false;
130  CAM_DIRS_CREATED_ = false;
131 
132  GRID_CREATED_ = false;
133  VERIFY_BINNING_ = false;
134 
135 
136  //read_settings(config_file);
137  read_parameters();
138 
139  // Retrieve singleton reference to system object
140  ROS_INFO_STREAM("*** SYSTEM INFORMATION ***");
141  ROS_INFO_STREAM("Creating system instance...");
142  ROS_INFO_STREAM("spinnaker_sdk_camera_driver package version: " << spinnaker_sdk_camera_driver_VERSION);
143  system_ = System::GetInstance();
144 
145  const LibraryVersion spinnakerLibraryVersion = system_->GetLibraryVersion();
146  ROS_INFO_STREAM("Spinnaker library version: "
147  << spinnakerLibraryVersion.major << "."
148  << spinnakerLibraryVersion.minor << "."
149  << spinnakerLibraryVersion.type << "."
150  << spinnakerLibraryVersion.build);
151 
152  load_cameras();
153 
154  //initializing the ros publisher
155  acquisition_pub = nh_.advertise<spinnaker_sdk_camera_driver::SpinnakerImageNames>("camera", 1000);
156 
157  #ifdef trigger_msgs_FOUND
158  // initiliazing the trigger subscriber
159  if (EXTERNAL_TRIGGER_){
160  timeStamp_sub = nh_.subscribe("/imu/sync_trigger", 1000, &acquisition::Capture::assignTimeStampCallback,this);
161 
162  for ( int i=0;i<numCameras_;i++){
163  std::queue<SyncInfo_> sync_message_queue;
164  sync_message_queue_vector_.push_back(sync_message_queue);
165  }
166  }
167  #endif
168 
169  //dynamic reconfigure
170  dynamicReCfgServer_ = new dynamic_reconfigure::Server<spinnaker_sdk_camera_driver::spinnaker_camConfig>(nh_pvt_);
171 
172  dynamic_reconfigure::Server<spinnaker_sdk_camera_driver::spinnaker_camConfig>::CallbackType dynamicReCfgServerCB_t;
173 
174  dynamicReCfgServerCB_t = boost::bind(&acquisition::Capture::dynamicReconfigureCallback,this, _1, _2);
175  dynamicReCfgServer_->setCallback(dynamicReCfgServerCB_t);
176 
177 }
179 
180  // Retrieve list of cameras from the system
181  ROS_INFO_STREAM("Retreiving list of cameras...");
182  camList_ = system_->GetCameras();
183 
184  numCameras_ = camList_.GetSize();
185  ROS_ASSERT_MSG(numCameras_,"No cameras found!");
186  ROS_INFO_STREAM("Numer of cameras found: " << numCameras_);
187  ROS_INFO_STREAM(" Cameras connected: " << numCameras_);
188 
189  for (int i=0; i<numCameras_; i++) {
190  acquisition::Camera cam(camList_.GetByIndex(i));
191  ROS_INFO_STREAM(" -"<< cam.get_id()
192  <<" "<< cam.getTLNodeStringValue("DeviceModelName")
193  <<" "<< cam.getTLNodeStringValue("DeviceVersion") );
194  }
195 
196  bool master_set = false;
197  int cam_counter = 0;
198 
199  for (int j=0; j<cam_ids_.size(); j++) {
200  bool current_cam_found=false;
201  for (int i=0; i<numCameras_; i++) {
202 
203  acquisition::Camera cam(camList_.GetByIndex(i));
204  if (!EXTERNAL_TRIGGER_){
205  cam.setGetNextImageTimeout(SPINNAKER_GET_NEXT_IMAGE_TIMEOUT_); // set to finite number when not using external triggering
206  }
207 
208  if (cam.get_id().compare(cam_ids_[j]) == 0) {
209  current_cam_found=true;
210  if (cam.get_id().compare(master_cam_id_) == 0) {
211  cam.make_master();
212  master_set = true;
213  MASTER_CAM_ = cam_counter;
214  }
215 
216  ImagePtr a_null;
217  pResultImages_.push_back(a_null);
218 
219  Mat img;
220  frames_.push_back(img);
221  time_stamps_.push_back("");
222 
223  cams.push_back(cam);
224 
225  camera_image_pubs.push_back(it_->advertiseCamera("camera_array/"+cam_names_[j]+"/image_raw", 1));
226  //camera_info_pubs.push_back(nh_.advertise<sensor_msgs::CameraInfo>("camera_array/"+cam_names_[j]+"/camera_info", 1));
227 
228  img_msgs.push_back(sensor_msgs::ImagePtr());
229 
230  sensor_msgs::CameraInfoPtr ci_msg(new sensor_msgs::CameraInfo());
231 
232  //int image_width = 0;
233  //int image_height = 0;
234  nh_pvt_.getParam("image_height", image_height_);
235  nh_pvt_.getParam("image_width", image_width_);
236  // full resolution image_size
237  ci_msg->height = image_height_;
238  ci_msg->width = image_width_;
239 
240  std::string distortion_model = "";
241  nh_pvt_.getParam("distortion_model", distortion_model);
242 
243  // distortion
244  ci_msg->distortion_model = distortion_model;
245  // binning
246  ci_msg->binning_x = binning_;
247  ci_msg->binning_y = binning_;
248 
250  ci_msg->roi.do_rectify = true;
251  ci_msg->roi.width = region_of_interest_width_;
252  ci_msg->roi.height = region_of_interest_height_;
253  ci_msg->roi.x_offset = region_of_interest_x_offset_;
254  ci_msg->roi.y_offset = region_of_interest_y_offset_;
255  }
256 
257  if (PUBLISH_CAM_INFO_){
258  ci_msg->D = distortion_coeff_vec_[j];
259  // intrinsic coefficients
260  for (int count = 0; count<intrinsic_coeff_vec_[j].size();count++){
261  ci_msg->K[count] = intrinsic_coeff_vec_[j][count];
262  }
263  // Rectification matrix
264  if (!rect_coeff_vec_.empty())
265  ci_msg->R = {
266  rect_coeff_vec_[j][0], rect_coeff_vec_[j][1],
267  rect_coeff_vec_[j][2], rect_coeff_vec_[j][3],
268  rect_coeff_vec_[j][4], rect_coeff_vec_[j][5],
269  rect_coeff_vec_[j][6], rect_coeff_vec_[j][7],
270  rect_coeff_vec_[j][8]};
271  // Projection/camera matrix
272  if (!proj_coeff_vec_.empty()){
273  ci_msg->P = {
274  proj_coeff_vec_[j][0], proj_coeff_vec_[j][1],
275  proj_coeff_vec_[j][2], proj_coeff_vec_[j][3],
276  proj_coeff_vec_[j][4], proj_coeff_vec_[j][5],
277  proj_coeff_vec_[j][6], proj_coeff_vec_[j][7],
278  proj_coeff_vec_[j][8], proj_coeff_vec_[j][9],
279  proj_coeff_vec_[j][10], proj_coeff_vec_[j][11]};
280  }
281  //else if(numCameras_ == 1){
282  else if(cam_ids_.size() == 1){
283  // for case of monocular camera, P[1:3,1:3]=K
284  ci_msg->P = {
286  intrinsic_coeff_vec_[j][2], 0,
287  intrinsic_coeff_vec_[j][3], intrinsic_coeff_vec_[j][4],
288  intrinsic_coeff_vec_[j][5], 0,
289  intrinsic_coeff_vec_[j][6], intrinsic_coeff_vec_[j][7],
290  intrinsic_coeff_vec_[j][8], 0};
291  }
292  }
293 
294  cam_info_msgs.push_back(ci_msg);
295  cam_counter++;
296  }
297  }
298  if (!current_cam_found) ROS_WARN_STREAM(" Camera "<<cam_ids_[j]<<" not detected!!!");
299  }
300  ROS_ASSERT_MSG(cams.size(),"None of the connected cameras are in the config list!");
301 
302  // Setting numCameras_ variable to reflect number of camera objects used.
303  // numCameras_ variable is used in other methods where it means size of cams list.
304  numCameras_ = cams.size();
305  // setting PUBLISH_CAM_INFO_ to true so export to ros method can publish it_.advertiseCamera msg with zero intrisics and distortion coeffs.
306  PUBLISH_CAM_INFO_ = true;
307 
308  if (!EXTERNAL_TRIGGER_)
309  ROS_ASSERT_MSG(master_set,"The camera supposed to be the master isn't connected!");
310 }
311 
313 
314  ROS_INFO_STREAM("*** PARAMETER SETTINGS ***");
315  ROS_INFO_STREAM("** Date = "<<todays_date_);
316 
317  if (nh_pvt_.getParam("save_path", path_)){
318  if(path_.front() =='~'){
319  const char *homedir;
320  if ((homedir = getenv("HOME")) == NULL)
321  homedir = getpwuid(getuid())->pw_dir;
322  std::string hd(homedir);
323  path_.replace(0,1,hd);
324  }
325  ROS_INFO_STREAM(" Save path set via parameter to: " << path_);
326  }
327  else {
328  boost::filesystem::path canonicalPath = boost::filesystem::canonical(".", boost::filesystem::current_path());
329  path_ = canonicalPath.string();
330 
331  ROS_WARN_STREAM(" Save path not provided, data will be saved to: " << path_);
332  }
333 
334  if (path_.back() != '/')
335  path_ = path_ + '/';
336 
337  struct stat sb;
338  ROS_ASSERT_MSG(stat(path_.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode),"Specified Path Doesn't Exist!!!");
339 
340  ROS_INFO(" Camera IDs:");
341 
342  std::vector<int> cam_id_vec;
343  ROS_ASSERT_MSG(nh_pvt_.getParam("cam_ids", cam_id_vec),"If cam_aliases are provided, they should be the same number as cam_ids and should correspond in order!");
344  int num_ids = cam_id_vec.size();
345  for (int i=0; i < num_ids; i++){
346  cam_ids_.push_back(to_string(cam_id_vec[i]));
347  ROS_INFO_STREAM(" " << to_string(cam_id_vec[i]));
348  }
349 
350  std::vector<string> cam_alias_vec;
351  if (nh_pvt_.getParam("cam_aliases", cam_names_)){
352  ROS_INFO_STREAM(" Camera Aliases:");
353  ROS_ASSERT_MSG(num_ids == cam_names_.size(),"If cam_aliases are provided, they should be the same number as cam_ids and should correspond in order!");
354  for (int i=0; i<cam_names_.size(); i++) {
355  ROS_INFO_STREAM(" " << cam_ids_[i] << " >> " << cam_names_[i]);
356  }
357  } else {
358  ROS_INFO_STREAM(" No camera aliases provided. Camera IDs will be used as names.");
359  for (int i=0; i<cam_ids_.size(); i++)
360  cam_names_.push_back(cam_ids_[i]);
361  }
362 
363  if (nh_pvt_.getParam("external_trigger", EXTERNAL_TRIGGER_)){
364  ROS_INFO(" External trigger: %s",EXTERNAL_TRIGGER_?"true":"false");
365  }
366  else ROS_WARN(" 'external_trigger' Parameter not set, using default behavior external_trigger=%s",EXTERNAL_TRIGGER_?"true":"false");
367 
368  #ifndef trigger_msgs_FOUND
369  if (EXTERNAL_TRIGGER_)
370  ROS_WARN(" Using 'external_trigger'. Trigger msgs package not found, will use machine timestamps");
371  #endif
372 
373  // Unless external trigger is being used, a master cam needs to be specified
374  // If the external trigger is set, all the cameras are set up as slave int mcam_int;
375 
376  int mcam_int;
377 
378  if (!EXTERNAL_TRIGGER_){
379  ROS_ASSERT_MSG(nh_pvt_.getParam("master_cam", mcam_int),"master_cam is required!");
380 
381  master_cam_id_=to_string(mcam_int);
382  bool found = false;
383  for (int i=0; i<cam_ids_.size(); i++) {
384  if (master_cam_id_.compare(cam_ids_[i]) == 0)
385  found = true;
386  }
387  ROS_ASSERT_MSG(found,"Specified master cam is not in the cam_ids list!");
388  }
389 
390  if (nh_pvt_.getParam("utstamps", MASTER_TIMESTAMP_FOR_ALL_)){
392  ROS_INFO(" Unique time stamps for each camera: %s",!MASTER_TIMESTAMP_FOR_ALL_?"true":"false");
393  }
394  else ROS_WARN(" 'utstamps' Parameter not set, using default behavior utstamps=%s",!MASTER_TIMESTAMP_FOR_ALL_?"true":"false");
395 
396  if (nh_pvt_.getParam("color", color_))
397  ROS_INFO(" color set to: %s",color_?"true":"false");
398  else ROS_WARN(" 'color' Parameter not set, using default behavior color=%s",color_?"true":"false");
399 
400  if (nh_pvt_.getParam("flip_horizontal", flip_horizontal_vec_)){
401  ROS_ASSERT_MSG(num_ids == flip_horizontal_vec_.size(),"If flip_horizontal flags are provided, they should be the same number as cam_ids and should correspond in order!");
402  for (int i=0; i<flip_horizontal_vec_.size(); i++) {
403  ROS_INFO_STREAM(" "<<cam_ids_[i] << " flip_horizontal " << flip_horizontal_vec_[i]);
404  }
405  }
406  else {
407  ROS_WARN_STREAM(" flip_horizontal flags are not provided. default behavior is false ");
408  for (int i=0; i<cam_ids_.size(); i++){
409  flip_horizontal_vec_.push_back(false);
410  ROS_WARN_STREAM(" "<<cam_ids_[i] << " flip_horizontal set to default = " << flip_horizontal_vec_[i]);
411  }
412  }
413 
414  if (nh_pvt_.getParam("flip_vertical", flip_vertical_vec_)){
415  ROS_ASSERT_MSG(num_ids == flip_vertical_vec_.size(),"If flip_vertical flags are provided, they should be the same number as cam_ids and should correspond in order!");
416  for (int i=0; i<flip_vertical_vec_.size(); i++) {
417  ROS_INFO_STREAM(" "<<cam_ids_[i] << " flip_vertical " << flip_vertical_vec_[i]);
418  }
419  }
420  else {
421  ROS_WARN_STREAM(" flip_vertical flags are not provided. default behavior is false ");
422  for (int i=0; i<cam_ids_.size(); i++){
423  flip_vertical_vec_.push_back(false);
424  ROS_WARN_STREAM(" "<<cam_ids_[i] << " flip_vertical set to default = " << flip_vertical_vec_[i]);
425  }
426  }
427 
428  if (nh_pvt_.getParam("to_ros", EXPORT_TO_ROS_))
429  ROS_INFO(" Exporting images to ROS: %s",EXPORT_TO_ROS_?"true":"false");
430  else ROS_WARN(" 'to_ros' Parameter not set, using default behavior to_ros=%s",EXPORT_TO_ROS_?"true":"false");
431 
432  if (nh_pvt_.getParam("live", LIVE_))
433  ROS_INFO(" Showing live images setting: %s",LIVE_?"true":"false");
434  else ROS_WARN(" 'live' Parameter not set, using default behavior live=%s",LIVE_?"true":"false");
435 
436  if (nh_pvt_.getParam("live_grid", GRID_VIEW_)){
438  ROS_INFO(" Showing grid-style live images setting: %s",GRID_VIEW_?"true":"false");
439  } else ROS_WARN(" 'live_grid' Parameter not set, using default behavior live_grid=%s",GRID_VIEW_?"true":"false");
440 
441  if (nh_pvt_.getParam("max_rate_save", MAX_RATE_SAVE_))
442  ROS_INFO(" Max Rate Save Mode: %s",MAX_RATE_SAVE_?"true":"false");
443  else ROS_WARN(" 'max_rate_save' Parameter not set, using default behavior max_rate_save=%s",MAX_RATE_SAVE_?"true":"false");
444 
445  if (nh_pvt_.getParam("time", TIME_BENCHMARK_))
446  ROS_INFO(" Displaying timing details: %s",TIME_BENCHMARK_?"true":"false");
447  else ROS_WARN(" 'time' Parameter not set, using default behavior time=%s",TIME_BENCHMARK_?"true":"false");
448 
449  if (nh_pvt_.getParam("skip", skip_num_)){
450  if (skip_num_ >0) ROS_INFO(" No. of images to skip set to: %d",skip_num_);
451  else {
452  skip_num_=20;
453  ROS_WARN(" Provided 'skip' is not valid, using default behavior, skip=%d",skip_num_);
454  }
455  } else ROS_WARN(" 'skip' Parameter not set, using default behavior: skip=%d",skip_num_);
456 
457  if (nh_pvt_.getParam("delay", init_delay_)){
458  if (init_delay_>=0) ROS_INFO(" Init sleep delays set to : %0.2f sec",init_delay_);
459  else {
460  init_delay_=1;
461  ROS_WARN(" Provided 'delay' is not valid, using default behavior, delay=%f",init_delay_);
462  }
463  } else ROS_WARN(" 'delay' Parameter not set, using default behavior: delay=%f",init_delay_);
464 
465  if (nh_pvt_.getParam("fps", master_fps_)){
466  if (master_fps_>=0) ROS_INFO(" Master cam fps set to : %0.2f",master_fps_);
467  else {
468  master_fps_=20;
469  ROS_WARN(" Provided 'fps' is not valid, using default behavior, fps=%0.2f",master_fps_);
470  }
471  }
472  else ROS_WARN(" 'fps' Parameter not set, using default behavior: fps=%0.2f",master_fps_);
473 
474  if (nh_pvt_.getParam("exposure_time", exposure_time_)){
475  if (exposure_time_ >0) ROS_INFO(" Exposure set to: %.1f",exposure_time_);
476  else ROS_INFO(" 'exposure_time'=%0.f, Setting autoexposure",exposure_time_);
477  } else ROS_WARN(" 'exposure_time' Parameter not set, using default behavior: Automatic Exposure ");
478 
479  if(nh_pvt_.getParam("gain", gain_)){
480  if(gain_>0){
481  ROS_INFO("gain value set to:%.1f",gain_);
482  }
483  else ROS_INFO(" 'gain' Parameter was zero or negative, using Auto gain based on target grey value");
484  }
485  else ROS_WARN(" 'gain' Parameter not set, using default behavior: Auto gain based on target grey value");
486 
487  if (nh_pvt_.getParam("target_grey_value", target_grey_value_)){
488  if (target_grey_value_ >0) ROS_INFO(" target_grey_value set to: %.1f",target_grey_value_);
489  else ROS_INFO(" 'target_grey_value'=%0.f, Setting AutoExposureTargetGreyValueAuto to Continuous/ auto",target_grey_value_);}
490  else ROS_WARN(" 'target_grey_value' Parameter not set, using default behavior: AutoExposureTargetGreyValueAuto to auto");
491 
492 
493  if (nh_pvt_.getParam("binning", binning_)){
494  if (binning_ >0) ROS_INFO(" Binning set to: %d",binning_);
495  else {
496  binning_=1;
497  ROS_INFO(" 'binning'=%d invalid, Using defauly binning=",binning_);
498  }
499  } else ROS_WARN(" 'binning' Parameter not set, using default behavior: Binning = %d",binning_);
500 
501  if (nh_pvt_.getParam("soft_framerate", soft_framerate_)){
502  if (soft_framerate_ >0) {
504  ROS_INFO(" Using Software rate control, rate set to: %d",soft_framerate_);
505  }
506  else ROS_INFO(" 'soft_framerate'=%d, software rate control set to off",soft_framerate_);
507  }
508  else ROS_WARN(" 'soft_framerate' Parameter not set, using default behavior: No Software Rate Control ");
509 
510  if (nh_pvt_.getParam("save", SAVE_))
511  ROS_INFO(" Saving images set to: %d",SAVE_);
512  else ROS_WARN(" 'save' Parameter not set, using default behavior save=%d",SAVE_);
513 
514  if (SAVE_||LIVE_){
515  if (nh_pvt_.getParam("save_type", ext_)){
516  if (ext_.compare("bin") == 0) SAVE_BIN_ = true;
517  ROS_INFO_STREAM(" save_type set as: "<<ext_);
518  ext_="."+ext_;
519  }else ROS_WARN(" 'save_type' Parameter not set, using default behavior save=%d",SAVE_);
520  }
521 
522  if (SAVE_||MAX_RATE_SAVE_){
523  if (nh_pvt_.getParam("frames", nframes_)) {
524  if (nframes_>0){
525  FIXED_NUM_FRAMES_ = true;
526  ROS_INFO(" Number of frames to be recorded: %d", nframes_ );
527  }else ROS_INFO(" Frames will be recorded until user termination");
528  }else ROS_WARN(" 'frames' Parameter not set, using defult behavior, frames will be recorded until user termination");
529  }
530 
531  if (nh_pvt_.hasParam("tf_prefix")){
532  nh_pvt_.param<std::string>("tf_prefix", tf_prefix_, "");
533  ROS_INFO_STREAM(" tf_prefix set to: "<<tf_prefix_);
534  }
535  else ROS_WARN(" 'tf_prefix' Parameter not set, using default behavior tf_prefix=" " ");
536 
537  if (nh_pvt_.hasParam("region_of_interest")){
539  if (!nh_pvt_.getParam("region_of_interest/width", region_of_interest_width_)){
540  region_of_interest_set_ = false;
541  }
542  if (!nh_pvt_.getParam("region_of_interest/height", region_of_interest_height_)){
543  region_of_interest_set_ = false;
544  }
545  if (!nh_pvt_.getParam("region_of_interest/x_offset", region_of_interest_x_offset_)){
546  region_of_interest_set_ = false;
547  }
548  if (!nh_pvt_.getParam("region_of_interest/y_offset", region_of_interest_y_offset_)){
549  region_of_interest_set_ = false;
550  }
551 
553  ROS_INFO(" Region of Interest set to width: %d\theight: %d\toffset_x: %d offset_y: %d",
555  } else ROS_ERROR(" 'region_of_interest' Parameter found but not configured correctly, NOT BEING USED");
556  } else ROS_INFO_STREAM(" 'region of interest' not set using full resolution");
557 
558  bool intrinsics_list_provided = false;
559  XmlRpc::XmlRpcValue intrinsics_list;
560  if (nh_pvt_.getParam("intrinsic_coeffs", intrinsics_list)) {
561  ROS_INFO(" Camera Intrinsic Paramters:");
562  ROS_ASSERT_MSG(intrinsics_list.size() == num_ids,"If intrinsic_coeffs are provided, they should be the same number as cam_ids and should correspond in order!");
563  for (int i=0; i<intrinsics_list.size(); i++){
564  std::vector<double> intrinsics;
565  String intrinsics_str="";
566  for (int j=0; j<intrinsics_list[i].size(); j++){
567  ROS_ASSERT_MSG(intrinsics_list[i][j].getType()== XmlRpc::XmlRpcValue::TypeDouble,"Make sure all numbers are entered as doubles eg. 0.0 or 1.1");
568  intrinsics.push_back(static_cast<double>(intrinsics_list[i][j]));
569  intrinsics_str = intrinsics_str +to_string(intrinsics[j])+" ";
570  }
571 
572  intrinsic_coeff_vec_.push_back(intrinsics);
573  ROS_INFO_STREAM(" "<< intrinsics_str );
574  intrinsics_list_provided=true;
575  }
576  }
577  bool distort_list_provided = false;
578  XmlRpc::XmlRpcValue distort_list;
579 
580  if (nh_pvt_.getParam("distortion_coeffs", distort_list)) {
581  ROS_INFO(" Camera Distortion Paramters:");
582  ROS_ASSERT_MSG(distort_list.size() == num_ids,"If intrinsic_coeffs are provided, they should be the same number as cam_ids and should correspond in order!");
583  for (int i=0; i<distort_list.size(); i++){
584  std::vector<double> distort;
585  String distort_str="";
586  for (int j=0; j<distort_list[i].size(); j++){
587  ROS_ASSERT_MSG(distort_list[i][j].getType()== XmlRpc::XmlRpcValue::TypeDouble,"Make sure all numbers are entered as doubles eg. 0.0 or 1.1");
588  distort.push_back(static_cast<double>(distort_list[i][j]));
589  distort_str = distort_str +to_string(distort[j])+" ";
590  }
591  distortion_coeff_vec_.push_back(distort);
592  ROS_INFO_STREAM(" "<< distort_str );
593  distort_list_provided = true;
594  }
595  }
596 
597  XmlRpc::XmlRpcValue rect_list;
598 
599  if (nh_pvt_.getParam("rectification_coeffs", rect_list)) {
600  ROS_INFO(" Camera Rectification Paramters:");
601  ROS_ASSERT_MSG(rect_list.size() == num_ids,"If rectification_coeffs are provided, they should be the same number as cam_ids and should correspond in order!");
602  for (int i=0; i<rect_list.size(); i++){
603  std::vector<double> rect;
604  String rect_str="";
605  for (int j=0; j<rect_list[i].size(); j++){
606  ROS_ASSERT_MSG(rect_list[i][j].getType()== XmlRpc::XmlRpcValue::TypeDouble,"Make sure all numbers are entered as doubles eg. 0.0 or 1.1");
607  rect.push_back(static_cast<double>(rect_list[i][j]));
608  rect_str = rect_str +to_string(rect[j])+" ";
609  }
610  rect_coeff_vec_.push_back(rect);
611  ROS_INFO_STREAM(" "<< rect_str );
612  }
613  }
614 
615  XmlRpc::XmlRpcValue proj_list;
616 
617  if (nh_pvt_.getParam("projection_coeffs", proj_list)) {
618  ROS_INFO(" Camera Projection Paramters:");
619  ROS_ASSERT_MSG(proj_list.size() == num_ids,"If projection_coeffs are provided, they should be the same number as cam_ids and should correspond in order!");
620  for (int i=0; i<proj_list.size(); i++){
621  std::vector<double> proj;
622  String proj_str="";
623  for (int j=0; j<proj_list[i].size(); j++){
624  ROS_ASSERT_MSG(proj_list[i][j].getType()== XmlRpc::XmlRpcValue::TypeDouble,"Make sure all numbers are entered as doubles eg. 0.0 or 1.1");
625  proj.push_back(static_cast<double>(proj_list[i][j]));
626  proj_str = proj_str +to_string(proj[j])+" ";
627  }
628  proj_coeff_vec_.push_back(proj);
629  ROS_INFO_STREAM(" "<< proj_str );
630  }
631  }
632 
633  PUBLISH_CAM_INFO_ = intrinsics_list_provided && distort_list_provided;
634  if (PUBLISH_CAM_INFO_)
635  ROS_INFO(" Camera coeffs provided, camera info messges will be published.");
636  else
637  ROS_WARN(" Camera coeffs not provided correctly, camera info messges intrinsics and distortion coeffs will be published with zeros.");
638 
639 // ROS_ASSERT_MSG(my_list.getType()
640 // int num_ids = cam_id_vec.size();
641 // for (int i=0; i < num_ids; i++){
642 // cam_ids_.push_back(to_string(cam_id_vec[i]));
643 // ROS_INFO_STREAM(" " << to_string(cam_id_vec[i]));
644 // }
645 
646 }
647 
648 
650 
651  ROS_INFO_STREAM("*** FLUSH SEQUENCE ***");
652 
653  init_cameras(true);
654 
656  sleep(init_delay_*0.5);
657 
658  end_acquisition();
659  sleep(init_delay_*0.5);
660 
661  deinit_cameras();
662  sleep(init_delay_*2.0);
663 
664  init_cameras(false);
665 
666  ROS_DEBUG_STREAM("Flush sequence done.");
667 
668 }
669 
670 void acquisition::Capture::init_cameras(bool soft = false) {
671 
672  ROS_INFO_STREAM("Initializing cameras...");
673 
674  // Set cameras 1 to 4 to continuous
675  for (int i = numCameras_-1 ; i >=0 ; i--) {
676 
677  ROS_DEBUG_STREAM("Initializing camera " << cam_ids_[i] << "...");
678 
679  try {
680 
681  cams[i].init();
682 
683  if (!soft) {
684 
685  cams[i].set_color(color_);
686  cams[i].setIntValue("BinningHorizontal", binning_);
687  cams[i].setIntValue("BinningVertical", binning_);
688  cams[i].setEnumValue("ExposureMode", "Timed");
689  cams[i].setBoolValue("ReverseX", flip_horizontal_vec_[i]);
690  cams[i].setBoolValue("ReverseY", flip_vertical_vec_[i]);
691 
693  if (region_of_interest_width_ != 0)
694  cams[i].setIntValue("Width", region_of_interest_width_);
696  cams[i].setIntValue("Height", region_of_interest_height_);
697  cams[i].setIntValue("OffsetX", region_of_interest_x_offset_);
698  cams[i].setIntValue("OffsetY", region_of_interest_y_offset_);
699  }
700 
701  if (exposure_time_ > 0) {
702  cams[i].setEnumValue("ExposureAuto", "Off");
703  cams[i].setFloatValue("ExposureTime", exposure_time_);
704  } else {
705  cams[i].setEnumValue("ExposureAuto", "Continuous");
706  }
707 
708  if(gain_>0){ //fixed gain
709  cams[i].setEnumValue("GainAuto", "Off");
710  double max_gain_allowed = cams[i].getFloatValueMax("Gain");
711  if (gain_ <= max_gain_allowed)
712  cams[i].setFloatValue("Gain", gain_);
713  else {
714  cams[i].setFloatValue("Gain", max_gain_allowed);
715  ROS_WARN("Provided Gain value is higher than max allowed, setting gain to %f", max_gain_allowed);
716  }
717  target_grey_value_ = 50;
718  } else {
719  cams[i].setEnumValue("GainAuto","Continuous");
720  }
721 
722  if (target_grey_value_ > 4.0) {
723  cams[i].setEnumValue("AutoExposureTargetGreyValueAuto", "Off");
724  cams[i].setFloatValue("AutoExposureTargetGreyValue", target_grey_value_);
725  } else {
726  cams[i].setEnumValue("AutoExposureTargetGreyValueAuto", "Continuous");
727  }
728 
729  // cams[i].setIntValue("DecimationHorizontal", decimation_);
730  // cams[i].setIntValue("DecimationVertical", decimation_);
731  // cams[i].setFloatValue("AcquisitionFrameRate", 5.0);
732 
733  if (color_)
734  cams[i].setEnumValue("PixelFormat", "BGR8");
735  else
736  cams[i].setEnumValue("PixelFormat", "Mono8");
737  cams[i].setEnumValue("AcquisitionMode", "Continuous");
738 
739  // set only master to be software triggered
740  if (cams[i].is_master()) {
741  if (MAX_RATE_SAVE_){
742  cams[i].setEnumValue("LineSelector", "Line2");
743  cams[i].setEnumValue("LineMode", "Output");
744  cams[i].setBoolValue("AcquisitionFrameRateEnable", false);
745  //cams[i].setFloatValue("AcquisitionFrameRate", 170);
746  } else{
747  cams[i].setEnumValue("TriggerMode", "On");
748  cams[i].setEnumValue("LineSelector", "Line2");
749  cams[i].setEnumValue("LineMode", "Output");
750  cams[i].setEnumValue("TriggerSource", "Software");
751  }
752  //cams[i].setEnumValue("LineSource", "ExposureActive");
753 
754 
755  } else{ // sets the configuration for external trigger: used for all slave cameras
756  // in master slave setup. Also in the mode when another sensor such as IMU triggers
757  // the camera
758  cams[i].setEnumValue("TriggerMode", "On");
759  cams[i].setEnumValue("LineSelector", "Line3");
760  cams[i].setEnumValue("TriggerSource", "Line3");
761  cams[i].setEnumValue("TriggerSelector", "FrameStart");
762  cams[i].setEnumValue("LineMode", "Input");
763 
764 // cams[i].setFloatValue("TriggerDelay", 40.0);
765  cams[i].setEnumValue("TriggerOverlap", "ReadOut");//"Off"
766  cams[i].setEnumValue("TriggerActivation", "RisingEdge");
767  }
768  }
769  }
770 
771  catch (Spinnaker::Exception &e) {
772  string error_msg = e.what();
773  ROS_FATAL_STREAM("Error: " << error_msg);
774  if (error_msg.find("Unable to set PixelFormat to BGR8") >= 0)
775  ROS_WARN("Most likely cause for this error is if your camera can't support color and your are trying to set it to color mode");
776  ros::shutdown();
777  }
778 
779  }
780  ROS_DEBUG_STREAM("All cameras initialized.");
781 }
782 
784 
785  for (int i = numCameras_-1; i>=0; i--)
786  cams[i].begin_acquisition();
787 
788  // for (int i=0; i<numCameras_; i++)
789  // cams[i].begin_acquisition();
790 
791 }
792 
794 
795  for (int i = 0; i < numCameras_; i++)
796  cams[i].end_acquisition();
797 
798 }
799 
801 
802  ROS_INFO_STREAM("Deinitializing cameras...");
803 
804  // end_acquisition();
805 
806  for (int i = numCameras_-1 ; i >=0 ; i--) {
807 
808  ROS_DEBUG_STREAM("Camera "<<i<<": Deinit...");
809  cams[i].deinit();
810  // pCam = NULL;
811  }
812  ROS_INFO_STREAM("All cameras deinitialized.");
813 
814 }
815 
817 
818  ROS_DEBUG_STREAM("Creating camera directories...");
819 
820  for (int i=0; i<numCameras_; i++) {
821  ostringstream ss;
822  ss<<path_<<cam_names_[i];
823  if (mkdir(ss.str().c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0) {
824  ROS_WARN_STREAM("Failed to create directory "<<ss.str()<<"! Data will be written into pre existing directory if it exists...");
825  }
826  }
827 
828  CAM_DIRS_CREATED_ = true;
829 
830 }
831 
833 
834  double t = ros::Time::now().toSec();
835 
836  if (!CAM_DIRS_CREATED_)
838 
839  string timestamp;
840  for (unsigned int i = 0; i < numCameras_; i++) {
841 
842  if (dump) {
843 
844  imwrite(dump_img_.c_str(), frames_[i]);
845  ROS_DEBUG_STREAM("Skipping frame...");
846 
847  } else {
848 
850  timestamp = time_stamps_[MASTER_CAM_];
851  else
852  timestamp = time_stamps_[i];
853 
854  ostringstream filename;
855  filename<< path_ << cam_names_[i] << "/" << timestamp << ext_;
856  ROS_DEBUG_STREAM("Saving image at " << filename.str());
857  //ros image names
858  mesg.name.push_back(filename.str());
859  imwrite(filename.str(), frames_[i]);
860 
861  }
862 
863  }
864 
866 
867 }
868 
870  double t = ros::Time::now().toSec();
871  std_msgs::Header img_msg_header;
872 
873  #ifdef trigger_msgs_FOUND
874  if (EXTERNAL_TRIGGER_){
875  if (latest_imu_trigger_count_ - prev_imu_trigger_count_ > 1 ){
876  ROS_WARN("Difference in trigger count more than 1, latest_count = %d and prev_count = %d",latest_imu_trigger_count_,prev_imu_trigger_count_);
877  }
878 
879  else if (latest_imu_trigger_count_ - prev_imu_trigger_count_ == 0){
880  double wait_time_start = ros::Time::now().toSec();
881  ROS_WARN("Difference in trigger count zero, latest_count = %d and prev_count = %d",latest_imu_trigger_count_,prev_imu_trigger_count_);
882  while(latest_imu_trigger_count_ - prev_imu_trigger_count_ == 0){
883  ros::Duration(0.0001).sleep();
884  }
885  ROS_INFO_STREAM("Time gap for sync messages: "<<ros::Time::now().toSec() - wait_time_start);
886  }
887  img_msg_header.stamp = latest_imu_trigger_time_;
888  prev_imu_trigger_count_ = latest_imu_trigger_count_;
889  }
890  else {
891  img_msg_header.stamp = mesg.header.stamp;
892  }
893  #endif
894 
895  #ifndef trigger_msgs_FOUND
896  img_msg_header.stamp = mesg.header.stamp;
897  #endif
898 
899  string frame_id_prefix;
900  if (tf_prefix_.compare("") != 0)
901  frame_id_prefix = tf_prefix_ +"/";
902  else frame_id_prefix="";
903 
904  for (unsigned int i = 0; i < numCameras_; i++) {
905  img_msg_header.frame_id = frame_id_prefix + "cam_"+to_string(i)+"_optical_frame";
906  cam_info_msgs[i]->header = img_msg_header;
907 
908  if(color_)
909  img_msgs[i]=cv_bridge::CvImage(img_msg_header, "bgr8", frames_[i]).toImageMsg();
910  else
911  img_msgs[i]=cv_bridge::CvImage(img_msg_header, "mono8", frames_[i]).toImageMsg();
912 
913  camera_image_pubs[i].publish(img_msgs[i],cam_info_msgs[i]);
914 
915  }
917 }
918 
920 
921  double t = ros::Time::now().toSec();
922 
923  if (!CAM_DIRS_CREATED_)
925 
926  string timestamp;
927  for (unsigned int i = 0; i < numCameras_; i++) {
928 
929  if (dump) {
930  //imwrite(dump_img_.c_str(), frames_[i]);
931  ROS_DEBUG_STREAM("Skipping frame...");
932  } else {
933 
935  timestamp = time_stamps_[MASTER_CAM_];
936  else
937  timestamp = time_stamps_[i];
938 
939  ostringstream filename;
940  filename<< path_ << cam_names_[i] << "/" << timestamp << ".bin";
941  ROS_DEBUG_STREAM("Saving image at " << filename.str());
942  //ros image names
943  mesg.name.push_back(filename.str());
944  std::ofstream ofs(filename.str());
945  boost::archive::binary_oarchive oa(ofs);
946  oa << frames_[i];
947  ofs.close();
948 
949  }
950 
951  }
953 
954 }
955 
957  //ros time stamp creation
958  //mesg.header.stamp = ros::Time::now();
959  //mesg.time = ros::Time::now();
960  double t = ros::Time::now().toSec();
961 
962  ostringstream ss;
963  ss<<"frameIDs: [";
964 
965  int frameID;
966  int fid_mismatch = 0;
967 
968 
969  for (int i=0; i<numCameras_; i++) {
970  //ROS_INFO_STREAM("CAM ID IS "<< i);
971  frames_[i] = cams[i].grab_mat_frame();
972  //ROS_INFO("sucess");
973  time_stamps_[i] = cams[i].get_time_stamp();
974 
975 
976  if (i==0)
977  frameID = cams[i].get_frame_id();
978  else
979  if (cams[i].get_frame_id() != frameID)
980  fid_mismatch = 1;
981 
982  if (i == numCameras_-1)
983  ss << cams[i].get_frame_id() << "]";
984  else
985  ss << cams[i].get_frame_id() << ", ";
986 
987  }
988  mesg.header.stamp = ros::Time::now();
989  mesg.time = ros::Time::now();
990  string message = ss.str();
991  ROS_DEBUG_STREAM(message);
992 
993  if (fid_mismatch)
994  ROS_WARN_STREAM("Frame IDs for grabbed set of images did not match!");
995 
996  toMat_time_ = ros::Time::now().toSec() - t;
997 
998 }
999 
1002  ROS_INFO("*** ACQUISITION ***");
1003 
1005 
1006  // Camera directories created at first save
1007 
1008  if (LIVE_)namedWindow("Acquisition", CV_WINDOW_NORMAL | CV_WINDOW_KEEPRATIO);
1009 
1010  int count = 0;
1011 
1012  if (!EXTERNAL_TRIGGER_) {
1013  cams[MASTER_CAM_].trigger();
1014  }
1015 
1016  get_mat_images();
1017  if (SAVE_) {
1018  count++;
1019  if (SAVE_BIN_)
1020  save_binary_frames(0);
1021  else
1022  save_mat_frames(0);
1023  }
1024 
1025  if(!VERIFY_BINNING_){
1026  // Gets called only once, when first image is being triggered
1027  for (unsigned int i = 0; i < numCameras_; i++) {
1028  //verify if binning is set successfully
1030  ROS_ASSERT_MSG(cams[i].verifyBinning(binning_), " Failed to set Binning= %d, could be either due to Invalid binning value, try changing binning value or due to spinnaker api bug - failing to set lower binning than previously set value - solution: unplug usb camera and re-plug it back and run to node with desired valid binning", binning_);
1031  }
1032  // warn if full sensor resolution is not same as calibration resolution
1033  cams[i].calibrationParamsTest(image_width_,image_height_);
1034  }
1035  VERIFY_BINNING_ = true;
1036  }
1037 
1038 
1039  ros::Rate ros_rate(soft_framerate_);
1040  try{
1041  while( ros::ok() ) {
1042 
1043  double t = ros::Time::now().toSec();
1044 
1045  if (LIVE_) {
1046  if (GRID_VIEW_) {
1047  update_grid();
1048  imshow("Acquisition", grid_);
1049  } else {
1050  imshow("Acquisition", frames_[CAM_]);
1051  char title[50];
1052  sprintf(title, "cam # = %d, cam ID = %s, cam name = %s", CAM_, cam_ids_[CAM_].c_str(), cam_names_[CAM_].c_str());
1053  displayOverlay("Acquisition", title);
1054  }
1055  }
1056 
1057  int key = cvWaitKey(1);
1058  ROS_DEBUG_STREAM("Key press: "<<(key & 255)<<endl);
1059 
1060  if ( (key & 255)!=255 ) {
1061 
1062  if ( (key & 255)==83 ) {
1063  if (CAM_<numCameras_-1) // RIGHT ARROW
1064  CAM_++;
1065  } else if( (key & 255)==81 ) { // LEFT ARROW
1066  if (CAM_>0)
1067  CAM_--;
1068  } else if( (key & 255)==84 && MANUAL_TRIGGER_) { // t
1069  cams[MASTER_CAM_].trigger();
1070  get_mat_images();
1071  } else if( (key & 255)==32 && !SAVE_) { // SPACE
1072  ROS_INFO_STREAM("Saving frame...");
1073  if (SAVE_BIN_)
1074  save_binary_frames(0);
1075  else{
1076  save_mat_frames(0);
1077  if (!EXPORT_TO_ROS_){
1078  ROS_INFO_STREAM("Exporting frames to ROS...");
1079  export_to_ROS();
1080  }
1081  }
1082  } else if( (key & 255)==27 ) { // ESC
1083  ROS_INFO_STREAM("Terminating...");
1084  cvDestroyAllWindows();
1085  ros::shutdown();
1086  break;
1087  }
1088  ROS_DEBUG_STREAM("active cam switched to: "<<CAM_);
1089  }
1090 
1091  double disp_time_ = ros::Time::now().toSec() - t;
1092 
1093  // Call update functions
1094  if (!MANUAL_TRIGGER_) {
1095  if (!EXTERNAL_TRIGGER_) {
1096  cams[MASTER_CAM_].trigger();
1097  }
1098  get_mat_images();
1099  }
1100 
1101  if (SAVE_) {
1102  count++;
1103  if (SAVE_BIN_)
1104  save_binary_frames(0);
1105  else
1106  save_mat_frames(0);
1107  }
1108 
1109  if (FIXED_NUM_FRAMES_) {
1110  cout<<"Nframes "<< nframes_<<endl;
1111  if (count > nframes_) {
1112  ROS_INFO_STREAM(nframes_ << " frames recorded. Terminating...");
1113  cvDestroyAllWindows();
1114  break;
1115  }
1116  }
1117 
1119  //cams[MASTER_CAM_].targetGreyValueTest();
1120  // ros publishing messages
1122 
1123  // double total_time = grab_time_ + toMat_time_ + disp_time_ + save_mat_time_;
1124  double total_time = toMat_time_ + disp_time_ + save_mat_time_+export_to_ROS_time_;
1126 
1128  "total time (ms): %.1f \tPossible FPS: %.1f\tActual FPS: %.1f",
1129  total_time*1000,1/total_time,1/achieved_time_);
1130 
1131  ROS_INFO_COND(TIME_BENCHMARK_,"Times (ms):- grab: %.1f, disp: %.1f, save: %.1f, exp2ROS: %.1f",
1132  toMat_time_*1000,disp_time_*1000,save_mat_time_*1000,export_to_ROS_time_*1000);
1133 
1135 
1136  if (SOFT_FRAME_RATE_CTRL_) {ros_rate.sleep();}
1137 
1138  }
1139  }
1140  catch(const std::exception &e){
1141  ROS_FATAL_STREAM("Exception: "<<e.what());
1142  }
1143  catch(...){
1144  ROS_FATAL_STREAM("Some unknown exception occured. \v Exiting gracefully, \n possible reason could be Camera Disconnection...");
1145  }
1146  ros::shutdown();
1147  //raise(SIGINT);
1148 }
1149 
1151  std::string token;
1152  std::ifstream file("/proc/meminfo");
1153  unsigned long int total, free;
1154  while (file >> token) {
1155  if (token == "MemTotal:")
1156  if (!(file >> total))
1157  ROS_FATAL_STREAM("Could not poll total memory!");
1158  if (token == "MemAvailable:")
1159  if (!(file >> free)) {
1160  ROS_FATAL_STREAM("Could not poll free memory!");
1161  break;
1162  }
1163  // ignore rest of the line
1164  file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
1165  }
1166  return 1-float(free)/float(total);
1167 }
1168 
1170 
1171  if (!GRID_CREATED_) {
1172  int height = frames_[0].rows;
1173  int width = frames_[0].cols*cams.size();
1174 
1175  if (color_)
1176  grid_.create(height, width, CV_8UC3);
1177  else
1178  grid_.create(height, width, CV_8U);
1179 
1180  GRID_CREATED_ = true;
1181  }
1182 
1183  for (int i=0; i<cams.size(); i++)
1184  frames_[i].copyTo(grid_.colRange(i*frames_[i].cols,i*frames_[i].cols+frames_[i].cols).rowRange(0,grid_.rows));
1185 
1186 }
1187 
1188 //*** CODE FOR MULTITHREADED WRITING
1189 void acquisition::Capture::write_queue_to_disk(queue<ImagePtr>* img_q, int cam_no) {
1190 
1191  ROS_DEBUG(" Write Queue to Disk Thread Initiated for cam: %d", cam_no);
1192 
1193  int imageCnt =0;
1194  string id = cam_ids_[cam_no];
1195 
1196  int k_numImages = nframes_;
1197 
1198  while (imageCnt < k_numImages){
1199 // ROS_DEBUG_STREAM(" Write Queue to Disk for cam: "<< cam_no <<" size = "<<img_q->size());
1200 
1201  #ifdef trigger_msgs_FOUND
1202  // sleep for 5 milliseconds if the queue is empty
1203  if(img_q->empty() || sync_message_queue_vector_.at(cam_no).empty()){
1204  boost::this_thread::sleep(boost::posix_time::milliseconds(5));
1205  continue;
1206  }
1207  #endif
1208 
1209  #ifndef trigger_msgs_FOUND
1210  if(img_q->empty()){
1211  boost::this_thread::sleep(boost::posix_time::milliseconds(5));
1212  continue;
1213  }
1214  #endif
1215 
1216  ROS_DEBUG_STREAM(" Write Queue to Disk for cam: "<< cam_no <<" size = "<<img_q->size());
1217 
1218  if (img_q->size()>100)
1219  ROS_WARN_STREAM(" Queue "<<cam_no<<" size is :"<< img_q->size());
1220 
1221  #ifdef trigger_msgs_FOUND
1222  if (abs((int)img_q->size() - (int)sync_message_queue_vector_.at(cam_no).size()) > 100){
1223  ROS_WARN_STREAM(" The camera image queue size is increasing, the sync trigger messages are not coming at the desired rate");
1224  }
1225  #endif
1226 
1227  ImagePtr convertedImage = img_q->front();
1228 
1229  #ifdef trigger_msgs_FOUND
1230  uint64_t timeStamp;
1231  if (EXTERNAL_TRIGGER_){
1232  SyncInfo_ sync_info = sync_message_queue_vector_.at(cam_no).front();
1233  sync_info.latest_imu_trigger_count_;
1234  timeStamp = sync_info.latest_imu_trigger_time_.toSec() * 1e6;
1235  ROS_INFO("time Queue size for cam %d is = %d",cam_no,sync_message_queue_vector_.at(cam_no).size());
1236  sync_message_queue_vector_.at(cam_no).pop();
1237  }
1238  else{
1239  timeStamp = convertedImage->GetTimeStamp() * 1e6;
1240  }
1241  #endif
1242 
1243  #ifndef trigger_msgs_FOUND
1244  uint64_t timeStamp = convertedImage->GetTimeStamp() * 1e6;
1245  #endif
1246 
1247  // Create a unique filename
1248  ostringstream filename;
1249  filename<<path_<<cam_names_[cam_no]<<"/"<<cam_names_[cam_no]
1250  <<"_"<<id<<"_"<<todays_date_ << "_"<<std::setfill('0')
1251  << std::setw(6) << imageCnt<<"_"<<timeStamp << ext_;
1252 
1253 // ROS_DEBUG_STREAM("Writing to "<<filename.str().c_str());
1254 
1255  convertedImage->Save(filename.str().c_str());
1256  // release the image before popping out to save memory
1257  convertedImage->Release();
1258  ROS_INFO("image Queue size for cam %d is = %zu",cam_no, img_q->size());
1259  queue_mutex_.lock();
1260  img_q->pop();
1261  queue_mutex_.unlock();
1262 
1263  ROS_DEBUG_STREAM("Image saved at " << filename.str());
1264  imageCnt++;
1265  }
1266 }
1267 
1268 void acquisition::Capture::acquire_images_to_queue(vector<queue<ImagePtr>>* img_qs) {
1269  int result = 0;
1270 
1271  ROS_DEBUG(" Acquire Images to Queue Thread Initiated");
1273  ROS_DEBUG(" Acquire Images to Queue Thread -> Acquisition Started");
1274 
1275  // Retrieve, convert, and save images for each camera
1276 
1277  int k_numImages = nframes_;
1278  auto start = ros::Time::now().toSec();
1279  auto elapsed = (ros::Time::now().toSec() - start)*1000;
1280 
1281  double flush_start_time = ros::Time::now().toSec();
1282  while ((ros::Time::now().toSec() - flush_start_time) < 3.0){
1283  for (int i = 0; i < numCameras_; i++) {
1284  cams[i].grab_frame();
1285  }
1286  ROS_DEBUG("Flushing time elapsed: %.3f",ros::Time::now().toSec() - flush_start_time);
1287  }
1288 
1289  first_image_received = true;
1290 
1291  for (int imageCnt = 0; imageCnt < k_numImages; imageCnt++) {
1292  uint64_t timeStamp = 0;
1293  for (int i = 0; i < numCameras_; i++) {
1294  try {
1295  // grab_frame() is a blocking call. It waits for the next image acquired by the camera
1296  //ImagePtr pResultImage = cams[i].grab_frame();
1297  ImagePtr convertedImage = cams[i].grab_frame();
1298  // Convert image to mono 8
1299  //ImagePtr convertedImage = pResultImage->Convert(PixelFormat_Mono8, HQ_LINEAR);
1300 
1301  if(cams[i].is_master()) {
1302  mesg.header.stamp = ros::Time::now();
1303  }
1304  timeStamp = convertedImage->GetTimeStamp() * 1000;
1305  // Create a unique filename
1306  ostringstream filename;
1307  //filename << cam_ids_[i].c_str()<< "-" << imageCnt << ext_;
1308  filename << cam_names_[i]<<"_"<<cam_ids_[i].c_str()
1309  << "_"<<todays_date_ << "_"<< std::setfill('0')
1310  << std::setw(6) << imageCnt<<"_"<<timeStamp << ext_;
1311  imageNames.push_back(filename.str());
1312 
1313  queue_mutex_.lock();
1314  img_qs->at(i).push(convertedImage);
1315  queue_mutex_.unlock();
1316 
1317  ROS_DEBUG_STREAM("Queue no. "<<i<<" size: "<<img_qs->at(i).size());
1318 
1319  // Release image
1320  //convertedImage->Release();
1321  }
1322  catch (Spinnaker::Exception &e) {
1323  ROS_ERROR_STREAM(" Exception in Acquire to queue thread" << "\nError: " << e.what());
1324  result = -1;
1325  }
1326  if(i==0) {
1327  elapsed = (ros::Time::now().toSec() - start)*1000;
1328  start = ros::Time::now().toSec();
1329  //cout << "Microsecs passed: " << microseconds << endl;
1330  ROS_DEBUG_STREAM("Rate of cam 0 write to queue: " << 1e3/elapsed);
1331  }
1332  }
1333  mesg.name = imageNames;
1334  //make sure that the vector has no image file names
1335  imageNames.clear();
1336 
1337  // ros publishing messages
1339  }
1340  return;
1341 }
1342 
1344  ROS_INFO("*** ACQUISITION MULTI-THREADED***");
1345 
1346  if (!CAM_DIRS_CREATED_)
1348 
1349  boost::thread_group threads;
1350 
1351  vector<std::queue<ImagePtr>> image_queue_vector;
1352 
1353  for (int i=0; i<numCameras_; i++) {
1354  std::queue<ImagePtr> img_ptr_queue;
1355  image_queue_vector.push_back(img_ptr_queue);
1356  }
1357 
1358  // start
1359  threads.create_thread(boost::bind(&Capture::acquire_images_to_queue, this, &image_queue_vector));
1360 
1361  // assign a new thread to write the nth image to disk acquired in a queue
1362  for (int i=0; i<numCameras_; i++)
1363  threads.create_thread(boost::bind(&Capture::write_queue_to_disk, this, &image_queue_vector.at(i), i));
1364 
1365  threads.join_all();
1366  ROS_DEBUG("All Threads Joined");
1367 }
1368 
1370  if (MAX_RATE_SAVE_)
1371  run_mt();
1372  else
1373  run_soft_trig();
1374  ROS_DEBUG("Run completed");
1375 }
1376 
1378 {
1379  char out[9];
1380  std::time_t t=std::time(NULL);
1381  std::strftime(out, sizeof(out), "%Y%m%d", std::localtime(&t));
1382  std::string td(out);
1383  return td;
1384 }
1385 
1386 void acquisition::Capture::dynamicReconfigureCallback(spinnaker_sdk_camera_driver::spinnaker_camConfig &config, uint32_t level){
1387 
1388  ROS_INFO_STREAM("Dynamic Reconfigure: Level : " << level);
1389  if(level == 1 || level ==3){
1390  ROS_INFO_STREAM("Target grey value : " << config.target_grey_value);
1391  for (int i = numCameras_-1 ; i >=0 ; i--) {
1392 
1393  cams[i].setEnumValue("AutoExposureTargetGreyValueAuto", "Off");
1394  cams[i].setFloatValue("AutoExposureTargetGreyValue", config.target_grey_value);
1395  }
1396  }
1397  if (level == 2 || level ==3){
1398  ROS_INFO_STREAM("Exposure "<<config.exposure_time);
1399  if(config.exposure_time > 0){
1400  for (int i = numCameras_-1 ; i >=0 ; i--) {
1401 
1402  cams[i].setEnumValue("ExposureAuto", "Off");
1403  cams[i].setEnumValue("ExposureMode", "Timed");
1404  cams[i].setFloatValue("ExposureTime", config.exposure_time);
1405  }
1406  }
1407  else if(config.exposure_time ==0){
1408  for (int i = numCameras_-1 ; i >=0 ; i--) {
1409  cams[i].setEnumValue("ExposureAuto", "Continuous");
1410  cams[i].setEnumValue("ExposureMode", "Timed");
1411  }
1412  }
1413  }
1414 }
1415 
1416 #ifdef trigger_msgs_FOUND
1417  void acquisition::Capture::assignTimeStampCallback(const trigger_msgs::sync_trigger::ConstPtr& msg){
1418  //ROS_INFO_STREAM("Time stamp is "<< msg->header.stamp);
1419 
1420  SyncInfo_ sync_info;
1421  latest_imu_trigger_count_ = msg->count;
1422  latest_imu_trigger_time_ = msg->header.stamp;
1423  sync_info.latest_imu_trigger_count_ = latest_imu_trigger_count_;
1424  sync_info.latest_imu_trigger_time_ = latest_imu_trigger_time_;
1425  ROS_DEBUG("Sync trigger receieved");
1427  for (int i = 0; i < numCameras_; i++){
1428  sync_message_queue_vector_.at(i).push(sync_info);
1429  ROS_DEBUG("Sync trigger added to cam: %d, length of queue: %d",i,sync_message_queue_vector_.at(i).size());
1430  }
1431  }
1432  //double curr_time_msg_recieved = ros::Time::now().toSec();
1433  //sync_trigger_rate = 1/(curr_time_msg_recieved - last_time_msg_recieved);
1434  //last_time_msg_recieved = curr_time_msg_recieved;
1435  }
1436 #endif
int region_of_interest_height_
Definition: capture.h:165
bool first_image_received
Definition: capture.h:120
void acquire_images_to_queue(vector< queue< ImagePtr >> *)
Definition: capture.cpp:1268
vector< vector< double > > distortion_coeff_vec_
Definition: capture.h:96
void start_acquisition()
Definition: capture.cpp:783
double export_to_ROS_time_
Definition: capture.h:107
void publish(const boost::shared_ptr< M > &message) const
int region_of_interest_width_
Definition: capture.h:164
vector< string > cam_ids_
Definition: capture.h:86
void write_queue_to_disk(queue< ImagePtr > *, int)
Definition: capture.cpp:1189
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
std::shared_ptr< boost::thread > pubThread_
Definition: capture.h:46
void setGetNextImageTimeout(uint64_t get_next_image_timeout)
Definition: camera.h:68
int size() const
virtual void onInit()
Definition: capture.cpp:47
bool sleep() const
vector< string > cam_names_
Definition: capture.h:87
std::string todays_date()
Definition: capture.cpp:1377
void init_variables_register_to_ros()
Definition: capture.cpp:61
CameraList camList_
Definition: capture.h:84
int region_of_interest_y_offset_
Definition: capture.h:167
#define ROS_WARN(...)
bool SOFT_FRAME_RATE_CTRL_
Definition: capture.h:141
ros::NodeHandle & getPrivateNodeHandle() const
vector< vector< double > > intrinsic_coeff_vec_
Definition: capture.h:95
#define ROS_FATAL_STREAM(args)
double save_mat_time_
Definition: capture.h:107
#define ROS_INFO(...)
ros::NodeHandle nh_pvt_
Definition: capture.h:175
vector< bool > flip_vertical_vec_
Definition: capture.h:101
bool param(const std::string &param_name, T &param_val, const T &default_val) const
#define ROS_ASSERT_MSG(cond,...)
vector< string > time_stamps_
Definition: capture.h:93
void dynamicReconfigureCallback(spinnaker_sdk_camera_driver::spinnaker_camConfig &config, uint32_t level)
Definition: capture.cpp:1386
double achieved_time_
Definition: capture.h:107
ROSCPP_DECL bool ok()
dynamic_reconfigure::Server< spinnaker_sdk_camera_driver::spinnaker_camConfig > * dynamicReCfgServer_
Definition: capture.h:178
vector< bool > flip_horizontal_vec_
Definition: capture.h:100
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
ros::NodeHandle & getNodeHandle() const
vector< sensor_msgs::ImagePtr > img_msgs
Definition: capture.h:186
#define ROS_WARN_STREAM(args)
#define ROS_DEBUG_STREAM(args)
ros::NodeHandle nh_
Definition: capture.h:174
spinnaker_sdk_camera_driver::SpinnakerImageNames mesg
Definition: capture.h:188
void save_mat_frames(int)
Definition: capture.cpp:832
bool sleep()
SystemPtr system_
Definition: capture.h:83
#define NODELET_INFO(...)
std::shared_ptr< image_transport::ImageTransport > it_
Definition: capture.h:176
#define ROS_INFO_STREAM(args)
vector< vector< double > > rect_coeff_vec_
Definition: capture.h:97
bool getParam(const std::string &key, std::string &s) const
boost::mutex queue_mutex_
Definition: capture.h:189
#define ROS_INFO_COND(cond,...)
double target_grey_value_
Definition: capture.h:119
static Time now()
vector< sensor_msgs::CameraInfoPtr > cam_info_msgs
Definition: capture.h:187
ROSCPP_DECL void shutdown()
bool region_of_interest_set_
Definition: capture.h:163
void create_cam_directories()
Definition: capture.cpp:816
bool hasParam(const std::string &key) const
#define ROS_ERROR_STREAM(args)
vector< acquisition::Camera > cams
Definition: capture.h:85
vector< ImagePtr > pResultImages_
Definition: capture.h:91
vector< string > imageNames
Definition: capture.h:99
vector< image_transport::CameraPublisher > camera_image_pubs
Definition: capture.h:182
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
unsigned int numCameras_
Definition: capture.h:89
void save_binary_frames(int)
Definition: capture.cpp:919
bool MASTER_TIMESTAMP_FOR_ALL_
Definition: capture.h:132
#define ROS_ERROR(...)
void init_cameras(bool)
Definition: capture.cpp:670
int region_of_interest_x_offset_
Definition: capture.h:166
vector< Mat > frames_
Definition: capture.h:92
sensor_msgs::ImagePtr toImageMsg() const
vector< vector< double > > proj_coeff_vec_
Definition: capture.h:98
uint64_t SPINNAKER_GET_NEXT_IMAGE_TIMEOUT_
Definition: capture.h:146
string master_cam_id_
Definition: capture.h:88
#define ROS_DEBUG(...)
ros::Publisher acquisition_pub
Definition: capture.h:180


spinnaker_sdk_camera_driver
Author(s): Abhishek Bajpayee, Pushyami Kaveti, Vikrant Shah
autogenerated on Sun Feb 14 2021 03:34:42