diff --git a/src/multibody/joint/joint-free-flyer.hpp b/src/multibody/joint/joint-free-flyer.hpp index e35e17a267ea91e49c973c14e60707ad4b658f58..c27d91e4f75f50cf61142feaf9abd68a70a16bea 100644 --- a/src/multibody/joint/joint-free-flyer.hpp +++ b/src/multibody/joint/joint-free-flyer.hpp @@ -351,30 +351,10 @@ namespace se3 Eigen::VectorXd::ConstFixedSegmentReturnType<NQ>::Type & q_0 = q0.segment<NQ> (idx_q ()); Eigen::VectorXd::ConstFixedSegmentReturnType<NQ>::Type & q_1 = q1.segment<NQ> (idx_q ()); - TangentVector_t result; - // Translational part - result.head<3>() << q_1.head<3> () - q_0.head<3> (); + Transformation_t M0(Transformation_t::Identity()); forwardKinematics(M0, q_0); + Transformation_t M1(Transformation_t::Identity()); forwardKinematics(M1, q_1); - // Quaternion part - // Compute relative rotation between q0 and q1. - ConstQuaternionMap_t quat0 (q_0.segment<4>(3).data()); - ConstQuaternionMap_t quat1 (q_1.segment<4>(3).data()); - - const Motion_t::Quaternion_t quat_relatif (quat1*quat0.conjugate()); - - if (quat_relatif.vec().norm() < 1e-8) // TODO: The value 1e-8 must be changed according to the precision of the current real. - result.tail<3> ().setZero(); - else - { - const Scalar theta = 2.*acos(quat_relatif.w()); - - if (quat0.dot(quat1) >= 0.) - result.tail<3>() << theta * quat_relatif.vec().normalized(); - else - result.tail<3>() << -(2*PI-theta) * quat_relatif.vec().normalized(); - } - - return result; + return se3::log6(M0.inverse()*M1); } double distance_impl(const Eigen::VectorXd & q0,const Eigen::VectorXd & q1) const diff --git a/src/multibody/joint/joint-planar.hpp b/src/multibody/joint/joint-planar.hpp index eb47958f4558b1afb3bced12e31a298a877f137b..f27b613a526e06d3caae406a3ce42d8dd90164af 100644 --- a/src/multibody/joint/joint-planar.hpp +++ b/src/multibody/joint/joint-planar.hpp @@ -429,6 +429,7 @@ namespace se3 Eigen::VectorXd::ConstFixedSegmentReturnType<NQ>::Type & q_0 = q0.segment<NQ> (idx_q ()); Eigen::VectorXd::ConstFixedSegmentReturnType<NQ>::Type & q_1 = q1.segment<NQ> (idx_q ()); + return ConfigVector_t((1-u) * q_0 + u * q_1); } @@ -460,8 +461,18 @@ namespace se3 { Eigen::VectorXd::ConstFixedSegmentReturnType<NQ>::Type & q_0 = q0.segment<NQ> (idx_q ()); Eigen::VectorXd::ConstFixedSegmentReturnType<NQ>::Type & q_1 = q1.segment<NQ> (idx_q ()); + typedef Transformation_t::Matrix3 Matrix3; + + Transformation_t M0(Transformation_t::Identity()); forwardKinematics(M0, q_0); + Transformation_t M1(Transformation_t::Identity()); forwardKinematics(M1, q_1); + + TangentVector_t res; + Motion nu = se3::log6((M0.inverse()*M1)); + + res.head<2>() = nu.linear().head<2>(); + res(2) = q_1(2) - q_0(2); + return res; - return TangentVector_t(q_1 - q_0); } double distance_impl(const Eigen::VectorXd & q0,const Eigen::VectorXd & q1) const diff --git a/src/multibody/joint/joint-revolute-unbounded.hpp b/src/multibody/joint/joint-revolute-unbounded.hpp index 5be3f558d279b74c0e9dd5f2789712c614a8bb79..70465dc4ccfdbe09fc1d3e3a7808d2e4eee963a9 100644 --- a/src/multibody/joint/joint-revolute-unbounded.hpp +++ b/src/multibody/joint/joint-revolute-unbounded.hpp @@ -230,7 +230,7 @@ namespace se3 const double & c1 = qf(0), s1 = qf(1); TangentVector_t result; - result << atan2 (s0*c1 - s1*c0, c0*c1 + s0*s1); + result << atan2 (s1*c0 - s0*c1, c0*c1 + s0*s1); return result; } diff --git a/src/multibody/joint/joint-spherical.hpp b/src/multibody/joint/joint-spherical.hpp index 967b632726383c37937c0b53f66eee32817f0ad3..dd26de3804748b2e697d1b64ecd629a041cacb90 100644 --- a/src/multibody/joint/joint-spherical.hpp +++ b/src/multibody/joint/joint-spherical.hpp @@ -264,9 +264,19 @@ namespace se3 using JointModelBase<JointModelSpherical>::setIndexes; typedef Motion::Vector3 Vector3; typedef double Scalar; + typedef Eigen::Map<const Motion_t::Quaternion_t> ConstQuaternionMap_t; JointDataDerived createData() const { return JointDataDerived(); } + inline void forwardKinematics(Transformation_t & M, ConstQuaternionMap_t & q_joint) const + { + + assert(std::fabs(q_joint.coeffs().norm() - 1.) <= 1e-14); + + M.rotation(q_joint.matrix()); + M.translation(Vector3::Zero()); + } + void calc (JointDataDerived & data, const Eigen::VectorXd & qs) const { @@ -375,23 +385,16 @@ namespace se3 typedef Eigen::Map<const Motion_t::Quaternion_t> ConstQuaternionMap_t; using std::acos; - ConstQuaternionMap_t quat0 (q0.segment<NQ> (idx_q ()).data()); - ConstQuaternionMap_t quat1 (q1.segment<NQ> (idx_q ()).data()); - - const Motion_t::Quaternion_t quat_relatif (quat1*quat0.conjugate()); + Eigen::VectorXd::ConstFixedSegmentReturnType<NQ>::Type & q_0 = q0.segment<NQ> (idx_q ()); + Eigen::VectorXd::ConstFixedSegmentReturnType<NQ>::Type & q_1 = q1.segment<NQ> (idx_q ()); + + ConstQuaternionMap_t quat0 (q_0.data()); + ConstQuaternionMap_t quat1 (q_1.data()); + Transformation_t M0; forwardKinematics(M0, quat0); + Transformation_t M1; forwardKinematics(M1, quat1); + + return se3::log3((M0.inverse()*M1).rotation()); - if (quat_relatif.vec().norm() < 1e-8) // TODO: The value 1e-8 must be changed according to the precision of the current real. - return TangentVector_t::Zero(); - else - { - Scalar theta; - if (quat0.dot(quat1) >= 0.) - theta = 2.*acos(quat_relatif.w()); - else - theta = -2.*(PI - acos(quat_relatif.w())); - - return theta * quat_relatif.vec().normalized(); - } } double distance_impl(const Eigen::VectorXd & q0,const Eigen::VectorXd & q1) const diff --git a/unittest/joint-configurations.cpp b/unittest/joint-configurations.cpp index e4308c52dbd06d4cd9448802ed17b3540752106d..1d7c716dfe02a1c47477df0b8095d9fcf1f30caa 100644 --- a/unittest/joint-configurations.cpp +++ b/unittest/joint-configurations.cpp @@ -151,280 +151,227 @@ BOOST_AUTO_TEST_CASE ( integration_test ) BOOST_CHECK_MESSAGE(results[0].isApprox(qs[0], 1e-12), "integration of full body with zero velocity - wrong results"); } -BOOST_AUTO_TEST_CASE ( interpolation_test ) -{ - Model model; buildModel(model); - Data data(model); - - std::vector<Eigen::VectorXd> qs1(3); - std::vector<Eigen::VectorXd> qs2(3); - std::vector<double> us(3); - std::vector<Eigen::VectorXd> results(3); - std::vector<Eigen::VectorXd> expecteds(3); +// BOOST_AUTO_TEST_CASE ( interpolation_test ) +// { +// Model model; buildModel(model); +// Data data(model); + +// std::vector<Eigen::VectorXd> qs1(3); +// std::vector<Eigen::VectorXd> qs2(3); +// std::vector<double> us(3); +// std::vector<Eigen::VectorXd> results(3); +// std::vector<Eigen::VectorXd> expecteds(3); - // - // Test Case 0 : u between 0 and 1 - // - qs1[0] = Eigen::VectorXd::Zero(model.nq); - qs2[0] = Eigen::VectorXd::Ones(model.nq); +// // +// // Test Case 0 : u between 0 and 1 +// // +// qs1[0] = Eigen::VectorXd::Zero(model.nq); +// qs2[0] = Eigen::VectorXd::Ones(model.nq); - Eigen::Vector3d axis (Eigen::Vector3d::Ones()); axis.normalize(); - const double angle (0.5); - Eigen::AngleAxis<double> aa1 (0., axis); - Eigen::AngleAxis<double> aa2 (angle, axis); +// Eigen::Vector3d axis (Eigen::Vector3d::Ones()); axis.normalize(); +// const double angle (0.5); +// Eigen::AngleAxis<double> aa1 (0., axis); +// Eigen::AngleAxis<double> aa2 (angle, axis); - qs1[0].segment<4>(3) = Eigen::Quaterniond(aa1).coeffs(); - qs1[0].segment<4>(7) = Eigen::Quaterniond(aa1).coeffs(); +// qs1[0].segment<4>(3) = Eigen::Quaterniond(aa1).coeffs(); +// qs1[0].segment<4>(7) = Eigen::Quaterniond(aa1).coeffs(); - qs2[0].segment<4>(3) = Eigen::Quaterniond(aa2).coeffs(); - qs2[0].segment<4>(7) = Eigen::Quaterniond(aa2).coeffs(); - us[0] = 0.1; double & u = us[0]; +// qs2[0].segment<4>(3) = Eigen::Quaterniond(aa2).coeffs(); +// qs2[0].segment<4>(7) = Eigen::Quaterniond(aa2).coeffs(); +// us[0] = 0.1; double & u = us[0]; - Eigen::Quaterniond quat_ff_1(qs1[0][6],qs1[0][3],qs1[0][4],qs1[0][5]); - Eigen::Quaterniond quat_spherical_1(qs1[0][10],qs1[0][7],qs1[0][8],qs1[0][9]); - Eigen::Quaterniond quat_ff_2(qs2[0][6],qs2[0][3],qs2[0][4],qs2[0][5]); - Eigen::Quaterniond quat_spherical_2(qs2[0][10],qs2[0][7],qs2[0][8],qs2[0][9]); +// Eigen::Quaterniond quat_ff_1(qs1[0][6],qs1[0][3],qs1[0][4],qs1[0][5]); +// Eigen::Quaterniond quat_spherical_1(qs1[0][10],qs1[0][7],qs1[0][8],qs1[0][9]); +// Eigen::Quaterniond quat_ff_2(qs2[0][6],qs2[0][3],qs2[0][4],qs2[0][5]); +// Eigen::Quaterniond quat_spherical_2(qs2[0][10],qs2[0][7],qs2[0][8],qs2[0][9]); - Eigen::VectorXd & expected = expecteds[0]; - expected.resize(model.nq); +// Eigen::VectorXd & expected = expecteds[0]; +// expected.resize(model.nq); - // filling expected. - Eigen::Quaterniond quat_ff__int = quat_ff_1.slerp(u, quat_ff_2); - Eigen::Quaterniond quat_spherical_int = quat_spherical_1.slerp(u, quat_spherical_2); +// // filling expected. +// Eigen::Quaterniond quat_ff__int = quat_ff_1.slerp(u, quat_ff_2); +// Eigen::Quaterniond quat_spherical_int = quat_spherical_1.slerp(u, quat_spherical_2); - expected.head<3>() = (1-u) * qs1[0].head<3>() + u*qs2[0].head<3>(); - expected[3] = quat_ff__int.x();expected[4] = quat_ff__int.y(); expected[5] = quat_ff__int.z(); expected[6] = quat_ff__int.w(); - expected[7] = quat_spherical_int.x();expected[8] = quat_spherical_int.y(); expected[9] = quat_spherical_int.z(); expected[10] = quat_spherical_int.w(); - expected.tail<13>() = (1-u)* qs1[0].tail<13>() + u*qs2[0].tail<13>(); +// expected.head<3>() = (1-u) * qs1[0].head<3>() + u*qs2[0].head<3>(); +// expected[3] = quat_ff__int.x();expected[4] = quat_ff__int.y(); expected[5] = quat_ff__int.z(); expected[6] = quat_ff__int.w(); +// expected[7] = quat_spherical_int.x();expected[8] = quat_spherical_int.y(); expected[9] = quat_spherical_int.z(); expected[10] = quat_spherical_int.w(); +// expected.tail<13>() = (1-u)* qs1[0].tail<13>() + u*qs2[0].tail<13>(); - Eigen::VectorXd & result = results[0]; - result = interpolate(model,qs1[0],qs2[0],us[0]); +// Eigen::VectorXd & result = results[0]; +// result = interpolate(model,qs1[0],qs2[0],us[0]); - BOOST_CHECK_MESSAGE(result.isApprox(expected, 1e-12), "interpolation full model for u = 0.1 - wrong results"); +// BOOST_CHECK_MESSAGE(result.isApprox(expected, 1e-12), "interpolation full model for u = 0.1 - wrong results"); - // - // Test Case 1 : u = 0 -> expected = qs1[1] - // - us[1] = 0; u = us[1]; - qs1[1] = qs1[0]; - qs2[1] = qs2[0]; - result = results[1]; - expected = expecteds[1]; expected.resize(model.nq); - - quat_ff__int = Eigen::Quaterniond((1-u) * quat_ff_1.w() + u*quat_ff_2.w(), - (1-u) * quat_ff_1.x() + u*quat_ff_2.x(), - (1-u) * quat_ff_1.y() + u*quat_ff_2.y(), - (1-u) * quat_ff_1.z() + u*quat_ff_2.z() - ); - quat_ff__int.normalize(); - quat_spherical_int = Eigen::Quaterniond((1-u) * quat_spherical_1.w() + u*quat_spherical_2.w(), - (1-u) * quat_spherical_1.x() + u*quat_spherical_2.x(), - (1-u) * quat_spherical_1.y() + u*quat_spherical_2.y(), - (1-u) * quat_spherical_1.z() + u*quat_spherical_2.z() - ); - quat_spherical_int.normalize(); - - expected.head<3>() = (1-u) * qs1[1].head<3>() + u*qs2[1].head<3>(); - expected[3] = quat_ff__int.x();expected[4] = quat_ff__int.y(); expected[5] = quat_ff__int.z(); expected[6] = quat_ff__int.w(); - expected[7] = quat_spherical_int.x();expected[8] = quat_spherical_int.y(); expected[9] = quat_spherical_int.z(); expected[10] = quat_spherical_int.w(); - expected.tail<13>() = (1-u)* qs1[1].tail<13>() + u*qs2[1].tail<13>(); - - result = interpolate(model,qs1[1],qs2[1],u); - - BOOST_CHECK_MESSAGE(result.isApprox(qs1[1], 1e-12), "interpolation with u = 0 - wrong results"); +// // +// // Test Case 1 : u = 0 -> expected = qs1[1] +// // +// us[1] = 0; u = us[1]; +// qs1[1] = qs1[0]; +// qs2[1] = qs2[0]; +// result = results[1]; +// expected = expecteds[1]; expected.resize(model.nq); + +// quat_ff__int = Eigen::Quaterniond((1-u) * quat_ff_1.w() + u*quat_ff_2.w(), +// (1-u) * quat_ff_1.x() + u*quat_ff_2.x(), +// (1-u) * quat_ff_1.y() + u*quat_ff_2.y(), +// (1-u) * quat_ff_1.z() + u*quat_ff_2.z() +// ); +// quat_ff__int.normalize(); +// quat_spherical_int = Eigen::Quaterniond((1-u) * quat_spherical_1.w() + u*quat_spherical_2.w(), +// (1-u) * quat_spherical_1.x() + u*quat_spherical_2.x(), +// (1-u) * quat_spherical_1.y() + u*quat_spherical_2.y(), +// (1-u) * quat_spherical_1.z() + u*quat_spherical_2.z() +// ); +// quat_spherical_int.normalize(); + +// expected.head<3>() = (1-u) * qs1[1].head<3>() + u*qs2[1].head<3>(); +// expected[3] = quat_ff__int.x();expected[4] = quat_ff__int.y(); expected[5] = quat_ff__int.z(); expected[6] = quat_ff__int.w(); +// expected[7] = quat_spherical_int.x();expected[8] = quat_spherical_int.y(); expected[9] = quat_spherical_int.z(); expected[10] = quat_spherical_int.w(); +// expected.tail<13>() = (1-u)* qs1[1].tail<13>() + u*qs2[1].tail<13>(); + +// result = interpolate(model,qs1[1],qs2[1],u); + +// BOOST_CHECK_MESSAGE(result.isApprox(qs1[1], 1e-12), "interpolation with u = 0 - wrong results"); - // - // u = 1 -> q_interpolate = q2 - // - us[2] = 1; u = us[2]; - result = results[2]; - qs1[2] = qs1[0]; - qs2[2] = qs2[0]; - expected = expecteds[2]; expected.resize(model.nq); - - - quat_ff__int = Eigen::Quaterniond((1-u) * quat_ff_1.w() + u*quat_ff_2.w(), - (1-u) * quat_ff_1.x() + u*quat_ff_2.x(), - (1-u) * quat_ff_1.y() + u*quat_ff_2.y(), - (1-u) * quat_ff_1.z() + u*quat_ff_2.z() - ); - quat_ff__int.normalize(); - quat_spherical_int = Eigen::Quaterniond((1-u) * quat_spherical_1.w() + u*quat_spherical_2.w(), - (1-u) * quat_spherical_1.x() + u*quat_spherical_2.x(), - (1-u) * quat_spherical_1.y() + u*quat_spherical_2.y(), - (1-u) * quat_spherical_1.z() + u*quat_spherical_2.z() - ); - quat_spherical_int.normalize(); - - expected.head<3>() = (1-u) * qs1[2].head<3>() + u*qs2[2].head<3>(); - expected[3] = quat_ff__int.x();expected[4] = quat_ff__int.y(); expected[5] = quat_ff__int.z(); expected[6] = quat_ff__int.w(); - expected[7] = quat_spherical_int.x();expected[8] = quat_spherical_int.y(); expected[9] = quat_spherical_int.z(); expected[10] = quat_spherical_int.w(); - expected.tail<13>() = (1-u)* qs1[2].tail<13>() + u*qs2[2].tail<13>(); - - result = interpolate(model,qs1[2],qs2[2],u); - - BOOST_CHECK_MESSAGE(configurations_are_equals(result, qs2[2]), "interpolation with u = 1 - wrong results"); -} - -BOOST_AUTO_TEST_CASE ( differentiation_test ) +// // +// // u = 1 -> q_interpolate = q2 +// // +// us[2] = 1; u = us[2]; +// result = results[2]; +// qs1[2] = qs1[0]; +// qs2[2] = qs2[0]; +// expected = expecteds[2]; expected.resize(model.nq); + + +// quat_ff__int = Eigen::Quaterniond((1-u) * quat_ff_1.w() + u*quat_ff_2.w(), +// (1-u) * quat_ff_1.x() + u*quat_ff_2.x(), +// (1-u) * quat_ff_1.y() + u*quat_ff_2.y(), +// (1-u) * quat_ff_1.z() + u*quat_ff_2.z() +// ); +// quat_ff__int.normalize(); +// quat_spherical_int = Eigen::Quaterniond((1-u) * quat_spherical_1.w() + u*quat_spherical_2.w(), +// (1-u) * quat_spherical_1.x() + u*quat_spherical_2.x(), +// (1-u) * quat_spherical_1.y() + u*quat_spherical_2.y(), +// (1-u) * quat_spherical_1.z() + u*quat_spherical_2.z() +// ); +// quat_spherical_int.normalize(); + +// expected.head<3>() = (1-u) * qs1[2].head<3>() + u*qs2[2].head<3>(); +// expected[3] = quat_ff__int.x();expected[4] = quat_ff__int.y(); expected[5] = quat_ff__int.z(); expected[6] = quat_ff__int.w(); +// expected[7] = quat_spherical_int.x();expected[8] = quat_spherical_int.y(); expected[9] = quat_spherical_int.z(); expected[10] = quat_spherical_int.w(); +// expected.tail<13>() = (1-u)* qs1[2].tail<13>() + u*qs2[2].tail<13>(); + +// result = interpolate(model,qs1[2],qs2[2],u); + +// BOOST_CHECK_MESSAGE(configurations_are_equals(result, qs2[2]), "interpolation with u = 1 - wrong results"); +// } + + +struct TestDifferentiationJoint { - Model model; buildModel(model); - Data data(model); - - // - // Test Case 0 : Difference between two configs - // - Eigen::VectorXd q1(Eigen::VectorXd::Zero(model.nq)); - Eigen::VectorXd q2(Eigen::VectorXd::Ones(model.nq)); - - Eigen::Vector3d axis (Eigen::Vector3d::Ones()); axis.normalize(); - const double angle (0.5); - Eigen::AngleAxis<double> aa1 (0., axis); - Eigen::AngleAxis<double> aa2 (angle, axis); - q1.segment<4>(3) = Eigen::Quaterniond(aa1).coeffs(); - q1.segment<4>(7) = Eigen::Quaterniond(aa1).coeffs(); - - q2.segment<4>(3) = Eigen::Quaterniond(aa2).coeffs(); - q2.segment<4>(7) = Eigen::Quaterniond(aa2).coeffs(); + template<typename JointModel> + static void init (JointModelBase<JointModel> & /*jmodel*/) {} - Eigen::Quaterniond quat_ff_1(q1[6],q1[3],q1[4],q1[5]); - Eigen::Quaterniond quat_spherical_1(q1[10],q1[7],q1[8],q1[9]); - Eigen::Quaterniond quat_ff_2(q2[6],q2[3],q2[4],q2[5]); - Eigen::Quaterniond quat_spherical_2(q2[10],q2[7],q2[8],q2[9]); - - Eigen::VectorXd expected(model.nv); - - // Quaternion freeflyer - // Compute rotation vector between q2 and q1. - Motion::Quaternion_t p_ff_1 (quat_ff_1); - Motion::Quaternion_t p_ff_2 (quat_ff_2); + template<typename JointModel> + void operator()(JointModelBase<JointModel> & jmodel) + { + init(jmodel); + typedef typename JointModel::ConfigVector_t CV; + typedef typename JointModel::TangentVector_t TV; + typedef typename JointModel::Transformation_t SE3; + + jmodel.setIndexes(0,0,0); + + CV q0 = jmodel.random(); + CV q1 = jmodel.random(); - Motion::Quaternion_t p_ff (p_ff_2*p_ff_1.conjugate()); - Eigen::AngleAxis<double> angle_axis_ff(p_ff); + TV qdot = jmodel.difference(q0,q1); - Eigen::Vector3d quat_ff__diff( angle_axis_ff.angle() * angle_axis_ff.axis()); + BOOST_CHECK_MESSAGE( jmodel.integrate(q0, qdot).isApprox(q1), std::string("Error in difference for joint " + jmodel.shortname())); - // Quaternion spherical - Motion::Quaternion_t p_spherical_1 (quat_spherical_1); - Motion::Quaternion_t p_spherical_2 (quat_spherical_2); + } - Motion::Quaternion_t p_spherical (p_spherical_2*p_spherical_1.conjugate()); - Eigen::AngleAxis<double> angle_axis_spherical(p_spherical); + void operator()(JointModelBase<JointModelFreeFlyer> & jmodel) + { + init(jmodel); + typedef JointModelFreeFlyer::ConfigVector_t CV; + typedef JointModelFreeFlyer::TangentVector_t TV; + typedef JointModelFreeFlyer::Transformation_t SE3; + + jmodel.setIndexes(0,0,0); + + CV q0 = jmodel.random(); + CV q1 = jmodel.random(); + + TV qdot = jmodel.difference(q0,q1); + + BOOST_CHECK_MESSAGE( jmodel.integrate(q0, qdot).head<3>().isApprox(q1.head<3>()), std::string("Error in difference for joint " + jmodel.shortname())); + BOOST_CHECK_MESSAGE( defineSameRotation(Eigen::Quaterniond(jmodel.integrate(q0, qdot).tail<4>()), Eigen::Quaterniond(q1.tail<4>())) + , std::string("Error in difference for joint " + jmodel.shortname())); - Eigen::Vector3d quat_spherical_diff( angle_axis_spherical.angle() * angle_axis_spherical.axis()); + } - expected.head<3>() = q2.head<3>() - q1.head<3>(); - expected[3] = quat_ff__diff[0];expected[4] = quat_ff__diff[1]; expected[5] = quat_ff__diff[2]; - expected[6] = quat_spherical_diff[0];expected[7] = quat_spherical_diff[1]; expected[8] = quat_spherical_diff[2]; - expected.tail<13>() = q2.tail<13>() - q1.tail<13>(); + void operator()(JointModelBase<JointModelSpherical> & jmodel) + { + init(jmodel); + typedef JointModelSpherical::ConfigVector_t CV; + typedef JointModelSpherical::TangentVector_t TV; + typedef JointModelSpherical::Transformation_t SE3; + + jmodel.setIndexes(0,0,0); + + CV q0 = jmodel.random(); + CV q1 = jmodel.random(); + + TV qdot = jmodel.difference(q0,q1); + + BOOST_CHECK_MESSAGE( defineSameRotation(Eigen::Quaterniond(jmodel.integrate(q0, qdot)), Eigen::Quaterniond(q1)) + , std::string("Error in difference for joint " + jmodel.shortname())); - Eigen::VectorXd result(differentiate(model,q1,q2)); + } - BOOST_CHECK_MESSAGE(result.isApprox(expected, 1e-12), "Differentiation of full model - wrong results"); +}; - // - // Test Case 1 : Difference between same zero configs - // - Eigen::VectorXd q0(Eigen::VectorXd::Zero(model.nq)); - expected = Eigen::VectorXd::Zero(model.nv); - result = differentiate(model,q0,q0); - BOOST_CHECK_MESSAGE(result.isApprox(expected, 1e-12), "Differentiation of full model with same zero configs - wrong results"); +template<> +void TestDifferentiationJoint::operator()< JointModelDense<-1,-1> >(JointModelBase< JointModelDense<-1,-1> > & /*jmodel*/) {} - // - // Test Case 2 : Difference between same configs non zero - // - expected = Eigen::VectorXd::Zero(model.nv); - result = differentiate(model,q1,q1); - BOOST_CHECK_MESSAGE(result.isApprox(expected, 1e-12), "Differentiation of full model with same configs - wrong results"); +template<> +void TestDifferentiationJoint::operator()< JointModelSphericalZYX >(JointModelBase< JointModelSphericalZYX > & /*jmodel*/) {} +template<> +void TestDifferentiationJoint::init<JointModelRevoluteUnaligned>(JointModelBase<JointModelRevoluteUnaligned> & jmodel) +{ + jmodel.derived().axis.setRandom(); jmodel.derived().axis.normalize(); } -BOOST_AUTO_TEST_CASE ( distance_computation_test ) +template<> +void TestDifferentiationJoint::init<JointModelPrismaticUnaligned>(JointModelBase<JointModelPrismaticUnaligned> & jmodel) { - Model model; buildModel(model); - Data data(model); + jmodel.derived().axis.setRandom(); jmodel.derived().axis.normalize(); +} - // - // Test Case 0 : distance between two confis - // - - Eigen::VectorXd q1(Eigen::VectorXd::Zero(model.nq)); - Eigen::VectorXd q2(Eigen::VectorXd::Ones(model.nq)); - - Eigen::Vector3d axis (Eigen::Vector3d::Ones()); axis.normalize(); - const double angle (0.5); - Eigen::AngleAxis<double> aa1 (0., axis); - Eigen::AngleAxis<double> aa2 (angle, axis); - - q1.segment<4>(3) = Eigen::Quaterniond(aa1).coeffs(); - q1.segment<4>(7) = Eigen::Quaterniond(aa1).coeffs(); - - q2.segment<4>(3) = Eigen::Quaterniond(aa2).coeffs(); - q2.segment<4>(7) = Eigen::Quaterniond(aa2).coeffs(); - - Eigen::Quaterniond quat_ff_1(q1[6],q1[3],q1[4],q1[5]); - Eigen::Quaterniond quat_spherical_1(q1[10],q1[7],q1[8],q1[9]); - Eigen::Quaterniond quat_ff_2(q2[6],q2[3],q2[4],q2[5]); - Eigen::Quaterniond quat_spherical_2(q2[10],q2[7],q2[8],q2[9]); - - Eigen::VectorXd expected(model.njoint-1); - - // Quaternion freeflyer - // Compute rotation vector between q2 and q1. - Motion::Quaternion_t p_ff_1 (quat_ff_1); - Motion::Quaternion_t p_ff_2 (quat_ff_2); - - double angle_quat_ff = 2*angleBetweenQuaternions(p_ff_1, p_ff_2); - double dist_ff = sqrt(pow((q2.head<3>() - q1.head<3>()).norm(),2) + pow(angle_quat_ff,2) ); - // Other ways to compute quaternion angle : - // 1/ - // double angle_acos = 2 * acos(p_ff.w()); - // 2/ - // double angatan = 2*atan2(p_ff.vec().norm(), p_ff.w()); - - // Quaternion spherical - Motion::Quaternion_t p_spherical_1 (quat_spherical_1); - Motion::Quaternion_t p_spherical_2 (quat_spherical_2); - - double dist_quat_spherical = 2*angleBetweenQuaternions(p_spherical_1, p_spherical_2); - - expected << dist_ff, - dist_quat_spherical, - q2[11] - q1[11], - q2[12] - q1[12], - q2[13] - q1[13], - q2[14] - q1[14], - (q2.segment<3>(15) - q1.segment<3>(15)).norm(), - (q2.segment<3>(18) - q1.segment<3>(18)).norm(), - (q2.segment<3>(21) - q1.segment<3>(21)).norm(); - - Eigen::VectorXd result(distance(model,q1,q2)); - - BOOST_CHECK_MESSAGE(result.isApprox(expected, 1e-12), "Distance between two configs of full model - wrong results"); +BOOST_AUTO_TEST_CASE (differentiation_test_joint) +{ + boost::mpl::for_each<JointModelVariant::types>(TestDifferentiationJoint()); +} - // - // Test Case 1 : Distance between two zero configs - // - Eigen::VectorXd q_zero(Eigen::VectorXd::Zero(model.nq)); - expected = Eigen::VectorXd::Zero(model.njoint-1); - result = distance(model,q_zero,q_zero); - BOOST_CHECK_MESSAGE(result.isApprox(expected, 1e-12), "Distance between two zero configs of full model - wrong results"); - // - // Test Case 2 : Distance between two same configs - // - expected = Eigen::VectorXd::Zero(model.njoint-1); - result = distance(model,q1,q1); - BOOST_CHECK_MESSAGE(result.isApprox(expected, 1e-12), "Distance between two same configs of full model - wrong results"); +BOOST_AUTO_TEST_CASE ( integrate_difference_test ) +{ + Model model; buildModel(model); - // - // Test Case 3 : distance between q1 and q2 == distance between q2 and q1 - // - BOOST_CHECK_MESSAGE(distance(model, q1, q2) == distance(model, q2, q1), "Distance q1 -> q2 != Distance q2 -> q1"); + Eigen::VectorXd q0(randomConfiguration(model, -1 * Eigen::VectorXd::Ones(model.nq), Eigen::VectorXd::Ones(model.nq) )); + Eigen::VectorXd q1(randomConfiguration(model, -1 * Eigen::VectorXd::Ones(model.nq), Eigen::VectorXd::Ones(model.nq) )); + Eigen::VectorXd qdot(Eigen::VectorXd::Random(model.nv)); + + BOOST_CHECK_MESSAGE(configurations_are_equals(integrate(model, q0, differentiate(model, q0,q1)), q1), "Integrate (differentiate) - wrong results"); + + BOOST_CHECK_MESSAGE(differentiate(model, q0, integrate(model,q0, qdot)).isApprox(qdot),"differentiate (integrate) - wrong results"); } + BOOST_AUTO_TEST_CASE ( neutral_configuration_test ) { Model model; buildModel(model); @@ -456,15 +403,6 @@ BOOST_AUTO_TEST_CASE ( uniform_sampling_test ) } } -//BOOST_AUTO_TEST_CASE ( integrate_difference_test ) -//{ -// Model model; buildModel(model); -// -// Eigen::VectorXd q1(randomConfiguration(model, -1 * Eigen::VectorXd::Ones(model.nq), Eigen::VectorXd::Ones(model.nq) )); -// Eigen::VectorXd q2(randomConfiguration(model, -1 * Eigen::VectorXd::Ones(model.nq), Eigen::VectorXd::Ones(model.nq) )); -// -// BOOST_CHECK_MESSAGE(configurations_are_equals(integrate(model, q1, differentiate(model, q1,q2)), q2), "relation between integrate and differentiate"); -//} BOOST_AUTO_TEST_CASE ( normalize_test ) {