google-deepmind / google-deepmind/mujoco
Discrete actuator derivative indexes control limits by actuator ordinal
- Dominant language
- C++
- Stars
- 15.2k
- Forks
- 1.8k
- Avg merge
- 10d 16h
- Merged PRs (30d)
- 25
Description
### 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 `main` at `10124d5d9dca411ec3c8988aa1e3b619103d71bb`
- 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:
```text
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-05
```
The second reproducer places a zero-input DC motor before the target. A whole-library AddressSanitizer build reports:
```text
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:4088
```
Relevant 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
1. Build the affected revision normally and run `poc/order_invariance.cc` with the commands in `poc/README.md`.
2. Observe equal forces but different velocities only when the target is clamped and follows the three-input actuator.
3. Build MuJoCo and `poc/zero_input.cc` with AddressSanitizer.
4. Observe the invalid metadata read in `actuatorInput`.
Reproduction package:
[discrete-integrator-control-limit-indexing-poc.zip](https://github.com/user-attachments/files/32260545/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
- [x] I searched the [latest documentation](https://mujoco.readthedocs.io/en/latest/overview.html) thoroughly before posting.
- [x] I searched previous [Issues](https://github.com/google-deepmind/mujoco/issues) and [Discussions](https://github.com/google-deepmind/mujoco/discussions), I am certain this has not been raised before.
Contributor guide
Research direction
Start with actuator metadata construction in src/user/user_model.cc and the actuatorInput and mjd_effActuation paths in src/engine/engine_derivative.c. Run poc/order_invariance.cc and poc/zero_input.cc using the commands in poc/README.md, then compare with the focused engine_forward_test regression. Done means the order-invariance case agrees, the AddressSanitizer metadata read is absent, and the reported test cases still pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- robotics
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 42/100