Skip to content

Does gym-ignition support nested models? #390

@FirefoxMetzger

Description

@FirefoxMetzger

SDFormat v1.5 introduced the ability to nest models within itself (the //model/model element). As part of my effort to test my python SDFormat bindings, I created a simple world with a nested model, which loads fine in gazebo itself, but fails to load in gym-ignition due to its inability to determine the canonical link (which I specify explicitly).

Here is the full SDF

SDF
<?xml version="1.0"?>
<sdf version="1.8">
    <world name="pose_world">
        <model name="parent" canonical_link="box::box_link">
            <frame name="table2">
                <pose>0.794 0 0 0 -0 1.5708</pose>
            </frame>
            <frame name="tabletop_2">
                <pose relative_to="table2">0 0 1.015 0 0 0</pose>
            </frame>
            <model name="box">
                <pose relative_to="tabletop_2">-0.2379753249844183 -0.036526411138213755 0.025 0 0 0</pose>
                <link name="box_link"></link>
                <link name="B">
                    <pose relative_to="box_link">1 0 0 0 0 0</pose>
                </link>
            </model>
        </model>
    </world>
</sdf>

And here is a MWE python script to reproduce the behavior

SDF
import tempfile
from scenario import gazebo as scenario_gazebo
from scipy.spatial.transform import Rotation as R
import numpy as np

# Allocate the simulator
simulator = scenario_gazebo.GazeboSimulator()

world_without_model_string = """
<?xml version="1.0" ?>
<sdf version="1.8">
    <world name="pose_world">
    </world>
</sdf>"""

with tempfile.NamedTemporaryFile(mode="r+") as f:

    # Write the world file
    f.write(world_without_model_string)

    # Insert the world file
    f.seek(0)
    assert simulator.insert_world_from_sdf(f.name)

assert simulator.initialize()
world = simulator.get_world("pose_world")

# Insert the physics
# ==> OTHERWISE THE POSES ARE NOT UPDATED <==
if not world.set_physics_engine(scenario_gazebo.PhysicsEngine_dart):
    raise RuntimeError("Failed to insert the physics plugin")

model_string_A = """
<?xml version="1.0" ?>
<sdf version="1.8">
    <model name="parent" canonical_link="box::box_link">
        <frame name="table2">
            <pose>0.794 0 0 0 -0 1.5708</pose>
        </frame>
        <frame name="tabletop_2">
            <pose relative_to="table2">0 0 1.015 0 0 0</pose>
        </frame>
        <model name="box">
            <pose relative_to="tabletop_2">-0.2379753249844183 -0.036526411138213755 0.025 0 0 0</pose>
            <link name="box_link"></link>
            <link name="B">
                <pose relative_to="box_link">1 0 0 0 0 0</pose>
            </link>
        </model>
    </model>
</sdf>"""
assert world.insert_model_from_string(model_string_A)

# A paused run should suffice
assert simulator.run(paused=True)

for model_name in world.model_names():
    model = world.get_model(model_name)
    print(f"Model: {model_name}")
    print(f"  Base link: {model.base_frame()}")

    for name in model.link_names():
        position = model.get_link(name).position()
        orientation_wxyz = np.asarray(model.get_link(name).orientation())
        orientation = R.from_quat(orientation_wxyz[[1, 2, 3, 0]]).as_euler("xyz")
        print(f"  {name}:", (*position, *tuple(orientation)))

On my machine, this produces:

Model: parent
Traceback (most recent call last):
  File "/usr/lib/python3.8/runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.8/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "/home/sebastian/.vscode/extensions/ms-python.python-2021.2.633441544/pythonFiles/lib/python/debugpy/__main__.py", line 45, in <module>
    cli.main()
  File "/home/sebastian/.vscode/extensions/ms-python.python-2021.2.633441544/pythonFiles/lib/python/debugpy/../debugpy/server/cli.py", line 444, in main
    run()
  File "/home/sebastian/.vscode/extensions/ms-python.python-2021.2.633441544/pythonFiles/lib/python/debugpy/../debugpy/server/cli.py", line 285, in run_file
    runpy.run_path(target_as_str, run_name=compat.force_str("__main__"))
  File "/usr/lib/python3.8/runpy.py", line 265, in run_path
    return _run_module_code(code, init_globals, run_name,
  File "/usr/lib/python3.8/runpy.py", line 97, in _run_module_code
    _run_code(code, mod_globals, init_globals,
  File "/usr/lib/python3.8/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "/home/sebastian/coding_projects/lila-legibility/lila/test_poses2.py", line 60, in <module>
    print(f"  Base link: {model.base_frame()}")
  File "/home/sebastian/.local/lib/python3.8/site-packages/scenario/bindings/core.py", line 2724, in base_frame
    return _core.Model_base_frame(self)
RuntimeError: [parent] Failed to find the canonical link

Is this a known limitation of gym-ignition, and if so, what are the plans to supporting nested models? For me, they are useful in this particular context, because I want to position a model @relative_to something, which only works if I can insert a full world with models (currently not possible because models should be inserted dynamically after physics are loaded) or if they are inside a nested model.

This is because due to SDF scoping rules, which prevent using @relative_to on a model that is a direct child of //sdf (since there are no other frames within that scope).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions