diff --git a/src/multibody/joint/joint-planar.hpp b/src/multibody/joint/joint-planar.hpp
index 6faa4b70a131e7f3a082b555695c51cf6a52d408..313c358e9534fa4262996a2d841e7aef7407c1c3 100644
--- a/src/multibody/joint/joint-planar.hpp
+++ b/src/multibody/joint/joint-planar.hpp
@@ -394,31 +394,52 @@ namespace se3
     {
       Eigen::VectorXd::ConstFixedSegmentReturnType<NQ>::Type & q = qs.segment<NQ> (idx_q ());
       Eigen::VectorXd::ConstFixedSegmentReturnType<NV>::Type & q_dot = vs.segment<NV> (idx_v ());
-      typedef Transformation_t::Matrix3 Matrix3;
-     
+      typedef Eigen::Matrix<double, 2, 2> Matrix22;
+      typedef Eigen::Matrix<double, 2, 1> Vector2;
+
       double c0,s0; SINCOS (q(2), &s0, &c0);
-      Matrix3 R0(Matrix3::Identity());
-      R0.topLeftCorner <2,2> () << c0, -s0, s0, c0;
+      Matrix22 R0;
+      R0 << c0, -s0, s0, c0;
       
+      const double& t = q_dot[2];
+      const double theta = std::fabs(t);
+
       ConfigVector_t res(q);
-      if(std::fabs(q_dot(2)) > 1e-14)
+      if(theta > 1e-14)
       {
-        ConfigVector_t tmp(ConfigVector_t::Zero());
-        
-        double c1,s1; SINCOS (q_dot(2), &s1, &c1);
-        const double c_coeff = (1.-c1)/q_dot(2);
-        tmp.head<2>() = s1/q_dot(2)*q_dot.head<2>();
-        tmp(0) -= c_coeff*q_dot(1);
-        tmp(1) += c_coeff*q_dot(0);
-        
-        res.head<2>() += R0.topLeftCorner<2,2>()*tmp.head<2>();
-        res(2) += q_dot(2);
-        
+        // q_dot = [ x, y, t ]
+        // w = [ 0, 0, t ]
+        // v = [ x, y, 0 ]
+        // Considering only the 2x2 top left corner:
+        // Sp = [ 0, -1; 1, 0],
+        // if t > 0: S = Sp
+        // else    : S = -Sp
+        // S / t = Sp / |t|
+        // S * S = - I2
+        // R = I2 + ( 1 - ct) / |t| * S + ( 1 - st / t ) * S * S
+        //   =      ( 1 - ct) / |t| * S +       st / t   * I2
+        //
+        // Ru = exp3 (w)
+        // tu = R * v = (1 - ct) / |t| * S * v + st / t * v
+        //
+        // M0 * Mu = ( R0 * Ru, R0 * tu + t0 )
+
+        Eigen::VectorXd::ConstFixedSegmentReturnType<2>::Type v = vs.segment<2>(idx_v());
+        double ct,st; SINCOS (theta, &st, &ct);
+        const double inv_theta = 1/theta;
+        const double c_coeff = (1.-ct) * inv_theta;
+        const double s_coeff = st * inv_theta;
+        const Vector2 Sp_v (-v[1], v[0]);
+
+        if (t > 0) res.head<2>() += R0 * (s_coeff * v + c_coeff * Sp_v);
+        else       res.head<2>() += R0 * (s_coeff * v - c_coeff * Sp_v);
+        res[2] += t;
         return res;
       }
       else
       {
-        res.head<2>() += R0.topLeftCorner<2,2>()*q_dot.head<2>();
+        res.head<2>() += R0*q_dot.head<2>();
+        res[2] += t;
       }
       
       return res;
@@ -433,6 +454,8 @@ namespace se3
       else if( u == 1) return q_1;
       else
       {
+        // TODO This only works if idx_v() == 0
+        assert(idx_v() == 0);
         TangentVector_t nu(u*difference(q0, q1));
         return integrate(q0, nu);
       }
diff --git a/src/spatial/explog.hpp b/src/spatial/explog.hpp
index 7794b146bbbc93fb848965877e764dab6914dd93..af9966690826cef547ea0a624bd287078cb94a23 100644
--- a/src/spatial/explog.hpp
+++ b/src/spatial/explog.hpp
@@ -83,9 +83,10 @@ namespace se3
     Scalar t = w.norm();
     if (t > 1e-15)
     {
-      Matrix3 S(alphaSkew(1./t, w));
+      const double inv_t = 1./t;
+      Matrix3 S(alphaSkew(inv_t, w));
       double ct,st; SINCOS (t,&st,&ct);
-      Matrix3 V((1. - ct)/t * S + (1. - st/t) * S * S);
+      Matrix3 V((1. - ct) * inv_t * S + (1. - st * inv_t) * S * S);
       Vector3 p(v + V * v);
       return SE3Tpl<_Scalar, _Options>(exp3(w), p);
     }
diff --git a/unittest/joint-configurations.cpp b/unittest/joint-configurations.cpp
index 8deb1215e928562192ce089946022275ef37fcc1..6e908a064d13d1503d416f481c4a0273712b4a5c 100644
--- a/unittest/joint-configurations.cpp
+++ b/unittest/joint-configurations.cpp
@@ -102,6 +102,19 @@ struct TestIntegrationJoint
     
     SE3 M1_exp = M0*exp6(v0);
     BOOST_CHECK(M1.isApprox(M1_exp));
+    
+    qdot *= -1;
+
+    jmodel.calc(jdata,q0,qdot);
+    M0 = jdata.M;
+    v0 = jdata.v;
+    
+    q1 = jmodel.integrate(q0,qdot);
+    jmodel.calc(jdata,q1);
+    M1 = jdata.M;
+    
+    M1_exp = M0*exp6(v0);
+    BOOST_CHECK(M1.isApprox(M1_exp));
   }
   
 };
@@ -175,6 +188,8 @@ struct TestDifferentiationJoint
 
     BOOST_CHECK_MESSAGE( jmodel.integrate(q0, qdot).isApprox(q1), std::string("Error in difference for joint " + jmodel.shortname()));
 
+    BOOST_CHECK_MESSAGE( jmodel.integrate(q1, -qdot).isApprox(q0), std::string("Error in difference for joint " + jmodel.shortname()));
+
   }
 
   void operator()(JointModelBase<JointModelFreeFlyer> & jmodel)