Skip to content

Commit ddb54d3

Browse files
Refactor articulation actuator ownership (#6839)
# Description This PR adds a backend-neutral actuator runtime around `ActuatorCollection` and separates actuator-model state from simulated joint state. It keeps one scoped collection per articulation while presenting one command, processed-command, telemetry, group-access, and lifecycle API across PhysX, Newton, and OVPhysX. The two main goals are: 1. make actuator ownership and runtime access consistent across backends; 2. batch compatible actuator groups to reduce launch overhead without changing their named configuration or access. ## Ownership and public API - `Articulation` owns actuator application and backend submission. - `ArticulationData` owns live solver joint properties, including joint gains, solver limits, armature, and friction. - `ActuatorCollection` owns articulation-wide commands, processed commands, effort telemetry, group lookup, and actuator lifecycle. - Each named group owns only its actuator-model parameters and state. - Backend `ActuatorControl` implementations own ordering conversion, joint-property writes, command submission, and native-controller integration. - Newton-native controllers retain controller parameters in Newton storage. ```python # Commands received by actuator models. robot.actuators.command.position robot.actuators.command.velocity robot.actuators.command.effort robot.actuators.command.set_position_index(value=position_command) # Commands produced for simulated joints on the Lab-managed path. robot.actuators.joint_command.position robot.actuators.joint_command.velocity robot.actuators.joint_command.effort # Articulation-wide effort telemetry. robot.actuators.computed_effort robot.actuators.applied_effort # Named model parameters and state. motor = robot.actuators["legs"] # explicit group motor.stiffness motor.damping motor.actuator_effort_limit drive = robot.actuators["gripper"] # implicit group drive.joint_effort_limit ``` All collection-wide arrays use articulation joint order. Native paths bypass `joint_command`, so that view is not submitted-command telemetry for them. ### Joint properties and actuator properties `actuator_effort_limit` is the explicit model clipping limit. `joint_effort_limit` and `joint_velocity_limit` configure the joint or solver. The deprecated `effort_limit` alias resolves to the actuator limit for explicit models and to the joint limit for implicit models. `effort_limit_sim` and `velocity_limit_sim` remain deprecated configuration aliases through 3.x. Explicit groups retain their model gains, rated velocity, delay, motor curves, and clipping limits. They do not retain copies of solver limits or friction. Implicit groups instead read stiffness, damping, and effort limits from live articulation buffers because the backend executes their drive. The former group-level joint-property accessors (`effort_limit_sim`, `velocity_limit_sim`, armature, and friction variants) are removed. Read those values through `ArticulationData` and update them with articulation joint writers. The legacy backend gain writers remain deprecated 3.x forwarders; managed randomization should use `randomize_actuator_gains`. ## Logical groups and execution batching Named groups remain the configuration and access surface. Internally: - disjoint stateless groups of the same exact Lab actuator class may execute as one batch even when their parameters differ; - implicit batches read live articulation-wide gains and limits and publish processed commands and telemetry in one fused Warp launch; - ideal-PD and DC-motor batches use pointer-stable staging, in-place Torch compute, cached Warp gathers, and fused output publication; - a singleton full-articulation explicit group keeps direct views and avoids a redundant gather; - stateful, neural, subclass-specialized, native, and incompatible groups stay separate. Native runtime parsing aggregates structurally compatible controllers while keeping per-DOF values. Unsupported custom explicit configurations raise before USD actuator state is changed. Two ambiguous construction states are rejected: - collection membership is fixed after construction; - a joint cannot belong to more than one actuator group. ## Backend behavior - **PhysX:** runs Lab models in the collection before submission and supported native explicit actuators through the shared host adapter. - **OVPhysX:** also runs Lab models in the collection; its native path uses the shared host adapter while preserving eager tensor binding and partial writes. - **Newton:** runs Lab models in the collection before submission and manager-owned native controllers inside the solver. - **Ordering:** collection buffers stay in public joint order; conversion occurs only at backend boundaries. The host adapter captures staging, native model execution, and telemetry on CUDA when possible and falls back to eager execution otherwise. It manages the capture for stateful native actuators. Neural checkpoints use Isaac Lab's shared file cache before Newton metadata is added, so local and remote paths follow the same loading path. ## Compatibility and documentation - Deprecated articulation command setters forward to `actuators.command`. - Deprecated `ArticulationData` command and torque-telemetry accessors forward to the collection. - Lab execution of explicit actuator models is deprecated in favor of supported Newton-native actuators. - The actuator concept page now documents ownership, commands, limits, explicit/implicit behavior, batching, native execution, and backend-specific constraints. - The 3.0 migration guide and tutorials use the new command and property names. LEAPP action terms retain the annotated articulation setters until the exporter supports collection setters. ## Final performance validation Both revisions used fresh, isolated environments and the same dependency lock. Run order was counterbalanced by row and seed. Throughput values below are mean ± sample standard deviation. Throughput changes are paired geometric FPS ratios with two-sided 95% t intervals; p-values are Holm-adjusted across all 12 rows. ### Checkpoint playback: five paired seeds Protocol: fixed policy checkpoints, 4,096 environments, 50 warm-up steps, and 1,000 measured steps under inference mode. This uses the full benchmark task configuration rather than the reduced interactive play configuration. The canonical result set contains 60 paired comparisons and 120 unique bundles. | Task | Physics | Actuator path | `develop` FPS | PR FPS | Paired change (95% CI) | Holm p | |---|---|---|---:|---:|---:|---:| | Cartpole | PhysX | Lab | 1,029,140 ± 8,301 | 1,269,172 ± 7,097 | +23.33% [+21.83%, +24.84%] | <0.0001 | | Cartpole | Newton | Lab | 1,505,687 ± 18,142 | 1,981,901 ± 17,827 | +31.63% [+28.28%, +35.07%] | 0.0001 | | G1 Flat | PhysX | Lab | 108,564 ± 3,465 | 117,091 ± 3,872 | +7.85% [+3.53%, +12.35%] | 0.0478 | | G1 Flat | Newton | Lab | 233,893 ± 1,211 | 250,100 ± 776 | +6.93% [+5.96%, +7.90%] | 0.0003 | | ANYmal-D Flat | PhysX | Lab neural | 268,397 ± 6,016 | 269,470 ± 5,798 | +0.40% [-0.79%, +1.61%] | 1.0000 | | ANYmal-D Flat | Newton | Lab neural | 430,949 ± 2,785 | 434,384 ± 5,860 | +0.79% [-0.80%, +2.41%] | 1.0000 | | Franka Reach | PhysX | Lab | 315,996 ± 9,606 | 332,548 ± 29,851 | +4.95% [-4.74%, +15.64%] | 1.0000 | | Franka Reach | Newton | Lab | 563,375 ± 8,702 | 635,729 ± 6,690 | +12.85% [+11.66%, +14.05%] | <0.0001 | | Go2 Flat | PhysX | Lab | 266,480 ± 37,831 | 280,768 ± 14,739 | +6.05% [-10.82%, +26.12%] | 1.0000 | | Go2 Flat | PhysX | Newton native | 297,084 ± 23,028 | 294,879 ± 29,591 | -0.91% [-20.53%, +23.56%] | 1.0000 | | Go2 Flat | Newton | Lab | 813,321 ± 5,481 | 836,744 ± 2,688 | +2.88% [+1.73%, +4.04%] | 0.0172 | | Go2 Flat | Newton | Newton native | 905,438 ± 5,792 | 924,958 ± 10,496 | +2.15% [+0.90%, +3.42%] | 0.0520 | There is no supported playback regression. Six rows remain significant after correction. The negative Go2 PhysX-native point estimate is small relative to its seed variance and its interval spans large gains and losses. #### Environment creation time (exploratory) The playback harness also records the time spent in `gym.make()`, including articulation construction. This is not total process startup: imports, task configuration, app launch, runner and checkpoint loading, and the first step are outside this timer. Persistent driver and Warp caches can also affect these measurements, so the intervals below are unadjusted and should be treated as follow-up evidence rather than a release gate. A positive change means the PR was slower to create the environment. | Task | Physics | Actuator path | `develop` seconds | PR seconds | Paired PR/develop change (95% CI) | |---|---|---|---:|---:|---:| | Cartpole | PhysX | Lab | 4.633 ± 0.036 | 4.670 ± 0.162 | +0.76% [-2.94%, +4.60%] | | Cartpole | Newton | Lab | 5.271 ± 0.055 | 5.294 ± 0.045 | +0.44% [-1.12%, +2.01%] | | G1 Flat | PhysX | Lab | 48.631 ± 0.269 | 48.605 ± 0.135 | -0.05% [-0.80%, +0.70%] | | G1 Flat | Newton | Lab | 8.379 ± 2.552 | 7.956 ± 0.017 | -2.14% [-29.19%, +35.23%] | | ANYmal-D Flat | PhysX | Lab neural | 21.974 ± 0.646 | 22.753 ± 1.897 | +3.31% [-6.73%, +14.42%] | | ANYmal-D Flat | Newton | Lab neural | 6.813 ± 0.456 | 6.852 ± 0.076 | +0.73% [-5.79%, +7.71%] | | Franka Reach | PhysX | Lab | 32.516 ± 0.097 | 33.241 ± 1.758 | +2.12% [-4.16%, +8.81%] | | Franka Reach | Newton | Lab | 8.554 ± 0.297 | 8.981 ± 0.791 | +4.74% [-7.75%, +18.92%] | | Go2 Flat | PhysX | Lab | 24.657 ± 0.356 | 24.509 ± 0.086 | -0.59% [-2.19%, +1.03%] | | Go2 Flat | PhysX | Newton native | 27.424 ± 1.349 | 26.848 ± 0.084 | -2.01% [-7.47%, +3.77%] | | Go2 Flat | Newton | Lab | 6.281 ± 0.044 | 6.506 ± 0.093 | +3.58% [+2.24%, +4.93%] | | Go2 Flat | Newton | Newton native | 6.329 ± 0.026 | 6.561 ± 0.054 | +3.66% [+2.35%, +4.99%] | Most rows are unresolved. The consistent signal worth a dedicated startup benchmark is the roughly 0.23-second increase for Go2 on Newton, on both the Lab and native actuator paths. ### Full training: three paired seeds Protocol: RSL-RL, 4,096 environments, 50 timing warm-up steps, and each task's full schedule: Cartpole 150, ANYmal-D and Go2 300, Franka 1,000, and G1 1,500 iterations. The canonical set contains 36 paired comparisons and 72 unique successful bundles. Native neural runs are excluded because that path is known not to work on either revision. | Task | Physics | Actuator path | `develop` FPS | PR FPS | Paired change (95% CI) | Holm p | |---|---|---|---:|---:|---:|---:| | Cartpole | PhysX | Lab | 609,337 ± 1,779 | 680,158 ± 3,496 | +11.62% [+10.98%, +12.27%] | 0.0018 | | Cartpole | Newton | Lab | 755,488 ± 11,886 | 846,398 ± 6,748 | +12.04% [+8.82%, +15.36%] | 0.0354 | | G1 Flat | PhysX | Lab | 100,722 ± 938 | 104,069 ± 1,021 | +3.32% [-1.42%, +8.29%] | 0.5742 | | G1 Flat | Newton | Lab | 184,909 ± 425 | 194,393 ± 975 | +5.13% [+4.35%, +5.91%] | 0.0131 | | ANYmal-D Flat | PhysX | Lab neural | 205,431 ± 716 | 205,932 ± 2,199 | +0.24% [-2.45%, +3.00%] | 1.0000 | | ANYmal-D Flat | Newton | Lab neural | 270,330 ± 1,242 | 273,531 ± 2,486 | +1.18% [-1.54%, +3.98%] | 1.0000 | | Franka Reach | PhysX | Lab | 241,489 ± 175 | 257,090 ± 2,820 | +6.46% [+3.51%, +9.48%] | 0.0855 | | Franka Reach | Newton | Lab | 376,112 ± 2,892 | 399,159 ± 8,936 | +6.11% [+2.22%, +10.15%] | 0.1455 | | Go2 Flat | PhysX | Lab | 228,745 ± 5,309 | 229,636 ± 10,642 | +0.34% [-9.65%, +11.43%] | 1.0000 | | Go2 Flat | PhysX | Newton native | 227,488 ± 10,813 | 232,861 ± 3,340 | +2.43% [-5.57%, +11.12%] | 1.0000 | | Go2 Flat | Newton | Lab | 443,121 ± 3,497 | 448,127 ± 4,156 | +1.13% [+0.73%, +1.53%] | 0.0607 | | Go2 Flat | Newton | Newton native | 458,881 ± 4,562 | 459,165 ± 1,376 | +0.06% [-1.75%, +1.91%] | 1.0000 | No row has a negative mean training-throughput change. Cartpole on both backends and G1 on Newton remain significant after correction. Each run's late-training reward is averaged over its final 100 iterations. The table reports the mean ± sample standard deviation across three seeds: | Task | Physics | Actuator path | `develop` reward | PR reward | |---|---|---|---:|---:| | Cartpole | PhysX | Lab | 4.917 ± 0.035 | 4.917 ± 0.035 | | Cartpole | Newton | Lab | 4.922 ± 0.016 | 4.922 ± 0.016 | | G1 Flat | PhysX | Lab | 28.252 ± 0.358 | 27.237 ± 0.502 | | G1 Flat | Newton | Lab | 22.992 ± 0.629 | 23.254 ± 0.722 | | ANYmal-D Flat | PhysX | Lab neural | 15.083 ± 2.840 | 15.083 ± 2.840 | | ANYmal-D Flat | Newton | Lab neural | 7.803 ± 0.088 | 12.673 ± 4.248 | | Franka Reach | PhysX | Lab | 0.033 ± 0.098 | 0.033 ± 0.098 | | Franka Reach | Newton | Lab | 0.014 ± 0.092 | -0.031 ± 0.047 | | Go2 Flat | PhysX | Lab | 32.038 ± 1.152 | 32.038 ± 1.152 | | Go2 Flat | PhysX | Newton native | 31.253 ± 1.027 | 31.547 ± 0.825 | | Go2 Flat | Newton | Lab | 34.071 ± 0.979 | 34.223 ± 1.019 | | Go2 Flat | Newton | Newton native | 34.604 ± 0.318 | 34.742 ± 0.538 | Episode length and success were also checked over the final 100 iterations. No convergence regression is statistically established. G1 PhysX has a lower mean reward on the PR, but the paired difference is unresolved (`p = 0.157`) and success is unchanged. ANYmal-D on Newton is bimodal across seeds; its apparent improvement is also unresolved (`p = 0.182`). Compared commits: - `develop`: `135cf98904cbd73f3b8bdd89188e1a463ebcbb97` - PR: `9ee6296124687ec54ed13e102ac59b7667b08d8d` ## Validation - [x] Complete core actuator suite on CPU and CUDA: **479 passed** - [x] Focused Newton target-mode, native-gain, and friction integration: **15 passed** - [x] Focused PhysX native current-state ordering: **2 passed** - [x] OVPhysX native command, mixed-path, reset, gain, and state-refresh coverage - [x] Warning-as-error Sphinx build succeeded - [x] All repository pre-commit hooks passed before the final push - [x] Independent final code review found no remaining Critical or Important findings - [x] Independent benchmark audit accepted all **192** canonical final bundles Fused implicit telemetry can differ from the previous Torch expression by one float32 ULP (`4.768e-7`) because of arithmetic ordering. Processed position, velocity, and feed-forward effort commands sent to the backend remain exact. ## Type of change - New feature: backend-neutral actuator collection and Newton-native execution - Performance: automatic batching and fused/cached Warp staging - Bug fix: joint/actuator ownership, class validation, ordering, and remote checkpoints - Documentation and migration update ## Checklist - [x] I have read and understood the contribution guidelines - [x] I have run pre-commit checks with `./isaaclab.sh -f` - [x] I have updated the documentation - [x] I have added focused behavioral tests and verified regression tests fail before their fixes - [x] I have added the required changelog fragments - [x] My name already exists in `CONTRIBUTORS.md`
1 parent fa4de7d commit ddb54d3

185 files changed

Lines changed: 9315 additions & 6736 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitattributes

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,15 @@
77
*.obj filter=lfs diff=lfs merge=lfs -text
88
*.gif filter=lfs diff=lfs merge=lfs -text
99
*.mp4 filter=lfs diff=lfs merge=lfs -text
10+
*.webp filter=lfs diff=lfs merge=lfs -text
1011
*.pt filter=lfs diff=lfs merge=lfs -text
1112
*.jit filter=lfs diff=lfs merge=lfs -text
1213
*.hdf5 filter=lfs diff=lfs merge=lfs -text
1314

1415
source/isaaclab_tasks/test/golden_images/**/*.png filter=lfs diff=lfs merge=lfs -text
1516

17+
# Generated actuator plots are reviewed as rendered images rather than XML.
18+
docs/source/_static/actuators/*.png binary linguist-generated
19+
1620
*.bat text eol=crlf
1721
*.sh text eol=lf

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ Table of Contents
9999
:caption: Concepts
100100

101101
source/concepts/backends_and_presets
102+
source/concepts/actuators
102103

103104

104105
.. toctree::
Lines changed: 3 additions & 0 deletions
Loading
131 KB
Loading
131 KB
Loading
Lines changed: 3 additions & 0 deletions
Loading
177 KB
Loading
177 KB
Loading
Lines changed: 3 additions & 0 deletions
Loading
240 KB
Loading

0 commit comments

Comments
 (0)