Add support for excluded contacts in adhesion actuators.

- Update example model.
- Update video.

PiperOrigin-RevId: 468464196
Change-Id: I603c5a89c2d5a736de127440e6d542beffc12583
This commit is contained in:
Yuval Tassa
2022-08-18 08:27:42 -07:00
committed by Copybara-Service
parent 4bfc2c0311
commit 833dc74074
4 changed files with 111 additions and 50 deletions
+16 -11
View File
@@ -3409,7 +3409,8 @@ helps clarify the role of bodies and geoms in MuJoCo.
assumption of uniform density. The internal default of 1000 is the density of water in SI units. This attribute is assumption of uniform density. The internal default of 1000 is the density of water in SI units. This attribute is
used only when the mass attribute above is unspecified. used only when the mass attribute above is unspecified.
:at:`shellinertia` :at-val:`[false, true], "false"` :at:`shellinertia` :at-val:`[false, true], "false"`
If true, the geom's inertia is computed assuming that all the mass is concentrated on the boundary. In this case :at:`density` is interpreted as surface density rather than volumetric density. If true, the geom's inertia is computed assuming that all the mass is concentrated on the boundary. In this case
:at:`density` is interpreted as surface density rather than volumetric density.
:at:`solmix`: :at-val:`real, "1"` :at:`solmix`: :at-val:`real, "1"`
This attribute specifies the weight used for averaging of contact parameters, and interacts with the priority This attribute specifies the weight used for averaging of contact parameters, and interacts with the priority
attribute. See :ref:`CContact`. attribute. See :ref:`CContact`.
@@ -4616,18 +4617,22 @@ This element has nine custom attributes in addition to the common attributes:
:el-prefix:`actuator/` **adhesion** (*) :el-prefix:`actuator/` **adhesion** (*)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. youtube:: HdBue4MUZys .. youtube:: BcHZ5BFeTmU
:align: right :align: right
:height: 200px :height: 150px
This element defines an active adhesion actuator which injects force at contacts in the normal direction. On the right This element defines an active adhesion actuator which injects forces at contacts in the normal direction, see
is a video demonstrating this actuator type. The model shown in the video can be found `here illustration video. The model shown in the video can be found `here
<https://github.com/deepmind/mujoco/tree/main/model/adhesion>`_. The transmission target is a :el:`body`, and adhesive <https://github.com/deepmind/mujoco/tree/main/model/adhesion>`_ and includes inline annotations. The transmission target
forces are injected into all contacts involving geoms which belong to this body. The force is divided equally between is a :el:`body`, and adhesive forces are injected into all contacts involving geoms which belong to this body. The force
multiple active contacts. Because it requires contact, it cannot apply a force at a distance, and is more like the active is divided equally between multiple contacts. When the :at:`gap` attribute is not used, this actuator requires active
adhesion on the feet of geckos and insects rather than an industrial vacuum gripper. Adhesion actuators' length is contacts and cannot apply a force at a distance, more like the active adhesion on the feet of geckos and insects rather
always 0. :at:`ctrlrange` is required and must also be nonnegative (no repulsive forces are allowed). The underlying than an industrial vacuum gripper. In order to enable "suction at a distance", "inflate" the body's geoms by
:el:`general` attributes are set as follows: :at:`margin` and add a corresponding :at:`gap` which activates contacts only after :at:`gap` penetration distance. This
will create a layer around the geom where contacts are detected but are inactive, and can be used for
applying the adhesive force. In the video above, such inactive contacts are blue, while active contacts are orange.
An adhesion actuator's length is always 0. :at:`ctrlrange` is required and must also be nonnegative (no repulsive forces
are allowed). The underlying :el:`general` attributes are set as follows:
=========== ======= =========== ======== =========== ======= =========== ========
Attribute Setting Attribute Setting Attribute Setting Attribute Setting
+10 -5
View File
@@ -7,15 +7,20 @@ Upcoming version (not yet released)
General General
^^^^^^^ ^^^^^^^
.. youtube:: BcHZ5BFeTmU
:align: right
:height: 150px
- Added :ref:`adhesion actuators<adhesion>`. - Added :ref:`adhesion actuators<adhesion>`.
- Added an `active adhesion example model <https://github.com/deepmind/mujoco/tree/main/model/adhesion>`_. - Added an `active adhesion example <https://github.com/deepmind/mujoco/tree/main/model/adhesion>`_ and video:
- Added :ref:`mj_jacSubtreeCom` for computing the translational Jacobian of the center-of-mass of a subtree. - Added :ref:`mj_jacSubtreeCom` for computing the translational Jacobian of the center-of-mass of a subtree.
- Added moment of inertia computation for concave meshes. This is currently activated by setting the compiler flag - Added moment of inertia computation for concave meshes. This is currently activated by setting the compiler flag
:at:`exactmeshinertia` to ``true`` (defaults to ``false``). This default may change in the future. :at:`exactmeshinertia` to ``true`` (defaults to ``false``). This default may change in the future.
- Added parameter :at:`shellinertia` in :at:`geom` for treating a mesh as a boundary mesh (shell) for inertia - Added parameter :at:`shellinertia` to :at:`geom`, for locating the inferred inertia on the boundary (shell).
computations. This is currently supported only for meshes. Currently only meshes are supported.
- Raise error if the orientation of mesh faces is not consistent, which causes the inertia computations to be - For meshes from which volumetric inertia is inferred, raise error if the orientation of mesh faces is not consistent.
inaccurate. If this occurs, open the mesh in MeshLab or Blender and recalculate the faces. If this occurs, fix the mesh in e.g., MeshLab or Blender.
- Added ``azimuth`` and ``elevation`` attributes to :ref:`visual/global<global>`, defining the initial orientation of - Added ``azimuth`` and ``elevation`` attributes to :ref:`visual/global<global>`, defining the initial orientation of
the free camera at model load time. the free camera at model load time.
- Added ``mjv_defaultFreeCamera`` which sets the default free camera, respecting the above attributes. - Added ``mjv_defaultFreeCamera`` which sets the default free camera, respecting the above attributes.
+17 -16
View File
@@ -1,4 +1,8 @@
<mujoco model="Active adhesion example"> <mujoco model="Active adhesion example">
<!--
Adding some fluid viscosity to prevent the hanging sphere from jiggling too much.
-->
<option viscosity="1"/>
<size nconmax="500" njmax="1000"/> <size nconmax="500" njmax="1000"/>
@@ -8,12 +12,7 @@
<default> <default>
<joint damping=".3" axis="0 1 0"/> <joint damping=".3" axis="0 1 0"/>
<!-- <geom type="box" friction=".5"/>
By adding 3mm of margin yet making solimp barely apply any force until 3mm penetration, we get
3mm of "action at a distance". This is important so that small changes in distance don't lead
to loss of adhesion
-->
<geom type="box" friction=".5" margin=".003" solimp="0 .99 .003 .9 6"/>
<default class="wall"> <default class="wall">
<geom rgba=".5 .5 .5 .4"/> <geom rgba=".5 .5 .5 .4"/>
</default> </default>
@@ -22,7 +21,12 @@
<tendon rgba=".5 .5 .8 1"/> <tendon rgba=".5 .5 .8 1"/>
</default> </default>
<default class="active_adhesion"> <default class="active_adhesion">
<geom rgba=".8 .5 .5 1"/> <!--
Geoms in the active_adhesion class are "inflated" with a margin of 1cm, but contacts are
activated only at a depth gap of 1cm, leading to a layer of inactive contacts at a 1cm
distance from the surface. However the contacts can be used by the adhesion actuator.
-->
<geom rgba=".8 .5 .5 1" margin=".01" gap=".01"/>
</default> </default>
<default class="object"> <default class="object">
<geom rgba=".5 .8 .5 1" density="100"/> <geom rgba=".5 .8 .5 1" density="100"/>
@@ -77,18 +81,15 @@
<site name="hook_left" pos=".08 0 .3"/> <site name="hook_left" pos=".08 0 .3"/>
<site name="hook_right" pos=".12 0 .3"/> <site name="hook_right" pos=".12 0 .3"/>
<body name="sphere" pos=".1 0 .2" childclass="active_adhesion"> <body name="sphere" pos=".1 0 .2" childclass="active_adhesion">
<!-- <freejoint/>
Note we are adding damping to a free joint. This is an easy yet unphysical way to prevent
the sphere from jiggling too much on the winch tendons. An alternative would be to add fluid
density or viscosity.
-->
<joint type="free" damping=".1"/>
<!-- <!--
The composite balls in the crate have only 3 linear DoFs with condim=1, effectively The composite balls in the crate have only 3 linear DoFs with condim=1, effectively
frictionless point particles. In order to make them stick to the sphere we give the sphere frictionless point particles. In order to make them stick to the sphere we give the sphere
priority 2, to force condim=3. priority 2, to force condim=3.
Also note the sphere has a margin+gap of 3cm as opposed to the 1cm of the arm box.
--> -->
<geom type="sphere" size=".03" priority="2"/> <geom type="sphere" size=".03" priority="2" margin=".03" gap=".03"/>
<site name="pin_left" pos="-.025 0 .025"/> <site name="pin_left" pos="-.025 0 .025"/>
<site name="pin_right" pos=".025 0 .025"/> <site name="pin_right" pos=".025 0 .025"/>
</body> </body>
@@ -127,9 +128,9 @@
<actuator> <actuator>
<position name="conveyor" joint="conveyor" ctrlrange="-.2 .2" ctrllimited="true" kp="400"/> <position name="conveyor" joint="conveyor" ctrlrange="-.2 .2" ctrllimited="true" kp="400"/>
<position name="arm" joint="arm2" ctrlrange="-.8 1" ctrllimited="true" kp="10"/> <position name="arm" joint="arm2" ctrlrange="-.8 1" ctrllimited="true" kp="10"/>
<adhesion name="adhere_arm" body="4boxes" ctrlrange="0 1" gain="20"/> <adhesion name="adhere_arm" body="4boxes" ctrlrange="0 1" gain="5"/>
<position name="winch" joint="winch" ctrlrange="-.7 .5" ctrllimited="true" kp="10"/> <position name="winch" joint="winch" ctrlrange="-.7 .5" ctrllimited="true" kp="10"/>
<adhesion name="adhere_winch" body="sphere" ctrlrange="0 1" gain="20"/> <adhesion name="adhere_winch" body="sphere" ctrlrange="0 1" gain="5"/>
</actuator> </actuator>
<sensor> <sensor>
+68 -18
View File
@@ -626,6 +626,12 @@ void mj_transmission(const mjModel* m, mjData* d) {
jacS = mj_stackAlloc(d, 3*nv); jacS = mj_stackAlloc(d, 3*nv);
mju_zero(moment, nu*nv); mju_zero(moment, nu*nv);
// define variables required for body transmission, don't allocate
int issparse = mj_isSparse(m);
mjtNum* efc_force = NULL; // used as marker for allocation requirement
mjtNum *moment_exclude, *jacdifp, *jac1p, *jac2p;
int *chain;
// compute lengths and moments // compute lengths and moments
for (int i=0; i<nu; i++) { for (int i=0; i<nu; i++) {
// extract info // extract info
@@ -791,37 +797,81 @@ void mj_transmission(const mjModel* m, mjData* d) {
// moment is average of all contact normal Jacobians // moment is average of all contact normal Jacobians
{ {
// find and count all relevant contacts, mark them in efc_force // allocate stack variables for the first mjTRN_BODY
int counter = 0; if (!efc_force) {
mjtNum* efc_force = mj_stackAlloc(d, d->nefc); efc_force = mj_stackAlloc(d, d->nefc);
moment_exclude = mj_stackAlloc(d, nv);
jacdifp = mj_stackAlloc(d, 3*nv);
jac1p = mj_stackAlloc(d, 3*nv);
jac2p = mj_stackAlloc(d, 3*nv);
chain = issparse ? (int*)mj_stackAlloc(d, nv) : NULL;
}
// clear efc_force and moment_exclude
mju_zero(efc_force, d->nefc); mju_zero(efc_force, d->nefc);
mju_zero(moment_exclude, nv);
// count all relevant contacts, accumulate Jacobians
int counter = 0;
for (int j=0; j<d->ncon; j++) { for (int j=0; j<d->ncon; j++) {
const mjContact* con = d->contact+j; const mjContact* con = d->contact+j;
if (m->geom_bodyid[con->geom1]==id || m->geom_bodyid[con->geom2]==id) { int b1 = m->geom_bodyid[con->geom1];
if (!con->exclude) { int b2 = m->geom_bodyid[con->geom2];
counter++;
// condim 1 or elliptic cones: normal is in the first row // irrelevant contact, continue
if (con->dim == 1 || m->opt.cone==mjCONE_ELLIPTIC) { if (b1 != id && b2 != id) {
efc_force[con->efc_address] = 1; continue;
} }
// pyramidal cones: average all pyramid directions // mark contact normals in efc_force
else { if (!con->exclude) {
int npyramid = con->dim-1; // number of frictional directions counter++;
for (int k=0; k<2*npyramid; k++) {
efc_force[con->efc_address+k] = 0.5/npyramid; // condim 1 or elliptic cones: normal is in the first row
} if (con->dim == 1 || m->opt.cone==mjCONE_ELLIPTIC) {
efc_force[con->efc_address] = 1;
}
// pyramidal cones: average all pyramid directions
else {
int npyramid = con->dim-1; // number of frictional directions
for (int k=0; k<2*npyramid; k++) {
efc_force[con->efc_address+k] = 0.5/npyramid;
} }
} else if (con->exclude == 1) { }
// TODO(b/240848298): compute Jacobians for excluded contact (in gap) }
// excluded contact, get sparse or dense Jacobian, accumulate
else if (con->exclude == 1) {
counter++;
// get Jacobian difference
int NV = mj_jacDifPair(m, d, chain, b1, b2, con->pos, con->pos,
jac1p, jac2p, jacdifp, NULL, NULL, NULL);
// project Jacobian along the normal of the contact frame
mju_mulMatMat(jac, con->frame, jacdifp, 1, 3, NV);
// accumulate in moment_exclude
if (issparse) {
for (int k=0; k<NV; k++) {
moment_exclude[chain[k]] += jac[k];
}
} else {
mju_addTo(moment_exclude, jac, nv);
} }
} }
} }
// moment is average over contact normal Jacobians, make negative for adhesion // moment is average over contact normal Jacobians, make negative for adhesion
if (counter) { if (counter) {
// accumulate active contact Jacobians into moment
mj_mulJacTVec(m, d, moment+i*nv, efc_force); mj_mulJacTVec(m, d, moment+i*nv, efc_force);
// add Jacobians from excluded contacts
mju_addTo(moment+i*nv, moment_exclude, nv);
// normalize by total contacts, flip sign
mju_scl(moment+i*nv, moment+i*nv, -1.0/counter, nv); mju_scl(moment+i*nv, moment+i*nv, -1.0/counter, nv);
} }
} }