Discrete actuator derivative indexes control limits by actuator ordinal
Intro
Hi!
I am testing order invariance for the discrete integrator with variable-width actuator inputs. The effective-metric derivative reads the target control from its control-block address but checks its limits using the actuator ordinal.
My setup
- MuJoCo source build from
mainat10124d5d9dca411ec3c8988aa1e3b619103d71bb - C API, double precision
- Ubuntu 24.04.5 LTS, Linux 7.0.0-28-generic x86_64
- Normal GCC 11.5.0 build and GCC 13.3.0 AddressSanitizer build
What's happening? What did you expect?
actuatorInput correctly reads d->ctrl[m->actuator_ctrladr[i]], but then uses m->actuator_ctrllimited[i] and m->actuator_ctrlrange[2*i]. Those metadata arrays are indexed by packed control slot. I expected inserting or moving a physically inactive variable-width actuator to leave the target actuator's force derivative and next state unchanged.
The first reproducer builds the same three-input zero-force PID and limited affine actuator in opposite orders. With an in-range target control, both steps agree. With raw control 100, the forward path clamps both target forces to 0.5, but only the target-first derivative uses the clamped input:
control=1 target-first adr=0 qvel=0.0049995000499950008 force=0.5
control=1 target-second adr=3 qvel=0.0049995000499950008 force=0.5
control=1 velocity-delta=0
control=100 target-first adr=0 qvel=0.0049995000499950008 force=0.5
control=100 target-second adr=3 qvel=0.0049504950495049506 force=0.5
control=100 velocity-delta=-4.9005000490050243e-05The second reproducer places a zero-input DC motor before the target. A whole-library AddressSanitizer build reports:
ERROR: AddressSanitizer: use-after-poison
READ of size 1
#0 actuatorInput ... src/engine/engine_derivative.c:2415
#1 actuatorLenDeriv ... src/engine/engine_derivative.c:2495
#2 mjd_effActuation ... src/engine/engine_derivative.c:4088Relevant source:
- https://github.com/google-deepmind/mujoco/blob/10124d5d9dca411ec3c8988aa1e3b619103d71bb/src/user/user_model.cc#L3852-L3861
- https://github.com/google-deepmind/mujoco/blob/10124d5d9dca411ec3c8988aa1e3b619103d71bb/src/engine/engine_derivative.c#L2404-L2427
- https://github.com/google-deepmind/mujoco/blob/10124d5d9dca411ec3c8988aa1e3b619103d71bb/src/engine/engine_derivative.c#L4072-L4104
Steps for reproduction
- Build the affected revision normally and run
poc/order_invariance.ccwith the commands inpoc/README.md. - Observe equal forces but different velocities only when the target is clamped and follows the three-input actuator.
- Build MuJoCo and
poc/zero_input.ccwith AddressSanitizer. - Observe the invalid metadata read in
actuatorInput.
Reproduction package:
discrete-integrator-control-limit-indexing-poc.zip
Minimal model for reproduction
Both complete asset-free MJCF models are embedded in the C++ programs. The order test includes a physically zero dummy actuator as the metamorphic control.
Code required for reproduction
See poc/order_invariance.cc and poc/zero_input.cc. The attached fix.patch uses the resolved control address consistently and adds an order-invariance regression. The focused regression and all 142 engine_forward_test cases pass; single-precision and repository-wide CI remain pending.
Confirmations
- I searched the latest documentation thoroughly before posting.
- I searched previous Issues and Discussions, I am certain this has not been raised before.
Source: google-deepmind/mujoco