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
50using namespace fawkes;
51
52void
53print_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{
81public:
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
154private:
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_refreshed(Interface *interface) noexcept
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
421private:
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
440int
441main(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
void wait_finished()
Wait for the calibration to be finished.
Definition: deadspots.cpp:130
std::vector< std::pair< float, float > > get_dead_spots()
Get spots.
Definition: deadspots.cpp:140
unsigned int num_detected_spots()
Get number of spots.
Definition: deadspots.cpp:149
Parse command line arguments.
Definition: argparser.h:64
BlackBoard interface listener.
void bbil_add_data_interface(Interface *interface)
Add an interface to the data modification watch list.
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 void unregister_listener(BlackBoardInterfaceListener *listener)
Unregister BB interface listener.
Definition: blackboard.cpp:212
virtual Interface * open_for_writing(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for writing.
virtual void register_listener(BlackBoardInterfaceListener *listener, ListenerRegisterFlag flag=BBIL_FLAG_ALL)
Register BB event listener.
Definition: blackboard.cpp:185
virtual void close(Interface *interface)=0
Close interface.
Iterator interface to iterate over config values.
Definition: config.h:75
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() noexcept
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:80
void write()
Write from local copy into BlackBoard memory.
Definition: interface.cpp:501
void read()
Read from BlackBoard into local copy.
Definition: interface.cpp:479
bool has_writer() const
Check if there is a writer for the interface.
Definition: interface.cpp:848
Laser360Interface Fawkes BlackBoard Interface.
float * distances() const
Get distances value.
size_t maxlenof_distances() const
Get maximum length of distances value.
Laser720Interface Fawkes BlackBoard Interface.
void set_distances(unsigned int index, const float new_distances)
Set distances value at given index.
float * distances() const
Get distances value.
size_t maxlenof_distances() const
Get maximum length of distances value.
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:50
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.
void wait()
Wait for the condition forever.
void wake_all()
Wake up all waiting threads.
Fawkes library namespace.