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