Delayed multi-input actuators use uninitialized control slots
Intro
Hi!
I am testing the interaction between current multi-input actuators and actuator history/delay. The control-history path remains scalar and leaves the remaining inputs of a delayed actuator uninitialized.
My setup
- MuJoCo source build from
mainat10124d5d9dca411ec3c8988aa1e3b619103d71bb - C API, double precision
- Ubuntu 24.04.5 LTS, Linux 7.0.0-28-generic x86_64
- CMake 3.28.3 and GCC 11.5.0
What's happening? What did you expect?
A PID actuator with input="pos vel ff" owns three control values. With live controls [1, 2, 3], its force is 6. I expected the delayed path to record and later use the same complete control block.
Actuator history allocation, insertion, mj_readCtrl, and mj_initCtrlHistory are hard-coded to dimension one. During actuation, a local array of all nu controls is allocated, but a delayed actuator assigns only ctrl[adr]. The remaining two slots are consumed by the PID gain without initialization.
The minimal reproduction reuses MuJoCo's stack allocation with canaries so the omitted slots are deterministic:
nu=3 delayed-force=501.0 direct-force=6.0The delayed path uses the recorded first input 1 plus stale stack values 200 and 300. Disabling only delay uses the live complete block and produces 6.
Relevant source and documentation:
- https://github.com/google-deepmind/mujoco/blob/10124d5d9dca411ec3c8988aa1e3b619103d71bb/src/user/user_model.cc#L2213-L2224
- https://github.com/google-deepmind/mujoco/blob/10124d5d9dca411ec3c8988aa1e3b619103d71bb/src/user/user_model.cc#L3863-L3872
- https://github.com/google-deepmind/mujoco/blob/10124d5d9dca411ec3c8988aa1e3b619103d71bb/src/engine/engine_forward.c#L386-L400
- https://github.com/google-deepmind/mujoco/blob/10124d5d9dca411ec3c8988aa1e3b619103d71bb/src/engine/engine_forward.c#L1344-L1360
- https://github.com/google-deepmind/mujoco/blob/10124d5d9dca411ec3c8988aa1e3b619103d71bb/src/engine/engine_support.c#L934-L1013
Steps for reproduction
- Check out and build the commit above.
- Compile
poc/reproducer.ccusingpoc/README.md. - Run it and compare delayed force with the direct-control causal control.
Reproduction package:
multi-input-actuator-delay-history-poc.zip
Minimal model for reproduction
The complete MJCF is embedded in the C++ file and contains one slider, one sphere, and one delayed three-input PID. No assets are required.
Code required for reproduction
See poc/reproducer.cc. A complete patch needs a block-aware history layout and API decision, so I have included a fix design rather than a partial one-line change.
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