Skip to content

Add usd support#152

Open
Giulero wants to merge 28 commits intomainfrom
add_usd_support
Open

Add usd support#152
Giulero wants to merge 28 commits intomainfrom
add_usd_support

Conversation

@Giulero
Copy link
Collaborator

@Giulero Giulero commented Feb 23, 2026

This pull request introduces USD integration.
It also refactors the RBDAlgorithms class to improve the computation of kinematic chains and Jacobians.


OpenUSD Integration and Documentation

  • Added OpenUSD support to installation instructions and dependency lists for both pip and conda (README.md, docs/installation.rst, ci_env.yml, ci_env_win.yml, pyproject.toml, docs/requirements.txt). [1] [2] [3] [4] [5] [6] [7]
  • Introduced a comprehensive OpenUSD guide (docs/guides/usd.rst) and linked it throughout the documentation, including backend guides and feature lists. [1] [2] [3] [4] [5] [6]
  • Added OpenUSD usage examples for all backends in quickstart guides (docs/quickstart/numpy.rst, docs/quickstart/jax.rst, docs/quickstart/casadi.rst, docs/quickstart/pytorch.rst). [1] [2] [3] [4]
  • Expanded API documentation to include OpenUSD conversion functions (docs/modules/model.conversions.rst).

Installation & Dependency Updates

  • Updated installation instructions to clarify optional model interfaces and backend grouping, and included OpenUSD and MuJoCo as optional dependencies (docs/installation.rst, README.md). [1] [2] [3] [4] [5] [6]
  • Added openusd to CI and test environment dependencies (ci_env.yml, ci_env_win.yml, pyproject.toml). [1] [2] [3]

Core Library Refactor

  • Introduced the ChainTraversal dataclass in src/adam/core/rbd_algorithms.py to encapsulate chain traversal results, and refactored forward_kinematics and joints_jacobian to use this new structure for improved clarity and maintainability. [1] [2] [3]

MuJoCo Documentation Improvements

  • Added explicit installation instructions for MuJoCo support in the guide (docs/guides/mujoco.rst).

README Enhancements

  • Added OpenUSD usage example in the main README.md to demonstrate model export and loading, and clarified backend options.

These changes provide robust OpenUSD support across the library, improve documentation and usability, and refactor core kinematics code for better structure and extensibility.


📚 Documentation preview 📚: https://adam-docs--152.org.readthedocs.build/en/152/

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds OpenUSD (USD) import/export support across the library (factory detection, model conversion utilities, and KinDyn entry points), expands documentation/install guides accordingly, and refactors RBDAlgorithms to reuse cached chain traversals for kinematics/Jacobians.

Changes:

  • Added USD model loading via build_model_factory(...) and KinDynComputations.from_usd(...) / from_usd_stage(...), plus a new USDModelFactory.
  • Added USD export utilities (model.to_usd, model_to_usd[_stage]) and USD conversion tests.
  • Refactored RBDAlgorithms forward kinematics/Jacobian computation to reuse cached traversal results; updated docs (including a new USD guide) and CI dependencies.

Reviewed changes

Copilot reviewed 28 out of 28 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/test_usd_conversion.py Adds roundtrip URDF→USD→KinDyn validation (FK/Jacobian/CoM).
tests/test_usd.py Adds USD-loaded KinDyn regression tests vs iDynTree references.
src/adam/model/usd_factory/usd_model.py Implements USDModelFactory to build ADAM models from USD stages/files.
src/adam/model/usd_factory/init.py Exposes USDModelFactory from the usd_factory package.
src/adam/model/model.py Adds Model.to_usd(...) convenience export API.
src/adam/model/kindyn_mixin.py Adds from_usd(...) and from_usd_stage(...) constructors for KinDyn frontends.
src/adam/model/factory.py Extends model factory detection/parsing to support USD paths and USD stages.
src/adam/model/conversions/usd.py Adds model/URDF → USD conversion utilities and stage writer.
src/adam/model/conversions/init.py Re-exports USD conversion helpers in the conversions package.
src/adam/model/init.py Exposes USDModelFactory at adam.model level.
src/adam/core/rbd_algorithms.py Refactors kinematics/Jacobians to reuse cached traversals; adds chain caching helpers.
pyproject.toml Adds optional mujoco/usd extras and includes USD dependency in test extra.
docs/requirements.txt Adds sphinx-shibuya for the new docs theme.
docs/quickstart/pytorch.rst Adds OpenUSD loading example for PyTorch backend.
docs/quickstart/numpy.rst Adds OpenUSD loading example for NumPy backend.
docs/quickstart/jax.rst Adds OpenUSD loading example for JAX backend.
docs/quickstart/index.rst Links quickstarts to model-interface guides (MuJoCo/OpenUSD).
docs/quickstart/casadi.rst Adds OpenUSD loading example for CasADi backend.
docs/modules/model.conversions.rst Documents the new USD conversion module in API docs.
docs/installation.rst Updates installation instructions for optional model interfaces (MuJoCo/USD).
docs/index.rst Adds OpenUSD to feature list and guide navigation.
docs/guides/usd.rst Introduces a dedicated OpenUSD integration guide.
docs/guides/mujoco.rst Adds explicit MuJoCo installation instructions.
docs/guides/index.rst Adds the USD guide to the guides toctree.
docs/conf.py Switches Sphinx HTML theme to shibuya.
ci_env_win.yml Adds openusd to Windows conda CI environment.
ci_env.yml Adds openusd to conda CI environment.
README.md Adds OpenUSD install instructions and a USD export/load example snippet.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +16 to +17
def _to_numpy(x: Any) -> np.ndarray:
val = x.array if isinstance(x, ArrayLike) else x
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_to_numpy() relies on np.asarray(val) when val comes from an ArrayLike wrapper. This will fail for non-NumPy backends in common setups (e.g., Torch tensors on CUDA, JAX device arrays), which is likely if a Model was built via the JAX/PyTorch SpatialMath factories. Consider either (1) explicitly documenting/validating that USD export only supports CPU/NumPy-backed models, or (2) adding backend-aware conversions (e.g., Torch: val.detach().cpu().numpy(), JAX: np.asarray(np.array(val))).

Suggested change
def _to_numpy(x: Any) -> np.ndarray:
val = x.array if isinstance(x, ArrayLike) else x
def _to_numpy(x: Any) -> np.ndarray:
"""
Convert an input (possibly an ArrayLike wrapper) to a NumPy float array.
Supports common non-NumPy backends used by SpatialMath (e.g. PyTorch, JAX)
by performing backend-aware host conversions when necessary.
"""
val = x.array if isinstance(x, ArrayLike) else x
# Detect common non-NumPy backends by module name to avoid hard imports.
mod = type(val).__module__ if not isinstance(val, (int, float, complex)) else ""
# PyTorch tensors (including CUDA) need an explicit detach+cpu before NumPy.
if mod.startswith("torch"):
# `detach()` for gradients, `cpu()` to ensure host memory.
return val.detach().cpu().numpy().astype(float, copy=False)
# JAX device arrays require a host transfer via np.array before np.asarray.
if mod.startswith("jax"):
return np.asarray(np.array(val), dtype=float)
# Fallback for NumPy arrays, Python sequences, and other array-likes.

Copilot uses AI. Check for mistakes.
Comment on lines +293 to +296
and (
lower_attr.HasAuthoredValueOpinion()
or upper_attr.HasAuthoredValueOpinion()
)
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In _joint_limits(), has_limits becomes true if only one of lower_attr/upper_attr has an authored opinion, but the code then reads both attributes. For the unauthored side, Get() will return the schema default (often 0.0), which can silently introduce incorrect joint limits. Consider requiring both limits to be authored, or handling each side independently (e.g., default to -inf/+inf when one side is missing).

Suggested change
and (
lower_attr.HasAuthoredValueOpinion()
or upper_attr.HasAuthoredValueOpinion()
)
and lower_attr.HasAuthoredValueOpinion()
and upper_attr.HasAuthoredValueOpinion()

Copilot uses AI. Check for mistakes.
@traversaro
Copy link
Contributor

It is not clear to me which model is used to test the conversion, can you provide some pointers to it?

@traversaro
Copy link
Contributor

It is not clear to me which model is used to test the conversion, can you provide some pointers to it?

Is it

url = "https://raw.githubusercontent.com/icub-tech-iit/ergocub-gazebo-simulations/master/models/stickBot/model.urdf"
, not related to this PR but I guess it would be really good if at least we pin the version downloaded instead of always download the latest one.

@Giulero
Copy link
Collaborator Author

Giulero commented Feb 23, 2026

It is not clear to me which model is used to test the conversion, can you provide some pointers to it?

@traversaro the models used for the conversion are the stickbot and iCubGenova04, see

adam/tests/conftest.py

Lines 60 to 63 in fec4af4

ROBOTS = [
"iCubGenova04",
"StickBot",
]

, not related to this PR but I guess it would be really good if at least we pin the version downloaded instead of always download the latest one.

Makes sense! If @CarlottaSartore agrees (this was introduced for the parametric interface) I can pin a version. However I checked and there is no release in https://github.com/icub-tech-iit/ergocub-gazebo-simulations to pin.

@Giulero Giulero requested a review from traversaro February 23, 2026 15:31
@traversaro
Copy link
Contributor

Based on my previous experience with parser and conversion, I really think this would benefit of having:

  • some automatically generated models to be fed in the usd round-trip tests (that is easily doable, either by using existing iDynTree facilities to generate random URDFs or adding something similar to adam).
  • test agains some other usd library: this is particularly relevant as otherwise we may be basically hallucinating features/semantics of usd, that only works out as our imported and exporter are coherent, but perhaps they are only coherent among each other and not against the usd spec. However, I am not sure if that is doable, i.e. something like that is easily available to test against

@traversaro
Copy link
Contributor

However I checked and there is no release in https://github.com/icub-tech-iit/ergocub-gazebo-simulations to pin.

We can pin a fixed checkout (even better in theory, as tags can be deleted).

@traversaro
Copy link
Contributor

traversaro commented Feb 23, 2026

  • However, I am not sure if that is doable, i.e. something like that is easily available to test against

I did a quick research on this https://chatgpt.com/share/699c75a0-fb18-8006-8167-38e56911f6e8 .

Leaving aside IsaacLab/IsaacSim that may be difficult to integrate/test against, other interesting options:

@traversaro
Copy link
Contributor

Also https://github.com/newton-physics/urdf-usd-converter/blob/main/docs/concept_mapping.md seems something you want to pass as a context to a LLM. :D

Comment on lines +252 to +253
"urdf_to_usd() is deprecated; build an ADAM model and use model.to_usd() "
"or model_to_usd(model, ...).",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a bit strange to introduce a new function and deprecate it directly.

Copy link
Collaborator Author

@Giulero Giulero Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought I removed it indeed :D It was in the documentation! Removed also here

@Giulero
Copy link
Collaborator Author

Giulero commented Feb 23, 2026

some automatically generated models to be fed in the usd round-trip tests (that is easily doable, either by using existing iDynTree facilities to generate random URDFs or adding something similar to adam).

This one should be done in
https://github.com/gbionics/adam/blob/add_usd_support/tests/test_usd_conversion.py

but this uses iCubGenova04 or Stickbot. I could use a random generated URDF!

@traversaro
Copy link
Contributor

To clarify, now we are testing that the two ADAM models generated like this:

                   ┌───────────────────────────────────▼►
                   │                                     
                   │                                     
     ┌────────────┐│  ┌───────────┐   ┌───────────┐      
────►│URDF to ADAM├┼─►│ADAM to USD┼──►│USD to ADAM┼────► 
     └────────────┘   └───────────┘   └───────────┘      

are consitent. This is fragile as any double bug in ADAM to USD and USD to ADAM is hidden.

A more robust method may be to also test (if it works):

         ┌────────────┐                   
───┬────►│URDF to ADAM├────────────────────────────────────►  
   │     └────────────┘                    
   │                                                          
   │     ┌──────────────────┐         ┌────────────┐          
   └────►│urdf-usd-converter┼────────►│USD to ADAM ├──────►   
         └──────────────────┘         └────────────┘          

that would be much more robust, and much more informative also for the llm to iterate on.

@traversaro
Copy link
Contributor

The macOS failures are due to NVIDIA-Omniverse/usd-exchange#10 . Probably we can skip testing usd on macOS, or just skip macOS?

Giulero and others added 4 commits February 24, 2026 10:21
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants