/// /// Copyright (c) 2011 CNRS /// Author: Florent Lamiraux /// /// // This file is part of hpp-model // hpp-model is free software: you can redistribute it // and/or modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation, either version // 3 of the License, or (at your option) any later version. // // hpp-model is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Lesser Public License for more details. You should have // received a copy of the GNU Lesser General Public License along with // hpp-model If not, see // . // This test // - builds a robot with various types of joints, // - randomly samples pairs of configurations, // - test consistency between hpp::model::difference and // hpp::model::integrate functions. #include #define BOOST_TEST_MODULE TEST_CONFIGURATION #include #include using boost::test_tools::output_test_stream; #include #include #include #include #include using hpp::model::vector_t; using hpp::model::vectorIn_t; using hpp::model::Configuration_t; using hpp::model::JointPtr_t; using hpp::model::ObjectFactory; using hpp::model::Transform3f; using fcl::Quaternion3f; using hpp::model::Device; using hpp::model::DevicePtr_t; using hpp::model::JointVector_t; using hpp::model::ConfigurationPtr_t; using hpp::model::size_type; using hpp::model::value_type; typedef Eigen::AngleAxis AngleAxis_t; typedef Eigen::Quaternion Quaternion_t; // Create a robot with various types of joints DevicePtr_t createRobot () { DevicePtr_t robot = Device::create ("robot"); Transform3f position; position.setIdentity (); ObjectFactory factory; // planar root joint JointPtr_t root = factory.createJointTranslation2 (position); robot->rootJoint (root); root->isBounded (0, true); root->lowerBound (0, -1); root->upperBound (0, 1); root->isBounded (1, true); root->lowerBound (1, -1); root->upperBound (1, 1); // Rotation around z position.setQuatRotation (Quaternion3f (sqrt (2)/2, 0, -sqrt (2)/2, 0)); JointPtr_t joint = factory.createUnBoundedJointRotation (position); root->addChildJoint (joint); position.setIdentity (); // SO3 joint position.setIdentity (); JointPtr_t j1 = factory.createJointSO3 (position); j1->name ("so3"); joint->addChildJoint (j1); return robot; } void shootRandomConfig (const DevicePtr_t& robot, Configuration_t& config) { JointVector_t jv = robot->getJointVector (); for (JointVector_t::const_iterator itJoint = jv.begin (); itJoint != jv.end (); itJoint++) { std::size_t rank = (*itJoint)->rankInConfiguration (); (*itJoint)->configuration ()->uniformlySample (rank, config); } // Shoot extra configuration variables size_type extraDim = robot->extraConfigSpace ().dimension (); size_type offset = robot->configSize () - extraDim; for (size_type i=0; iextraConfigSpace ().lower (i); value_type upper = robot->extraConfigSpace ().upper (i); value_type range = upper - lower; if ((range < 0) || (range == std::numeric_limits::infinity())) { std::ostringstream oss ("Cannot uniformy sample extra config variable "); oss << i << ". min = " << ", max = " << upper << std::endl; throw std::runtime_error (oss.str ()); } config [offset + i] = (upper - lower) * rand ()/RAND_MAX; } } vector_t slerp (vectorIn_t v0, vectorIn_t v1, const value_type t) { Quaternion_t q0(v0[0], v0[1], v0[2], v0[3]); Quaternion_t q1(v1[0], v1[1], v1[2], v1[3]); Quaternion_t q = q0.slerp (t, q1); vector_t res(4); res[0] = q.w(); res[1] = q.x(); res[2] = q.y(); res[3] = q.z(); return res; } AngleAxis_t aa (vectorIn_t v0, vectorIn_t v1) { Quaternion_t q0(v0[0], v0[1], v0[2], v0[3]); Quaternion_t q1(v1[0], v1[1], v1[2], v1[3]); return AngleAxis_t (q0 * q1.conjugate ()); } vector_t interpolation (DevicePtr_t robot, vectorIn_t q0, vectorIn_t q1, int n) { const size_type rso3 = 4; bool print = false; vector_t q2 (q0); value_type u = 0; value_type step = (value_type)1 / (value_type)(n + 2); vector_t angle1 (n+2), angle2(n+2); if (print) std::cout << "HPP : "; for (int i = 0; i < n + 2; ++i) { u = 0 + i * step; hpp::model::interpolate (robot, q0, q1, u, q2); AngleAxis_t aa1 (aa (q0.segment<4>(rso3),q2.segment<4>(rso3))); angle1[i] = aa1.angle (); if (print) std::cout << aa1.angle () << ", "; } if (print) std::cout << "\n"; if (print) std::cout << "Eigen: "; for (int i = 0; i < n + 2; ++i) { u = 0 + i * step; vector_t eigen_slerp = slerp (q0.segment<4>(rso3), q1.segment<4>(rso3), u); AngleAxis_t aa2 (aa (q0.segment<4>(rso3),eigen_slerp)); angle2[i] = aa2.angle (); if (print) std::cout << aa2.angle () << ", "; } if (print) std::cout << "\n"; return angle1 - angle2; } BOOST_AUTO_TEST_CASE(difference_and_integrate) { DevicePtr_t robot = createRobot (); Configuration_t q0; q0.resize (robot->configSize ()); Configuration_t q1; q1.resize (robot->configSize ()); Configuration_t q2; q2.resize (robot->configSize ()); vector_t q1_minus_q0; q1_minus_q0.resize (robot->numberDof ()); const value_type eps_dist = robot->numberDof() * sqrt(Eigen::NumTraits::epsilon()); for (size_type i=0; i<10000; ++i) { shootRandomConfig (robot, q0); shootRandomConfig (robot, q1); hpp::model::difference (robot, q1, q0, q1_minus_q0); hpp::model::integrate (robot, q0, q1_minus_q0, q2); // Check that the distance is the norm of the difference value_type distance = hpp::model::distance (robot, q0, q1); BOOST_CHECK_MESSAGE (distance - q1_minus_q0.norm () < Eigen::NumTraits::dummy_precision(), "\nThe distance is not the norm of the difference\n" << "q0=" << q0.transpose () << "\n" << "q1=" << q1.transpose () << "\n" << "distance=" << distance << "\n" << "(q1 - q0).norm () = " << q1_minus_q0.norm () ); // Check that distance (q0 + (q1 - q0), q1) is zero distance = hpp::model::distance (robot, q1, q2); BOOST_CHECK_MESSAGE (distance < eps_dist, "\n(q0 + (q1 - q0)) is not equivalent to q1\n" << "q1=" << q1.transpose () << "\n" << "q2=" << q2.transpose () << "\n" << "distance=" << distance ); } } BOOST_AUTO_TEST_CASE(interpolate) { DevicePtr_t robot = createRobot (); Configuration_t q0; q0.resize (robot->configSize ()); Configuration_t q1; q1.resize (robot->configSize ()); Configuration_t q2; q2.resize (robot->configSize ()); vector_t q1_minus_q0; q1_minus_q0.resize (robot->numberDof ()); const value_type eps_dist = robot->numberDof() * sqrt(Eigen::NumTraits::epsilon()); value_type distance; for (size_type i=0; i<10000; ++i) { shootRandomConfig (robot, q0); shootRandomConfig (robot, q1); hpp::model::interpolate (robot, q0, q1, 0, q2); distance = hpp::model::distance (robot, q0, q2); BOOST_CHECK_MESSAGE (distance < eps_dist, "\n(q0 + 0 * (q1 - q0)) is not equivalent to q0\n" << "q0=" << q0.transpose () << "\n" << "q1=" << q1.transpose () << "\n" << "q2=" << q2.transpose () << "\n" << "distance=" << distance ); const size_type rso3 = 4; vector_t errors = interpolation (robot, q0, q1, 4); BOOST_CHECK_MESSAGE (errors.isZero (), "The interpolation computed by HPP does not match the Eigen SLERP" ); hpp::model::interpolate (robot, q0, q1, 1, q2); distance = hpp::model::distance (robot, q1, q2); BOOST_CHECK_MESSAGE (distance < eps_dist, "\n(q0 + 1 * (q1 - q0)) is not equivalent to q1\n" << "q0=" << q0.transpose () << "\n" << "q1=" << q1.transpose () << "\n" << "q2=" << q2.transpose () << "\n" << "distance=" << distance ); } } BOOST_AUTO_TEST_CASE(toEigenFunction) { // Compilation check only. using namespace hpp::model; vector3_t fcl_v; matrix3_t fcl_m; fcl_v.setValue (1); fcl_m.setValue (3); vector_t eigen_v(3); matrix_t eigen_m(3,3); toEigen (fcl_v, eigen_v); toEigen (fcl_m, eigen_m); toEigen (fcl_v, eigen_m.col(0)); }