Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 62 additions & 2 deletions orocos_kdl/src/chainiksolvervel_pinv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ namespace KDL
eps(_eps),
maxiter(_maxiter),
nrZeroSigmas(0),
svdResult(0)
svdResult(0),
sigmaMin(0),
Smaxtomin(nj)
{
}

Expand All @@ -52,13 +54,35 @@ 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()
{
}


void ChainIkSolverVel_pinv::setEps(const double eps_in)
{
if (0 < eps_in) eps = eps_in;
// else silently ignore
}

void ChainIkSolverVel_pinv::setMaxIter(const unsigned int maxiter_in)
{
if (1 <= maxiter_in) 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<Sout.rows();i++)
Sout(i)=Smaxtomin(i);
return (error = E_NOERROR);
}

int ChainIkSolverVel_pinv::CartToJnt(const JntArray& q_in, const Twist& v_in, JntArray& qdot_out)
{
if (nj != chain.getNrOfJoints())
Expand All @@ -75,8 +99,9 @@ namespace KDL
double sum;
unsigned int i,j;

// Initialize near zero singular value counter
// Initialize (internal) return values
nrZeroSigmas = 0 ;
sigmaMin = 0.;

//Do a singular value decomposition of "jac" with maximum
//iterations "maxiter", put the results in "U", "S" and "V"
Expand All @@ -88,6 +113,18 @@ namespace KDL
return (error = E_SVD_FAILED);
}

// Sort S in descending order (S is not sorted in SVD_HH)
// copied from svd_eigen_HH.cpp
Smaxtomin = S;
SortJntArrayMaxToMin(Smaxtomin);
// Minimum of six largest singular values of J is S(5) if number of joints >=6 and 0 for <6
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this behaviour comming from? As there should be the same number of singular values as the number of joints, correct?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the number of singular values is the same as the number of joints. However, any singular values beyond the sixth which is S(5) will be zero (assuming SVs are ordered from high to low). We are interested in whether the sixth singular value is zero because that is when the determinant of J*J^T is zero and a Cartesian degree of freedom is lost. Then the condition corresponding to fabs(S(i))<eps (line 140) must be applied in order to compute the pseudoinverse.

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
Expand Down Expand Up @@ -129,6 +166,29 @@ namespace KDL
}
}

void ChainIkSolverVel_pinv::SortJntArrayMaxToMin(JntArray& Smaxtomin)
{
int n=Smaxtomin.rows();
for (int i=0; i<n; i++){
double S_max = Smaxtomin(i);
int i_max = i;
for (int j=i+1; j<n; j++){
double Sj = Smaxtomin(j);
if (Sj > 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;
}
}
return;
}

const char* ChainIkSolverVel_pinv::strError(const int error) const
{
if (E_CONVERGE_PINV_SINGULAR == error) return "Converged put pseudo inverse of jacobian is singular.";
Expand Down
43 changes: 41 additions & 2 deletions orocos_kdl/src/chainiksolvervel_pinv.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,19 +79,57 @@ 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 1 <= maxiter, otherwise maxiter is ignored
*/
void setMaxIter(const unsigned 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(),
* then the jacobian pseudoinverse is singular
*/
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 1 <= maxiter, otherwise maxiter is ignored
*/
unsigned 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;

Expand All @@ -108,10 +146,11 @@ namespace KDL
std::vector<JntArray> V;
JntArray tmp;
double eps;
int maxiter;
unsigned int maxiter;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is ABI breaking change. I can't accept this for now.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maxiter is an int type in the constructor.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, so why not also store it as an int, which is the current situation.

But I can't accept ABI breaking changes. So this one needs to be reverted.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still open issue

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how to revert this change in this system. Note that changing maxiter to an int might break the comparison in setMaxIter() which expects an unsigned int input;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can change that too....

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved this issue with second to last commit on the latest branch. "maxiter" was updated to int in several other places in the same commit.

unsigned int nrZeroSigmas;
int svdResult;

double sigmaMin;
JntArray Smaxtomin;
};
}
#endif
Expand Down
79 changes: 79 additions & 0 deletions orocos_kdl/tests/solvertest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,85 @@ void SolverTest::IkVelSolverWDLSTest()
}


void SolverTest::IkVelSolverPinvTest()
{
unsigned int maxiter = 30;
double eps = 1e-6;
unsigned 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. ;
q(1) = 0.5 ;
q(2) = 0.4 ;
q(3) = -PI_2 ;
q(4) = 0. ;
q(5) = 0. ;
q(6) = 0. ;

CPPUNIT_ASSERT_EQUAL((int)SolverI::E_NOERROR,
ikvelsolver.CartToJnt(q, dx, dq)) ; // pinv mode
CPPUNIT_ASSERT(1==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,(int)ikvelsolver.getSigma(S)) ;
for(unsigned int i=0;i<nj;i++) {
CPPUNIT_ASSERT_DOUBLES_EQUAL(Sexp(i),S(i),0.0001);
}
double Smin = ikvelsolver.getSigmaMin();
CPPUNIT_ASSERT_EQUAL(S(5),Smin);


std::cout<<"smallest singular value is below threshold"<<std::endl;

q(1) = 0.2 ;

CPPUNIT_ASSERT_EQUAL((int)ChainIkSolverVel_pinv::E_CONVERGE_PINV_SINGULAR,
ikvelsolver.CartToJnt(q, dx, dq)) ; // pinv mode
CPPUNIT_ASSERT_EQUAL((unsigned int)2,ikvelsolver.getNrZeroSigmas()) ; // 2 singular values

q(1) = 0.0 ;

CPPUNIT_ASSERT_EQUAL((int)ChainIkSolverVel_pinv::E_CONVERGE_PINV_SINGULAR,
ikvelsolver.CartToJnt(q, dx, dq)) ; // pinv mode
CPPUNIT_ASSERT_EQUAL((unsigned int)2,ikvelsolver.getNrZeroSigmas()) ; // 2 singular values

// fully singular
q(2) = 0.0 ;
q(3) = 0.0 ;

CPPUNIT_ASSERT_EQUAL((int)ChainIkSolverVel_pinv::E_CONVERGE_PINV_SINGULAR,
ikvelsolver.CartToJnt(q, dx, dq)) ; // pinv mode
CPPUNIT_ASSERT_EQUAL(4,(int)ikvelsolver.getNrZeroSigmas()) ;
}


void SolverTest::FkPosAndJacLocal(Chain& chain,ChainFkSolverPos& fksolverpos,ChainJntToJacSolver& jacsolver)
{
double deltaq = 1E-4;
Expand Down
2 changes: 2 additions & 0 deletions orocos_kdl/tests/solvertest.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class SolverTest : public CppUnit::TestFixture
CPPUNIT_TEST(ExternalWrenchEstimatorTest );
CPPUNIT_TEST(IkSingularValueTest );
CPPUNIT_TEST(IkVelSolverWDLSTest );
CPPUNIT_TEST(IkVelSolverPinvTest );
CPPUNIT_TEST(FkPosVectTest );
CPPUNIT_TEST(FkVelVectTest );
CPPUNIT_TEST(FdSolverDevelopmentTest );
Expand All @@ -58,6 +59,7 @@ class SolverTest : public CppUnit::TestFixture
void ExternalWrenchEstimatorTest();
void IkSingularValueTest() ;
void IkVelSolverWDLSTest();
void IkVelSolverPinvTest();
void FkPosVectTest();
void FkVelVectTest();
void FdSolverDevelopmentTest();
Expand Down