Skip to content

Commit 6bc1e9b

Browse files
authored
Fix inverse dynamics with damping and stiffness (#1451)
1 parent b377b09 commit 6bc1e9b

File tree

5 files changed

+129
-7
lines changed

5 files changed

+129
-7
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* Dynamics
66

77
* Update the Properties version of a BodyNode when moved to a new Skeleton: [#1445](https://github.com/dartsim/dart/pull/1445)
8+
* Fixed incorrect implicit joint damping/spring force computation in inverse dynamics: : [#1451](https://github.com/dartsim/dart/pull/1451)
89

910
### [DART 6.9.2 (2019-08-16)](https://github.com/dartsim/dart/milestone/60?closed=1)
1011

dart/dynamics/Skeleton.hpp

+26-1
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,32 @@ class Skeleton :
668668
/// Compute forward dynamics
669669
void computeForwardDynamics();
670670

671-
/// Compute inverse dynamics
671+
/// Computes inverse dynamics.
672+
///
673+
/// The inverse dynamics is computed according to the following equations of
674+
/// motion:
675+
///
676+
/// \f$ M(q) \ddot{q} + C(q, \dot{q}) + N(q) - \tau_{\text{ext}} - \tau_d -
677+
/// \tau_s = \tau \f$
678+
///
679+
/// where \f$ \tau_{\text{ext}} \f$, \f$ \tau_d \f$, and \f$ \tau_s \f$ are
680+
/// external forces, joint damping forces, and joint spring forces projected
681+
/// on to the joint space, respectively. This function provides three flags
682+
/// whether to take into account each forces in computing the joint forces,
683+
/// \f$ \tau_d \f$. Not accounting each forces implies that the forces is
684+
/// added to \f$ \tau \f$ in order to keep the equation equivalent. If there
685+
/// forces are zero (by setting external forces, damping coeff, spring
686+
/// stiffness zeros), these flags have no effect.
687+
///
688+
/// Once this function is called, the joint forces, \f$ \tau \f$, can be
689+
/// obtained by calling getForces().
690+
///
691+
/// \param[in] _withExternalForces Set \c true to take external forces into
692+
/// account.
693+
/// \param[in] _withDampingForces Set \c true to take damping forces into
694+
/// account.
695+
/// \param[in] _withSpringForces Set \c true to take spring forces into
696+
/// account.
672697
void computeInverseDynamics(bool _withExternalForces = false,
673698
bool _withDampingForces = false,
674699
bool _withSpringForces = false);

dart/dynamics/detail/GenericJoint.hpp

+7-4
Original file line numberDiff line numberDiff line change
@@ -2367,23 +2367,26 @@ void GenericJoint<ConfigSpaceT>::updateForceID(
23672367
{
23682368
this->mAspectState.mForces = getRelativeJacobianStatic().transpose() * bodyForce;
23692369

2370-
// Damping force
2370+
// Implicit damping force:
2371+
// tau_d = -Kd * dq - Kd * h * ddq
23712372
if (withDampingForces)
23722373
{
23732374
const typename ConfigSpaceT::Vector dampingForces
23742375
= -Base::mAspectProperties.mDampingCoefficients.cwiseProduct(
2375-
getVelocitiesStatic());
2376+
getVelocitiesStatic() + getAccelerationsStatic() * timeStep);
23762377
this->mAspectState.mForces -= dampingForces;
23772378
}
23782379

2379-
// Spring force
2380+
// Implicit spring force:
2381+
// tau_s = -Kp * (q - q0) - Kp * h * dq - Kp * h^2 * ddq
23802382
if (withSpringForces)
23812383
{
23822384
const typename ConfigSpaceT::Vector springForces
23832385
= -Base::mAspectProperties.mSpringStiffnesses.cwiseProduct(
23842386
getPositionsStatic()
23852387
- Base::mAspectProperties.mRestPositions
2386-
+ getVelocitiesStatic() * timeStep);
2388+
+ getVelocitiesStatic() * timeStep
2389+
+ getAccelerationsStatic() * timeStep * timeStep);
23872390
this->mAspectState.mForces -= springForces;
23882391
}
23892392
}

doxygen/Doxyfile.in

+2-2
Original file line numberDiff line numberDiff line change
@@ -1472,7 +1472,7 @@ FORMULA_TRANSPARENT = YES
14721472
# The default value is: NO.
14731473
# This tag requires that the tag GENERATE_HTML is set to YES.
14741474

1475-
USE_MATHJAX = NO
1475+
USE_MATHJAX = YES
14761476

14771477
# When MathJax is enabled you can set the default output format to be used for
14781478
# the MathJax output. See the MathJax site (see:
@@ -1502,7 +1502,7 @@ MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
15021502
# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
15031503
# This tag requires that the tag USE_MATHJAX is set to YES.
15041504

1505-
MATHJAX_EXTENSIONS =
1505+
MATHJAX_EXTENSIONS = TeX/AMSmath
15061506

15071507
# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
15081508
# of code that will be used on startup of the MathJax code. See the MathJax site

unittests/comprehensive/test_Dynamics.cpp

+93
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ class DynamicsTest : public ::testing::Test
9191
// transformations, spatial velocities, and spatial accelerations correctly.
9292
void testForwardKinematics(const common::Uri& uri);
9393

94+
// Test inverse dynamics with various joint forces.
95+
void testInverseDynamics(const common::Uri& uri);
96+
9497
// Compare dynamics terms in equations of motion such as mass matrix, mass
9598
// inverse matrix, Coriolis force vector, gravity force vector, and external
9699
// force vector.
@@ -1385,6 +1388,84 @@ void DynamicsTest::testForwardKinematics(const common::Uri& uri)
13851388
}
13861389
}
13871390

1391+
//==============================================================================
1392+
void DynamicsTest::testInverseDynamics(const common::Uri& uri)
1393+
{
1394+
//---------------------------- Settings --------------------------------------
1395+
// Number of random state tests for each skeleton
1396+
#ifndef NDEBUG // Debug mode
1397+
const std::size_t nRandomItr = 2;
1398+
#else
1399+
const std::size_t nRandomItr = 100;
1400+
#endif
1401+
1402+
// Lower and upper bound of configuration for system
1403+
const double lb = -1.0 * math::constantsd::pi();
1404+
const double ub = 1.0 * math::constantsd::pi();
1405+
1406+
// Lower and upper bound of joint damping and stiffness
1407+
const double lbD = 0.0;
1408+
const double ubD = 10.0;
1409+
const double lbK = 0.0;
1410+
const double ubK = 10.0;
1411+
1412+
// Lower and upper bound of joint forces
1413+
const double lbF = -10.0;
1414+
const double ubF = 10.0;
1415+
1416+
simulation::WorldPtr world = utils::SkelParser::readWorld(uri);
1417+
ASSERT_TRUE(world != nullptr);
1418+
1419+
for (std::size_t i = 0; i < world->getNumSkeletons(); ++i)
1420+
{
1421+
dynamics::SkeletonPtr skel = world->getSkeleton(i);
1422+
const std::size_t dofs = skel->getNumDofs();
1423+
1424+
for (std::size_t j = 0; j < nRandomItr; ++j)
1425+
{
1426+
// Random joint stiffness and damping coefficients
1427+
for (std::size_t l = 0; l < dofs; ++l)
1428+
{
1429+
dynamics::DegreeOfFreedom* dof = skel->getDof(l);
1430+
dof->setDampingCoefficient(math::Random::uniform(lbD, ubD));
1431+
dof->setSpringStiffness(math::Random::uniform(lbK, ubK));
1432+
1433+
double lbRP = dof->getPositionLowerLimit();
1434+
double ubRP = dof->getPositionUpperLimit();
1435+
lbRP = std::max(lbRP, -math::constantsd::pi());
1436+
ubRP = std::min(ubRP, +math::constantsd::pi());
1437+
dof->setRestPosition(math::Random::uniform(lbRP, ubRP));
1438+
}
1439+
1440+
// Set random states and forces
1441+
const VectorXd q0 = math::Random::uniform<VectorXd>(dofs, lb, ub);
1442+
const VectorXd dq0 = math::Random::uniform<VectorXd>(dofs, lb, ub);
1443+
const VectorXd f0 = math::Random::uniform<VectorXd>(dofs, lbF, ubF);
1444+
1445+
// Forward dynamics to compute accelerations
1446+
skel->setPositions(q0);
1447+
skel->setVelocities(dq0);
1448+
skel->setForces(f0);
1449+
skel->computeForwardDynamics();
1450+
const VectorXd ddq = skel->getAccelerations();
1451+
1452+
// Test inverse dynamics to ensure the result joint forces are identical
1453+
// to the forces used to compute the input accelerations
1454+
skel->setAccelerations(ddq);
1455+
skel->computeInverseDynamics(false, true, true);
1456+
const VectorXd f = skel->getForces();
1457+
EXPECT_TRUE(equals(f, f0));
1458+
1459+
// Test forward dynamics to ensure the result joint accelerations are
1460+
// identical to the accelerations used to compute the input forces
1461+
skel->setForces(f);
1462+
skel->computeForwardDynamics();
1463+
const VectorXd ddq2 = skel->getAccelerations();
1464+
EXPECT_TRUE(equals(ddq, ddq2));
1465+
}
1466+
}
1467+
}
1468+
13881469
//==============================================================================
13891470
void DynamicsTest::compareEquationsOfMotion(const common::Uri& uri)
13901471
{
@@ -2163,6 +2244,18 @@ TEST_F(DynamicsTest, testForwardKinematics)
21632244
}
21642245
}
21652246

2247+
//==============================================================================
2248+
TEST_F(DynamicsTest, testInverseDynamics)
2249+
{
2250+
for (std::size_t i = 0; i < getList().size(); ++i)
2251+
{
2252+
#ifndef NDEBUG
2253+
dtdbg << getList()[i].toString() << std::endl;
2254+
#endif
2255+
testInverseDynamics(getList()[i]);
2256+
}
2257+
}
2258+
21662259
//==============================================================================
21672260
TEST_F(DynamicsTest, compareEquationsOfMotion)
21682261
{

0 commit comments

Comments
 (0)