Add actuator and sensor delays. Fixes #1004

PiperOrigin-RevId: 866478839
Change-Id: Id21a6da0f98454c8fa39ea5af8a5e213d6eae497
This commit is contained in:
Yuval Tassa
2026-02-06 08:46:45 -08:00
committed by Copybara-Service
parent 84fa527723
commit 6419534bad
48 changed files with 6282 additions and 219 deletions
+113 -1
View File
@@ -132,6 +132,7 @@ static inline int mj_stateElemSize(const mjModel* m, mjtState sig) {
case mjSTATE_QPOS: return m->nq;
case mjSTATE_QVEL: return m->nv;
case mjSTATE_ACT: return m->na;
case mjSTATE_HISTORY: return m->nhistory;
case mjSTATE_WARMSTART: return m->nv;
case mjSTATE_CTRL: return m->nu;
case mjSTATE_QFRC_APPLIED: return m->nv;
@@ -155,6 +156,7 @@ static inline mjtNum* mj_stateElemPtr(const mjModel* m, mjData* d, mjtState sig)
case mjSTATE_QPOS: return d->qpos;
case mjSTATE_QVEL: return d->qvel;
case mjSTATE_ACT: return d->act;
case mjSTATE_HISTORY: return d->history;
case mjSTATE_WARMSTART: return d->qacc_warmstart;
case mjSTATE_CTRL: return d->ctrl;
case mjSTATE_QFRC_APPLIED: return d->qfrc_applied;
@@ -619,7 +621,7 @@ void mj_differentiatePos(const mjModel* m, mjtNum* qvel, mjtNum dt,
vadr += 3;
padr += 3;
// continute with rotations
// continue with rotations
mjFALLTHROUGH;
case mjJNT_BALL:
@@ -806,3 +808,113 @@ void mju_camIntrinsics(const mjModel* m, int camid,
// extent only used for orthographic cameras
*extent = m->cam_fovy[camid];
}
// read delayed ctrl value for actuator at given time
mjtNum mj_readCtrl(const mjModel* m, const mjData* d, int id, mjtNum time, int interp) {
// validate actuator id
if (id < 0 || id >= m->nu) {
mjERROR("invalid actuator id %d", id);
return 0;
}
// no delay: return current ctrl value
int nsample = m->actuator_history[2*id];
if (nsample == 0) {
return d->ctrl[id];
}
// resolve interpolation order: use model's interp if argument is -1
if (interp < 0) interp = m->actuator_history[2*id+1];
// get buffer pointer and read from history buffer
mjtNum delay = m->actuator_delay[id];
const mjtNum* buf = d->history + m->actuator_historyadr[id];
mjtNum res;
const mjtNum* ptr = mju_delayRead(buf, nsample, /*dim=*/1, &res, time - delay, interp);
return ptr ? *ptr : res;
}
// read sensor value from history buffer at given time
const mjtNum* mj_readSensor(const mjModel* m, const mjData* d, int id, mjtNum time,
mjtNum* result, int interp) {
// validate sensor id
if (id < 0 || id >= m->nsensor) {
mjERROR("invalid sensor id %d", id);
return NULL;
}
// no history: return current sensor value
int nsample = m->sensor_history[2*id];
if (nsample == 0) {
return d->sensordata + m->sensor_adr[id];
}
// resolve interpolation order: use model's interp if argument is -1
if (interp < 0) interp = m->sensor_history[2*id+1];
// get buffer pointer and read from history buffer
int dim = m->sensor_dim[id];
mjtNum delay = m->sensor_delay[id];
const mjtNum* buf = d->history + m->sensor_historyadr[id];
return mju_delayRead(buf, nsample, dim, result, time - delay, interp);
}
// initialize history buffer for actuator
void mj_initCtrlHistory(const mjModel* m, mjData* d, int id,
const mjtNum* times, const mjtNum* values) {
// validate actuator id
if (id < 0 || id >= m->nu) {
mjERROR("invalid actuator id %d", id);
return;
}
// check that actuator has a history buffer
int nsample = m->actuator_history[2*id];
if (nsample == 0) {
mjERROR("actuator %d has no history buffer", id);
return;
}
// get buffer pointer
mjtNum* buf = d->history + m->actuator_historyadr[id];
// if times is NULL, use existing buffer times
const mjtNum* buf_times = times ? times : buf + 2;
// get existing user value (preserve it)
mjtNum user = buf[0];
// initialize history buffer
mju_delayInit(buf, nsample, 1, buf_times, values, user);
}
// initialize history buffer for sensor
void mj_initSensorHistory(const mjModel* m, mjData* d, int id,
const mjtNum* times, const mjtNum* values, mjtNum phase) {
// validate sensor id
if (id < 0 || id >= m->nsensor) {
mjERROR("invalid sensor id %d", id);
return;
}
// check that sensor has a history buffer
int nsample = m->sensor_history[2*id];
if (nsample == 0) {
mjERROR("sensor %d has no history buffer", id);
return;
}
// get buffer pointer and dimension
mjtNum* buf = d->history + m->sensor_historyadr[id];
int dim = m->sensor_dim[id];
// if times is NULL, use existing buffer times
const mjtNum* buf_times = times ? times : buf + 2;
// initialize history buffer with provided phase
mju_delayInit(buf, nsample, dim, buf_times, values, phase);
}