Merge pull request #3466 from smallquail:flex-implicit-contact
PiperOrigin-RevId: 960804180 Change-Id: Ic3eb203ca0d9cf19c9043b46127db342678d94f9
This commit is contained in:
@@ -2549,11 +2549,22 @@ static int mj_nc(const mjModel* m, mjData* d, int* nnz) {
|
||||
for (int i=0; i < ncon; i++) {
|
||||
mjContact* con = d->contact + i;
|
||||
|
||||
// skip if passive
|
||||
if ((con->flex[0] > -1 && m->flex_passive[con->flex[0]]) ||
|
||||
(con->flex[1] > -1 && m->flex_passive[con->flex[1]])) {
|
||||
con->efc_address = -1;
|
||||
con->exclude = 4;
|
||||
// Passive path: flex-flex (including self-collision) and flex-vs-static-geometry, where every
|
||||
// dof is a metric-carried flex vertex so the Hessian is assembled in full. Flex-vs-moving-body
|
||||
// stays on the constraint solver. Passive if either flex asks for it.
|
||||
{
|
||||
int f0 = con->flex[0], f1 = con->flex[1];
|
||||
int wants = (f0 > -1 && m->flex_passive[f0]) || (f1 > -1 && m->flex_passive[f1]);
|
||||
int ok = (f0 > -1 && f1 > -1); // flex-flex, or a flex with itself
|
||||
for (int s = 0; s < 2 && !ok; s++) {
|
||||
if (con->flex[s] < 0 && con->geom[s] > -1) {
|
||||
ok = (m->body_weldid[m->geom_bodyid[con->geom[s]]] == 0); // welded to the world
|
||||
}
|
||||
}
|
||||
if (wants && ok) {
|
||||
con->efc_address = -1;
|
||||
con->exclude = 4;
|
||||
}
|
||||
}
|
||||
|
||||
// skip if excluded
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <mujoco/mjdata.h>
|
||||
#include <mujoco/mjmodel.h>
|
||||
#include <mujoco/mjsan.h> // IWYU pragma: keep
|
||||
#include "engine/engine_core_constraint.h"
|
||||
#include "engine/engine_core_smooth.h"
|
||||
#include "engine/engine_core_util.h"
|
||||
#include "engine/engine_crossplatform.h"
|
||||
@@ -1630,6 +1631,58 @@ mjtBool mjd_flexInterpAssemblable(const mjModel* m) {
|
||||
// does ANY flex contribute assemblable implicit stiffness? (cheap existence check for the
|
||||
// solver gate: stretch stiffness on a standard flex, or -- when Krot will be supplied -- an
|
||||
// operator-processed interp flex)
|
||||
// does any flex use the passive contact path? Distinct from elasticity: an empty CSR is valid for
|
||||
// elastic models (matrix-free operators) but means "nothing" for a contact-only flex.
|
||||
static mjtBool flexPassiveContact_any(const mjModel* m) {
|
||||
for (int f = 0; f < m->nflex; f++) {
|
||||
if (!m->flex_interp[f] && !m->flex_rigid[f] && m->flex_dim[f] >= 2 && m->flex_passive[f]) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// res += scale * K_contact * vec, where K_contact = sum_c k_c * J_c^T J_c over passive flex
|
||||
// contacts. Any class that contributes to K must also contribute to the shift -h*K*v (see
|
||||
// mjd_effShift), otherwise the contact is stiff but undamped.
|
||||
void mjd_flexContact_mul(const mjModel* m, mjData* d, mjtNum* res, const mjtNum* vec,
|
||||
mjtNum scale) {
|
||||
if (!d->ncon) {
|
||||
return;
|
||||
}
|
||||
int nv = m->nv;
|
||||
mj_markStack(d);
|
||||
mjtNum* jacdif = mjSTACKALLOC(d, 3*nv, mjtNum);
|
||||
mjtNum* jac1 = mjSTACKALLOC(d, 3*nv, mjtNum);
|
||||
mjtNum* jac2 = mjSTACKALLOC(d, 3*nv, mjtNum);
|
||||
mjtNum* jacn = mjSTACKALLOC(d, 3*nv, mjtNum);
|
||||
int* chain = mjSTACKALLOC(d, nv, int);
|
||||
for (int i = 0; i < d->ncon; i++) {
|
||||
const mjContact* con = d->contact + i;
|
||||
if (con->exclude != 4) {
|
||||
continue;
|
||||
}
|
||||
mjtNum k = mjd_flexContactStiffness(m, d, con);
|
||||
if (k <= 0) {
|
||||
continue;
|
||||
}
|
||||
int NV = mj_contactJacobian(m, d, con, con->dim, jacdif, NULL, jac1, jac2, NULL, NULL, chain);
|
||||
if (!NV) {
|
||||
continue;
|
||||
}
|
||||
mju_mulMatMat(jacn, con->frame, jacdif, con->dim > 1 ? 3 : 1, 3, NV);
|
||||
mjtNum Jv = 0;
|
||||
for (int a = 0; a < NV; a++) {
|
||||
Jv += jacn[a] * vec[chain[a]];
|
||||
}
|
||||
mjtNum s = scale * k * Jv;
|
||||
for (int a = 0; a < NV; a++) {
|
||||
res[chain[a]] += s * jacn[a];
|
||||
}
|
||||
}
|
||||
mj_freeStack(d);
|
||||
}
|
||||
|
||||
mjtBool mjd_flexStiff_any(const mjModel* m, int flg_interp) {
|
||||
for (int f = 0; f < m->nflex; f++) {
|
||||
if (flg_interp && flexInterp_processed(m, f)) {
|
||||
@@ -1645,6 +1698,11 @@ mjtBool mjd_flexStiff_any(const mjModel* m, int flg_interp) {
|
||||
|
||||
|
||||
// does this standard flex contribute implicit stiffness under the given term flags?
|
||||
// A flex participates if it has elasticity OR passive contacts: the contact stiffness may be the
|
||||
// only stiffness, so vertex slots must exist either way.
|
||||
static mjtBool flexMetric_participates(const mjModel* m, int f, int flg_bend, int flg_stretch,
|
||||
int flg_contact);
|
||||
|
||||
static mjtBool flexStiff_active(const mjModel* m, int f, int flg_bend, int flg_stretch) {
|
||||
if (m->flex_interp[f] || m->flex_rigid[f] || m->flex_dim[f] < 2) {
|
||||
return 0;
|
||||
@@ -1655,6 +1713,88 @@ static mjtBool flexStiff_active(const mjModel* m, int f, int flg_bend, int flg_s
|
||||
return bend || stretch;
|
||||
}
|
||||
|
||||
// Passive contact stiffness: k = omega^2 * m_min, a natural frequency scaled by the smallest
|
||||
// nonzero participating mass (pinned vertices carry mass 0 and are skipped).
|
||||
#define mjFLEXCONTACT_OMEGA2 5e7
|
||||
|
||||
mjtNum mjd_flexContactStiffness(const mjModel* m, const mjData* d, const mjContact* con) {
|
||||
mjtNum mmin = 0;
|
||||
for (int side = 0; side < 2; side++) {
|
||||
int f = con->flex[side];
|
||||
if (f < 0) {
|
||||
continue;
|
||||
}
|
||||
int gv[8], ngv = 0;
|
||||
if (con->vert[side] >= 0) {
|
||||
gv[ngv++] = m->flex_vertadr[f] + con->vert[side];
|
||||
} else if (con->elem[side] >= 0) {
|
||||
int nvrt = m->flex_dim[f] + 1;
|
||||
const int* e = m->flex_elem + m->flex_elemdataadr[f] + nvrt*con->elem[side];
|
||||
for (int j = 0; j < nvrt && ngv < 8; j++) {
|
||||
gv[ngv++] = m->flex_vertadr[f] + e[j];
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < ngv; j++) {
|
||||
int b = m->flex_vertbodyid[gv[j]];
|
||||
if (m->body_dofnum[b] != 3) {
|
||||
continue;
|
||||
}
|
||||
int da = m->body_dofadr[b];
|
||||
mjtNum mv = d->M[m->M_rowadr[da] + m->M_rownnz[da] - 1]; // diagonal: the point mass
|
||||
if (mv > 0 && (mmin == 0 || mv < mmin)) {
|
||||
mmin = mv;
|
||||
}
|
||||
}
|
||||
}
|
||||
return mjFLEXCONTACT_OMEGA2 * mmin; // 0 if every participant is massless: no stiffness, no NaN
|
||||
}
|
||||
|
||||
// The flex vertex slots a passive contact couples: the vertex itself for a vertex side, the
|
||||
// element's vertices for an element side. Duplicates dropped, and slots outside the metric skipped.
|
||||
static int contactFlexSlots(const mjModel* m, const mjContact* con, const int* vslot,
|
||||
int* out, int cap) {
|
||||
int n = 0;
|
||||
for (int side = 0; side < 2; side++) {
|
||||
int f = con->flex[side];
|
||||
if (f < 0) {
|
||||
continue;
|
||||
}
|
||||
int gv[8], ngv = 0;
|
||||
if (con->vert[side] >= 0) {
|
||||
gv[ngv++] = m->flex_vertadr[f] + con->vert[side];
|
||||
} else if (con->elem[side] >= 0) {
|
||||
int nvrt = m->flex_dim[f] + 1;
|
||||
const int* e = m->flex_elem + m->flex_elemdataadr[f] + nvrt*con->elem[side];
|
||||
for (int j = 0; j < nvrt && ngv < 8; j++) {
|
||||
gv[ngv++] = m->flex_vertadr[f] + e[j];
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < ngv; j++) {
|
||||
int s = vslot[gv[j]];
|
||||
if (s < 0) {
|
||||
continue;
|
||||
}
|
||||
int dup = 0;
|
||||
for (int q = 0; q < n; q++) {
|
||||
if (out[q] == s) { dup = 1; break; }
|
||||
}
|
||||
if (!dup && n < cap) {
|
||||
out[n++] = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static mjtBool flexMetric_participates(const mjModel* m, int f, int flg_bend, int flg_stretch,
|
||||
int flg_contact) {
|
||||
if (flexStiff_active(m, f, flg_bend, flg_stretch)) {
|
||||
return 1;
|
||||
}
|
||||
return flg_contact && m->flex_passive[f] && !m->flex_rigid[f] && !m->flex_interp[f] &&
|
||||
m->flex_dim[f] >= 2;
|
||||
}
|
||||
|
||||
|
||||
// assemble the standard-flex implicit stiffness K = (s1 + s2*damping) * (K_bend + K_stretch)
|
||||
// into dof-level CSR (same terms mjd_flexBend_mul / mjd_flexStretch_mul apply matrix-free; the
|
||||
@@ -1669,7 +1809,7 @@ static mjtBool flexStiff_active(const mjModel* m, int f, int flg_bend, int flg_s
|
||||
// so one CSR replaces all three matrix-free operators uniformly.
|
||||
int mjd_flexStiff_assemble(const mjModel* m, mjData* d, int* rownnz, int* rowadr,
|
||||
int* colind, mjtNum* val, mjtNum s1, mjtNum s2,
|
||||
int flg_bend, int flg_stretch, const mjtNum* Krot) {
|
||||
int flg_bend, int flg_stretch, int flg_contact, const mjtNum* Krot) {
|
||||
int nv = m->nv;
|
||||
mj_markStack(d);
|
||||
|
||||
@@ -1680,7 +1820,7 @@ int mjd_flexStiff_assemble(const mjModel* m, mjData* d, int* rownnz, int* rowadr
|
||||
vslot[i] = -1;
|
||||
}
|
||||
for (int f = 0; f < m->nflex; f++) {
|
||||
if (!flexStiff_active(m, f, flg_bend, flg_stretch)) {
|
||||
if (!flexMetric_participates(m, f, flg_bend, flg_stretch, flg_contact)) {
|
||||
continue;
|
||||
}
|
||||
for (int lv = 0; lv < m->flex_vertnum[f]; lv++) {
|
||||
@@ -1777,6 +1917,20 @@ int mjd_flexStiff_assemble(const mjModel* m, mjData* d, int* rownnz, int* rowadr
|
||||
}
|
||||
}
|
||||
|
||||
// passive contacts (counting): each contact makes its vertices mutual neighbours in the CSR.
|
||||
if (flg_contact) {
|
||||
for (int i = 0; i < d->ncon; i++) {
|
||||
const mjContact* con = d->contact + i;
|
||||
if (con->exclude != 4) {
|
||||
continue;
|
||||
}
|
||||
int cs[8], ncs = contactFlexSlots(m, con, vslot, cs, 8);
|
||||
for (int a = 0; a < ncs; a++) {
|
||||
ncand[cs[a]] += ncs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// gather candidate neighbor lists (vertex slots, with duplicates)
|
||||
int* cadr = mjSTACKALLOC(d, nvert + 1, int);
|
||||
cadr[0] = 0;
|
||||
@@ -1842,6 +1996,22 @@ int mjd_flexStiff_assemble(const mjModel* m, mjData* d, int* rownnz, int* rowadr
|
||||
}
|
||||
}
|
||||
|
||||
// passive contacts (filling)
|
||||
if (flg_contact) {
|
||||
for (int i = 0; i < d->ncon; i++) {
|
||||
const mjContact* con = d->contact + i;
|
||||
if (con->exclude != 4) {
|
||||
continue;
|
||||
}
|
||||
int cs[8], ncs = contactFlexSlots(m, con, vslot, cs, 8);
|
||||
for (int a = 0; a < ncs; a++) {
|
||||
for (int b = 0; b < ncs; b++) {
|
||||
cand[cadr[cs[a]] + ncand[cs[a]]++] = cs[b];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// per vertex: sort by neighbor dofadr, unique -> neighbor lists
|
||||
int* nadr = mjSTACKALLOC(d, nvert + 1, int);
|
||||
int* neigh = mjSTACKALLOC(d, cadr[nvert] > 0 ? cadr[nvert] : 1, int);
|
||||
@@ -2103,6 +2273,69 @@ int mjd_flexStiff_assemble(const mjModel* m, mjData* d, int* rownnz, int* rowadr
|
||||
})
|
||||
}
|
||||
}
|
||||
// passive contacts (values): assemble k*J^T*J blocks, where J is the contact-normal Jacobian.
|
||||
// All participants are metric-carried flex vertices, so the block is assembled in full.
|
||||
if (flg_contact && d->ncon) {
|
||||
int* dof2slot = mjSTACKALLOC(d, nv, int);
|
||||
mjtNum* jacdif = mjSTACKALLOC(d, 3*nv, mjtNum);
|
||||
mjtNum* jac1 = mjSTACKALLOC(d, 3*nv, mjtNum);
|
||||
mjtNum* jac2 = mjSTACKALLOC(d, 3*nv, mjtNum);
|
||||
mjtNum* jacn = mjSTACKALLOC(d, 3*nv, mjtNum);
|
||||
int* chain = mjSTACKALLOC(d, nv, int);
|
||||
mjtNum* w = mjSTACKALLOC(d, 3*(nvert > 0 ? nvert : 1), mjtNum);
|
||||
for (int i = 0; i < nv; i++) {
|
||||
dof2slot[i] = -1;
|
||||
}
|
||||
for (int s = 0; s < nvert; s++) {
|
||||
for (int k = 0; k < 3; k++) {
|
||||
dof2slot[vdof[s] + k] = s;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < d->ncon; i++) {
|
||||
const mjContact* con = d->contact + i;
|
||||
if (con->exclude != 4) {
|
||||
continue;
|
||||
}
|
||||
int cs[8], ncs = contactFlexSlots(m, con, vslot, cs, 8);
|
||||
if (ncs < 1) {
|
||||
continue;
|
||||
}
|
||||
mjtNum k = mjd_flexContactStiffness(m, d, con);
|
||||
if (k <= 0) {
|
||||
continue;
|
||||
}
|
||||
int NV = mj_contactJacobian(m, d, con, con->dim, jacdif, NULL, jac1, jac2, NULL, NULL, chain);
|
||||
if (NV == 0) {
|
||||
continue;
|
||||
}
|
||||
// rotate into the contact frame and keep the normal row
|
||||
mju_mulMatMat(jacn, con->frame, jacdif, con->dim > 1 ? 3 : 1, 3, NV);
|
||||
for (int a = 0; a < ncs; a++) {
|
||||
mju_zero(w + 3*cs[a], 3);
|
||||
}
|
||||
for (int a = 0; a < NV; a++) {
|
||||
int s = dof2slot[chain[a]];
|
||||
if (s >= 0) {
|
||||
w[3*s + (chain[a] - vdof[s])] = jacn[a];
|
||||
}
|
||||
}
|
||||
for (int a = 0; a < ncs; a++) {
|
||||
for (int b = 0; b < ncs; b++) {
|
||||
int pos;
|
||||
FLEXSTIFF_BLOCK(cs[a], cs[b], pos);
|
||||
if (pos < 0) {
|
||||
continue;
|
||||
}
|
||||
for (int r = 0; r < 3; r++) {
|
||||
for (int c = 0; c < 3; c++) {
|
||||
val[rowadr[vdof[cs[a]] + r] + 3*pos + c] += s1 * k * w[3*cs[a] + r] * w[3*cs[b] + c];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef FLEXSTIFF_BLOCK
|
||||
#undef FLEXINTERP_WALK
|
||||
|
||||
@@ -3166,6 +3399,7 @@ void mjd_effShift(const mjModel* m, mjData* d) {
|
||||
mjd_flexInterp_mul(m, d, d->efm_c, d->qvel, h, 0, d->flexelem_krot);
|
||||
mjd_flexBend_mul(m, d, d->efm_c, d->qvel, -h, 0);
|
||||
mjd_flexStretch_mul(m, d, d->efm_c, d->qvel, -h, 0);
|
||||
mjd_flexContact_mul(m, d, d->efm_c, d->qvel, -h);
|
||||
}
|
||||
|
||||
|
||||
@@ -3197,16 +3431,17 @@ void mjd_effBuild(const mjModel* m, mjData* d, int active, int flg_factor) {
|
||||
const mjtNum* krot = mjd_flexInterpAssemblable(m) ? d->flexelem_krot : NULL;
|
||||
d->efm_K_rownnz = EFMALLOC(int, nv);
|
||||
d->efm_K_rowadr = EFMALLOC(int, nv);
|
||||
if (mjd_flexStiff_any(m, krot != NULL)) {
|
||||
if (mjd_flexStiff_any(m, krot != NULL) || flexPassiveContact_any(m)) {
|
||||
d->nefmK = mjd_flexStiff_assemble(m, d, d->efm_K_rownnz, d->efm_K_rowadr,
|
||||
NULL, NULL, h*h, h, /*bend*/ 1, /*stretch*/ 1, krot);
|
||||
NULL, NULL, h*h, h, /*bend*/ 1, /*stretch*/ 1,
|
||||
/*contact*/ 1, krot);
|
||||
}
|
||||
if (d->nefmK) {
|
||||
d->efm_K_colind = EFMALLOC(int, d->nefmK);
|
||||
d->efm_K_val = EFMALLOC(mjtNum, d->nefmK);
|
||||
mjd_flexStiff_assemble(m, d, d->efm_K_rownnz, d->efm_K_rowadr,
|
||||
d->efm_K_colind, d->efm_K_val, h*h, h,
|
||||
/*bend*/ 1, /*stretch*/ 1, krot);
|
||||
/*bend*/ 1, /*stretch*/ 1, /*contact*/ 1, krot);
|
||||
// per-step factor of the flex block of (M + K): the stiffness is constant during the
|
||||
// step, so one factorization here turns every preconditioner application into a direct
|
||||
// solve (the stiff flex block stops being iterated on). Consumers that only multiply
|
||||
@@ -3219,6 +3454,7 @@ void mjd_effBuild(const mjModel* m, mjData* d, int active, int flg_factor) {
|
||||
mju_zeroInt(d->efm_K_rownnz, nv);
|
||||
mju_zeroInt(d->efm_K_rowadr, nv);
|
||||
}
|
||||
|
||||
d->efm_active = 1;
|
||||
|
||||
// fill the shift with the current velocity (refreshed again in the velocity stage)
|
||||
|
||||
@@ -77,9 +77,16 @@ MJAPI void mjd_flexStretch_mul(const mjModel* m, mjData* d, mjtNum* res, const m
|
||||
// dof-level CSR; phase 1 (colind==NULL) fills rownnz/rowadr and returns total nnz, phase 2
|
||||
// fills colind/val. Interp flexes are assembled iff Krot (mjd_flexInterp_cacheKrot cache) is
|
||||
// non-NULL and the centered fast path applies (check mjd_flexInterpAssemblable first).
|
||||
// Passive contact stiffness (omega^2 * m_min); force and Hessian must use the same value.
|
||||
// res += scale * K_contact * vec (shift counterpart of the contact stiffness in the metric).
|
||||
MJAPI void mjd_flexContact_mul(const mjModel* m, mjData* d, mjtNum* res, const mjtNum* vec,
|
||||
mjtNum scale);
|
||||
|
||||
MJAPI mjtNum mjd_flexContactStiffness(const mjModel* m, const mjData* d, const mjContact* con);
|
||||
|
||||
MJAPI int mjd_flexStiff_assemble(const mjModel* m, mjData* d, int* rownnz, int* rowadr,
|
||||
int* colind, mjtNum* val, mjtNum s1, mjtNum s2,
|
||||
int flg_bend, int flg_stretch, const mjtNum* Krot);
|
||||
int flg_bend, int flg_stretch, int flg_contact, const mjtNum* Krot);
|
||||
|
||||
// can all interp flexes be assembled to dof-level CSR? (centered fast path everywhere)
|
||||
MJAPI mjtBool mjd_flexInterpAssemblable(const mjModel* m);
|
||||
|
||||
@@ -1591,6 +1591,16 @@ void mj_RungeKutta(const mjModel* m, mjData* d, int N) {
|
||||
|
||||
|
||||
// return 1 if any flex needs implicit stiffness treatment (interp or bending)
|
||||
// return 1 if any non-rigid flex uses passive contacts (needs the metric independently of elasticity)
|
||||
static mjtBool flex_has_passive_contact(const mjModel* m) {
|
||||
for (int f=0; f < m->nflex; f++) {
|
||||
if (!m->flex_rigid[f] && m->flex_passive[f]) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static mjtBool flex_has_implicit_stiffness(const mjModel* m) {
|
||||
for (int f=0; f < m->nflex; f++) {
|
||||
if (m->flex_rigid[f]) {
|
||||
@@ -1634,7 +1644,7 @@ int mj_flexCG(const mjModel* m) {
|
||||
return m->opt.solver == mjSOL_CG &&
|
||||
(m->opt.integrator == mjINT_IMPLICIT || m->opt.integrator == mjINT_IMPLICITFAST) &&
|
||||
m->opt.cone != mjCONE_ELLIPTIC && !mjENABLED(mjENBL_SLEEP) &&
|
||||
flex_has_implicit_stiffness(m);
|
||||
(flex_has_implicit_stiffness(m) || flex_has_passive_contact(m));
|
||||
}
|
||||
|
||||
|
||||
@@ -1776,6 +1786,12 @@ void mj_implicit(const mjModel* m, mjData* d) {
|
||||
void mj_forwardSkip(const mjModel* m, mjData* d, int skipstage, int skipsensor) {
|
||||
TM_START;
|
||||
|
||||
// Passive flex contact is too stiff for explicit integration; require the effective metric.
|
||||
if (flex_has_passive_contact(m) && !mj_flexCG(m)) {
|
||||
mjERROR("passive flex contact requires the effective metric: use integrator=\"implicit\" or "
|
||||
"\"implicitfast\" with solver=\"CG\", pyramidal cones and sleep disabled");
|
||||
}
|
||||
|
||||
// position-dependent
|
||||
if (skipstage < mjSTAGE_POS) {
|
||||
mj_fwdPosition(m, d);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "engine/engine_callback.h"
|
||||
#include "engine/engine_core_constraint.h"
|
||||
#include "engine/engine_core_util.h"
|
||||
#include "engine/engine_derivative.h"
|
||||
#include "engine/engine_crossplatform.h"
|
||||
#include "engine/engine_inline.h"
|
||||
#include "engine/engine_memory.h"
|
||||
@@ -36,8 +37,6 @@
|
||||
|
||||
//----------------------------- passive forces -----------------------------------------------------
|
||||
|
||||
// stiffness for passive contacts
|
||||
static const mjtNum kContactStiffness = 1e4;
|
||||
|
||||
// local edge-based vertex indexing for 2D and 3D elements, 2D and 3D elements
|
||||
// have 3 and 6 edges, respectively so the missing indexes are set to 0
|
||||
@@ -962,8 +961,8 @@ int mj_contactPassive(const mjModel* m, mjData* d) {
|
||||
// rotate Jacobian differences to contact frame
|
||||
mju_mulMatMat(jac, con->frame, jacdifp, dim > 1 ? 3 : 1, 3, NV);
|
||||
|
||||
// compute passive contact force (dim = 1)
|
||||
mjtNum scl = -kContactStiffness*con->dist;
|
||||
// compute passive contact force (dim = 1); stiffness shared with the metric Hessian.
|
||||
mjtNum scl = -mjd_flexContactStiffness(m, d, con)*con->dist;
|
||||
if (!issparse) {
|
||||
mju_addToScl(d->qfrc_spring, jac, scl, nv);
|
||||
} else {
|
||||
|
||||
@@ -1416,10 +1416,11 @@ static void setEfm0Factor(mjModel* m, mjData* d) {
|
||||
int* K_rownnz = mjSTACKALLOC(d, nv, int);
|
||||
int* K_rowadr = mjSTACKALLOC(d, nv, int);
|
||||
int nK = mjd_flexStiff_assemble(m, d, K_rownnz, K_rowadr, NULL, NULL, h*h, h,
|
||||
/*flg_bend=*/1, /*flg_stretch=*/0, NULL);
|
||||
/*flg_bend=*/1, /*flg_stretch=*/0, /*flg_contact=*/0,
|
||||
NULL);
|
||||
int* K_colind = mjSTACKALLOC(d, nK > 0 ? nK : 1, int);
|
||||
mjtNum* K_val = mjSTACKALLOC(d, nK > 0 ? nK : 1, mjtNum);
|
||||
mjd_flexStiff_assemble(m, d, K_rownnz, K_rowadr, K_colind, K_val, h*h, h, 1, 0, NULL);
|
||||
mjd_flexStiff_assemble(m, d, K_rownnz, K_rowadr, K_colind, K_val, h*h, h, 1, 0, 0, NULL);
|
||||
|
||||
// inverse map: dof address -> compact factor row (monotone: slots follow dof order)
|
||||
int* dofrow = mjSTACKALLOC(d, nv, int);
|
||||
|
||||
Reference in New Issue
Block a user