void check_self_consistency(SkeletonPtr skeleton) { for(size_t i=0; i<skeleton->getNumBodyNodes(); ++i) { BodyNode* bn = skeleton->getBodyNode(i); EXPECT_TRUE(bn->getIndexInSkeleton() == i); EXPECT_TRUE(skeleton->getBodyNode(bn->getName()) == bn); Joint* joint = bn->getParentJoint(); EXPECT_TRUE(skeleton->getJoint(joint->getName()) == joint); for(size_t j=0; j<joint->getNumDofs(); ++j) { DegreeOfFreedom* dof = joint->getDof(j); EXPECT_TRUE(dof->getIndexInJoint() == j); EXPECT_TRUE(skeleton->getDof(dof->getName()) == dof); } } for(size_t i=0; i<skeleton->getNumDofs(); ++i) { DegreeOfFreedom* dof = skeleton->getDof(i); EXPECT_TRUE(dof->getIndexInSkeleton() == i); EXPECT_TRUE(skeleton->getDof(dof->getName()) == dof); } }
SkeletonPtr createWall() { SkeletonPtr wall = Skeleton::create("wall"); BodyNode* bn = wall->createJointAndBodyNodePair<WeldJoint>().second; std::shared_ptr<BoxShape> shape = std::make_shared<BoxShape>( Eigen::Vector3d(default_wall_thickness, default_ground_width, default_wall_height)); auto shapeNode = bn->createShapeNodeWith<VisualAddon, CollisionAddon, DynamicsAddon>(shape); shapeNode->getVisualAddon()->setColor(Eigen::Vector3d(0.8, 0.8, 0.8)); Eigen::Isometry3d tf(Eigen::Isometry3d::Identity()); tf.translation() = Eigen::Vector3d( (default_ground_width + default_wall_thickness)/2.0, 0.0, (default_wall_height - default_wall_thickness)/2.0); bn->getParentJoint()->setTransformFromParentBodyNode(tf); bn->setRestitutionCoeff(0.2); return wall; }
//============================================================================== void SoftDynamicsTest::compareEquationsOfMotion(const std::string& _fileName) { using namespace std; using namespace Eigen; using namespace dart; using namespace math; using namespace dynamics; using namespace simulation; using namespace utils; //---------------------------- Settings -------------------------------------- // Number of random state tests for each skeletons #ifndef NDEBUG // Debug mode size_t nRandomItr = 1; #else size_t nRandomItr = 1; #endif // Lower and upper bound of configuration for system double lb = -1.5 * DART_PI; double ub = 1.5 * DART_PI; // Lower and upper bound of joint damping and stiffness double lbD = 0.0; double ubD = 10.0; double lbK = 0.0; double ubK = 10.0; simulation::World* myWorld = NULL; //----------------------------- Tests ---------------------------------------- // Check whether multiplication of mass matrix and its inverse is identity // matrix. myWorld = utils::SkelParser::readWorld(_fileName); EXPECT_TRUE(myWorld != NULL); for (size_t i = 0; i < myWorld->getNumSkeletons(); ++i) { dynamics::Skeleton* skel = myWorld->getSkeleton(i); dynamics::Skeleton* softSkel = dynamic_cast<dynamics::Skeleton*>(skel); int dof = skel->getNumDofs(); // int nBodyNodes = skel->getNumBodyNodes(); int nSoftBodyNodes = 0; if (softSkel != NULL) nSoftBodyNodes = softSkel->getNumSoftBodyNodes(); if (dof == 0) { dtmsg << "Skeleton [" << skel->getName() << "] is skipped since it has " << "0 DOF." << endl; continue; } for (size_t j = 0; j < nRandomItr; ++j) { // Random joint stiffness and damping coefficient for (size_t k = 0; k < skel->getNumBodyNodes(); ++k) { BodyNode* body = skel->getBodyNode(k); Joint* joint = body->getParentJoint(); int localDof = joint->getNumDofs(); for (int l = 0; l < localDof; ++l) { joint->setDampingCoefficient(l, random(lbD, ubD)); joint->setSpringStiffness (l, random(lbK, ubK)); double lbRP = joint->getPositionLowerLimit(l); double ubRP = joint->getPositionUpperLimit(l); joint->setRestPosition (l, random(lbRP, ubRP)); } } // Set random states VectorXd x = skel->getState(); for (int k = 0; k < x.size(); ++k) x[k] = random(lb, ub); skel->setState(x); skel->computeForwardKinematics(true, true, false); //------------------------ Mass Matrix Test ---------------------------- // Get matrices MatrixXd M = skel->getMassMatrix(); MatrixXd M2 = getMassMatrix(skel); MatrixXd InvM = skel->getInvMassMatrix(); MatrixXd M_InvM = M * InvM; MatrixXd InvM_M = InvM * M; MatrixXd AugM = skel->getAugMassMatrix(); MatrixXd AugM2 = getAugMassMatrix(skel); MatrixXd InvAugM = skel->getInvAugMassMatrix(); MatrixXd AugM_InvAugM = AugM * InvAugM; MatrixXd InvAugM_AugM = InvAugM * AugM; MatrixXd I = MatrixXd::Identity(dof, dof); // Check if the number of generalized coordinates and dimension of mass // matrix are same. EXPECT_EQ(M.rows(), dof); EXPECT_EQ(M.cols(), dof); // Check mass matrix EXPECT_TRUE(equals(M, M2, 1e-6)); if (!equals(M, M2, 1e-6)) { cout << "M :" << endl << M << endl << endl; cout << "M2:" << endl << M2 << endl << endl; } // Check augmented mass matrix EXPECT_TRUE(equals(AugM, AugM2, 1e-6)); if (!equals(AugM, AugM2, 1e-6)) { cout << "AugM :" << endl << AugM << endl << endl; cout << "AugM2:" << endl << AugM2 << endl << endl; } // Check if both of (M * InvM) and (InvM * M) are identity. EXPECT_TRUE(equals(M_InvM, I, 1e-6)); if (!equals(M_InvM, I, 1e-6)) { cout << "InvM :" << endl << InvM << endl << endl; } EXPECT_TRUE(equals(InvM_M, I, 1e-6)); if (!equals(InvM_M, I, 1e-6)) { cout << "InvM_M:" << endl << InvM_M << endl << endl; } // Check if both of (M * InvM) and (InvM * M) are identity. EXPECT_TRUE(equals(AugM_InvAugM, I, 1e-6)); if (!equals(AugM_InvAugM, I, 1e-6)) { cout << "InvAugM :" << endl << InvAugM << endl << endl; cout << "InvAugM2 :" << endl << AugM.inverse() << endl << endl; cout << "AugM_InvAugM :" << endl << AugM_InvAugM << endl << endl; } EXPECT_TRUE(equals(InvAugM_AugM, I, 1e-6)); if (!equals(InvAugM_AugM, I, 1e-6)) { cout << "InvAugM_AugM:" << endl << InvAugM_AugM << endl << endl; } //------- Coriolis Force Vector and Combined Force Vector Tests -------- // Get C1, Coriolis force vector using recursive method VectorXd C = skel->getCoriolisForces(); VectorXd Cg = skel->getCoriolisAndGravityForces(); // Get C2, Coriolis force vector using inverse dynamics algorithm Vector3d oldGravity = skel->getGravity(); VectorXd oldTau = skel->getForces(); VectorXd oldDdq = skel->getAccelerations(); // TODO(JS): Save external forces of body nodes vector<double> oldKv(nSoftBodyNodes, 0.0); vector<double> oldKe(nSoftBodyNodes, 0.0); vector<double> oldD(nSoftBodyNodes, 0.0); for (int k = 0; k < nSoftBodyNodes; ++k) { assert(softSkel != NULL); dynamics::SoftBodyNode* sbn = softSkel->getSoftBodyNode(k); oldKv[k] = sbn->getVertexSpringStiffness(); oldKe[k] = sbn->getEdgeSpringStiffness(); oldD[k] = sbn->getDampingCoefficient(); } skel->resetForces(); skel->clearExternalForces(); skel->setAccelerations(VectorXd::Zero(dof)); for (int k = 0; k < nSoftBodyNodes; ++k) { assert(softSkel != NULL); dynamics::SoftBodyNode* sbn = softSkel->getSoftBodyNode(k); sbn->setVertexSpringStiffness(0.0); sbn->setEdgeSpringStiffness(0.0); sbn->setDampingCoefficient(0.0); } EXPECT_TRUE(skel->getForces() == VectorXd::Zero(dof)); EXPECT_TRUE(skel->getExternalForces() == VectorXd::Zero(dof)); EXPECT_TRUE(skel->getAccelerations() == VectorXd::Zero(dof)); skel->setGravity(Vector3d::Zero()); EXPECT_TRUE(skel->getGravity() == Vector3d::Zero()); skel->computeInverseDynamics(false, false); VectorXd C2 = skel->getForces(); skel->setGravity(oldGravity); EXPECT_TRUE(skel->getGravity() == oldGravity); skel->computeInverseDynamics(false, false); VectorXd Cg2 = skel->getForces(); EXPECT_TRUE(equals(C, C2, 1e-6)); if (!equals(C, C2, 1e-6)) { cout << "C :" << C.transpose() << endl; cout << "C2:" << C2.transpose() << endl; } EXPECT_TRUE(equals(Cg, Cg2, 1e-6)); if (!equals(Cg, Cg2, 1e-6)) { cout << "Cg :" << Cg.transpose() << endl; cout << "Cg2:" << Cg2.transpose() << endl; } skel->setForces(oldTau); skel->setAccelerations(oldDdq); // TODO(JS): Restore external forces of body nodes } } delete myWorld; }
//============================================================================== void ConstraintTest::SingleContactTest(const std::string& /*_fileName*/) { using namespace std; using namespace Eigen; using namespace dart::math; using namespace dart::collision; using namespace dart::constraint; using namespace dart::dynamics; using namespace dart::simulation; using namespace dart::io; //---------------------------------------------------------------------------- // Settings //---------------------------------------------------------------------------- // Number of random state tests for each skeletons #ifndef NDEBUG // Debug mode // std::size_t testCount = 1; #else // std::size_t testCount = 1; #endif WorldPtr world = World::create(); EXPECT_TRUE(world != nullptr); world->setGravity(Vector3d(0.0, -10.00, 0.0)); world->setTimeStep(0.001); world->getConstraintSolver()->setCollisionDetector( DARTCollisionDetector::create()); SkeletonPtr sphereSkel = createSphere(0.05, Vector3d(0.0, 1.0, 0.0)); BodyNode* sphere = sphereSkel->getBodyNode(0); Joint* sphereJoint = sphere->getParentJoint(); sphereJoint->setVelocity(3, Random::uniform(-2.0, 2.0)); // x-axis sphereJoint->setVelocity(5, Random::uniform(-2.0, 2.0)); // z-axis world->addSkeleton(sphereSkel); EXPECT_EQ(sphereSkel->getGravity(), world->getGravity()); assert(sphere); SkeletonPtr boxSkel = createBox(Vector3d(1.0, 1.0, 1.0), Vector3d(0.0, 1.0, 0.0)); BodyNode* box = boxSkel->getBodyNode(0); Joint* boxJoint = box->getParentJoint(); boxJoint->setVelocity(3, Random::uniform(-2.0, 2.0)); // x-axis boxJoint->setVelocity(5, Random::uniform(-2.0, 2.0)); // z-axis // world->addSkeleton(boxSkel); // EXPECT_EQ(boxSkel->getGravity(), world->getGravity()); // assert(box); SkeletonPtr groundSkel = createGround(Vector3d(10000.0, 0.1, 10000.0), Vector3d(0.0, -0.05, 0.0)); groundSkel->setMobile(false); // BodyNode* ground = groundSkel->getBodyNode(0); world->addSkeleton(groundSkel); EXPECT_EQ(groundSkel->getGravity(), world->getGravity()); // assert(ground); EXPECT_EQ((int)world->getNumSkeletons(), 2); // Lower and upper bound of configuration for system // double lb = -1.5 * constantsd::pi(); // double ub = 1.5 * constantsd::pi(); int maxSteps = 500; for (int i = 0; i < maxSteps; ++i) { // Vector3d pos1 = sphere->getWorldTransform().translation(); // Vector3d vel1 = sphere->getWorldLinearVelocity(pos1); // std::cout << "pos1:" << pos1.transpose() << std::endl; // std::cout << "vel1:" << vel1.transpose() << std::endl; if (!world->checkCollision()) { world->step(); continue; } // for (std::size_t j = 0; j < cd->getNumContacts(); ++j) // { // Contact contact = cd->getContact(j); // Vector3d pos1 = sphere->getTransform().inverse() * contact.point; // Vector3d vel1 = sphere->getWorldLinearVelocity(pos1); // std::cout << "pos1:" << pos1.transpose() << std::endl; // std::cout << "vel1:" << vel1.transpose() << std::endl; // } world->step(); const auto& result = world->getConstraintSolver()->getLastCollisionResult(); for (const auto& contact : result.getContacts()) { Vector3d pos1 = sphere->getTransform().inverse() * contact.point; Vector3d vel1 = sphere->getLinearVelocity(pos1); // std::cout << "pos1:" << pos1.transpose() << std::endl; // std::cout << "pos1[1]: " << pos1[1] << std::endl; // std::cout << "pos1:" << pos1.transpose() << std::endl; std::cout << "vel1:" << vel1.transpose() << ", pos1[1]: " << pos1[1] << std::endl; // EXPECT_NEAR(pos1[0], 0.0, 1e-9); // EXPECT_NEAR(pos1[1], -0.05, 1e-2); // EXPECT_NEAR(pos1[2], 0.0, 1e-9); // EXPECT_NEAR(vel1[0], 0.0, 1e-9); // EXPECT_NEAR(vel1[1], 0.0, 1e-9); // EXPECT_NEAR(vel1[2], 0.0, 1e-9); // if (!equals(vel1, Vector3d(0.0, 0.0, 0.0))) // std::cout << "vel1:" << vel1.transpose() << std::endl; // EXPECT_EQ(vel1, Vector3d::Zero()); } // std::cout << std::endl; break; } }
//============================================================================== void DynamicsTest::testImpulseBasedDynamics(const std::string& _fileName) { using namespace std; using namespace Eigen; using namespace dart; using namespace math; using namespace dynamics; using namespace simulation; using namespace utils; //---------------------------- Settings -------------------------------------- // Number of random state tests for each skeletons #ifndef NDEBUG // Debug mode int nRandomItr = 1; #else int nRandomItr = 100; #endif // Lower and upper bound of configuration for system double lb = -1.5 * DART_PI; double ub = 1.5 * DART_PI; simulation::World* myWorld = NULL; //----------------------------- Tests ---------------------------------------- // Check whether multiplication of mass matrix and its inverse is identity // matrix. myWorld = utils::SkelParser::readWorld(_fileName); EXPECT_TRUE(myWorld != NULL); for (int i = 0; i < myWorld->getNumSkeletons(); ++i) { dynamics::Skeleton* skel = myWorld->getSkeleton(i); int dof = skel->getNumGenCoords(); // int nBodyNodes = skel->getNumBodyNodes(); if (dof == 0 || !skel->isMobile()) { dtdbg << "Skeleton [" << skel->getName() << "] is skipped since it has " << "0 DOF or is immobile." << endl; continue; } for (int j = 0; j < nRandomItr; ++j) { // Set random configurations for (int k = 0; k < skel->getNumBodyNodes(); ++k) { BodyNode* body = skel->getBodyNode(k); Joint* joint = body->getParentJoint(); int localDof = joint->getNumGenCoords(); for (int l = 0; l < localDof; ++l) { double lbRP = joint->getGenCoord(l)->getPosMin(); double ubRP = joint->getGenCoord(l)->getPosMax(); if (lbRP < -DART_PI) lbRP = -DART_PI; if (ubRP > DART_PI) ubRP = DART_PI; joint->setConfig(l, random(lbRP, ubRP), true, false, false); } } skel->setConfigs(VectorXd::Zero(dof)); // TODO(JS): Just clear what should be skel->clearExternalForces(); skel->clearConstraintImpulses(); // Set random impulses VectorXd impulses = VectorXd::Zero(dof); for (size_t k = 0; k < impulses.size(); ++k) impulses[k] = random(lb, ub); skel->setConstraintImpulses(impulses); // Compute impulse-based forward dynamics skel->computeImpulseForwardDynamics(); // Compare resultant velocity change and invM * impulses VectorXd deltaVel1 = skel->getVelsChange(); MatrixXd invM = skel->getInvMassMatrix(); VectorXd deltaVel2 = invM * impulses; EXPECT_TRUE(equals(deltaVel1, deltaVel2, 1e-6)); if (!equals(deltaVel1, deltaVel2, 1e-6)) { cout << "deltaVel1: " << deltaVel1.transpose() << endl; cout << "deltaVel2: " << deltaVel2.transpose() << endl; } } } delete myWorld; }
//============================================================================== void DynamicsTest::centerOfMass(const std::string& _fileName) { using namespace std; using namespace Eigen; using namespace dart; using namespace math; using namespace dynamics; using namespace simulation; using namespace utils; //---------------------------- Settings -------------------------------------- // Number of random state tests for each skeletons #ifndef NDEBUG // Debug mode int nRandomItr = 10; #else int nRandomItr = 100; #endif // Lower and upper bound of configuration for system double lb = -1.5 * DART_PI; double ub = 1.5 * DART_PI; // Lower and upper bound of joint damping and stiffness double lbD = 0.0; double ubD = 10.0; double lbK = 0.0; double ubK = 10.0; simulation::World* myWorld = NULL; //----------------------------- Tests ---------------------------------------- // Check whether multiplication of mass matrix and its inverse is identity // matrix. myWorld = utils::SkelParser::readWorld(_fileName); EXPECT_TRUE(myWorld != NULL); for (int i = 0; i < myWorld->getNumSkeletons(); ++i) { dynamics::Skeleton* skel = myWorld->getSkeleton(i); int dof = skel->getNumGenCoords(); // int nBodyNodes = skel->getNumBodyNodes(); if (dof == 0) { dtmsg << "Skeleton [" << skel->getName() << "] is skipped since it has " << "0 DOF." << endl; continue; } for (int j = 0; j < nRandomItr; ++j) { // Random joint stiffness and damping coefficient for (int k = 0; k < skel->getNumBodyNodes(); ++k) { BodyNode* body = skel->getBodyNode(k); Joint* joint = body->getParentJoint(); int localDof = joint->getNumGenCoords(); for (int l = 0; l < localDof; ++l) { joint->setDampingCoefficient(l, random(lbD, ubD)); joint->setSpringStiffness (l, random(lbK, ubK)); double lbRP = joint->getGenCoord(l)->getPosMin(); double ubRP = joint->getGenCoord(l)->getPosMax(); if (lbRP < -DART_PI) lbRP = -DART_PI; if (ubRP > DART_PI) ubRP = DART_PI; joint->setRestPosition (l, random(lbRP, ubRP)); } } // Set random states VectorXd x = skel->getState(); for (int k = 0; k < x.size(); ++k) x[k] = random(lb, ub); skel->setState(x, true, true, false); VectorXd tau = skel->getGenForces(); for (int k = 0; k < tau.size(); ++k) tau[k] = random(lb, ub); skel->setGenForces(tau); skel->computeForwardDynamics(); VectorXd q = skel->getConfigs(); VectorXd dq = skel->getGenVels(); VectorXd ddq = skel->getGenAccs(); VectorXd com = skel->getWorldCOM(); VectorXd dcom = skel->getWorldCOMVelocity(); VectorXd ddcom = skel->getWorldCOMAcceleration(); MatrixXd comJ = skel->getWorldCOMJacobian(); MatrixXd comdJ = skel->getWorldCOMJacobianTimeDeriv(); VectorXd dcom2 = comJ * dq; VectorXd ddcom2 = comdJ * dq + comJ * ddq; EXPECT_TRUE(equals(dcom, dcom2, 1e-6)); if (!equals(dcom, dcom2, 1e-6)) { cout << "dcom :" << dcom.transpose() << endl; cout << "dcom2:" << dcom2.transpose() << endl; } EXPECT_TRUE(equals(ddcom, ddcom2, 1e-6)); if (!equals(ddcom, ddcom2, 1e-6)) { cout << "ddcom :" << ddcom.transpose() << endl; cout << "ddcom2:" << ddcom2.transpose() << endl; } } } delete myWorld; }
TEST(Skeleton, Restructuring) { std::vector<SkeletonPtr> skeletons = getSkeletons(); #ifndef NDEBUG size_t numIterations = 10; #else size_t numIterations = 2*skeletons.size(); #endif // Test moves within the current Skeleton for(size_t i=0; i<numIterations; ++i) { size_t index = floor(math::random(0, skeletons.size())); index = std::min(index, skeletons.size()-1); SkeletonPtr skeleton = skeletons[index]; SkeletonPtr original = skeleton->clone(); size_t maxNode = skeleton->getNumBodyNodes()-1; BodyNode* bn1 = skeleton->getBodyNode(floor(math::random(0, maxNode))); BodyNode* bn2 = skeleton->getBodyNode(ceil(math::random(0, maxNode))); if(bn1 == bn2) { --i; continue; } BodyNode* child = bn1->descendsFrom(bn2)? bn1 : bn2; BodyNode* parent = child == bn1? bn2 : bn1; child->moveTo(parent); EXPECT_TRUE(skeleton->getNumBodyNodes() == original->getNumBodyNodes()); if(skeleton->getNumBodyNodes() == original->getNumBodyNodes()) { for(size_t j=0; j<skeleton->getNumBodyNodes(); ++j) { // Make sure no BodyNodes have been lost or gained in translation std::string name = original->getBodyNode(j)->getName(); BodyNode* bn = skeleton->getBodyNode(name); EXPECT_FALSE(bn == nullptr); if(bn) EXPECT_TRUE(bn->getName() == name); name = skeleton->getBodyNode(j)->getName(); bn = original->getBodyNode(name); EXPECT_FALSE(bn == nullptr); if(bn) EXPECT_TRUE(bn->getName() == name); // Make sure no Joints have been lost or gained in translation name = original->getJoint(j)->getName(); Joint* joint = skeleton->getJoint(name); EXPECT_FALSE(joint == nullptr); if(joint) EXPECT_TRUE(joint->getName() == name); name = skeleton->getJoint(j)->getName(); joint = original->getJoint(name); EXPECT_FALSE(joint == nullptr); if(joint) EXPECT_TRUE(joint->getName() == name); } } EXPECT_TRUE(skeleton->getNumDofs() == original->getNumDofs()); for(size_t j=0; j<skeleton->getNumDofs(); ++j) { std::string name = original->getDof(j)->getName(); DegreeOfFreedom* dof = skeleton->getDof(name); EXPECT_FALSE(dof == nullptr); if(dof) EXPECT_TRUE(dof->getName() == name); name = skeleton->getDof(j)->getName(); dof = original->getDof(name); EXPECT_FALSE(dof == nullptr); if(dof) EXPECT_TRUE(dof->getName() == name); } } // Test moves between Skeletons for(size_t i=0; i<numIterations; ++i) { size_t fromIndex = floor(math::random(0, skeletons.size())); fromIndex = std::min(fromIndex, skeletons.size()-1); SkeletonPtr fromSkel = skeletons[fromIndex]; if(fromSkel->getNumBodyNodes() == 0) { --i; continue; } size_t toIndex = floor(math::random(0, skeletons.size())); toIndex = std::min(toIndex, skeletons.size()-1); SkeletonPtr toSkel = skeletons[toIndex]; if(toSkel->getNumBodyNodes() == 0) { --i; continue; } BodyNode* childBn = fromSkel->getBodyNode( floor(math::random(0, fromSkel->getNumBodyNodes()-1))); BodyNode* parentBn = toSkel->getBodyNode( floor(math::random(0, toSkel->getNumBodyNodes()-1))); if(fromSkel == toSkel) { if(childBn == parentBn) { --i; continue; } if(parentBn->descendsFrom(childBn)) { BodyNode* tempBn = childBn; childBn = parentBn; parentBn = tempBn; SkeletonPtr tempSkel = fromSkel; fromSkel = toSkel; toSkel = tempSkel; } } BodyNode* originalParent = childBn->getParentBodyNode(); std::vector<BodyNode*> subtree; constructSubtree(subtree, childBn); // Move to a new Skeleton childBn->moveTo(parentBn); // Make sure all the objects have moved for(size_t j=0; j<subtree.size(); ++j) { BodyNode* bn = subtree[j]; EXPECT_TRUE(bn->getSkeleton() == toSkel); } // Move to the Skeleton's root while producing a new Joint type sub_ptr<Joint> originalJoint = childBn->getParentJoint(); childBn->moveTo<FreeJoint>(nullptr); // The original parent joint should be deleted now EXPECT_TRUE(originalJoint == nullptr); // The BodyNode should now be a root node EXPECT_TRUE(childBn->getParentBodyNode() == nullptr); // The subtree should still be in the same Skeleton for(size_t j=0; j<subtree.size(); ++j) { BodyNode* bn = subtree[j]; EXPECT_TRUE(bn->getSkeleton() == toSkel); } // Create some new Skeletons and mangle them all up childBn->copyTo<RevoluteJoint>(fromSkel, originalParent); SkeletonPtr temporary = childBn->split("temporary"); SkeletonPtr other_temporary = childBn->split<PrismaticJoint>("other temporary"); SkeletonPtr another_temporary = childBn->copyAs("another temporary"); SkeletonPtr last_temporary = childBn->copyAs<ScrewJoint>("last temporary"); childBn->copyTo(another_temporary->getBodyNode( another_temporary->getNumBodyNodes()-1)); childBn->copyTo<PlanarJoint>(another_temporary->getBodyNode(0)); childBn->copyTo<TranslationalJoint>(temporary, nullptr); childBn->moveTo(last_temporary, last_temporary->getBodyNode(last_temporary->getNumBodyNodes()-1)); childBn->moveTo<BallJoint>(last_temporary, nullptr); childBn->moveTo<EulerJoint>(last_temporary, last_temporary->getBodyNode(0)); childBn->changeParentJointType<FreeJoint>(); // Test the non-recursive copying if(toSkel->getNumBodyNodes() > 1) { SkeletonPtr singleBodyNode = toSkel->getBodyNode(0)->copyAs("single", false); EXPECT_TRUE(singleBodyNode->getNumBodyNodes() == 1); std::pair<Joint*, BodyNode*> singlePair = toSkel->getBodyNode(0)->copyTo(nullptr, false); EXPECT_TRUE(singlePair.second->getNumChildBodyNodes() == 0); } // Check that the mangled Skeletons are all self-consistent check_self_consistency(fromSkel); check_self_consistency(toSkel); check_self_consistency(temporary); check_self_consistency(other_temporary); check_self_consistency(another_temporary); check_self_consistency(last_temporary); } }
// Current code only works for the left leg with only one constraint VectorXd MyWorld::updateGradients() { // compute c(q) mC = mSkel->getMarker(mConstrainedMarker)->getWorldPosition() - mTarget; // compute J(q) Vector4d offset; offset << mSkel->getMarker(mConstrainedMarker)->getLocalPosition(), 1; // Create a vector in homogeneous coordinates // w.r.t ankle dofs BodyNode *node = mSkel->getMarker(mConstrainedMarker)->getBodyNode(); Joint *joint = node->getParentJoint(); Matrix4d worldToParent = node->getParentBodyNode()->getTransform().matrix(); Matrix4d parentToJoint = joint->getTransformFromParentBodyNode().matrix(); Matrix4d dR = joint->getTransformDerivative(0); // Doesn't need .matrix() because it returns a Matrix4d instead of Isometry3d Matrix4d R = joint->getTransform(1).matrix(); Matrix4d jointToChild = joint->getTransformFromChildBodyNode().inverse().matrix(); Vector4d jCol = worldToParent * parentToJoint * dR * R * jointToChild * offset; int colIndex = joint->getIndexInSkeleton(0); mJ.col(colIndex) = jCol.head(3); // Take the first 3 elelemtns of jCol dR = joint->getTransformDerivative(1); R = joint->getTransform(0).matrix(); jCol = worldToParent * parentToJoint * R * dR * jointToChild * offset; colIndex = joint->getIndexInSkeleton(1); mJ.col(colIndex) = jCol.head(3); offset = parentToJoint * joint->getTransform(0).matrix() * joint->getTransform(1).matrix() * jointToChild * offset; // Update offset so it stores the chain below the parent joint // w.r.t knee dof node = node->getParentBodyNode(); // return NULL if node is the root node joint = node->getParentJoint(); worldToParent = node->getParentBodyNode()->getTransform().matrix(); parentToJoint = joint->getTransformFromParentBodyNode().matrix(); dR = joint->getTransformDerivative(0); // Doesn't need .matrix() because it returns a Matrix4d instead of Isometry3d jointToChild = joint->getTransformFromChildBodyNode().inverse().matrix(); jCol = worldToParent * parentToJoint * dR * jointToChild * offset; colIndex = joint->getIndexInSkeleton(0); mJ.col(colIndex) = jCol.head(3); // Take the first 3 elelemtns of jCol offset = parentToJoint * joint->getTransform(0).matrix() * jointToChild * offset; // w.r.t hip dofs node = node->getParentBodyNode(); joint = node->getParentJoint(); worldToParent = node->getParentBodyNode()->getTransform().matrix(); parentToJoint = joint->getTransformFromParentBodyNode().matrix(); dR = joint->getTransformDerivative(0); // Doesn't need .matrix() because it returns a Matrix4d instead of Isometry3d Matrix4d R1 = joint->getTransform(1).matrix(); Matrix4d R2 = joint->getTransform(2).matrix(); jointToChild = joint->getTransformFromChildBodyNode().inverse().matrix(); jCol = worldToParent * parentToJoint * dR * R1 * R2 * jointToChild * offset; colIndex = joint->getIndexInSkeleton(0); mJ.col(colIndex) = jCol.head(3); // Take the first 3 elelemtns of J R1 = joint->getTransform(0).matrix(); dR = joint->getTransformDerivative(1); R2 = joint->getTransform(2).matrix(); jCol = worldToParent * parentToJoint * R1 * dR * R2 * jointToChild * offset; colIndex = joint->getIndexInSkeleton(1); mJ.col(colIndex) = jCol.head(3); R1 = joint->getTransform(0).matrix(); R2 = joint->getTransform(1).matrix(); dR = joint->getTransformDerivative(2); jCol = worldToParent * parentToJoint * R1 * R2 * dR * jointToChild * offset; colIndex = joint->getIndexInSkeleton(2); mJ.col(colIndex) = jCol.head(3); // compute gradients VectorXd gradients = 2 * mJ.transpose() * mC; return gradients; }
// Current code only works for the left leg with only one constraint VectorXd MyWorld::updateGradients() { mJ.setZero(); mC.setZero(); // compute c(q) //std::cout << "HAMYDEBUG: mConstrainedMarker = " << getMarker(mConstrainedMarker) << std::endl; mC = getMarker(mConstrainedMarker)->getWorldPosition() - mTarget; std::cout << "C(q) = " << mC << std::endl; // compute J(q) Vector4d offset; offset << getMarker(mConstrainedMarker)->getLocalPosition(), 1; // Create a vector in homogeneous coordinates //Setup vars BodyNode *node = getMarker(mConstrainedMarker)->getBodyNode(); Joint *joint = node->getParentJoint(); Matrix4d worldToParent; Matrix4d parentToJoint; //Declare Vars Matrix4d dR; // Doesn't need .matrix() because it returns a Matrix4d instead of Isometry3d Matrix4d R; Matrix4d R1; Matrix4d R2; Matrix4d jointToChild; Vector4d jCol; int colIndex; //TODO: Might want to change this to check if root using given root fcn //Iterate until we get to the root node while(true) { //std::cout << "HAMY DEBUG: Beginning new looop" << std::endl; if(node->getParentBodyNode() == NULL) { worldToParent = worldToParent.setIdentity(); } else { worldToParent = node->getParentBodyNode()->getTransform().matrix(); } parentToJoint = joint->getTransformFromParentBodyNode().matrix(); // Doesn't need .matrix() because it returns a Matrix4d instead of Isometry3d jointToChild = joint->getTransformFromChildBodyNode().inverse().matrix(); //TODO: R1, R2, ... Rn code depending on DOFs int nDofs = joint->getNumDofs(); //std::cout << "HAMY: nDofs=" << nDofs << std::endl; //Can only have up to 3 DOFs on any one piece switch(nDofs){ case 1: //std::cout << "HAMY: 1 nDOF" << std::endl; dR = joint->getTransformDerivative(0); jCol = worldToParent * parentToJoint * dR * jointToChild * offset; colIndex = joint->getIndexInSkeleton(0); mJ.col(colIndex) = jCol.head(3); // Take the first 3 elelemtns of jCol offset = parentToJoint * joint->getTransform(0).matrix() * jointToChild * offset; break; case 2: //std::cout << "HAMY: 2 nDOF" << std::endl; dR = joint->getTransformDerivative(0); // Doesn't need .matrix() because it returns a Matrix4d instead of Isometry3d R = joint->getTransform(1).matrix(); jointToChild = joint->getTransformFromChildBodyNode().inverse().matrix(); jCol = worldToParent * parentToJoint * dR * R * jointToChild * offset; colIndex = joint->getIndexInSkeleton(0); mJ.col(colIndex) = jCol.head(3); // Take the first 3 elelemtns of jCol dR = joint->getTransformDerivative(1); R = joint->getTransform(0).matrix(); jCol = worldToParent * parentToJoint * R * dR * jointToChild * offset; colIndex = joint->getIndexInSkeleton(1); mJ.col(colIndex) = jCol.head(3); offset = parentToJoint * joint->getTransform(0).matrix() * joint->getTransform(1).matrix() * jointToChild * offset; // Upd break; case 3: //std::cout << "HAMY: 3 nDOF" << std::endl; dR = joint->getTransformDerivative(0); // Doesn't need .matrix() because it returns a Matrix4d instead of Isometry3d R1 = joint->getTransform(1).matrix(); R2 = joint->getTransform(2).matrix(); jointToChild = joint->getTransformFromChildBodyNode().inverse().matrix(); jCol = worldToParent * parentToJoint * dR * R1 * R2 * jointToChild * offset; colIndex = joint->getIndexInSkeleton(0); mJ.col(colIndex) = jCol.head(3); // Take the first 3 elelemtns of J R1 = joint->getTransform(0).matrix(); dR = joint->getTransformDerivative(1); R2 = joint->getTransform(2).matrix(); jCol = worldToParent * parentToJoint * R1 * dR * R2 * jointToChild * offset; colIndex = joint->getIndexInSkeleton(1); mJ.col(colIndex) = jCol.head(3); R1 = joint->getTransform(0).matrix(); R2 = joint->getTransform(1).matrix(); dR = joint->getTransformDerivative(2); jCol = worldToParent * parentToJoint * R1 * R2 * dR * jointToChild * offset; colIndex = joint->getIndexInSkeleton(2); mJ.col(colIndex) = jCol.head(3); offset = parentToJoint * joint->getTransform(0).matrix() * joint->getTransform(1).matrix() * joint->getTransform(2).matrix() * jointToChild * offset; break; default: //std::cout << "HAMY: Unexpected nDOF = " << nDofs << std::endl; break; } if(node != mSkel->getRootBodyNode()) { //std::cout << "HAMY DEBUG: Not root, continue loop" << std::endl; node = node->getParentBodyNode(); // return NULL if node is the root node joint = node->getParentJoint(); } else { break; } } // compute gradients VectorXd gradients = 2 * mJ.transpose() * mC; return gradients; }
//============================================================================== void ConstraintTest::SingleContactTest(const std::string& _fileName) { using namespace std; using namespace Eigen; using namespace dart::math; using namespace dart::collision; using namespace dart::constraint; using namespace dart::dynamics; using namespace dart::simulation; using namespace dart::utils; //---------------------------------------------------------------------------- // Settings //---------------------------------------------------------------------------- // Number of random state tests for each skeletons #ifndef NDEBUG // Debug mode int testCount = 1; #else int testCount = 1; #endif World* world = new World; EXPECT_TRUE(world != NULL); world->setGravity(Vector3d(0.0, -10.00, 0.0)); world->setTimeStep(0.001); world->getConstraintSolver()->setCollisionDetector( new DARTCollisionDetector()); Skeleton* sphereSkel = createSphere(0.05, Vector3d(0.0, 1.0, 0.0)); BodyNode* sphere = sphereSkel->getBodyNode(0); Joint* sphereJoint = sphere->getParentJoint(); sphereJoint->setVelocity(3, random(-2.0, 2.0)); // x-axis sphereJoint->setVelocity(5, random(-2.0, 2.0)); // z-axis world->addSkeleton(sphereSkel); EXPECT_EQ(sphereSkel->getGravity(), world->getGravity()); assert(sphere); Skeleton* boxSkel = createBox(Vector3d(1.0, 1.0, 1.0), Vector3d(0.0, 1.0, 0.0)); BodyNode* box = boxSkel->getBodyNode(0); Joint* boxJoint = box->getParentJoint(); boxJoint->setVelocity(3, random(-2.0, 2.0)); // x-axis boxJoint->setVelocity(5, random(-2.0, 2.0)); // z-axis // world->addSkeleton(boxSkel); // EXPECT_EQ(boxSkel->getGravity(), world->getGravity()); // assert(box); Skeleton* groundSkel = createGround(Vector3d(10000.0, 0.1, 10000.0), Vector3d(0.0, -0.05, 0.0)); groundSkel->setMobile(false); BodyNode* ground = groundSkel->getBodyNode(0); world->addSkeleton(groundSkel); EXPECT_EQ(groundSkel->getGravity(), world->getGravity()); assert(ground); EXPECT_EQ(world->getNumSkeletons(), 2); ConstraintSolver* cs = world->getConstraintSolver(); CollisionDetector* cd = cs->getCollisionDetector(); // Lower and upper bound of configuration for system double lb = -1.5 * DART_PI; double ub = 1.5 * DART_PI; int maxSteps = 500; for (int i = 0; i < maxSteps; ++i) { // Vector3d pos1 = sphere->getWorldTransform().translation(); // Vector3d vel1 = sphere->getWorldLinearVelocity(pos1); // std::cout << "pos1:" << pos1.transpose() << std::endl; // std::cout << "vel1:" << vel1.transpose() << std::endl; cd->detectCollision(true, true); if (cd->getNumContacts() == 0) { world->step(); continue; } for (int j = 0; j < cd->getNumContacts(); ++j) { Contact contact = cd->getContact(j); Vector3d pos1 = sphere->getTransform().inverse() * contact.point; Vector3d vel1 = sphere->getWorldLinearVelocity(pos1); // std::cout << "pos1:" << pos1.transpose() << std::endl; // std::cout << "vel1:" << vel1.transpose() << std::endl; } world->step(); for (int j = 0; j < cd->getNumContacts(); ++j) { Contact contact = cd->getContact(j); Vector3d pos1 = sphere->getTransform().inverse() * contact.point; Vector3d vel1 = sphere->getWorldLinearVelocity(pos1); // std::cout << "pos1:" << pos1.transpose() << std::endl; // std::cout << "pos1[1]: " << pos1[1] << std::endl; // std::cout << "pos1:" << pos1.transpose() << std::endl; std::cout << "vel1:" << vel1.transpose() << ", pos1[1]: " << pos1[1] << std::endl; // EXPECT_NEAR(pos1[0], 0.0, 1e-9); // EXPECT_NEAR(pos1[1], -0.05, 1e-2); // EXPECT_NEAR(pos1[2], 0.0, 1e-9); // EXPECT_NEAR(vel1[0], 0.0, 1e-9); // EXPECT_NEAR(vel1[1], 0.0, 1e-9); // EXPECT_NEAR(vel1[2], 0.0, 1e-9); // if (!equals(vel1, Vector3d(0.0, 0.0, 0.0))) // std::cout << "vel1:" << vel1.transpose() << std::endl; // EXPECT_EQ(vel1, Vector3d::Zero()); } // std::cout << std::endl; break; } delete world; }