genicam_device_nodelet.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Roboception GmbH
3  * All rights reserved
4  *
5  * Author: Heiko Hirschmueller
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 "genicam_device_nodelet.h"
45 
46 #include <rc_genicam_api/device.h>
47 #include <rc_genicam_api/stream.h>
48 #include <rc_genicam_api/buffer.h>
49 #include <rc_genicam_api/config.h>
51 
53 #include <exception>
54 
55 #include <sstream>
56 #include <stdexcept>
57 
58 #include <ros/ros.h>
59 #include <rc_common_msgs/ReturnCodeConstants.h>
60 #include <rc_common_msgs/CameraParam.h>
61 
62 namespace rc
63 {
65 {
66  scomponents = 0;
67  scolor = 0;
68 
69  running = false;
70 
71  gev_packet_size = 0;
77  streaming = false;
78 }
79 
81 {
82  NODELET_INFO("Shutting down");
83 
84  // signal running threads and wait until they finish
85 
86  running = false;
87  if (grab_thread.joinable())
88  {
89  grab_thread.join();
90  }
91 
93 }
94 
96 {
97  NODELET_INFO("Initialization started");
98 
99  std::string ns = ros::this_node::getNamespace();
100 
101  if (ns.size() > 0 && ns[0] == '/')
102  {
103  ns = ns.substr(1);
104  }
105 
106  if (ns.size() > 0)
107  {
108  frame_id = ns + "_camera";
109  }
110  else
111  {
112  frame_id = "camera";
113  }
114 
115  // get parameter configuration
116 
118  ros::NodeHandle nh(getNodeHandle(), "");
119 
120  std::string id = "*";
121  std::string access = "control";
122 
123  pnh.param("device", id, id);
124  pnh.param("gev_access", access, access);
125 
126  rcg::Device::ACCESS access_id;
127  if (access == "exclusive")
128  {
129  access_id = rcg::Device::EXCLUSIVE;
130  }
131  else if (access == "control")
132  {
133  access_id = rcg::Device::CONTROL;
134  }
135  else
136  {
137  NODELET_FATAL_STREAM("Access must be 'control' or 'exclusive': " << access);
138  return;
139  }
140 
141  // setup services
142 
144  pnh.advertiseService("depth_acquisition_trigger", &GenICamDeviceNodelet::depthAcquisitionTrigger, this);
145 
146  // add callbacks for diagnostics publishing
147 
150 
151  // start grabbing thread
152 
153  running = true;
154  grab_thread = std::thread(&GenICamDeviceNodelet::grab, this, id, access_id);
155 
156  NODELET_INFO("Initialization done");
157 }
158 
159 bool GenICamDeviceNodelet::depthAcquisitionTrigger(rc_common_msgs::Trigger::Request& req,
160  rc_common_msgs::Trigger::Response& res)
161 {
162  std::lock_guard<std::recursive_mutex> lock(device_mtx);
163 
164  if (nodemap)
165  {
166  if (config.depth_acquisition_mode != "Continuous")
167  {
168  try
169  {
170  NODELET_DEBUG("Triggering stereo matching");
171 
172  rcg::callCommand(nodemap, "DepthAcquisitionTrigger", true);
173 
174  res.return_code.value = rc_common_msgs::ReturnCodeConstants::SUCCESS;
175  res.return_code.message = "Stereo matching was triggered.";
176  }
177  catch (const std::exception& ex)
178  {
179  res.return_code.value = rc_common_msgs::ReturnCodeConstants::INTERNAL_ERROR;
180  res.return_code.message = ex.what();
181  NODELET_ERROR(ex.what());
182  }
183  }
184  else
185  {
186  res.return_code.value = rc_common_msgs::ReturnCodeConstants::NOT_APPLICABLE;
187  res.return_code.message = "Triggering stereo matching is only possible if acquisition_mode is set to SingleFrame "
188  "or SingleFrameOut1!";
189  NODELET_DEBUG_STREAM("" << res.return_code.message);
190  }
191  }
192  else
193  {
194  res.return_code.value = rc_common_msgs::ReturnCodeConstants::NOT_APPLICABLE;
195  res.return_code.message = "Not connected";
196  }
197 
198  return true;
199 }
200 
202 {
203  std::lock_guard<std::recursive_mutex> lock(device_mtx);
204 
206 
207  // get current camera configuration
208 
209  config.camera_fps = rcg::getFloat(nodemap, "AcquisitionFrameRate", 0, 0, true);
210 
211  std::string v = rcg::getEnum(nodemap, "ExposureAuto", true);
212  config.camera_exp_auto = (v != "Off");
213 
214  if (config.camera_exp_auto)
215  {
216  if (v == "Continuous")
217  {
218  config.camera_exp_auto_mode = "Normal";
219  }
220  else
221  {
222  config.camera_exp_auto_mode = v;
223  }
224  }
225 
226  config.camera_exp_max = rcg::getFloat(nodemap, "ExposureTimeAutoMax", 0, 0, true) / 1000000;
227 
228  try
229  {
230  config.camera_exp_auto_average_max = rcg::getFloat(nodemap, "RcExposureAutoAverageMax", 0, 0, true);
231  config.camera_exp_auto_average_min = rcg::getFloat(nodemap, "RcExposureAutoAverageMin", 0, 0, true);
232  }
233  catch (const std::exception&)
234  {
235  config.camera_exp_auto_average_max = 0.75f;
236  config.camera_exp_auto_average_min = 0.25f;
237  }
238 
239  config.camera_exp_width = rcg::getInteger(nodemap, "ExposureRegionWidth", 0, 0, true);
240  config.camera_exp_height = rcg::getInteger(nodemap, "ExposureRegionHeight", 0, 0, true);
241  config.camera_exp_offset_x = rcg::getInteger(nodemap, "ExposureRegionOffsetX", 0, 0, true);
242  config.camera_exp_offset_y = rcg::getInteger(nodemap, "ExposureRegionOffsetY", 0, 0, true);
243  config.camera_exp_value = rcg::getFloat(nodemap, "ExposureTime", 0, 0, true) / 1000000;
244 
245  rcg::setEnum(nodemap, "GainSelector", "All", false);
246  config.camera_gain_value = rcg::getFloat(nodemap, "Gain", 0, 0, true);
247 
248  try
249  {
250  std::string v = rcg::getEnum(nodemap, "BalanceWhiteAuto", true);
251 
252  config.camera_wb_auto = (v != "Off");
253  rcg::setEnum(nodemap, "BalanceRatioSelector", "Red", true);
254  config.camera_wb_ratio_red = rcg::getFloat(nodemap, "BalanceRatio", 0, 0, true);
255  rcg::setEnum(nodemap, "BalanceRatioSelector", "Blue", true);
256  config.camera_wb_ratio_blue = rcg::getFloat(nodemap, "BalanceRatio", 0, 0, true);
257  }
258  catch (const std::exception&)
259  {
260  config.camera_wb_auto = true;
261  config.camera_wb_ratio_red = 1.2;
262  config.camera_wb_ratio_blue = 2.4;
263  }
264 
265  // get depth image configuration
266 
267  config.depth_acquisition_mode = rcg::getEnum(nodemap, "DepthAcquisitionMode", true);
268  config.depth_quality = rcg::getEnum(nodemap, "DepthQuality", true);
269  config.depth_static_scene = rcg::getBoolean(nodemap, "DepthStaticScene", true);
270  config.depth_double_shot = rcg::getBoolean(nodemap, "DepthDoubleShot", false);
271  config.depth_seg = rcg::getInteger(nodemap, "DepthSeg", 0, 0, true);
272  config.depth_smooth = rcg::getBoolean(nodemap, "DepthSmooth", true);
273  config.depth_fill = rcg::getInteger(nodemap, "DepthFill", 0, 0, true);
274  config.depth_minconf = rcg::getFloat(nodemap, "DepthMinConf", 0, 0, true);
275  config.depth_mindepth = rcg::getFloat(nodemap, "DepthMinDepth", 0, 0, true);
276  config.depth_maxdepth = rcg::getFloat(nodemap, "DepthMaxDepth", 0, 0, true);
277  config.depth_maxdeptherr = rcg::getFloat(nodemap, "DepthMaxDepthErr", 0, 0, true);
278 
279  config.ptp_enabled = rcg::getBoolean(nodemap, "GevIEEE1588", false);
280 
281  rcg::setEnum(nodemap, "LineSelector", "Out1", true);
282  config.out1_mode = rcg::getEnum(nodemap, "LineSource", true);
283 
284  rcg::setEnum(nodemap, "LineSelector", "Out2", true);
285  config.out2_mode = rcg::getEnum(nodemap, "LineSource", true);
286 
287  // try to get ROS parameters: if parameter is not set in parameter server
288  // default to current sensor configuration
289 
290  pnh.param("camera_fps", config.camera_fps, config.camera_fps);
291  pnh.param("camera_exp_auto", config.camera_exp_auto, config.camera_exp_auto);
292  pnh.param("camera_exp_auto_mode", config.camera_exp_auto_mode, config.camera_exp_auto_mode);
293  pnh.param("camera_exp_max", config.camera_exp_max, config.camera_exp_max);
294  pnh.param("camera_exp_auto_average_max", config.camera_exp_auto_average_max, config.camera_exp_auto_average_max);
295  pnh.param("camera_exp_auto_average_min", config.camera_exp_auto_average_min, config.camera_exp_auto_average_min);
296  pnh.param("camera_exp_value", config.camera_exp_value, config.camera_exp_value);
297  pnh.param("camera_gain_value", config.camera_gain_value, config.camera_gain_value);
298  pnh.param("camera_exp_offset_x", config.camera_exp_offset_x, config.camera_exp_offset_x);
299  pnh.param("camera_exp_offset_y", config.camera_exp_offset_y, config.camera_exp_offset_y);
300  pnh.param("camera_exp_width", config.camera_exp_width, config.camera_exp_width);
301  pnh.param("camera_exp_height", config.camera_exp_height, config.camera_exp_height);
302  pnh.param("camera_wb_auto", config.camera_wb_auto, config.camera_wb_auto);
303  pnh.param("camera_wb_ratio_red", config.camera_wb_ratio_red, config.camera_wb_ratio_red);
304  pnh.param("camera_wb_ratio_blue", config.camera_wb_ratio_blue, config.camera_wb_ratio_blue);
305  pnh.param("depth_acquisition_mode", config.depth_acquisition_mode, config.depth_acquisition_mode);
306  pnh.param("depth_quality", config.depth_quality, config.depth_quality);
307  pnh.param("depth_static_scene", config.depth_static_scene, config.depth_static_scene);
308  pnh.param("depth_double_shot", config.depth_double_shot, config.depth_double_shot);
309  pnh.param("depth_seg", config.depth_seg, config.depth_seg);
310  pnh.param("depth_smooth", config.depth_smooth, config.depth_smooth);
311  pnh.param("depth_fill", config.depth_fill, config.depth_fill);
312  pnh.param("depth_minconf", config.depth_minconf, config.depth_minconf);
313  pnh.param("depth_mindepth", config.depth_mindepth, config.depth_mindepth);
314  pnh.param("depth_maxdepth", config.depth_maxdepth, config.depth_maxdepth);
315  pnh.param("depth_maxdeptherr", config.depth_maxdeptherr, config.depth_maxdeptherr);
316  pnh.param("ptp_enabled", config.ptp_enabled, config.ptp_enabled);
317  pnh.param("out1_mode", config.out1_mode, config.out1_mode);
318  pnh.param("out2_mode", config.out2_mode, config.out2_mode);
319 
320  // set parameters on parameter server so that dynamic reconfigure picks them up
321 
322  pnh.setParam("camera_fps", config.camera_fps);
323  pnh.setParam("camera_exp_auto", config.camera_exp_auto);
324  pnh.setParam("camera_exp_auto_mode", config.camera_exp_auto_mode);
325  pnh.setParam("camera_exp_max", config.camera_exp_max);
326  pnh.setParam("camera_exp_auto_average_max", config.camera_exp_auto_average_max);
327  pnh.setParam("camera_exp_auto_average_min", config.camera_exp_auto_average_min);
328  pnh.setParam("camera_exp_value", config.camera_exp_value);
329  pnh.setParam("camera_gain_value", config.camera_gain_value);
330  pnh.setParam("camera_exp_offset_x", config.camera_exp_offset_x);
331  pnh.setParam("camera_exp_offset_y", config.camera_exp_offset_y);
332  pnh.setParam("camera_exp_width", config.camera_exp_width);
333  pnh.setParam("camera_exp_height", config.camera_exp_height);
334  pnh.setParam("camera_wb_auto", config.camera_wb_auto);
335  pnh.setParam("camera_wb_ratio_red", config.camera_wb_ratio_red);
336  pnh.setParam("camera_wb_ratio_blue", config.camera_wb_ratio_blue);
337  pnh.setParam("depth_acquisition_mode", config.depth_acquisition_mode);
338  pnh.setParam("depth_quality", config.depth_quality);
339  pnh.setParam("depth_static_scene", config.depth_static_scene);
340  pnh.setParam("depth_double_shot", config.depth_double_shot);
341  pnh.setParam("depth_seg", config.depth_seg);
342  pnh.setParam("depth_smooth", config.depth_smooth);
343  pnh.setParam("depth_fill", config.depth_fill);
344  pnh.setParam("depth_minconf", config.depth_minconf);
345  pnh.setParam("depth_mindepth", config.depth_mindepth);
346  pnh.setParam("depth_maxdepth", config.depth_maxdepth);
347  pnh.setParam("depth_maxdeptherr", config.depth_maxdeptherr);
348  pnh.setParam("ptp_enabled", config.ptp_enabled);
349  pnh.setParam("out1_mode", config.out1_mode);
350  pnh.setParam("out2_mode", config.out2_mode);
351 }
352 
353 void GenICamDeviceNodelet::reconfigure(rc_genicam_driver::rc_genicam_driverConfig& c, uint32_t level)
354 {
355  std::lock_guard<std::recursive_mutex> lock(device_mtx);
356 
357  try
358  {
359  if (nodemap)
360  {
361  if (level & 1)
362  {
363  rcg::setFloat(nodemap, "AcquisitionFrameRate", c.camera_fps, true);
364  }
365 
366  if (level & 2)
367  {
368  if (c.camera_exp_auto)
369  {
370  // Normal means continuous and off must be controlled with exp_auto
371 
372  if (c.camera_exp_auto_mode == "Off" || c.camera_exp_auto_mode == "Normal")
373  {
374  c.camera_exp_auto_mode = "Continuous";
375  }
376 
377  // find user requested auto exposure mode in the list of enums
378 
379  std::vector<std::string> list;
380  rcg::getEnum(nodemap, "ExposureAuto", list, false);
381 
382  std::string mode = "Continuous";
383  for (size_t i = 0; i < list.size(); i++)
384  {
385  if (c.camera_exp_auto_mode == list[i])
386  {
387  mode = list[i];
388  }
389  }
390 
391  // set auto exposure mode
392 
393  rcg::setEnum(nodemap, "ExposureAuto", mode.c_str(), true);
394 
395  // Continuous means normal
396 
397  if (mode == "Continuous")
398  {
399  mode = "Normal";
400  }
401 
402  c.camera_exp_auto_mode = mode;
403  }
404  else
405  {
406  rcg::setEnum(nodemap, "ExposureAuto", "Off", true);
407 
408  usleep(100 * 1000);
409 
410  c.camera_exp_value = rcg::getFloat(nodemap, "ExposureTime", 0, 0, true, true) / 1000000;
411  c.camera_gain_value = rcg::getFloat(nodemap, "Gain", 0, 0, true, true);
412  }
413  }
414 
415  if (level & 4)
416  {
417  rcg::setFloat(nodemap, "ExposureTimeAutoMax", 1000000 * c.camera_exp_max, true);
418  }
419 
420  if (level & 8)
421  {
422  if (!rcg::setFloat(nodemap, "RcExposureAutoAverageMax", c.camera_exp_auto_average_max, false))
423  {
424  NODELET_WARN("rc_visard does not support parameter 'exp_auto_average_max'");
425  c.camera_exp_auto_average_max = 0.75f;
426  }
427  }
428 
429  if (level & 16)
430  {
431  if (!rcg::setFloat(nodemap, "RcExposureAutoAverageMin", c.camera_exp_auto_average_min, false))
432  {
433  NODELET_WARN("rc_visard does not support parameter 'exp_auto_average_min'");
434  c.camera_exp_auto_average_min = 0.25f;
435  }
436  }
437 
438  if (level & 32)
439  {
440  rcg::setFloat(nodemap, "ExposureTime", 1000000 * c.camera_exp_value, true);
441  }
442 
443  c.camera_gain_value = round(c.camera_gain_value / 6) * 6;
444 
445  if (level & 64)
446  {
447  rcg::setFloat(nodemap, "Gain", c.camera_gain_value, true);
448  }
449 
450  if (level & 128)
451  {
452  rcg::setInteger(nodemap, "ExposureRegionOffsetX", c.camera_exp_offset_x, true);
453  }
454 
455  if (level & 256)
456  {
457  rcg::setInteger(nodemap, "ExposureRegionOffsetY", c.camera_exp_offset_y, true);
458  }
459 
460  if (level & 512)
461  {
462  rcg::setInteger(nodemap, "ExposureRegionWidth", c.camera_exp_width, true);
463  }
464 
465  if (level & 1024)
466  {
467  rcg::setInteger(nodemap, "ExposureRegionHeight", c.camera_exp_height, true);
468  }
469 
470  bool color_ok = true;
471 
472  if (level & 2048)
473  {
474  if (c.camera_wb_auto)
475  {
476  color_ok = rcg::setEnum(nodemap, "BalanceWhiteAuto", "Continuous", false);
477  }
478  else
479  {
480  color_ok = rcg::setEnum(nodemap, "BalanceWhiteAuto", "Off", false);
481 
482  usleep(100 * 1000);
483 
484  rcg::setEnum(nodemap, "BalanceRatioSelector", "Red", false);
485  c.camera_wb_ratio_red = rcg::getFloat(nodemap, "BalanceRatio", 0, 0, false, true);
486 
487  rcg::setEnum(nodemap, "BalanceRatioSelector", "Blue", false);
488  c.camera_wb_ratio_blue = rcg::getFloat(nodemap, "BalanceRatio", 0, 0, false, true);
489  }
490  }
491 
492  if (level & 4096)
493  {
494  rcg::setEnum(nodemap, "BalanceRatioSelector", "Red", false);
495  color_ok = rcg::setFloat(nodemap, "BalanceRatio", c.camera_wb_ratio_red, false);
496  }
497 
498  if (level & 8192)
499  {
500  rcg::setEnum(nodemap, "BalanceRatioSelector", "Blue", false);
501  color_ok = rcg::setFloat(nodemap, "BalanceRatio", c.camera_wb_ratio_blue, false);
502  }
503 
504  if (!color_ok)
505  {
506  c.camera_wb_auto = true;
507  c.camera_wb_ratio_red = 1.2;
508  c.camera_wb_ratio_blue = 2.4;
509  }
510 
511  if (level & 16384)
512  {
513  // correct configuration strings if needed
514 
515  if (c.depth_acquisition_mode == "S" || c.depth_acquisition_mode == "SingleFrame")
516  {
517  c.depth_acquisition_mode = "SingleFrame";
518  }
519  else if (c.depth_acquisition_mode == "O" || c.depth_acquisition_mode == "SingleFrameOut1")
520  {
521  c.depth_acquisition_mode = "SingleFrameOut1";
522  }
523  else if (c.depth_acquisition_mode == "C" || c.depth_acquisition_mode == "Continuous")
524  {
525  c.depth_acquisition_mode = "Continuous";
526  }
527  else
528  {
529  c.depth_acquisition_mode = "Continuous";
530  }
531 
532  rcg::setEnum(nodemap, "DepthAcquisitionMode", c.depth_acquisition_mode.c_str(), true);
533  }
534 
535  if (level & 32768)
536  {
537  if (c.depth_quality == "Full" || c.depth_quality == "F")
538  {
539  c.depth_quality = "Full";
540  }
541  else if (c.depth_quality == "High" || c.depth_quality == "H")
542  {
543  c.depth_quality = "High";
544  }
545  else if (c.depth_quality == "Medium" || c.depth_quality == "M")
546  {
547  c.depth_quality = "Medium";
548  }
549  else if (c.depth_quality == "Low" || c.depth_quality == "L")
550  {
551  c.depth_quality = "Low";
552  }
553  else
554  {
555  c.depth_quality = "High";
556  }
557 
558  try
559  {
560  rcg::setEnum(nodemap, "DepthQuality", c.depth_quality.c_str(), true);
561  }
562  catch (const std::exception&)
563  {
564  c.depth_quality = "High";
565  rcg::setEnum(nodemap, "DepthQuality", c.depth_quality.c_str(), false);
566 
567  NODELET_ERROR("Cannot set full quality. Sensor may have no 'stereo_plus' license!");
568  }
569  }
570 
571  if (level & 65536)
572  {
573  rcg::setBoolean(nodemap, "DepthStaticScene", c.depth_static_scene, true);
574  }
575 
576  if (level & 131072)
577  {
578  try
579  {
580  rcg::setBoolean(nodemap, "DepthDoubleShot", c.depth_double_shot, true);
581  }
582  catch (const std::exception&)
583  {
584  c.depth_double_shot = false;
585  NODELET_ERROR("Cannot set double shot mode. Please update the sensor to version >= 20.11.0!");
586  }
587  }
588 
589  if (level & 262144)
590  {
591  rcg::setInteger(nodemap, "DepthSeg", c.depth_seg, true);
592  }
593 
594  if (level & 524288 && c.depth_smooth != config.depth_smooth)
595  {
596  try
597  {
598  rcg::setBoolean(nodemap, "DepthSmooth", c.depth_smooth, true);
599  }
600  catch (const std::exception&)
601  {
602  c.depth_smooth = false;
603  rcg::setBoolean(nodemap, "DepthSmooth", c.depth_smooth, false);
604 
605  NODELET_ERROR("Cannot switch on smoothing. Sensor may have no 'stereo_plus' license!");
606  }
607  }
608 
609  if (level & 1048576)
610  {
611  rcg::setInteger(nodemap, "DepthFill", c.depth_fill, true);
612  }
613 
614  if (level & 2097152)
615  {
616  rcg::setFloat(nodemap, "DepthMinConf", c.depth_minconf, true);
617  }
618 
619  if (level & 4194304)
620  {
621  rcg::setFloat(nodemap, "DepthMinDepth", c.depth_mindepth, true);
622  }
623 
624  if (level & 8388608)
625  {
626  rcg::setFloat(nodemap, "DepthMaxDepth", c.depth_maxdepth, true);
627  }
628 
629  if (level & 16777216)
630  {
631  rcg::setFloat(nodemap, "DepthMaxDepthErr", c.depth_maxdeptherr, true);
632  }
633 
634  if ((level & 33554432) && c.ptp_enabled != config.ptp_enabled)
635  {
636  if (!rcg::setBoolean(nodemap, "GevIEEE1588", c.ptp_enabled, false))
637  {
638  NODELET_ERROR("Cannot change PTP.");
639  c.ptp_enabled = false;
640  }
641  }
642 
643  if ((level & 67108864) && c.out1_mode != config.out1_mode)
644  {
645  if (c.out1_mode != "Low" && c.out1_mode != "High" && c.out1_mode != "ExposureActive" &&
646  c.out1_mode != "ExposureAlternateActive")
647  {
648  c.out1_mode = "Low";
649  }
650 
651  rcg::setEnum(nodemap, "LineSelector", "Out1", true);
652 
653  if (!rcg::setEnum(nodemap, "LineSource", c.out1_mode.c_str(), false))
654  {
655  c.out1_mode = "Low";
656  NODELET_ERROR("Cannot change out1 mode. Sensor may have no 'iocontrol' license!");
657  }
658  }
659 
660  if (level & 134217728 && c.out2_mode != config.out2_mode)
661  {
662  if (c.out2_mode != "Low" && c.out2_mode != "High" && c.out2_mode != "ExposureActive" &&
663  c.out2_mode != "ExposureAlternateActive")
664  {
665  c.out2_mode = "Low";
666  }
667 
668  rcg::setEnum(nodemap, "LineSelector", "Out2", true);
669 
670  if (!rcg::setEnum(nodemap, "LineSource", c.out2_mode.c_str(), false))
671  {
672  c.out2_mode = "Low";
673  NODELET_ERROR("Cannot change out2 mode. Sensor may have no 'iocontrol' license!");
674  }
675  }
676  }
677  }
678  catch (const std::exception& ex)
679  {
680  NODELET_ERROR(ex.what());
681  }
682 
683  config = c;
684 }
685 
687 {
688  std::lock_guard<std::recursive_mutex> lock(device_mtx);
689 
690  // collect required components and color
691 
692  int rcomponents = 0;
693  bool rcolor = false;
694 
695  for (auto&& p : pub)
696  {
697  p->requiresComponents(rcomponents, rcolor);
698  }
699 
700  // Intensity is contained in IntensityCombined
701 
703  {
704  rcomponents &= ~GenICam2RosPublisher::ComponentIntensity;
705  }
706 
707  // enable or disable components as required
708 
709  const static struct
710  {
711  const char* name;
712  int flag;
713  } comp[] = { { "Intensity", GenICam2RosPublisher::ComponentIntensity },
714  { "IntensityCombined", GenICam2RosPublisher::ComponentIntensityCombined },
718  { 0, 0 } };
719 
720  for (size_t i = 0; comp[i].name != 0; i++)
721  {
722  if (((rcomponents ^ scomponents) & comp[i].flag) || force)
723  {
724  rcg::setEnum(nodemap, "ComponentSelector", comp[i].name, true);
725  rcg::setBoolean(nodemap, "ComponentEnable", (rcomponents & comp[i].flag), true);
726 
727  const char* status = "disabled";
728  if (rcomponents & comp[i].flag)
729  status = "enabled";
730 
731  if (!force)
732  {
733  NODELET_INFO_STREAM("Component '" << comp[i].name << "' " << status);
734  }
735  }
736  }
737 
738  // enable or disable color
739 
740  if (rcolor != scolor || force)
741  {
742  const char* format = "Mono8";
743  if (rcolor)
744  {
745  format = "YCbCr411_8";
746  }
747 
748  rcg::setEnum(nodemap, "ComponentSelector", "Intensity", true);
749  rcg::setEnum(nodemap, "PixelFormat", format, false);
750  rcg::setEnum(nodemap, "ComponentSelector", "IntensityCombined", true);
751  rcg::setEnum(nodemap, "PixelFormat", format, false);
752  }
753 
754  // store current settings
755 
756  scomponents = rcomponents;
757  scolor = rcolor;
758 }
759 
761 {
762  updateSubscriptions(false);
763 }
764 
766 {
767  stat.add("connection_loss_total", connection_loss_total);
768  stat.add("complete_buffers_total", complete_buffers_total);
769  stat.add("incomplete_buffers_total", incomplete_buffers_total);
770  stat.add("image_receive_timeouts_total", image_receive_timeouts_total);
771  stat.add("current_reconnect_trial", current_reconnect_trial);
772 
773  // general connection status
774 
775  if (device_serial.empty())
776  {
777  stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Disconnected");
778  return;
779  }
780 
781  // at least we are connected to gev server
782 
783  stat.add("ip_interface", device_interface);
784  stat.add("ip_address", device_ip);
785  stat.add("gev_packet_size", gev_packet_size);
786 
787  if (scomponents)
788  {
789  if (streaming)
790  {
791  // someone subscribed to images, and we actually receive data via GigE vision
792  stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Streaming");
793  }
794  else
795  {
796  // someone subscribed to images, but we do not receive any data via GigE vision (yet)
797  stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "No data");
798  }
799  }
800  else
801  {
802  // no one requested images -> node is ok but stale
803  stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Idle");
804  }
805 }
806 
808 {
809  if (device_serial.empty())
810  {
811  stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Unknown");
812  }
813  else
814  {
815  stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Info");
816  stat.add("model", device_model);
817  stat.add("image_version", device_version);
818  stat.add("serial", device_serial);
819  stat.add("mac", device_mac);
820  stat.add("user_id", device_name);
821  }
822 }
823 
824 namespace
825 {
826 std::vector<std::shared_ptr<rcg::Device> > getSupportedDevices(const std::string& devid,
827  const std::vector<std::string>& iname)
828 {
829  std::vector<std::shared_ptr<rcg::System> > system = rcg::System::getSystems();
830  std::vector<std::shared_ptr<rcg::Device> > ret;
831 
832  for (size_t i = 0; i < system.size(); i++)
833  {
834  system[i]->open();
835 
836  std::vector<std::shared_ptr<rcg::Interface> > interf = system[i]->getInterfaces();
837 
838  for (size_t k = 0; k < interf.size(); k++)
839  {
840  if (interf[k]->getTLType() == "GEV" &&
841  (iname.size() == 0 || std::find(iname.begin(), iname.end(), interf[k]->getID()) != iname.end()))
842  {
843  interf[k]->open();
844 
845  std::vector<std::shared_ptr<rcg::Device> > device = interf[k]->getDevices();
846 
847  for (size_t j = 0; j < device.size(); j++)
848  {
849  if ((device[j]->getVendor() == "Roboception GmbH" ||
850  device[j]->getModel().substr(0, 9) == "rc_visard" || device[j]->getModel().substr(0, 7) == "rc_cube") &&
851  (devid == "*" || device[j]->getID() == devid || device[j]->getSerialNumber() == devid ||
852  device[j]->getDisplayName() == devid))
853  {
854  ret.push_back(device[j]);
855  }
856  }
857 
858  interf[k]->close();
859  }
860  }
861 
862  system[i]->close();
863  }
864 
865  return ret;
866 }
867 
868 class NoDeviceException : public std::invalid_argument
869 {
870 public:
871  NoDeviceException(const char* msg) : std::invalid_argument(msg)
872  {
873  }
874 };
875 
876 void split(std::vector<std::string>& list, const std::string& s, char delim, bool skip_empty = true)
877 {
878  std::stringstream in(s);
879  std::string elem;
880 
881  while (getline(in, elem, delim))
882  {
883  if (!skip_empty || elem.size() > 0)
884  {
885  list.push_back(elem);
886  }
887  }
888 }
889 
890 } // namespace
891 
893 {
894  try
895  {
896  device_model = "";
897  device_version = "";
898  device_serial = "";
899  device_mac = "";
900  device_name = "";
901  device_interface = "";
902  device_ip = "";
903  gev_packet_size = 0;
905 
906  NODELET_INFO_STREAM("Grabbing thread started for device '" << id << "'");
907 
908  // loop until nodelet is killed
909 
910  while (running)
911  {
912  streaming = false;
913 
914  // report standard exceptions and try again
915 
916  try
917  {
918  std::shared_ptr<GenApi::CChunkAdapter> chunkadapter;
919 
920  {
921  std::lock_guard<std::recursive_mutex> lock(device_mtx);
922 
923  // open device and get nodemap
924 
925  std::vector<std::string> iname; // empty
926  std::string dname = id;
927 
928  {
929  size_t i = dname.find(':');
930  if (i != std::string::npos)
931  {
932  if (i > 0)
933  {
934  iname.push_back(id.substr(0, i));
935  }
936 
937  dname = dname.substr(i + 1);
938  }
939  }
940 
941  std::vector<std::shared_ptr<rcg::Device> > devices = getSupportedDevices(dname, iname);
942 
943  if (devices.size() == 0)
944  {
945  throw NoDeviceException(("Cannot find device '" + id + "'").c_str());
946  }
947 
948  if (devices.size() > 1)
949  {
950  throw std::invalid_argument("Too many devices, please specify unique ID");
951  }
952 
953  dev = devices[0];
954  dev->open(access);
955  nodemap = dev->getRemoteNodeMap();
956 
957  // check if device is ready
958 
959  if (!rcg::getBoolean(nodemap, "RcSystemReady", true, true))
960  {
961  throw std::invalid_argument("Device is not yet ready");
962  }
963 
964  // get serial number and IP
965 
966  device_interface = dev->getParent()->getID();
967  device_serial = dev->getSerialNumber();
968  device_mac = rcg::getString(nodemap, "GevMACAddress", true);
969  device_name = rcg::getString(nodemap, "DeviceUserID", true);
970  device_ip = rcg::getString(nodemap, "GevCurrentIPAddress", true);
971 
973  << "Connecting to sensor '" << device_interface << ":" << device_serial << "' alias "
974  << dev->getDisplayName());
975 
977 
978  // ensure that device version >= 20.04
979 
980  device_version = rcg::getString(nodemap, "DeviceVersion");
981 
982  std::vector<std::string> list;
983  split(list, device_version, '.');
984 
985  if (list.size() < 3 || std::stoi(list[0]) < 20 || (std::stoi(list[0]) == 20 && std::stoi(list[1]) < 4))
986  {
987  running = false;
988  throw std::invalid_argument("Device version must be 20.04 or higher: " + device_version);
989  }
990 
991  // get model type of the device
992 
993  device_model = rcg::getString(nodemap, "DeviceModelName");
994 
995  // initialise configuration and start dynamic reconfigure server
996 
997  if (!reconfig)
998  {
1000  reconfig = new dynamic_reconfigure::Server<rc_genicam_driver::rc_genicam_driverConfig>(
1002  }
1003 
1004  // initialize some values as the old values are checked in the
1005  // reconfigure callback
1006 
1007  config.depth_smooth = rcg::getBoolean(nodemap, "DepthSmooth", true);
1008 
1009  rcg::setEnum(nodemap, "LineSelector", "Out1", true);
1010  config.out1_mode = rcg::getEnum(nodemap, "LineSource", true);
1011  rcg::setEnum(nodemap, "LineSelector", "Out2", true);
1012  config.out2_mode = rcg::getEnum(nodemap, "LineSource", true);
1013 
1014  config.ptp_enabled = rcg::getBoolean(nodemap, "GevIEEE1588", false);
1015 
1016  // assign callback each time to trigger resetting all values
1017 
1018  dynamic_reconfigure::Server<rc_genicam_driver::rc_genicam_driverConfig>::CallbackType cb;
1019  cb = boost::bind(&GenICamDeviceNodelet::reconfigure, this, _1, _2);
1020  reconfig->setCallback(cb);
1021  }
1022 
1023  // enable chunk data and multipart
1024 
1025  rcg::setEnum(nodemap, "AcquisitionAlternateFilter", "Off", false);
1026  rcg::setEnum(nodemap, "AcquisitionMultiPartMode", "SingleComponent", true);
1027  rcg::setBoolean(nodemap, "ChunkModeActive", true, true);
1028 
1029  // set up chunk adapter
1030 
1031  chunkadapter = rcg::getChunkAdapter(nodemap, dev->getTLType());
1032 
1033  // check for color and iocontrol
1034 
1035  bool color = false;
1036 
1037  {
1038  std::vector<std::string> formats;
1039  rcg::setEnum(nodemap, "ComponentSelector", "Intensity", true);
1040  rcg::getEnum(nodemap, "PixelFormat", formats, true);
1041  for (auto&& format : formats)
1042  {
1043  if (format == "YCbCr411_8")
1044  {
1045  color = true;
1046  break;
1047  }
1048  }
1049  }
1050 
1051  bool iocontrol_avail = nodemap->_GetNode("LineSource")->GetAccessMode() == GenApi::RW;
1052 
1053  if (!color)
1054  {
1055  NODELET_INFO("Not a color camera. wb_auto, wb_ratio_red and wb_ratio_blue are without "
1056  "function.");
1057  }
1058 
1059  if (nodemap->_GetNode("DepthSmooth")->GetAccessMode() != GenApi::RW)
1060  {
1061  NODELET_WARN("No stereo_plus license on device. quality=full and smoothing is not available.");
1062  }
1063 
1064  if (!iocontrol_avail)
1065  {
1066  NODELET_WARN("No iocontrol license on device. out1_mode and out2_mode are without function.");
1067  }
1068 
1069  // advertise publishers
1070 
1071  ros::NodeHandle nh(getNodeHandle(), "stereo");
1073  std::function<void()> callback = std::bind(&GenICamDeviceNodelet::subChanged, this);
1074 
1075  pub.clear();
1076  scomponents = 0;
1077  scolor = false;
1078 
1079  pub.push_back(std::make_shared<CameraInfoPublisher>(nh, frame_id, true, callback));
1080  pub.push_back(std::make_shared<CameraInfoPublisher>(nh, frame_id, false, callback));
1081  pub.push_back(std::make_shared<CameraParamPublisher>(nh, frame_id, true, callback));
1082  pub.push_back(std::make_shared<CameraParamPublisher>(nh, frame_id, false, callback));
1083 
1084  pub.push_back(std::make_shared<ImagePublisher>(it, frame_id, true, false, iocontrol_avail, callback));
1085  pub.push_back(std::make_shared<ImagePublisher>(it, frame_id, false, false, iocontrol_avail, callback));
1086 
1087  if (color)
1088  {
1089  pub.push_back(std::make_shared<ImagePublisher>(it, frame_id, true, true, iocontrol_avail, callback));
1090  pub.push_back(std::make_shared<ImagePublisher>(it, frame_id, false, true, iocontrol_avail, callback));
1091  }
1092 
1093  pub.push_back(std::make_shared<DisparityPublisher>(nh, frame_id, callback));
1094  pub.push_back(std::make_shared<DisparityColorPublisher>(it, frame_id, callback));
1095  pub.push_back(std::make_shared<DepthPublisher>(nh, frame_id, callback));
1096 
1097  pub.push_back(std::make_shared<ConfidencePublisher>(nh, frame_id, callback));
1098  pub.push_back(std::make_shared<ErrorDisparityPublisher>(nh, frame_id, callback));
1099  pub.push_back(std::make_shared<ErrorDepthPublisher>(nh, frame_id, callback));
1100 
1101  pub.push_back(std::make_shared<Points2Publisher>(nh, frame_id, callback));
1102 
1103  // make nodemap available to publshers
1104 
1105  for (auto&& p : pub)
1106  {
1107  p->setNodemap(nodemap);
1108  }
1109 
1110  // update subscriptions
1111 
1112  updateSubscriptions(true);
1113 
1114  // start streaming
1115 
1116  std::vector<std::shared_ptr<rcg::Stream> > stream = dev->getStreams();
1117 
1118  if (stream.size() == 0)
1119  {
1120  throw std::invalid_argument("Device does not offer streams");
1121  }
1122 
1123  stream[0]->open();
1124  stream[0]->startStreaming();
1125 
1127 
1129 
1130  NODELET_INFO_STREAM("Start streaming images");
1131 
1132  // grabbing and publishing
1133 
1134  while (running)
1135  {
1136  // grab next buffer
1137 
1138  const rcg::Buffer* buffer = stream[0]->grab(500);
1139  std::string out1_mode_on_sensor;
1140 
1141  // process buffer
1142 
1143  if (buffer)
1144  {
1145  streaming = true;
1146 
1147  if (buffer->getIsIncomplete())
1148  {
1150  out1_mode_on_sensor = "";
1151  }
1152  else
1153  {
1155 
1156  std::lock_guard<std::recursive_mutex> lock(device_mtx);
1157 
1158  if (gev_packet_size == 0)
1159  {
1160  gev_packet_size = rcg::getInteger(nodemap, "GevSCPSPacketSize", 0, 0, true, false);
1161  }
1162 
1163  // attach buffer to nodemap to access chunk data
1164 
1165  chunkadapter->AttachBuffer(reinterpret_cast<std::uint8_t*>(buffer->getGlobalBase()),
1166  buffer->getSizeFilled());
1167 
1168  // get out1 mode on device, which may have changed
1169 
1170  rcg::setEnum(nodemap, "ChunkLineSelector", "Out1", true);
1171  out1_mode_on_sensor = rcg::getEnum(nodemap, "ChunkLineSource", true);
1172 
1173  // publish all parts of buffer
1174 
1175  uint32_t npart = buffer->getNumberOfParts();
1176  for (uint32_t part = 0; part < npart; part++)
1177  {
1178  if (buffer->getImagePresent(part))
1179  {
1180  uint64_t pixelformat = buffer->getPixelFormat(part);
1181  for (auto&& p : pub)
1182  {
1183  p->publish(buffer, part, pixelformat);
1184  }
1185  }
1186  }
1187 
1188  // detach buffer from nodemap
1189 
1190  chunkadapter->DetachBuffer();
1191  }
1192  }
1193  else
1194  {
1196  streaming = false;
1197 
1198  // get out1 mode from sensor (this is also used to check if the
1199  // connection is still valid)
1200 
1201  std::lock_guard<std::recursive_mutex> lock(device_mtx);
1202  rcg::setEnum(nodemap, "LineSelector", "Out1", true);
1203  out1_mode_on_sensor = rcg::getString(nodemap, "LineSource", true, true);
1204  }
1205 
1206  {
1207  std::lock_guard<std::recursive_mutex> lock(device_mtx);
1208 
1209  // update out1 mode, if it is different to current settings on sensor
1210  // (which is the only GEV parameter which could have changed outside this code,
1211  // i.e. on the rc_visard by the stereomatching module)
1212 
1213  if (out1_mode_on_sensor.size() == 0)
1214  {
1215  // use current settings if the value on the sensor cannot be determined
1216  out1_mode_on_sensor = config.out1_mode;
1217  }
1218 
1219  if (out1_mode_on_sensor != config.out1_mode)
1220  {
1221  config.out1_mode = out1_mode_on_sensor;
1222  reconfig->updateConfig(config);
1223  }
1224  }
1225 
1226  updater.update();
1227  }
1228 
1229  pub.clear();
1230 
1231  // stop streaming
1232 
1233  stream[0]->stopStreaming();
1234  stream[0]->close();
1235 
1236  // stop publishing
1237 
1238  device_model = "";
1239  device_version = "";
1240  device_serial = "";
1241  device_mac = "";
1242  device_name = "";
1243  device_interface = "";
1244  device_ip = "";
1245  gev_packet_size = 0;
1246  streaming = false;
1247 
1249  }
1250  catch (const NoDeviceException& ex)
1251  {
1252  // report error, wait and retry
1253 
1254  NODELET_WARN(ex.what());
1255 
1257  streaming = false;
1258  pub.clear();
1259 
1261 
1262  sleep(3);
1263  }
1264  catch (const std::exception& ex)
1265  {
1266  // close everything and report error
1267 
1268  if (device_ip.size() > 0)
1269  {
1271  }
1272 
1273  device_model = "";
1274  device_version = "";
1275  device_serial = "";
1276  device_mac = "";
1277  device_name = "";
1278  device_interface = "";
1279  device_ip = "";
1280  gev_packet_size = 0;
1281  streaming = false;
1282 
1284  pub.clear();
1285 
1286  NODELET_ERROR(ex.what());
1287 
1289 
1290  sleep(3);
1291  }
1292 
1293  // close device
1294 
1295  {
1296  std::lock_guard<std::recursive_mutex> lock(device_mtx);
1297 
1298  if (dev)
1299  dev->close();
1300 
1301  dev.reset();
1302  nodemap.reset();
1303  }
1304  }
1305  }
1306  catch (const std::exception& ex)
1307  {
1308  NODELET_FATAL(ex.what());
1309  }
1310  catch (...)
1311  {
1312  NODELET_FATAL("Unknown exception");
1313  }
1314 
1315  device_model = "";
1316  device_version = "";
1317  device_serial = "";
1318  device_mac = "";
1319  device_name = "";
1320  device_interface = "";
1321  device_ip = "";
1322  gev_packet_size = 0;
1323  streaming = false;
1325 
1326  running = false;
1327  NODELET_INFO("Grabbing thread stopped");
1328 }
1329 
1330 } // namespace rc
1331 
Interface for all publishers relating to images, point clouds or other stereo-camera data...
std::shared_ptr< rcg::Device > dev
msg
bool getBoolean(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, bool exception=false, bool igncache=false)
#define NODELET_INFO_STREAM(...)
#define NODELET_ERROR(...)
bool depthAcquisitionTrigger(rc_common_msgs::Trigger::Request &req, rc_common_msgs::Trigger::Response &resp)
#define NODELET_WARN(...)
diagnostic_updater::Updater updater
size_t getSizeFilled() const
void summary(unsigned char lvl, const std::string s)
std::istream & getline(std::istream &is, GENICAM_NAMESPACE::gcstring &str)
int64_t round(double x)
std::shared_ptr< GenApi::CChunkAdapter > getChunkAdapter(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const std::string &tltype)
static const int ComponentDisparity
void setHardwareID(const std::string &hwid)
XmlRpcServer s
static std::vector< std::shared_ptr< System > > getSystems()
rc_genicam_driver::rc_genicam_driverConfig config
void add(const std::string &name, TaskFunction f)
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)
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
boost::recursive_mutex reconfig_mtx
bool setFloat(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, double value, bool exception=false)
bool setEnum(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, const char *value, bool exception=false)
ros::NodeHandle & getPrivateNodeHandle() const
static const int ComponentConfidence
static void clearSystems()
static const int ComponentIntensity
void * getGlobalBase() const
void publishConnectionDiagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat)
ROSCPP_DECL const std::string & getNamespace()
void updateSubscriptions(bool force=false)
std::string getEnum(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, bool exception=false)
uint64_t getPixelFormat(std::uint32_t part) const
bool param(const std::string &param_name, T &param_val, const T &default_val) const
ros::NodeHandle & getNodeHandle() const
ros::ServiceServer trigger_service
#define NODELET_DEBUG_STREAM(...)
bool setBoolean(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, bool value, bool exception=false)
std::shared_ptr< GenApi::CNodeMapRef > nodemap
#define NODELET_INFO(...)
double getFloat(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, double *vmin=0, double *vmax=0, bool exception=false, bool igncache=false)
dynamic_reconfigure::Server< rc_genicam_driver::rc_genicam_driverConfig > * reconfig
void publishDeviceDiagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat)
void grab(std::string id, rcg::Device::ACCESS access)
bool callCommand(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, bool exception=false)
#define NODELET_FATAL_STREAM(...)
bool getImagePresent(std::uint32_t part) const
bool getIsIncomplete() const
bool setInteger(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, int64_t value, bool exception=false)
void add(const std::string &key, const T &val)
std::vector< std::shared_ptr< GenICam2RosPublisher > > pub
#define NODELET_FATAL(...)
RW
void reconfigure(rc_genicam_driver::rc_genicam_driverConfig &c, uint32_t level)
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
void setParam(const std::string &key, const XmlRpc::XmlRpcValue &v) const
#define NODELET_DEBUG(...)
std::string getString(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, bool exception=false, bool igncache=false)
static const int ComponentIntensityCombined
std::recursive_mutex device_mtx
std::uint32_t getNumberOfParts() const


rc_genicam_driver
Author(s): Heiko Hirschmueller , Felix Ruess
autogenerated on Sat Feb 13 2021 03:55:07