Do not update qacc_warmstart at the end of the solver call; instead, update it at the same time as all other state variables. This change makes mj_forward idempotent.

See changelog herein for motivation and discussion.

PiperOrigin-RevId: 797392841
Change-Id: If50e9f09e1d07e8363169d3589c32097aeca2432
This commit is contained in:
Yuval Tassa
2025-08-20 11:29:13 -07:00
committed by Copybara-Service
parent bf04103b6f
commit c7a82c32dc
8 changed files with 34 additions and 26 deletions
+4 -1
View File
@@ -285,7 +285,7 @@ mjModel* LoadModel(const char* file, mj::Simulate& sim) {
// simulate in background thread (while rendering in main thread)
void PhysicsLoop(mj::Simulate& sim) {
// cpu-sim syncronization point
// cpu-sim synchronization point
std::chrono::time_point<mj::Simulate::Clock> syncCPU;
mjtNum syncSim = 0;
@@ -438,6 +438,9 @@ void PhysicsLoop(mj::Simulate& sim) {
else {
// run mj_forward, to update rendering and joint sliders
mj_forward(m, d);
if (sim.pause_update) {
mju_copy(d->qacc_warmstart, d->qacc, m->nv);
}
sim.speed_changed = true;
}
}
+2 -2
View File
@@ -1922,8 +1922,8 @@ void Simulate::Sync(bool state_only) {
return;
}
bool update_profiler = this->profiler && (this->pause_update || this->run);
bool update_sensor = this->sensor && (this->pause_update || this->run);
bool update_profiler = this->profiler;
bool update_sensor = this->sensor;
for (int i = 0; i < m_->njnt; ++i) {
std::optional<std::pair<mjtNum, mjtNum>> range;
+1 -1
View File
@@ -193,7 +193,7 @@ class Simulate {
int info = 0;
int profiler = 0;
int sensor = 0;
int pause_update = 1;
int pause_update = 0;
int fullscreen = 0;
int vsync = 1;
int busywait = 0;