PyBullet inverse-dynamics cache is stale after mass changes and body reuse
Environment
- OS: Ubuntu 24.04.5 LTS, Linux 7.0.0-28-generic x86_64
- Compiler: GCC 11.5.0
- Python: 3.12.3
- Source:
bulletphysics/bullet3masterat63c4d67e337017f9d8b298c900e9aabdb69296e7 - PyBullet: built locally from that exact checkout
Description
calculateInverseDynamics, calculateMassMatrix, and Jacobian calculation share an inverse-dynamics model cached by raw btMultiBody*. changeDynamics can change mass or inertia without invalidating the model, and removeBody deletes a multibody without erasing its cache entry. A replacement can reuse both body ID and allocation, so calculations for the replacement use the deleted body's parameters.
Expected behavior: derived dynamics calculations reflect the current body's mass and inertia after a dynamics mutation or body replacement.
Actual behavior: for the reproducer's one-DOF fixed-base model, a fresh 10 kg link returns inverse torque -90 and mass matrix [[10]]. If a cached 1 kg body is changed to 10 kg, or removed and replaced by a 10 kg body at reused ID 0, both operations still return the 1 kg results -9 and [[1]].
Sources:
- https://github.com/bulletphysics/bullet3/blob/63c4d67e337017f9d8b298c900e9aabdb69296e7/examples/SharedMemory/PhysicsServerCommandProcessor.cpp#L1996-L2029
- https://github.com/bulletphysics/bullet3/blob/63c4d67e337017f9d8b298c900e9aabdb69296e7/examples/SharedMemory/PhysicsServerCommandProcessor.cpp#L10656-L10981
- https://github.com/bulletphysics/bullet3/blob/63c4d67e337017f9d8b298c900e9aabdb69296e7/examples/SharedMemory/PhysicsServerCommandProcessor.cpp#L12739-L12832
Reproduction package:
inverse-dynamics-cache-invalidation-poc.zip
Steps to reproduce
- Build PyBullet from the commit above using
poc/README.md. - Run
python poc/reproducer.py fresh. - Run
python poc/reproducer.py reuse. - Run
python poc/reproducer.py mutate.
The exact baseline and fixed outputs are in poc/observed-output.txt.
Source: bulletphysics/bullet3