device_nodelet.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 Roboception GmbH
3  * All rights reserved
4  *
5  * Author: Heiko Hirschmueller, Christian Emmerich
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice,
11  * this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright notice,
14  * this list of conditions and the following disclaimer in the documentation
15  * and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its contributors
18  * may be used to endorse or promote products derived from this software without
19  * specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "device_nodelet.h"
45 
47 
48 #include <rc_genicam_api/device.h>
49 #include <rc_genicam_api/stream.h>
50 #include <rc_genicam_api/buffer.h>
51 #include <rc_genicam_api/config.h>
53 
55 
57 #include <exception>
58 
59 #include <sstream>
60 #include <stdexcept>
61 
62 #include <ros/ros.h>
63 #include <geometry_msgs/PoseWithCovarianceStamped.h>
65 #include <rc_common_msgs/ReturnCodeConstants.h>
66 #include <rc_common_msgs/CameraParam.h>
67 
68 namespace {
69 
71  bool isRcVisardDevice(const std::string& vendor, const std::string& model)
72  {
73  bool isKuka3DPerception = vendor.find("KUKA") != std::string::npos && model.find("3d_perception") != std::string::npos;
74  bool isRcVisard = model.find("rc_visard") != std::string::npos;
75  return isKuka3DPerception || isRcVisard;
76  }
77 
79  std::vector<std::string> discoverRcVisardDevices()
80  {
81  std::vector<std::string> device_ids;
82  for (auto system : rcg::System::getSystems())
83  {
84  system->open();
85  for (auto interf : system->getInterfaces())
86  {
87  interf->open();
88  for (auto dev : interf->getDevices())
89  {
90  if (isRcVisardDevice(dev->getVendor(), dev->getModel()))
91  {
92  device_ids.push_back(dev->getID());
93  }
94  }
95  interf->close();
96  }
97  system->close();
98  }
99  return device_ids;
100  }
101 }
102 
103 namespace rc
104 {
105 namespace rcd = dynamics;
106 using rc_common_msgs::ReturnCodeConstants;
107 
109  const std::string& stream, ros::NodeHandle& nh,
110  const std::string& frame_id_prefix, bool tfEnabled,
111  bool staticImu2CamTf)
112 {
113  if (stream == "pose")
114  {
115  return ThreadedStream::Ptr(new PoseAndTFStream(rcdIface, stream, nh, frame_id_prefix, tfEnabled));
116  }
117  if (stream == "pose_ins" || stream == "pose_rt" || stream == "pose_rt_ins" || stream == "imu")
118  {
119  return ThreadedStream::Ptr(new Protobuf2RosStream(rcdIface, stream, nh, frame_id_prefix));
120  }
121  if (stream == "dynamics" || stream == "dynamics_ins")
122  {
123  return ThreadedStream::Ptr(new DynamicsStream(rcdIface, stream, nh, frame_id_prefix, !staticImu2CamTf));
124  }
125 
126  throw std::runtime_error(std::string("Not yet implemented! Stream type: ") + stream);
127 }
128 
130 {
131  reconfig = 0;
132  dev_supports_gain = false;
133  dev_supports_color = false;
134  dev_supports_chunk_data = false;
135  dev_supports_wb = false;
138  iocontrol_avail = false;
139  dev_supports_double_shot = false;
140  level = 0;
141 
143 
145 
146  stopRecoverThread = false;
147  recoveryRequested = true;
148  cntConsecutiveRecoveryFails = -1; // first time not giving any warnings
154 }
155 
157 {
158  std::cout << "rc_visard_driver: Shutting down" << std::endl;
159 
160  // signal running threads and wait until they finish
161 
162  stopImageThread = true;
163  dynamicsStreams->stop_all();
164  stopRecoverThread = true;
165 
166  if (imageThread.joinable())
167  imageThread.join();
168  dynamicsStreams->join_all();
169  if (recoverThread.joinable())
170  recoverThread.join();
171 
172  delete reconfig;
173 
175 }
176 
178 {
179  // run initialization and recover routine in separate thread
181 
182  // add callbacks for diagnostics publishing
185 }
186 
188 {
189  // get parameter configuration
190 
192 
193  // device defaults to empty string which serves as a wildcard to connect to any
194  // rc_visard as long as only one sensor is available in the network
195  std::string device = "";
196  std::string access = "control";
198 
199  tfEnabled = false;
202  tfPrefix = (ns != "") ? ns + "_" : "";
203 
204  pnh.param("device", device, device);
205  pnh.param("gev_access", access, access);
206  pnh.param("max_reconnects", maxNumRecoveryTrials, maxNumRecoveryTrials);
207  pnh.param("enable_tf", tfEnabled, tfEnabled);
208  pnh.param("autostart_dynamics", autostartDynamics, autostartDynamics);
209  pnh.param("autostart_dynamics_with_slam", autostartSlam, autostartSlam);
210  pnh.param("autostop_dynamics", autostopDynamics, autostopDynamics);
211  pnh.param("autopublish_trajectory", autopublishTrajectory, autopublishTrajectory);
212 
213  rcg::Device::ACCESS access_id;
214  if (access == "exclusive")
215  {
216  access_id = rcg::Device::EXCLUSIVE;
217  }
218  else if (access == "control")
219  {
220  access_id = rcg::Device::CONTROL;
221  }
222  else if (access == "off")
223  {
224  access_id = rcg::Device::READONLY;
225  }
226  else
227  {
228  ROS_FATAL_STREAM("rc_visard_driver: Access must be 'control', 'exclusive' or 'off': " << access);
229  return;
230  }
231 
232  // setup service for depth acquisition trigger
233 
235 
236  // setup services for starting and stopping rcdynamics module
237 
244 
247  slamSaveMapService = pnh.advertiseService("slam_save_map", &DeviceNodelet::saveSlamMap, this);
248  slamLoadMapService = pnh.advertiseService("slam_load_map", &DeviceNodelet::loadSlamMap, this);
249  slamRemoveMapService = pnh.advertiseService("slam_remove_map", &DeviceNodelet::removeSlamMap, this);
250 
252  {
253  trajPublisher = getNodeHandle().advertise<nav_msgs::Path>("trajectory", 10);
254  }
255 
256  // run start-keep-alive-and-recover loop
257 
258  while (!stopRecoverThread && (
259  (maxNumRecoveryTrials < 0) ||
261  ))
262  {
263  // check if everything is running smoothly
264 
265  if (!recoveryRequested)
266  {
267  bool allSucceeded = (!imageRequested || imageSuccess);
268  if ((cntConsecutiveRecoveryFails > 0) && allSucceeded)
269  {
271  ROS_INFO("rc_visard_driver: Device successfully recovered from previous fail(s)!");
272  }
273 
274  updater.update(); // regularly update the status for publishing diagnostics (rate limited by parameter '~diagnostic_period')
275  usleep(1000 * 100);
276  continue;
277  }
278 
279  // it's not running smoothly, we need recovery
280 
284  }
285  updater.force_update(); // immediately update the diagnostics status
286 
287  // stop image and dynamics threads
288 
289  stopImageThread = true;
290  dynamicsStreams->stop_all();
291 
292  if (imageThread.joinable())
293  imageThread.join();
294  dynamicsStreams->join_all();
295 
296  // try discover, open and bring up device
297 
298  bool successfullyOpened = false;
299  while (!stopRecoverThread && !successfullyOpened && (
300  (maxNumRecoveryTrials < 0) ||
302  ))
303  {
304  // if we are recovering, put warning and wait before retrying
305 
307  {
308  ROS_ERROR_STREAM("rc_visard_driver: Failed or lost connection. Trying to recover"
309  " rc_visard_driver from failed state ("
311  << ((maxNumRecoveryTrials>=0) ? std::string("/") + std::to_string(maxNumRecoveryTrials) : "" )
312  << ")...");
313  usleep(1000 * 500);
314  }
315 
316  try
317  {
318  if (rcgdev)
319  {
320  rcgdev->close();
321  }
322 
323  if (device.size() == 0)
324  {
325  ROS_INFO("No device ID given in the private parameter 'device'! Trying to auto-detect a single rc_visard device in the network...");
326  auto device_ids = discoverRcVisardDevices();
327  if (device_ids.size() != 1)
328  {
330  throw std::runtime_error("Auto-connection with rc_visard device failed because none or multiple devices were found!");
331  }
332  ROS_INFO_STREAM("Found rc_visard device '" << device_ids[0] << "'");
333  rcgdev = rcg::getDevice(device_ids[0].c_str());
334  } else {
335  rcgdev = rcg::getDevice(device.c_str());
336  }
337 
338  if (!rcgdev)
339  {
341  throw std::invalid_argument("Unknown or non-unique device '" + device + "'");
342  }
343 
344  ROS_INFO_STREAM("rc_visard_driver: Opening connection to '" << rcgdev->getID() << "'");
345  rcgdev->open(access_id);
346  rcgnodemap = rcgdev->getRemoteNodeMap();
347 
348  // in newer rc_visard image versions, we can check via genicam if rc_visard is ready
349 
350  try {
351  bool isReady = rcg::getBoolean(rcgnodemap, "RcSystemReady", true, true);
352  if (!isReady)
353  {
354  ROS_INFO_STREAM("rc_visard_driver: rc_visard device not yet ready (GEV). Trying again...");
355  continue; // to next trial!
356  }
357  } catch (std::invalid_argument& e)
358  {
359  // genicam feature is not implemented in this version of rc_visard's firmware,
360  // so we have to assume rc_visard is ready and continue
361  }
362 
363  // extract some diagnostics data from device
364  dev_serialno = rcg::getString(rcgnodemap, "DeviceID", true);
365  dev_macaddr = rcg::getString(rcgnodemap, "GevMACAddress", true);
366  dev_ipaddr = rcg::getString(rcgnodemap, "GevCurrentIPAddress", true);
367  dev_version = rcg::getString(rcgnodemap, "DeviceVersion", true);
368  gev_userid = rcg::getString(rcgnodemap, "DeviceUserID", true);
369  gev_packet_size = rcg::getString(rcgnodemap, "GevSCPSPacketSize", true);
370 
373 
374  // instantiating dynamics interface, check if ready, and autostart dynamics on sensor if desired
375 
376  dynamicsInterface = rcd::RemoteInterface::create(dev_ipaddr);
377  try {
378  if (!dynamicsInterface->checkSystemReady())
379  {
380  ROS_INFO_STREAM("rc_visard_driver: rc_visard device not yet ready (REST). Trying again...");
381  continue; // to next trial!
382  }
383  } catch (std::exception& e)
384  {
385  ROS_ERROR_STREAM("rc_visard_driver: checking system ready failed: " << e.what());
386  }
387 
389  {
390  ROS_INFO_STREAM("rc_visard_driver: Auto-start requested (" <<
391  "autostart_dynamics=" << autostartDynamics << ", "
392  "autostart_dynamics_with_slam=" << autostartSlam << ")");
393 
394  rc_common_msgs::Trigger::Request dummyreq;
395  rc_common_msgs::Trigger::Response dummyresp;
396 
397  bool autostart_failed = false;
398  autostart_failed |= (autostartSlam && !this->dynamicsStartSlam(dummyreq, dummyresp));
399  autostart_failed |= (!autostartSlam && autostartDynamics && !this->dynamicsStart(dummyreq, dummyresp));
400  autostart_failed |= dummyresp.return_code.value < ReturnCodeConstants::SUCCESS;
401 
402  if (autostart_failed)
403  {
404  ROS_WARN_STREAM("rc_visard_driver: Could not auto-start dynamics module! " << dummyresp.return_code.message);
406  continue; // to next trial!
407  }
408  }
409 
410  // get and publish static transform between IMU and camera (if feature available)
411 
412  bool staticImu2CamTf = false;
413  try {
414  auto pbFrame = dynamicsInterface->getCam2ImuTransform();
415 
416  // first prefix all frame ids
417  pbFrame.set_name(tfPrefix + pbFrame.name());
418  pbFrame.set_parent(tfPrefix + pbFrame.parent());
419 
420  // invert cam2imu and convert to tf transform
421  auto imu2cam = tf::StampedTransform(
422  toRosTfTransform(pbFrame.pose().pose()).inverse(),
423  toRosTime(pbFrame.pose().timestamp()),
424  pbFrame.name(), pbFrame.parent());
425  // send it
426  geometry_msgs::TransformStamped msg;
427  tf::transformStampedTFToMsg(imu2cam, msg);
429  staticImu2CamTf = true;
430 
431  } catch (rcd::RemoteInterface::NotAvailable& e)
432  {
433  ROS_WARN_STREAM("rc_visard_driver: Could not get and publish static transformation between camera and IMU "
434  << "because feature is not avilable in that rc_visard firmware version. Please update the firmware image "
435  << "or subscribe to the dynamics topic to have that transformation available in tf.");
436  }
437 
438  // add streaming thread for each available stream on rc_visard device
439 
440  auto availStreams = dynamicsInterface->getAvailableStreams();
442  for (const auto& streamName : availStreams)
443  {
444  try
445  {
446  auto newStream =
448  dynamicsStreams->add(newStream);
449  }
450  catch (const std::exception& e)
451  {
452  ROS_WARN_STREAM("rc_visard_driver: Unable to create dynamics stream of type " << streamName << ": "
453  << e.what());
454  }
455  }
456 
457  successfullyOpened = true;
459  }
460  catch (std::exception& ex)
461  {
463  ROS_ERROR_STREAM("rc_visard_driver: " << ex.what());
464  }
465  }
466  if (stopRecoverThread)
467  break;
468 
470  {
471  ROS_FATAL_STREAM("rc_visard_driver: could not recover from failed state!");
472  break;
473  }
474 
475  // start grabbing threads
476 
477  recoveryRequested = false;
478  if (access_id != rcg::Device::READONLY)
479  {
480  imageThread = std::thread(&DeviceNodelet::grab, this, device, access_id);
481  }
482  dynamicsStreams->start_all();
483 
484  }
485 
486  if (autostopDynamics)
487  {
488  rc_common_msgs::Trigger::Request dummyreq;
489  rc_common_msgs::Trigger::Response dummyresp;
490  ROS_INFO("rc_visard_driver: Autostop dynamics ...");
491  if (!this->dynamicsStop(dummyreq, dummyresp))
492  { // autostop failed!
493  ROS_WARN("rc_visard_driver: Could not auto-stop dynamics module!");
494  }
495  }
496  std::cout << "rc_visard_driver: stopped." << std::endl;
497 }
498 
499 void DeviceNodelet::initConfiguration(const std::shared_ptr<GenApi::CNodeMapRef>& nodemap,
500  rc_visard_driver::rc_visard_driverConfig& cfg, rcg::Device::ACCESS access)
501 {
503 
504  // get current camera configuration
505 
506  cfg.camera_fps = rcg::getFloat(nodemap, "AcquisitionFrameRate", 0, 0, true);
507 
508  std::string v = rcg::getEnum(nodemap, "ExposureAuto", true);
509  cfg.camera_exp_auto = (v != "Off");
510 
511  if (cfg.camera_exp_auto)
512  {
513  if (v == "Continuous")
514  {
515  cfg.camera_exp_auto_mode = "Normal";
516  }
517  else
518  {
519  cfg.camera_exp_auto_mode = v;
520  }
521  }
522 
523  cfg.camera_exp_value = rcg::getFloat(nodemap, "ExposureTime", 0, 0, true) / 1000000;
524  cfg.camera_exp_max = rcg::getFloat(nodemap, "ExposureTimeAutoMax", 0, 0, true) / 1000000;
525 
526  // get optional exposure region
527  cfg.camera_exp_width = rcg::getInteger(nodemap, "ExposureRegionWidth", 0, 0, false);
528  cfg.camera_exp_height = rcg::getInteger(nodemap, "ExposureRegionHeight", 0, 0, false);
529  cfg.camera_exp_offset_x = rcg::getInteger(nodemap, "ExposureRegionOffsetX", 0, 0, false);
530  cfg.camera_exp_offset_y = rcg::getInteger(nodemap, "ExposureRegionOffsetY", 0, 0, false);
531 
532  // get optional gain value
533 
534  v = rcg::getEnum(nodemap, "GainSelector", false);
535  if (v.size() > 0)
536  {
537  dev_supports_gain = true;
538 
539  if (v != "All")
540  {
541  dev_supports_gain = rcg::setEnum(nodemap, "GainSelector", "All", true);
542  }
543 
544  if (dev_supports_gain)
545  {
546  cfg.camera_gain_value = rcg::getFloat(nodemap, "Gain", 0, 0, true);
547  }
548  }
549  else
550  {
551  ROS_WARN("rc_visard_driver: Device does not support setting gain. gain_value is without function.");
552 
553  dev_supports_gain = false;
554  cfg.camera_gain_value = 0;
555  }
556 
557  // check if camera is color camera
558 
559  std::vector<std::string> formats;
560  rcg::setEnum(rcgnodemap, "ComponentSelector", "Intensity", true);
561  rcg::getEnum(rcgnodemap, "PixelFormat", formats, true);
562  for (auto&& format : formats)
563  {
564  if (format == "YCbCr411_8")
565  {
566  dev_supports_color = true;
567  break;
568  }
569  }
570 
571  // get optional white balancing values (only for color camera)
572 
573  v = rcg::getEnum(nodemap, "BalanceWhiteAuto", false);
574  if (dev_supports_color && v.size() > 0)
575  {
576  dev_supports_wb = true;
577  cfg.camera_wb_auto = (v != "Off");
578  rcg::setEnum(nodemap, "BalanceRatioSelector", "Red", true);
579  cfg.camera_wb_ratio_red = rcg::getFloat(nodemap, "BalanceRatio", 0, 0, true);
580  rcg::setEnum(nodemap, "BalanceRatioSelector", "Blue", true);
581  cfg.camera_wb_ratio_blue = rcg::getFloat(nodemap, "BalanceRatio", 0, 0, true);
582  }
583  else
584  {
585  ROS_WARN("rc_visard_driver: Not a color camera. wb_auto, wb_ratio_red and wb_ratio_blue are without function.");
586 
587  dev_supports_wb = false;
588  cfg.camera_wb_auto = true;
589  cfg.camera_wb_ratio_red = 1;
590  cfg.camera_wb_ratio_blue = 1;
591  }
592 
593  // get current depth image configuration
594 
595  v = rcg::getEnum(nodemap, "DepthAcquisitionMode", false);
596  if (v.size() > 0)
597  {
599  cfg.depth_acquisition_mode = v;
600  }
601  else
602  {
603  ROS_WARN("rc_visard_driver: Device does not support triggering depth images. depth_acquisition_mode is without function.");
604 
606  cfg.depth_acquisition_mode = "Continuous";
607  }
608 
609  v = rcg::getEnum(nodemap, "DepthQuality", true);
610  cfg.depth_quality = v;
611 
612  cfg.depth_static_scene = rcg::getBoolean(nodemap, "DepthStaticScene", false);
613  cfg.depth_seg = rcg::getInteger(nodemap, "DepthSeg", 0, 0, true);
614  cfg.depth_fill = rcg::getInteger(nodemap, "DepthFill", 0, 0, true);
615  cfg.depth_minconf = rcg::getFloat(nodemap, "DepthMinConf", 0, 0, true);
616  cfg.depth_mindepth = rcg::getFloat(nodemap, "DepthMinDepth", 0, 0, true);
617  cfg.depth_maxdepth = rcg::getFloat(nodemap, "DepthMaxDepth", 0, 0, true);
618  cfg.depth_maxdeptherr = rcg::getFloat(nodemap, "DepthMaxDepthErr", 0, 0, true);
619 
620  cfg.ptp_enabled = rcg::getBoolean(nodemap, "GevIEEE1588", false);
621 
622  // fix for rc_visard < 1.5
623 
624  if (cfg.depth_quality[0] == 'S')
625  {
626  cfg.depth_quality = "High";
627  cfg.depth_static_scene = true;
628  }
629 
630  // check for stereo_plus license
631 
632  try
633  {
634  cfg.depth_smooth = rcg::getBoolean(nodemap, "DepthSmooth", true);
635  stereo_plus_avail = nodemap->_GetNode("DepthSmooth")->GetAccessMode() == GenApi::RW;
636 
637  if (!stereo_plus_avail)
638  {
639  ROS_INFO("rc_visard_driver: License for stereo_plus not available, disabling depth_quality=Full and depth_smooth.");
640  }
641  }
642  catch (const std::exception&)
643  {
644  ROS_WARN("rc_visard_driver: rc_visard has an older firmware, disabling depth_quality=Full and depth_smooth.");
645  stereo_plus_avail = false;
646  }
647 
648  try
649  {
650  cfg.depth_double_shot = rcg::getBoolean(nodemap, "DepthDoubleShot", true);
652  }
653  catch (const std::exception&)
654  {
655  dev_supports_double_shot = false;
656  ROS_WARN("rc_visard_driver: rc_visard has an older firmware, depth_double_shot is not available.");
657  }
658 
659  // check if io-control is available and get values
660 
661  try
662  {
663  // disable filtering images on the sensor
664 
665  rcg::setEnum(nodemap, "AcquisitionAlternateFilter", "Off", false);
666 
667  // get current values
668 
669  rcg::setEnum(nodemap, "LineSelector", "Out1", true);
670  cfg.out1_mode = rcg::getString(nodemap, "LineSource", true);
671 
672  rcg::setEnum(nodemap, "LineSelector", "Out2", true);
673  cfg.out2_mode = rcg::getString(nodemap, "LineSource", true);
674 
675  // check if license for IO control functions is available
676 
677  iocontrol_avail = nodemap->_GetNode("LineSource")->GetAccessMode() == GenApi::RW;
678 
679  if (!iocontrol_avail)
680  {
681  ROS_INFO("rc_visard_driver: License for iocontrol module not available, disabling out1_mode and out2_mode.");
682  }
683  }
684  catch (const std::exception&)
685  {
686  ROS_WARN("rc_visard_driver: rc_visard has an older firmware, IO control functions are not available.");
687 
688  cfg.out1_mode = "ExposureActive";
689  cfg.out2_mode = "Low";
690 
691  iocontrol_avail = false;
692  }
693 
694  // enabling chunk data for getting live camera/image parameters
695  // (e.g. line status, current gain and exposure, etc.)
696 
697  dev_supports_chunk_data = rcg::setBoolean(nodemap, "ChunkModeActive", true, false);
699  {
700  ROS_WARN("rc_visard_driver: rc_visard has an older firmware that does not support chunk data.");
701 
702  }
703 
704  // try to get ROS parameters: if parameter is not set in parameter server, default to current sensor configuration
705 
706  pnh.param("camera_fps", cfg.camera_fps, cfg.camera_fps);
707  pnh.param("camera_exp_auto", cfg.camera_exp_auto, cfg.camera_exp_auto);
708  pnh.param("camera_exp_auto_mode", cfg.camera_exp_auto_mode, cfg.camera_exp_auto_mode);
709  pnh.param("camera_exp_value", cfg.camera_exp_value, cfg.camera_exp_value);
710  pnh.param("camera_gain_value", cfg.camera_gain_value, cfg.camera_gain_value);
711  pnh.param("camera_exp_max", cfg.camera_exp_max, cfg.camera_exp_max);
712  pnh.param("camera_exp_width", cfg.camera_exp_width, cfg.camera_exp_width);
713  pnh.param("camera_exp_height", cfg.camera_exp_height, cfg.camera_exp_height);
714  pnh.param("camera_exp_offset_x", cfg.camera_exp_offset_x, cfg.camera_exp_offset_x);
715  pnh.param("camera_exp_offset_y", cfg.camera_exp_offset_y, cfg.camera_exp_offset_y);
716  pnh.param("camera_wb_auto", cfg.camera_wb_auto, cfg.camera_wb_auto);
717  pnh.param("camera_wb_ratio_red", cfg.camera_wb_ratio_red, cfg.camera_wb_ratio_red);
718  pnh.param("camera_wb_ratio_blue", cfg.camera_wb_ratio_blue, cfg.camera_wb_ratio_blue);
719  pnh.param("depth_acquisition_mode", cfg.depth_acquisition_mode, cfg.depth_acquisition_mode);
720  pnh.param("depth_quality", cfg.depth_quality, cfg.depth_quality);
721  pnh.param("depth_static_scene", cfg.depth_static_scene, cfg.depth_static_scene);
722  pnh.param("depth_double_shot", cfg.depth_double_shot, cfg.depth_double_shot);
723  pnh.param("depth_seg", cfg.depth_seg, cfg.depth_seg);
724  pnh.param("depth_smooth", cfg.depth_smooth, cfg.depth_smooth);
725  pnh.param("depth_fill", cfg.depth_fill, cfg.depth_fill);
726  pnh.param("depth_minconf", cfg.depth_minconf, cfg.depth_minconf);
727  pnh.param("depth_mindepth", cfg.depth_mindepth, cfg.depth_mindepth);
728  pnh.param("depth_maxdepth", cfg.depth_maxdepth, cfg.depth_maxdepth);
729  pnh.param("depth_maxdeptherr", cfg.depth_maxdeptherr, cfg.depth_maxdeptherr);
730  pnh.param("ptp_enabled", cfg.ptp_enabled, cfg.ptp_enabled);
731  pnh.param("out1_mode", cfg.out1_mode, cfg.out1_mode);
732  pnh.param("out2_mode", cfg.out2_mode, cfg.out2_mode);
733 
734  // set parameters on parameter server so that dynamic reconfigure picks them up
735 
736  pnh.setParam("camera_fps", cfg.camera_fps);
737  pnh.setParam("camera_exp_auto", cfg.camera_exp_auto);
738  pnh.setParam("camera_exp_auto_mode", cfg.camera_exp_auto_mode);
739  pnh.setParam("camera_exp_value", cfg.camera_exp_value);
740  pnh.setParam("camera_gain_value", cfg.camera_gain_value);
741  pnh.setParam("camera_exp_max", cfg.camera_exp_max);
742  pnh.setParam("camera_exp_width", cfg.camera_exp_width);
743  pnh.setParam("camera_exp_height", cfg.camera_exp_height);
744  pnh.setParam("camera_exp_offset_x", cfg.camera_exp_offset_x);
745  pnh.setParam("camera_exp_offset_y", cfg.camera_exp_offset_y);
746  pnh.setParam("camera_wb_auto", cfg.camera_wb_auto);
747  pnh.setParam("camera_wb_ratio_red", cfg.camera_wb_ratio_red);
748  pnh.setParam("camera_wb_ratio_blue", cfg.camera_wb_ratio_blue);
749  pnh.setParam("depth_acquisition_mode", cfg.depth_acquisition_mode);
750  pnh.setParam("depth_quality", cfg.depth_quality);
751  pnh.setParam("depth_static_scene", cfg.depth_static_scene);
752  pnh.setParam("depth_double_shot", cfg.depth_double_shot);
753  pnh.setParam("depth_seg", cfg.depth_seg);
754  pnh.setParam("depth_smooth", cfg.depth_smooth);
755  pnh.setParam("depth_fill", cfg.depth_fill);
756  pnh.setParam("depth_minconf", cfg.depth_minconf);
757  pnh.setParam("depth_mindepth", cfg.depth_mindepth);
758  pnh.setParam("depth_maxdepth", cfg.depth_maxdepth);
759  pnh.setParam("depth_maxdeptherr", cfg.depth_maxdeptherr);
760  pnh.setParam("ptp_enabled", cfg.ptp_enabled);
761  pnh.setParam("out1_mode", cfg.out1_mode);
762  pnh.setParam("out2_mode", cfg.out2_mode);
763 
764  if (reconfig == 0)
765  {
766  // TODO: we need to dismangle initialization of dynreconfserver from not-READONLY-access-condition
767  reconfig = new dynamic_reconfigure::Server<rc_visard_driver::rc_visard_driverConfig>(mtx, pnh);
768  }
769  // always set callback to (re)load configuration even after recovery
770  dynamic_reconfigure::Server<rc_visard_driver::rc_visard_driverConfig>::CallbackType cb;
771  cb = boost::bind(&DeviceNodelet::reconfigure, this, _1, _2);
772  reconfig->setCallback(cb);
773 }
774 
775 void DeviceNodelet::reconfigure(rc_visard_driver::rc_visard_driverConfig& c, uint32_t l)
776 {
777  boost::recursive_mutex::scoped_lock lock(mtx);
778 
779  // check and correct parameters
780 
781  if (!dev_supports_gain)
782  {
783  c.camera_gain_value = 0;
784  l &= ~8192;
785  }
786 
788  {
789  c.depth_double_shot = false;
790  l &= ~32;
791  }
792 
793  c.camera_gain_value = round(c.camera_gain_value / 6) * 6;
794 
795  if (!dev_supports_wb)
796  {
797  c.camera_wb_auto = true;
798  c.camera_wb_ratio_red = 1;
799  c.camera_wb_ratio_blue = 1;
800  l &= ~(16384 | 32768 | 65536);
801  }
802 
804  {
805  c.depth_acquisition_mode = "Continuous";
806  l &= ~1048576;
807  }
808 
809  if (c.depth_quality[0] == 'L')
810  {
811  c.depth_quality = "Low";
812  }
813  else if (c.depth_quality[0] == 'M')
814  {
815  c.depth_quality = "Medium";
816  }
817  else if (c.depth_quality[0] == 'F' && stereo_plus_avail)
818  {
819  c.depth_quality = "Full";
820  }
821  else
822  {
823  c.depth_quality = "High";
824  }
825 
826  if (!stereo_plus_avail)
827  {
828  c.depth_smooth=false;
829  l &= ~4194304;
830  }
831 
832  if (iocontrol_avail)
833  {
834  if (c.out1_mode != "Low" && c.out1_mode != "High" && c.out1_mode != "ExposureActive" &&
835  c.out1_mode != "ExposureAlternateActive")
836  {
837  c.out1_mode = "Low";
838  }
839 
840  if (c.out2_mode != "Low" && c.out2_mode != "High" && c.out2_mode != "ExposureActive" &&
841  c.out2_mode != "ExposureAlternateActive")
842  {
843  c.out2_mode = "Low";
844  }
845  }
846  else
847  {
848  c.out1_mode = "Low";
849  c.out2_mode = "Low";
850  }
851 
852  // if out1_mode or out2_mode are changed, immediately set new value here
853  // If we do this in the grabbing thread we have a race condition and another parameter update
854  if (l & 262144)
855  {
856  l &= ~262144;
857 
859  {
860  rcg::setEnum(rcgnodemap, "LineSelector", "Out1", false);
861  rcg::setEnum(rcgnodemap, "LineSource", c.out1_mode.c_str(), false);
862  ROS_DEBUG_STREAM("Set LineSource Out1 to " << c.out1_mode);
863  }
864  }
865 
866  if (l & 524288)
867  {
868  l &= ~524288;
869 
871  {
872  rcg::setEnum(rcgnodemap, "LineSelector", "Out2", false);
873  rcg::setEnum(rcgnodemap, "LineSource", c.out2_mode.c_str(), false);
874  ROS_DEBUG_STREAM("Set LineSource Out2 to " << c.out2_mode);
875  }
876  }
877 
878  // If camera_exp_auto (ExposureAuto) is changed, immediately set new value here
879  // so that ExposureTime and Gain can be read and published again.
880  // If we do this in the grabbing thread we have a race condition and another parameter update
881  // in the meantime could be lost because we need to overwrite the config with the updated time and gain values.
882  if (l & 2)
883  {
884  l &= ~2;
885 
886  if (rcgnodemap)
887  {
888  if (c.camera_exp_auto)
889  {
890  std::string mode = c.camera_exp_auto_mode;
891  if (mode == "Normal") mode = "Continuous";
892 
893  if (!rcg::setEnum(rcgnodemap, "ExposureAuto", mode.c_str(), false))
894  {
895  c.camera_exp_auto_mode = "Normal";
896  rcg::setEnum(rcgnodemap, "ExposureAuto", "Continuous", true);
897  }
898  }
899  else
900  {
901  rcg::setEnum(rcgnodemap, "ExposureAuto", "Off", true);
902  }
903 
904  // if exposure mode changed to manual, read current exposure value and gain again
905  if (!c.camera_exp_auto)
906  {
907  c.camera_exp_value = rcg::getFloat(rcgnodemap, "ExposureTime", 0, 0, true, true) / 1000000;
908  if (dev_supports_gain)
909  {
910  c.camera_gain_value = rcg::getFloat(rcgnodemap, "Gain", 0, 0, true, true);
911  }
912  }
913  }
914  }
915 
916  // copy config for using it in the grabbing thread
917 
918  config = c;
919  level |= l;
920 }
921 
922 namespace
923 {
924 /*
925  Set changed values of the given configuration.
926 */
927 
928 void setConfiguration(const std::shared_ptr<GenApi::CNodeMapRef>& nodemap,
929  const rc_visard_driver::rc_visard_driverConfig& cfg, uint32_t lvl, bool iocontrol_avail)
930 {
931  uint32_t prev_lvl = 0;
932 
933  while (lvl != 0 && prev_lvl != lvl)
934  {
935  prev_lvl = lvl; // used to avoid endless loops
936 
937  try
938  {
939  // NOTE: The flags used in lvl are defined in cfg/rc_visard_driver.cfg
940 
941  // set changed values via genicam
942 
943  if (lvl & 1)
944  {
945  lvl &= ~1;
946  rcg::setFloat(nodemap, "AcquisitionFrameRate", cfg.camera_fps, true);
947  ROS_DEBUG_STREAM("Set AcquisitionFrameRate to " << cfg.camera_fps);
948  }
949 
950  // lvl 2 (camera_exp_auto) is immediately set in dynamic reconfigure callback
951 
952  if (lvl & 4)
953  {
954  lvl &= ~4;
955  rcg::setFloat(nodemap, "ExposureTime", 1000000 * cfg.camera_exp_value, true);
956  ROS_DEBUG_STREAM("Set ExposureTime to " << cfg.camera_exp_value);
957  }
958 
959  if (lvl & 8192)
960  {
961  lvl &= ~8192;
962  rcg::setFloat(nodemap, "Gain", cfg.camera_gain_value, true);
963  ROS_DEBUG_STREAM("Set Gain to " << cfg.camera_gain_value);
964  }
965 
966  if (lvl & 8)
967  {
968  lvl &= ~8;
969  rcg::setFloat(nodemap, "ExposureTimeAutoMax", 1000000 * cfg.camera_exp_max, true);
970  ROS_DEBUG_STREAM("Set ExposureTimeAutoMax to " << cfg.camera_exp_max);
971  }
972 
973  if (lvl & 8388608)
974  {
975  lvl &= ~8388608;
976  rcg::setInteger(nodemap, "ExposureRegionWidth", cfg.camera_exp_width, false);
977  ROS_DEBUG_STREAM("Set ExposureRegionWidth to " << cfg.camera_exp_width);
978  }
979 
980  if (lvl & 16777216)
981  {
982  lvl &= ~16777216;
983  rcg::setInteger(nodemap, "ExposureRegionHeight", cfg.camera_exp_height, false);
984  ROS_DEBUG_STREAM("Set ExposureRegionHeight to " << cfg.camera_exp_height);
985  }
986 
987  if (lvl & 33554432)
988  {
989  lvl &= ~33554432;
990  rcg::setInteger(nodemap, "ExposureRegionOffsetX", cfg.camera_exp_offset_x, false);
991  ROS_DEBUG_STREAM("Set ExposureRegionOffsetX to " << cfg.camera_exp_offset_x);
992  }
993 
994  if (lvl & 67108864)
995  {
996  lvl &= ~67108864;
997  rcg::setInteger(nodemap, "ExposureRegionOffsetY", cfg.camera_exp_offset_y, false);
998  ROS_DEBUG_STREAM("Set ExposureRegionOffsetY to " << cfg.camera_exp_offset_y);
999  }
1000 
1001  if (lvl & 16384)
1002  {
1003  lvl &= ~16384;
1004 
1005  if (cfg.camera_wb_auto)
1006  {
1007  rcg::setEnum(nodemap, "BalanceWhiteAuto", "Continuous", false);
1008  ROS_DEBUG_STREAM("Set BalanceWhiteAuto to " << "Continuous");
1009  }
1010  else
1011  {
1012  rcg::setEnum(nodemap, "BalanceWhiteAuto", "Off", false);
1013  ROS_DEBUG_STREAM("Set BalanceWhiteAuto to " << "Off");
1014  }
1015  }
1016 
1017  if (lvl & 32768)
1018  {
1019  lvl &= ~32768;
1020 
1021  rcg::setEnum(nodemap, "BalanceRatioSelector", "Red", false);
1022  rcg::setFloat(nodemap, "BalanceRatio", cfg.camera_wb_ratio_red, false);
1023  ROS_DEBUG_STREAM("Set BalanceRatio Red to " << cfg.camera_wb_ratio_red);
1024  }
1025 
1026  if (lvl & 65536)
1027  {
1028  lvl &= ~65536;
1029 
1030  rcg::setEnum(nodemap, "BalanceRatioSelector", "Blue", false);
1031  rcg::setFloat(nodemap, "BalanceRatio", cfg.camera_wb_ratio_blue, false);
1032  ROS_DEBUG_STREAM("Set BalanceRatio Blue to " << cfg.camera_wb_ratio_blue);
1033  }
1034 
1035  if (lvl & 1048576)
1036  {
1037  lvl &= ~1048576;
1038 
1039  std::vector<std::string> list;
1040  rcg::getEnum(nodemap, "DepthAcquisitionMode", list, true);
1041 
1042  std::string val;
1043  for (size_t i = 0; i < list.size(); i++)
1044  {
1045  if (list[i].compare(cfg.depth_acquisition_mode) == 0)
1046  {
1047  val = list[i];
1048  }
1049  }
1050 
1051  if (val.size() > 0)
1052  {
1053  rcg::setEnum(nodemap, "DepthAcquisitionMode", val.c_str(), true);
1054  ROS_DEBUG_STREAM("Set DepthAcquisitionMode to " << val);
1055  }
1056  else
1057  {
1058  ROS_WARN_STREAM("DepthAcquisitionMode " << cfg.depth_acquisition_mode << " not supported by rc_visard");
1059  }
1060 
1061  }
1062 
1063  if (lvl & 16)
1064  {
1065  lvl &= ~16;
1066 
1067  std::vector<std::string> list;
1068  rcg::getEnum(nodemap, "DepthQuality", list, true);
1069 
1070  std::string val;
1071 
1072  if (cfg.depth_quality == "High" && cfg.depth_static_scene)
1073  {
1074  // support for rc_visard < 1.5
1075 
1076  for (size_t i = 0; i < list.size() && val.size() == 0; i++)
1077  {
1078  if (list[i].compare(0, 1, "StaticHigh", 0, 1) == 0)
1079  {
1080  val = "StaticHigh";
1081  }
1082  }
1083  }
1084 
1085  for (size_t i = 0; i < list.size() && val.size() == 0; i++)
1086  {
1087  if (list[i].compare(0, 1, cfg.depth_quality, 0, 1) == 0)
1088  {
1089  val = list[i];
1090  }
1091  }
1092 
1093  if (val.size() > 0)
1094  {
1095  rcg::setEnum(nodemap, "DepthQuality", val.c_str(), true);
1096  ROS_DEBUG_STREAM("Set DepthQuality to " << val);
1097  }
1098  }
1099 
1100  if (lvl & 32)
1101  {
1102  lvl &= ~32;
1103  rcg::setBoolean(nodemap, "DepthDoubleShot", cfg.depth_double_shot, false);
1104  ROS_DEBUG_STREAM("Set DepthDoubleShot to " << cfg.depth_double_shot);
1105  }
1106 
1107  if (lvl & 2097152)
1108  {
1109  lvl &= ~2097152;
1110  ROS_DEBUG_STREAM("Set DepthStaticScene to " << cfg.depth_static_scene);
1111  if (!rcg::setBoolean(nodemap, "DepthStaticScene", cfg.depth_static_scene, false))
1112  {
1113  // support for rc_visard < 1.5
1114 
1115  std::string quality = cfg.depth_quality;
1116 
1117  if (cfg.depth_static_scene && quality == "High")
1118  {
1119  quality = "StaticHigh";
1120  }
1121 
1122  std::vector<std::string> list;
1123  rcg::getEnum(nodemap, "DepthQuality", list, true);
1124 
1125  std::string val;
1126  for (size_t i = 0; i < list.size() && val.size() == 0; i++)
1127  {
1128  if (list[i].compare(0, 1, quality, 0, 1) == 0)
1129  {
1130  val = list[i];
1131  }
1132  }
1133 
1134  if (val.size() > 0)
1135  {
1136  rcg::setEnum(nodemap, "DepthQuality", val.c_str(), true);
1137  ROS_DEBUG_STREAM("Set DepthQuality to " << val);
1138  }
1139  }
1140  }
1141 
1142  if (lvl & 64)
1143  {
1144  lvl &= ~64;
1145  rcg::setInteger(nodemap, "DepthSeg", cfg.depth_seg, true);
1146  ROS_DEBUG_STREAM("Set DepthSeg to " << cfg.depth_seg);
1147  }
1148 
1149  if (lvl & 4194304)
1150  {
1151  lvl &= ~4194304;
1152  rcg::setBoolean(nodemap, "DepthSmooth", cfg.depth_smooth, false);
1153  ROS_DEBUG_STREAM("Set DepthSmooth to " << cfg.depth_smooth);
1154  }
1155 
1156  if (lvl & 256)
1157  {
1158  lvl &= ~256;
1159  rcg::setInteger(nodemap, "DepthFill", cfg.depth_fill, true);
1160  ROS_DEBUG_STREAM("Set DepthFill to " << cfg.depth_fill);
1161  }
1162 
1163  if (lvl & 512)
1164  {
1165  lvl &= ~512;
1166  rcg::setFloat(nodemap, "DepthMinConf", cfg.depth_minconf, true);
1167  ROS_DEBUG_STREAM("Set DepthMinConf to " << cfg.depth_minconf);
1168  }
1169 
1170  if (lvl & 1024)
1171  {
1172  lvl &= ~1024;
1173  rcg::setFloat(nodemap, "DepthMinDepth", cfg.depth_mindepth, true);
1174  ROS_DEBUG_STREAM("Set DepthMinDepth to " << cfg.depth_mindepth);
1175  }
1176 
1177  if (lvl & 2048)
1178  {
1179  lvl &= ~2048;
1180  rcg::setFloat(nodemap, "DepthMaxDepth", cfg.depth_maxdepth, true);
1181  ROS_DEBUG_STREAM("Set DepthMaxDepth to " << cfg.depth_maxdepth);
1182  }
1183 
1184  if (lvl & 4096)
1185  {
1186  lvl &= ~4096;
1187  rcg::setFloat(nodemap, "DepthMaxDepthErr", cfg.depth_maxdeptherr, true);
1188  ROS_DEBUG_STREAM("Set DepthMaxDepthErr to " << cfg.depth_maxdeptherr);
1189  }
1190 
1191  if (lvl & 131072)
1192  {
1193  lvl &= ~131072;
1194  rcg::setBoolean(nodemap, "GevIEEE1588", cfg.ptp_enabled, true);
1195  ROS_DEBUG_STREAM("Set GevIEEE1588 to " << cfg.ptp_enabled);
1196  }
1197 
1198  // lvl 262144 (out1_mode) is immediately set in dynamic reconfigure callback
1199 
1200  // lvl 524288 (out2_mode) is immediately set in dynamic reconfigure callback
1201  }
1202  catch (const std::exception& ex)
1203  {
1204  ROS_ERROR_STREAM("rc_visard_driver: " << ex.what());
1205  }
1206  }
1207 }
1208 
1209 /*
1210  Disable all available components.
1211 
1212  @param nodemap Feature nodemap.
1213 */
1214 
1215 void disableAll(const std::shared_ptr<GenApi::CNodeMapRef>& nodemap)
1216 {
1217  std::vector<std::string> component;
1218 
1219  rcg::getEnum(nodemap, "ComponentSelector", component, true);
1220 
1221  for (size_t i = 0; i < component.size(); i++)
1222  {
1223  rcg::setEnum(nodemap, "ComponentSelector", component[i].c_str(), true);
1224  rcg::setBoolean(nodemap, "ComponentEnable", false, true);
1225  }
1226 
1227  rcg::setEnum(nodemap, "ComponentSelector", "Intensity");
1228  rcg::setEnum(nodemap, "PixelFormat", "Mono8");
1229 
1230  // if multipart is available, still send single components per buffer
1231  rcg::setEnum(nodemap, "AcquisitionMultiPartMode", "SingleComponent");
1232 }
1233 
1234 /*
1235  Conditionally enables a component.
1236 
1237  @param nodemap Feature nodemap.
1238  @param en_curr Current selection status, which will be changed.
1239  @param en_new New selection status.
1240  @return 1 if status changed, 0 otherwise.
1241 */
1242 
1243 int enable(const std::shared_ptr<GenApi::CNodeMapRef>& nodemap, const char* component, bool& en_curr, bool en_new)
1244 {
1245  if (en_new != en_curr)
1246  {
1247  if (en_new)
1248  ROS_INFO_STREAM("rc_visard_driver: Enabled image stream: " << component);
1249  else
1250  ROS_INFO_STREAM("rc_visard_driver: Disabled image stream: " << component);
1251 
1252  rcg::setEnum(nodemap, "ComponentSelector", component, true);
1253  rcg::setBoolean(nodemap, "ComponentEnable", en_new);
1254  en_curr = en_new;
1255 
1256  return 1;
1257  }
1258 
1259  return 0;
1260 }
1261 
1262 rc_common_msgs::CameraParam extractChunkData(const std::shared_ptr<GenApi::CNodeMapRef>& rcgnodemap)
1263 {
1264  rc_common_msgs::CameraParam cam_param;
1265 
1266  // get list of all available IO lines and iterate over them to get their LineSource values
1267  std::vector<std::string> lines;
1268  rcg::getEnum(rcgnodemap, "ChunkLineSelector", lines, false);
1269  for (auto&& line : lines)
1270  {
1271  rc_common_msgs::KeyValue line_source;
1272  line_source.key = line;
1273  rcg::setEnum(rcgnodemap, "ChunkLineSelector", line.c_str(), false); // set respective selector
1274  line_source.value = rcg::getEnum(rcgnodemap, "ChunkLineSource", false); // get the actual source value
1275  cam_param.line_source.push_back(line_source);
1276  }
1277 
1278  // get LineStatusAll
1279  cam_param.line_status_all = rcg::getInteger(rcgnodemap, "ChunkLineStatusAll", 0, 0, false);
1280 
1281  // get camera's exposure time and gain value
1282  cam_param.gain = rcg::getFloat(rcgnodemap, "ChunkGain", 0, 0, false);
1283  cam_param.exposure_time = rcg::getFloat(rcgnodemap, "ChunkExposureTime", 0, 0, false) / 1000000l;
1284 
1285  // add extra data
1286  cam_param.extra_data.clear();
1287  try
1288  {
1289  rc_common_msgs::KeyValue kv;
1290  kv.key = "noise";
1291  kv.value = std::to_string(rcg::getFloat(rcgnodemap, "ChunkRcNoise", 0, 0, true));
1292  cam_param.extra_data.push_back(kv);
1293  }
1294  catch (std::invalid_argument& e)
1295  {
1296  // calculate camera's noise level
1297  static float NOISE_BASE = 2.0;
1298  rc_common_msgs::KeyValue kv;
1299  kv.key = "noise";
1300  kv.value = std::to_string(static_cast<float>(NOISE_BASE * std::exp(cam_param.gain * std::log(10)/20)));
1301  cam_param.extra_data.push_back(kv);
1302  }
1303 
1304  try
1305  {
1306  rc_common_msgs::KeyValue kv;
1307  kv.key = "test";
1308  kv.value = std::to_string(rcg::getBoolean(rcgnodemap, "ChunkRcTest", true));
1309  cam_param.extra_data.push_back(kv);
1310  }
1311  catch (std::invalid_argument& e)
1312  {
1313  }
1314 
1315  try
1316  {
1317  std::string out1_reduction;
1318  try
1319  {
1320  out1_reduction = std::to_string(rcg::getFloat(rcgnodemap, "ChunkRcOut1Reduction", 0, 0, true));
1321  }
1322  catch (const std::exception& e)
1323  {
1324  // try to fallback to older name in versions < 20.10.1
1325  out1_reduction = std::to_string(rcg::getFloat(rcgnodemap, "ChunkRcAdaptiveOut1Reduction", 0, 0, true));
1326  }
1327 
1328  rc_common_msgs::KeyValue kv;
1329  kv.key = "out1_reduction";
1330  kv.value = out1_reduction;
1331  cam_param.extra_data.push_back(kv);
1332  }
1333  catch (std::invalid_argument& e)
1334  {
1335  }
1336 
1337  try
1338  {
1339  rc_common_msgs::KeyValue kv;
1340  kv.key = "brightness";
1341  kv.value = std::to_string(rcg::getFloat(rcgnodemap, "ChunkRcBrightness", 0, 0, true));
1342  cam_param.extra_data.push_back(kv);
1343  }
1344  catch (std::invalid_argument& e)
1345  {
1346  }
1347 
1348  return cam_param;
1349 }
1350 
1351 } //anonymous namespace
1352 
1353 void DeviceNodelet::grab(std::string device, rcg::Device::ACCESS access)
1354 {
1355  unsigned int maxNumConsecutiveFails = 5;
1356 
1357  stopImageThread = false;
1358 
1359  imageRequested = true;
1360  imageSuccess = false;
1361 
1362  // at most 5 consecutive failures are permitted
1363 
1364  unsigned int cntConsecutiveFails = 0;
1365  while (!stopImageThread && cntConsecutiveFails < maxNumConsecutiveFails)
1366  {
1367  imageSuccess = false;
1368  try
1369  {
1370  // mark all dynamic parameters as changed
1371 
1372  level=0xffffffff;
1373 
1374  // initially switch off all components
1375 
1376  disableAll(rcgnodemap);
1377 
1378  bool ccolor = false;
1379  bool cintensity = false;
1380  bool cintensitycombined = false;
1381  bool cdisparity = false;
1382  bool cconfidence = false;
1383  bool cerror = false;
1384 
1385  bool firstTime = true;
1386 
1387  // get focal length factor of the camera
1388 
1389  double f = rcg::getFloat(rcgnodemap, "FocalLengthFactor", 0, 0, false);
1390  if (!f) // backward compatibility: also check for old name 'FocalLength'
1391  {
1392  f = rcg::getFloat(rcgnodemap, "FocalLength", 0, 0, false);
1393  if (!f)
1394  {
1395  throw std::runtime_error("Focal length not found: Neither 'FocalLength' nor 'FocalLengthFactor'!");
1396  }
1397  }
1398 
1399  // get baseline of the camera (for backward capability check unit)
1400 
1401  double t = rcg::getFloat(rcgnodemap, "Baseline", 0, 0, true);
1402  GenApi::INode* node = rcgnodemap->_GetNode("Baseline");
1403  if (!node || !GenApi::IsReadable(node))
1404  {
1405  throw std::invalid_argument("Feature not found or not readable: Baseline");
1406  }
1407  GenApi::IFloat* val = dynamic_cast<GenApi::IFloat*>(node);
1408  if (!val)
1409  {
1410  throw std::invalid_argument("Feature not float: Baseline");
1411  }
1412  if (val->GetUnit() == "mm") // in previous versions rc_visard reported as mm
1413  {
1414  t /= 1000;
1415  }
1416 
1417  // get disparity scale
1418 
1419  double scale = rcg::getFloat(rcgnodemap, "Scan3dCoordinateScale", 0, 0, true);
1420 
1421  // check certain values
1422 
1423  rcg::checkFeature(rcgnodemap, "Scan3dOutputMode", "DisparityC");
1424  rcg::checkFeature(rcgnodemap, "Scan3dCoordinateOffset", "0");
1425  rcg::checkFeature(rcgnodemap, "Scan3dInvalidDataFlag", "1");
1426  rcg::checkFeature(rcgnodemap, "Scan3dInvalidDataValue", "0");
1427 
1428  // get current configuration and start dynamic reconfigure server
1429 
1431 
1432  float mindepth = config.depth_mindepth;
1433  float maxdepth = config.depth_maxdepth;
1434  bool is_depth_acquisition_continuous = (config.depth_acquisition_mode[0] == 'C');
1435 
1436  // prepare chunk adapter for getting chunk data
1437 
1438  std::shared_ptr<GenApi::CChunkAdapter> chunkadapter;
1440  {
1441  chunkadapter = rcg::getChunkAdapter(rcgnodemap, rcgdev->getTLType());
1442  }
1443 
1444  // initialize all publishers
1445 
1446  ros::NodeHandle nh(getNodeHandle(), "stereo");
1448 
1449  CameraInfoPublisher lcaminfo(nh, tfPrefix, f, t, true);
1450  CameraInfoPublisher rcaminfo(nh, tfPrefix, f, t, false);
1451 
1452  ImagePublisher limage(it, tfPrefix, true, false, true);
1453  ImagePublisher rimage(it, tfPrefix, false, false, true);
1454 
1455  DisparityPublisher disp(nh, tfPrefix, f, t, scale);
1456  DisparityColorPublisher cdisp(it, tfPrefix, f, t, scale);
1457  DepthPublisher depth(nh, tfPrefix, f, t, scale);
1458 
1459  ConfidencePublisher confidence(nh, tfPrefix);
1460  ErrorDisparityPublisher error_disp(nh, tfPrefix, scale);
1461  ErrorDepthPublisher error_depth(nh, tfPrefix, f, t, scale);
1462 
1463  Points2Publisher points2(nh, tfPrefix, f, t, scale);
1464 
1465  // add color image publishers if the camera supports color
1466 
1467  std::shared_ptr<ImagePublisher> limage_color;
1468  std::shared_ptr<ImagePublisher> rimage_color;
1469  if (dev_supports_color)
1470  {
1471  limage_color = std::make_shared<ImagePublisher>(it, tfPrefix, true, true, true);
1472  rimage_color = std::make_shared<ImagePublisher>(it, tfPrefix, false, true, true);
1473  }
1474 
1475  // add camera/image params publishers if the camera supports chunkdata
1476 
1477  std::shared_ptr<CameraParamPublisher> lcamparams;
1478  std::shared_ptr<CameraParamPublisher> rcamparams;
1480  {
1481  lcamparams = std::make_shared<CameraParamPublisher>(nh, tfPrefix, true);
1482  rcamparams = std::make_shared<CameraParamPublisher>(nh, tfPrefix, false);
1483  }
1484 
1485  // start streaming of first stream
1486 
1487  std::vector<std::shared_ptr<rcg::Stream> > stream = rcgdev->getStreams();
1488 
1489  gev_packet_size="";
1490 
1491  if (stream.size() > 0)
1492  {
1493  stream[0]->open();
1494  stream[0]->startStreaming();
1495 
1496  // enter grabbing loop
1497  ros::SteadyTime tlastimage = ros::SteadyTime::now();
1498  std::string out1_mode_on_sensor;
1499 
1500  while (!stopImageThread)
1501  {
1502  const rcg::Buffer* buffer = stream[0]->grab(40);
1503 
1504  if (buffer != 0 && !buffer->getIsIncomplete())
1505  {
1507  if (gev_packet_size.size() == 0)
1508  {
1509  gev_packet_size = rcg::getString(rcgnodemap, "GevSCPSPacketSize", true, true);
1510  ROS_INFO_STREAM("rc_visard_driver: Image streams ready (Packet size "
1511  << gev_packet_size << ")");
1512  }
1513 
1514  // get camera/image parameters (GenICam chunk data) if possible
1515  // (e.g. out1_mode, line_status_all, current gain and exposure, etc.)
1516 
1517  bool out1 = false;
1518  if (chunkadapter && buffer->getContainsChunkdata())
1519  {
1520  chunkadapter->AttachBuffer(reinterpret_cast<std::uint8_t*>(buffer->getGlobalBase()),
1521  buffer->getSizeFilled());
1522 
1523  // get current out1 mode
1524  rcg::setEnum(rcgnodemap, "ChunkLineSelector", "Out1", false);
1525  std::string v = rcg::getEnum(rcgnodemap, "ChunkLineSource", false);
1526 
1527  if (v.size() > 0)
1528  {
1529  out1_mode_on_sensor = v;
1530  }
1531  }
1532 
1533  // if in alternate mode, then make publishers aware of it before
1534  // publishing
1535 
1536  bool out1_alternate = (out1_mode_on_sensor == "ExposureAlternateActive");
1537  points2.setOut1Alternate(out1_alternate);
1538 
1539  rc_common_msgs::CameraParam cam_param = extractChunkData(rcgnodemap);
1540  cam_param.is_color_camera = dev_supports_color;
1541  out1 = (cam_param.line_status_all & 0x1);
1542 
1543  uint32_t npart=buffer->getNumberOfParts();
1544  for (uint32_t part=0; part<npart; part++)
1545  {
1546  if (buffer->getImagePresent(part))
1547  {
1548  // reset counter of consecutive missing images and failures
1549  tlastimage = ros::SteadyTime::now();
1550  cntConsecutiveFails = 0;
1551  imageSuccess = true;
1552 
1553  // the buffer is offered to all publishers
1554 
1555  disp.setDepthRange(mindepth, maxdepth);
1556  cdisp.setDepthRange(mindepth, maxdepth);
1557 
1558  uint64_t pixelformat = buffer->getPixelFormat(part);
1559 
1560  lcaminfo.publish(buffer, part, pixelformat);
1561  rcaminfo.publish(buffer, part, pixelformat);
1562 
1563  if (lcamparams && rcamparams)
1564  {
1565  lcamparams->publish(buffer, cam_param, pixelformat);
1566  rcamparams->publish(buffer, cam_param, pixelformat);
1567  }
1568 
1569  limage.publish(buffer, part, pixelformat, out1);
1570  rimage.publish(buffer, part, pixelformat, out1);
1571 
1572  if (limage_color && rimage_color)
1573  {
1574  limage_color->publish(buffer, part, pixelformat, out1);
1575  rimage_color->publish(buffer, part, pixelformat, out1);
1576  }
1577 
1578  disp.publish(buffer, part, pixelformat);
1579  cdisp.publish(buffer, part, pixelformat);
1580  depth.publish(buffer, part, pixelformat);
1581 
1582  confidence.publish(buffer, part, pixelformat);
1583  error_disp.publish(buffer, part, pixelformat);
1584  error_depth.publish(buffer, part, pixelformat);
1585 
1586  points2.publish(buffer, part, pixelformat, out1);
1587 
1588  // use out1_mode for updating dynamic parameters (below) only
1589  // from buffers with intensity images
1590 
1591  if (pixelformat != Mono8 && pixelformat != YCbCr411_8)
1592  {
1593  out1_mode_on_sensor = "";
1594  }
1595  }
1596  }
1597 
1598  // detach buffer from nodemap
1599 
1600  if (chunkadapter) chunkadapter->DetachBuffer();
1601  }
1602  else if (buffer != 0 && buffer->getIsIncomplete())
1603  {
1604  tlastimage = ros::SteadyTime::now();
1606  ROS_WARN("rc_visard_driver: Received incomplete image buffer");
1607  }
1608  else if (buffer == 0)
1609  {
1610  // throw an expection if data from enabled components is expected,
1611  // but not comming for more than 3 seconds
1612 
1613  if (cintensity || cintensitycombined ||
1614  (is_depth_acquisition_continuous && (cdisparity || cconfidence || cerror)))
1615  {
1616  double t = (ros::SteadyTime::now() - tlastimage).toSec();
1617 
1618  if (t > 3) // report error
1619  {
1621  std::ostringstream out;
1622  out << "No images received for " << t << " seconds!";
1623  throw std::underflow_error(out.str());
1624  }
1625  }
1626  else
1627  {
1628  // if nothing is expected then store current time as last time
1629  // to avoid possible timeout after resubscription
1630 
1631  tlastimage = ros::SteadyTime::now();
1632  }
1633 
1634  // get out1 mode from sensor (this is also used to check if the
1635  // connection is still valid)
1636 
1637  rcg::setEnum(rcgnodemap, "LineSelector", "Out1", true);
1638  out1_mode_on_sensor = rcg::getString(rcgnodemap, "LineSource", true, true);
1639  }
1640 
1641  // trigger depth
1642 
1644  {
1646  rcg::callCommand(rcgnodemap, "DepthAcquisitionTrigger", true);
1647  ROS_INFO("rc_visard_driver: Depth image acquisition triggered");
1648  }
1649 
1650  // determine what should be streamed, according to subscriptions to
1651  // topics
1652 
1653  // switch color on or off
1654 
1655  if (limage_color && rimage_color && (limage_color->used() || rimage_color->used() || points2.used()))
1656  {
1657  if (!ccolor)
1658  {
1659  rcg::setEnum(rcgnodemap, "ComponentSelector", "Intensity", true);
1660  rcg::setEnum(rcgnodemap, "PixelFormat", "YCbCr411_8", true);
1661  ccolor = true;
1662  }
1663  }
1664  else
1665  {
1666  if (ccolor)
1667  {
1668  rcg::setEnum(rcgnodemap, "ComponentSelector", "Intensity", true);
1669  rcg::setEnum(rcgnodemap, "PixelFormat", "Mono8", true);
1670  ccolor = false;
1671  }
1672  }
1673 
1674  // enable or disable components
1675 
1676  int changed = enable(rcgnodemap, "IntensityCombined", cintensitycombined,
1677  rimage.used() || (rimage_color && rimage_color->used()));
1678 
1679  changed += enable(rcgnodemap, "Intensity", cintensity,
1680  !cintensitycombined && (lcaminfo.used() || rcaminfo.used() ||
1681  (lcamparams && lcamparams->used()) ||
1682  (rcamparams && rcamparams->used()) ||
1683  limage.used() ||
1684  (limage_color && limage_color->used()) || points2.used()));
1685 
1686  changed += enable(rcgnodemap, "Disparity", cdisparity,
1687  disp.used() || cdisp.used() || depth.used() || error_depth.used() || points2.used());
1688 
1689  changed += enable(rcgnodemap, "Confidence", cconfidence, confidence.used());
1690 
1691  changed += enable(rcgnodemap, "Error", cerror, error_disp.used() || error_depth.used());
1692 
1693  // report activation of all components, everytime when a component is
1694  // enabled or disabled
1695 
1696  if (changed > 0 || firstTime)
1697  {
1698  if (cintensity || cintensitycombined || cdisparity || cconfidence || cerror)
1699  imageRequested = true;
1700  else
1701  imageRequested = false;
1702  firstTime = false;
1703  }
1704 
1705  // check if dynamic configuration has changed
1706 
1707  if (level != 0)
1708  {
1709  // set all changed values via genicam
1710 
1711  mtx.lock();
1712  rc_visard_driver::rc_visard_driverConfig cfg = config;
1713  uint32_t lvl = level;
1714  level = 0;
1715  mtx.unlock();
1716 
1717  setConfiguration(rcgnodemap, cfg, lvl, iocontrol_avail);
1718 
1719  mindepth = cfg.depth_mindepth;
1720  maxdepth = cfg.depth_maxdepth;
1721 
1722  // if depth acquisition changed to continuous mode, reset last
1723  // grabbing time to avoid triggering timout if only disparity,
1724  // confidence and/or error components are enabled
1725 
1726  is_depth_acquisition_continuous = (cfg.depth_acquisition_mode[0] == 'C');
1727 
1728  if (lvl & 1048576)
1729  {
1730  if (is_depth_acquisition_continuous)
1731  {
1732  tlastimage = ros::SteadyTime::now();
1733  }
1734  }
1735  }
1736 
1737  // update out1 mode, if it is different to current settings on sensor
1738  // (which is the only GEV parameter which could have changed outside this code,
1739  // i.e. on the rc_visard by the stereomatching module)
1740 
1741  mtx.lock();
1742  if (out1_mode_on_sensor.size() == 0)
1743  {
1744  // use current settings if the value on the sensor cannot be determined
1745  out1_mode_on_sensor = config.out1_mode;
1746  }
1747 
1748  if (out1_mode_on_sensor != config.out1_mode)
1749  {
1750  config.out1_mode = out1_mode_on_sensor;
1751  reconfig->updateConfig(config);
1752  }
1753  mtx.unlock();
1754  }
1755 
1756  stream[0]->stopStreaming();
1757  stream[0]->close();
1758  }
1759  else
1760  {
1761  ROS_ERROR("rc_visard_driver: No stream");
1762  cntConsecutiveFails++;
1763  }
1764  }
1765  catch (const std::exception& ex)
1766  {
1767  ROS_ERROR_STREAM("rc_visard_driver: " << ex.what());
1768  cntConsecutiveFails++;
1769  }
1770  }
1771 
1772  // report failures, if any
1773 
1774  if (cntConsecutiveFails > 0)
1775  {
1776  ROS_ERROR_STREAM("rc_visard_driver: Number of consecutive failures: " << cntConsecutiveFails);
1777  }
1778  if (cntConsecutiveFails >= maxNumConsecutiveFails)
1779  {
1780  ROS_ERROR_STREAM("rc_visard_driver: Image grabbing failed.");
1781  recoveryRequested = true;
1783  }
1784 }
1785 
1786 bool DeviceNodelet::depthAcquisitionTrigger(rc_common_msgs::Trigger::Request& req,
1787  rc_common_msgs::Trigger::Response& resp)
1788 {
1790 
1791  resp.return_code.value = ReturnCodeConstants::SUCCESS;
1792  resp.return_code.message = "";
1793 
1794  return true;
1795 }
1796 
1797 
1799 {
1800  stat.add("connection_loss_total", totalConnectionLosses);
1801  stat.add("complete_buffers_total", totalCompleteBuffers);
1802  stat.add("incomplete_buffers_total", totalIncompleteBuffers);
1803  stat.add("image_receive_timeouts_total", totalImageReceiveTimeouts);
1804  stat.add("current_reconnect_trial", cntConsecutiveRecoveryFails);
1805 
1806  // general connection status is supervised by the recoveryRequested variable
1807 
1808  if (recoveryRequested) {
1809  stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Disconnected");
1810  return;
1811  }
1812 
1813  // at least we are connected to gev server
1814 
1815  stat.add("ip_address", dev_ipaddr);
1816  stat.add("gev_packet_size", gev_packet_size);
1817 
1818  if (imageRequested) {
1819  if (imageSuccess) {
1820  // someone subscribed to images, and we actually receive data via GigE vision
1821  stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Streaming");
1822  } else {
1823  // someone subscribed to images, but we do not receive any data via GigE vision (yet)
1824  stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "No data");
1825  }
1826  } else {
1827  // no one requested images -> node is ok but stale
1828  stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Idle");
1829  }
1830 
1831 }
1832 
1834  if (dev_serialno.empty()) {
1835  stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Unknown");
1836  } else {
1837  stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Info");
1838  stat.add("serial", dev_serialno);
1839  stat.add("mac", dev_macaddr);
1840  stat.add("user_id", gev_userid);
1841  stat.add("image_version", dev_version);
1842  }
1843 }
1844 
1845 } // namespace rc
1846 
msg
bool dynamicsStart(rc_common_msgs::Trigger::Request &req, rc_common_msgs::Trigger::Response &resp)
Start Stereo INS.
bool getBoolean(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, bool exception=false, bool igncache=false)
ThreadedStream::Manager::Ptr dynamicsStreams
void publish(const rcg::Buffer *buffer, uint32_t part, uint64_t pixelformat) override
Offers a buffer for publication.
std::shared_ptr< Device > getDevice(const char *devid)
bool used() override
Returns true if there are subscribers to the topic.
bool used() override
Returns true if there are subscribers to the topic.
tf::Transform toRosTfTransform(const roboception::msgs::Pose &pose)
Mono8
f
size_t getSizeFilled() const
Specific implementation for roboception::msgs::Frame messages that publishes received messages not on...
unsigned int totalIncompleteBuffers
bool dynamicsStopSlam(rc_common_msgs::Trigger::Request &req, rc_common_msgs::Trigger::Response &resp)
Stop SLAM (keep Stereo INS running)
void summary(unsigned char lvl, const std::string s)
void reconfigure(rc_visard_driver::rc_visard_driverConfig &config, uint32_t level)
bool used() override
Returns true if there are subscribers to the topic.
int64_t round(double x)
std::shared_ptr< GenApi::CChunkAdapter > getChunkAdapter(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const std::string &tltype)
bool used() override
Returns true if there are subscribers to the topic.
void publish(const rcg::Buffer *buffer, uint32_t part, uint64_t pixelformat) override
Offers a buffer for publication.
void produce_connection_diagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat)
void publish(const rcg::Buffer *buffer, uint32_t part, uint64_t pixelformat) override
Offers a buffer for publication.
void setHardwareID(const std::string &hwid)
static std::vector< std::shared_ptr< System > > getSystems()
bool used() override
Returns true if there are subscribers to the topic.
std::shared_ptr< ThreadedStream > Ptr
diagnostic_updater::Updater updater
diagnostics publishing
void add(const std::string &name, TaskFunction f)
bool used() override
Returns true if there are subscribers to the topic.
bool getSlamTrajectory(rc_visard_driver::GetTrajectory::Request &req, rc_visard_driver::GetTrajectory::Response &resp)
Get the Slam trajectory.
int64_t getInteger(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, int64_t *vmin=0, int64_t *vmax=0, bool exception=false, bool igncache=false)
ros::ServiceServer slamLoadMapService
bool dynamicsStartSlam(rc_common_msgs::Trigger::Request &req, rc_common_msgs::Trigger::Response &resp)
Start Stereo INS+SLAM.
void grab(std::string device, rcg::Device::ACCESS access)
void publish(const rcg::Buffer *buffer, uint32_t part, uint64_t pixelformat) override
Offers a buffer for publication.
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
void publish(const rcg::Buffer *buffer, uint32_t part, uint64_t pixelformat) override
Offers a buffer for publication.
std::string dev_version
std::string str()
void produce_device_diagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat)
#define ROS_WARN(...)
Implementation of a ThreadedStream that receives rc_visard&#39;s dynamics protobuf messages and re-publis...
bool setFloat(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, double value, bool exception=false)
YCbCr411_8
ros::ServiceServer depthAcquisitionTriggerService
wrapper for REST-API calls relating to rc_visard&#39;s dynamics interface
bool setEnum(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, const char *value, bool exception=false)
ros::ServiceServer dynamicsStartSlamService
bool dynamicsRestart(rc_common_msgs::Trigger::Request &req, rc_common_msgs::Trigger::Response &resp)
Restart Stereo INS.
ros::NodeHandle & getPrivateNodeHandle() const
bool removeSlamMap(rc_common_msgs::Trigger::Request &req, rc_common_msgs::Trigger::Response &resp)
Remove the onboard SLAM map.
ros::ServiceServer getSlamTrajectoryService
interface GENAPI_DECL_ABSTRACT IFloat
static void clearSystems()
bool perform_depth_acquisition_trigger
bool tfEnabled
should poses published also via tf?
void publish(const rcg::Buffer *buffer, uint32_t part, uint64_t pixelformat) override
Offers a buffer for publication.
bool dev_supports_depth_acquisition_trigger
virtual void onInit()
void initConfiguration(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, rc_visard_driver::rc_visard_driverConfig &cfg, rcg::Device::ACCESS access)
tf2_ros::StaticTransformBroadcaster tfStaticBroadcaster
std::atomic_bool imageSuccess
bool used() override
Returns true if there are subscribers to the topic.
void * getGlobalBase() const
std::thread imageThread
ROSCPP_DECL const std::string & getNamespace()
unsigned int totalCompleteBuffers
static SteadyTime now()
ros::ServiceServer dynamicsStopSlamService
void checkFeature(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, const char *value, bool igncache=false)
unsigned int totalImageReceiveTimeouts
#define ROS_FATAL_STREAM(args)
std::string getEnum(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, bool exception=false)
ros::ServiceServer dynamicsRestartSlamService
uint64_t getPixelFormat(std::uint32_t part) const
#define ROS_INFO(...)
static ThreadedStream::Ptr CreateDynamicsStreamOfType(rc::dynamics::RemoteInterface::Ptr rcdIface, const std::string &stream, ros::NodeHandle &nh, const std::string &frame_id_prefix, bool tfEnabled, bool staticImu2CamTf)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
std::atomic_uint_least32_t level
TFSIMD_FORCE_INLINE Quaternion inverse(const Quaternion &q)
rc_visard_driver::rc_visard_driverConfig config
void keepAliveAndRecoverFromFails()
bool used() override
Returns true if there are subscribers to the topic.
ros::ServiceServer slamSaveMapService
bool IsReadable(const CPointer< T, B > &ptr)
ros::ServiceServer dynamicsStopService
void setOut1Alternate(bool alternate)
std::atomic_bool imageRequested
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
std::string gev_packet_size
ros::NodeHandle & getNodeHandle() const
#define ROS_WARN_STREAM(args)
ros::Publisher trajPublisher
#define ROS_DEBUG_STREAM(args)
void publish(const rcg::Buffer *buffer, uint32_t part, uint64_t pixelformat) override
Offers a buffer for publication.
bool setBoolean(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, bool value, bool exception=false)
std::shared_ptr< rcg::Device > rcgdev
bool atLeastOnceSuccessfullyStarted
ros::ServiceServer dynamicsStartService
std::string strip_leading_slash(const std::string &frame_name)
bool dynamicsResetSlam(rc_common_msgs::Trigger::Request &req, rc_common_msgs::Trigger::Response &resp)
Reset SLAM (keep Stereo INS running)
std::atomic_bool stopImageThread
ros::ServiceServer dynamicsRestartService
bool dynamicsStop(rc_common_msgs::Trigger::Request &req, rc_common_msgs::Trigger::Response &resp)
Stop Stereo INS(+SLAM if running)
dynamic_reconfigure::Server< rc_visard_driver::rc_visard_driverConfig > * reconfig
bool getContainsChunkdata() const
double getFloat(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, double *vmin=0, double *vmax=0, bool exception=false, bool igncache=false)
bool dynamicsRestartSlam(rc_common_msgs::Trigger::Request &req, rc_common_msgs::Trigger::Response &resp)
Restart Stereo INS+SLAM.
bool depthAcquisitionTrigger(rc_common_msgs::Trigger::Request &req, rc_common_msgs::Trigger::Response &resp)
Trigger stereo matching in mode &#39;SingleFrame&#39;.
#define ROS_INFO_STREAM(args)
std::atomic_bool stopRecoverThread
rc::dynamics::RemoteInterface::Ptr dynamicsInterface
std::string dev_macaddr
void publish(const rcg::Buffer *buffer, uint32_t part, uint64_t pixelformat) override
Offers a buffer for publication.
bool callCommand(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, bool exception=false)
std::string dev_serialno
std::string gev_userid
bool getImagePresent(std::uint32_t part) const
bool getIsIncomplete() const
Specific implementation for roboception::msgs::Dynamics messages.
static void transformStampedTFToMsg(const StampedTransform &bt, geometry_msgs::TransformStamped &msg)
bool setInteger(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, int64_t value, bool exception=false)
std::thread recoverThread
void setDepthRange(double _mindepth, double _maxdepth)
Set the depth range of the disparity images.
void add(const std::string &key, const T &val)
#define ROS_ERROR_STREAM(args)
RW
bool saveSlamMap(rc_common_msgs::Trigger::Request &req, rc_common_msgs::Trigger::Response &resp)
Save the onboard SLAM map.
unsigned int totalConnectionLosses
interface GENAPI_DECL_ABSTRACT INode
void sendTransform(const geometry_msgs::TransformStamped &transform)
std::shared_ptr< GenApi::CNodeMapRef > rcgnodemap
ros::Time toRosTime(const roboception::msgs::Time &time)
ros::ServiceServer dynamicsResetSlamService
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
boost::recursive_mutex mtx
#define ROS_ERROR(...)
void setParam(const std::string &key, const XmlRpc::XmlRpcValue &v) const
bool used() override
Returns true if there are subscribers to the topic.
std::string getString(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, bool exception=false, bool igncache=false)
std::string dev_ipaddr
virtual ~DeviceNodelet()
void publish(const rcg::Buffer *buffer, uint32_t part, uint64_t pixelformat) override
Offers a buffer for publication.
std::string tfPrefix
all frame names must be prefixed when using more than one rc_visard
void setDepthRange(double _mindepth, double _maxdepth)
Set the depth range of the disparity images.
bool loadSlamMap(rc_common_msgs::Trigger::Request &req, rc_common_msgs::Trigger::Response &resp)
Load the onboard SLAM map.
ros::ServiceServer slamRemoveMapService
std::uint32_t getNumberOfParts() const


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Sat Feb 13 2021 03:42:55