diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 7e757c1210aacc1886568794283f45b7c9acc269..d8ff7e15a2028a1781fe3a7f0ede56e7fca2877d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -438,6 +438,9 @@ ENDIF(OpenCV_FOUND)
 # Add the capture sub-directory
 ADD_SUBDIRECTORY(captures)
 
+# Add the sensor sub-directory
+ADD_SUBDIRECTORY(sensors)
+
 IF (cereal_FOUND)
   ADD_SUBDIRECTORY(serialization/cereal)
 ENDIF(cereal_FOUND)
@@ -479,6 +482,7 @@ ADD_LIBRARY(${PROJECT_NAME}
             ${SRCS_BASE} 
             ${SRCS}
             ${SRCS_CAPTURE}
+            ${SRCS_SENSOR}
             #${SRCS_DTASSC} 
             ${SRCS_WRAPPER}
             )
@@ -530,6 +534,8 @@ INSTALL(FILES ${HDRS}
 #    DESTINATION include/iri-algorithms/wolf/data_association)
 INSTALL(FILES ${HDRS_CAPTURE}
     DESTINATION include/iri-algorithms/wolf/captures)
+INSTALL(FILES ${HDRS_SENSOR}
+    DESTINATION include/iri-algorithms/wolf/sensors)
 INSTALL(FILES ${HDRS_WRAPPER}
     DESTINATION include/iri-algorithms/wolf/ceres_wrapper)
 INSTALL(FILES ${HDRS_SOLVER}
diff --git a/src/sensors/CMakeLists.txt b/src/sensors/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..65520638ce8de1fd3e7200873e0b95f0b1ba22c3
--- /dev/null
+++ b/src/sensors/CMakeLists.txt
@@ -0,0 +1,11 @@
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+
+# Forward var to parent scope
+
+SET(HDRS_SENSOR ${HDRS_SENSOR}
+                ${CMAKE_CURRENT_SOURCE_DIR}/diff_drive_tools.h
+                ${CMAKE_CURRENT_SOURCE_DIR}/diff_drive_tools.hpp
+                ${CMAKE_CURRENT_SOURCE_DIR}/sensor_diff_drive.h PARENT_SCOPE)
+
+SET(SRCS_SENSOR ${SRCS_SENSOR}
+                ${CMAKE_CURRENT_SOURCE_DIR}/sensor_diff_drive.cpp PARENT_SCOPE)
diff --git a/src/sensors/diff_drive_tools.h b/src/sensors/diff_drive_tools.h
new file mode 100644
index 0000000000000000000000000000000000000000..c95784001db1a2f952ae1cd4b870766294fd0c4f
--- /dev/null
+++ b/src/sensors/diff_drive_tools.h
@@ -0,0 +1,421 @@
+/**
+ * \file diff_drive_tools.h
+ *
+ *  Created on: Oct 20, 2016
+ *  \author: Jeremie Deray
+ */
+
+#ifndef _WOLF_PROCESSOR_DIFF_DRIVE_TOOLS_H_
+#define _WOLF_PROCESSOR_DIFF_DRIVE_TOOLS_H_
+
+#include "../eigen_checks.h"
+
+namespace wolf {
+
+enum class DiffDriveModel : std::size_t
+{
+  Two_Factor_Model   = 0,
+  Three_Factor_Model = 1,
+  Five_Factor_Model  = 2
+};
+
+constexpr double ANGULAR_VELOCITY_MIN(1e-8);
+
+/**
+ * @brief computeDiffDriveComand. Compute wheels velocity comands given
+ * linear and angular velocity.
+ *
+ * @param comand. Linear and angular velocity comands.
+ * @param wheel_comand. Wheels velocity comands.
+ *
+ * @param left_radius. Left wheel radius.
+ * @param right_radius. Right wheel radius.
+ * @param separation. Wheels separation.
+ */
+//template <typename T0, typename T1>
+//void computeDiffDriveComand(const Eigen::MatrixBase<T0> &comand,
+//                            Eigen::MatrixBase<T1> &wheel_comand,
+//                            const typename T1::Scalar left_radius,
+//                            const typename T1::Scalar right_radius,
+//                            const typename T1::Scalar separation)
+//{
+//  Eigen::VectorSizeCheck<2>::check(comand);
+
+//  using T = typename T1::Scalar;
+
+//  const T linear  = comand(0);
+//  const T angular = comand(1);
+
+//  wheel_comand = Eigen::Matrix<T, 2, 1>((linear - angular * separation * T(0.5)) / left_radius,
+//                                        (linear + angular * separation * T(0.5)) / right_radius);
+//}
+
+/**
+ * @brief computeDiffDriveComand. Compute wheels velocity comands given
+ * linear and angular velocity.
+ *
+ * @param comand. Linear and angular velocity comands.
+ * @param wheel_comand. Wheels velocity comands.
+ *
+ * @param wheel_radius. Wheel radius.
+ * @param separation. Wheels separation.
+ */
+//template <typename T0, typename T1>
+//void computeDiffDriveComand(const Eigen::MatrixBase<T0> &comand,
+//                            Eigen::MatrixBase<T1> &wheel_comand,
+//                            const typename T1::Scalar wheel_radius,
+//                            const typename T1::Scalar separation)
+//{
+//  computeDiffDriveComand(comand, wheel_comand,
+//                         wheel_radius, wheel_radius, separation);
+//}
+
+/**
+ * @brief VelocityComand. Holds a velocity comand vector
+ * together with its covariance.
+ *
+ * @note
+ * 2d : [linear_x, angular]
+ *
+ */
+template <typename Scalar = double>
+struct VelocityComand
+{
+  Eigen::Matrix<Scalar, Eigen::Dynamic, 1>              comand;
+  Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> comand_cov;
+};
+
+namespace detail {
+
+template <DiffDriveModel>
+struct wheelPositionIncrementToVelocityHelper
+{
+  template <typename T0, typename T1, typename T2>
+  static std::tuple<VelocityComand<typename T0::Scalar>,
+                    Eigen::Matrix<typename T0::Scalar, 2, 2>,
+                    Eigen::Matrix<typename T0::Scalar, 2, 3>>
+  wheelPositionIncrementToVelocity(const Eigen::MatrixBase<T0>& position_increment,
+                                   const Eigen::MatrixBase<T1>& position_increment_cov,
+                                   const typename T0::Scalar    left_radius,
+                                   const typename T0::Scalar    right_radius,
+                                   const typename T0::Scalar    separation,
+                                   const Eigen::MatrixBase<T2>& factors,
+                                   const typename T0::Scalar    dt);
+};
+
+} /* namespace detail */
+
+/**
+ * @brief Convert from wheels joint positions to per-wheel velocity comands.
+ * @param[in] position_increment. A vector containing the wheels position increments.
+ * @param[in] position_increment_cov. The covariance associated to the vector position_increment.
+ * @param[in] left_radius. The left wheel radius.
+ * @param[in] right_radius. The right wheel radius.
+ * @param[in] separation. The distance separing both wheels.
+ * @param[in] factors. The diff-drive correction factors (calibration).
+ * @param[in] dt. UNUSED.
+ *
+ * @return std::tuple. First element is the computed VelocityComand,
+ * second element is the Jacobian matrix J_vel_data,
+ * third element is the Jacobian matrix J_vel_factor.
+ */
+template <DiffDriveModel M, typename T0, typename T1, typename T2>
+std::tuple<VelocityComand<typename T0::Scalar>,
+           Eigen::Matrix<typename T0::Scalar, 2, 2>,
+           Eigen::Matrix<typename T0::Scalar, 2, 3>>
+wheelPositionIncrementToVelocity(const Eigen::MatrixBase<T0>& position_increment,
+                                 const Eigen::MatrixBase<T1>& position_increment_cov,
+                                 const typename T0::Scalar    left_radius,
+                                 const typename T0::Scalar    right_radius,
+                                 const typename T0::Scalar    separation,
+                                 const Eigen::MatrixBase<T2>& factors,
+                                 const typename T0::Scalar    dt)
+{
+  return detail::wheelPositionIncrementToVelocityHelper<M>::wheelPositionIncrementToVelocity(
+        position_increment, position_increment_cov,
+        left_radius, right_radius, separation,
+        factors, dt);
+}
+
+/**
+ * @brief WheelPositionAbsoluteToIncrement.
+ * Simple class to convert from absolute position to increment position.
+ *
+ * @todo handle num wheels 4-6-etc
+ */
+template <typename T>
+class WheelPositionAbsoluteToIncrement
+{
+public:
+
+  WheelPositionAbsoluteToIncrement()  = default;
+  ~WheelPositionAbsoluteToIncrement() = default;
+
+  template <typename T0>
+  WheelPositionAbsoluteToIncrement(const Eigen::MatrixBase<T0>& positions)
+  {
+    init(positions);
+  }
+
+  inline bool init() const noexcept { return init_; }
+
+  template <typename T0>
+  void update(const Eigen::MatrixBase<T0>& positions)
+  {
+    Eigen::VectorSizeCheck<2>::check(positions);
+
+    positions_ = positions.template cast<T>();
+  }
+
+  template <typename T0>
+  void init(const Eigen::MatrixBase<T0>& positions)
+  {
+    update(positions);
+
+    init_ = true;
+  }
+
+  template <typename T0, typename T1>
+  void toIncrement(const Eigen::MatrixBase<T0>& positions,
+                   Eigen::MatrixBase<T1>& positions_increment)
+  {
+    Eigen::VectorSizeCheck<2>::check(positions);
+
+    if (!init_) init(positions);
+
+    positions_increment =
+        (positions - positions_.template cast<typename T0::Scalar>()).
+          template cast<typename T1::Scalar>();
+  }
+
+  template <typename T0, typename T1>
+  void operator() (const Eigen::MatrixBase<T0>& positions,
+                   Eigen::MatrixBase<T1>& positions_increment)
+  {
+    toIncrement(positions, positions_increment);
+    update(positions);
+  }
+
+protected:
+
+  bool init_ = false;
+
+  Eigen::Matrix<T, Eigen::Dynamic, 1> positions_;
+};
+
+/**
+ * @brief integrateRungeKutta. Runge-Kutta 2nd order integration.
+ *
+ * @param[in] data. The input linear and angular velocities.
+ * @param[in] data_cov. The covariance matrix associated to data.
+ * @param[out] delta. The computed delta (2d).
+ * @param[out] delta_cov. The covariance matrix associated to delta.
+ * @param[out] jacobian. The Jacobian matrix J_delta_vel
+ *
+ * @note
+ *
+ * Linear  velocity [m]   (linear  displacement, i.e.   m/s * dt)
+ * Angular velocity [rad] (angular displacement, i.e. rad/s * dt)
+ *
+ * MATHS of delta
+ * dx  = dv * cos( dw * 0.5 )
+ * dy  = dv * sin( dw * 0.5 )
+ * dth = dw
+ */
+template <typename T0, typename T1, typename T2, typename T3, typename T4>
+void integrateRungeKutta(const Eigen::MatrixBase<T0> &data,
+                         const Eigen::MatrixBase<T1> &data_cov,
+                         Eigen::MatrixBase<T2>       &delta,
+                         Eigen::MatrixBase<T3>       &delta_cov,
+                         Eigen::MatrixBase<T4>       &jacobian)
+{
+  using std::sin;
+  using std::cos;
+
+  /// @note data is size 3 -> linear vel on x + angular vel on yaw
+  Eigen::VectorSizeCheck<2>::check(data);
+  /// @todo check dim
+  Eigen::MatrixSizeCheck<2,2>::check(data_cov);
+
+  using T = typename T2::Scalar;
+
+  const T v = data(0);
+  const T w = data(1);
+
+  const T w_05 = w * T(.5);
+
+  const T cos_w_05 = cos(w_05);
+  const T sin_w_05 = sin(w_05);
+
+  delta = Eigen::Matrix<T, 3, 1>(cos_w_05 * v,
+                                 sin_w_05 * v,
+                                      w       );
+  // Fill delta covariance
+  Eigen::Matrix<typename T3::Scalar,
+      Eigen::MatrixBase<T2>::RowsAtCompileTime,
+      Eigen::MatrixBase<T0>::RowsAtCompileTime> J;
+
+  J.setZero(delta.rows(), data.rows());
+
+  // Compute jacobian
+  jacobian =
+      Eigen::Matrix<typename T4::Scalar,
+        Eigen::MatrixBase<T2>::RowsAtCompileTime,
+        Eigen::MatrixBase<T0>::RowsAtCompileTime>::Zero(delta.rows(), data.rows());
+
+  Eigen::MatrixSizeCheck<3,2>::check(jacobian);
+
+  jacobian(0,0) =  cos_w_05;
+  jacobian(1,0) =  sin_w_05;
+  jacobian(2,0) =  typename T3::Scalar(0);
+
+  jacobian(0,1) = -v * sin_w_05 * typename T3::Scalar(.5);
+  jacobian(1,1) =  v * cos_w_05 * typename T3::Scalar(.5);
+  jacobian(2,1) =  typename T3::Scalar(1);
+
+  // Fill delta covariance
+  delta_cov = J * data_cov * J.transpose();
+}
+
+/**
+ * @brief integrateExact. Exact integration.
+ *
+ * @param[in] data. The input linear and angular velocities.
+ * @param[in] data_cov. The covariance matrix associated to data.
+ * @param[out] delta. The computed delta (2d).
+ * @param[out] delta_cov. The covariance matrix associated to delta.
+ * @param[out] jacobian. The Jacobian matrix J_delta_vel
+ *
+ * @note
+ *
+ * Linear  velocity [m]   (linear  displacement, i.e.   m/s * dt)
+ * Angular velocity [rad] (angular displacement, i.e. rad/s * dt)
+ *
+ * MATHS of delta
+ * dx  =  dv / dw * (sin(dw) - sin(0))
+ * dy  = -dv / dw * (cos(dw) - cos(0))
+ * dth =  dw
+ */
+template <typename T0, typename T1, typename T2, typename T3, typename T4>
+void integrateExact(const Eigen::MatrixBase<T0> &data,
+                    const Eigen::MatrixBase<T1> &data_cov,
+                    Eigen::MatrixBase<T2>       &delta,
+                    Eigen::MatrixBase<T3>       &delta_cov,
+                    Eigen::MatrixBase<T4>       &jacobian)
+{
+  using std::sin;
+  using std::cos;
+
+  /// @note data is size 3 -> linear vel on x & y + angular vel on yaw
+  Eigen::VectorSizeCheck<2>::check(data);
+  /// @todo check dim
+  Eigen::MatrixSizeCheck<2,2>::check(data_cov);
+
+  using T = typename T2::Scalar;
+
+  // Compute delta
+
+  const T v = data(0);
+  const T w = data(1);
+
+  const T inv_w  = T(1) / w;
+
+  const T r =  v * inv_w;
+
+  const T theta_1 = w;
+
+  const T sin_theta_0 = 0;
+  const T cos_theta_0 = 1;
+
+  const T sin_theta_1 = sin(theta_1);
+  const T cos_theta_1 = cos(theta_1);
+
+  const T sin_diff = sin_theta_1 - sin_theta_0;
+  const T cos_diff = cos_theta_1 - cos_theta_0;
+
+  delta = Eigen::Matrix<T, 3, 1>( r * sin_diff,
+                                 -r * cos_diff,
+                                      w       );
+
+  const T inv_w2 = inv_w * inv_w;
+
+  // Compute jacobian
+  jacobian =
+      Eigen::Matrix<typename T4::Scalar,
+        Eigen::MatrixBase<T2>::RowsAtCompileTime,
+        Eigen::MatrixBase<T0>::RowsAtCompileTime>::Zero(delta.rows(), data.rows());
+
+  Eigen::MatrixSizeCheck<3,2>::check(jacobian);
+
+  jacobian(0,0) =  sin_diff * inv_w;
+  jacobian(1,0) = -cos_diff * inv_w;
+  jacobian(2,0) = T(0);
+
+  jacobian(0,1) =  (v * cos_theta_1 * inv_w) - (v * sin_diff * inv_w2);
+  jacobian(1,1) =  (v * sin_theta_1 * inv_w) + (v * cos_diff * inv_w2);
+  jacobian(2,1) =  T(1);
+
+  // Fill delta covariance
+  delta_cov = jacobian * data_cov * jacobian.transpose();
+}
+
+
+/**
+ * @brief integrate. Helper function to call either
+ * `integrateRung` or `integrateExact` depending on the
+ * angular velocity value.
+ *
+ * @see integrateRungeKutta
+ * @see integrateExact
+ * @see ANGULAR_VELOCITY_MIN
+ */
+template <typename T0, typename T1, typename T2, typename T3, typename T4>
+void integrate(const Eigen::MatrixBase<T0>& data,
+               const Eigen::MatrixBase<T1>& data_cov,
+               Eigen::MatrixBase<T2>& delta,
+               Eigen::MatrixBase<T3>& delta_cov,
+               Eigen::MatrixBase<T4>& jacobian)
+{
+  (data(1) < ANGULAR_VELOCITY_MIN) ?
+        integrateRungeKutta(data, data_cov, delta, delta_cov, jacobian) :
+        integrateExact(data, data_cov, delta, delta_cov, jacobian);
+}
+
+/**
+ * @brief computeWheelJointPositionCov. Compute a covariance matrix to associate
+ * to wheel position increment.
+ *
+ * Set covariance matrix (diagonal):
+ * second term is the wheel resolution covariance,
+ * similar to a DC offset equal to half of the resolution,
+ * which is the theoretical average error.
+ */
+template <typename T>
+Eigen::Matrix<typename T::Scalar, 2, 2> computeWheelJointPositionCov(
+    const Eigen::MatrixBase<T>& data,
+    const typename T::Scalar left_wheel_resolution,
+    const typename T::Scalar right_wheel_resolution,
+    const typename T::Scalar left_wheel_cov_gain,
+    const typename T::Scalar right_wheel_cov_gain)
+{
+  using std::abs;
+
+  Eigen::VectorSizeCheck<2>::check(data);
+
+  using S = typename T::Scalar;
+
+  const S dp_var_l = left_wheel_cov_gain  * abs(data(0));
+  const S dp_var_r = right_wheel_cov_gain * abs(data(1));
+
+  Eigen::Matrix<S, 2, 2> data_cov;
+  data_cov << dp_var_l + (left_wheel_resolution  * S(0.5)), 0,
+              0, dp_var_r + (right_wheel_resolution * S(0.5));
+
+  return data_cov;
+}
+
+} // namespace wolf
+
+#include "diff_drive_tools.hpp"
+
+#endif /* _WOLF_PROCESSOR_DIFF_DRIVE_TOOLS_H_ */
diff --git a/src/sensors/diff_drive_tools.hpp b/src/sensors/diff_drive_tools.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..f70ca2c373796de8eccfff4debb6cb9ae9b7fab9
--- /dev/null
+++ b/src/sensors/diff_drive_tools.hpp
@@ -0,0 +1,115 @@
+/**
+ * \file diff_drive_tools.h
+ *
+ *  Created on: Oct 20, 2016
+ *  \author: Jeremie Deray
+ */
+
+#ifndef _WOLF_PROCESSOR_DIFF_DRIVE_TOOLS_HPP_
+#define _WOLF_PROCESSOR_DIFF_DRIVE_TOOLS_HPP_
+
+// un-comment for IDE highlight
+//#include "diff_drive_tools.h"
+#include <tuple>
+
+namespace wolf {
+namespace detail {
+
+template <>
+template <typename T0, typename T1, typename T2>
+std::tuple<VelocityComand<typename T0::Scalar>, Eigen::Matrix<typename T0::Scalar, 2, 2>, Eigen::Matrix<typename T0::Scalar, 2, 3>>
+wheelPositionIncrementToVelocityHelper<DiffDriveModel::Two_Factor_Model>::wheelPositionIncrementToVelocity(
+    const Eigen::MatrixBase<T0>& position_increment,
+    const Eigen::MatrixBase<T1>& position_increment_cov,
+    const typename T0::Scalar left_radius,
+    const typename T0::Scalar right_radius,
+    const typename T0::Scalar separation,
+    const Eigen::MatrixBase<T2>& factors,
+    const typename T0::Scalar /*dt*/)
+{ 
+  Eigen::VectorSizeCheck<2>::check(position_increment);
+  Eigen::MatrixSizeCheck<2,2>::check(position_increment_cov);
+
+  Eigen::VectorSizeCheck<2>::check(factors);
+
+  using T = typename T0::Scalar;
+
+  const T left_wheel_vel  = (left_radius  * factors(0)) * position_increment(0);
+  const T right_wheel_vel = (right_radius * factors(0)) * position_increment(1);
+
+  const T o_5(0.5);
+  const T s_f = separation * factors(1);
+
+  const Eigen::Matrix<T, 2, 1> comand =
+      Eigen::Matrix<T, 2, 1>((right_wheel_vel + left_wheel_vel) * o_5,
+                             (right_wheel_vel - left_wheel_vel) / s_f) /* * dt*/;
+
+  const T p_r = position_increment(1) * right_radius;
+  const T p_l = position_increment(0) * left_radius;
+
+  Eigen::Matrix<T, 2, 2> J_vel_posinc;
+
+  J_vel_posinc << left_radius * factors(0) * o_5 ,  right_radius * factors(1) * o_5,
+                   left_radius * factors(0) / s_f, -right_radius * factors(1) / s_f;
+
+  Eigen::Matrix<T, 2, 3> J_vel_factor;
+
+  J_vel_factor << (p_l + p_r) * o_5,   0,
+                  (p_l - p_r) / s_f,  ((p_r - p_l) * factors(0)) / (s_f * factors(1));
+
+  const Eigen::Matrix<T, 2, 2> comand_cov = J_vel_posinc * position_increment_cov * J_vel_posinc.transpose();
+
+  return std::make_tuple(VelocityComand<T>{comand, comand_cov}, J_vel_posinc, J_vel_factor);
+}
+
+template <>
+template <typename T0, typename T1, typename T2>
+std::tuple<VelocityComand<typename T0::Scalar>, Eigen::Matrix<typename T0::Scalar, 2, 2>, Eigen::Matrix<typename T0::Scalar, 2, 3>>
+wheelPositionIncrementToVelocityHelper<DiffDriveModel::Three_Factor_Model>::wheelPositionIncrementToVelocity(
+    const Eigen::MatrixBase<T0>& position_increment,
+    const Eigen::MatrixBase<T1>& position_increment_cov,
+    const typename T0::Scalar left_radius,
+    const typename T0::Scalar right_radius,
+    const typename T0::Scalar separation,
+    const Eigen::MatrixBase<T2>& factors,
+    const typename T0::Scalar /*dt*/)
+{
+  Eigen::VectorSizeCheck<2>::check(position_increment);
+  Eigen::MatrixSizeCheck<2,2>::check(position_increment_cov);
+
+  Eigen::VectorSizeCheck<3>::check(factors);
+
+  using T = typename T0::Scalar;
+
+  const T left_wheel_vel  = (left_radius  * factors(0)) * position_increment(0);
+  const T right_wheel_vel = (right_radius * factors(1)) * position_increment(1);
+
+  const T o_5(0.5);
+  const T s_f = separation * factors(2);
+
+  const Eigen::Matrix<T, 2, 1> comand =
+      Eigen::Matrix<T, 2, 1>((right_wheel_vel + left_wheel_vel) * o_5,
+                             (right_wheel_vel - left_wheel_vel) / s_f) /* * dt*/;
+
+  const T p_l = position_increment(0) * left_radius;
+  const T p_r = position_increment(1) * right_radius;
+
+  Eigen::Matrix<T, 2, 2> J_vel_posinc;
+
+  J_vel_posinc << left_radius * factors(0) * o_5 , right_radius * factors(1) * o_5,
+                   left_radius * factors(0) / s_f, -right_radius * factors(1) / s_f;
+
+  Eigen::Matrix<T, 2, 3> J_vel_factor;
+
+  J_vel_factor << p_l * o_5,   p_r * o_5,     0,
+                  p_l / s_f,  -p_r / s_f,  (p_r * factors(1) - p_l * factors(0)) / (s_f * factors(2));
+
+  const Eigen::Matrix<T, 2, 2> comand_cov = J_vel_posinc * position_increment_cov * J_vel_posinc.transpose();
+
+  return std::make_tuple(VelocityComand<T>{comand, comand_cov}, J_vel_posinc, J_vel_factor);
+}
+
+} /* namespace detail */
+} /* namespace wolf */
+
+#endif /* _WOLF_PROCESSOR_DIFF_DRIVE_TOOLS_HPP_ */
diff --git a/src/sensors/sensor_diff_drive.cpp b/src/sensors/sensor_diff_drive.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ae484a9c3f15cba753544a6b8d0b6ca45595a464
--- /dev/null
+++ b/src/sensors/sensor_diff_drive.cpp
@@ -0,0 +1,133 @@
+#include "sensor_diff_drive.h"
+#include "state_block.h"
+#include "capture_motion.h"
+#include "eigen_checks.h"
+
+namespace wolf {
+
+SensorDiffDrive::SensorDiffDrive(const StateBlockPtr& _p_ptr,
+                                 const StateBlockPtr& _o_ptr,
+                                 const StateBlockPtr& _i_ptr,
+                                 const IntrinsicsDiffDrivePtr& _intrinsics) :
+  SensorBase("DIFF DRIVE", _p_ptr, _o_ptr, _i_ptr, 2, false, true),
+  intrinsics_ptr_{_intrinsics}
+{
+  //
+}
+
+// Define the factory method
+SensorBasePtr SensorDiffDrive::create(const std::string& _unique_name,
+                                      const Eigen::VectorXs& _extrinsics_po,
+                                      const IntrinsicsBasePtr _intrinsics)
+{
+  Eigen::VectorSizeCheck<3>::check(_extrinsics_po);
+
+  // cast intrinsics into derived type
+  IntrinsicsDiffDrivePtr params = std::dynamic_pointer_cast<IntrinsicsDiffDrive>(_intrinsics);
+
+  if (params == nullptr)
+  {
+    WOLF_ERROR("SensorDiffDrive::create expected IntrinsicsDiffDrive !");
+    return nullptr;
+  }
+
+  StateBlockPtr pos_ptr = std::make_shared<StateBlock>(_extrinsics_po.head(2), true);
+  StateBlockPtr ori_ptr = std::make_shared<StateBlock>(_extrinsics_po.tail(1), true);
+  StateBlockPtr int_ptr = std::make_shared<StateBlock>(params->factors_,       true);
+
+  SensorBasePtr odo = std::make_shared<SensorDiffDrive>(pos_ptr, ori_ptr, int_ptr, params);
+
+  odo->setName(_unique_name);
+
+  return odo;
+}
+
+
+/// @todo Further work to enforce wheel model
+
+//const IntrinsicsDiffDrive& SensorDiffDrive::getIntrinsics()
+//{
+////  if (intrinsic_ptr_)
+////  {
+////    const auto& intrinsics = intrinsic_ptr_->getVector();
+
+////    intrinsics_.left_radius_factor_  = intrinsics(0);
+////    intrinsics_.right_radius_factor_ = intrinsics(1);
+////    intrinsics_.separation_factor_   = intrinsics(2);
+////  }
+
+//  return intrinsics_;
+//}
+
+//void SensorDiffDrive::initIntrisicsPtr()
+//{
+//  assert(intrinsic_ptr_ == nullptr &&
+//         "SensorDiffDrive::initIntrisicsPtr should only be called once at construction.");
+
+//  Eigen::Vector3s state;
+//  state << intrinsics_.left_radius_factor_,
+//           intrinsics_.right_radius_factor_,
+//           intrinsics_.separation_factor_;
+
+//  assert(state(0) > 0 && "The left_radius_factor should be rather close to 1.");
+//  assert(state(1) > 0 && "The right_radius_factor should be rather close to 1.");
+//  assert(state(2) > 0 && "The separation_factor should be rather close to 1.");
+
+//  intrinsic_ptr_ = new StateBlock(state);
+//}
+
+//void SensorDiffDrive::computeDataCov(const Eigen::Vector2s &_data, Eigen::Matrix2s &_data_cov)
+//{
+//  const double dp_std_l = intrinsics_.left_gain_  * _data(0);
+//  const double dp_std_r = intrinsics_.right_gain_ * _data(1);
+
+//  const double dp_var_l = dp_std_l * dp_std_l;
+//  const double dp_var_r = dp_std_r * dp_std_r;
+
+//  /// Wheel resolution covariance, which is like a DC offset equal to half of
+//  /// the resolution, which is the theoretical average error:
+//  const double dp_std_avg = Scalar(0.5) * intrinsics_.left_resolution_;
+//  const double dp_var_avg = dp_std_avg * dp_std_avg;
+
+//  /// Set covariance matrix (diagonal):
+//  _data_cov.diagonal() << dp_var_l + dp_var_avg,
+//                          dp_var_r + dp_var_avg;
+//}
+
+// This overload is probably not the best solution as it forces
+// me to call addCapture from a SensorDiffDrivePtr whereas
+// problem->installSensor() return a SensorBasePtr.
+//bool SensorDiffDrive::addCapture(CaptureBasePtr _capture_ptr)
+//{
+//  std::shared_ptr<CaptureMotion> capture_ptr = std::static_pointer_cast<CaptureMotion>(_capture_ptr);
+
+//  if (intrinsics_.data_is_position_)
+//  {
+//    Eigen::Vector2s data = capture_ptr->getData();
+
+//    // dt is set to one as we are dealing with wheel position
+//    data = pose_inc_(data, intrinsics_.left_radius_, intrinsics_.right_radius_,
+//                     intrinsics_.separation_, 1);
+
+//    capture_ptr->setData(data);
+
+//    Eigen::Matrix2s data_cov;
+//    data_cov << 0.00001, 0, 0, 0.00001; // Todo
+
+//    computeDataCov(data, data_cov);
+
+//    capture_ptr->setDataCovariance(data_cov);
+//  }
+
+//  /// @todo tofix
+//  return false;//SensorBase::addCapture(_capture_ptr);
+//}
+
+} // namespace wolf
+
+
+// Register in the SensorFactory
+#include "sensor_factory.h"
+namespace wolf {
+WOLF_REGISTER_SENSOR("DIFF DRIVE", SensorDiffDrive)
+} // namespace wolf
diff --git a/src/sensors/sensor_diff_drive.h b/src/sensors/sensor_diff_drive.h
new file mode 100644
index 0000000000000000000000000000000000000000..334fea3895676f923f84625997caf79b4637bafc
--- /dev/null
+++ b/src/sensors/sensor_diff_drive.h
@@ -0,0 +1,107 @@
+/**
+ * \file sensor_diff_drive.h
+ *
+ *  Created on: Oct 20, 2016
+ *  \author: Jeremie Deray
+ */
+
+#ifndef WOLF_SENSOR_DIFF_DRIVE_H_
+#define WOLF_SENSOR_DIFF_DRIVE_H_
+
+//wolf includes
+#include "../sensor_base.h"
+#include "diff_drive_tools.h"
+
+namespace wolf {
+
+struct IntrinsicsDiffDrive : public IntrinsicsBase
+{
+  IntrinsicsDiffDrive() = default;
+
+  IntrinsicsDiffDrive(const Scalar _left_radius,
+                      const Scalar _right_radius,
+                      const Scalar _separation,
+                      const DiffDriveModel _model,
+                      const Eigen::VectorXs& _factors,
+                      const Scalar _left_resolution,
+                      const Scalar _right_resolution,
+                      const Scalar _left_gain,
+                      const Scalar _right_gain) :
+    left_radius_(_left_radius),
+    right_radius_(_right_radius),
+    separation_(_separation),
+    model_(_model),
+    factors_(_factors),
+    left_resolution_(_left_resolution),
+    right_resolution_(_right_resolution),
+    left_gain_(_left_gain),
+    right_gain_(_right_gain)
+  {
+    //
+  }
+
+  Scalar left_radius_;
+  Scalar right_radius_;
+  Scalar separation_;
+
+  DiffDriveModel model_ = DiffDriveModel::Three_Factor_Model;
+
+  Eigen::VectorXs factors_ = Eigen::Vector3s(1, 1, 1);
+
+  Scalar left_resolution_;
+  Scalar right_resolution_;
+
+  Scalar left_gain_  = 0.01;
+  Scalar right_gain_ = 0.01;
+};
+
+typedef std::shared_ptr<IntrinsicsDiffDrive> IntrinsicsDiffDrivePtr;
+
+class SensorDiffDrive : public SensorBase
+{
+public:
+
+  /**
+   * \brief Constructor with arguments
+   *
+   * Constructor with arguments
+   * \param _p_ptr StateBlock pointer to the sensor position wrt vehicle base.
+   * \param _o_ptr StateBlock pointer to the sensor orientation wrt vehicle base.
+   * \param _i_ptr StateBlock pointer to the sensor dynamic intrinsics (factors).
+   * \param _intrinsics The intrinsics parameters of the sensor.
+   *
+   **/
+  SensorDiffDrive(const StateBlockPtr& _p_ptr,
+                  const StateBlockPtr& _o_ptr,
+                  const StateBlockPtr& _i_ptr,
+                  const IntrinsicsDiffDrivePtr& _intrinsics);
+
+  /**
+   * \brief Default destructor (not recommended)
+   **/
+  virtual ~SensorDiffDrive() = default;
+
+  inline IntrinsicsDiffDrivePtr getIntrinsics() const {return intrinsics_ptr_;}
+
+protected:
+
+  IntrinsicsDiffDrivePtr intrinsics_ptr_;
+
+public:
+
+  /**
+   * @brief create. Factory function to create a SensorDiffDrive.
+   * @param _unique_name. A unique name for the sensor.
+   * @param _extrinsics_po. The (2d) position of the sensor w.r.t to the robot base frame.
+   * @param _intrinsics. The sensor extrinsics parameters.
+   * @return a SensorBasePtr holding the sensor. If the sensor creation failed,
+   * the returned pointer is nullptr.
+   */
+  static SensorBasePtr create(const std::string& _unique_name,
+                              const Eigen::VectorXs& _extrinsics_po,
+                              const IntrinsicsBasePtr _intrinsics);
+};
+
+} // namespace wolf
+
+#endif /* WOLF_SENSOR_DIFF_DRIVE_H_ */