Skip to content
Open
63 changes: 63 additions & 0 deletions orocos_kdl/src/chainjnttojacsolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,68 @@ namespace KDL
}
return (error = E_NOERROR);
}

int ChainJntToJacSolver::JntToJac(const JntArray& q_in, std::vector<Jacobian>& jac, int seg_nr)
{
if(locked_joints_.size() != chain.getNrOfJoints())
return (error = E_NOT_UP_TO_DATE);
unsigned int segmentNr;
if(seg_nr<0)
segmentNr=chain.getNrOfSegments();
else
segmentNr = seg_nr;

//Initialize Jacobian to zero since only segmentNr columns are computed
SetToZero(jac[0]);

if( q_in.rows()!=chain.getNrOfJoints() || jac[0].columns() != chain.getNrOfJoints())
return (error = E_SIZE_MISMATCH);
else if(segmentNr>chain.getNrOfSegments())
return (error = E_OUT_OF_RANGE);
else if(jac.size() < segmentNr)
return (error = E_SIZE_MISMATCH);

T_tmp = Frame::Identity();
SetToZero(t_tmp);
int j=0;
int k=0;
Frame total;

// Loop through segments
for (unsigned int i=0;i<segmentNr;i++)
{
if (i > 0)
jac[i] = jac[i-1];
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please explain why you take the jacobian of the previous segment

Copy link
Author

Choose a reason for hiding this comment

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

This is just the initialization for the Jacobian in the current segment. The Jacobian for each segment builds upon the Jacobian for the previous segment. This is exactly the same algorithm as the original JntToJac but with the Jacobian for each segment stored in Jac[I].


// Calculate new Frame_base_ee
if (chain.getSegment(i).getJoint().getType() != Joint::Fixed)
{
// Pose of the new end-point expressed in the base
total = T_tmp * chain.getSegment(i).pose(q_in(j));
// Changing base of new segment's twist to base frame if it is not locked
if (!locked_joints_[j])
t_tmp = T_tmp.M * chain.getSegment(i).twist(q_in(j),1.0);
}
else
{
total = T_tmp * chain.getSegment(i).pose(0.0);
}

// Changing Refpoint of all columns to new ee
changeRefPoint(jac[i], total.p - T_tmp.p, jac[i]);

// Only increase jointnr if the segment has a joint
if (chain.getSegment(i).getJoint().getType() != Joint::Fixed)
{
//Only put the twist inside if it is not locked
if (!locked_joints_[j])
jac[i].setColumn(k++, t_tmp);
j++;
}

T_tmp = total;
}
return (error = E_NOERROR);
}
}

16 changes: 15 additions & 1 deletion orocos_kdl/src/chainjnttojacsolver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,27 @@ namespace KDL
* KDL::ChainFkSolverVel_recursive
*
* @param q_in input joint positions
* @param jac output jacobian
* @param jac output jacobian of last segment
* @param seg_nr The final segment to compute
* @return success/error code
*/
virtual int JntToJac(const JntArray& q_in, Jacobian& jac, int seg_nr=-1);

virtual ~ChainJntToJacSolver();
/**
* Calculate the jacobian expressed in the base frame of the
* chain, with reference point at the end effector of the
* *chain. The algorithm is similar to the one used in
* KDL::ChainFkSolverVel_recursive
*
* @param q_in input joint positions
* @param jac output array of jacobians for each segment
* @param seg_nr The final segment to compute
* @return success/error code
*/
virtual int JntToJac(const JntArray& q_in, std::vector<Jacobian>& jac, int seg_nr=-1);

/**
*
* @param locked_joints new values for locked joints
* @return success/error code
Expand Down
37 changes: 37 additions & 0 deletions orocos_kdl/tests/solvertest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,43 @@ void SolverTest::FkPosAndIkPosLocal(Chain& chain,ChainFkSolverPos& fksolverpos,
}


void SolverTest::JacAllSegments()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please also add this test in python

Copy link
Contributor

Choose a reason for hiding this comment

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

I can take a look at this

{
std::cout << "KDL Jac Solver Test for returning all segment Jacobians" << std::endl;

double eps = 1e-6;

unsigned int nj = motomansia10.getNrOfJoints();
unsigned int ns = motomansia10.getNrOfSegments();

JntArray q(nj);
Jacobian jac(nj);
std::vector<Jacobian> jac_all(ns, Jacobian(nj));

ChainJntToJacSolver jacsolver(motomansia10);

// random
q(0) = 0.2;
q(1) = 0.6;
q(2) = 1.;
q(3) = 0.5;
q(4) = -1.4;
q(5) = 0.3;
q(6) = -0.8;

CPPUNIT_ASSERT_EQUAL((int)SolverI::E_NOERROR, jacsolver.JntToJac(q, jac_all, ns));
for (unsigned int seg=0; seg<ns; seg++)
{
jacsolver.JntToJac(q, jac, seg+1);
for ( unsigned int i=0; i<jac.rows(); i++ ) {
for ( unsigned int j=0; j<nj; j++ ) {
CPPUNIT_ASSERT(Equal(jac(i,j), jac_all[seg](i,j), eps));
}
}
}
}


void SolverTest::VereshchaginTest()
{
std::cout << "KDL Vereshchagin Hybrid Dynamics Tests" <<std::endl;
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 @@ -33,6 +33,7 @@ class SolverTest : public CppUnit::TestFixture
CPPUNIT_TEST(FkVelAndJacTest );
CPPUNIT_TEST(FkVelAndIkVelTest );
CPPUNIT_TEST(FkPosAndIkPosTest );
CPPUNIT_TEST(JacAllSegments );
CPPUNIT_TEST(VereshchaginTest );
CPPUNIT_TEST(ExternalWrenchEstimatorTest );
CPPUNIT_TEST(IkSingularValueTest );
Expand All @@ -54,6 +55,7 @@ class SolverTest : public CppUnit::TestFixture
void FkVelAndJacTest();
void FkVelAndIkVelTest();
void FkPosAndIkPosTest();
void JacAllSegments();
void VereshchaginTest();
void ExternalWrenchEstimatorTest();
void IkSingularValueTest() ;
Expand Down
4 changes: 3 additions & 1 deletion python_orocos_kdl/PyKDL/kinfam.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,9 @@ void init_kinfam(pybind11::module &m)
// ------------------------------
py::class_<ChainJntToJacSolver, SolverI> chain_jnt_to_jac_solver(m, "ChainJntToJacSolver");
chain_jnt_to_jac_solver.def(py::init<const Chain&>(), py::arg("chain"));
chain_jnt_to_jac_solver.def("JntToJac", &ChainJntToJacSolver::JntToJac,
chain_jnt_to_jac_solver.def("JntToJac", (int (ChainJntToJacSolver::*)(const JntArray&, Jacobian&, int)) &ChainJntToJacSolver::JntToJac,
py::arg("q_in"), py::arg("jac"), py::arg("seg_nr")=-1);
chain_jnt_to_jac_solver.def("JntToJac", (int (ChainJntToJacSolver::*)(const JntArray&, std::vector<Jacobian>&, int)) &ChainJntToJacSolver::JntToJac,
Copy link
Collaborator

Choose a reason for hiding this comment

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

This doesn't work yet, see also

// Argument by reference doesn't work for container types
// chain_fk_solver_vel.def("JntToCart", (int (ChainFkSolverVel::*)(const JntArrayVel&, std::vector<FrameVel>&, int)) &ChainFkSolverVel::JntToCart,
// py::arg("q_in"), py::arg("p_out"), py::arg("segmentNr")=-1);

There are multiple ways to work around this. docs I don't like making custom vectors. I would go for converting this to a lamda function, which accepts a py::list instead of the vector. Then you need to copy from the vector to the python list.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Take a look at #497

Copy link
Contributor

Choose a reason for hiding this comment

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

I made these changes for Craig. These were just a copy/paste of existing code.
Are you saying that the existing code doesn't work and you would like that fixed? Or is there an error in the copy/paste itself?

Copy link
Collaborator

Choose a reason for hiding this comment

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

What I am saying is that pybind can't handle references of container arguments. So when a reference container argument is an output of the function, you don't get the update value of the argument. I will be same as when you called the function. So see #497 for how I fixed it for another function with a reference container argument.

py::arg("q_in"), py::arg("jac"), py::arg("seg_nr")=-1);
chain_jnt_to_jac_solver.def("setLockedJoints", &ChainJntToJacSolver::setLockedJoints, py::arg("locked_joints"));

Expand Down
Loading