google-deepmind / mujoco

Multi-Joint dynamics with Contact. A general purpose physics simulator.
https://mujoco.org
Apache License 2.0
8.25k stars 823 forks source link

`MjSpec`: `actuator not found for plugin instance 0` when attaching multiple bodies of a spec with plugin actuator. #2111

Closed hartikainen closed 1 month ago

hartikainen commented 1 month ago

This is the most recent blocker I've observed when trying to achieve the attachment described in https://github.com/google-deepmind/mujoco/discussions/2063.

Intro

Hi!

I am a MuJoCo user working on manipulation.

My setup

MuJoCo: (built from https://github.com/google-deepmind/mujoco/commit/cb745db4121e64841819f27af966fecee0e950e7)

$ python -c "import mujoco; print(mujoco.__version__)"
3.2.3

API: Python

OS:

$ python -c "import platform; print(f'{platform.system()=}, {platform.release()=}, {platform.machine()=}')"
platform.system()='Darwin', platform.release()='24.0.0', platform.machine()='arm64'

What's happening? What did you expect?

I have a MjSpec with two bodies: one with just geom and another with joint corresponding to a plugin actuator. When I attach both of these bodies to another spec, the compilation errors because of an error with the plugin. When I only attach one of the bodies, the model compiles fine. I'd expect both of these cases to work.

I believe this happens because attaching a body that is not associated with a plugin or actuator still copies the plugin to the new spec, while, as expected, the actuator is not copied.

Steps for reproduction

See below test case.

Minimal model for reproduction

See below test case.

Code required for reproduction

This one fails:

  def test_actuator_not_found_for_plugin_instance(self):
    spec_1 = mujoco.MjSpec.from_string(textwrap.dedent("""
      <mujoco model="MuJoCo Model">
        <worldbody>
          <body name="body-1"/>
        </worldbody>
      </mujoco>
    """))
    spec_2 = mujoco.MjSpec.from_string(textwrap.dedent("""
      <mujoco model="MuJoCo Model">
        <extension>
          <plugin plugin="mujoco.pid">
            <instance name="plugin-actuator">
              <config key="kp" value="2.8"/>
              <config key="ki" value="4.0"/>
              <config key="kd" value="0.03"/>
              <config key="imax" value="0.1"/>
              <config key="slewmax" value="3.14159"/>
            </instance>
          </plugin>
        </extension>

        <worldbody>
          <body name="B0" >
            <geom name="G0" size="0.1"/>
          </body>
          <body name="B1">
            <joint name="J0" axis="0 0 -1" range="-0.8727 0.8727" armature="8e-05" damping="0.009" frictionloss="0.009"/>
            <geom name="G1" size="0.1"/>
          </body>
        </worldbody>

        <actuator>
          <plugin name="J0" plugin="mujoco.pid" instance="plugin-actuator" joint="J0" actdim="2"/>
        </actuator>
      </mujoco>
    """))

    spec_1.compile()
    spec_2.compile()

    body_1 = spec_1.find_body("body-1")
    attachment_frame = body_1.add_frame()

    body = spec_2.worldbody.first_body()
    while body is not None:
        attachment_frame.attach_body(body, body.name, "")
        body = spec_2.worldbody.next_body(body)

    spec_1.compile()
$ python -m unittest ./python/mujoco/specs_test.py -k "actuator_not_found_for_plugin_instance"

[...]

----------------------------------------------------------------------
Traceback (most recent call last):
  File "mujoco/python/mujoco/specs_test.py", line 1015, in test_actuator_not_found_for_plugin_instance
    spec_1.compile()
ValueError: Error: engine error: mj_initPlugin: plugin->init failed for plugin id 0
actuator not found for plugin instance 0

----------------------------------------------------------------------

This one works:

  def test_actuator_not_found_for_plugin_instance(self):
    spec_1 = mujoco.MjSpec.from_string(textwrap.dedent("""
      <mujoco model="MuJoCo Model">
        <worldbody>
          <body name="body-1"/>
        </worldbody>
      </mujoco>
    """))
    spec_2 = mujoco.MjSpec.from_string(textwrap.dedent("""
      <mujoco model="MuJoCo Model">
        <extension>
          <plugin plugin="mujoco.pid">
            <instance name="plugin-actuator">
              <config key="kp" value="2.8"/>
              <config key="ki" value="4.0"/>
              <config key="kd" value="0.03"/>
              <config key="imax" value="0.1"/>
              <config key="slewmax" value="3.14159"/>
            </instance>
          </plugin>
        </extension>

        <worldbody>
          <!-- <body name="B0" > -->
          <!--   <geom name="G0" size="0.1"/> -->
          <!-- </body> -->
          <body name="B1">
            <joint name="J0" axis="0 0 -1" range="-0.8727 0.8727" armature="8e-05" damping="0.009" frictionloss="0.009"/>
            <geom name="G1" size="0.1"/>
          </body>
        </worldbody>

        <actuator>
          <plugin name="J0" plugin="mujoco.pid" instance="plugin-actuator" joint="J0" actdim="2"/>
        </actuator>
      </mujoco>
    """))

    spec_1.compile()
    spec_2.compile()

    body_1 = spec_1.find_body("body-1")
    attachment_frame = body_1.add_frame()

    body = spec_2.worldbody.first_body()
    while body is not None:
        attachment_frame.attach_body(body, body.name, "")
        body = spec_2.worldbody.next_body(body)

    spec_1.compile()

Confirmations

hartikainen commented 1 month ago

I just observed a couple of new bugs that are probably related to this one: 1) When attaching two sibling bodies that each have their own plugin actuator from one spec to another, the spec compilation fails. 2) When attaching three sibling bodies that each have their own plugin actuator from one spec to another, the spec compilation fails again, but this time with different error.

The underlying cause for all of these errors might be the same so I'll just provide the test cases here instead of opening new bugs.

The test code is effectively the same as above, but the two models for cases (1) and (2) are:

<mujoco model="model-1">
  <extension>
    <plugin plugin="mujoco.pid">
      <instance name="pid-actuator">
        <config key="kp" value="2.8"/>
        <config key="ki" value="4.0"/>
        <config key="kd" value="0.03"/>
        <config key="imax" value="0.1"/>
        <config key="slewmax" value="3.14159"/>
      </instance>
    </plugin>
  </extension>
  <worldbody>
    <body name="F0/">
      <joint name="J0"/>
      <geom name="G0" size="0.025"/>
    </body>
    <body name="F1/">
      <joint name="J1"/>
      <geom name="G1" size="0.025"/>
    </body>
    <!-- <body name="F2/"> -->
    <!--   <joint name="J2"/> -->
    <!--   <geom name="G2" size="0.025"/> -->
    <!-- </body> -->
  </worldbody>
  <actuator>
    <plugin name="J0" plugin="mujoco.pid" instance="pid-actuator" joint="J0" actdim="2"/>
    <plugin name="J1" plugin="mujoco.pid" instance="pid-actuator" joint="J1" actdim="2"/>
    <!-- <plugin name="J2" plugin="mujoco.pid" instance="pid-actuator" joint="J2" actdim="2"/> -->
  </actuator>
</mujoco>

This one fails with:

----------------------------------------------------------------------
Traceback (most recent call last):
  File "mujoco/python/mujoco/specs_test.py", line 960, in test_incompatible_id_in_body_array
    spec_1.compile()
ValueError: Error: incompatible id in plugin array, position 1
Element name 'pid-actuator', id 0, line 3

----------------------------------------------------------------------
<mujoco model="model-2">
  <extension>
    <plugin plugin="mujoco.pid">
      <instance name="pid-actuator">
        <config key="kp" value="2.8"/>
        <config key="ki" value="4.0"/>
        <config key="kd" value="0.03"/>
        <config key="imax" value="0.1"/>
        <config key="slewmax" value="3.14159"/>
      </instance>
    </plugin>
  </extension>
  <worldbody>
    <body name="F0/">
      <joint name="J0"/>
      <geom name="G0" size="0.025"/>
    </body>
    <body name="F1/">
      <joint name="J1"/>
      <geom name="G1" size="0.025"/>
    </body>
    <body name="F2/">
      <joint name="J2"/>
      <geom name="G2" size="0.025"/>
    </body>
  </worldbody>
  <actuator>
    <plugin name="J0" plugin="mujoco.pid" instance="pid-actuator" joint="J0" actdim="2"/>
    <plugin name="J1" plugin="mujoco.pid" instance="pid-actuator" joint="J1" actdim="2"/>
    <plugin name="J2" plugin="mujoco.pid" instance="pid-actuator" joint="J2" actdim="2"/>
  </actuator>
</mujoco>

This one fails with:

----------------------------------------------------------------------
Traceback (most recent call last):
  File "mujoco/python/mujoco/specs_test.py", line 960, in test_incompatible_id_in_body_array
    spec_1.compile()
ValueError: Error: incompatible id in body array, position 5
Element name 'body-1', id 1, line 4

----------------------------------------------------------------------
quagla commented 1 month ago

Should be fixed by dfe8e45101382a6afb579550259bdb15e21764ef (I typed the wrong issue # in the commit message).

hartikainen commented 1 month ago

The latter two tests, for models model-1 and model-2 pass now from dfe8e4510138. The original one still fails.