diff --git a/include/vision/processor/processor_visual_odometry.h b/include/vision/processor/processor_visual_odometry.h
index d58369e4a99cf87c6c9966aea46d5ebeafa513d8..5368e965f2433b14498d7fcff23d70ed6fdddb65 100644
--- a/include/vision/processor/processor_visual_odometry.h
+++ b/include/vision/processor/processor_visual_odometry.h
@@ -35,23 +35,37 @@
 
 // wolf includes
 #include <core/math/rotations.h>
+#include <core/math/SE3.h>
+#include <core/state_block/state_composite.h>
 #include <core/processor/processor_tracker.h>
 #include <core/processor/track_matrix.h>
+#include <core/processor/motion_provider.h>
 
 // Opencv includes
 #include <opencv2/core.hpp>
+#include <opencv2/imgproc.hpp>
+#include <opencv2/calib3d.hpp>
 #include <opencv2/imgcodecs.hpp>
 #include <opencv2/features2d.hpp>
 #include <opencv2/calib3d/calib3d.hpp>
 #include <opencv2/video/tracking.hpp>
+#include <opencv2/core/eigen.hpp>
 
 
 
 namespace wolf{
 
+/** \brief Buffer of VectorComposite
+ *
+ * Object and functions to manage a buffer of VectorComposite objects.
+ * Used to hold a memory of origin->last relative poses.
+ */
+class BufferVectorCompositePtr : public Buffer<std::shared_ptr<VectorComposite>> { };
+
+
 WOLF_STRUCT_PTR_TYPEDEFS(ParamsProcessorVisualOdometry);
 
-struct ParamsProcessorVisualOdometry : public ParamsProcessorTracker
+struct ParamsProcessorVisualOdometry : public ParamsProcessorTracker, public ParamsMotionProvider
 {
     struct RansacParams
     {
@@ -107,7 +121,8 @@ struct ParamsProcessorVisualOdometry : public ParamsProcessorTracker
 
     ParamsProcessorVisualOdometry() = default;
     ParamsProcessorVisualOdometry(std::string _unique_name, const ParamsServer& _server):
-        ParamsProcessorTracker(_unique_name, _server)
+        ParamsProcessorTracker(_unique_name, _server),
+        ParamsMotionProvider(_unique_name, _server)
     {
         std_pix = _server.getParam<double>(prefix + _unique_name + "/std_pix");
 
@@ -171,12 +186,18 @@ struct ParamsProcessorVisualOdometry : public ParamsProcessorTracker
 
 WOLF_PTR_TYPEDEFS(ProcessorVisualOdometry);
 
-class ProcessorVisualOdometry : public ProcessorTracker
+class ProcessorVisualOdometry : public ProcessorTracker, public MotionProvider
 {
     public:
         ProcessorVisualOdometry(ParamsProcessorVisualOdometryPtr _params_visual_odometry);
         virtual ~ProcessorVisualOdometry() override {};
 
+        // MotionProvider class pure virtual methods
+        VectorComposite getState(const StateStructure& _structure = "") const override;
+        TimeStamp getTimeStamp( ) const override;
+        VectorComposite getState(const TimeStamp& _ts, const StateStructure& _structure = "") const override;
+        VectorComposite getRelativePoseOriginLast() const;
+
         WOLF_PROCESSOR_CREATE(ProcessorVisualOdometry, ParamsProcessorVisualOdometry);
 
     protected:
@@ -204,6 +225,9 @@ class ProcessorVisualOdometry : public ProcessorTracker
         // bookeeping
         TracksMap tracks_map_li_matched_;
 
+        // buffer of origin->last camera relative poses mapping origin to last
+        BufferVectorCompositePtr buffer_pose_cam_ol_;
+
 
     public:
 
@@ -300,7 +324,11 @@ class ProcessorVisualOdometry : public ProcessorTracker
 
         /** \brief Remove outliers from the tracks map with a RANSAC 5-points algorithm implemented on openCV
          */
-        bool filterWithEssential(const KeyPointsMap mwkps_prev, const KeyPointsMap mwkps_curr, TracksMap &tracks_prev_curr, cv::Mat &E);
+        bool filterWithEssential(const KeyPointsMap mwkps_prev, 
+                                 const KeyPointsMap mwkps_curr, 
+                                 TracksMap &tracks_prev_curr, 
+                                 cv::Mat &E, 
+                                 VectorComposite &_pose_prev_curr);
 
         /** \brief Tool to merge tracks 
          */
@@ -310,6 +338,14 @@ class ProcessorVisualOdometry : public ProcessorTracker
 
         const TrackMatrix& getTrackMatrix() const {return track_matrix_;}
 
+        VectorComposite getStateFromRelativeOriginLast(VectorComposite co_pose_cl) const;
+
+        static VectorComposite pose_from_essential_matrix(const cv::Mat& _E, 
+                                                          const std::vector<cv::Point2d>& p2d_prev, 
+                                                          const std::vector<cv::Point2d>& p2d_curr, 
+                                                          const cv::Mat& _K,
+                                                          cv::Mat& cvMask);
+
     private:
         void retainBest(std::vector<cv::KeyPoint> &_keypoints, int n);
 
@@ -330,7 +366,6 @@ class ProcessorVisualOdometry : public ProcessorTracker
         void detect_keypoints_in_empty_grid_cells(cv::Mat img_last, const TracksMap& tracks_last_incoming_filtered, const KeyPointsMap& mwkps_last, 
                                                   std::vector<cv::KeyPoint>& kps_last_new, KeyPointsMap& mwkps_last_filtered);
 
-
 };
 
 } //namespace wolf
diff --git a/src/processor/processor_visual_odometry.cpp b/src/processor/processor_visual_odometry.cpp
index 44688712b2cfdf5644ecf07471cdff6ac27f8250..6af48425384750639bd07f5e71926926510c7a72 100644
--- a/src/processor/processor_visual_odometry.cpp
+++ b/src/processor/processor_visual_odometry.cpp
@@ -24,17 +24,16 @@
 //standard
 #include "vision/processor/processor_visual_odometry.h"
 
-#include <opencv2/imgproc.hpp>
-#include <opencv2/calib3d.hpp>
-#include <opencv2/core/eigen.hpp>
-
 #include <chrono>
 #include <ctime>
 
 namespace wolf{
 
+using namespace SE3;
+
 ProcessorVisualOdometry::ProcessorVisualOdometry(ParamsProcessorVisualOdometryPtr _params_vo) :
                 ProcessorTracker("ProcessorVisualOdometry", "PO", 3, _params_vo),
+                MotionProvider("PO", _params_vo),
                 params_visual_odometry_(_params_vo)
 {
     // Preprocessor stuff
@@ -146,7 +145,16 @@ void ProcessorVisualOdometry::preProcess()
 
     // Outliers rejection with essential matrix
     cv::Mat E;
-    filterWithEssential(mwkps_origin, mwkps_incoming, tracks_origin_incoming, E);
+    VectorComposite pose_ol("PO", {3,4});
+    bool success = filterWithEssential(mwkps_origin, mwkps_incoming, tracks_origin_incoming, E, pose_ol);
+    if (success){
+        // store result of recoverPose if RANSAC was handled well
+        buffer_pose_cam_ol_.emplace(origin_ptr_->getTimeStamp(), std::make_shared<VectorComposite>(pose_ol));
+    }
+    else{
+        WOLF_WARN("!!!!!!Essential matrix RANSAC failed!!!!!!!!");
+        // return;  // What should we do in this case? 
+    }
 
     // Edit tracks prev with only inliers wrt origin
     // and remove also from mwkps_incoming all the keypoints that have not been tracked
@@ -193,7 +201,8 @@ void ProcessorVisualOdometry::preProcess()
 
         // Outliers rejection with essential matrix
         // tracks that are not geometrically consistent are removed from tracks_last_incoming_new
-        filterWithEssential(mwkps_last_filtered, mwkps_incoming_filtered, tracks_last_incoming_filtered, E);
+        VectorComposite not_used;
+        filterWithEssential(mwkps_last_filtered, mwkps_incoming_filtered, tracks_last_incoming_filtered, E, not_used);
 
         WOLF_DEBUG("New total : ", n_tracks_origin, " + ", mwkps_incoming_new.size(), " = ", tracks_last_incoming_filtered.size(), " tracks");
 
@@ -492,7 +501,6 @@ LandmarkBasePtr ProcessorVisualOdometry::emplaceLandmarkNaive(FeaturePointImageP
 }
 
 
-
 Eigen::Isometry3d ProcessorVisualOdometry::getTcw(TimeStamp _ts) const
 {
     // get robot position and orientation at capture's timestamp
@@ -642,7 +650,11 @@ TracksMap ProcessorVisualOdometry::kltTrack(const cv::Mat _img_prev, const cv::M
     return tracks_prev_curr;
 }
 
-bool ProcessorVisualOdometry::filterWithEssential(const KeyPointsMap _mwkps_prev, const KeyPointsMap _mwkps_curr, TracksMap &_tracks_prev_curr, cv::Mat &_E)
+bool ProcessorVisualOdometry::filterWithEssential(const KeyPointsMap _mwkps_prev, 
+                                                  const KeyPointsMap _mwkps_curr, 
+                                                  TracksMap &_tracks_prev_curr, 
+                                                  cv::Mat &_E, 
+                                                  VectorComposite &_pose_prev_curr)
 {
     // We need at least five tracks
     // TODO: this case is NOT handled by the rest of the algorithm currently
@@ -696,6 +708,12 @@ bool ProcessorVisualOdometry::filterWithEssential(const KeyPointsMap _mwkps_prev
                               prms.thresh,
                               cvMask);
 
+    // recover the pose relative pose if asked
+    if (_pose_prev_curr.includesStructure("PO")){
+        // modifies the mask of inliers -> maybe to change?
+        _pose_prev_curr = pose_from_essential_matrix(_E, p2d_prev, p2d_curr, Kcv_, cvMask);
+    }
+
     // Let's remove outliers from tracksMap
     for (size_t k=0; k<all_indices.size(); k++){
         if (cvMask.at<bool>(k) == 0){
@@ -706,6 +724,29 @@ bool ProcessorVisualOdometry::filterWithEssential(const KeyPointsMap _mwkps_prev
     return true;
 }
 
+
+VectorComposite ProcessorVisualOdometry::pose_from_essential_matrix(const cv::Mat& _E, 
+                                                                    const std::vector<cv::Point2d>& _p2d_prev, 
+                                                                    const std::vector<cv::Point2d>& _p2d_curr, 
+                                                                    const cv::Mat& _K,
+                                                                    cv::Mat& _cvMask)
+{
+    cv::Mat R_out, t_out;
+    cv::recoverPose(_E, _p2d_prev, _p2d_curr, _K, R_out, t_out, _cvMask);
+
+    // translation into eigen objects
+    Eigen::Matrix3d R_eig;
+    Eigen::Vector3d t_eig;
+    cv::cv2eigen(R_out, R_eig);
+    cv::cv2eigen(t_out, t_eig);
+
+    VectorComposite pose_prev_curr("PO", {3,4});
+    pose_prev_curr['P'] = t_eig;
+    pose_prev_curr['O'] = Quaterniond(R_eig).coeffs();
+    return pose_prev_curr;
+}
+
+
 void ProcessorVisualOdometry::retainBest(std::vector<cv::KeyPoint> &_keypoints, int n)
 {
     if (_keypoints.size() > n) {
@@ -853,6 +894,95 @@ void ProcessorVisualOdometry::detect_keypoints_in_empty_grid_cells(cv::Mat img_l
 }
 
 
+
+
+
+
+
+/////////////////////////
+// MotionProvider methods
+/////////////////////////
+
+VectorComposite ProcessorVisualOdometry::getState( const StateStructure& _structure ) const
+{
+    return getState(getTimeStamp(), _structure);
+}
+
+TimeStamp ProcessorVisualOdometry::getTimeStamp() const
+{
+    if ( last_ptr_ == nullptr )
+        return TimeStamp::Invalid();
+    else
+        return last_ptr_->getTimeStamp();
+}
+
+VectorComposite ProcessorVisualOdometry::getState(const TimeStamp& _ts, const StateStructure& _structure) const
+{
+    // valid last...
+    if (last_ptr_ != origin_ptr_)
+    {
+
+        std::shared_ptr<VectorComposite> pose_cam_ol_ptr = buffer_pose_cam_ol_.selectFirstBefore(_ts, getTimeTolerance());
+
+        if( !pose_cam_ol_ptr )
+        {
+            WOLF_WARN(getName(), ": Requested state with time stamp out of tolerance. Returning empty VectorComposite");
+            return VectorComposite();
+        }
+        else
+        {
+            return *pose_cam_ol_ptr;
+        }
+    }
+    // return state at origin if possible
+    else
+    {
+        if (origin_ptr_ == nullptr || fabs(_ts - origin_ptr_->getTimeStamp()) > params_->time_tolerance)
+        {
+            WOLF_WARN(getName(), ": Requested state with time stamp out of tolerance. Returning empty VectorComposite");
+            return VectorComposite();
+        }
+        else
+            return origin_ptr_->getFrame()->getState("PO");
+    }
+}
+
+
+
+
+
+VectorComposite ProcessorVisualOdometry::getStateFromRelativeOriginLast(VectorComposite co_pose_cl) const
+{
+    if (origin_ptr_ == nullptr or
+        origin_ptr_->isRemoving() or
+        last_ptr_ == nullptr or
+        last_ptr_->getFrame() == nullptr) // We do not have any info of where to find a valid state
+                                          // Further checking here for origin_ptr is redundant: if last=null, then origin=null too.
+    {
+        WOLF_WARN("Processor has no state. Returning an empty VectorComposite");
+        return VectorComposite(); // return empty state
+    }
+    
+    VectorComposite r_pose_c = getSensor()->getState();
+    VectorComposite c_pose_r = inverse(r_pose_c);
+
+    // composte poses to obtain the relative robot transformation
+    VectorComposite ro_pose_rl = SE3::compose(r_pose_c, SE3::compose(co_pose_cl, c_pose_r));
+
+    // Pose at origin
+    VectorComposite w_pose_ro = getOrigin()->getFrame()->getState();
+
+    // Pose at last using composition
+    VectorComposite w_pose_rl = SE3::compose(w_pose_ro, ro_pose_rl);
+
+    WOLF_INFO("I WAS CALLED!!!")
+
+    return w_pose_rl;
+}
+
+
+
+
 } //namespace wolf
 
 // Register in the FactoryProcessor
diff --git a/test/gtest_processor_visual_odometry.cpp b/test/gtest_processor_visual_odometry.cpp
index e56f8dc3fd4f293da7e96d4ad3562d4b58aa9eb2..9e6d167cc90d4ef7e3a586c859765a60fe22f203 100644
--- a/test/gtest_processor_visual_odometry.cpp
+++ b/test/gtest_processor_visual_odometry.cpp
@@ -429,19 +429,21 @@ TEST_F(ProcessorVOMultiView_class, filterWithEssential)
     cv::Mat E;
 
     // Let's try FilterWithEssential, all points here are inliers
-    processor->filterWithEssential(mwkps_c1, mwkps_c2, tracks_c1_c2, E);
+    VectorComposite toto;  // empty VectorComposite -> does not recoverPose
+    bool success = processor->filterWithEssential(mwkps_c1, mwkps_c2, tracks_c1_c2, E, toto);
+    ASSERT_TRUE(success);
     ASSERT_EQ(tracks_c1_c2.size(), mwkps_c2.size());
 
     ////////////////////////////////////////////////////////////////////
     // We had here an outlier: a keyPoint that doesn't move
-    mwkps_c1.insert(std::pair<size_t, WKeyPoint>(8, WKeyPoint(cv::KeyPoint(cv::Point2f(120,140), 1))));
-    mwkps_c2.insert(std::pair<size_t, WKeyPoint>(8, WKeyPoint(cv::KeyPoint(cv::Point2f(120,140), 1))));
+    mwkps_c1.insert(std::pair<size_t, WKeyPoint>(8, WKeyPoint(cv::KeyPoint(cv::Point2d(120,140), 1))));
+    mwkps_c2.insert(std::pair<size_t, WKeyPoint>(8, WKeyPoint(cv::KeyPoint(cv::Point2d(120,140), 1))));
     tracks_c1_c2.insert(std::pair<size_t, size_t>(8,8)); 
 
     // point at 8 must be discarded
-    processor->filterWithEssential(mwkps_c1, mwkps_c2, tracks_c1_c2, E);
+    success = processor->filterWithEssential(mwkps_c1, mwkps_c2, tracks_c1_c2, E, toto);
+    ASSERT_TRUE(success);
     ASSERT_EQ(tracks_c1_c2.count(8), 0);
-
 }
 
 
@@ -453,11 +455,12 @@ TEST_F(ProcessorVOMultiView_class, recoverPoseOpenCV)
     cv::Mat E;
 
     // Compute essential matrix, all points here are inliers
-    processor->filterWithEssential(mwkps_c1, mwkps_c2, tracks_c1_c2, E);
+    VectorComposite titi;
+    processor->filterWithEssential(mwkps_c1, mwkps_c2, tracks_c1_c2, E, titi);
 
     ////////////////////////////////////////////////////////////////////
     // can we retrieve the right orientation from the essential matrix?
-    std::vector<cv::Point2f> pts_c1, pts_c2;
+    std::vector<cv::Point2d> pts_c1, pts_c2;
     for (int i=0; i < mwkps_c1.size(); i++){
         pts_c1.push_back(mwkps_c1.at(i).getCvKeyPoint().pt);
         pts_c2.push_back(mwkps_c2.at(i).getCvKeyPoint().pt);
@@ -472,6 +475,11 @@ TEST_F(ProcessorVOMultiView_class, recoverPoseOpenCV)
     cv::cv2eigen(R_out, R_out_eig);
     ASSERT_MATRIX_APPROX(R_21, R_out_eig, 1e-4);
 
+
+    // Same with helper function
+    VectorComposite pose_21_out = ProcessorVisualOdometry::pose_from_essential_matrix(E, pts_c1, pts_c2, Kcv, mask);
+
+
     //////////////////////////////////////////////////////
     // Can we also use it to detect outliers using cheirality check?
     // Does not seem so...
@@ -482,26 +490,28 @@ TEST_F(ProcessorVOMultiView_class, recoverPoseOpenCV)
     // Can simply mean an absence of movement, hard to tune threshold...
 
     // add outliers
-    pts_c1.push_back(cv::Point2f(165.0, 190.0));
-    pts_c2.push_back(cv::Point2f(200.0, 190.0));
+    pts_c1.push_back(cv::Point2d(165.0, 190.0));
+    pts_c2.push_back(cv::Point2d(200.0, 190.0));
 
-    pts_c1.push_back(cv::Point2f(100.0, 250.0));
-    pts_c2.push_back(cv::Point2f(100.0, 250.0));
+    pts_c1.push_back(cv::Point2d(100.0, 250.0));
+    pts_c2.push_back(cv::Point2d(100.0, 250.0));
 
-    pts_c1.push_back(cv::Point2f(400.0, 70.0));
-    pts_c2.push_back(cv::Point2f(400.0, 70.0));
+    pts_c1.push_back(cv::Point2d(400.0, 70.0));
+    pts_c2.push_back(cv::Point2d(400.0, 70.0));
 
-    pts_c1.push_back(cv::Point2f(300.0, 300.0));
-    pts_c2.push_back(cv::Point2f(100.0, 300.0));    
+    pts_c1.push_back(cv::Point2d(300.0, 300.0));
+    pts_c2.push_back(cv::Point2d(100.0, 300.0));    
     
+    mask = 255*cv::Mat::ones(12, 1, CV_64F);
     
     cv::Mat triangulated_pts;
     double distance_threshold = 80.0;
     // cv::recoverPose(E, pts_c1, pts_c2, Kcv, R_out, t_out, mask);
-    cv::recoverPose(E, pts_c1, pts_c2, Kcv, R_out, t_out, distance_threshold, mask, triangulated_pts);
+    cv::Mat new_mask;
+    cv::recoverPose(E, pts_c1, pts_c2, Kcv, R_out, t_out, distance_threshold, new_mask, triangulated_pts);
 
     // triangulated_pts.size()
-    std::cout << triangulated_pts.size() << std::endl;
+    // std::cout << triangulated_pts.size() << std::endl;
 
 
     // std::cout << "mask" << std::endl;
@@ -511,9 +521,6 @@ TEST_F(ProcessorVOMultiView_class, recoverPoseOpenCV)
     // std::cout << R_out << std::endl;
     // std::cout << "t_out" << std::endl;
     // std::cout << t_out << std::endl;
-
-
-
 }