Closed drewhamiltonasdf closed 10 months ago
Thanks for the clear write-up and the example code!
I agree with your assessment. In fact, I see the same problem even more clearly in the dm_control acrobot.xml example.
from pydrake.all import ModelVisualizer, StartMeshcat, PackageMap
visualizer = ModelVisualizer(meshcat=meshcat)
visualizer.parser().package_map().AddRemote(
package_name="dm_control",
params=PackageMap.RemoteParams(
urls=[
f"https://github.com/google-deepmind/dm_control/archive/refs/tags/1.0.15.tar.gz"
],
sha256=("bac091b18689330a99b7c18ddf86baa916527f5e4ab8e3ded0c8caff1dab2048"),
strip_prefix="dm_control-1.0.15/",
),
)
visualizer.AddModels(url="package://dm_control/dm_control/suite/acrobot.xml")
plant = visualizer.parser().plant()
visualizer.Run(loop_once=not running_as_notebook)
meshcat.DeleteAddedControls()
Drake is clearly putting the joint at the origin, but mujoco is clearly putting it at [0,0,2].
As far as I can tell, drake is following the mujoco xml documentation, but the behavior in mujoco is not following the xml documentation? Please check me on this. The body/joint
docs say
This element creates a joint. As explained in Kinematic tree, a joint creates motion degrees of freedom between the body where it is defined and the body’s parent.
and then also
pos: real(3), “0 0 0” Position of the joint, specified in the frame of the parent body. For free joints this attribute is ignored.
I guess if one interprets the second usage of the term "parent body" to mean the current body (the parent of this joint), not the parent of the body, then things work out ok. Presumably the axis
element is ok, since it is by definition the same in the parent and child bodies.
100%. I think this is the issue. I only noticed because I was really trying to break something I'm working on and was spending a lot of time loading URDF's, SDF's, and MuJoCo representations. I mentioned in the reviewable that I don't quite have time to look, but I trust if it's passing tests it's good to go. Thanks for the fix!
What happened?
It seems that MuJoCo imports both joints and inertial masses as an offset from the body it is nested in. Drake on the other hand seems to compute the joint location with respect to the previous body.
For example:
Drake will currently interpret this as the joint1 frame being offset from link1 frame by [0.0, 0.02, 0.02]: On the other hand, MuJoCo would interpret it as and offset of [0.0 0.12 0.62] a very significant difference.
This example is not a great way to specify body/joint locations, but it is incorrect nonetheless and could lead to some significant issues. Interestingly, Drake seems to import the geometry objects and inertial masses correctly parented to the parent body frame, but gets the joint position wrong. I assume this has to do with how the parenting works in other formats, where the joint is the parent of the body instead of the other way around.
I hope that makes sense. I can provide a sample xml and minimal Drake code / MuJoCo code to see the difference if it is helpful.
Here is a (very gross) xml to demonstrate this:
It will throw a few unsupported material warnings but load fine so you can move the joints in meshcat, and just to make things easy on you, here's minimal code to load this in MuJoCo (python):
That mass matrix printed above will, naturally, be quite different than the one printed in Drake.
Version
No response
What operating system are you using?
Ubuntu 22.04
What installation option are you using?
pip install drake
Relevant log output
No response