diff --git a/orocos_kdl/src/chainiksolvervel_pinv.cpp b/orocos_kdl/src/chainiksolvervel_pinv.cpp index 4ecc0cc4..bb5231e2 100644 --- a/orocos_kdl/src/chainiksolvervel_pinv.cpp +++ b/orocos_kdl/src/chainiksolvervel_pinv.cpp @@ -36,7 +36,9 @@ namespace KDL eps(_eps), maxiter(_maxiter), nrZeroSigmas(0), - svdResult(0) + svdResult(0), + sigmaMin(0), + Smaxtomin(nj) { } @@ -52,6 +54,7 @@ namespace KDL for(unsigned int i = 0 ; i < V.size(); i++) V[i].resize(nj); tmp.resize(nj); + Smaxtomin.resize(nj); } ChainIkSolverVel_pinv::~ChainIkSolverVel_pinv() @@ -59,6 +62,29 @@ namespace KDL } + void ChainIkSolverVel_pinv::setEps(const double eps_in) + { + if (eps_in > 0) + eps = eps_in; + // else silently ignore + } + + void ChainIkSolverVel_pinv::setMaxIter(const int maxiter_in) + { + if (maxiter_in >= 1) + maxiter = maxiter_in; + // else silently ignore + } + + int ChainIkSolverVel_pinv::getSigma(JntArray& Sout) + { + if (Sout.rows() != Smaxtomin.rows()) + return (error = E_SIZE_MISMATCH); + for (unsigned int i=0; i=6 and 0 for <6 + if (jac.columns() >= 6) + { + sigmaMin = Smaxtomin(5); + } + else + { + sigmaMin = 0; + } + // We have to calculate qdot_out = jac_pinv*v_in // Using the svd decomposition this becomes(jac_pinv=V*S_pinv*Ut): // qdot_out = V*S_pinv*Ut*v_in @@ -129,6 +170,32 @@ namespace KDL } } + void ChainIkSolverVel_pinv::SortJntArrayMaxToMin(JntArray& Smaxtomin) + { + unsigned int n = Smaxtomin.rows(); + for (unsigned int i=0; i S_max) + { + S_max = Sj; + i_max = j; + } + } + if (i_max != i) + { + /* swap eigenvalues */ + double tmp = Smaxtomin(i); + Smaxtomin(i) =Smaxtomin(i_max); + Smaxtomin(i_max) = tmp; + } + } + } + const char* ChainIkSolverVel_pinv::strError(const int error) const { if (E_CONVERGE_PINV_SINGULAR == error) return "Converged put pseudo inverse of jacobian is singular."; diff --git a/orocos_kdl/src/chainiksolvervel_pinv.hpp b/orocos_kdl/src/chainiksolvervel_pinv.hpp index b31f2dd4..84295d04 100644 --- a/orocos_kdl/src/chainiksolvervel_pinv.hpp +++ b/orocos_kdl/src/chainiksolvervel_pinv.hpp @@ -79,6 +79,18 @@ namespace KDL */ virtual int CartToJnt(const JntArray& /*q_init*/, const FrameVel& /*v_in*/, JntArrayVel& /*q_out*/){return -1;}; + /** + * Set eps + * \pre 0 < eps, otherwise eps is ignored + */ + void setEps(const double eps_in); + + /** + * Set maxIter + * \pre maxiter >= 1, otherwise maxiter is ignored + */ + void setMaxIter(const int maxiter_in); + /** * Retrieve the number of singular values of the jacobian that are < eps; * if the number of near zero singular values is > jac.col()-jac.row(), @@ -86,12 +98,38 @@ namespace KDL */ unsigned int getNrZeroSigmas()const {return nrZeroSigmas;}; + /** + * Request the minimum of the first six singular values + */ + double getSigmaMin( )const { return sigmaMin; }; + + /** + * Request the singular values of the Jacobian + */ + int getSigma(JntArray& Sout); + + /** + * Request the value of eps + */ + double getEps() const { return eps; }; + + /** + * Get maximum number of iterations + * \pre maxiter >= 1, otherwise maxiter is ignored + */ + int getMaxIter() const { return maxiter; } + /** * Retrieve the latest return code from the SVD algorithm * @return 0 if CartToJnt() not yet called, otherwise latest SVD result code. */ int getSVDResult()const {return svdResult;}; + /** + * Sort a JntArray from maximum to minimum value + */ + void SortJntArrayMaxToMin(JntArray& Smaxtomin); + /// @copydoc KDL::SolverI::strError() virtual const char* strError(const int error) const; @@ -111,7 +149,8 @@ namespace KDL int maxiter; unsigned int nrZeroSigmas; int svdResult; - + double sigmaMin; + JntArray Smaxtomin; }; } #endif diff --git a/orocos_kdl/tests/solvertest.cpp b/orocos_kdl/tests/solvertest.cpp index 24bde309..a25b8dc9 100644 --- a/orocos_kdl/tests/solvertest.cpp +++ b/orocos_kdl/tests/solvertest.cpp @@ -517,7 +517,7 @@ void SolverTest::FkPosAndIkPosTest() void SolverTest::IkSingularValueTest() { - unsigned int maxiter = 30; + int maxiter = 30; double eps = 1e-6 ; int maxiter_vel = 30; double eps_vel = 0.1 ; @@ -695,8 +695,80 @@ void SolverTest::IkVelSolverWDLSTest() CPPUNIT_ASSERT_EQUAL(4,(int)ikvelsolver.getNrZeroSigmas()) ; CPPUNIT_ASSERT_EQUAL(ikvelsolver.getLambdaScaled(),lambda) ; // full value } +void SolverTest::IkVelSolverPinvTest() +{ + int maxiter = 30; + double eps = 1e-6; + int maxiternew = 10; + double epsnew = 0.1; + + std::cout << "KDL-IK Pinv Vel Solver Tests for Near Zero SVs" << std::endl; + + KDL::ChainIkSolverVel_pinv ikvelsolver(motomansia10, eps, maxiter); + CPPUNIT_ASSERT_EQUAL(eps, ikvelsolver.getEps()); + CPPUNIT_ASSERT_EQUAL(maxiter, ikvelsolver.getMaxIter()); + ikvelsolver.setEps(epsnew); + CPPUNIT_ASSERT_EQUAL(epsnew, ikvelsolver.getEps()); + ikvelsolver.setMaxIter(maxiternew); + CPPUNIT_ASSERT_EQUAL(maxiternew, ikvelsolver.getMaxIter()); + + unsigned int nj = motomansia10.getNrOfJoints(); + JntArray q(nj), dq(nj); + + KDL::Vector v05(0.05, 0.05, 0.05); + KDL::Twist dx(v05, v05); + std::cout << "smallest singular value is above threshold (no Pinv)" << std::endl; + + q(0) = 0.0; + q(1) = 0.5; + q(2) = 0.4; + q(3) = -PI_2; + q(4) = 0.0; + q(5) = 0.0; + q(6) = 0.0; + + CPPUNIT_ASSERT_EQUAL((int)SolverI::E_NOERROR, ikvelsolver.CartToJnt(q, dx, dq)); // pinv mode + CPPUNIT_ASSERT_EQUAL(1u, ikvelsolver.getNrZeroSigmas()); // 1 singular value + + std::cout << "Test singular value function" << std::endl; + JntArray S(nj), Sexp(nj); + Sexp(0) = 1.86694; + Sexp(1) = 1.61924; + Sexp(2) = 1.3175; + Sexp(3) = 0.330559; + Sexp(4) = 0.206596; + Sexp(5) = 0.1163; + Sexp(6) = 0.0; + CPPUNIT_ASSERT_EQUAL(0, ikvelsolver.getSigma(S)); + for(unsigned int i=0; i