[Fawkes Git] branch/fzwilling/robot-memory: 3 revs updated. (0.5.0-3445-g903a772)

Frederik Zwilling zwilling at kbsg.rwth-aachen.de
Wed Nov 23 21:28:05 CET 2016


Changes have been pushed for the project "Fawkes Robotics Software Framework".

Gitweb: http://git.fawkesrobotics.org/fawkes.git
Trac:   http://trac.fawkesrobotics.org

The branch, fzwilling/robot-memory has been updated
        to  903a772eb9e57c66896d10b79d77348702884a71 (commit)
       via  e570dcea0de2b155604638f626ff724d523a58a4 (commit)
       via  2a80e6e1514bb310afc31fdaf2a6c8fc90b07042 (commit)
      from  c909ed2f6a3ada8913d2b8eba7359de2b97ab122 (commit)

http://git.fawkesrobotics.org/fawkes.git/fzwilling/robot-memory

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- *Log* ---------------------------------------------------------------
commit 2a80e6e1514bb310afc31fdaf2a6c8fc90b07042
Author:     Frederik Zwilling <zwilling at kbsg.rwth-aachen.de>
AuthorDate: Wed Nov 23 15:26:25 2016 +0100
Commit:     Frederik Zwilling <zwilling at kbsg.rwth-aachen.de>
CommitDate: Wed Nov 23 21:27:48 2016 +0100

    robot-memory: function to insert vector of documents

http://git.fawkesrobotics.org/fawkes.git/commit/2a80e6e
http://trac.fawkesrobotics.org/changeset/2a80e6e

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
commit e570dcea0de2b155604638f626ff724d523a58a4
Author:     Frederik Zwilling <zwilling at kbsg.rwth-aachen.de>
AuthorDate: Wed Nov 23 15:27:15 2016 +0100
Commit:     Frederik Zwilling <zwilling at kbsg.rwth-aachen.de>
CommitDate: Wed Nov 23 21:27:54 2016 +0100

    robot-memory: Use RM instead of mongo client in computable_manager
    
    The DBClientConnection is not thread safe. Thus we now use the robot
    memory functions to access the database in the computable manager,
    because they already include mutex locks.

http://git.fawkesrobotics.org/fawkes.git/commit/e570dce
http://trac.fawkesrobotics.org/changeset/e570dce

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
commit 903a772eb9e57c66896d10b79d77348702884a71
Author:     Frederik Zwilling <zwilling at kbsg.rwth-aachen.de>
AuthorDate: Wed Nov 23 21:20:50 2016 +0100
Commit:     Frederik Zwilling <zwilling at kbsg.rwth-aachen.de>
CommitDate: Wed Nov 23 21:28:01 2016 +0100

    robot-memory: caching computables
    
    A computable now can cache computed documents. During the caching time
    these documents stay in the robot memory and the same query given a
    second time does not invoke the computation again. After the caching
    time, computed documents are removed.

http://git.fawkesrobotics.org/fawkes.git/commit/903a772
http://trac.fawkesrobotics.org/changeset/903a772

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


- *Summary* -----------------------------------------------------------
 .../robot-memory/computables/computable.cpp        |   11 ++++-
 src/plugins/robot-memory/computables/computable.h  |    3 +-
 .../computables/computables_manager.cpp            |   54 ++++++++++++++------
 .../robot-memory/computables/computables_manager.h |   16 ++++--
 .../computables/transform_computable.cpp           |   11 ++---
 src/plugins/robot-memory/robot_memory.cpp          |   39 +++++++++++++-
 src/plugins/robot-memory/robot_memory.h            |    6 ++-
 7 files changed, 106 insertions(+), 34 deletions(-)


- *Diffs* -------------------------------------------------------------

- *commit* 2a80e6e1514bb310afc31fdaf2a6c8fc90b07042 - - - - - - - - - -
Author:  Frederik Zwilling <zwilling at kbsg.rwth-aachen.de>
Date:    Wed Nov 23 15:26:25 2016 +0100
Subject: robot-memory: function to insert vector of documents

 src/plugins/robot-memory/robot_memory.cpp |   37 ++++++++++++++++++++++++++++-
 src/plugins/robot-memory/robot_memory.h   |    2 +
 2 files changed, 38 insertions(+), 1 deletions(-)

_Diff for modified files_:
diff --git a/src/plugins/robot-memory/robot_memory.cpp b/src/plugins/robot-memory/robot_memory.cpp
index 62585cc..ccbfe0c 100644
--- a/src/plugins/robot-memory/robot_memory.cpp
+++ b/src/plugins/robot-memory/robot_memory.cpp
@@ -150,7 +150,7 @@ int RobotMemory::insert(BSONObj obj, std::string collection)
 {
   check_collection_name(collection);
 
-  log_deb(std::string("Executing Query "+ obj.toString() + " on collection " + collection));
+  log_deb(std::string("Inserting "+ obj.toString() + " into collection " + collection));
 
   //lock (mongo_client not thread safe)
   MutexLocker lock(mutex_);
@@ -169,6 +169,41 @@ int RobotMemory::insert(BSONObj obj, std::string collection)
 }
 
 /**
+ * Inserts all document of a vector into the robot memory
+ * @param v_obj The vector of BSONObj document
+ * @param collection The database and collection to use as string (e.g. robmem.worldmodel)
+ * @return 1: Success 0: Error
+ */
+int RobotMemory::insert(std::vector<BSONObj> v_obj, std::string collection)
+{
+  check_collection_name(collection);
+
+  std::string insert_string = "[";
+  for(BSONObj obj : v_obj)
+  {
+    insert_string += obj.toString() + ",\n";
+  }
+  insert_string += "]";
+
+  log_deb(std::string("Inserting vector of documents " + insert_string+  " into collection " + collection));
+
+  //lock (mongo_client not thread safe)
+  MutexLocker lock(mutex_);
+
+  //actually execute insert
+  try{
+    mongodb_client_->insert(collection, v_obj);
+  } catch (DBException &e) {
+    std::string error = "Error for insert " + insert_string
+        + "\n Exception: " + e.toString();
+    log_deb(error, "error");
+    return 0;
+  }
+  //return success
+  return 1;
+}
+
+/**
  * Inserts a document into the robot memory
  * @param obj_str The document as json string
  * @param collection The database and collection to use as string (e.g. robmem.worldmodel)
diff --git a/src/plugins/robot-memory/robot_memory.h b/src/plugins/robot-memory/robot_memory.h
index a701b57..441ca99 100644
--- a/src/plugins/robot-memory/robot_memory.h
+++ b/src/plugins/robot-memory/robot_memory.h
@@ -26,6 +26,7 @@
 #include <aspect/logging.h>
 #include <aspect/blackboard.h>
 #include <memory>
+#include <vector>
 
 #include <mongo/client/dbclient.h>
 #include "interfaces/RobotMemoryInterface.h"
@@ -53,6 +54,7 @@ class RobotMemory
     //robot memory functions
     QResCursor query(mongo::Query query, std::string collection = "");
     int insert(mongo::BSONObj obj, std::string collection = "");
+    int insert(std::vector<mongo::BSONObj> v_obj, std::string collection = "");
     int insert(std::string obj_str, std::string collection = "");
     int update(mongo::Query query, mongo::BSONObj update, std::string collection = "", bool upsert = false);
     int update(mongo::Query query, std::string update_str, std::string collection = "", bool upsert = false);

- *commit* e570dcea0de2b155604638f626ff724d523a58a4 - - - - - - - - - -
Author:  Frederik Zwilling <zwilling at kbsg.rwth-aachen.de>
Date:    Wed Nov 23 15:27:15 2016 +0100
Subject: robot-memory: Use RM instead of mongo client in computable_manager

 .../computables/computables_manager.cpp            |   18 ++++++++++--------
 .../robot-memory/computables/computables_manager.h |    7 +++++--
 src/plugins/robot-memory/robot_memory.cpp          |    2 +-
 3 files changed, 16 insertions(+), 11 deletions(-)

_Diff for modified files_:
diff --git a/src/plugins/robot-memory/computables/computables_manager.cpp b/src/plugins/robot-memory/computables/computables_manager.cpp
index da8189c..391ad69 100644
--- a/src/plugins/robot-memory/computables/computables_manager.cpp
+++ b/src/plugins/robot-memory/computables/computables_manager.cpp
@@ -21,6 +21,7 @@
 
 #include "computables_manager.h"
 #include <core/exception.h>
+#include <plugins/robot-memory/robot_memory.h>
 
 /** @class ComputablesManager  computables_manager.h
  *  This class manages registering computables and can check
@@ -32,11 +33,11 @@ using namespace fawkes;
 using namespace mongo;
 
 ComputablesManager::ComputablesManager(fawkes::Logger* logger, fawkes::Configuration* config,
-  mongo::DBClientBase* mongodb_client, fawkes::Clock* clock)
+  RobotMemory* robot_memory, fawkes::Clock* clock)
 {
   logger_ = logger;
   config_ = config;
-  mongodb_client_ = mongodb_client;
+  robot_memory_ = robot_memory;
   clock_ = clock;
 
   matching_test_collection_ = "robmem.computables_matching";
@@ -77,15 +78,16 @@ void ComputablesManager::remove_computable(Computable* computable)
  */
 bool ComputablesManager::check_and_compute(mongo::Query query, std::string collection)
 {
-  //logger_->log_info(name.c_str(), "checking query: %s", query.toString().c_str());
+  if(collection == matching_test_collection_)
+    return false; //not necessary for matching test itself
   bool added_computed_docs = false;
   //check if the query is matched by the computable identifyer
   //to do that we just insert the query as if it would be a document and query for it with the computable identifiers
-  mongodb_client_->dropCollection(matching_test_collection_);
-  mongodb_client_->insert(matching_test_collection_, query.obj);
+  robot_memory_->remove(fromjson("{}"), matching_test_collection_);
+  robot_memory_->insert(query.obj, matching_test_collection_);
   for(std::list<Computable*>::iterator it = computables.begin(); it != computables.end(); it++)
   {
-    if(collection == (*it)->get_collection() &&  mongodb_client_->query(matching_test_collection_, (*it)->get_query())->more())
+    if(collection == (*it)->get_collection() &&  robot_memory_->query((*it)->get_query(), matching_test_collection_)->more())
     {
       std::list<BSONObj> computed_docs_list = (*it)->compute(query.obj);
       if(computed_docs_list.size() > 0)
@@ -93,7 +95,7 @@ bool ComputablesManager::check_and_compute(mongo::Query query, std::string colle
         //move list into vector
         std::vector<BSONObj> computed_docs_vector{ std::make_move_iterator(std::begin(computed_docs_list)),
           std::make_move_iterator(std::end(computed_docs_list))};
-        mongodb_client_->insert((*it)->get_collection(), computed_docs_vector);
+        robot_memory_->insert(computed_docs_vector, (*it)->get_collection());
         added_computed_docs = true;
       }
     }
@@ -112,7 +114,7 @@ void ComputablesManager::cleanup_computed_docs()
 {
   for(std::string collection : collections_to_cleanup)
   {
-    mongodb_client_->remove(collection, fromjson("{'_robmem_info.computed':true}"));
+    robot_memory_->remove(fromjson("{'_robmem_info.computed':true}"), collection);
   }
   collections_to_cleanup.clear();
 }
diff --git a/src/plugins/robot-memory/computables/computables_manager.h b/src/plugins/robot-memory/computables/computables_manager.h
index 9e73945..c741a7c 100644
--- a/src/plugins/robot-memory/computables/computables_manager.h
+++ b/src/plugins/robot-memory/computables/computables_manager.h
@@ -30,11 +30,14 @@
 #include <boost/bind.hpp>
 #include <utility>
 
+//forward declaration
+class RobotMemory;
+
 class ComputablesManager
 {
   public:
     ComputablesManager(fawkes::Logger* logger, fawkes::Configuration* config,
-      mongo::DBClientBase* mongodb_client, fawkes::Clock* clock);
+      RobotMemory* robot_memory, fawkes::Clock* clock);
     virtual ~ComputablesManager();
 
     bool check_and_compute(mongo::Query query, std::string collection);
@@ -62,7 +65,7 @@ class ComputablesManager
     std::string name = "RobotMemory ComputablesManager";
     fawkes::Logger* logger_;
     fawkes::Configuration* config_;
-    mongo::DBClientBase* mongodb_client_;
+    RobotMemory* robot_memory_;
     fawkes::Clock* clock_;
 
     std::list<Computable*> computables;
diff --git a/src/plugins/robot-memory/robot_memory.cpp b/src/plugins/robot-memory/robot_memory.cpp
index ccbfe0c..d55bc79 100644
--- a/src/plugins/robot-memory/robot_memory.cpp
+++ b/src/plugins/robot-memory/robot_memory.cpp
@@ -96,7 +96,7 @@ void RobotMemory::init()
 
   //Setup event trigger and computables manager
   trigger_manager_ = new EventTriggerManager(logger_, config_);
-  computables_manager_ = new ComputablesManager(logger_, config_, mongodb_client_, clock_);
+  computables_manager_ = new ComputablesManager(logger_, config_, this, clock_);
 
   log_deb("Initialized RobotMemory");
 }

- *commit* 903a772eb9e57c66896d10b79d77348702884a71 - - - - - - - - - -
Author:  Frederik Zwilling <zwilling at kbsg.rwth-aachen.de>
Date:    Wed Nov 23 21:20:50 2016 +0100
Subject: robot-memory: caching computables

 .../robot-memory/computables/computable.cpp        |   11 +++++-
 src/plugins/robot-memory/computables/computable.h  |    3 +-
 .../computables/computables_manager.cpp            |   38 +++++++++++++++-----
 .../robot-memory/computables/computables_manager.h |    9 +++--
 .../computables/transform_computable.cpp           |   11 ++----
 src/plugins/robot-memory/robot_memory.h            |    4 +-
 6 files changed, 53 insertions(+), 23 deletions(-)

_Diff for modified files_:
diff --git a/src/plugins/robot-memory/computables/computable.cpp b/src/plugins/robot-memory/computables/computable.cpp
index 592b45d..b8ac359 100644
--- a/src/plugins/robot-memory/computables/computable.cpp
+++ b/src/plugins/robot-memory/computables/computable.cpp
@@ -20,19 +20,23 @@
  */
 
 #include "computable.h"
+#include <chrono>
 
 using namespace mongo;
 
 /** @class Computable  computable.h
  * Class holding information for a single computable
+ * this class also enhances computed documents by additional information, such as the caching time
  * @author Frederik Zwilling
  */
 
-Computable::Computable(Query query_to_compute, std::string collection, const boost::function<std::list<BSONObj> (BSONObj, std::string)> &compute_function)
+Computable::Computable(Query query_to_compute, std::string collection, const boost::function<std::list<BSONObj> (BSONObj, std::string)> &compute_function, double caching_time)
 {
   this->compute_function = compute_function;
   this->query_to_compute = query_to_compute;
   this->collection = collection;
+  //convert caching time to milliseconds
+  this->caching_time = (int) (caching_time * 1000.0);
 }
 
 Computable::~Computable()
@@ -49,11 +53,16 @@ std::list<BSONObj> Computable::compute(BSONObj query)
 {
   // use provided function to compute demanded documents
   std::list<BSONObj> docs = compute_function(query, collection);
+  long long milliseconds_since_epoch =
+      std::chrono::system_clock::now().time_since_epoch() /
+      std::chrono::milliseconds(1);
+  long long cached_until = milliseconds_since_epoch + caching_time;
   //add metainformation for each document
   for(BSONObj &obj : docs)
   {
     BSONObjBuilder info_b;
     info_b.append("computed", true);
+    info_b.append("cached_until", cached_until);
     BSONObjBuilder obj_b;
     obj_b.appendElements(obj);
     obj_b.append("_robmem_info", info_b.obj());
diff --git a/src/plugins/robot-memory/computables/computable.h b/src/plugins/robot-memory/computables/computable.h
index a15f474..1783367 100644
--- a/src/plugins/robot-memory/computables/computable.h
+++ b/src/plugins/robot-memory/computables/computable.h
@@ -28,7 +28,7 @@
 class Computable
 {
   public:
-    Computable(mongo::Query query_to_compute, std::string collection, const boost::function<std::list<mongo::BSONObj> (mongo::BSONObj, std::string)> &compute_function);
+    Computable(mongo::Query query_to_compute, std::string collection, const boost::function<std::list<mongo::BSONObj> (mongo::BSONObj, std::string)> &compute_function, double caching_time = 0.0);
     virtual ~Computable();
 
     std::list<mongo::BSONObj> compute(mongo::BSONObj query);
@@ -39,6 +39,7 @@ class Computable
     boost::function<std::list<mongo::BSONObj> (mongo::BSONObj, std::string)> compute_function;
     mongo::Query query_to_compute;
     std::string collection;
+    int caching_time; //in milliseconds
 };
 
 #endif /* FAWKES_SRC_PLUGINS_ROBOT_MEMORY_COMPUTABLE_H_ */
diff --git a/src/plugins/robot-memory/computables/computables_manager.cpp b/src/plugins/robot-memory/computables/computables_manager.cpp
index 391ad69..4e2f21e 100644
--- a/src/plugins/robot-memory/computables/computables_manager.cpp
+++ b/src/plugins/robot-memory/computables/computables_manager.cpp
@@ -22,6 +22,7 @@
 #include "computables_manager.h"
 #include <core/exception.h>
 #include <plugins/robot-memory/robot_memory.h>
+#include <chrono>
 
 /** @class ComputablesManager  computables_manager.h
  *  This class manages registering computables and can check
@@ -78,6 +79,16 @@ void ComputablesManager::remove_computable(Computable* computable)
  */
 bool ComputablesManager::check_and_compute(mongo::Query query, std::string collection)
 {
+  //check if computation result of the query is already cached
+  for(std::map<std::tuple<std::string, std::string>, long long>::iterator it = cached_querries_.begin();
+      it != cached_querries_.end(); it++)
+  {
+    if(collection == std::get<0>(it->first) && query.toString() == std::get<1>(it->first))
+    {
+      logger_->log_info(name.c_str(), "Already computed");
+      return false;
+    }
+  }
   if(collection == matching_test_collection_)
     return false; //not necessary for matching test itself
   bool added_computed_docs = false;
@@ -95,15 +106,15 @@ bool ComputablesManager::check_and_compute(mongo::Query query, std::string colle
         //move list into vector
         std::vector<BSONObj> computed_docs_vector{ std::make_move_iterator(std::begin(computed_docs_list)),
           std::make_move_iterator(std::end(computed_docs_list))};
+        //remember how long a query is cached:
+        long long cached_until = computed_docs_vector[0].getField("_robmem_info").Obj().getField("cached_until").Long();
+        cached_querries_[std::make_tuple(collection, query.toString())] = cached_until;
+        //TODO: fix problem: equivalent queries in different order jield unequal strings
         robot_memory_->insert(computed_docs_vector, (*it)->get_collection());
         added_computed_docs = true;
       }
     }
   }
-  if(added_computed_docs)
-  {
-    collections_to_cleanup.push_back(collection);
-  }
   return added_computed_docs;
 }
 
@@ -112,9 +123,18 @@ bool ComputablesManager::check_and_compute(mongo::Query query, std::string colle
  */
 void ComputablesManager::cleanup_computed_docs()
 {
-  for(std::string collection : collections_to_cleanup)
-  {
-    robot_memory_->remove(fromjson("{'_robmem_info.computed':true}"), collection);
-  }
-  collections_to_cleanup.clear();
+  long long current_time_ms =
+          std::chrono::system_clock::now().time_since_epoch() /
+          std::chrono::milliseconds(1);
+  for(std::map<std::tuple<std::string, std::string>, long long>::iterator it = cached_querries_.begin();
+        it != cached_querries_.end(); it++)
+    {
+      if(current_time_ms > it->second)
+      {
+        logger_->log_info(name.c_str(), "Removing cache %s", std::get<0>(it->first).c_str());
+        robot_memory_->remove(BSON("_robmem_info.computed" << true
+            << "_robmem_info.cached_until" << BSON("$lt" << current_time_ms)), std::get<0>(it->first));
+        cached_querries_.erase(it->first);
+      }
+    }
 }
diff --git a/src/plugins/robot-memory/computables/computables_manager.h b/src/plugins/robot-memory/computables/computables_manager.h
index c741a7c..c4edb8b 100644
--- a/src/plugins/robot-memory/computables/computables_manager.h
+++ b/src/plugins/robot-memory/computables/computables_manager.h
@@ -29,6 +29,8 @@
 #include "computable.h"
 #include <boost/bind.hpp>
 #include <utility>
+#include <map>
+#include <tuple>
 
 //forward declaration
 class RobotMemory;
@@ -54,9 +56,9 @@ class ComputablesManager
      * @return Computable Object pointer used for removing it
      */
     template<typename T>
-    Computable* register_computable(mongo::Query query_to_compute, std::string collection, std::list<mongo::BSONObj>(T::*compute_func)(mongo::BSONObj, std::string), T *obj)
+    Computable* register_computable(mongo::Query query_to_compute, std::string collection, std::list<mongo::BSONObj>(T::*compute_func)(mongo::BSONObj, std::string), T *obj, double caching_time = 0.0)
     {
-      Computable* comp = new Computable(query_to_compute, collection, boost::bind(compute_func, obj, _1, _2));
+      Computable* comp = new Computable(query_to_compute, collection, boost::bind(compute_func, obj, _1, _2), caching_time);
       computables.push_back(comp);
       return comp;
     }
@@ -70,7 +72,8 @@ class ComputablesManager
 
     std::list<Computable*> computables;
     std::string matching_test_collection_;
-    std::list<std::string> collections_to_cleanup;
+    //cached querries as ((collection, querry), cached_until)
+    std::map<std::tuple<std::string, std::string>, long long> cached_querries_;
 };
 
 #endif /* FAWKES_SRC_PLUGINS_ROBOT_MEMORY_COMPUTABLES_COMPUTABLES_MANAGER_H_ */
diff --git a/src/plugins/robot-memory/computables/transform_computable.cpp b/src/plugins/robot-memory/computables/transform_computable.cpp
index fdfc907..cb082e1 100644
--- a/src/plugins/robot-memory/computables/transform_computable.cpp
+++ b/src/plugins/robot-memory/computables/transform_computable.cpp
@@ -55,8 +55,6 @@ TransformComputable::~TransformComputable()
 
 std::list<mongo::BSONObj> TransformComputable::compute_transform(mongo::BSONObj query, std::string collection)
 {
-  logger_->log_info(name_, "Tfcomputable: %s", query.toString().c_str());
-
   //get positions in other frames
   BSONObjBuilder query_other_frames;
   query_other_frames.appendElements(query.removeField("frame").removeField("allow_tf"));
@@ -69,7 +67,6 @@ std::list<mongo::BSONObj> TransformComputable::compute_transform(mongo::BSONObj
   while(cur->more())
   {
     BSONObj pos = cur->next();
-    logger_->log_info(name_, "Transforming: %s", pos.toString().c_str());
     if(pos.hasField("frame") && pos.hasField("translation") && pos.hasField("rotation"))
     {
       std::string src_frame = pos.getField("frame").String();
@@ -102,10 +99,10 @@ std::list<mongo::BSONObj> TransformComputable::compute_transform(mongo::BSONObj
 
         res.push_back(res_pos.obj());
       }
-      else
-      {
-        logger_->log_info(name_, "Cant transform %s to %s", src_frame.c_str(), target_frame.c_str());
-      }
+//      else
+//      {
+//        logger_->log_info(name_, "Cant transform %s to %s", src_frame.c_str(), target_frame.c_str());
+//      }
     }
   }
   return res;
diff --git a/src/plugins/robot-memory/robot_memory.h b/src/plugins/robot-memory/robot_memory.h
index 441ca99..2deb923 100644
--- a/src/plugins/robot-memory/robot_memory.h
+++ b/src/plugins/robot-memory/robot_memory.h
@@ -102,9 +102,9 @@ class RobotMemory
      * @return Computable Object pointer used for removing it
      */
     template<typename T>
-    Computable* register_computable(mongo::Query query_to_compute, std::string collection, std::list<mongo::BSONObj>(T::*compute_func)(mongo::BSONObj, std::string), T *obj)
+    Computable* register_computable(mongo::Query query_to_compute, std::string collection, std::list<mongo::BSONObj>(T::*compute_func)(mongo::BSONObj, std::string), T *obj, double caching_time = 0.0)
     {
-      return computables_manager_->register_computable(query_to_compute, collection, compute_func, obj);
+      return computables_manager_->register_computable(query_to_compute, collection, compute_func, obj, caching_time);
     }
     void remove_computable(Computable* computable);
 




-- 
Fawkes Robotics Framework                 http://www.fawkesrobotics.org


More information about the fawkes-commits mailing list