Add nested models support in mujoco plugin#1002
Conversation
Signed-off-by: Shameek Ganguly <shameek@intrinsic.ai>
…ested models in mujoco plugin Signed-off-by: Shameek Ganguly <shameek@intrinsic.ai>
Signed-off-by: Shameek Ganguly <shameek@intrinsic.ai>
Signed-off-by: Shameek Ganguly <shameek@intrinsic.ai>
Signed-off-by: Shameek Ganguly <shameek@intrinsic.ai>
Signed-off-by: Shameek Ganguly <shameek@intrinsic.ai>
Signed-off-by: Shameek Ganguly <shameek@intrinsic.ai>
Signed-off-by: Shameek Ganguly <shameek@intrinsic.ai>
Signed-off-by: Shameek Ganguly <shameek@intrinsic.ai>
Signed-off-by: Shameek Ganguly <shameek@intrinsic.ai>
Signed-off-by: Shameek Ganguly <shameek@intrinsic.ai>
95e5e6d to
cc76c26
Compare
Signed-off-by: Shameek Ganguly <shameek@intrinsic.ai>
cc76c26 to
bfcbfc9
Compare
Signed-off-by: Shameek Ganguly <shameek@intrinsic.ai>
Signed-off-by: Shameek Ganguly <shameek@intrinsic.ai>
Signed-off-by: Shameek Ganguly <shameek@intrinsic.ai>
Signed-off-by: Shameek Ganguly <shameek@intrinsic.ai>
azeey
left a comment
There was a problem hiding this comment.
I haven't finished reviewing yet, but I wanted to start a conversation about how self_collide tags are handled.
| // every pair | ||
| auto &objMap = modelInfo->links.objectToID; | ||
| for (auto it1 = objMap.begin(); it1 != objMap.end(); ++it1) | ||
| std::vector<const mjsBody *> allBodies; |
There was a problem hiding this comment.
This differs from the current behavior in DART. I did a quick test and came up with the following table that summarizes the behavior of the self_collide tag on a parent and nested models.
| Parent flag | nested model (child) flag | note |
|---|---|---|
| true | true | Bodies in the parent collide against other bodies in the parent. Bodies in the child collide against other bodies in the child. Bodies in the parent collide against other bodies in the child and vice-versa. |
| true | false | Bodies in the parent collide against other bodies in the parent. Bodies in child do not collide against each other. Bodies in the parent collide against other bodies in the child and vice-versa. |
| false | true | Bodies in the parent do not collide against other bodies in the parent. Bodies in the child collide against other bodies in the child. Bodies in the parent collide against other bodies in the child and vice-versa |
| false | false | Bodies in the parent do not collide against other bodies in the parent. Bodies in child do not collide against each other. Bodies in the parent collide against other bodies in the child and vice-versa. |
I believe what this code does is completely ignore the self_collide tag of nested models and treat all bodies as though they were in the parent model.
I've also created a simple SDF file to demonstrate the different behaviors with AI assistance:
https://gist.github.com/azeey/3f2392c0fc05a586d56869da23f28d40
All four cases are laid out side-by-side:
- Case 1 (Parent:
true, Child:true): Located atx = -4.5 - Case 2 (Parent:
true, Child:false): Located atx = -1.5 - Case 3 (Parent:
false, Child:true): Located atx = 1.5 - Case 4 (Parent:
false, Child:false): Located atx = 4.5
For each case, three tests run independently:
- PP (Parent-Parent) at
y = -1.5: A parent-level dropper (red sphere) falls onto a parent-level platform (red box). - CC (Child-Child) at
y = 0.0: A nested child-level dropper (blue sphere) falls onto a nested child-level platform (blue box). - PC (Parent-Child) at
y = 1.5: A nested child-level dropper (blue sphere) falls onto a parent-level platform (red box).
DART
Screen.Recording.2026-06-24.at.15.50.13.mov
MuJoCo
Screen.Recording.2026-06-24.at.15.50.59.mov
| // Parent body is worldbody. | ||
| childPoseInParent = _rootSdfModel.RawPose() * childPoseInRoot; |
There was a problem hiding this comment.
This was discovered by Gemini, but I agree with it. The root model here might be a nested model itself. However, if we're the parent body is null, we need it's pose relative to the worldbody (absolute pose) rather than using RawPose which is the pose relative to its parent model.
* mujoco: Implement AttachFixedJointFeature and DetachJointFeature - Implemented `AttachFixedJoint` using MuJoCo equality weld constraints. - Optimized `AttachFixedJoint` and `DetachJoint` to reuse and toggle constraints (`active = 0/1`) to avoid expensive `mjModel` recompilations. - Implemented `CastToFixedJoint` to identify fixed joints. - Added comprehensive unit tests in `detachable_joint.cc`. Generated-by: Gemini 3.1 Pro --------- Signed-off-by: Addisu Z. Taddese <addisuzt@intrinsic.ai>
Set compiler.degree option to false to prevent MuJoCo from interpreting joint limits specified in radians as degrees. Also added a test case asserting the compiled joint limits of joint_limit_test. Generated-by: Gemini 3.5 Flash Signed-off-by: Addisu Z. Taddese <addisuzt@intrinsic.ai>
Signed-off-by: Shameek Ganguly <shameek@intrinsic.ai>
bade604 to
c71af2b
Compare
Signed-off-by: Shameek Ganguly <shameek@intrinsic.ai>
azeey
left a comment
There was a problem hiding this comment.
Disclaimer: I've used Gemini to help with the reviews.
Signed-off-by: Shameek Ganguly <shameek@intrinsic.ai>
azeey
left a comment
There was a problem hiding this comment.
Looks great! Thanks for iterating. Just one more small comment.
Signed-off-by: Shameek Ganguly <shameek@intrinsic.ai>
6e73e36 to
f7b29e0
Compare
🎉 New feature
Part of #299
Summary
Mujoco plugin now supports nested models.
ConstructNestedModelinmujoco/src/SDFFeatures.ccmujoco/src/EntityManagementFeatures.ccPhysicssystem). This is currently failing in bullet-featherstone. I will follow up with a fix.Backport Policy
Can be backported with the rest of the PRs that add the Mujoco plugin.
Test it
Checklist
codecheckpassed (See contributing)Generated-by: Gemini 3.1 pro in Antigravity
Note to maintainers: Remember to use Squash-Merge and edit the commit message to match the pull request summary while retaining
Signed-off-byandGenerated-bymessages.Backports: If this is a backport, please use Rebase and Merge instead.