diff --git a/include/core/capture/capture_base.h b/include/core/capture/capture_base.h
index aaa76c9220c4351f1cca5b6a38bf290ef8e69c58..70fee2c15f074e571fd273d7cfccfbdc21c20552 100644
--- a/include/core/capture/capture_base.h
+++ b/include/core/capture/capture_base.h
@@ -101,7 +101,7 @@ class CaptureBase : public NodeBase, public HasStateBlocks, public std::enable_s
         static std::shared_ptr<classType> emplace(FrameBasePtr _frm_ptr, T&&... all);
 
     protected:
-        SizeEigen computeCalibSize() const;
+        virtual SizeEigen computeCalibSize() const;
 
     private:
         FeatureBasePtr addFeature(FeatureBasePtr _ft_ptr);
diff --git a/include/core/ceres_wrapper/ceres_manager.h b/include/core/ceres_wrapper/ceres_manager.h
index 5115c2a1bab9a3430494842147bbc5b0a802e025..802ab7b49dabf93455f8f93fc8c30745415fe33e 100644
--- a/include/core/ceres_wrapper/ceres_manager.h
+++ b/include/core/ceres_wrapper/ceres_manager.h
@@ -84,6 +84,8 @@ class CeresManager : public SolverManager
 
         void check();
 
+        const Eigen::SparseMatrixd computeHessian() const;
+
     protected:
 
         std::string solveImpl(const ReportVerbosity report_level) override;
diff --git a/include/core/factor/factor_block_absolute.h b/include/core/factor/factor_block_absolute.h
index eb55faae757f7fe1b02d2fe29c75a049e0b04299..0743548b7b4aad0517ecdd2590955c4cdf7c023c 100644
--- a/include/core/factor/factor_block_absolute.h
+++ b/include/core/factor/factor_block_absolute.h
@@ -41,7 +41,7 @@ class FactorBlockAbsolute : public FactorAnalytic
                             ProcessorBasePtr _processor_ptr = nullptr,
                             bool _apply_loss_function = false,
                             FactorStatus _status = FAC_ACTIVE) :
-            FactorAnalytic("BLOCK ABS",
+            FactorAnalytic("FactorBlockAbsolute",
                            nullptr,
                            nullptr,
                            nullptr,
diff --git a/include/core/factor/factor_block_difference.h b/include/core/factor/factor_block_difference.h
index 8f62b63838d79c6a654c80120bff4e4a144f4098..d3558ef21aa6e6577fc54d26015db3f9e3193312 100644
--- a/include/core/factor/factor_block_difference.h
+++ b/include/core/factor/factor_block_difference.h
@@ -37,8 +37,12 @@ class FactorBlockDifference : public FactorAnalytic
          *
          */
         FactorBlockDifference(
-                            StateBlockPtr _sb1_ptr,
-                            StateBlockPtr _sb2_ptr,
+                            const StateBlockPtr& _sb1_ptr,
+                            const StateBlockPtr& _sb2_ptr,
+                            const FrameBasePtr& _frame_other = nullptr,
+                            const CaptureBasePtr& _cap_other = nullptr,
+                            const FeatureBasePtr& _feat_other = nullptr,
+                            const LandmarkBasePtr& _lmk_other = nullptr,
                             unsigned int _start_idx1 = 0,
                             int _size1 = -1,
                             unsigned int _start_idx2 = 0,
@@ -46,11 +50,11 @@ class FactorBlockDifference : public FactorAnalytic
                             ProcessorBasePtr _processor_ptr = nullptr,
                             bool _apply_loss_function = false,
                             FactorStatus _status = FAC_ACTIVE) :
-            FactorAnalytic("BLOCK ABS",
-                           nullptr,
-                           nullptr,
-                           nullptr,
-                           nullptr,
+            FactorAnalytic("FactorBlockDifference",
+                           _frame_other,
+                           _cap_other,
+                           _feat_other,
+                           _lmk_other,
                            _processor_ptr,
                            _apply_loss_function,
                            _status,
@@ -146,10 +150,16 @@ inline void FactorBlockDifference::evaluateJacobians(const std::vector<Eigen::Ma
     assert(_st_vector[1].size() == sb2_size_ && "Wrong StateBlock size");
     assert(_st_vector[0].size() >= getMeasurement().size() && "StateBlock size and measurement size should match");
     assert(_st_vector[1].size() >= getMeasurement().size() && "StateBlock size and measurement size should match");
-
-    // normalized jacobian
-    _jacobians[0] = getMeasurementSquareRootInformationUpper() * J_res_sb1_;
-    _jacobians[1] = getMeasurementSquareRootInformationUpper() * J_res_sb2_;
+    assert(getMeasurementSquareRootInformationUpper().cols() == J_res_sb1_.rows() && "Wrong jacobian sb1 or covariance size");
+    assert(getMeasurementSquareRootInformationUpper().cols() == J_res_sb2_.rows() && "Wrong jacobian sb2 or covariance size");
+
+    // normalized jacobian, computed according to the _compute_jacobian flag
+    if (_compute_jacobian[0]){
+        _jacobians[0] = getMeasurementSquareRootInformationUpper() * J_res_sb1_;
+    }
+    if (_compute_jacobian[1]){
+        _jacobians[1] = getMeasurementSquareRootInformationUpper() * J_res_sb2_;
+    }
 }
 
 inline void FactorBlockDifference::evaluateJacobians(const std::vector<Eigen::Map<const Eigen::VectorXd>>& _st_vector,
@@ -163,10 +173,16 @@ inline void FactorBlockDifference::evaluateJacobians(const std::vector<Eigen::Ma
     assert(_st_vector[1].size() == sb2_size_ && "Wrong StateBlock size");
     assert(_st_vector[0].size() >= getMeasurement().size() && "StateBlock size and measurement size should match");
     assert(_st_vector[1].size() >= getMeasurement().size() && "StateBlock size and measurement size should match");
-
-    // normalized jacobian
-    _jacobians[0] = getMeasurementSquareRootInformationUpper() * J_res_sb1_;
-    _jacobians[1] = getMeasurementSquareRootInformationUpper() * J_res_sb2_;
+    assert(getMeasurementSquareRootInformationUpper().cols() == J_res_sb1_.rows() && "Wrong jacobian sb1 or covariance size");
+    assert(getMeasurementSquareRootInformationUpper().cols() == J_res_sb2_.rows() && "Wrong jacobian sb2 or covariance size");
+
+    // normalized jacobian, computed according to the _compute_jacobian flag
+    if (_compute_jacobian[0]){
+        _jacobians[0] = getMeasurementSquareRootInformationUpper() * J_res_sb1_;
+    }
+    if (_compute_jacobian[1]){
+        _jacobians[1] = getMeasurementSquareRootInformationUpper() * J_res_sb2_;
+    }
 }
 
 inline void FactorBlockDifference::evaluatePureJacobians(std::vector<Eigen::MatrixXd>& _pure_jacobians) const
diff --git a/include/core/problem/problem.h b/include/core/problem/problem.h
index 65f3b604de57df0d48c6e562191bb49f0960261d..f2b19ef05c22f7a4c6777f889031dbda45d80a5b 100644
--- a/include/core/problem/problem.h
+++ b/include/core/problem/problem.h
@@ -46,8 +46,7 @@ class Problem : public std::enable_shared_from_this<Problem>
         HardwareBasePtr     hardware_ptr_;
         TrajectoryBasePtr   trajectory_ptr_;
         MapBasePtr          map_ptr_;
-        IsMotionPtr  processor_motion_ptr_;
-//        IsMotionPtr         is_motion_ptr_;
+        std::list<IsMotionPtr>  processor_is_motion_list_;
         std::map<std::pair<StateBlockPtr, StateBlockPtr>, Eigen::MatrixXd> covariances_;
         SizeEigen state_size_, state_cov_size_, dim_;
         std::map<FactorBasePtr, Notification> factor_notification_map_;
@@ -147,15 +146,15 @@ class Problem : public std::enable_shared_from_this<Problem>
     protected:
         /** \brief Set the processor motion
          *
-         * Set the processor motion.
+         * Add a new processor of type is motion to the processor is motion list.
          */
-        void setProcessorMotion(IsMotionPtr _processor_motion_ptr);
-        IsMotionPtr setProcessorMotion(const std::string& _unique_processor_name);
-        void clearProcessorMotion();
+        void addProcessorIsMotion(IsMotionPtr _processor_motion_ptr);
+        void clearProcessorIsMotion(IsMotionPtr proc);
 
     public:
-        IsMotionPtr& getProcessorMotion();
-
+        IsMotionPtr getProcessorIsMotion();
+        std::list<IsMotionPtr> getProcessorIsMotionList();
+        
         // Trajectory branch ----------------------------------
         TrajectoryBasePtr getTrajectory() const;
         virtual FrameBasePtr setPrior(const Eigen::VectorXd& _prior_state, //
@@ -271,10 +270,10 @@ class Problem : public std::enable_shared_from_this<Problem>
         // Zero state provider
         Eigen::VectorXd zeroState ( ) const;
         bool priorIsSet() const;
+        void setPriorIsSet(bool _prior_is_set);
         // Perturb state
         void            perturb(double amplitude = 0.01);
 
-
         // Map branch -----------------------------------------
         MapBasePtr getMap() const;
         void loadMap(const std::string& _filename_dot_yaml);
@@ -367,9 +366,22 @@ inline bool Problem::priorIsSet() const
     return prior_is_set_;
 }
 
-inline IsMotionPtr& Problem::getProcessorMotion()
+inline void Problem::setPriorIsSet(bool _prior_is_set)
+{
+    prior_is_set_ = _prior_is_set;
+}
+
+inline IsMotionPtr Problem::getProcessorIsMotion()
+{
+    if (!processor_is_motion_list_.empty())
+        return processor_is_motion_list_.front();
+    return nullptr;
+}
+
+
+inline std::list<IsMotionPtr> Problem::getProcessorIsMotionList()
 {
-    return processor_motion_ptr_;
+    return processor_is_motion_list_;
 }
 
 inline std::map<StateBlockPtr,Notification> Problem::consumeStateBlockNotificationMap()
diff --git a/include/core/processor/is_motion.h b/include/core/processor/is_motion.h
index f3cf0d781f39c9fda6ffb9e64817ceed0acfa162..8c99fe72e37698a2210e35a3af0c14bf9168f65e 100644
--- a/include/core/processor/is_motion.h
+++ b/include/core/processor/is_motion.h
@@ -43,6 +43,12 @@ class IsMotion
         TimeStamp       getCurrentTimeStamp() const;
         Eigen::VectorXd getState(const TimeStamp& _ts) const;
 
+        std::string getStateStructure(){return state_structure_;};
+        void setStateStructure(std::string _state_structure){state_structure_ = _state_structure;};
+    
+    protected:
+        std::string state_structure_; ///< The structure of the state vector (to retrieve state blocks from frames)
+
 };
 
 }
diff --git a/include/core/processor/processor_base.h b/include/core/processor/processor_base.h
index f3feeb56a3bcc6787d8efeb1355175b989dd3f3e..dc62abcac8375fc238f7c93617a33ccb8662d246 100644
--- a/include/core/processor/processor_base.h
+++ b/include/core/processor/processor_base.h
@@ -117,13 +117,18 @@ public:
     *
     * elements are ordered from most recent to oldest
     */
-    std::map<TimeStamp,T> getContainer();
+    const std::map<TimeStamp,T>& getContainer();
 
     /**\brief Remove all packs in the buffer with a time stamp older than the specified
     *
     */
     void removeUpTo(const TimeStamp& _time_stamp);
 
+    /**\brief Remove all packs in the buffer with a time stamp older than the specified
+    *
+    */
+    void removeUpToLower(const TimeStamp& _time_stamp);
+
     /**\brief Clear the buffer
     *
     */
@@ -503,7 +508,7 @@ void Buffer<T>::add(const TimeStamp& _time_stamp, const T& _element)
 }
 
 template <typename T>
-std::map<TimeStamp,T> Buffer<T>::getContainer()
+const std::map<TimeStamp,T>& Buffer<T>::getContainer()
 {
     return container_;
 }
@@ -533,6 +538,13 @@ inline void Buffer<T>::removeUpTo(const TimeStamp& _time_stamp)
     container_.erase(container_.begin(), post); // erasing by range
 }
 
+template <typename T>
+inline void Buffer<T>::removeUpToLower(const TimeStamp& _time_stamp)
+{
+    Buffer::Iterator post = container_.lower_bound(_time_stamp);
+    container_.erase(container_.begin(), post); // erasing by range
+}
+
 template <typename T>
 inline bool Buffer<T>::doubleCheckTimeTolerance(const TimeStamp& _time_stamp1, const double& _time_tolerance1,
                                 const TimeStamp& _time_stamp2, const double& _time_tolerance2)
diff --git a/include/core/processor/processor_motion.h b/include/core/processor/processor_motion.h
index 2b8d4b7b86acc974d01b5864f2093a6d8e871a56..81a9184ad4798ccbaac1ebd61a194f6e287331b4 100644
--- a/include/core/processor/processor_motion.h
+++ b/include/core/processor/processor_motion.h
@@ -148,6 +148,7 @@ class ProcessorMotion : public ProcessorBase, public IsMotion
     // This is the main public interface
     public:
         ProcessorMotion(const std::string& _type,
+                        std::string _state_structure,
                         int _dim,
                         SizeEigen _state_size,
                         SizeEigen _delta_size,
@@ -505,11 +506,12 @@ inline void ProcessorMotion::getCurrentState(Eigen::VectorXd& _x) const
     assert(origin_ptr_ && "Trying to access origin_ptr_ but it is nullptr!");
 
     // ensure proper size of the provided reference
-    _x.resize( getProblem()->getFrameStructureSize() );
+    Eigen::VectorXd curr_x = origin_ptr_->getFrame()->getState(state_structure_);
+    _x.resize( curr_x.size() );
 
     // do get timestamp and state corrected by possible self-calibrations
     double Dt = getCurrentTimeStamp() - origin_ptr_->getTimeStamp();
-    statePlusDelta(origin_ptr_->getFrame()->getState(), last_ptr_->getDeltaCorrected(origin_ptr_->getCalibration()), Dt, _x);
+    statePlusDelta(curr_x, last_ptr_->getDeltaCorrected(origin_ptr_->getCalibration()), Dt, _x);
 }
 
 inline const Eigen::MatrixXd ProcessorMotion::getCurrentDeltaPreintCov() const
diff --git a/include/core/state_block/has_state_blocks.h b/include/core/state_block/has_state_blocks.h
index ef55d163be4764393c4e1b08ac0003ae67b1d223..97c570cb8550d5fb9aa6a2bf076e7e9674ab75c5 100644
--- a/include/core/state_block/has_state_blocks.h
+++ b/include/core/state_block/has_state_blocks.h
@@ -15,6 +15,10 @@
 namespace wolf
 {
 
+/// State of nodes containing several state blocks
+typedef std::unordered_map<std::string, Eigen::VectorXd> State;
+
+
 class HasStateBlocks
 {
     public:
@@ -62,11 +66,13 @@ class HasStateBlocks
         void removeStateBlocks(ProblemPtr _problem);
 
         // States
-        virtual void    setState(const Eigen::VectorXd& _state, const bool _notify = true);
-        Eigen::VectorXd getState() const;
-        void            getState(Eigen::VectorXd& _state) const;
-        unsigned int    getSize() const;
-        unsigned int    getLocalSize() const;
+        inline void setState(const Eigen::VectorXd& _state, std::string _sub_structure="", const bool _notify = true);
+        void getState(Eigen::VectorXd& _state, std::string structure="") const;
+        Eigen::VectorXd getState(std::string structure="") const;
+        unsigned int getSize(std::string _sub_structure="") const;
+        unsigned int getLocalSize(std::string _sub_structure="") const;
+
+        State getStateComposite();
 
         // Perturb state
         void            perturb(double amplitude = 0.01);
@@ -198,60 +204,100 @@ inline bool HasStateBlocks::isFixed() const
     return fixed;
 }
 
-inline void HasStateBlocks::setState(const Eigen::VectorXd& _state, const bool _notify)
+inline void HasStateBlocks::setState(const Eigen::VectorXd& _state, std::string _sub_structure, const bool _notify)
 {
-    int size = getSize();
-
+    if (_sub_structure == ""){
+        _sub_structure = structure_;
+    }
+    int size = getSize(_sub_structure);
     assert(_state.size() == size && "In FrameBase::setState wrong state size");
 
     unsigned int index = 0;
-    for (const char key : getStructure())
+    for (const char key : _sub_structure)
     {
         const auto& sb = getStateBlock(key);
-
+        if (!sb){
+            WOLF_ERROR("Stateblock key ", key, " not in the structure");
+        }
         sb->setState(_state.segment(index, sb->getSize()), _notify); // do not notify if state block is not estimated by the solver
         index += sb->getSize();
     }
 
 }
 
-inline void HasStateBlocks::getState(Eigen::VectorXd& _state) const
+// _sub_structure can be either stateblock structure of the node or a subset of this structure
+inline void HasStateBlocks::getState(Eigen::VectorXd& _state, std::string _sub_structure) const
 {
-    _state.resize(getSize());
+    if (_sub_structure == ""){
+        _sub_structure = structure_;
+    }
+    _state.resize(getSize(_sub_structure));
 
     unsigned int index = 0;
-    for (const char key : getStructure())
+    for (const char key : _sub_structure)
     {
         const auto& sb = getStateBlock(key);
-
+        if (!sb){
+            WOLF_ERROR("Stateblock key ", key, " not in the structure");
+        }
         _state.segment(index,sb->getSize()) = sb->getState();
         index += sb->getSize();
     }
 
 }
 
-inline Eigen::VectorXd HasStateBlocks::getState() const
+inline Eigen::VectorXd HasStateBlocks::getState(std::string _sub_structure) const
 {
     Eigen::VectorXd state;
 
-    getState(state);
+    getState(state, _sub_structure);
+
+    return state;
+}
 
+inline State HasStateBlocks::getStateComposite()
+{
+    State state;
+    for (auto& pair_key_kf : state_block_map_)
+    {
+        state.emplace(pair_key_kf.first, pair_key_kf.second->getState());
+    }
     return state;
 }
 
-inline unsigned int HasStateBlocks::getSize() const
+inline unsigned int HasStateBlocks::getSize(std::string _sub_structure) const
 {
+    if (_sub_structure == ""){
+        _sub_structure = structure_;
+    }
     unsigned int size = 0;
-    for (const auto& pair_key_sb : getStateBlockMap())
-            size += pair_key_sb.second->getSize();
+    for (const char key : _sub_structure)
+    {
+        const auto& sb = getStateBlock(key);
+        if (!sb){
+            WOLF_ERROR("Stateblock key ", key, " not in the structure");
+        }
+        size += sb->getSize();
+    }
+
     return size;
 }
 
-inline unsigned int HasStateBlocks::getLocalSize() const
+inline unsigned int HasStateBlocks::getLocalSize(std::string _sub_structure) const
 {
+    if (_sub_structure == ""){
+        _sub_structure = structure_;
+    }
     unsigned int size = 0;
-    for (const auto& pair_key_sb : getStateBlockMap())
-            size += pair_key_sb.second->getLocalSize();
+    for (const char key : _sub_structure)
+    {
+        const auto& sb = getStateBlock(key);
+        if (!sb){
+            WOLF_ERROR("Stateblock key ", key, " not in the structure");
+        }
+        size += sb->getLocalSize();
+    }
+
     return size;
 }
 
diff --git a/include/core/state_block/state_block.h b/include/core/state_block/state_block.h
index 33aa6fcb4b221ea1dc23f24b21f4a0fb12cbfc0d..ab3bb7147f3c81f57a3436216412274394acc04a 100644
--- a/include/core/state_block/state_block.h
+++ b/include/core/state_block/state_block.h
@@ -74,6 +74,10 @@ public:
          **/
         Eigen::VectorXd getState() const;
 
+        /** \brief Returns the state vector data array
+         **/
+        double* getStateData();
+
         /** \brief Sets the state vector
          **/
         void setState(const Eigen::VectorXd& _state, const bool _notify = true);
@@ -283,6 +287,11 @@ inline void StateBlock::resetLocalParamUpdated()
     local_param_updated_.store(false);
 }
 
+inline double* StateBlock::getStateData()
+{
+    return state_.data();
+}
+
 }// namespace wolf
 
 #endif
diff --git a/src/ceres_wrapper/ceres_manager.cpp b/src/ceres_wrapper/ceres_manager.cpp
index ecf57e7d7e29b4b8ccfecf09f8c39d8eacdafdbb..0d8cba6f97cb7e2c2cdf067e7ebcb65d8ac79c10 100644
--- a/src/ceres_wrapper/ceres_manager.cpp
+++ b/src/ceres_wrapper/ceres_manager.cpp
@@ -443,6 +443,77 @@ void CeresManager::check()
     }
 }
 
+void insertSparseBlock(const Eigen::MatrixXd& ins, Eigen::SparseMatrixd& original, const unsigned int& row, const unsigned int& col)
+{
+    for (auto ins_row = 0; ins_row < ins.rows(); ins_row++)
+        for (auto ins_col = 0; ins_col < ins.cols(); ins_col++)
+            original.insert(row+ins_row, col+ins_col) = ins(ins_row,ins_col);
+
+    original.makeCompressed();
+}
+
+const Eigen::SparseMatrixd CeresManager::computeHessian() const
+{
+    Eigen::SparseMatrixd H;
+    Eigen::SparseMatrixd A;
+    // fac_2_residual_idx_
+    // fac_2_costfunction_
+    // state_blocks_local_param_
+    int ix_row = 0;  // index of the factor/measurement in the 
+    for (auto fac_res_pair: fac_2_residual_idx_){
+        FactorBasePtr fac_ptr = fac_res_pair.first;
+        ix_row += fac_ptr->getSize();
+
+        // retrieve all stateblocks data related to this factor
+        std::vector<const double*> fac_states_ptr;
+        for (auto sb : fac_res_pair.first->getStateBlockPtrVector()){
+            fac_states_ptr.push_back(sb->getStateData());
+        }
+        
+        // retrieve residual value, not used afterwards in this case since we just care about jacobians
+        Eigen::VectorXd residual(fac_ptr->getSize());
+        // retrieve jacobian in group size, not local size
+        std::vector<Eigen::MatrixXd> jacobians;
+        fac_ptr->evaluate(fac_states_ptr, residual, jacobians);
+
+        // Retrieve the block row sparse matrix of this factor
+        Eigen::SparseMatrixd A_block_row(fac_ptr->getSize(), A.cols());
+        for (auto i = 0; i < jacobians.size(); i++)
+        {
+            StateBlockPtr sb = fac_ptr->getStateBlockPtrVector()[i];
+            if (!sb->isFixed())
+            {
+                assert((state_blocks_local_param_.find(sb) != state_blocks_local_param_.end()) && "factor involving a state block not added");
+                assert((A.cols() >= sb->getLocalSize() + jacobians[i].cols()) - 1 && "bad A number of cols");
+
+                // insert since A_block_row has just been created so it's empty for sure
+                if (sb->hasLocalParametrization()){
+                    // if the state block has a local parameterization, we need to right multiply by the manifold element / tangent element jacobian
+                    Eigen::MatrixXd J_manif_tang(sb->getSize(), sb->getLocalSize());
+                    Eigen::Map<Eigen::MatrixRowXd> J_manif_tang_map(J_manif_tang.data(), sb->getSize(), sb->getLocalSize());
+                    Eigen::Map<const Eigen::VectorXd> sb_state_map(sb->getStateData(), sb->getSize());
+
+                    sb->getLocalParametrization()->computeJacobian(sb_state_map, J_manif_tang_map);
+                    insertSparseBlock(jacobians[i] * J_manif_tang, A_block_row, 0, sb->getLocalSize());  // (to_insert, matrix_to_fill, row, col)
+                }
+                else {
+                    insertSparseBlock(jacobians[i], A_block_row, 0, sb->getLocalSize());
+                }
+            }
+        }
+        
+        // fill the weighted jacobian matrix block row
+        A.block(ix_row, 0, fac_ptr->getSize(), A.cols());
+
+    }
+
+    // compute the hessian matrix from the weighted jacobian 
+    H = A.transpose() * A;
+
+    return H;
+}
+
+
 } // namespace wolf
 #include "core/solver/solver_factory.h"
 namespace wolf {
diff --git a/src/frame/frame_base.cpp b/src/frame/frame_base.cpp
index 85f94bd2a97af8a68e4b1551d3352daa8e8906d8..42a11b3782a5a669264471bcae49571ec1322840 100644
--- a/src/frame/frame_base.cpp
+++ b/src/frame/frame_base.cpp
@@ -64,14 +64,14 @@ FrameBase::FrameBase(const std::string _frame_structure, const SizeEigen _dim, c
            time_stamp_(_ts)
 {
     if(_frame_structure.compare("PO") == 0 and _dim == 2){
-        assert(_x.size() == 3 && "Wrong state vector size. Should be 3 for 2d!");
+        assert(_x.size() == 3 && "Wrong state vector size. Should be 3 for PO 2D!");
         StateBlockPtr p_ptr ( std::make_shared<StateBlock>    (_x.head    <2> ( ) ) );
         StateBlockPtr o_ptr ( std::make_shared<StateAngle>    ((double) _x(2) ) );
         addStateBlock("P", p_ptr);
         addStateBlock("O", o_ptr);
         this->setType("PO 2d");
     }else if(_frame_structure.compare("PO") == 0 and _dim == 3){
-        assert(_x.size() == 7 && "Wrong state vector size. Should be 7 for 3d!");
+        assert(_x.size() == 7 && "Wrong state vector size. Should be 7 for PO 3D!");
         StateBlockPtr p_ptr ( std::make_shared<StateBlock>      (_x.head    <3> ( ) ) );
         StateBlockPtr o_ptr ( std::make_shared<StateQuaternion> (_x.tail    <4> ( ) ) );
         addStateBlock("P", p_ptr);
@@ -79,7 +79,7 @@ FrameBase::FrameBase(const std::string _frame_structure, const SizeEigen _dim, c
         this->setType("PO 3d");
     }else if(_frame_structure.compare("POV") == 0 and _dim == 3){
         // auto _x = Eigen::VectorXd::Zero(10);
-        assert(_x.size() == 10 && "Wrong state vector size. Should be 10 for 3d!");
+        assert(_x.size() == 10 && "Wrong state vector size. Should be 10 for POV 3D!");
         StateBlockPtr p_ptr ( std::make_shared<StateBlock>      (_x.head    <3> ( ) ) );
         StateBlockPtr o_ptr ( std::make_shared<StateQuaternion> (_x.segment <4> (3) ) );
         StateBlockPtr v_ptr ( std::make_shared<StateBlock>      (_x.tail    <3> ( ) ) );
@@ -87,6 +87,22 @@ FrameBase::FrameBase(const std::string _frame_structure, const SizeEigen _dim, c
         addStateBlock("O", o_ptr);
         addStateBlock("V", v_ptr);
         this->setType("POV 3d");
+    }else if(_frame_structure.compare("POVCDL") == 0 and _dim == 3){
+        // auto _x = Eigen::VectorXd::Zero(10);
+        assert(_x.size() == 19 && "Wrong state vector size. Should be 19 for POVCDL 3D!");
+        StateBlockPtr p_ptr ( std::make_shared<StateBlock>      (_x.head    <3> (  ) ) );
+        StateBlockPtr o_ptr ( std::make_shared<StateQuaternion> (_x.segment <4> (3 ) ) );
+        StateBlockPtr v_ptr ( std::make_shared<StateBlock>      (_x.segment <3> (7 ) ) );
+        StateBlockPtr c_ptr ( std::make_shared<StateBlock>      (_x.segment <3> (10) ) );
+        StateBlockPtr cd_ptr ( std::make_shared<StateBlock>      (_x.segment <3> (13) ) );
+        StateBlockPtr Lc_ptr ( std::make_shared<StateBlock>      (_x.segment <3> (16) ) );
+        addStateBlock("P", p_ptr);
+        addStateBlock("O", o_ptr);
+        addStateBlock("V", v_ptr);
+        addStateBlock("C", c_ptr);
+        addStateBlock("D", cd_ptr);
+        addStateBlock("L", Lc_ptr);
+        this->setType("POVCDL 3d");
     }else{
         std::cout << _frame_structure << " ^^ " << _dim << std::endl;
         throw std::runtime_error("Unknown frame structure");
diff --git a/src/problem/problem.cpp b/src/problem/problem.cpp
index 8e74f8411fcad44e8c8fcc8fbfd62bf96e8d0f90..e79de9572f545e85142450497f3d4780621adc7b 100644
--- a/src/problem/problem.cpp
+++ b/src/problem/problem.cpp
@@ -35,25 +35,27 @@ Problem::Problem(const std::string& _frame_structure, SizeEigen _dim) :
         hardware_ptr_(std::make_shared<HardwareBase>()),
         trajectory_ptr_(std::make_shared<TrajectoryBase>(_frame_structure)),
         map_ptr_(std::make_shared<MapBase>()),
-        processor_motion_ptr_(),
+        processor_is_motion_list_(std::list<IsMotionPtr>()),
         prior_is_set_(false),
         frame_structure_(_frame_structure)
 {
+    dim_ = _dim;
     if (_frame_structure == "PO" and _dim == 2)
     {
         state_size_ = 3;
         state_cov_size_ = 3;
-        dim_ = 2;
     }else if (_frame_structure == "PO" and _dim == 3)
     {
         state_size_ = 7;
         state_cov_size_ = 6;
-        dim_ = 3;
-    } else if (_frame_structure == "POV" and _dim == 3)
+    }else if (_frame_structure == "POV" and _dim == 3)
     {
         state_size_ = 10;
         state_cov_size_ = 9;
-        dim_ = 3;
+    }else if (_frame_structure == "POVCDL" and _dim == 3)
+    {
+        state_size_ = 19;
+        state_cov_size_ = 18;
     }
     else std::runtime_error(
             "Problem::Problem(): Unknown frame structure. Add appropriate frame structure to the switch statement.");
@@ -226,7 +228,7 @@ ProcessorBasePtr Problem::installProcessor(const std::string& _prc_type, //
     //Dimension check
     int prc_dim = prc_ptr->getDim();
     auto prb = this;
-    assert((prc_dim == 0 or prc_dim == prb->getDim()) && "Processor and Problem do not agree on dimension");
+    assert(((prc_dim == 0) or (prc_dim == prb->getDim())) && "Processor and Problem do not agree on dimension");
 
     prc_ptr->configure(_corresponding_sensor_ptr);
     prc_ptr->link(_corresponding_sensor_ptr);
@@ -235,10 +237,6 @@ ProcessorBasePtr Problem::installProcessor(const std::string& _prc_type, //
     if (prc_ptr->isMotion() && prior_is_set_)
         (std::static_pointer_cast<ProcessorMotion>(prc_ptr))->setOrigin(getLastKeyFrame());
 
-    // setting the main processor motion
-    if (prc_ptr->isMotion() && processor_motion_ptr_ == nullptr)
-        processor_motion_ptr_ = std::dynamic_pointer_cast<IsMotion>(prc_ptr);
-
     return prc_ptr;
 }
 
@@ -274,7 +272,7 @@ ProcessorBasePtr Problem::installProcessor(const std::string& _prc_type, //
     //Dimension check
     int prc_dim = prc_ptr->getDim();
     auto prb = this;
-    assert((prc_dim == 0 or prc_dim == prb->getDim()) && "Processor and Problem do not agree on dimension");
+    assert(((prc_dim == 0) or (prc_dim == prb->getDim())) && "Processor and Problem do not agree on dimension");
 
     prc_ptr->configure(sen_ptr);
     prc_ptr->link(sen_ptr);
@@ -284,10 +282,6 @@ ProcessorBasePtr Problem::installProcessor(const std::string& _prc_type, //
     if (prc_ptr->isMotion() && prior_is_set_)
         (std::static_pointer_cast<ProcessorMotion>(prc_ptr))->setOrigin(getLastKeyFrame());
 
-    // setting the main processor motion
-    if (prc_ptr->isMotion() && processor_motion_ptr_ == nullptr)
-        processor_motion_ptr_ = std::static_pointer_cast<ProcessorMotion>(prc_ptr);
-
     return prc_ptr;
 }
 
@@ -306,47 +300,6 @@ SensorBasePtr Problem::getSensor(const std::string& _sensor_name) const
     return (*sen_it);
 }
 
-IsMotionPtr Problem::setProcessorMotion(const std::string& _processor_name)
-{
-    for (auto sen : getHardware()->getSensorList()) // loop all sensors
-    {
-        auto prc_it = std::find_if(sen->getProcessorList().begin(), // find processor by its name
-                                   sen->getProcessorList().end(),
-                                   [&](ProcessorBasePtr prc)
-                                   {
-                                       return prc->getName() == _processor_name;
-                                   }); // lambda function for the find_if
-
-        if (prc_it != sen->getProcessorList().end())  // found something!
-        {
-            if ((*prc_it)->isMotion()) // found, and it's motion!
-            {
-                std::cout << "Found processor '" << _processor_name << "', of type Motion, and set as the main motion processor." << std::endl;
-                processor_motion_ptr_ = std::dynamic_pointer_cast<IsMotion>(*prc_it);
-                return processor_motion_ptr_;
-            }
-            else // found, but it's not motion!
-            {
-                std::cout << "Found processor '" << _processor_name << "', but not of type Motion!" << std::endl;
-                return nullptr;
-            }
-        }
-    }
-    // nothing found!
-    std::cout << "Processor '" << _processor_name << "' not found!" << std::endl;
-    return nullptr;
-}
-
-void Problem::setProcessorMotion(IsMotionPtr _processor_motion_ptr)
-{
-    processor_motion_ptr_ = _processor_motion_ptr;
-}
-
-void Problem::clearProcessorMotion()
-{
-    processor_motion_ptr_.reset();
-}
-
 FrameBasePtr Problem::emplaceFrame(const std::string& _frame_structure, //
                                    const SizeEigen _dim, //
                                    FrameType _frame_key_type, //
@@ -387,41 +340,108 @@ Eigen::VectorXd Problem::getCurrentState() const
 
 void Problem::getCurrentState(Eigen::VectorXd& _state) const
 {
-    if (processor_motion_ptr_ != nullptr)
-        processor_motion_ptr_->getCurrentState(_state);
-    else if (trajectory_ptr_->getLastKeyOrAuxFrame() != nullptr)
-        trajectory_ptr_->getLastKeyOrAuxFrame()->getState(_state);
-    else
-        _state = zeroState();
+    TimeStamp ts;  // throwaway timestamp
+    getCurrentStateAndStamp(_state, ts);
 }
 
-void Problem::getCurrentStateAndStamp(Eigen::VectorXd& _state, TimeStamp& ts) const
-{
-    if (processor_motion_ptr_ != nullptr)
+void Problem::getCurrentStateAndStamp(Eigen::VectorXd& _state, TimeStamp& _ts) const
+{   
+    if (!processor_is_motion_list_.empty())
     {
-        processor_motion_ptr_->getCurrentState(_state);
-        processor_motion_ptr_->getCurrentTimeStamp(ts);
+        // retrieve the minimum of the most recent ts in all processor is motion then call getSate(ts, state)
+        std::list<TimeStamp> proc_is_motion_current_ts;
+        for (auto proc: processor_is_motion_list_){
+            proc_is_motion_current_ts.push_back(proc->getCurrentTimeStamp());
+        }
+        auto min_it = std::min_element(proc_is_motion_current_ts.begin(), proc_is_motion_current_ts.end());
+        getState(*min_it, _state);
+        _ts = *min_it;
     }
     else if (trajectory_ptr_->getLastKeyOrAuxFrame() != nullptr)
     {
-        trajectory_ptr_->getLastKeyOrAuxFrame()->getTimeStamp(ts);
+        // kind of redundant with getState(_ts, _state)
+        trajectory_ptr_->getLastKeyOrAuxFrame()->getTimeStamp(_ts);
         trajectory_ptr_->getLastKeyOrAuxFrame()->getState(_state);
     }
     else
         _state = zeroState();
 }
 
+
+// Problem of this implmentation: if more state
 void Problem::getState(const TimeStamp& _ts, Eigen::VectorXd& _state) const
 {
-    // try to get the state from processor_motion if any, otherwise...
-    if (processor_motion_ptr_ == nullptr || !processor_motion_ptr_->getState(_ts, _state))
-    {
-        FrameBasePtr closest_frame = trajectory_ptr_->closestKeyOrAuxFrameToTimeStamp(_ts);
+    // if _ts is too recent, for some of the processor is motion, they return the state corresponding to their last frame timestamp
+    FrameBasePtr closest_frame = trajectory_ptr_->closestKeyOrAuxFrameToTimeStamp(_ts);
+    if (processor_is_motion_list_.empty()){
         if (closest_frame != nullptr)
-            closest_frame->getState(_state);
+            _state = closest_frame->getState();
         else
             _state = zeroState();
     }
+
+    // RETRIEVE FROM PROCESSOR MOTION
+    // TODO: current implementation messy, would be much easier with a state being an std::unordered_map
+    else {
+        // Iterate over the problem state structure and get the corresponding state
+        // in the first processor is motion that provides it
+        // finally check if the state to concatenate list has the same total size as the problem state_size 
+        
+        // an map is necessary as a temporary structure because we do not know in which order we will find the state blocks in processors 
+        std::unordered_map<char, Eigen::VectorXd> states_to_concat_map;  // not necessary to be ordered
+        for (auto proc: processor_is_motion_list_){
+            Eigen::VectorXd proc_state = proc->getState(_ts);
+
+            int idx = 0;
+            for (char sb_name: proc->getStateStructure()){
+                // not already there
+                if (states_to_concat_map.find(sb_name) == states_to_concat_map.end()){
+                    if (sb_name == 'O'){
+                        int size_sb = dim_ == 3 ? 4 : 1;  // really bad: should be more transparent
+                        states_to_concat_map[sb_name] = proc_state.segment(idx, size_sb);
+                        idx += size_sb;
+                    }
+                    else{
+                        int size_sb = dim_ == 3 ? 3 : 2;
+                        states_to_concat_map[sb_name] = proc_state.segment(idx, size_sb);
+                        idx += size_sb;
+                    } 
+                }
+            }
+        }
+
+        int concat_size = 0;
+        for (auto state_map_it: states_to_concat_map){
+            concat_size += state_map_it.second.size();
+        }
+        // assert(concat_size == state_size_  && "Problem with the concatenated size: " );
+
+        // fill the state value from the state concatenation in the order dictated by frame_structure_
+        int idx = 0;
+        _state.resize(state_size_);
+        for (char sb_name: frame_structure_){
+            Eigen::VectorXd sb_state;
+            int size_sb;  // really bad...
+            if (sb_name == 'O'){
+                size_sb = dim_ == 3 ? 4 : 1;
+            }
+            else {
+                size_sb = dim_ == 3 ? 3 : 2;
+            }
+            if (states_to_concat_map.find(sb_name) != states_to_concat_map.end()){
+                sb_state = states_to_concat_map[sb_name];
+            }
+            else {
+                // Should be taken from the last state but too messy already
+                sb_state.resize(size_sb); 
+                sb_state.setZero();
+            }
+
+            _state.segment(idx, size_sb) = sb_state;
+            idx += size_sb;
+
+        }
+    }
 }
 
 Eigen::VectorXd Problem::getState(const TimeStamp& _ts) const
@@ -451,6 +471,18 @@ std::string Problem::getFrameStructure() const
     return frame_structure_;
 }
 
+void Problem::addProcessorIsMotion(IsMotionPtr _processor_motion_ptr)
+{
+    processor_is_motion_list_.push_back(_processor_motion_ptr);
+}
+
+void Problem::clearProcessorIsMotion(IsMotionPtr proc){
+    auto it = std::find(processor_is_motion_list_.begin(), processor_is_motion_list_.end(), proc);
+    if (it != processor_is_motion_list_.end()){
+        processor_is_motion_list_.erase(it);
+    }
+}
+
 Eigen::VectorXd Problem::zeroState() const
 {
     Eigen::VectorXd state = Eigen::VectorXd::Zero(getFrameStructureSize());
@@ -846,10 +878,16 @@ FrameBasePtr Problem::setPrior(const Eigen::VectorXd& _prior_state, const Eigen:
         // create origin capture with the given state as data
         // Capture fix only takes 3d position and Quaternion orientation
         CapturePosePtr init_capture;
-        if (this->getFrameStructure() == "POV" and this->getDim() == 3)
+        // if (this->getFrameStructure() == "POV" and this->getDim() == 3)
+        //     init_capture = CaptureBase::emplace<CapturePose>(origin_keyframe, _ts, nullptr, _prior_state.head(7), _prior_cov.topLeftCorner(6,6));
+        // else
+        //     init_capture = CaptureBase::emplace<CapturePose>(origin_keyframe, _ts, nullptr, _prior_state, _prior_cov);
+
+        if (this->getDim() == 3)
             init_capture = CaptureBase::emplace<CapturePose>(origin_keyframe, _ts, nullptr, _prior_state.head(7), _prior_cov.topLeftCorner(6,6));
         else
-            init_capture = CaptureBase::emplace<CapturePose>(origin_keyframe, _ts, nullptr, _prior_state, _prior_cov);
+            init_capture = CaptureBase::emplace<CapturePose>(origin_keyframe, _ts, nullptr, _prior_state.head(3), _prior_cov.topLeftCorner(3,3));
+
 
         // emplace feature and factor
         init_capture->emplaceFeatureAndFactor();
@@ -1003,6 +1041,15 @@ void Problem::print(int depth, std::ostream& stream, bool constr_by, bool metric
                 }
                 stream << std::endl;
             }
+            // if (state_blocks)
+            // {
+            //     cout << "    sb:";
+            //     for (const auto& sb : F->getStateBlockVec())
+            //     {
+            //         cout << " " << (sb->isFixed() ? "Fix" : "Est");
+            //     }
+            //     cout << endl;
+            // }
             if (depth >= 2)
             {
                 // Captures =======================================================================================
diff --git a/src/processor/processor_base.cpp b/src/processor/processor_base.cpp
index a35097f2c70d3b047117ae6d0c9bf81a5fe2f5da..f61f861b021e51a08dd92db301aa1bd8de159272 100644
--- a/src/processor/processor_base.cpp
+++ b/src/processor/processor_base.cpp
@@ -53,12 +53,13 @@ void ProcessorBase::captureCallback(CaptureBasePtr _capture_ptr)
     assert(_capture_ptr != nullptr && "captureCallback with a nullptr capture");
     WOLF_DEBUG("P", isMotion() ? "M " : "T ", getName(), ": Capture ", _capture_ptr->id(), " callback received with ts = ", _capture_ptr->getTimeStamp());
 
-    // if trigger, process directly without buffering
-    if (triggerInCapture(_capture_ptr))
-        processCapture(_capture_ptr);
     // asking if capture should be stored
     if (storeCapture(_capture_ptr))
         buffer_capture_.add(_capture_ptr->getTimeStamp(), _capture_ptr);
+
+    // if trigger, process directly without buffering
+    if (triggerInCapture(_capture_ptr))
+        processCapture(_capture_ptr);
 }
 
 void ProcessorBase::remove()
@@ -68,12 +69,12 @@ void ProcessorBase::remove()
         is_removing_ = true;
         ProcessorBasePtr this_p = shared_from_this();
 
-        // clear Problem::processor_motion_ptr_
         if (isMotion())
         {
             ProblemPtr P = getProblem();
-            if(P && (P->getProcessorMotion() == std::dynamic_pointer_cast<IsMotion>( shared_from_this() ) ) )
-                P->clearProcessorMotion();
+            auto this_proc_cast_attempt = std::dynamic_pointer_cast<IsMotion>( shared_from_this() );
+            if(P && this_proc_cast_attempt )
+                P->clearProcessorIsMotion(this_proc_cast_attempt);
         }
 
         // remove from upstream
diff --git a/src/processor/processor_motion.cpp b/src/processor/processor_motion.cpp
index 634d1f6d1284997573ef763bd329dcdf37cc94d3..aded1532cc17fc6a0f2e0d48edbbca857a1ab28b 100644
--- a/src/processor/processor_motion.cpp
+++ b/src/processor/processor_motion.cpp
@@ -7,6 +7,7 @@ namespace wolf
 {
 
 ProcessorMotion::ProcessorMotion(const std::string& _type,
+                                 std::string _state_structure,
                                  int _dim,
                                  SizeEigen _state_size,
                                  SizeEigen _delta_size,
@@ -25,7 +26,8 @@ ProcessorMotion::ProcessorMotion(const std::string& _type,
         origin_ptr_(),
         last_ptr_(),
         incoming_ptr_(),
-        dt_(0.0), x_(_state_size),
+        dt_(0.0), 
+        x_(_state_size),
         delta_(_delta_size),
         delta_cov_(_delta_cov_size, _delta_cov_size),
         delta_integrated_(_delta_size),
@@ -34,7 +36,8 @@ ProcessorMotion::ProcessorMotion(const std::string& _type,
         jacobian_delta_preint_(delta_cov_size_, delta_cov_size_),
         jacobian_delta_(delta_cov_size_, delta_cov_size_),
         jacobian_calib_(delta_cov_size_, calib_size_)
-{
+{   
+    setStateStructure(_state_structure);
     //
 }
 
@@ -267,7 +270,7 @@ void ProcessorMotion::processCapture(CaptureBasePtr _incoming_ptr)
     // Update state and time stamps
     last_ptr_->setTimeStamp(getCurrentTimeStamp());
     last_ptr_->getFrame()->setTimeStamp(getCurrentTimeStamp());
-    last_ptr_->getFrame()->setState(getCurrentState());
+    last_ptr_->getFrame()->setState(getProblem()->getState(getCurrentTimeStamp()));
 
     if (permittedKeyFrame() && voteForKeyFrame())
     {
@@ -315,7 +318,7 @@ void ProcessorMotion::processCapture(CaptureBasePtr _incoming_ptr)
 
         // create a new frame
         auto frame_new      = getProblem()->emplaceFrame(NON_ESTIMATED,
-                                                        getCurrentState(),
+                                                        getProblem()->getCurrentState(),
                                                         getCurrentTimeStamp());
         // create a new capture
         auto capture_new    = emplaceCapture(frame_new,
@@ -346,6 +349,7 @@ void ProcessorMotion::processCapture(CaptureBasePtr _incoming_ptr)
     postProcess();
 }
 
+// _x needs to have the size of the processor state
 bool ProcessorMotion::getState(const TimeStamp& _ts, Eigen::VectorXd& _x) const
 {
     CaptureMotionPtr capture_motion;
@@ -360,7 +364,7 @@ bool ProcessorMotion::getState(const TimeStamp& _ts, Eigen::VectorXd& _x) const
     {
         // Get origin state and calibration
         CaptureBasePtr cap_orig   = capture_motion->getOriginCapture();
-        VectorXd state_0          = cap_orig->getFrame()->getState();
+        VectorXd state_0          = cap_orig->getFrame()->getState(state_structure_);
         VectorXd calib            = cap_orig->getCalibration();
 
         // Get delta and correct it with new calibration params
@@ -371,7 +375,7 @@ bool ProcessorMotion::getState(const TimeStamp& _ts, Eigen::VectorXd& _x) const
         VectorXd delta            = capture_motion->correctDelta( motion.delta_integr_, delta_step);
 
         // ensure proper size of the provided reference
-        _x.resize( getProblem()->getFrameStructureSize() );
+        _x.resize( state_0.size() );
 
         // Compose on top of origin state using the buffered time stamp, not the query time stamp
         double dt = motion.ts_ - capture_motion->getBuffer().get().front().ts_;
@@ -380,7 +384,7 @@ bool ProcessorMotion::getState(const TimeStamp& _ts, Eigen::VectorXd& _x) const
     else
     {
         // We could not find any CaptureMotion for the time stamp requested
-        WOLF_ERROR("Could not find any Capture for the time stamp requested. ");
+        WOLF_ERROR("Could not find any Capture for the time stamp requested. ", _ts);
         WOLF_TRACE("Did you forget to call Problem::setPrior() in your application?")
         return false;
     }
@@ -415,9 +419,11 @@ void ProcessorMotion::setOrigin(FrameBasePtr _origin_frame)
 
     // ---------- LAST ----------
     // Make non-key-frame for last Capture
+    TimeStamp origin_ts = _origin_frame->getTimeStamp();
     auto new_frame_ptr  = getProblem()->emplaceFrame(NON_ESTIMATED,
-                                                     _origin_frame->getState(),
-                                                     _origin_frame->getTimeStamp());
+                                                      _origin_frame->getState(),
+                                                     origin_ts);
+                                        
     // emplace (emtpy) last Capture
     last_ptr_ = emplaceCapture(new_frame_ptr,
                                getSensor(),
@@ -562,7 +568,8 @@ CaptureMotionPtr ProcessorMotion::findCaptureContainingTimeStamp(const TimeStamp
             ++frame_rev_iter)
     {
         frame   = *frame_rev_iter;
-        capture = frame->getCaptureOf(getSensor());
+        auto sensor = getSensor();
+        capture = frame->getCaptureOf(sensor);
         if (capture != nullptr)
         {
             // Rule 1 satisfied! We found a Capture belonging to this processor's Sensor ==> it is a CaptureMotion
@@ -621,6 +628,9 @@ PackKeyFramePtr ProcessorMotion::computeProcessingStep()
 
 void ProcessorMotion::setProblem(ProblemPtr _problem)
 {
+    std::string str = "Processor works with " + std::to_string(dim_) + "D but problem is " + std::to_string(_problem->getDim()) + "D";
+    assert((dim_ == 0 or dim_ == _problem->getDim()) && str.c_str());
+
     if (_problem == nullptr or _problem == this->getProblem())
         return;
 
@@ -629,11 +639,10 @@ void ProcessorMotion::setProblem(ProblemPtr _problem)
     // set the origin
     if (origin_ptr_ == nullptr && this->getProblem()->getLastKeyFrame() != nullptr)
         this->setOrigin(this->getProblem()->getLastKeyFrame());
-
-    // set the main processor motion
-    if (this->getProblem()->getProcessorMotion() == nullptr)
-        this->getProblem()->setProcessorMotion(std::static_pointer_cast<ProcessorMotion>(shared_from_this()));
-};
+    
+    // adding processor is motion to the processor is motion vector
+    getProblem()->addProcessorIsMotion(std::dynamic_pointer_cast<IsMotion>(shared_from_this()));
+}
 
 bool ProcessorMotion::storeKeyFrame(FrameBasePtr _frame_ptr)
 {
diff --git a/src/processor/processor_odom_2d.cpp b/src/processor/processor_odom_2d.cpp
index c986ebf7cf9cd7fb83df1417ea19c42beed66c74..929c1ed7ceb825fdaa265a1af592fa8125832789 100644
--- a/src/processor/processor_odom_2d.cpp
+++ b/src/processor/processor_odom_2d.cpp
@@ -6,7 +6,7 @@ namespace wolf
 {
 
 ProcessorOdom2d::ProcessorOdom2d(ProcessorParamsOdom2dPtr _params) :
-                ProcessorMotion("ProcessorOdom2d", 2, 3, 3, 3, 2, 0, _params),
+                ProcessorMotion("ProcessorOdom2d", "PO", 2, 3, 3, 3, 2, 0, _params),
                 params_odom_2d_(_params)
 {
     unmeasured_perturbation_cov_ = _params->unmeasured_perturbation_std * _params->unmeasured_perturbation_std * Matrix3d::Identity();
diff --git a/src/processor/processor_odom_3d.cpp b/src/processor/processor_odom_3d.cpp
index 967031e9ccd1a68fcee41567be0f7dbf7523ef2c..3e1268eb1d705b3a335d9c8d9389e0c9449ebba1 100644
--- a/src/processor/processor_odom_3d.cpp
+++ b/src/processor/processor_odom_3d.cpp
@@ -3,7 +3,7 @@ namespace wolf
 {
 
 ProcessorOdom3d::ProcessorOdom3d(ProcessorParamsOdom3dPtr _params) :
-                        ProcessorMotion("ProcessorOdom3d", 3, 7, 7, 6, 6, 0, _params),
+                        ProcessorMotion("ProcessorOdom3d", "PO", 3, 7, 7, 6, 6, 0, _params),
                         params_odom_3d_ (_params),
                         k_disp_to_disp_ (0),
                         k_disp_to_rot_  (0),
diff --git a/test/gtest_factor_block_difference.cpp b/test/gtest_factor_block_difference.cpp
index 20bbe2c42ed27688820569a3da345596da3903f1..1e06c7a80377b99197a721e85473319f9bf34862 100644
--- a/test/gtest_factor_block_difference.cpp
+++ b/test/gtest_factor_block_difference.cpp
@@ -50,18 +50,17 @@ class FixtureFactorBlockDifference : public testing::Test
 
             Vector10d x_origin = problem_->zeroState();
             Eigen::Matrix9d cov_prior = 1e-3 * Eigen::Matrix9d::Identity(); 
-            KF0_ =problem_->setPrior(x_origin, cov_prior, t0, 0.1);
+            KF0_ = problem_->setPrior(x_origin, cov_prior, t0, 0.1);
             
             CaptureBasePtr capV0 = CaptureBase::emplace<CaptureBase>(KF0_, "Vel0", t0);
             FeatureBasePtr featV0 = FeatureBase::emplace<FeatureBase>(capV0, "Vel0", x_origin.tail(3), cov_prior.bottomRightCorner<3,3>());
             FactorBasePtr facV0 = FactorBase::emplace<FactorBlockAbsolute>(featV0, KF0_->getV());
 
-            // KF0_ = problem_->emplaceFrame(KEY, problem_->zeroState(), t0);
             KF1_ = problem_->emplaceFrame(KEY, problem_->zeroState(), t1);
 
-            Cap_ = CaptureBase::emplace<CaptureBase>(KF1_, "DIFF", t1);
+            Cap_ = CaptureBase::emplace<CaptureBase>(KF1_, "BlockDifference", t1);
             Eigen::Matrix3d cov = 0.2 * Eigen::Matrix3d::Identity();
-            Feat_ = FeatureBase::emplace<FeatureBase>(Cap_, "DIFF", zero3, cov);
+            Feat_ = FeatureBase::emplace<FeatureBase>(Cap_, "BlockDifference", zero3, cov);
         }
 
         virtual void TearDown() override {}
@@ -150,6 +149,7 @@ TEST_F(FixtureFactorBlockDifference, DiffPx)
     Feat_->setMeasurementCovariance(cov_diff);
     FactorBlockDifferencePtr Fac = FactorBase::emplace<FactorBlockDifference>(
         Feat_, KF0_->getP(), KF1_->getP(),
+        nullptr, nullptr, nullptr, nullptr,
         0, 1, 0, 1
     );
 
@@ -174,6 +174,7 @@ TEST_F(FixtureFactorBlockDifference, DiffPxy)
     Feat_->setMeasurementCovariance(cov_diff);
     FactorBlockDifferencePtr Fac = FactorBase::emplace<FactorBlockDifference>(
         Feat_, KF0_->getP(), KF1_->getP(),
+        nullptr, nullptr, nullptr, nullptr,
         0, 2, 0, 2
     );
 
@@ -195,6 +196,7 @@ TEST_F(FixtureFactorBlockDifference, DiffPyz)
     Feat_->setMeasurementCovariance(cov_diff);
     FactorBlockDifferencePtr Fac = FactorBase::emplace<FactorBlockDifference>(
         Feat_, KF0_->getP(), KF1_->getP(),
+        nullptr, nullptr, nullptr, nullptr,
         1, 2, 1, 2
     );
 
diff --git a/test/gtest_problem.cpp b/test/gtest_problem.cpp
index e0ba9a42a17936b62ec329c1fb022052d5ae6c30..ae7e14ae893449e8c42df4736eae792dfbd4b20d 100644
--- a/test/gtest_problem.cpp
+++ b/test/gtest_problem.cpp
@@ -94,7 +94,7 @@ TEST(Problem, Processor)
     ProblemPtr P = Problem::create("PO", 3);
 
     // check motion processor is null
-    ASSERT_FALSE(P->getProcessorMotion());
+    ASSERT_FALSE(P->getProcessorIsMotion());
 
     // add a motion sensor and processor
     auto Sm = SensorBase::emplace<SensorOdom3d>(P->getHardware(), (Eigen::Vector7d()<<0,0,0, 0,0,0,1).finished(), ParamsSensorOdom3d());
@@ -103,7 +103,7 @@ TEST(Problem, Processor)
     auto Pm = ProcessorBase::emplace<ProcessorOdom3d>(Sm, std::make_shared<ProcessorParamsOdom3d>());
 
     // check motion processor IS NOT by emplace
-    ASSERT_EQ(P->getProcessorMotion(), Pm);
+    ASSERT_EQ(P->getProcessorIsMotion(), Pm);
 }
 
 TEST(Problem, Installers)
@@ -118,16 +118,16 @@ TEST(Problem, Installers)
     auto pt = P->installProcessor("ProcessorTrackerFeatureDummy", "dummy", "odometer");
 
     // check motion processor IS NOT set
-    ASSERT_FALSE(P->getProcessorMotion());
+    ASSERT_FALSE(P->getProcessorIsMotion());
 
     // install processor motion
     ProcessorBasePtr pm = P->installProcessor("ProcessorOdom3d", "odom integrator", "odometer", wolf_root + "/test/yaml/processor_odom_3d.yaml");
 
     // check motion processor is set
-    ASSERT_TRUE(P->getProcessorMotion());
+    ASSERT_TRUE(P->getProcessorIsMotion() != nullptr);
 
     // check motion processor is correct
-    ASSERT_EQ(std::dynamic_pointer_cast<ProcessorMotion>(P->getProcessorMotion()), pm);
+    ASSERT_EQ(std::dynamic_pointer_cast<ProcessorMotion>(P->getProcessorIsMotion()), pm);
 }
 
 TEST(Problem, SetOrigin_PO_2d)
diff --git a/test/gtest_processor_base.cpp b/test/gtest_processor_base.cpp
index 1933da8599234e61c534e9f05008710ac4396661..c4a1c4b0470c92bf09df1a950a1c19e57d35642d 100644
--- a/test/gtest_processor_base.cpp
+++ b/test/gtest_processor_base.cpp
@@ -125,7 +125,7 @@ TEST(ProcessorBase, KeyFrameCallback)
         capt_trk = make_shared<CaptureVoid>(t, sens_trk);
         proc_trk->captureCallback(capt_trk);
 
-//        problem->print(4,1,1,0);
+       problem->print(4,1,1,0);
 
         // Only odom creating KFs
         ASSERT_TRUE( problem->getLastKeyFrame()->getType().compare("PO 2d")==0 );