#include "rbdl_tests.h" #include "rbdl/rbdl.h" #include "rbdl/Constraints.h" #include #include "PendulumModels.h" using namespace std; using namespace RigidBodyDynamics; using namespace RigidBodyDynamics::Math; const double TEST_PREC = 1.0e-11; struct PinJointCustomConstraint : public RigidBodyDynamics::CustomConstraint { PinJointCustomConstraint():RigidBodyDynamics::CustomConstraint(5){ } PinJointCustomConstraint(unsigned int x0y1z2):RigidBodyDynamics::CustomConstraint(5){ TuP.resize(mConstraintCount); for(unsigned int i=0; i(3,0) = rmP0.transpose() * (r0S0 - r0P0); for(unsigned int i=0; i < TuP.size(); ++i){ errPos[i+errStartIndex] = TuP[i].transpose()*err; } } virtual void CalcVelocityError( Model &UNUSED(model), unsigned int UNUSED(custom_constraint_id), const Math::VectorNd &UNUSED(Q), const Math::VectorNd &QDot, ConstraintSet &UNUSED(CS), const Math::MatrixNd &Gblock, Math::VectorNd &errVel, unsigned int errStartIndex) { //Since this is a time-invariant constraint the expression for //the velocity error is quite straight forward: errVelBlock = Gblock*QDot; for(unsigned int i=0; i < errVelBlock.rows();++i){ errVel[errStartIndex+i] = errVelBlock[i]; } } std::vector < SpatialVector > TuP; //Constraint direction vectors resolved in //the frame that P is on. SpatialVector err, eT0, eT0Dot, v0P0, v0S0, dv0P0nl ,dv0S0nl; Vector3d r0P0, r0S0; Matrix3d rmP0, rmS0, rmPS; SpatialTransform xP0; VectorNd errVelBlock; }; struct DoublePerpendicularPendulumCustomConstraint { DoublePerpendicularPendulumCustomConstraint() : model() , cs() , q() , qd() , qdd() , tau() , l1(1.) , l2(1.) , m1(1.) , m2(1.) , idB1(0) , idB2(0) , X_p1(Xtrans(Vector3d(0., 0., 0.))) , X_s1(Xtrans(Vector3d(0., 0., 0.))) , X_p2(Xtrans(Vector3d(0.,-l1, 0.))) , X_s2(Xtrans(Vector3d(0., 0., 0.))){ model.gravity = Vector3d(0.,-9.81,0.); //Planar pendulum is at 0 when it is hanging down. // x: points to the right // y: points up // z: out of the page Body link1 = Body(m1, Vector3d( 0., -l1*0.5, 0.), Matrix3d( m1*l1*l1/3., 0., 0., 0., m1*l1*l1/30., 0., 0., 0., m1*l1*l1/3.)); Body link2 = Body(m2, Vector3d( l2*0.5, 0., 0.), Matrix3d( m2*l2*l2/30., 0., 0., 0., m2*l2*l2/3., 0., 0., 0., m2*l2*l2/3.)); //Joint joint_free(JointTypeFloatingBase); Joint jointEA123T123(SpatialVector(0.,0.,0.,1.,0.,0.), SpatialVector(0.,0.,0.,0.,1.,0.), SpatialVector(0.,0.,0.,0.,0.,1.), SpatialVector(0.,0.,1.,0.,0.,0.), SpatialVector(0.,1.,0.,0.,0.,0.), SpatialVector(1.,0.,0.,0.,0.,0.)); idB1 = model.AddBody(0, Xtrans(Vector3d(0., 0., 0. )), jointEA123T123, link1); idB2 = model.AddBody(0, Xtrans(Vector3d(0., 0., 0.)), jointEA123T123, link2); //Make the revolute joints about the y axis using 5 constraints //between the end points ccPJZaxis = PinJointCustomConstraint(2); ccPJYaxis = PinJointCustomConstraint(1); cs.AddCustomConstraint(&ccPJZaxis, 0,idB1, X_p1, X_s1, false, 0.1); cs.AddCustomConstraint(&ccPJYaxis,idB1,idB2, X_p2, X_s2, false, 0.1); cs.Bind(model); q = VectorNd::Zero(model.dof_count); qd = VectorNd::Zero(model.dof_count); qdd = VectorNd::Zero(model.dof_count); tau = VectorNd::Zero(model.dof_count); } Model model; ConstraintSet cs; VectorNd q; VectorNd qd; VectorNd qdd; VectorNd tau; double l1; double l2; double m1; double m2; unsigned int idB1; unsigned int idB2; unsigned int idB01; unsigned int idB02; SpatialTransform X_p1; SpatialTransform X_s1; SpatialTransform X_p2; SpatialTransform X_s2; PinJointCustomConstraint ccPJZaxis; PinJointCustomConstraint ccPJYaxis; }; TEST_CASE (__FILE__"_CustomConstraintCorrectnessTest", "") { //Test to add: // Jacobian vs. num Jacobian DoublePerpendicularPendulumCustomConstraint dbcc = DoublePerpendicularPendulumCustomConstraint(); DoublePerpendicularPendulumAbsoluteCoordinates dba = DoublePerpendicularPendulumAbsoluteCoordinates(); DoublePerpendicularPendulumJointCoordinates dbj = DoublePerpendicularPendulumJointCoordinates(); //1. Set the pendulum modeled using joint coordinates to a specific // state and then compute the spatial acceleration of the body. dbj.q[0] = M_PI/3.0; //About z0 dbj.q[1] = M_PI/6.0; //About y1 dbj.qd[0] = M_PI; //About z0 dbj.qd[1] = M_PI/2.0; //About y1 dbj.tau[0]= 0.; dbj.tau[1]= 0.; ForwardDynamics(dbj.model,dbj.q,dbj.qd,dbj.tau,dbj.qdd); Vector3d r010 = CalcBodyToBaseCoordinates( dbj.model,dbj.q,dbj.idB1, Vector3d(0.,0.,0.),true); Vector3d r020 = CalcBodyToBaseCoordinates( dbj.model,dbj.q,dbj.idB2, Vector3d(0.,0.,0.),true); // Vector3d r030 = CalcBodyToBaseCoordinates( // dbj.model,dbj.q,dbj.idB2, // Vector3d(dbj.l2,0.,0.),true); SpatialVector v010 = CalcPointVelocity6D( dbj.model,dbj.q,dbj.qd,dbj.idB1, Vector3d(0.,0.,0.),true); SpatialVector v020 = CalcPointVelocity6D( dbj.model,dbj.q,dbj.qd,dbj.idB2, Vector3d(0.,0.,0.),true); // SpatialVector v030 = CalcPointVelocity6D( // dbj.model,dbj.q,dbj.qd,dbj.idB2, // Vector3d(dbj.l2,0.,0.),true); SpatialVector a010 = CalcPointAcceleration6D( dbj.model,dbj.q,dbj.qd,dbj.qdd, dbj.idB1,Vector3d(0.,0.,0.),true); SpatialVector a020 = CalcPointAcceleration6D( dbj.model,dbj.q,dbj.qd,dbj.qdd, dbj.idB2,Vector3d(0.,0.,0.),true); SpatialVector a030 = CalcPointAcceleration6D( dbj.model,dbj.q,dbj.qd,dbj.qdd, dbj.idB2,Vector3d(dbj.l2,0.,0.),true); //2. Set the pendulum modelled using absolute coordinates to the // equivalent state as the pendulum modelled using joint // coordinates. Next double qError = 1.0; double qDotError = 1.0; //Pefectly initialize the pendulum made with custom constraints and //perturb the initialization a bit. dbcc.q[0] = r010[0]; dbcc.q[1] = r010[1]+qError; dbcc.q[2] = r010[2]; dbcc.q[3] = dbj.q[0]; dbcc.q[4] = 0; dbcc.q[5] = 0; dbcc.q[6] = r020[0]; dbcc.q[7] = r020[1]; dbcc.q[8] = r020[2]; dbcc.q[9] = dbj.q[0]; dbcc.q[10] = dbj.q[1]; dbcc.q[11] = 0; dbcc.qd[0] = v010[3]; dbcc.qd[1] = v010[4]+qDotError; dbcc.qd[2] = v010[5]; dbcc.qd[3] = dbj.qd[0]; dbcc.qd[4] = 0; dbcc.qd[5] = 0; dbcc.qd[6] = v020[3]; dbcc.qd[7] = v020[4]; dbcc.qd[8] = v020[5]; dbcc.qd[9] = dbj.qd[0]; dbcc.qd[10] = dbj.qd[1]; dbcc.qd[11] = 0; VectorNd err(dbcc.cs.size()); VectorNd errd(dbcc.cs.size()); CalcConstraintsPositionError(dbcc.model,dbcc.q,dbcc.cs,err,true); CalcConstraintsVelocityError(dbcc.model,dbcc.q,dbcc.qd,dbcc.cs,errd,true); REQUIRE (err.norm() >= qError); REQUIRE (errd.norm() >= qDotError); //Solve for the initial q and qdot terms that satisfy the constraints VectorNd qAsm,qDotAsm,w; qAsm.resize(dbcc.q.rows()); qDotAsm.resize(dbcc.q.rows()); w.resize(dbcc.q.rows()); for(unsigned int i=0; i