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