Add sleep related data structures

PiperOrigin-RevId: 829055431
Change-Id: I1ccbd77a57044a754ae7db611b4c2c0010fbda53
This commit is contained in:
Yuval Tassa
2025-11-06 12:09:59 -08:00
committed by Copybara-Service
parent 3080e3424f
commit 252a0d73df
37 changed files with 1907 additions and 186 deletions
+251 -10
View File
@@ -59,6 +59,230 @@ static void mj_setM0(mjModel* m, mjData* d) {
}
// helper function to get the tree id of a wrap object
static int GetWrapBodyTreeId(const mjModel* m, int wrap_index) {
int bodyid = -1;
int objid = m->wrap_objid[wrap_index];
switch ((mjtWrap)m->wrap_type[wrap_index]) {
case mjWRAP_JOINT:
bodyid = m->jnt_bodyid[objid];
break;
case mjWRAP_SITE:
bodyid = m->site_bodyid[objid];
break;
case mjWRAP_SPHERE:
case mjWRAP_CYLINDER:
bodyid = m->geom_bodyid[objid];
break;
case mjWRAP_PULLEY:
case mjWRAP_NONE:
break;
}
return (bodyid != -1) ? m->body_treeid[bodyid] : -1;
}
// set fixed quantities (do not depend on qpos0)
static void setFixed(mjModel* m, mjData* d) {
mj_markStack(d);
// ----- general
// compute subtreemass
for (int i=0; i < m->nbody; i++) {
m->body_subtreemass[i] = m->body_mass[i];
}
for (int i=m->nbody-1; i > 0; i--) {
m->body_subtreemass[m->body_parentid[i]] += m->body_subtreemass[i];
}
// compute ngravcomp: number of bodies with gravity compensation
int ngravcomp = 0;
for (int i=0; i < m->nbody; i++) {
ngravcomp += (m->body_gravcomp[i] > 0);
}
m->ngravcomp = ngravcomp;
// ----- tree related (body_treeid and dof_treeid already computed)
// compute body_treeid
for (int i=0; i < m->nbody; i++) {
int weldid = m->body_weldid[i];
if (m->body_dofnum[weldid]) {
m->body_treeid[i] = m->dof_treeid[m->body_dofadr[weldid]];
} else {
m->body_treeid[i] = -1;
}
}
// compute tree_bodyadr, tree_bodynum
mju_zeroInt(m->tree_bodynum, m->ntree);
int tree_current = -1;
for (int i=1; i < m->nbody; i++) {
int treeid = m->body_treeid[i];
if (treeid != -1) {
if (treeid > tree_current) {
m->tree_bodyadr[++tree_current] = i;
}
m->tree_bodynum[tree_current]++;
}
}
// compute tree_dofadr, tree_dofnum
mju_zeroInt(m->tree_dofnum, m->ntree);
tree_current = -1;
for (int i=0; i < m->nv; i++) {
if (m->dof_treeid[i] > tree_current) {
m->tree_dofadr[++tree_current] = i;
}
m->tree_dofnum[tree_current]++;
}
// compute tendon_treeid, tendon_treenum
int* tree_marker = mjSTACKALLOC(d, m->ntree, int); // 1 if tree has been visited, 0 otherwise
for (int i = 0; i < m->ntendon; i++) {
mju_zeroInt(tree_marker, m->ntree);
m->tendon_treenum[i] = 0;
m->tendon_treeid[2*i] = -1;
m->tendon_treeid[2*i+1] = -1;
for (int j = m->tendon_adr[i]; j < m->tendon_adr[i] + m->tendon_num[i]; j++) {
int wrap_treeid = GetWrapBodyTreeId(m, j);
if (wrap_treeid != -1 && !tree_marker[wrap_treeid]) {
tree_marker[wrap_treeid] = 1;
if (m->tendon_treenum[i] == 0) {
m->tendon_treeid[2*i] = wrap_treeid;
} else if (m->tendon_treenum[i] == 1) {
m->tendon_treeid[2*i+1] = wrap_treeid;
}
m->tendon_treenum[i]++;
}
}
}
// ----- apply compiler AUTO tree sleep policy
// actuators: trees with any actuated joint, site, body, or tendon do not auto-sleep
for (int i=0; i < m->nu; i++) {
int bodyid = -1;
int tid = m->actuator_trnid[2*i];
switch ((mjtTrn)m->actuator_trntype[i]) {
case mjTRN_JOINT:
case mjTRN_JOINTINPARENT:
bodyid = m->jnt_bodyid[tid];
break;
case mjTRN_SITE:
case mjTRN_SLIDERCRANK:
bodyid = m->site_bodyid[tid];
break;
case mjTRN_BODY:
bodyid = tid;
break;
case mjTRN_TENDON:
// wake all trees connected by this actuated tendon
for (int j = m->tendon_adr[tid]; j < m->tendon_adr[tid] + m->tendon_num[tid]; j++) {
int treeid = GetWrapBodyTreeId(m, j);
if (treeid != -1 && m->tree_sleep_policy[treeid] == mjSLEEP_AUTO) {
m->tree_sleep_policy[treeid] = mjSLEEP_AUTO_NEVER;
}
}
continue; // next actuator
case mjTRN_UNDEFINED:
continue; // next actuator
}
// wake tree containing bodyid, if any
if (bodyid != -1) {
int treeid = m->body_treeid[bodyid];
if (treeid != -1 && m->tree_sleep_policy[treeid] == mjSLEEP_AUTO) {
m->tree_sleep_policy[treeid] = mjSLEEP_AUTO_NEVER;
}
}
}
// trees with inter-tree tendons that have non-zero stiffness or damping do not auto-sleep
// if the tendon spans more than 2 trees.
for (int i=0; i < m->ntendon; i++) {
int treenum = m->tendon_treenum[i];
// tendon spans 1 or 0 trees: skip
if (treenum < 2) {
continue;
}
// tendon spans 2 trees and has no stiffness or damping: skip
if (treenum == 2 && m->tendon_stiffness[i] == 0 && m->tendon_damping[i] == 0) {
continue;
}
// tendon spans two trees with stiffness or damping or more than two trees: wake all trees
mju_zeroInt(tree_marker, m->ntree);
for (int j = m->tendon_adr[i]; j < m->tendon_adr[i] + m->tendon_num[i]; j++) {
int treeid = GetWrapBodyTreeId(m, j);
// if the tree is not yet marked, mark it and wake it up
if (treeid != -1 && !tree_marker[treeid]) {
tree_marker[treeid] = 1;
int policy = m->tree_sleep_policy[treeid];
// mark tree as never sleeping
if (policy == mjSLEEP_AUTO) {
m->tree_sleep_policy[treeid] = mjSLEEP_AUTO_NEVER;
}
// if the user marked it as sleepable, throw an error
else if (policy == mjSLEEP_ALLOWED || policy == mjSLEEP_INIT) {
mj_freeStack(d);
if (treenum > 2) {
mjERROR("tree %d connected to tendon %d which spans more than 2 trees, "
"sleeping not allowed", treeid, i);
} else {
mjERROR("tree %d connected to tendon %d with non-zero stiffness or damping, "
"sleeping not allowed", treeid, i);
}
}
}
}
}
// flexes: trees containing bodies that are part of any flex are not allowed to sleep
for (int i = 0; i < m->nflex; ++i) {
// node-based flex
if (m->flex_interp[i]) {
int nodenum = m->flex_nodenum[i];
int* bodyid = m->flex_nodebodyid + m->flex_nodeadr[i];
for (int j = 0; j < nodenum; ++j) {
int treeid = m->body_treeid[bodyid[j]];
if (treeid != -1 && m->tree_sleep_policy[treeid] == mjSLEEP_AUTO) {
m->tree_sleep_policy[treeid] = mjSLEEP_AUTO_NEVER;
}
}
}
// vertex-based flex
else {
int vertnum = m->flex_vertnum[i];
int* bodyid = m->flex_vertbodyid + m->flex_vertadr[i];
for (int j = 0; j < vertnum; ++j) {
int treeid = m->body_treeid[bodyid[j]];
if (treeid != -1 && m->tree_sleep_policy[treeid] == mjSLEEP_AUTO) {
m->tree_sleep_policy[treeid] = mjSLEEP_AUTO_NEVER;
}
}
}
}
// set remaining trees with mjSLEEP_AUTO policy to mjSLEEP_AUTO_ALLOWED
for (int i = 0; i < m->ntree; i++) {
if (m->tree_sleep_policy[i] == mjSLEEP_AUTO) {
m->tree_sleep_policy[i] = mjSLEEP_AUTO_ALLOWED;
}
}
mj_freeStack(d);
}
// set quantities that depend on qpos0
static void set0(mjModel* m, mjData* d) {
int nv = m->nv;
@@ -429,6 +653,8 @@ static void setStat(mjModel* m, mjData* d) {
mjtNum xmax[3] = {-1E+10, -1E+10, -1E+10};
mjtNum rbound;
mj_markStack(d);
// approximate length associated with each body
mjtNum* body = mjSTACKALLOC(d, m->nbody, mjtNum);
// compute bounding box of bodies, joint centers, geoms and sites
@@ -528,6 +754,22 @@ static void setStat(mjModel* m, mjData* d) {
}
}
// inherit dof length from parent body
for (int i=0; i < m->nv; i++) {
// default to linear dof, already has length units
m->dof_length[i] = 1;
// if rotational dof, inherit from body
int jnt = m->dof_jntid[i];
mjtJoint type = m->jnt_type[jnt];
int offset = i - m->jnt_dofadr[jnt];
if (type == mjJNT_BALL ||
type == mjJNT_HINGE ||
(type == mjJNT_FREE && offset >= 3)) {
m->dof_length[i] = body[m->dof_bodyid[i]];
}
}
// fix extent if too small compared to meanbody
m->stat.extent = mju_max(m->stat.extent, 2 * m->stat.meansize);
@@ -553,7 +795,7 @@ static void setStat(mjModel* m, mjData* d) {
}
// set quantities that depend on qpos_spring
// set quantities that depend qpos_spring
static void setSpring(mjModel* m, mjData* d) {
// run computations in qpos_spring
mju_copy(d->qpos, m->qpos_spring, m->nq);
@@ -572,19 +814,18 @@ static void setSpring(mjModel* m, mjData* d) {
}
// entry point: set all constant fields of mjModel, except for lengthrange
// entry point: set all remaining constant fields of mjModel, except for lengthrange
void mj_setConst(mjModel* m, mjData* d) {
// compute subtreemass
for (int i=0; i < m->nbody; i++) {
m->body_subtreemass[i] = m->body_mass[i];
}
for (int i=m->nbody-1; i > 0; i--) {
m->body_subtreemass[m->body_parentid[i]] += m->body_subtreemass[i];
}
// set fixed quantities
setFixed(m, d);
// call functions
// set quantities that depend on qpos0
set0(m, d);
// compute statistics
setStat(m, d);
// set quantities that depend qpos_spring
setSpring(m, d);
}