Fawkes API  Fawkes Development Version
deadspots.cpp
1 
2 /***************************************************************************
3  * deadspots.cpp - Laser dead spots calibration tool
4  *
5  * Created: Wed Jun 24 12:00:54 2009
6  * Copyright 2006-2009 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Library General Public License for more details.
19  *
20  * Read the full text in the LICENSE.GPL file in the doc directory.
21  */
22 
23 #include <core/threading/thread.h>
24 #include <core/threading/wait_condition.h>
25 #include <utils/system/argparser.h>
26 #include <utils/time/time.h>
27 #include <netcomm/fawkes/client.h>
28 #include <blackboard/remote.h>
29 #include <blackboard/interface_listener.h>
30 #include <config/netconf.h>
31 
32 #include <interfaces/Laser360Interface.h>
33 #include <interfaces/Laser720Interface.h>
34 
35 #include <cstring>
36 #include <cstdlib>
37 #include <cstdio>
38 #include <unistd.h>
39 #include <cmath>
40 #include <vector>
41 #include <algorithm>
42 #include <utility>
43 
44 #define MAX_WAIT_TIME 60
45 #define DEFAULT_WAIT_TIME 10
46 #define DEFAULT_NUM_MEASUREMENTS 100
47 #define DEFAULT_COMPARE_DISTANCE 0.9
48 
49 #define INITIAL_MEASUREMENT 123456.0
50 
51 using namespace fawkes;
52 
53 void
54 print_usage(const char *program_name)
55 {
56  printf("Usage: %s [-h] [-r host[:port]] <num_spots> <config_prefix>\n"
57  " -h This help message\n"
58  " -r host[:port] Remote host (and optionally port) to connect to\n"
59  " -n <NUM> Number of measurements to use, defaults to %u\n"
60  " -w <SEC> Wait time in seconds, defaults to %u\n"
61  " -c <DIST> Compare distance in m, defaults to %f\n"
62  " -m <MARGIN_DEG> Margin in degree to add around dead spot regions\n"
63  " -d Dry-run, do not save results to configuration\n"
64  " -b Show data by opening a blackboard laser interface\n"
65  " -i <ID> Open laser interface named <ID>\n"
66  "<num_spots> Expected number of dead spots\n",
67  program_name, DEFAULT_NUM_MEASUREMENTS, DEFAULT_WAIT_TIME,
68  DEFAULT_COMPARE_DISTANCE);
69 }
70 
71 /** Calibrator for dead ranges.
72  * Depending how the laser is mounted parts of the range it covers might be
73  * useless data, for example if hidden behind rods. This calibrator detects
74  * those ranges and writes the information to the config suitable to be
75  * used by the LaserDeadSpotsDataFilter.
76  * @author Tim Niemueller
77  */
79 {
80  public:
81  /** Constructor.
82  * @param num_spots number of expected spots
83  * @param num_measurements number of measurements to take
84  * @param compare_distance distance to compare values to
85  * @param margin extra margin in degree to add around detected regions
86  * @param blackboard blackboard to register with as listener
87  * @param laser360 360 beams laser interface
88  * @param laser720 720 beams laser interface
89  */
90  LaserDeadSpotCalibrator(unsigned int num_spots, unsigned int num_measurements,
91  float compare_distance, float margin,
92  BlackBoard *blackboard,
93  Laser360Interface *laser360, Laser720Interface *laser720)
94  : BlackBoardInterfaceListener("LaserDeadSpotCalibrator")
95  {
96  __laser720 = laser720;
97  __laser360 = laser360;
98  __blackboard = blackboard;
99  __num_spots_expected = num_spots;
100  __num_measurements = num_measurements;
101  __cur_measurement = 0;
102  __num_beams = 0;
103  __margin = margin;
104  __compare_distance = compare_distance;
105  __measurements.clear();
106  __num_spots_found = 0;
107 
108  if (!__laser720 || ! __laser720->has_writer()) {
109  __lowres_calibrate = true;
110  __num_beams = __laser360->maxlenof_distances();
111  bbil_add_data_interface(__laser360);
112  } else {
113  __lowres_calibrate = false;
114  __num_beams = __laser720->maxlenof_distances();
115  bbil_add_data_interface(__laser720);
116  }
117  std::vector<float> tmp;
118  tmp.resize(__num_measurements, INITIAL_MEASUREMENT);
119  __measurements.resize(__num_beams, tmp);
120 
121  __blackboard->register_listener(this);
122  }
123 
124  /** Wait for the calibration to be finished. */
125  void
127  {
128  __start_measuring = true;
129  __finish_waitcond.wait();
130  }
131 
132  /** Get spots.
133  * @return vector of detected dead regions
134  */
135  std::vector<std::pair<float, float> >
137  {
138  return __dead_spots;
139  }
140 
141  /** Get number of spots.
142  * @return number of spots
143  */
144  unsigned int
146  {
147  return __num_spots_found;
148  }
149 
150  private:
151  float
152  calculate_median(std::vector<float> measurements)
153  {
154  std::sort(measurements.begin(), measurements.end());
155  return measurements[measurements.size() / 2];
156  }
157 
158  std::vector<float>
159  calculate_medians()
160  {
161  std::vector<float> rv;
162  rv.resize(__num_beams, INITIAL_MEASUREMENT);
163 
164  for (unsigned int i = 0; i < __measurements.size(); ++i) {
165  rv[i] = calculate_median(__measurements[i]);
166  }
167 
168  return rv;
169  }
170 
171 
172  void
173  analyze()
174  {
175  //printf("ANALYZING\n");
176  float angle_factor = 360.0 / __num_beams;
177 
178  std::vector<float> medians = calculate_medians();
179 
180  bool iteration_done = false;
181  for (unsigned int i = 0; ! iteration_done && i < medians.size(); ++i) {
182 
183  if (medians[i] == INITIAL_MEASUREMENT) {
184  printf("WARNING: No valid measurement at angle %f°!\n", i * angle_factor);
185  continue;
186  }
187 
188  if (medians[i] < __compare_distance) {
189  // start of spot, look for end
190  float start_angle = i * angle_factor;
191 
192  //printf("Region starting at %f\n", start_angle);
193 
194  do {
195  //printf("Median %u: %f < %f\n", i, medians[i], __compare_distance);
196 
197  if ((i + 1) >= medians.size()) {
198  if (iteration_done) {
199  printf("Could not find end for region starting at %f°, all values "
200  "too short?\n", start_angle);
201  break;
202  } else {
203  iteration_done = true;
204  i = 0;
205  }
206  } else {
207  ++i;
208  }
209  } while ((medians[i] < __compare_distance) && (medians[i] != INITIAL_MEASUREMENT));
210  if (medians[i] >= __compare_distance) {
211  float end_angle = i * angle_factor;
212  //printf("Region ends at %f\n", end_angle);
213  __dead_spots.push_back(std::make_pair(start_angle, end_angle));
214  } else {
215  // did not find end of region
216  break;
217  }
218  }
219  }
220  }
221 
222  void
223  sort_spots()
224  {
225  std::sort(__dead_spots.begin(), __dead_spots.end());
226  }
227 
228  bool
229  merge_region(unsigned int ind1, unsigned int ind2)
230  {
231  if (__dead_spots[ind1].second >= __dead_spots[ind2].first) {
232  // regions overlap, merge!
233  if (__dead_spots[ind1].first > __dead_spots[ind2].second) {
234  // merging would create a region across the discontinuity, do a
235  // split-merge, i.e. join regions to one, but save as two (cf. normalize())
236  //printf("Merging overlapping regions %u [%f, %f] and %u [%f, %f] to [%f, %f]/[%f, %f]\n",
237  // ind1, __dead_spots[ind1].first, __dead_spots[ind1].second,
238  // ind2, __dead_spots[ind2].first, __dead_spots[ind2].second,
239  // __dead_spots[ind1].first, 360., 0., __dead_spots[ind2].second);
240  __dead_spots[ind1].second = 360.;
241  __dead_spots[ind2].first = 0.;
242  } else {
243  //printf("Merging overlapping regions %u [%f, %f] and %u [%f, %f] to [%f, %f]\n",
244  // ind1, __dead_spots[ind1].first, __dead_spots[ind1].second,
245  // ind2, __dead_spots[ind2].first, __dead_spots[ind2].second,
246  // __dead_spots[ind1].first, __dead_spots[ind2].second);
247  __dead_spots[ind1].second = __dead_spots[ind2].second;
248  __dead_spots.erase(__dead_spots.begin() + ind2);
249  return false;
250  }
251  }
252  return true;
253  }
254 
255  void
256  merge_spots()
257  {
258  //printf("MERGING\n");
259  unsigned int i = 0;
260  while (i < __dead_spots.size() - 1) {
261  //printf("Comparing %u, %u, %f >= %f, %zu\n", i, i+1,
262  // __dead_spots[i].second, __dead_spots[i+1].first, __dead_spots.size());
263  if (merge_region(i, i+1)) ++i;
264  }
265  // now check for posssible merge of first and last region (at the discontinuity
266  unsigned int last = __dead_spots.size() - 1;
267  if ((__dead_spots[last].second >= __dead_spots[0].first) && (__dead_spots[last].second <= __dead_spots[0].second) &&
268  (__dead_spots[0].first >= __dead_spots[last].first - 360) && (__dead_spots[0].second <= __dead_spots[last].second)) {
269  merge_region(last, 0);
270  }
271  }
272 
273  void
274  apply_margin()
275  {
276  //printf("MARGIN\n");
277  if (__margin != 0.0) {
278  // post-process, add margins, possibly causing regions to be merged
279  // add margins
280  for (unsigned int i = 0; i != __dead_spots.size(); ++i) {
281  //float before_start = __dead_spots[i].first;
282  //float before_end = __dead_spots[i].second;
283  __dead_spots[i].first -= __margin;
284  __dead_spots[i].second += __margin;
285  if (__dead_spots[i].second > 360.0) {
286  __dead_spots[i].second -= 360.0;
287  }
288  //printf("Applying margin to spot %i, [%f, %f] -> [%f, %f]\n",
289  // i, before_start, before_end,
290  // __dead_spots[i].first, __dead_spots[i].second);
291  }
292  // look if regions need to be merged
293  merge_spots();
294  }
295  }
296 
297  void
298  normalize()
299  {
300  //printf("NORMALIZING\n");
301  // normalize
302  for (unsigned int i = 0; i != __dead_spots.size(); ++i) {
303  if (__dead_spots[i].first < 0.) {
304  //printf("Normalizing %i start angle %f -> %f\n", i,
305  // __dead_spots[i].first, 360. + __dead_spots[i].first);
306  __dead_spots[i].first = 360. + __dead_spots[i].first;
307  }
308  if (__dead_spots[i].second < 0.) {
309  //printf("Normalizing %i end angle %f -> %f\n", i,
310  // __dead_spots[i].second, 360. + __dead_spots[i].second);
311  __dead_spots[i].second = 360. + __dead_spots[i].first;
312  }
313 
314  if (__dead_spots[i].first > __dead_spots[i].second) {
315  // range over the discontinuity at 0°/360°, split into two regions
316  //printf("Splitting (size %zu) region %i from [%f, %f] ", __dead_spots.size(), i,
317  // __dead_spots[i].first, __dead_spots[i].second);
318  __dead_spots.resize(__dead_spots.size() + 1);
319  for (int j = __dead_spots.size()-1; j >= (int)i; --j) {
320  __dead_spots[j+1] = __dead_spots[j];
321  }
322  __dead_spots[i+1].first = 0;
323  __dead_spots[i].second = 360.0;
324 
325  //printf("to [%f, %f] and [%f, %f] (size %zu)\n", __dead_spots[i].first, __dead_spots[i].second,
326  // __dead_spots[i+1].first, __dead_spots[i+1].second, __dead_spots.size());
327  }
328  }
329  //print_spots();
330  sort_spots();
331  merge_spots();
332  }
333 
334 
335  void
336  print_spots()
337  {
338  for (unsigned int i = 0; i != __dead_spots.size(); ++i) {
339  printf("Spot %u start: %3.2f end: %3.2f\n", i,
340  __dead_spots[i].first, __dead_spots[i].second);
341  }
342  }
343 
344  void
345  process_measurements()
346  {
347  analyze();
348 
349  if (__dead_spots.size() > 0) {
350  apply_margin();
351  print_spots();
352 
353  __num_spots_found = __dead_spots.size();
354  normalize();
355  } else {
356  __num_spots_found = 0;
357  }
358 
359  if (__num_spots_found != __num_spots_expected) {
360  printf("Error, expected %u dead spots, but detected %u.\n",
361  __num_spots_expected, __num_spots_found);
362  print_spots();
363  } else {
364  printf("Found expected number of %u dead spots\n", __num_spots_expected);
365  if (__dead_spots.size() > __num_spots_expected) {
366  printf("Note that more regions will be printed than spots were expected.\n"
367  "This is due to splitting that occurs around the discontinuity at 0°/360°\n");
368  }
369  if (__num_spots_expected > __dead_spots.size()) {
370  printf("Note that less regions will be printed than spots were expected.\n"
371  "This is due to merging that occurred after applying the margin you\n"
372  "suggested and normalizing the data.\n");
373  }
374  print_spots();
375  }
376  }
377 
378  virtual void
379  bb_interface_data_changed(Interface *interface) throw()
380  {
381  if (! __start_measuring) return;
382 
383  printf("\r%3u samples remaining...", __num_measurements - __cur_measurement);
384  fflush(stdout);
385 
386  float *distances = NULL;
387  unsigned int num_distances = 0;
388  if (__lowres_calibrate) {
389  __laser360->read();
390  distances = __laser360->distances();
391  num_distances = __laser360->maxlenof_distances();
392  } else {
393  __laser720->read();
394  distances = __laser720->distances();
395  num_distances = __laser720->maxlenof_distances();
396  }
397 
398  for (unsigned int i = 0; i < num_distances; ++i) {
399  if (finite(distances[i]) && distances[i] > 1e-6) {
400  __measurements[i][__cur_measurement] = distances[i];
401  }
402  }
403 
404  if (++__cur_measurement >= __num_measurements) {
405  printf("\rMeasuring done, post-processing data now.\n");
406  process_measurements();
407  __blackboard->unregister_listener(this);
408  __finish_waitcond.wake_all();
409  }
410  }
411 
412  private:
413  BlackBoard *__blackboard;
414  Laser360Interface *__laser360;
415  Laser720Interface *__laser720;
416  WaitCondition __finish_waitcond;
417 
418  float __margin;
419  bool __lowres_calibrate;
420  bool __start_measuring;
421  unsigned int __num_spots_expected;
422  unsigned int __num_beams;
423  unsigned int __num_measurements;
424  unsigned int __cur_measurement;
425  unsigned int __num_spots_found;
426  float __compare_distance;
427  std::vector<std::vector<float> > __measurements;
428  std::vector<std::pair<float, float> > __dead_spots;
429 };
430 
431 int
432 main(int argc, char **argv)
433 {
434  ArgumentParser argp(argc, argv, "hr:n:w:c:m:bdi:");
435 
436  if ( argp.has_arg("h") ) {
437  print_usage(argv[0]);
438  exit(0);
439  }
440 
441  char *host = (char *)"localhost";
442  unsigned short int port = FAWKES_TCP_PORT;
443  long int num_measurements = DEFAULT_NUM_MEASUREMENTS;
444  long int wait_time = DEFAULT_WAIT_TIME;
445  float compare_distance = DEFAULT_COMPARE_DISTANCE;
446  float margin = 0;
447  std::string interface_id = "Laser";
448  std::string cfg_prefix = "";
449 
450  if (argp.has_arg("n")) {
451  num_measurements = argp.parse_int("n");
452  if (num_measurements <= 0) {
453  printf("Invalid number of measurements, must be > 0\n\n");
454  print_usage(argp.program_name());
455  return -4;
456  }
457  }
458  if (argp.has_arg("w")) {
459  wait_time = argp.parse_int("w");
460  if (wait_time < 0) {
461  printf("Invalid wait time, must be integer > 0\n\n");
462  print_usage(argp.program_name());
463  return -4;
464  } else if (wait_time > MAX_WAIT_TIME) {
465  printf("Wait time of more than %u seconds are nonsense, aborting.\n\n", MAX_WAIT_TIME);
466  print_usage(argp.program_name());
467  return -4;
468  }
469  }
470  if (argp.has_arg("c")) {
471  compare_distance = argp.parse_float("c");
472  if (compare_distance < 0) {
473  printf("Invalid compare distance, must be > 0\n\n");
474  print_usage(argp.program_name());
475  return -4;
476  }
477  }
478  if (argp.has_arg("m")) {
479  margin = argp.parse_int("m");
480  if ((margin <= -360) || (margin >= 360)) {
481  printf("Invalid margin, must be in the ragen [-359, 359]\n\n");
482  print_usage(argp.program_name());
483  return -4;
484  }
485  }
486  if (argp.num_items() == 0) {
487  printf("Number of expected dead spots not supplied\n\n");
488  print_usage(argp.program_name());
489  return -4;
490  } else if ((argp.num_items() == 1) && ! argp.has_arg("d") ) {
491  printf("Config prefix not given and not dry-run\n\n");
492  print_usage(argp.program_name());
493  return -4;
494  } else if (argp.num_items() > 2) {
495  printf("Too many arguments\n\n");
496  print_usage(argp.program_name());
497  return -4;
498  } else if (argp.num_items() == 2) {
499  cfg_prefix = argp.items()[1];
500  if (cfg_prefix[cfg_prefix.length() - 1] != '/') {
501  cfg_prefix += "/";
502  }
503  }
504 
505  if (argp.has_arg("i")) {
506  interface_id = argp.arg("i");
507  }
508  bool free_host = argp.parse_hostport("r", &host, &port);
509 
510  FawkesNetworkClient *client;
511  BlackBoard *blackboard;
512  NetworkConfiguration *netconf;
513 
514  try {
515  client = new FawkesNetworkClient(host, port);
516  client->connect();
517  blackboard = new RemoteBlackBoard(client);
518  netconf = new NetworkConfiguration(client);
519  } catch (Exception &e) {
520  printf("Failed to connect to remote host at %s:%u\n\n", host, port);
521  e.print_trace();
522  return -1;
523  }
524 
525  if ( free_host ) free(host);
526 
527  Laser360Interface *laser360 = NULL;
528  Laser720Interface *laser720 = NULL;
529  try {
530  laser360 = blackboard->open_for_reading<Laser360Interface>(interface_id.c_str());
531  laser720 = blackboard->open_for_reading<Laser720Interface>(interface_id.c_str());
532  } catch (Exception &e) {
533  printf("Failed to open blackboard interfaces");
534  e.print_trace();
535  //return -2;
536  }
537 
538  if (! laser720->has_writer() && ! laser360->has_writer() ) {
539  printf("No writer for neither high nor low resolution laser.\n"
540  "Laser plugin not loaded?\n\n");
541  blackboard->close(laser360);
542  blackboard->close(laser720);
543  //return -3;
544  }
545 
546  if (! laser720->has_writer()) {
547  printf("Warning: high resolution laser not found calibrating with 1° resolution.\n"
548  " It is recommended to enable the high resolution mode for\n"
549  " calibration. Acquired 1° data may be unsuitable when used in\n"
550  " high resolution mode!\n\n");
551  blackboard->close(laser720);
552  laser720 = NULL;
553  }
554 
555  Time now, start;
556  start.stamp();
557  now.stamp();
558 
559  printf("Position the laser such that it has %f m of free space around it.\n\n"
560  "Also verify that the laser is running with disable filters\n\n", compare_distance);
561  fflush(stdout);
562  float diff = 0;
563  while ((diff = (now - &start)) < wait_time) {
564  printf("\rCalibration will start in %2li sec (Ctrl-C to abort)...", wait_time - (unsigned int)floor(diff));
565  fflush(stdout);
566  usleep(200000);
567  now.stamp();
568  }
569  printf("\rCalibration starting now. \n");
570 
571  unsigned int num_spots = argp.parse_item_int(0);
572 
574  calib = new LaserDeadSpotCalibrator(num_spots, num_measurements, compare_distance, margin,
575  blackboard, laser360, laser720);
576  calib->wait_finished();
577 
578  std::vector<std::pair<float, float> > dead_spots = calib->get_dead_spots();
579 
580  if ( ! argp.has_arg("d") ) {
581  if ( num_spots != calib->num_detected_spots() ) {
582  printf("Number of spots does not match expectation. Not writing to config file.");
583  } else {
584  printf("Storing information in remote config\n");
585 
586  netconf->set_mirror_mode(true);
587 
588  for (unsigned int i = 0; i < 2; ++i) {
589  // do twice, after erasing host specific values there might be default
590  // values
591  Configuration::ValueIterator *vit = netconf->search("/hardware/laser/dead_spots/");
592  while (vit->next()) {
593  //printf("Erasing existing value %s\n", vit->path());
594  if (vit->is_default()) {
595  netconf->erase_default(vit->path());
596  } else {
597  netconf->erase(vit->path());
598  }
599  }
600  delete vit;
601  }
602 
603  for (unsigned int i = 0; i < dead_spots.size(); ++i) {
604  char *prefix;
605  if (asprintf(&prefix, "%s%u/", cfg_prefix.c_str(), i) == -1) {
606  printf("Failed to store dead spot %u, out of memory\n", i);
607  continue;
608  }
609  std::string start_path = std::string(prefix) + "start";
610  std::string end_path = std::string(prefix) + "end";
611  free(prefix);
612  netconf->set_float(start_path.c_str(), dead_spots[i].first);
613  netconf->set_float(end_path.c_str(), dead_spots[i].second);
614  }
615  }
616  }
617 
618  delete calib;
619  delete netconf;
620  blackboard->close(laser360);
621  blackboard->close(laser720);
622 
623  if (argp.has_arg("b")) {
624  Laser720Interface *lcalib = blackboard->open_for_writing<Laser720Interface>("Laser Calibration");
625  for (unsigned int i = 0; i < 720; ++i) {
626  lcalib->set_distances(i, 1.0);
627  }
628  for (unsigned int i = 0; i != dead_spots.size(); ++i) {
629  const unsigned int start = (unsigned int)dead_spots[i].first * 2;
630  unsigned int end = (unsigned int)dead_spots[i].second * 2;
631  if (end == 720) end = 719;
632  //printf("Marking dead %f/%u to %f/%u\n",
633  // dead_spots[i].first, start, dead_spots[i].second, end);
634  for (unsigned int j = start; j <= end; ++j) {
635  lcalib->set_distances(j, 0.0);
636  }
637  }
638  lcalib->write();
639  printf("Storing data in BlackBoard for visualization. Press Ctrl-C to quit.\n");
640  while (1) {
641  usleep(1000000);
642  }
643  }
644 
645  delete blackboard;
646  delete client;
647 
648  return 0;
649 }
Laser360Interface Fawkes BlackBoard Interface.
const char * program_name() const
Get name of program.
Definition: argparser.cpp:502
Wait until a given condition holds.
const char * arg(const char *argn)
Get argument value.
Definition: argparser.cpp:182
bool parse_hostport(const char *argn, char **host, unsigned short int *port)
Parse host:port string.
Definition: argparser.cpp:231
double parse_float(const char *argn)
Parse argument as double.
Definition: argparser.cpp:394
Simple Fawkes network client.
Definition: client.h:52
const std::vector< const char *> & items() const
Get non-option items.
Definition: argparser.cpp:462
virtual void set_float(const char *path, float f)
Set new value in configuration of type float.
Definition: netconf.cpp:751
Fawkes library namespace.
void connect()
Connect to remote.
Definition: client.cpp:417
Parse command line arguments.
Definition: argparser.h:66
A class for handling time.
Definition: time.h:91
virtual bool next()=0
Check if there is another element and advance to this if possible.
void write()
Write from local copy into BlackBoard memory.
Definition: interface.cpp:500
Base class for all Fawkes BlackBoard interfaces.
Definition: interface.h:79
unsigned int num_detected_spots()
Get number of spots.
Definition: deadspots.cpp:145
long int parse_int(const char *argn)
Parse argument as integer.
Definition: argparser.cpp:370
void wait_finished()
Wait for the calibration to be finished.
Definition: deadspots.cpp:126
Calibrator for dead ranges.
Definition: deadspots.cpp:78
std::vector< const char *>::size_type num_items() const
Get number of non-option items.
Definition: argparser.cpp:472
Base class for exceptions in Fawkes.
Definition: exception.h:36
LaserDeadSpotCalibrator(unsigned int num_spots, unsigned int num_measurements, float compare_distance, float margin, BlackBoard *blackboard, Laser360Interface *laser360, Laser720Interface *laser720)
Constructor.
Definition: deadspots.cpp:90
virtual void erase(const char *path)
Erase the given value from the configuration.
Definition: netconf.cpp:941
bool has_writer() const
Check if there is a writer for the interface.
Definition: interface.cpp:834
std::vector< std::pair< float, float > > get_dead_spots()
Get spots.
Definition: deadspots.cpp:136
void set_distances(unsigned int index, const float new_distances)
Set distances value at given index.
virtual void set_mirror_mode(bool mirror)
Enable or disable mirror mode.
Definition: netconf.cpp:1324
virtual const char * path() const =0
Path of value.
void print_trace()
Prints trace to stderr.
Definition: exception.cpp:619
Remote BlackBoard.
Definition: remote.h:48
Iterator interface to iterate over config values.
Definition: config.h:72
virtual Interface * open_for_reading(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for reading.
virtual bool is_default() const =0
Check if current value was read from the default config.
Time & stamp()
Set this time to the current time.
Definition: time.cpp:783
bool has_arg(const char *argn)
Check if argument has been supplied.
Definition: argparser.cpp:169
The BlackBoard abstract class.
Definition: blackboard.h:48
virtual Interface * open_for_writing(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for writing.
ValueIterator * search(const char *path)
Iterator with search results.
Definition: netconf.cpp:1448
Laser720Interface Fawkes BlackBoard Interface.
BlackBoard interface listener.
Remote configuration via Fawkes net.
Definition: netconf.h:49
long int parse_item_int(unsigned int index)
Parse item as integer.
Definition: argparser.cpp:418
virtual void erase_default(const char *path)
Erase the given default value from the configuration.
Definition: netconf.cpp:948
virtual void close(Interface *interface)=0
Close interface.