Commit ddb54d3
authored
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
- docs
- source
- _static/actuators
- api/lab
- concepts
- how-to
- migration
- overview/core-concepts
- physical-backends
- newton
- policy_deployment
- 02_gear_assembly
- 04_reach
- setup/walkthrough
- tutorials
- 01_assets
- 03_envs
- scripts/tutorials
- 01_assets
- 06_deploy
- skills/user
- migrate-2x-to-3x
- prepare-assets-for-newton
- use-sensors-actuators
- source
- isaaclab_assets
- changelog.d
- isaaclab_assets/robots
- isaaclab_contrib
- changelog.d
- isaaclab_contrib/assets/multirotor
- isaaclab_experimental
- changelog.d
- isaaclab_experimental/envs/mdp
- test/envs/mdp
- isaaclab_newton
- changelog.d
- isaaclab_newton
- actuators
- assets/articulation
- benchmark/assets
- physics
- test
- assets
- physics
- sensors
- isaaclab_ov
- changelog.d
- isaaclab_ov
- assets/articulation
- benchmark/assets
- test
- assets
- sensors
- isaaclab_physx
- changelog.d
- isaaclab_physx
- assets/articulation
- benchmark/assets
- test
- assets
- sensors
- isaaclab_tasks
- changelog.d
- isaaclab_tasks
- contrib
- anymal_c_direct
- assemble_trocar/mdp
- automate
- cabinet/config/openarm
- deploy/gear_assembly/config
- rizon_4s
- ur_10e
- dr_legs/mdp
- factory
- humanoid_amp
- locomanip_pick_place/mdp
- stack/config/so101
- velocity/config/spot/mdp
- core
- cabinet
- lift
- config
- franka_soft
- franka
- mdp
- velocity/config/go2
- test/core
- isaaclab
- changelog.d
- isaaclab
- actuators
- newton
- assets/articulation
- benchmark
- asset_suites
- entrypoints
- envs/mdp
- sim
- schemas
- test
- utils
- utils
- leapp
- warp
- test
- actuators
- assets
- utils
- warp
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
16 | 20 | | |
17 | 21 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
99 | 99 | | |
100 | 100 | | |
101 | 101 | | |
| 102 | + | |
102 | 103 | | |
103 | 104 | | |
104 | 105 | | |
| |||
Loading
Loading
Loading
Loading
0 commit comments