From ac658382edd4856e4c1f6b102f6dbf18e60ef2e2 Mon Sep 17 00:00:00 2001
From: Joseph Mirabel <jmirabel@laas.fr>
Date: Mon, 25 Jun 2018 10:54:21 +0200
Subject: [PATCH] Add RosTfListener

---
 CMakeLists.txt          |   1 +
 src/ros_tf_listener.cpp |   9 ++++
 src/ros_tf_listener.hh  | 107 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 117 insertions(+)
 create mode 100644 src/ros_tf_listener.cpp
 create mode 100644 src/ros_tf_listener.hh

diff --git a/CMakeLists.txt b/CMakeLists.txt
index c58e04e..f58a660 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -133,6 +133,7 @@ endmacro()
 compile_plugin(ros_publish)
 compile_plugin(ros_subscribe)
 compile_plugin(ros_queued_subscribe)
+compile_plugin(ros_tf_listener)
 compile_plugin(ros_time)
 compile_plugin(ros_joint_state)
 pkg_config_use_dependency(ros_joint_state pinocchio)
diff --git a/src/ros_tf_listener.cpp b/src/ros_tf_listener.cpp
new file mode 100644
index 0000000..7dd625a
--- /dev/null
+++ b/src/ros_tf_listener.cpp
@@ -0,0 +1,9 @@
+#include "dynamic_graph_bridge/ros_init.hh"
+#include "ros_tf_listener.hh"
+
+#include <dynamic-graph/factory.h>
+
+namespace dynamicgraph
+{
+  DYNAMICGRAPH_FACTORY_ENTITY_PLUGIN(RosTfListener, "RosTfListener");
+}
diff --git a/src/ros_tf_listener.hh b/src/ros_tf_listener.hh
new file mode 100644
index 0000000..d09433e
--- /dev/null
+++ b/src/ros_tf_listener.hh
@@ -0,0 +1,107 @@
+#ifndef DYNAMIC_GRAPH_ROS_TF_LISTENER_HH
+# define DYNAMIC_GRAPH_ROS_TF_LISTENER_HH
+
+# include <boost/bind.hpp>
+
+# include <tf/transform_listener.h>
+
+# include <dynamic-graph/entity.h>
+# include <dynamic-graph/signal.h>
+# include <dynamic-graph/command-bind.h>
+
+# include <sot/core/matrix-geometry.hh>
+
+namespace dynamicgraph {
+  class RosTfListener;
+
+  namespace internal
+  {
+    struct TransformListenerData {
+      typedef Signal<sot::MatrixHomogeneous, int> signal_t;
+
+      tf::TransformListener& listener;
+      const std::string toFrame, fromFrame;
+      tf::StampedTransform transform;
+      signal_t signal;
+
+      TransformListenerData (tf::TransformListener& l,
+          const std::string& to, const std::string& from,
+          const std::string& signame)
+        : listener (l)
+        , toFrame (to)
+        , fromFrame (from)
+        , signal (signame)
+      {
+        signal.setFunction (boost::bind(&TransformListenerData::getTransform, this, _1, _2));
+      }
+
+      sot::MatrixHomogeneous& getTransform (sot::MatrixHomogeneous& res, int time)
+      {
+        static const ros::Time rosTime(0);
+        try {
+          listener.lookupTransform (toFrame, fromFrame, rosTime, transform);
+        } catch (const tf::TransformException& ex) {
+          res.setIdentity();
+          ROS_ERROR("Enable to get transform at time %i: %s",time,ex.what());
+        }
+        for (sot::MatrixHomogeneous::Index r = 0; r < 3; ++r) {
+          for (sot::MatrixHomogeneous::Index c = 0; c < 3; ++c)
+            res.linear ()(r,c) = transform.getBasis().getRow(r)[c];
+          res.translation()[r] = transform.getOrigin()[r];
+        }
+        return res;
+      }
+    };
+  } // end of internal namespace.
+
+  class RosTfListener : public Entity
+  {
+    DYNAMIC_GRAPH_ENTITY_DECL();
+
+    public:
+      typedef internal::TransformListenerData TransformListenerData; 
+
+      RosTfListener (const std::string& name) : Entity (name)
+      {
+        std::string docstring =
+          "\n"
+          "  Add a signal containing the transform between two frames.\n"
+          "\n"
+          "  Input:\n"
+          "    - to  : frame name\n"
+          "    - from: frame name,\n"
+          "    - signalName: the signal name in dynamic-graph"
+          "\n";
+        addCommand ("add",
+            command::makeCommandVoid3(*this, &RosTfListener::add, docstring));
+      }
+
+      ~RosTfListener ()
+      {
+        for (Map_t::const_iterator _it = listenerDatas.begin(); _it != listenerDatas.end(); ++_it)
+          delete _it->second;
+      }
+
+      void add (const std::string& to, const std::string& from, const std::string& signame)
+      {
+        if (listenerDatas.find(signame) != listenerDatas.end())
+          throw std::invalid_argument ("A signal " + signame
+              + " already exists in RosTfListener " + getName());
+
+        boost::format signalName ("RosTfListener(%1%)::output(MatrixHomo)::%2%");
+        signalName % getName () % signame;
+
+        TransformListenerData* tld = new TransformListenerData (
+            listener, to, from, signalName.str());
+        signalRegistration (tld->signal);
+        listenerDatas[signame] = tld;
+      }
+
+    private:
+      typedef std::map<std::string, TransformListenerData*> Map_t;
+      Map_t listenerDatas;
+      tf::TransformListener listener;
+  };
+} // end of namespace dynamicgraph.
+
+#endif // DYNAMIC_GRAPH_ROS_TF_LISTENER_HH
-- 
GitLab