Skip to content

Commit ec86149

Browse files
authored
Parse SDF mimic joints and retarget mimic pendulum example (#2254)
1 parent c3c4da1 commit ec86149

File tree

4 files changed

+381
-422
lines changed

4 files changed

+381
-422
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
- Removed all APIs deprecated in DART 6.13 (the legacy `dart::common::Timer` utility, `ConstraintSolver::getConstraints()`/`containSkeleton()`, `ContactConstraint`'s raw constructor and material helper statistics, and the `MetaSkeleton` vector-returning `getBodyNodes()`/`getJoints()` accessors).
5151
- Removed the remaining 6.13 compatibility shims: deleted `dart/utils/urdf/URDFTypes.hpp`, the Eigen alias typedefs in `math/MathTypes.hpp`, the `dart7::comps::NameComponent` alias, and the legacy `dInfinity`/`dPAD` helpers, and tightened `SkelParser` plane parsing to treat `<point>` as an error.
5252
- Updated `dart::utils::SdfParser` to canonicalize input through libsdformat so it can parse SDF 1.7+ models without the legacy version gate: [#264](https://github.com/dartsim/dart/issues/264)
53+
- `dart::utils::SdfParser` now imports SDF mimic metadata (reference joint/DoF, multiplier/offset, and constraint type), and the mimic pendulum example/tests rely on those parsed joints when reproducing gz-physics #432 instead of bespoke SDF readers.
5354
- Fixed Collada mesh imports ignoring `<unit>` metadata by preserving the Assimp-provided scale transform ([#287](https://github.com/dartsim/dart/issues/287)).
5455

5556
- dartpy

dart/utils/sdf/SdfParser.cpp

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "dart/dynamics/CylinderShape.hpp"
4545
#include "dart/dynamics/FreeJoint.hpp"
4646
#include "dart/dynamics/MeshShape.hpp"
47+
#include "dart/dynamics/MimicDofProperties.hpp"
4748
#include "dart/dynamics/PrismaticJoint.hpp"
4849
#include "dart/dynamics/RevoluteJoint.hpp"
4950
#include "dart/dynamics/ScrewJoint.hpp"
@@ -193,8 +194,21 @@ struct SDFJoint
193194
std::string parentName;
194195
std::string childName;
195196
std::string type;
197+
struct MimicInfo
198+
{
199+
std::string referenceJointName;
200+
std::size_t referenceDof = 0;
201+
double multiplier = 1.0;
202+
double offset = 0.0;
203+
dynamics::MimicConstraintType constraintType
204+
= dynamics::MimicConstraintType::Motor;
205+
};
206+
std::vector<MimicInfo> mimicInfos;
196207
};
197208

209+
std::vector<SDFJoint::MimicInfo> readMimicElements(
210+
const ElementPtr& axisElement);
211+
198212
// Maps the name of a BodyNode to its properties
199213
using BodyMap = common::aligned_map<std::string, SDFBodyNode>;
200214

@@ -213,6 +227,9 @@ dynamics::SkeletonPtr readSkeleton(
213227
const common::Uri& baseUri,
214228
const ResolvedOptions& options);
215229

230+
void applyMimicConstraints(
231+
const dynamics::SkeletonPtr& skeleton, const JointMap& sdfJoints);
232+
216233
bool createPair(
217234
dynamics::SkeletonPtr skeleton,
218235
dynamics::BodyNode* parent,
@@ -807,6 +824,8 @@ dynamics::SkeletonPtr readSkeleton(
807824
// Set positions to their initial values
808825
newSkeleton->resetPositions();
809826

827+
applyMimicConstraints(newSkeleton, sdfJoints);
828+
810829
return newSkeleton;
811830
}
812831

@@ -878,6 +897,62 @@ NextResult getNextJointAndNodePair(
878897
return VALID;
879898
}
880899

900+
//==============================================================================
901+
void applyMimicConstraints(
902+
const dynamics::SkeletonPtr& skeleton, const JointMap& sdfJoints)
903+
{
904+
for (const auto& entry : sdfJoints) {
905+
const auto& jointInfo = entry.second;
906+
if (jointInfo.mimicInfos.empty())
907+
continue;
908+
909+
auto* joint = skeleton->getJoint(jointInfo.properties->mName);
910+
if (!joint)
911+
continue;
912+
913+
std::vector<dynamics::MimicDofProperties> props
914+
= joint->getMimicDofProperties();
915+
props.resize(joint->getNumDofs());
916+
917+
bool applied = false;
918+
bool useCoupler = false;
919+
for (const auto& mimic : jointInfo.mimicInfos) {
920+
auto* ref = skeleton->getJoint(mimic.referenceJointName);
921+
if (!ref) {
922+
DART_WARN(
923+
"[SdfParser] Ignoring mimic joint [{}] referencing missing joint "
924+
"[{}]",
925+
jointInfo.properties->mName,
926+
mimic.referenceJointName);
927+
continue;
928+
}
929+
930+
const std::size_t followerIndex
931+
= std::min(mimic.referenceDof, joint->getNumDofs() - 1);
932+
const std::size_t referenceIndex
933+
= std::min(mimic.referenceDof, ref->getNumDofs() - 1);
934+
935+
auto& prop = props[followerIndex];
936+
prop.mReferenceJoint = ref;
937+
prop.mReferenceDofIndex = referenceIndex;
938+
prop.mMultiplier = mimic.multiplier;
939+
prop.mOffset = mimic.offset;
940+
prop.mConstraintType = mimic.constraintType;
941+
applied = true;
942+
useCoupler
943+
= useCoupler
944+
|| mimic.constraintType == dynamics::MimicConstraintType::Coupler;
945+
}
946+
947+
if (!applied)
948+
continue;
949+
950+
joint->setMimicJointDofs(props);
951+
joint->setActuatorType(dynamics::Joint::MIMIC);
952+
joint->setUseCouplerConstraint(useCoupler);
953+
}
954+
}
955+
881956
dynamics::SkeletonPtr makeSkeleton(
882957
const ElementPtr& _skeletonElement, Eigen::Isometry3d& skeletonFrame)
883958
{
@@ -1343,6 +1418,34 @@ JointMap readAllJoints(
13431418
return sdfJoints;
13441419
}
13451420

1421+
std::vector<SDFJoint::MimicInfo> readMimicElements(
1422+
const ElementPtr& axisElement)
1423+
{
1424+
std::vector<SDFJoint::MimicInfo> mimics;
1425+
if (!axisElement || !hasElement(axisElement, "mimic"))
1426+
return mimics;
1427+
1428+
const auto mimicElement = getElement(axisElement, "mimic");
1429+
if (!mimicElement)
1430+
return mimics;
1431+
1432+
SDFJoint::MimicInfo info;
1433+
info.referenceJointName = getAttributeString(mimicElement, "joint");
1434+
if (hasAttribute(mimicElement, "axis")) {
1435+
const auto axisAttr = getAttributeString(mimicElement, "axis");
1436+
info.referenceDof = axisAttr == "axis2" ? 1u : 0u;
1437+
}
1438+
info.multiplier = hasElement(mimicElement, "multiplier")
1439+
? getValueDouble(mimicElement, "multiplier")
1440+
: 1.0;
1441+
info.offset = hasElement(mimicElement, "offset")
1442+
? getValueDouble(mimicElement, "offset")
1443+
: 0.0;
1444+
mimics.push_back(info);
1445+
1446+
return mimics;
1447+
}
1448+
13461449
SDFJoint readJoint(
13471450
const ElementPtr& _jointElement,
13481451
const BodyMap& _sdfBodyNodes,
@@ -1410,6 +1513,23 @@ SDFJoint readJoint(
14101513
= (parent_it == _sdfBodyNodes.end()) ? "" : parent_it->first;
14111514
newJoint.childName = (child_it == _sdfBodyNodes.end()) ? "" : child_it->first;
14121515

1516+
//--------------------------------------------------------------------------
1517+
// Mimic metadata (captured before joint creation)
1518+
if (hasElement(_jointElement, "axis")) {
1519+
const ElementPtr& axisElement = getElement(_jointElement, "axis");
1520+
const auto mimics = readMimicElements(axisElement);
1521+
newJoint.mimicInfos.insert(
1522+
newJoint.mimicInfos.end(), mimics.begin(), mimics.end());
1523+
}
1524+
if (hasElement(_jointElement, "axis2")) {
1525+
const ElementPtr& axis2Element = getElement(_jointElement, "axis2");
1526+
auto mimics = readMimicElements(axis2Element);
1527+
for (auto& m : mimics)
1528+
m.referenceDof = 1u; // axis2 maps to the second DoF
1529+
newJoint.mimicInfos.insert(
1530+
newJoint.mimicInfos.end(), mimics.begin(), mimics.end());
1531+
}
1532+
14131533
//--------------------------------------------------------------------------
14141534
// transformation
14151535
Eigen::Isometry3d parentWorld = Eigen::Isometry3d::Identity();

0 commit comments

Comments
 (0)