diff --git a/CMakeLists.txt b/CMakeLists.txt index 827c626c0c21b834affe1c8659adaa331daaef68..e7ac94b0471a2b46b7819b4b918077efff412563 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,7 +55,7 @@ SET(${PROJECT_NAME}_HEADERS tools/timer.hpp algorithm/rnea.hpp algorithm/crba.hpp - algorithm/crba2.hpp + algorithm/jacobian.hpp algorithm/cholesky.hpp algorithm/kinematics.hpp ) @@ -103,6 +103,9 @@ ADD_EXECUTABLE(crba EXCLUDE_FROM_ALL unittest/crba.cpp) PKG_CONFIG_USE_DEPENDENCY(crba eigenpy) PKG_CONFIG_USE_DEPENDENCY(crba urdfdom) +ADD_EXECUTABLE(jacobian EXCLUDE_FROM_ALL unittest/jacobian.cpp) +PKG_CONFIG_USE_DEPENDENCY(jacobian eigenpy) + ADD_EXECUTABLE(cholesky EXCLUDE_FROM_ALL unittest/cholesky.cpp) PKG_CONFIG_USE_DEPENDENCY(cholesky eigenpy) PKG_CONFIG_USE_DEPENDENCY(cholesky urdfdom) diff --git a/src/algorithm/jacobian.hpp b/src/algorithm/jacobian.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a3883002250fa39460a0d2b31c877bb49e049042 --- /dev/null +++ b/src/algorithm/jacobian.hpp @@ -0,0 +1,90 @@ +#ifndef __se3_jacobian_hpp__ +#define __se3_jacobian_hpp__ + +#include "pinocchio/multibody/visitor.hpp" +#include "pinocchio/multibody/model.hpp" +#include <iostream> + #include <boost/utility/binary.hpp> + +namespace se3 +{ + // inline const Eigen::MatrixXd& + // jacobian(const Model & model, + // Data& data, + // const Eigen::VectorXd & q); + +} // namespace se3 + +/* --- Details -------------------------------------------------------------------- */ +namespace se3 +{ + struct JacobianForwardStep : public fusion::JointVisitor<JacobianForwardStep> + { + typedef boost::fusion::vector< const se3::Model&, + se3::Data&, + const Eigen::VectorXd & + > ArgsType; + + JOINT_VISITOR_INIT(JacobianForwardStep); + + template<typename JointModel> + static void algo(const se3::JointModelBase<JointModel> & jmodel, + se3::JointDataBase<typename JointModel::JointData> & jdata, + const se3::Model& model, + se3::Data& data, + const Eigen::VectorXd & q) + { + using namespace Eigen; + using namespace se3; + + const Model::Index & i = jmodel.id(); + const Model::Index & parent = model.parents[i]; + + jmodel.calc(jdata.derived(),q); + + data.liMi[i] = model.jointPlacements[i]*jdata.M(); + if(parent>0) data.oMi[i] = data.oMi[parent]*data.liMi[i]; + else data.oMi[i] = data.liMi[i]; + + // std::cout << data.oMi[i] << std::endl << std::endl; + // std::cout << data.oMi[i].toActionMatrix() << std::endl << std::endl; + // std::cout << data.oMi[i].act(jdata.S()) << std::endl << std::endl; + data.J.block(0,jmodel.idx_v(),6,jmodel.nv()) = data.oMi[i].act(jdata.S()); + } + + }; + + + inline const Eigen::MatrixXd& + computeJacobian(const Model & model, Data& data, + const Eigen::VectorXd & q) + { + for( int i=1;i<model.nbody;++i ) + { + JacobianForwardStep::run(model.joints[i],data.joints[i], + JacobianForwardStep::ArgsType(model,data,q)); + } + + return data.J; + } + + template<bool localFrame> + void getJacobian(const Model & model, const Data& data, + Model::Index jointId, Eigen::MatrixXd & J) + { + assert( J.rows() == data.J.rows() ); + assert( J.cols() == data.J.cols() ); + + const SE3 & oMjoint = data.oMi[jointId]; + int colRef = nv(model.joints[jointId])+idx_v(model.joints[jointId])-1; + for(int j=colRef;j>=0;j=data.parents_fromRow[j]) + { + if(! localFrame ) J.col(j) = data.J.col(j); + // else J.col(j) = oMi.actInv(Motion(data.J.col(j))); + } + } + +} // namespace se3 + +#endif // ifndef __se3_jacobian_hpp__ + diff --git a/src/multibody/joint/joint-base.hpp b/src/multibody/joint/joint-base.hpp index 9293e218bf92af00f2e8fe0631c0a22f632fb0ec..fd9b2b104ef5834fa856e02e56f54eeae6621704 100644 --- a/src/multibody/joint/joint-base.hpp +++ b/src/multibody/joint/joint-base.hpp @@ -40,6 +40,12 @@ namespace se3 * JointInertia::block = J::Constraint::Transpose*F */ + /* Jacobian operations + * + * internal::ActionReturn<Constraint>::Type + * Constraint::se3Action + */ + #define SE3_JOINT_TYPEDEF \ typedef int Index; \ typedef typename traits<Joint>::JointData JointData; \ diff --git a/src/multibody/joint/joint-free-flyer.hpp b/src/multibody/joint/joint-free-flyer.hpp index 977cdd93f1b877b59252c88a71462f8e617700e1..a6bcb95e0e241e648c4c9c4acb09db5de73781d4 100644 --- a/src/multibody/joint/joint-free-flyer.hpp +++ b/src/multibody/joint/joint-free-flyer.hpp @@ -21,6 +21,8 @@ namespace se3 struct ConstraintIdentity { + SE3::Matrix6 se3Action(const SE3 & m) const { return m.toActionMatrix(); } + struct TransposeConst { Force::Vector6 operator* (const Force & phi) @@ -38,7 +40,6 @@ namespace se3 }; - /* [CRBA] ForceSet operator* (Inertia Y,Constraint S) */ Inertia::Matrix6 operator*( const Inertia& Y,const JointFreeFlyer::ConstraintIdentity & ) { @@ -53,6 +54,12 @@ namespace se3 return F; } + namespace internal + { + template<> + struct ActionReturn<JointFreeFlyer::ConstraintIdentity > + { typedef SE3::Matrix6 Type; }; + } template<> diff --git a/src/multibody/joint/joint-revolute.hpp b/src/multibody/joint/joint-revolute.hpp index 2e898d6995bda29b034fc4849ffd06a5ae55b2a3..666a7d3a3265f7c3aaf4444783c914690e8df61a 100644 --- a/src/multibody/joint/joint-revolute.hpp +++ b/src/multibody/joint/joint-revolute.hpp @@ -54,7 +54,9 @@ namespace se3 } }; // struct MotionRevolute - friend const MotionRevolute& operator+ (const MotionRevolute& m, const BiasZero&) { return m; } + friend const MotionRevolute& operator+ (const MotionRevolute& m, const BiasZero&) + { return m; } + friend Motion operator+( const MotionRevolute& m1, const Motion& m2) { return Motion( m2.linear(),m2.angular()+typename revolute::CartesianVector3<axis>(m1.w)); @@ -62,7 +64,16 @@ namespace se3 struct ConstraintRevolute { template<typename D> - MotionRevolute operator*( const Eigen::MatrixBase<D> & v ) const { return MotionRevolute(v[0]); } + MotionRevolute operator*( const Eigen::MatrixBase<D> & v ) const + { return MotionRevolute(v[0]); } + + Eigen::Matrix<double,6,1> se3Action(const SE3 & m) const + { + Eigen::Matrix<double,6,1> res; + res.head<3>() = m.translation().cross( m.rotation().col(0)); + res.tail<3>() = m.rotation().col(0); + return res; + } struct TransposeConst { @@ -85,6 +96,7 @@ namespace se3 }; TransposeConst transpose() const { return TransposeConst(*this); } + /* CRBA joint operators * - ForceSet::Block = ForceSet * - ForceSet operator* (Inertia Y,Constraint S) @@ -230,6 +242,21 @@ namespace se3 return res; } + namespace internal + { + // TODO: I am not able to write the next three lines as a template. Why? + template<> + struct ActionReturn<typename JointRevolute<0>::ConstraintRevolute > + { typedef Eigen::Matrix<double,6,1> Type; }; + template<> + struct ActionReturn<typename JointRevolute<1>::ConstraintRevolute > + { typedef Eigen::Matrix<double,6,1> Type; }; + template<> + struct ActionReturn<typename JointRevolute<2>::ConstraintRevolute > + { typedef Eigen::Matrix<double,6,1> Type; }; + } + + template<int axis> struct traits< JointRevolute<axis> > diff --git a/src/multibody/model.hpp b/src/multibody/model.hpp index 34c64673133ac5fa21dc7d2e351d5a53f254b9cd..d6d3eb12e3730ae6f4a184dd2fb1ecca196e6c8b 100644 --- a/src/multibody/model.hpp +++ b/src/multibody/model.hpp @@ -89,6 +89,7 @@ namespace se3 std::vector<int> parents_fromRow; // First previous non-zero row in M (used in Cholesky) std::vector<int> nvSubtree_fromRow; // + Eigen::MatrixXd J; // Jacobian of joint placement Data( const Model& ref ); @@ -193,6 +194,7 @@ namespace se3 ,tmp(ref.nv) ,parents_fromRow(ref.nv) ,nvSubtree_fromRow(ref.nv) + ,J(6,ref.nv) { for(int i=0;i<model.nbody;++i) joints.push_back(CreateJointData::run(model.joints[i])); @@ -205,6 +207,9 @@ namespace se3 /* Init for Cholesky */ U = Eigen::MatrixXd::Identity(ref.nv,ref.nv); computeParents_fromRow(ref); + + /* Init Jacobian */ + J.fill(0); } void Data::computeLastChild(const Model& model) diff --git a/unittest/jacobian.cpp b/unittest/jacobian.cpp new file mode 100644 index 0000000000000000000000000000000000000000..18fe497e4ac98f1cb51b6d2894be9b609628fd56 --- /dev/null +++ b/unittest/jacobian.cpp @@ -0,0 +1,90 @@ +#include "pinocchio/multibody/model.hpp" +#include "pinocchio/algorithm/jacobian.hpp" +#include "pinocchio/algorithm/rnea.hpp" +#include <iostream> +#include <boost/utility/binary.hpp> + +#include "pinocchio/tools/timer.hpp" +#include "pinocchio/multibody/parser/sample-models.hpp" + + +void timings(const se3::Model & model, se3::Data& data, long flag) +{ + using namespace se3; + StackTicToc timer(StackTicToc::US); +#ifdef NDEBUG + const int NBT = 1000*1000; +#else + const int NBT = 1; +#endif + + bool verbose = flag & (flag-1) ; // True is two or more binaries of the flag are 1. + if(verbose) std::cout <<"--" << std::endl; + Eigen::VectorXd q = Eigen::VectorXd::Zero(model.nq); + + if( flag >> 0 & 1 ) + { + timer.tic(); + SMOOTH(NBT) + { + computeJacobian(model,data,q); + } + if(verbose) std::cout << "Compute =\t"; + timer.toc(std::cout,NBT); + } + if( flag >> 1 & 1 ) + { + computeJacobian(model,data,q); + Model::Index idx = model.existBodyName("rarm6")?model.getBodyId("rarm6"):model.nbody-1; + Eigen::MatrixXd Jrh(6,model.nv); Jrh.fill(0); + + timer.tic(); + SMOOTH(NBT) + { + getJacobian<false>(model,data,idx,Jrh); + } + if(verbose) std::cout << "Copy =\t"; + timer.toc(std::cout,NBT); + } +} + +void assertValues(const se3::Model & model, se3::Data& data) +{ + using namespace Eigen; + using namespace se3; + + VectorXd q = VectorXd::Zero(model.nq); + computeJacobian(model,data,q); + + Model::Index idx = model.existBodyName("rarm2")?model.getBodyId("rarm2"):model.nbody-1; + MatrixXd Jrh(6,model.nv); Jrh.fill(0); + getJacobian<false>(model,data,idx,Jrh); + + VectorXd qdot = VectorXd::Random(model.nv); + VectorXd qddot = VectorXd::Zero(model.nv); + rnea( model,data,q,qdot,qddot ); + + Motion v = data.oMi[idx].act( data.v[idx] ); + assert( v.toVector().isApprox( Jrh*qdot )); + + std::cout << "Jrh = [ " << Jrh << " ];" << std::endl; + std::cout << "J = [ " << data.J << " ];" << std::endl; +} + +int main() +{ + using namespace Eigen; + using namespace se3; + + se3::Model model; + se3::buildModels::humanoidSimple(model); + se3::Data data(model); + +#ifndef NDEBUG + assertValues(model,data); +#else + timings(model,data,BOOST_BINARY(11)); +#endif + + return 0; +}