Fawkes API  Fawkes Development Version
navgraph_interactive_thread.cpp
1 /***************************************************************************
2  * navgraph_interactive_thread.cpp - Interactive navgraph editing
3  *
4  * Created: Thu Jan 15 16:26:40 2015
5  * Copyright 2015 Tim Niemueller [www.niemueller.de]
6  ****************************************************************************/
7 
8 /* This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Library General Public License for more details.
17  *
18  * Read the full text in the LICENSE.GPL file in the doc directory.
19  */
20 
21 #include "navgraph_interactive_thread.h"
22 
23 #include <navgraph/yaml_navgraph.h>
24 #include <tf/types.h>
25 
26 #include <interactive_markers/interactive_marker_server.h>
27 
28 using namespace fawkes;
29 using namespace interactive_markers;
30 
31 /** @class NavGraphInteractiveThread "navgraph_interactive_thread.h"
32  * Thread to perform graph-based path planning.
33  * @author Tim Niemueller
34  */
35 
36 /** Constructor. */
38  : Thread("NavGraphInteractiveThread", Thread::OPMODE_WAITFORWAKEUP)
39 {
40 }
41 
42 /** Destructor. */
44 {
45 }
46 
47 
48 void
49 NavGraphInteractiveThread::process_node_ori_feedback
50  (const visualization_msgs::InteractiveMarkerFeedbackConstPtr &feedback,
51  const NodeMenu &menu, visualization_msgs::InteractiveMarker &int_marker)
52 {
53  const std::shared_ptr<MenuHandler> &handler = menu.handler;
54  MenuHandler::EntryHandle entry_handle = (MenuHandler::EntryHandle)feedback->menu_entry_id;
55  MenuHandler::CheckState check_state;
56  if (handler->getCheckState(entry_handle, check_state)) {
57  if (check_state == MenuHandler::UNCHECKED) {
58  visualization_msgs::InteractiveMarkerControl ori_control;
59  ori_control.name = "rot_z";
60  ori_control.orientation.w = 1;
61  ori_control.orientation.x = 0;
62  ori_control.orientation.y = 1;
63  ori_control.orientation.z = 0;
64  ori_control.interaction_mode =
65  visualization_msgs::InteractiveMarkerControl::ROTATE_AXIS;
66  int_marker.controls.push_back(ori_control);
67  handler->setCheckState(entry_handle, MenuHandler::CHECKED);
68 
69  auto control =
70  std::find_if(int_marker.controls.begin(), int_marker.controls.end(),
71  [](const visualization_msgs::InteractiveMarkerControl &c)->bool {
72  return c.name == "menu";
73  });
74  if (control != int_marker.controls.end() && ! control->markers.empty()) {
75  visualization_msgs::Marker &box_marker = control->markers[0];
76  box_marker.type = visualization_msgs::Marker::ARROW;
77  box_marker.points.clear();
78  geometry_msgs::Point p1, p2;
79  p1.x = p1.y = p1.z = 0.;
80  p2.x = 0.2;
81  p2.y = p2.z = 0.;
82  box_marker.points.push_back(p1);
83  box_marker.points.push_back(p2);
84  box_marker.scale.x = 0.35;
85  box_marker.scale.y = 0.35;
86  box_marker.scale.z = 0.2;
87  }
88  } else {
89  int_marker.controls.erase(
90  std::remove_if(int_marker.controls.begin(), int_marker.controls.end(),
91  [](const visualization_msgs::InteractiveMarkerControl &c)->bool {
92  return c.name == "rot_z";
93  }),
94  int_marker.controls.end());
95  handler->setCheckState(entry_handle, MenuHandler::UNCHECKED);
96 
97  auto control =
98  std::find_if(int_marker.controls.begin(), int_marker.controls.end(),
99  [](const visualization_msgs::InteractiveMarkerControl &c)->bool {
100  return c.name == "menu";
101  });
102  if (control != int_marker.controls.end() && ! control->markers.empty()) {
103  visualization_msgs::Marker &box_marker = control->markers[0];
104  box_marker.points.clear();
105  box_marker.type = visualization_msgs::Marker::SPHERE;
106  box_marker.scale.x = 0.25;
107  box_marker.scale.y = 0.25;
108  box_marker.scale.z = 0.25;
109  }
110  }
111  server_->insert(int_marker, boost::bind(&NavGraphInteractiveThread::process_node_feedback, this, _1));
112  server_->applyChanges();
113  handler->reApply(*server_);
114  } else {
115  logger->log_warn(name(), "Got menu feedback for %s/%s, but check state cannot be retrieved",
116  feedback->marker_name.c_str(), feedback->control_name.c_str());
117  }
118 }
119 
120 void
121 NavGraphInteractiveThread::process_node_feedback(const visualization_msgs::InteractiveMarkerFeedbackConstPtr &feedback)
122 {
123  switch ( feedback->event_type )
124  {
125  case visualization_msgs::InteractiveMarkerFeedback::BUTTON_CLICK:
126  break;
127 
128  case visualization_msgs::InteractiveMarkerFeedback::MENU_SELECT:
129  logger->log_debug(name(), "%s/%s: menu item %u clicked",
130  feedback->marker_name.c_str(), feedback->control_name.c_str(),
131  feedback->menu_entry_id);
132  {
133  visualization_msgs::InteractiveMarker int_marker;
134  if (server_->get(feedback->marker_name, int_marker)) {
135  if (node_menus_.find(int_marker.name) != node_menus_.end()) {
136  NodeMenu &menu = node_menus_[int_marker.name];
137  if (feedback->menu_entry_id == menu.ori_handle) {
138  process_node_ori_feedback(feedback, menu, int_marker);
139  } else if (feedback->menu_entry_id == menu.goto_handle) {
140  if (nav_if_->has_writer()) {
142  new NavigatorInterface::PlaceGotoMessage(int_marker.name.c_str());
143  nav_if_->msgq_enqueue(gotomsg);
144  } else {
145  logger->log_error(name(), "Cannot goto %s, no writer for interface",
146  int_marker.name.c_str());
147  }
148  } else if (feedback->menu_entry_id == menu.remove_handle) {
149  navgraph.lock();
150  navgraph->remove_node(feedback->marker_name);
151  navgraph->calc_reachability(true);
152  navgraph.unlock();
153  server_->erase(feedback->marker_name);
154  server_->applyChanges();
155  } else if (menu.undir_connect_nodes.find(feedback->menu_entry_id) != menu.undir_connect_nodes.end()) {
156  std::string to_node = menu.undir_connect_nodes[feedback->menu_entry_id];
157  NavGraphEdge edge(int_marker.name, to_node);
158  navgraph.lock();
159  try {
160  navgraph->add_edge(edge);
161  navgraph->calc_reachability(true);
162  } catch (Exception &e) {
163  navgraph.unlock();
164  logger->log_error(name(), "Failed to insert edge %s--%s as requested, exception follows",
165  int_marker.name.c_str(), to_node.c_str());
166  logger->log_error(name(), e);
167  }
168  server_->erase(int_marker.name);
169  add_node(navgraph->node(int_marker.name), *navgraph);
170  server_->erase(to_node);
171  add_node(navgraph->node(to_node), *navgraph);
172  navgraph.unlock();
173  server_->applyChanges();
174 
175  } else if (menu.dir_connect_nodes.find(feedback->menu_entry_id) != menu.dir_connect_nodes.end()) {
176  NavGraphEdge edge(int_marker.name,
177  menu.dir_connect_nodes[feedback->menu_entry_id]);
178  edge.set_directed(true);
179  navgraph.lock();
180  try {
181  navgraph->add_edge(edge);
182  navgraph->calc_reachability(true);
183  } catch (Exception &e) {
184  navgraph.unlock();
185  logger->log_error(name(), "Failed to insert edge %s->%s as requested, "
186  "exception follows", int_marker.name.c_str(),
187  menu.dir_connect_nodes[feedback->menu_entry_id].c_str());
188  logger->log_error(name(), e);
189  }
190  server_->erase(int_marker.name);
191  add_node(navgraph->node(int_marker.name), *navgraph);
192  navgraph.unlock();
193  server_->applyChanges();
194 
195  } else if (menu.disconnect_nodes.find(feedback->menu_entry_id) != menu.disconnect_nodes.end()) {
196  navgraph.lock();
197  std::string to_node = menu.disconnect_nodes[feedback->menu_entry_id];
198  NavGraphEdge edge = navgraph->edge(feedback->marker_name, to_node);
199  if (! edge) {
200  logger->log_error(name(), "Failed to find edge %s--%s",
201  feedback->marker_name.c_str(), to_node.c_str());
202  }
203  navgraph->remove_edge(edge);
204  navgraph->calc_reachability(true);
205  server_->erase(feedback->marker_name);
206  add_node(navgraph->node(feedback->marker_name), *navgraph);
207  if (! edge.is_directed()) {
208  server_->erase(to_node);
209  add_node(navgraph->node(to_node), *navgraph);
210  }
211  navgraph.unlock();
212  server_->applyChanges();
213  } else {
214  logger->log_warn(name(), "Got menu feedback for %s/%s, but marker not known",
215  feedback->marker_name.c_str(), feedback->control_name.c_str());
216  }
217 
218  } else {
219  logger->log_warn(name(), "Got feedback for %s/%s, but marker not known",
220  feedback->marker_name.c_str(), feedback->control_name.c_str());
221  }
222  }
223  }
224  break;
225 
226  case visualization_msgs::InteractiveMarkerFeedback::POSE_UPDATE:
227  if (feedback->header.frame_id == cfg_global_frame_) {
228  navgraph.lock();
229  NavGraphNode node = navgraph->node(feedback->marker_name);
230  if (node) {
231 
232  if (feedback->control_name == "rot_z") {
233  // orientation update
234  tf::Quaternion q(feedback->pose.orientation.x, feedback->pose.orientation.y,
235  feedback->pose.orientation.z, feedback->pose.orientation.w);
236  node.set_property(navgraph::PROP_ORIENTATION, (float)tf::get_yaw(q));
237  } else {
238  // position update
239  node.set_x(feedback->pose.position.x);
240  node.set_y(feedback->pose.position.y);
241  }
242  navgraph->update_node(node);
243  } else {
244  logger->log_warn(name(), "Position update for %s, but not unknown",
245  feedback->marker_name.c_str());
246  }
247  navgraph.unlock();
248  navgraph->notify_of_change();
249  } else {
250  logger->log_warn(name(), "Interactive marker feedback in non-global frame %s, ignoring",
251  feedback->header.frame_id.c_str());
252  }
253  break;
254 
255  case visualization_msgs::InteractiveMarkerFeedback::MOUSE_DOWN:
256  case visualization_msgs::InteractiveMarkerFeedback::MOUSE_UP:
257  break;
258  }
259 
260  server_->applyChanges();
261 }
262 
263 
264 void
265 NavGraphInteractiveThread::process_graph_feedback(const visualization_msgs::InteractiveMarkerFeedbackConstPtr &feedback)
266 {
267  if (feedback->event_type == visualization_msgs::InteractiveMarkerFeedback::MENU_SELECT) {
268  if (feedback->menu_entry_id == graph_menu_.stop_handle) {
269  if (nav_if_->has_writer()) {
271  nav_if_->msgq_enqueue(stop);
272  } else {
273  logger->log_error(name(), "Cannot stop, no writer for interface");
274  }
275  } else if (feedback->menu_entry_id == graph_menu_.add_handle) {
276  navgraph.lock();
277  for (unsigned int i = 0; i < 1000; ++i) {
278  std::string name = NavGraph::format_name("N%u", i);
279  if (! navgraph->node_exists(name)) {
280  // valid new node name, create node
281  NavGraphNode node(name, 0., 0.);
282  navgraph->add_node(node);
283  add_node(node, *navgraph);
284  navgraph->calc_reachability(true);
285  server_->applyChanges();
286  break;
287  }
288  }
289  navgraph.unlock();
290  } else if (feedback->menu_entry_id == graph_menu_.save_handle) {
291  navgraph.lock();
292  save_yaml_navgraph(cfg_save_filename_, *navgraph);
293  navgraph.unlock();
294  }
295  }
296 }
297 
298 void
300 {
301  cfg_global_frame_ = config->get_string("/navgraph/global_frame");
302  cfg_save_filename_ = config->get_string("/navgraph/interactive/out-file");
303 
304  // create an interactive marker server on the topic namespace simple_marker
305  server_ = new interactive_markers::InteractiveMarkerServer("navgraph_interactive");
306 
307  navgraph.lock();
308  add_graph(*navgraph);
309 
310  const std::vector<NavGraphNode> &nodes = navgraph->nodes();
311  for (const NavGraphNode &node : nodes) {
312  add_node(node, *navgraph);
313  }
314  navgraph.unlock();
315 
316  // 'commit' changes and send to all clients
317  server_->applyChanges();
318 
319  nav_if_ = blackboard->open_for_reading<NavigatorInterface>("Pathplan");
320 }
321 
322 void
324 {
325  node_menus_.clear();
326  graph_menu_handler_.reset();
327  delete server_;
328  blackboard->close(nav_if_);
329 }
330 
331 void
333 {
334 }
335 
336 
337 void
338 NavGraphInteractiveThread::add_node(const NavGraphNode &node, NavGraph *navgraph)
339 {
340  const bool has_ori = node.has_property(navgraph::PROP_ORIENTATION);
341  const tf::Quaternion ori_q = has_ori
342  ? tf::create_quaternion_from_yaw(node.property_as_float(navgraph::PROP_ORIENTATION))
343  : tf::Quaternion(0,0,0,1);
344 
345  // create an interactive marker for our server
346  visualization_msgs::InteractiveMarker int_marker;
347  int_marker.header.frame_id = cfg_global_frame_;
348  int_marker.name = node.name();
349  int_marker.description = ""; //node.name();
350  int_marker.scale = 0.5;
351 
352  int_marker.pose.position.x = node.x();
353  int_marker.pose.position.y = node.y();
354  int_marker.pose.position.z = 0.;
355  if (has_ori) {
356  int_marker.pose.orientation.x = ori_q[0];
357  int_marker.pose.orientation.y = ori_q[1];
358  int_marker.pose.orientation.z = ori_q[2];
359  int_marker.pose.orientation.w = ori_q[3];
360  } else {
361  int_marker.pose.orientation.x = int_marker.pose.orientation.y = int_marker.pose.orientation.z = 0.;
362  int_marker.pose.orientation.w = 1.;
363  }
364 
365  // create a grey box marker
366  visualization_msgs::Marker box_marker;
367  if (has_ori) {
368  box_marker.type = visualization_msgs::Marker::ARROW;
369  geometry_msgs::Point p1, p2;
370  p1.x = p1.y = p1.z = 0.;
371  p2.x = 0.2;
372  p2.y = p2.z = 0.;
373  box_marker.points.push_back(p1);
374  box_marker.points.push_back(p2);
375  box_marker.scale.x = 0.35;
376  box_marker.scale.y = 0.35;
377  box_marker.scale.z = 0.2;
378 
379  } else {
380  box_marker.type = visualization_msgs::Marker::SPHERE;
381  box_marker.scale.x = 0.25;
382  box_marker.scale.y = 0.25;
383  box_marker.scale.z = 0.25;
384  }
385  box_marker.color.r = 0.5;
386  box_marker.color.g = 0.5;
387  box_marker.color.b = 0.5;
388  box_marker.color.a = 1.0;
389 
390  // create a non-interactive control which contains the box
391  visualization_msgs::InteractiveMarkerControl box_control;
392  box_control.always_visible = true;
393  box_control.markers.push_back(box_marker);
394  box_control.interaction_mode = visualization_msgs::InteractiveMarkerControl::MENU;
395  box_control.description="Options";
396  box_control.name="menu";
397  int_marker.controls.push_back(box_control);
398 
399  NodeMenu menu;
400  menu.handler = std::shared_ptr<MenuHandler>(new MenuHandler());
401  menu.ori_handle =
402  menu.handler->insert("Orientation", boost::bind(&NavGraphInteractiveThread::process_node_feedback, this, _1));
403  menu.goto_handle =
404  menu.handler->insert("Go to", boost::bind(&NavGraphInteractiveThread::process_node_feedback, this, _1));
405  menu.handler->setCheckState(menu.ori_handle, MenuHandler::UNCHECKED);
406  const std::vector<NavGraphNode> &nodes = navgraph->nodes();
407  const std::vector<NavGraphEdge> &edges = navgraph->edges();
408  MenuHandler::EntryHandle connect_undir_menu_handle = menu.handler->insert("Connect with");
409  MenuHandler::EntryHandle connect_dir_menu_handle = menu.handler->insert("Connect directed");
410  MenuHandler::EntryHandle disconnect_menu_handle = menu.handler->insert("Disconnect from");
411  std::for_each(nodes.begin(), nodes.end(),
412  [&, this](const NavGraphNode &n)->void {
413  if (n.name() != node.name()) {
414  auto edge = std::find_if(edges.begin(), edges.end(),
415  [&n, &node](const NavGraphEdge &e)->bool {
416  return
417  (e.from() == node.name() &&
418  e.to() == n.name()) ||
419  (! e.is_directed() &&
420  e.from() == n.name() &&
421  e.to() == node.name());
422  });
423  if (edge == edges.end()) {
424  MenuHandler::EntryHandle undir_handle =
425  menu.handler->insert(connect_undir_menu_handle, n.name(),
426  boost::bind(&NavGraphInteractiveThread::process_node_feedback, this, _1));
427  menu.undir_connect_nodes[undir_handle] = n.name();
428 
429  MenuHandler::EntryHandle dir_handle =
430  menu.handler->insert(connect_dir_menu_handle, n.name(),
431  boost::bind(&NavGraphInteractiveThread::process_node_feedback, this, _1));
432  menu.dir_connect_nodes[dir_handle] = n.name();
433  } else {
434  MenuHandler::EntryHandle handle =
435  menu.handler->insert(disconnect_menu_handle, n.name(),
436  boost::bind(&NavGraphInteractiveThread::process_node_feedback, this, _1));
437  menu.disconnect_nodes[handle] = n.name();
438  }
439  }
440  });
441 
442  MenuHandler::EntryHandle properties_menu_handle = menu.handler->insert("Properties");
443  for (const auto &p : node.properties()) {
444  std::string p_s = p.first + ": " + p.second;
445  menu.handler->insert(properties_menu_handle, p_s);
446  }
447 
448  menu.remove_handle =
449  menu.handler->insert("Remove Node",
450  boost::bind(&NavGraphInteractiveThread::process_node_feedback,
451  this, _1));
452 
453  // create a control which will move the box
454  // this control does not contain any markers,
455  // which will cause RViz to insert two arrows
456  visualization_msgs::InteractiveMarkerControl pos_control;
457  pos_control.orientation_mode =
458  visualization_msgs::InteractiveMarkerControl::FIXED;
459  pos_control.interaction_mode =
460  visualization_msgs::InteractiveMarkerControl::MOVE_AXIS;
461 
462  pos_control.name = "move_x";
463  pos_control.orientation.x = 0.;
464  pos_control.orientation.y = 0.;
465  pos_control.orientation.z = 0.;
466  pos_control.orientation.w = 1.;
467  int_marker.controls.push_back(pos_control);
468 
469  pos_control.name = "move_y";
470  pos_control.orientation.x = 0.;
471  pos_control.orientation.y = 0.;
472  pos_control.orientation.z = 1.;
473  pos_control.orientation.w = 1.;
474  int_marker.controls.push_back(pos_control);
475 
476  if (has_ori) {
477  visualization_msgs::InteractiveMarkerControl ori_control;
478  ori_control.name = "rot_z";
479  ori_control.orientation.w = 1;
480  ori_control.orientation.x = 0;
481  ori_control.orientation.y = 1;
482  ori_control.orientation.z = 0;
483  ori_control.interaction_mode =
484  visualization_msgs::InteractiveMarkerControl::ROTATE_AXIS;
485  int_marker.controls.push_back(ori_control);
486  menu.handler->setCheckState(menu.ori_handle, MenuHandler::CHECKED);
487  }
488 
489  server_->insert(int_marker, boost::bind(&NavGraphInteractiveThread::process_node_feedback, this, _1));
490 
491  menu.handler->apply(*server_, int_marker.name);
492  node_menus_[int_marker.name] = menu;
493 }
494 
495 
496 void
497 NavGraphInteractiveThread::add_graph(NavGraph *navgraph)
498 {
499  // create an interactive marker for our server
500  visualization_msgs::InteractiveMarker int_marker;
501  int_marker.header.frame_id = cfg_global_frame_;
502  int_marker.name = navgraph->name();
503  int_marker.description = "";
504  int_marker.scale = 0.5;
505 
506  int_marker.pose.position.x = 0.;
507  int_marker.pose.position.y = 0.;
508  int_marker.pose.position.z = 1.;
509  int_marker.pose.orientation.x = int_marker.pose.orientation.y = int_marker.pose.orientation.z = 0.;
510  int_marker.pose.orientation.w = 1.;
511 
512  // create a grey box marker
513  visualization_msgs::Marker box_marker;
514  box_marker.type = visualization_msgs::Marker::CUBE;
515  box_marker.scale.x = 0.25;
516  box_marker.scale.y = 0.25;
517  box_marker.scale.z = 0.25;
518  box_marker.color.r = 0.5;
519  box_marker.color.g = 0.5;
520  box_marker.color.b = 0.5;
521  box_marker.color.a = 1.0;
522 
523  // create a non-interactive control which contains the box
524  visualization_msgs::InteractiveMarkerControl box_control;
525  box_control.always_visible = true;
526  box_control.markers.push_back(box_marker);
527  box_control.interaction_mode = visualization_msgs::InteractiveMarkerControl::MENU;
528  box_control.description="Graph Ops";
529  box_control.name="menu";
530  int_marker.controls.push_back(box_control);
531 
532  std::shared_ptr<MenuHandler> menu_handler(new MenuHandler());
533  graph_menu_.add_handle =
534  menu_handler->insert("Add Node",
535  boost::bind(&NavGraphInteractiveThread::process_graph_feedback,
536  this, _1));
537  graph_menu_.save_handle =
538  menu_handler->insert("Save Graph",
539  boost::bind(&NavGraphInteractiveThread::process_graph_feedback,
540  this, _1));
541 
542  graph_menu_.stop_handle =
543  menu_handler->insert("STOP",
544  boost::bind(&NavGraphInteractiveThread::process_graph_feedback,
545  this, _1));
546 
547  graph_menu_handler_ = menu_handler;
548 
549  server_->insert(int_marker,
550  boost::bind(&NavGraphInteractiveThread::process_graph_feedback, this, _1));
551 
552  menu_handler->apply(*server_, int_marker.name);
553 }
virtual ~NavGraphInteractiveThread()
Destructor.
fawkes::LockPtr< NavGraph > navgraph
NavGraph instance shared in framework.
Definition: navgraph.h:46
virtual void init()
Initialize the thread.
Fawkes library namespace.
Topological map graph.
Definition: navgraph.h:57
bool is_directed() const
Check if edge is directed.
void save_yaml_navgraph(std::string filename, NavGraph *graph)
Save navgraph to YAML file.
void set_y(float y)
Set Y position.
bool has_property(const std::string &property) const
Check if node has specified property.
Definition: navgraph_node.h:95
Thread class encapsulation of pthreads.
Definition: thread.h:42
Logger * logger
This is the Logger member used to access the logger.
Definition: logging.h:44
const std::vector< NavGraphNode > & nodes() const
Get nodes of the graph.
Definition: navgraph.cpp:124
const std::map< std::string, std::string > & properties() const
Get all properties.
Definition: navgraph_node.h:88
std::string name() const
Get graph name.
Definition: navgraph.cpp:114
PlaceGotoMessage Fawkes BlackBoard Interface Message.
virtual void loop()
Code to execute in the thread.
Base class for exceptions in Fawkes.
Definition: exception.h:36
void set_property(const std::string &property, const std::string &value)
Set property.
const std::string & name() const
Get name of node.
Definition: navgraph_node.h:49
bool has_writer() const
Check if there is a writer for the interface.
Definition: interface.cpp:834
void set_directed(bool directed)
Set directed state.
const char * name() const
Get name of thread.
Definition: thread.h:95
const std::vector< NavGraphEdge > & edges() const
Get edges of the graph.
Definition: navgraph.cpp:134
virtual void log_warn(const char *component, const char *format,...)=0
Log warning message.
virtual void log_error(const char *component, const char *format,...)=0
Log error message.
float y() const
Get Y coordinate in global frame.
Definition: navgraph_node.h:59
virtual void finalize()
Finalize the thread.
unsigned int msgq_enqueue(Message *message)
Enqueue message at end of queue.
Definition: interface.cpp:903
void set_x(float x)
Set X position.
Topological graph edge.
Definition: navgraph_edge.h:39
Topological graph node.
Definition: navgraph_node.h:38
virtual void log_debug(const char *component, const char *format,...)=0
Log debug message.
virtual Interface * open_for_reading(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for reading.
float x() const
Get X coordinate in global frame.
Definition: navgraph_node.h:54
float property_as_float(const std::string &prop) const
Get property converted to float.
Configuration * config
This is the Configuration member used to access the configuration.
Definition: configurable.h:44
virtual std::string get_string(const char *path)=0
Get value from configuration which is of type string.
BlackBoard * blackboard
This is the BlackBoard instance you can use to interact with the BlackBoard.
Definition: blackboard.h:44
StopMessage Fawkes BlackBoard Interface Message.
NavigatorInterface Fawkes BlackBoard Interface.
virtual void close(Interface *interface)=0
Close interface.