-
Notifications
You must be signed in to change notification settings - Fork 3.8k
[Task Clean-up][Newton] Dexterous Part 1/8: Fix cloner rows, cubric fallback, and visualizer teardown #6411
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from 1 commit
e706d95
f424e9c
71a0fb5
504957a
28567d8
4337a76
e553e07
345dd78
78c157d
51e8e77
b921d6d
8a616a2
3794920
adb8998
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| Fixed | ||
| ^^^^^ | ||
|
|
||
| * Fixed detached articulation links with Newton and Isaac RTX by falling back | ||
| from unvalidated cubric adapter versions. | ||
|
|
||
| * Fixed Newton clone imports creating empty MuJoCo custom-frequency rows from | ||
| ignored environment subtrees. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,7 +5,9 @@ | |
|
|
||
| from __future__ import annotations | ||
|
|
||
| import re | ||
| from collections.abc import Callable, Sequence | ||
| from dataclasses import replace | ||
| from typing import Any | ||
|
|
||
| import torch | ||
|
|
@@ -18,6 +20,75 @@ | |
| from isaaclab.sim.utils.newton_model_utils import replace_newton_builder_shape_colors | ||
|
|
||
|
|
||
| def _add_global_stage_to_builder( | ||
| builder: ModelBuilder, | ||
| stage: Usd.Stage, | ||
| ignore_paths: Sequence[str], | ||
| schema_resolvers: Sequence[Any], | ||
| ) -> Any: | ||
| """Import global prims without parsing custom rows from ignored clone subtrees. | ||
|
|
||
| Newton's built-in USD import honors ``ignore_paths``, but its custom-frequency | ||
| traversal currently does not. MuJoCo frequencies are also registered from | ||
| inside :meth:`ModelBuilder.add_usd`, so both existing and newly registered | ||
| callbacks are scoped for this import and restored afterward. | ||
| """ | ||
| ignored_patterns = tuple(re.compile(path) for path in ignore_paths) | ||
| original_filters = { | ||
| frequency_key: frequency.usd_prim_filter for frequency_key, frequency in builder.custom_frequencies.items() | ||
| } | ||
|
|
||
| def _scope_filter(callback): | ||
| if callback is None: | ||
| return None | ||
|
|
||
| def _filtered(prim: Usd.Prim, context: dict[str, Any]) -> bool: | ||
| prim_path = str(prim.GetPath()) | ||
| if any(pattern.match(prim_path) for pattern in ignored_patterns): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For a correct prefix check, replace the regex compile and match with a plain string prefix comparison that also requires a |
||
| return False | ||
| return callback(prim, context) | ||
|
|
||
| return _filtered | ||
|
|
||
| for frequency_key, callback in original_filters.items(): | ||
| builder.custom_frequencies[frequency_key].usd_prim_filter = _scope_filter(callback) | ||
|
|
||
| original_add_custom_frequency = builder.add_custom_frequency | ||
| had_instance_override = "add_custom_frequency" in vars(builder) | ||
| original_instance_override = vars(builder).get("add_custom_frequency") | ||
|
|
||
| def _add_scoped_custom_frequency(frequency: ModelBuilder.CustomFrequency) -> None: | ||
| frequency_key = frequency.key | ||
| existing = builder.custom_frequencies.get(frequency_key) | ||
| if existing is not None: | ||
| if ( | ||
| original_filters[frequency_key] is not frequency.usd_prim_filter | ||
| or existing.usd_entry_expander is not frequency.usd_entry_expander | ||
| ): | ||
| raise ValueError(f"Custom frequency '{frequency_key}' is already registered with different callbacks.") | ||
| return | ||
|
|
||
| original_filters[frequency_key] = frequency.usd_prim_filter | ||
| original_add_custom_frequency(replace(frequency, usd_prim_filter=_scope_filter(frequency.usd_prim_filter))) | ||
|
|
||
| setattr(builder, "add_custom_frequency", _add_scoped_custom_frequency) | ||
| try: | ||
| return builder.add_usd( | ||
| stage, | ||
| ignore_paths=ignore_paths, | ||
| schema_resolvers=schema_resolvers, | ||
| ) | ||
| finally: | ||
| if had_instance_override: | ||
| setattr(builder, "add_custom_frequency", original_instance_override) | ||
| else: | ||
| delattr(builder, "add_custom_frequency") | ||
| for frequency_key, callback in original_filters.items(): | ||
| frequency = builder.custom_frequencies.get(frequency_key) | ||
| if frequency is not None: | ||
| frequency.usd_prim_filter = callback | ||
|
|
||
|
|
||
| def build_source_builders( | ||
| stage: Usd.Stage, | ||
| sources: Sequence[str], | ||
|
|
||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't know that was a thing, that looks lovely /s
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changes are reasonable otherwise. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1294,7 +1294,9 @@ def instantiate_builder_from_stage(cls): | |
| else: | ||
| # Load everything except the env subtrees (ground plane, lights, etc.) | ||
| ignore_paths = [path for _, path in env_paths] | ||
| builder.add_usd(stage, ignore_paths=ignore_paths, schema_resolvers=schema_resolvers) | ||
| from isaaclab_newton.cloner.newton_clone_utils import _add_global_stage_to_builder | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time! |
||
|
|
||
| _add_global_stage_to_builder(builder, stage, ignore_paths, schema_resolvers) | ||
| replace_newton_builder_shape_colors(builder, stage) | ||
|
|
||
| _, proto_path = env_paths[0] | ||
|
|
||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is also in another PRs. Worth checking out like the solver coupling PR. https://github.com/isaac-sim/IsaacLab/pull/5834/changes#diff-1b68f4d0395901f033293c2fbb2f489b98135587b9e94bbe7fb560bff647498f
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's different context though in the same file. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| # Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md). | ||
| # All rights reserved. | ||
| # | ||
| # SPDX-License-Identifier: BSD-3-Clause | ||
|
|
||
| import ctypes | ||
|
|
||
| from isaaclab_newton.physics._cubric import CubricBindings | ||
|
|
||
|
|
||
| def _verify_version(major: int, minor: int) -> bool: | ||
| """Run the cubric ABI verifier against an in-memory plugin descriptor.""" | ||
| interface_name = ctypes.create_string_buffer(b"omni::cubric::IAdapter\0") | ||
| interface = (ctypes.c_uint64 * 2)() | ||
| interface[0] = ctypes.addressof(interface_name) | ||
| ctypes.c_uint32.from_address(ctypes.addressof(interface) + 8).value = major | ||
| ctypes.c_uint32.from_address(ctypes.addressof(interface) + 12).value = minor | ||
|
|
||
| plugin_descriptor = (ctypes.c_ubyte * 56)() | ||
| ctypes.c_uint64.from_address(ctypes.addressof(plugin_descriptor) + 40).value = ctypes.addressof(interface) | ||
| ctypes.c_uint64.from_address(ctypes.addressof(plugin_descriptor) + 48).value = 1 | ||
|
|
||
| get_descriptor_type = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p) | ||
| get_descriptor = get_descriptor_type(lambda _: ctypes.addressof(plugin_descriptor)) | ||
| framework = (ctypes.c_uint64 * 13)() | ||
| framework[12] = ctypes.cast(get_descriptor, ctypes.c_void_p).value | ||
|
|
||
| return CubricBindings._verify_iadapter_version(ctypes.addressof(framework), 1) | ||
|
|
||
|
|
||
| def test_cubric_adapter_rejects_unvalidated_minor_version(): | ||
| """A newer minor ABI must use the safe CPU transform-hierarchy fallback.""" | ||
| assert _verify_version(0, 1) | ||
| assert not _verify_version(0, 2) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| Fixed | ||
| ^^^^^ | ||
|
|
||
| * Fixed Newton visualization marker cleanup during interpreter shutdown. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Major: Register custom frequencies before attempting to scope them
The fresh global builders used by these call sites have no MuJoCo custom frequencies, and the repository's pinned Newton
ModelBuilder.add_usd()does not calladd_custom_frequency()despite this statement. Consequentlyoriginal_filtersis empty and the method interception never sees a registration. The newly addedtest_global_import_does_not_create_tendon_rows_from_ignored_envsfails withKeyError: 'mujoco:tendon', so this workaround does not establish the behavior it claims. Configure the global builder with the active solver's custom attributes before importing, preferably through the same shared builder setup used for source builders. Once registration is explicit, delete the speculativeadd_custom_frequencymonkeypatch and duplicate callback-identity checks; the pinned importer has no path that needs them. Keep the regression assertion proving one global tendon row plus the replicated source rows.