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
@@ -498,6 +498,7 @@ void mjXWriter::OneGeom(XMLElement* elem, const mjCGeom* geom, mjCDef* def, stri
|
||||
WriteAttr(elem, "margin", 1, &geom->margin, &def->Geom().margin);
|
||||
WriteAttr(elem, "gap", 1, &geom->gap, &def->Geom().gap);
|
||||
WriteAttr(elem, "surfacevel", 6, geom->surfacevel, def->Geom().surfacevel, true);
|
||||
WriteAttr(elem, "adhesion", 1, &geom->adhesion, &def->Geom().adhesion);
|
||||
WriteAttrKey(elem, "fluidshape",
|
||||
fluid_map, 2, geom->fluid_ellipsoid, def->Geom().fluid_ellipsoid);
|
||||
WriteAttr(elem, "fluidcoef", 5, geom->fluid_coefs, def->Geom().fluid_coefs);
|
||||
@@ -672,6 +673,7 @@ void mjXWriter::OnePair(XMLElement* elem, const mjCPair* pair, mjCDef* def) {
|
||||
WriteAttrInt(elem, "condim", pair->condim, def->Pair().spec.condim);
|
||||
WriteAttr(elem, "margin", 1, &pair->margin, &def->Pair().spec.margin);
|
||||
WriteAttr(elem, "gap", 1, &pair->gap, &def->Pair().spec.gap);
|
||||
WriteAttr(elem, "adhesion", 1, &pair->adhesion, &def->Pair().spec.adhesion);
|
||||
WriteAttr(elem, "solref", mjNREF, pair->solref, def->Pair().spec.solref, true);
|
||||
WriteAttr(elem, "solreffriction", mjNREF, pair->solreffriction, def->Pair().spec.solreffriction,
|
||||
true);
|
||||
|
||||
Reference in New Issue
Block a user