Add geom adhesion: contacts that pull, via translated friction cones.
https://youtu.be/GioWwB36XHI The new geom attribute adhesion (units of force, signed; pair-level override) translates the contact friction cone along its normal so that the force origin lies strictly inside it. Consequences: each contact can pull with up to the given force before breaking, and the tangential friction budget becomes mu*(f_N + adhesion) -- the Mohr-Coulomb yield condition with cohesion c = mu*adhesion -- so lightly-squeezed grasps retain a guaranteed friction floor. A translated cone factors exactly into {constant attractive force} + {original cone}, so no solver kernels change. The implementation is this factorization: a constant attraction along contact normals accumulated into the new mjData.qfrc_adhesion (summed into qfrc_passive), plus a bias of adhesive contact rows' reference acceleration (aref += R*adhesion), which makes resting penetration exactly independent of adhesion. Contacts of adhesive pairs remain active throughout the gap zone, producing rows with positive violation whose reference acceleration pulls: a tether that resists pull-off smoothly, captures objects released within the band into steady contact, and detaches at the specified force. Adhesion values of the two geoms combine by sum; explicit pairs override. mj_contactForce reports the net interface force (cone force minus the adhesive pull), whose normal component can now be negative. Negative adhesion is allowed and produces a repulsive offset (air hockey). PiperOrigin-RevId: 950858148 Change-Id: I879c08eba7ae501e5c0f8c2f807167344da4c2bc
This commit is contained in:
committed by
Copybara-Service
parent
b942c9f922
commit
a264d0bc8b
@@ -3063,6 +3063,7 @@ void mjCModel::CopyTree(mjModel* m) {
|
||||
m->geom_margin[gid] = (mjtNum)pg->margin;
|
||||
m->geom_gap[gid] = (mjtNum)pg->gap;
|
||||
mjuu_copyvec(m->geom_surfacevel+6*gid, pg->surfacevel, 6);
|
||||
m->geom_adhesion[gid] = (mjtNum)pg->adhesion;
|
||||
mjuu_copyvec(m->geom_fluid+mjNFLUID*gid, pg->fluid, mjNFLUID);
|
||||
mjuu_copyvec(m->geom_user+nuser_geom*gid, pg->get_userdata().data(), nuser_geom);
|
||||
mjuu_copyvec(m->geom_rgba+4*gid, pg->rgba, 4);
|
||||
@@ -3927,6 +3928,7 @@ void mjCModel::CopyObjects(mjModel* m) {
|
||||
mjuu_copyvec(m->pair_solimp+mjNIMP*i, pairs_[i]->solimp, mjNIMP);
|
||||
m->pair_margin[i] = (mjtNum)pairs_[i]->margin;
|
||||
m->pair_gap[i] = (mjtNum)pairs_[i]->gap;
|
||||
m->pair_adhesion[i] = (mjtNum)pairs_[i]->adhesion;
|
||||
mjuu_copyvec(m->pair_friction+5*i, pairs_[i]->friction, 5);
|
||||
}
|
||||
|
||||
@@ -5843,6 +5845,7 @@ bool mjCModel::CopyBack(const mjModel* m) {
|
||||
pg->margin = (double)m->geom_margin[i];
|
||||
pg->gap = (double)m->geom_gap[i];
|
||||
mjuu_copyvec(pg->surfacevel, m->geom_surfacevel+6*i, 6);
|
||||
pg->adhesion = (double)m->geom_adhesion[i];
|
||||
|
||||
if (nuser_geom) {
|
||||
mjuu_copyvec(pg->userdata_.data(), m->geom_user + nuser_geom*i, nuser_geom);
|
||||
@@ -5926,6 +5929,7 @@ bool mjCModel::CopyBack(const mjModel* m) {
|
||||
mjuu_copyvec(pairs_[i]->solimp, m->pair_solimp+mjNIMP*i, mjNIMP);
|
||||
pairs_[i]->margin = (double)m->pair_margin[i];
|
||||
pairs_[i]->gap = (double)m->pair_gap[i];
|
||||
pairs_[i]->adhesion = (double)m->pair_adhesion[i];
|
||||
mjuu_copyvec(pairs_[i]->friction, m->pair_friction+5*i, 5);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user