mujoco icon indicating copy to clipboard operation
mujoco copied to clipboard

Expected behavior of mj_saveLastXML regarding asset file path: absolute vs relative?

Open younghyopark opened this issue 2 months ago • 0 comments

Intro

Hi!

I am a PhD student at MIT, using mujoco for dexterous manipulation research.

I'm curious what's actually the expected behavior of mj_saveLastXML regarding the asset file paths; is it supposed to save with absolute paths for all the files, or relative paths based on the original XML file that MjModel was loaded with (using from_xml_path)? I am observing both behaviors in different scenarios, which I cannot find the pattern of its behavior.

My setup

I'm on macOS using the latest mujoco version (3.3.7) installed via pip install mujoco

What's happening? What did you expect?

I basically have this directory structure, which I attached as a zip file.

saveLastXML_bug.zip

xmls/
   |_ panda_2f85/
        |_ xxx.obj 
        |_ xxx.obj 
        |_ panda_2f85.xml 
   |_ scene.xml 

where scene.xml is nothing but an XML model defined with some mocap bodies and ground floors, where the panda model is included using the <include> tag.

<mujoco model="panda scene">

  <include file="panda_2f85/panda_2f85.xml"/>

  <worldbody>
    <body name="target" pos="0.5 -0.4 .5" quat="0 1 0 0" mocap="true">
      <geom type="box" size=".02 .02 .02" contype="0" conaffinity="0" rgba=".6 .3 .3 .5"/>
      <site type="sphere" size="0.01" rgba="0 0 1 1" group="1"/>
    </body>
  </worldbody>

</mujoco>

Everything loads properly when I load it directly via mujoco GUI.

Now, depending on what XML you load, and how you load it, the outcome of mj_saveLastXML is different.

Case 1. Load xmls/panda_2f85/panda_2f85.xml

model = mujoco.MjModel.from_xml_path(f"xmls/panda_2f85/panda_2f85.xml")
mujoco.mj_saveLastXML("test.xml", model)
with open("test.xml", "r") as f:
    xml_content = f.read()
check_if_file_paths_are_absolute(xml_content)

Then mj_saveLastXML returns every file path as its relative path.

Number of relative paths : 75
Number of absolute paths : 0

Case 2. Load xmls/scene.xml (using relative path)

model = mujoco.MjModel.from_xml_path("xmls/scene.xml")
mujoco.mj_saveLastXML("test.xml", model)
with open("test.xml", "r") as f:
    xml_content = f.read()
check_if_file_paths_are_absolute(xml_content)

Then I cannot load the model; it parses the asset path in a weird way.

Error opening file 'xmls/xmls/panda_2f85/base.stl': No such file or directory

Case 3. Load xmls/scene.xml (using absolute path)

    model = mujoco.MjModel.from_xml_path(os.path.abspath("xmls/scene.xml"))
    mujoco.mj_saveLastXML("test.xml", model)
    with open("test.xml", "r") as f:
        xml_content = f.read()
    file_paths = check_file_paths(xml_content)

Then everything loads properly, and mj_saveLastXML writes everything in absolute path.

Number of relative paths : 0
Number of absolute paths : 75

Expected behavior

For every case above,

  1. MjModel.from_xml_path successfully loads the model
  2. mj_saveLastXML returns an XML with every file path being absolute path.

Steps for reproduction

saveLastXML_bug.zip

Unzip the file, and launch

pip install mujoco 
python test.py 

Minimal model for reproduction

No response

Code required for reproduction

No response

Confirmations

younghyopark avatar Nov 11 '25 22:11 younghyopark