1 /*
2  * Copyright (c) 2011-2021, The DART development contributors
3  * All rights reserved.
4  *
5  * The list of contributors can be found at:
6  *   https://github.com/dartsim/dart/blob/master/LICENSE
7  *
8  * This file is provided under the following "BSD-style" License:
9  *   Redistribution and use in source and binary forms, with or
10  *   without modification, are permitted provided that the following
11  *   conditions are met:
12  *   * Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  *   * Redistributions in binary form must reproduce the above
15  *     copyright notice, this list of conditions and the following
16  *     disclaimer in the documentation and/or other materials provided
17  *     with the distribution.
18  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19  *   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  *   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26  *   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  *   POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include "dart/dynamics/Joint.hpp"
34 
35 #include <string>
36 
37 #include "dart/common/Console.hpp"
38 #include "dart/dynamics/BodyNode.hpp"
39 #include "dart/dynamics/DegreeOfFreedom.hpp"
40 #include "dart/dynamics/Skeleton.hpp"
41 #include "dart/math/Helpers.hpp"
42 
43 namespace dart {
44 namespace dynamics {
45 
46 //==============================================================================
47 const Joint::ActuatorType Joint::DefaultActuatorType
48     = detail::DefaultActuatorType;
49 // These declarations are needed for linking to work
50 constexpr Joint::ActuatorType Joint::FORCE;
51 constexpr Joint::ActuatorType Joint::PASSIVE;
52 constexpr Joint::ActuatorType Joint::SERVO;
53 constexpr Joint::ActuatorType Joint::MIMIC;
54 constexpr Joint::ActuatorType Joint::ACCELERATION;
55 constexpr Joint::ActuatorType Joint::VELOCITY;
56 constexpr Joint::ActuatorType Joint::LOCKED;
57 
58 namespace detail {
59 
60 //==============================================================================
JointProperties(const std::string & _name,const Eigen::Isometry3d & _T_ParentBodyToJoint,const Eigen::Isometry3d & _T_ChildBodyToJoint,bool _isPositionLimitEnforced,ActuatorType _actuatorType,const Joint * _mimicJoint,double _mimicMultiplier,double _mimicOffset)61 JointProperties::JointProperties(
62     const std::string& _name,
63     const Eigen::Isometry3d& _T_ParentBodyToJoint,
64     const Eigen::Isometry3d& _T_ChildBodyToJoint,
65     bool _isPositionLimitEnforced,
66     ActuatorType _actuatorType,
67     const Joint* _mimicJoint,
68     double _mimicMultiplier,
69     double _mimicOffset)
70   : mName(_name),
71     mT_ParentBodyToJoint(_T_ParentBodyToJoint),
72     mT_ChildBodyToJoint(_T_ChildBodyToJoint),
73     mIsPositionLimitEnforced(_isPositionLimitEnforced),
74     mActuatorType(_actuatorType),
75     mMimicJoint(_mimicJoint),
76     mMimicMultiplier(_mimicMultiplier),
77     mMimicOffset(_mimicOffset)
78 {
79   // Do nothing
80 }
81 
82 } // namespace detail
83 
84 //==============================================================================
ExtendedProperties(const Properties & standardProperties,const CompositeProperties & aspectProperties)85 Joint::ExtendedProperties::ExtendedProperties(
86     const Properties& standardProperties,
87     const CompositeProperties& aspectProperties)
88   : Properties(standardProperties), mCompositeProperties(aspectProperties)
89 {
90   // Do nothing
91 }
92 
93 //==============================================================================
ExtendedProperties(Properties && standardProperties,CompositeProperties && aspectProperties)94 Joint::ExtendedProperties::ExtendedProperties(
95     Properties&& standardProperties, CompositeProperties&& aspectProperties)
96   : Properties(std::move(standardProperties)),
97     mCompositeProperties(std::move(aspectProperties))
98 {
99   // Do nothing
100 }
101 
102 //==============================================================================
~Joint()103 Joint::~Joint()
104 {
105   // Do nothing
106 }
107 
108 //==============================================================================
setProperties(const Properties & properties)109 void Joint::setProperties(const Properties& properties)
110 {
111   setAspectProperties(properties);
112 }
113 
114 //==============================================================================
setAspectProperties(const AspectProperties & properties)115 void Joint::setAspectProperties(const AspectProperties& properties)
116 {
117   setName(properties.mName);
118   setTransformFromParentBodyNode(properties.mT_ParentBodyToJoint);
119   setTransformFromChildBodyNode(properties.mT_ChildBodyToJoint);
120   setLimitEnforcement(properties.mIsPositionLimitEnforced);
121   setActuatorType(properties.mActuatorType);
122   setMimicJoint(
123       properties.mMimicJoint,
124       properties.mMimicMultiplier,
125       properties.mMimicOffset);
126 }
127 
128 //==============================================================================
getJointProperties() const129 const Joint::Properties& Joint::getJointProperties() const
130 {
131   return mAspectProperties;
132 }
133 
134 //==============================================================================
copy(const Joint & _otherJoint)135 void Joint::copy(const Joint& _otherJoint)
136 {
137   if (this == &_otherJoint)
138     return;
139 
140   setProperties(_otherJoint.getJointProperties());
141 }
142 
143 //==============================================================================
copy(const Joint * _otherJoint)144 void Joint::copy(const Joint* _otherJoint)
145 {
146   if (nullptr == _otherJoint)
147     return;
148 
149   copy(*_otherJoint);
150 }
151 
152 //==============================================================================
operator =(const Joint & _otherJoint)153 Joint& Joint::operator=(const Joint& _otherJoint)
154 {
155   copy(_otherJoint);
156   return *this;
157 }
158 
159 //==============================================================================
setName(const std::string & _name,bool _renameDofs)160 const std::string& Joint::setName(const std::string& _name, bool _renameDofs)
161 {
162   if (mAspectProperties.mName == _name)
163   {
164     if (_renameDofs)
165       updateDegreeOfFreedomNames();
166     return mAspectProperties.mName;
167   }
168 
169   const SkeletonPtr& skel
170       = mChildBodyNode ? mChildBodyNode->getSkeleton() : nullptr;
171   if (skel)
172   {
173     skel->mNameMgrForJoints.removeName(mAspectProperties.mName);
174     mAspectProperties.mName = _name;
175 
176     skel->addEntryToJointNameMgr(this, _renameDofs);
177   }
178   else
179   {
180     mAspectProperties.mName = _name;
181 
182     if (_renameDofs)
183       updateDegreeOfFreedomNames();
184   }
185 
186   return mAspectProperties.mName;
187 }
188 
189 //==============================================================================
getName() const190 const std::string& Joint::getName() const
191 {
192   return mAspectProperties.mName;
193 }
194 
195 //==============================================================================
setActuatorType(Joint::ActuatorType _actuatorType)196 void Joint::setActuatorType(Joint::ActuatorType _actuatorType)
197 {
198   mAspectProperties.mActuatorType = _actuatorType;
199 }
200 
201 //==============================================================================
getActuatorType() const202 Joint::ActuatorType Joint::getActuatorType() const
203 {
204   return mAspectProperties.mActuatorType;
205 }
206 
207 //==============================================================================
setMimicJoint(const Joint * _mimicJoint,double _mimicMultiplier,double _mimicOffset)208 void Joint::setMimicJoint(
209     const Joint* _mimicJoint, double _mimicMultiplier, double _mimicOffset)
210 {
211   mAspectProperties.mMimicJoint = _mimicJoint;
212   mAspectProperties.mMimicMultiplier = _mimicMultiplier;
213   mAspectProperties.mMimicOffset = _mimicOffset;
214 }
215 
216 //==============================================================================
getMimicJoint() const217 const Joint* Joint::getMimicJoint() const
218 {
219   return mAspectProperties.mMimicJoint;
220 }
221 
222 //==============================================================================
getMimicMultiplier() const223 double Joint::getMimicMultiplier() const
224 {
225   return mAspectProperties.mMimicMultiplier;
226 }
227 
228 //==============================================================================
getMimicOffset() const229 double Joint::getMimicOffset() const
230 {
231   return mAspectProperties.mMimicOffset;
232 }
233 
234 //==============================================================================
isKinematic() const235 bool Joint::isKinematic() const
236 {
237   switch (mAspectProperties.mActuatorType)
238   {
239     case FORCE:
240     case PASSIVE:
241     case SERVO:
242     case MIMIC:
243       return false;
244     case ACCELERATION:
245     case VELOCITY:
246     case LOCKED:
247       return true;
248     default:
249     {
250       dterr << "Unsupported actuator type." << std::endl;
251       return false;
252     }
253   }
254 }
255 
256 //==============================================================================
isDynamic() const257 bool Joint::isDynamic() const
258 {
259   return !isKinematic();
260 }
261 
262 //==============================================================================
getChildBodyNode()263 BodyNode* Joint::getChildBodyNode()
264 {
265   return mChildBodyNode;
266 }
267 
268 //==============================================================================
getChildBodyNode() const269 const BodyNode* Joint::getChildBodyNode() const
270 {
271   return mChildBodyNode;
272 }
273 
274 //==============================================================================
getParentBodyNode()275 BodyNode* Joint::getParentBodyNode()
276 {
277   if (mChildBodyNode)
278     return mChildBodyNode->getParentBodyNode();
279 
280   return nullptr;
281 }
282 
283 //==============================================================================
getParentBodyNode() const284 const BodyNode* Joint::getParentBodyNode() const
285 {
286   return const_cast<Joint*>(this)->getParentBodyNode();
287 }
288 
289 //==============================================================================
getSkeleton()290 SkeletonPtr Joint::getSkeleton()
291 {
292   return mChildBodyNode ? mChildBodyNode->getSkeleton() : nullptr;
293 }
294 
295 //==============================================================================
getSkeleton() const296 std::shared_ptr<const Skeleton> Joint::getSkeleton() const
297 {
298   return mChildBodyNode ? mChildBodyNode->getSkeleton() : nullptr;
299 }
300 
301 //==============================================================================
getLocalTransform() const302 const Eigen::Isometry3d& Joint::getLocalTransform() const
303 {
304   return getRelativeTransform();
305 }
306 
307 //==============================================================================
getLocalSpatialVelocity() const308 const Eigen::Vector6d& Joint::getLocalSpatialVelocity() const
309 {
310   return getRelativeSpatialVelocity();
311 }
312 
313 //==============================================================================
getLocalSpatialAcceleration() const314 const Eigen::Vector6d& Joint::getLocalSpatialAcceleration() const
315 {
316   return getRelativeSpatialAcceleration();
317 }
318 
319 //==============================================================================
getLocalPrimaryAcceleration() const320 const Eigen::Vector6d& Joint::getLocalPrimaryAcceleration() const
321 {
322   return getRelativePrimaryAcceleration();
323 }
324 
325 //==============================================================================
getLocalJacobian() const326 const math::Jacobian Joint::getLocalJacobian() const
327 {
328   return getRelativeJacobian();
329 }
330 
331 //==============================================================================
getLocalJacobian(const Eigen::VectorXd & positions) const332 math::Jacobian Joint::getLocalJacobian(const Eigen::VectorXd& positions) const
333 {
334   return getRelativeJacobian(positions);
335 }
336 
337 //==============================================================================
getLocalJacobianTimeDeriv() const338 const math::Jacobian Joint::getLocalJacobianTimeDeriv() const
339 {
340   return getRelativeJacobianTimeDeriv();
341 }
342 
343 //==============================================================================
getRelativeTransform() const344 const Eigen::Isometry3d& Joint::getRelativeTransform() const
345 {
346   if (mNeedTransformUpdate)
347   {
348     updateRelativeTransform();
349     mNeedTransformUpdate = false;
350   }
351 
352   return mT;
353 }
354 
355 //==============================================================================
getRelativeSpatialVelocity() const356 const Eigen::Vector6d& Joint::getRelativeSpatialVelocity() const
357 {
358   if (mNeedSpatialVelocityUpdate)
359   {
360     updateRelativeSpatialVelocity();
361     mNeedSpatialVelocityUpdate = false;
362   }
363 
364   return mSpatialVelocity;
365 }
366 
367 //==============================================================================
getRelativeSpatialAcceleration() const368 const Eigen::Vector6d& Joint::getRelativeSpatialAcceleration() const
369 {
370   if (mNeedSpatialAccelerationUpdate)
371   {
372     updateRelativeSpatialAcceleration();
373     mNeedSpatialAccelerationUpdate = false;
374   }
375 
376   return mSpatialAcceleration;
377 }
378 
379 //==============================================================================
getRelativePrimaryAcceleration() const380 const Eigen::Vector6d& Joint::getRelativePrimaryAcceleration() const
381 {
382   if (mNeedPrimaryAccelerationUpdate)
383   {
384     updateRelativePrimaryAcceleration();
385     mNeedPrimaryAccelerationUpdate = false;
386   }
387 
388   return mPrimaryAcceleration;
389 }
390 
391 //==============================================================================
setPositionLimitEnforced(bool enforced)392 void Joint::setPositionLimitEnforced(bool enforced)
393 {
394   setLimitEnforcement(enforced);
395 }
396 
397 //==============================================================================
setLimitEnforcement(bool enforced)398 void Joint::setLimitEnforcement(bool enforced)
399 {
400   mAspectProperties.mIsPositionLimitEnforced = enforced;
401 }
402 
403 //==============================================================================
isPositionLimitEnforced() const404 bool Joint::isPositionLimitEnforced() const
405 {
406   return areLimitsEnforced();
407 }
408 
409 //==============================================================================
areLimitsEnforced() const410 bool Joint::areLimitsEnforced() const
411 {
412   return mAspectProperties.mIsPositionLimitEnforced;
413 }
414 
415 //==============================================================================
getJointIndexInSkeleton() const416 std::size_t Joint::getJointIndexInSkeleton() const
417 {
418   return mChildBodyNode->getIndexInSkeleton();
419 }
420 
421 //==============================================================================
getJointIndexInTree() const422 std::size_t Joint::getJointIndexInTree() const
423 {
424   return mChildBodyNode->getIndexInTree();
425 }
426 
427 //==============================================================================
getTreeIndex() const428 std::size_t Joint::getTreeIndex() const
429 {
430   return mChildBodyNode->getTreeIndex();
431 }
432 
433 //==============================================================================
checkSanity(bool _printWarnings) const434 bool Joint::checkSanity(bool _printWarnings) const
435 {
436   bool sane = true;
437   for (std::size_t i = 0; i < getNumDofs(); ++i)
438   {
439     if (getInitialPosition(i) < getPositionLowerLimit(i)
440         || getPositionUpperLimit(i) < getInitialPosition(i))
441     {
442       if (_printWarnings)
443       {
444         dtwarn << "[Joint::checkSanity] Initial position of index " << i << " ["
445                << getDofName(i) << "] in Joint [" << getName() << "] is "
446                << "outside of its position limits\n"
447                << " -- Initial Position: " << getInitialPosition(i) << "\n"
448                << " -- Limits: [" << getPositionLowerLimit(i) << ", "
449                << getPositionUpperLimit(i) << "]\n";
450       }
451       else
452       {
453         return false;
454       }
455 
456       sane = false;
457     }
458 
459     if (getInitialVelocity(i) < getVelocityLowerLimit(i)
460         || getVelocityUpperLimit(i) < getInitialVelocity(i))
461     {
462       if (_printWarnings)
463       {
464         dtwarn << "[Joint::checkSanity] Initial velocity of index " << i << " ["
465                << getDofName(i) << "] is Joint [" << getName() << "] is "
466                << "outside of its velocity limits\n"
467                << " -- Initial Velocity: " << getInitialVelocity(i) << "\n"
468                << " -- Limits: [" << getVelocityLowerLimit(i) << ", "
469                << getVelocityUpperLimit(i) << "]\n";
470       }
471       else
472       {
473         return false;
474       }
475 
476       sane = false;
477     }
478   }
479 
480   return sane;
481 }
482 
483 //==============================================================================
getPotentialEnergy() const484 double Joint::getPotentialEnergy() const
485 {
486   return computePotentialEnergy();
487 }
488 
489 //==============================================================================
setTransformFromParentBodyNode(const Eigen::Isometry3d & _T)490 void Joint::setTransformFromParentBodyNode(const Eigen::Isometry3d& _T)
491 {
492   assert(math::verifyTransform(_T));
493   mAspectProperties.mT_ParentBodyToJoint = _T;
494   notifyPositionUpdated();
495 }
496 
497 //==============================================================================
setTransformFromChildBodyNode(const Eigen::Isometry3d & _T)498 void Joint::setTransformFromChildBodyNode(const Eigen::Isometry3d& _T)
499 {
500   assert(math::verifyTransform(_T));
501   mAspectProperties.mT_ChildBodyToJoint = _T;
502   updateRelativeJacobian();
503   notifyPositionUpdated();
504 }
505 
506 //==============================================================================
getTransformFromParentBodyNode() const507 const Eigen::Isometry3d& Joint::getTransformFromParentBodyNode() const
508 {
509   return mAspectProperties.mT_ParentBodyToJoint;
510 }
511 
512 //==============================================================================
getTransformFromChildBodyNode() const513 const Eigen::Isometry3d& Joint::getTransformFromChildBodyNode() const
514 {
515   return mAspectProperties.mT_ChildBodyToJoint;
516 }
517 
518 //==============================================================================
Joint()519 Joint::Joint()
520   : mChildBodyNode(nullptr),
521     mT(Eigen::Isometry3d::Identity()),
522     mSpatialVelocity(Eigen::Vector6d::Zero()),
523     mSpatialAcceleration(Eigen::Vector6d::Zero()),
524     mPrimaryAcceleration(Eigen::Vector6d::Zero()),
525     mNeedTransformUpdate(true),
526     mNeedSpatialVelocityUpdate(true),
527     mNeedSpatialAccelerationUpdate(true),
528     mNeedPrimaryAccelerationUpdate(true),
529     mIsRelativeJacobianDirty(true),
530     mIsRelativeJacobianTimeDerivDirty(true)
531 {
532   // Do nothing. The Joint::Aspect must be created by a derived class.
533 }
534 
535 //==============================================================================
createDofPointer(std::size_t _indexInJoint)536 DegreeOfFreedom* Joint::createDofPointer(std::size_t _indexInJoint)
537 {
538   return new DegreeOfFreedom(this, _indexInJoint);
539 }
540 
541 //==============================================================================
updateLocalTransform() const542 void Joint::updateLocalTransform() const
543 {
544   updateRelativeTransform();
545 }
546 
547 //==============================================================================
updateLocalSpatialVelocity() const548 void Joint::updateLocalSpatialVelocity() const
549 {
550   updateRelativeSpatialVelocity();
551 }
552 
553 //==============================================================================
updateLocalSpatialAcceleration() const554 void Joint::updateLocalSpatialAcceleration() const
555 {
556   updateRelativeSpatialAcceleration();
557 }
558 
559 //==============================================================================
updateLocalPrimaryAcceleration() const560 void Joint::updateLocalPrimaryAcceleration() const
561 {
562   updateRelativePrimaryAcceleration();
563 }
564 
565 //==============================================================================
updateLocalJacobian(bool mandatory) const566 void Joint::updateLocalJacobian(bool mandatory) const
567 {
568   updateRelativeJacobian(mandatory);
569 }
570 
571 //==============================================================================
updateLocalJacobianTimeDeriv() const572 void Joint::updateLocalJacobianTimeDeriv() const
573 {
574   updateRelativeJacobianTimeDeriv();
575 }
576 
577 //==============================================================================
updateArticulatedInertia() const578 void Joint::updateArticulatedInertia() const
579 {
580   mChildBodyNode->getArticulatedInertia();
581 }
582 
583 //==============================================================================
584 // Eigen::VectorXd Joint::getDampingForces() const
585 //{
586 //  int numDofs = getNumDofs();
587 //  Eigen::VectorXd dampingForce(numDofs);
588 
589 //  for (int i = 0; i < numDofs; ++i)
590 //    dampingForce(i) = -mDampingCoefficient[i] * getGenCoord(i)->getVel();
591 
592 //  return dampingForce;
593 //}
594 
595 //==============================================================================
596 // Eigen::VectorXd Joint::getSpringForces(double _timeStep) const
597 //{
598 //  int dof = getNumDofs();
599 //  Eigen::VectorXd springForce(dof);
600 //  for (int i = 0; i < dof; ++i)
601 //  {
602 //    springForce(i) =
603 //        -mSpringStiffness[i] * (getGenCoord(i)->getPos()
604 //                                + getGenCoord(i)->getVel() * _timeStep
605 //                                - mRestPosition[i]);
606 //  }
607 //  assert(!math::isNan(springForce));
608 //  return springForce;
609 //}
610 
611 //==============================================================================
notifyPositionUpdate()612 void Joint::notifyPositionUpdate()
613 {
614   notifyPositionUpdated();
615 }
616 
617 //==============================================================================
notifyPositionUpdated()618 void Joint::notifyPositionUpdated()
619 {
620   if (mChildBodyNode)
621   {
622     mChildBodyNode->dirtyTransform();
623     mChildBodyNode->dirtyJacobian();
624     mChildBodyNode->dirtyJacobianDeriv();
625   }
626 
627   mIsRelativeJacobianDirty = true;
628   mIsRelativeJacobianTimeDerivDirty = true;
629   mNeedPrimaryAccelerationUpdate = true;
630 
631   mNeedTransformUpdate = true;
632   mNeedSpatialVelocityUpdate = true;
633   mNeedSpatialAccelerationUpdate = true;
634 
635   SkeletonPtr skel = getSkeleton();
636   if (skel)
637   {
638     std::size_t tree = mChildBodyNode->mTreeIndex;
639     skel->dirtyArticulatedInertia(tree);
640     skel->mTreeCache[tree].mDirty.mExternalForces = true;
641     skel->mSkelCache.mDirty.mExternalForces = true;
642   }
643 }
644 
645 //==============================================================================
notifyVelocityUpdate()646 void Joint::notifyVelocityUpdate()
647 {
648   notifyVelocityUpdated();
649 }
650 
651 //==============================================================================
notifyVelocityUpdated()652 void Joint::notifyVelocityUpdated()
653 {
654   if (mChildBodyNode)
655   {
656     mChildBodyNode->dirtyVelocity();
657     mChildBodyNode->dirtyJacobianDeriv();
658   }
659 
660   mIsRelativeJacobianTimeDerivDirty = true;
661 
662   mNeedSpatialVelocityUpdate = true;
663   mNeedSpatialAccelerationUpdate = true;
664 }
665 
666 //==============================================================================
notifyAccelerationUpdate()667 void Joint::notifyAccelerationUpdate()
668 {
669   notifyAccelerationUpdated();
670 }
671 
672 //==============================================================================
notifyAccelerationUpdated()673 void Joint::notifyAccelerationUpdated()
674 {
675   if (mChildBodyNode)
676     mChildBodyNode->dirtyAcceleration();
677 
678   mNeedSpatialAccelerationUpdate = true;
679   mNeedPrimaryAccelerationUpdate = true;
680 }
681 
682 } // namespace dynamics
683 } // namespace dart
684