Git Product home page Git Product logo

rod's Introduction

RObot Description processor

The ultimate Python tool for RObot Descriptions processing.

ROD is yet another library to operate on robot descriptions based on the SDFormat specification.

Why SDFormat?

Among the many existing robot description formats, SDFormat provides a well-defined and maintained versioned specification that controls the available fields and their content. Open Robotics already provides the C++ library gazebosim/sdformat with initial support of Python bindings. However, C++ dependencies in pure-Python projects are typically quite complicated to handle and maintain. Here ROD comes to rescue.

URDF, thanks to native ROS support, is historically the most popular robot description used by the community. The main problem of URDF is that it is not a specification, and developers of URDF descriptions might produce models and parsers that do not comply to any standard. Luckily, URDF models can be easily converted to SDF1. If the URDF model is not compliant, the process errors with clear messages. Furthermore, modern versions of the converter produce a SDF description with standardized pose semantics, that greatly simplifies the life of downstream developers that do not have to guess the reference frame or pose elements. Last but not least, the pose semantics also makes SDF aware of the concept of frame that URDF is missing.

Features

  • Out-of-the-box support for SDFormat specifications ≥ 1.10.
  • Serialization and deserialization support for SDF files.
  • In-memory layout based on dataclasses.
  • Syntax highlighting and auto-completion.
  • Programmatic creation of SDF files from Python APIs.
  • Transitive support for URDF through conversion to SDF.
  • Type validation of elements and attributes.
  • Automatic check of missing required elements.
  • High-performance serialization and deserialization using Fatal1ty/mashumaro.
  • Export in-memory model description to URDF.

Installation

Tip

ROD does not support out-of-the-box URDF files. URDF support is obtained by converting URDF files to SDF using the gz sdf command provided by sdformat and gz-tools. Ensure these tools are installed on your system if URDF support is needed (more information below).

Using conda (recommended)

Installing ROD using conda is the recommended way to obtain a complete installation with out-of-the-box support for both URDF and SDF descriptions:

conda install rod -c conda-forge

This will automatically install sdformat and gz-tools.

Using pip

You can install ROD from PyPI with pypa/pip, preferably in a virtual environment:

pip install rod[all]

If you need URDF support, follow the official instructions to install Gazebo Sim on your operating system, making sure to obtain sdformat ≥ 13.0 and gz-tools ≥ 2.0.

You don't need to install the entire Gazebo Sim suite. For example, on Ubuntu, you can only install the libsdformat13 gz-tools2 packages.

Examples

Serialize and deserialize SDF files
import pathlib

from rod import Sdf

# Supported SDF resources
sdf_resource_1 = "/path/to/file.sdf"
sdf_resource_2 = pathlib.Path(sdf_resource_1)
sdf_resource_3 = sdf_resource_2.read_text()

# Deserialize SDF resources
sdf_1 = Sdf.load(sdf=sdf_resource_1)
sdf_2 = Sdf.load(sdf=sdf_resource_2)
sdf_3 = Sdf.load(sdf=sdf_resource_3)

# Serialize in-memory Sdf object
print(sdf_3.serialize(pretty=True))
Create SDF models programmatically
from rod import Axis, Inertia, Inertial, Joint, Limit, Link, Model, Sdf, Xyz

sdf = Sdf(
    version="1.7",
    model=Model(
        name="my_model",
        link=[
            Link(name="base_link", inertial=Inertial(mass=1.0, inertia=Inertia())),
            Link(name="my_link", inertial=Inertial(mass=0.5, inertia=Inertia())),
        ],
        joint=Joint(
            name="base_to_my_link",
            type="revolute",
            parent="base_link",
            child="my_link",
            axis=Axis(xyz=Xyz(xyz=[0, 0, 1]), limit=Limit(lower=-3.13, upper=3.14)),
        ),
    ),
)

print(sdf.serialize(pretty=True))
<?xml version="1.0" encoding="utf-8"?>
<sdf version="1.7">
  <model name="my_model">
    <link name="base_link">
      <inertial>
        <mass>1.0</mass>
        <inertia>
          <ixx>1.0</ixx>
          <iyy>1.0</iyy>
          <izz>1.0</izz>
          <ixy>0.0</ixy>
          <ixz>0.0</ixz>
          <iyz>0.0</iyz>
        </inertia>
      </inertial>
    </link>
    <link name="my_link">
      <inertial>
        <mass>0.5</mass>
        <inertia>
          <ixx>1.0</ixx>
          <iyy>1.0</iyy>
          <izz>1.0</izz>
          <ixy>0.0</ixy>
          <ixz>0.0</ixz>
          <iyz>0.0</iyz>
        </inertia>
      </inertial>
    </link>
    <joint name="base_to_my_link" type="revolute">
      <parent>base_link</parent>
      <child>my_link</child>
      <axis>
        <xyz>0 0 1</xyz>
        <limit>
          <lower>-3.13</lower>
          <upper>3.14</upper>
        </limit>
      </axis>
    </joint>
  </model>
</sdf>
Exporting SDF to URDF
# Generate first the 'sdf' object with the collapsed code
# of the section 'Create SDF models programmatically'.

from rod.urdf.exporter import UrdfExporter

urdf_string = UrdfExporter(pretty=True, gazebo_preserve_fixed_joints=True).to_urdf_string(
    sdf=sdf
)

print(urdf_string)
<?xml version="1.0" encoding="utf-8"?>
<robot name="my_model">
  <link name="base_link">
    <inertial>
      <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
      <mass value="1.0"/>
      <inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
    </inertial>
  </link>
  <link name="my_link">
    <inertial>
      <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
      <mass value="0.5"/>
      <inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
    </inertial>
  </link>
  <joint name="base_to_my_link" type="revolute">
    <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
    <parent link="base_link"/>
    <child link="my_link"/>
    <axis xyz="0 0 1"/>
    <limit effort="3.4028235e+38" velocity="3.4028235e+38" lower="-3.13" upper="3.14"/>
  </joint>
</robot>

Similar projects

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Maintainers

@diegoferigo

License

BSD3

Footnotes

  1. Conversion can be done using the gz sdf command included in Gazebo Sim starting from Garden.

rod's People

Contributors

diegoferigo avatar flferretti avatar lorycontixd avatar traversaro avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

rod's Issues

Evaluate support of SDF → URDF conversion

Currently rod supports URDF indirectly by performing a under-the-hood conversion to SDF, assuming that Gazebo Sim and sdformat are found in the system.

However, some of our libraries (e.g. iDynTree) do not yet support SDF, and this is the reason why most of our code still relies on URDF files. While waiting that SDF support propagates, it might be a good idea to implement a SDF → URDF conversion.

The URDF structure is much simpler than SDF, and converting rod.* objects would be pretty easy. Of course, there would be some information getting lost.

Extra care would be however necessary in the following cases:

  • Frame semantics logic since URDFs cannot specify the reference frame of pose elements
  • Frames, that could be optionally converted to (fixed_jointempty_link) chains
  • Extra elements that could be defined in custom <gazebo> tags

Implement logic to resolve resources URIs

SDF files could use different special tags to access resources from the file system without using absolute paths:

There's always been some confusion (at least in my case) to figure out what is the correct environment variable and URI to use. For example, this is what I ended up implementing in gym-ignition-models, and this is the configuration of icub-models.

Furthermore, URDF to SDF conversion could still be affected by gazebosim/sdformat#227, but I didn't try recently if it was fixed.

This being said, we could implement a pretty extensive logic to resolve all the combinations. I already ended up implementing a work around in a downstream library, that could be ported here in rod.

Parse URDF models from ergocub-software

I've encountered an issue while trying to parse the URDF model using the ergoCubGazeboV1_minContacts model from the ergocub-software repository. Specifically, the problem arises when rod tries to convert the model from URDF to SDF format.

Interestingly, removing the <gazebo> tags from the URDF resolves the problem. As a expected behaviour, I believe that if the rod tool doesn't recognize these tags, it should ideally ignore them and possibly log a warning message.

Here's the traceback I'm encountering:

Traceback (most recent call last):
  File "/home/flferretti/git/element_rl-for-codesign/src/evogym/envs/ergocub.py", line 686, in <module>
    env = ErgoCub()
  File "/home/flferretti/git/element_rl-for-codesign/src/evogym/envs/ergocub.py", line 243, in __init__
    model = self.simulator.insert_model_from_description(
  File "/home/flferretti/jaxsim/src/jaxsim/simulation/simulator.py", line 247, in insert_model_from_description
    model = jaxsim.high_level.model.Model.build_from_model_description(
  File "/home/flferretti/jaxsim/src/jaxsim/high_level/model.py", line 155, in build_from_model_description
    model_description = jaxsim.parsers.rod.build_model_description(
  File "/home/flferretti/jaxsim/src/jaxsim/parsers/rod/parser.py", line 315, in build_model_description
    sdf_data = extract_model_data(
  File "/home/flferretti/jaxsim/src/jaxsim/parsers/rod/parser.py", line 53, in extract_model_data
    sdf_element = rod.Sdf.load(sdf=model_description, is_urdf=is_urdf)
  File "/home/flferretti/.local/lib/python3.10/site-packages/rod/sdf/sdf.py", line 103, in load
    raise ValueError("Failed to parse 'sdf' argument")
ValueError: Failed to parse 'sdf' argument

C.C. @diegoferigo @traversaro

Finalize SDFormat 1.10 specification

Refer to: SDFormat 1.10.

Adding new elements is fairly easy, we do accept pull requests.

sdf

  • sdf/actor
  • sdf/light

world

  • world/audio
  • world/wind
  • world/include
  • world/atmosphere
  • world/gui
  • world/light
  • world/frame #12
  • world/actor
  • world/plugin
  • world/road
  • world/spherical_coordinates
  • world/state
  • world/population

scene

  • scene/sky
  • scene/fog

state

  • state

physics

  • physics/dart
  • physics/simbody
  • physics/bullet
  • physics/ode

light

  • light

actor

  • actor

model

  • model/frame #12
  • model/plugin
  • model/gripper

link

  • link/velocity_decay
  • link/sensor
  • link/projector
  • link/audio_sink
  • link/audio_source
  • link/battery
  • link/light
  • link/particle_emitter

sensor

  • sensor

joint

  • joint/gearbox_ratio
  • joint/gearbox_reference_body
  • joint/thread_pitch
  • joint/axis2
  • joint/physics
  • joint/sensor

collision

  • collision/laser_retro
  • collision/max_contacts
  • collision/surface

visual

  • visual/cast_shadows
  • visual/laser_retro
  • visual/transparency
  • visual/visibility_flags
  • visual/meta
  • visual/plugin

material

  • material/shader
  • material/render_order
  • material/double_sided
  • material/pbr

geometry

  • geometry/empty
  • geometry/heightmap/texture
  • geometry/heightmap/blend
  • geometry/heightmap/use_terrain_paging
  • geometry/heightmap/sampling
  • geometry/image
  • geometry/mesh/submesh
  • geometry/polyline

ModuleNotFoundError: No module named 'rod.element'

Just installed rod from the README instruction:

pip install git+https://github.com/ami-iit/rod

Trying to import it afterwards:

Python 3.8.10 (default, Jun 22 2022, 20:18:18) 
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import rod
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "~/.local/lib/python3.8/site-packages/rod/__init__.py", line 1, in <module>
    from .collision import Collision
  File "~/.local/lib/python3.8/site-packages/rod/collision.py", line 6, in <module>
    from .common import Pose
  File "~/.local/lib/python3.8/site-packages/rod/common.py", line 6, in <module>
    from .element import Element
ModuleNotFoundError: No module named 'rod.element'

Error when looking for gazebo executable in Colab

Despite having the command gz sdf --help working in Colab, when using rod, the following error is always raised:

RuntimeError: Failed to find 'sdf' command part of /usr/bin/gz installation.

I believe the problem is in these lines:

cp = subprocess.run([executable, "sdf", "--help"], capture_output=True)
if cp.returncode != 0:
msg = f"Failed to find 'sdf' command part of {executable} installation"
raise RuntimeError(msg)

as by running them in a Colab cell, gives the same exact error.

Passing the environment variables did not help:

import subprocess
import os

executable = "/usr/bin/gz"
env = os.environ.copy()

cp = subprocess.run([executable, "sdf", "--help"], capture_output=True, env=env)

if cp.returncode != 0:
    msg = f"Failed to find 'sdf' command part of {executable} installation"
    raise RuntimeError(msg)

Thanks @xela-95 for raising this up.

URDF to SDF conversion is not working on Windows

@diegoferigo in #24 wrote:

On Windows, the gz sdf command line we use for the URDF to SDF conversion does not work for some reason, the pytest suite is disabled on this OS. cc @traversaro

Windows error
        if cp.returncode != 0:
            msg = f"Failed to find 'sdf' command part of {executable} installation"
           raise RuntimeError(msg)
           RuntimeError: Failed to find 'sdf' command part of C:\Miniconda3\envs\test\Library\bin\gz.BAT installation

I open this issue to track this problem.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.