Add mj_geomDistance API function and sensors for geometric distance, normal direction and segment between between two geoms. Fixes #51

PiperOrigin-RevId: 632458301
Change-Id: I65b7e5bb0df59008028114cf4a07e0d6365ff3d3
This commit is contained in:
Yuval Tassa
2024-05-10 04:51:46 -07:00
committed by Copybara-Service
parent 31de1dad9d
commit 02d015458c
29 changed files with 1002 additions and 66 deletions
+26 -4
View File
@@ -57,8 +57,8 @@ Main simulation
These are the main entry points to the simulator. Most users will only need to call :ref:`mj_step`, which computes
everything and advanced the simulation state by one time step. Controls and applied forces must either be set in advance
(in mjData.{ctrl, qfrc_applied, xfrc_applied}), or a control callback :ref:`mjcb_control` must be installed which will be
called just before the controls and applied forces are needed. Alternatively, one can use :ref:`mj_step1` and
(in mjData.{ctrl, qfrc_applied, xfrc_applied}), or a control callback :ref:`mjcb_control` must be installed which will
be called just before the controls and applied forces are needed. Alternatively, one can use :ref:`mj_step1` and
:ref:`mj_step2` which break down the simulation pipeline into computations that are executed before and after the
controls are needed; in this way one can set controls that depend on the results from :ref:`mj_step1`. Keep in mind
though that the RK4 solver does not work with mj_step1/2.
@@ -72,8 +72,8 @@ be set before calling this function. Given the state (qpos, qvel, act), mj_forwa
while mj_inverse maps from acceleration to force. Mathematically these functions are inverse of each other, but
numerically this may not always be the case because the forward dynamics rely on a constraint optimization algorithm
which is usually terminated early. The difference between the results of forward and inverse dynamics can be computed
with the function :ref:`mj_compareFwdInv`, which can be thought of as another solver accuracy check (as well as a general
sanity check).
with the function :ref:`mj_compareFwdInv`, which can be thought of as another solver accuracy check (as well as a
general sanity check).
The skip version of :ref:`mj_forward` and :ref:`mj_inverse` are useful for example when qpos was unchanged but qvel was
changed (usually in the context of finite differencing). Then there is no point repeating the computations that only
@@ -408,6 +408,28 @@ Compute object 6D acceleration (rot:lin) in object-centered frame, world/local o
sensors are not present in the model, :ref:`mj_rnePostConstraint` must be manually called in order to calculate
mjData.cacc -- the total body acceleration, including contributions from the constraint solver.
.. _mj_geomDistance:
mj_geomDistance
~~~~~~~~~~~~~~~
.. mujoco-include:: mj_geomDistance
Returns the smallest signed distance between two geoms and optionally the segment from ``geom1`` to ``geom2``.
Returned distances are bounded from above by ``distmax``. |br| If no collision of distance smaller than ``distmax`` is
found, the function will return ``distmax`` and ``fromto``, if given, will be set to (0, 0, 0, 0, 0, 0).
.. admonition:: Positive ``distmax`` values
:class: note
.. TODO: b/339596989 - Improve mjc_Convex.
For some colliders, a large, positive ``distmax`` will result in an accurate measurement. However, for collision
pairs which use the general ``mjc_Convex`` collider, the result will be approximate and likely innacurate.
This is considered a bug to be fixed in a future release.
In order to determine whether a geom pair uses ``mjc_Convex``, inspect the table at the top of
`engine_collision_driver.c <https://github.com/google-deepmind/mujoco/blob/main/src/engine/engine_collision_driver.c>`__.
.. _mj_contactForce:
mj_contactForce
+21 -4
View File
@@ -33,8 +33,8 @@ The model and all files referenced in it can be loaded from disk or from a VFS w
These are the main entry points to the simulator. Most users will only need to call :ref:`mj_step`, which computes
everything and advanced the simulation state by one time step. Controls and applied forces must either be set in advance
(in mjData.{ctrl, qfrc_applied, xfrc_applied}), or a control callback :ref:`mjcb_control` must be installed which will be
called just before the controls and applied forces are needed. Alternatively, one can use :ref:`mj_step1` and
(in mjData.{ctrl, qfrc_applied, xfrc_applied}), or a control callback :ref:`mjcb_control` must be installed which will
be called just before the controls and applied forces are needed. Alternatively, one can use :ref:`mj_step1` and
:ref:`mj_step2` which break down the simulation pipeline into computations that are executed before and after the
controls are needed; in this way one can set controls that depend on the results from :ref:`mj_step1`. Keep in mind
though that the RK4 solver does not work with mj_step1/2.
@@ -48,8 +48,8 @@ be set before calling this function. Given the state (qpos, qvel, act), mj_forwa
while mj_inverse maps from acceleration to force. Mathematically these functions are inverse of each other, but
numerically this may not always be the case because the forward dynamics rely on a constraint optimization algorithm
which is usually terminated early. The difference between the results of forward and inverse dynamics can be computed
with the function :ref:`mj_compareFwdInv`, which can be thought of as another solver accuracy check (as well as a general
sanity check).
with the function :ref:`mj_compareFwdInv`, which can be thought of as another solver accuracy check (as well as a
general sanity check).
The skip version of :ref:`mj_forward` and :ref:`mj_inverse` are useful for example when qpos was unchanged but qvel was
changed (usually in the context of finite differencing). Then there is no point repeating the computations that only
@@ -180,6 +180,23 @@ generalized velocities to subtree angular momentum. More precisely if :math:`h`
body index ``body`` in ``mjData.subtree_angmom`` (reported by the :ref:`subtreeangmom<sensor-subtreeangmom>` sensor)
and :math:`\dot q` is the generalized velocity ``mjData.qvel``, then :math:`h = H \dot q`.
.. _mj_geomDistance:
Returns the smallest signed distance between two geoms and optionally the segment from ``geom1`` to ``geom2``.
Returned distances are bounded from above by ``distmax``. |br| If no collision of distance smaller than ``distmax`` is
found, the function will return ``distmax`` and ``fromto``, if given, will be set to (0, 0, 0, 0, 0, 0).
.. admonition:: Positive ``distmax`` values
:class: note
.. TODO: b/339596989 - Improve mjc_Convex.
For some colliders, a large, positive ``distmax`` will result in an accurate measurement. However, for collision
pairs which use the general ``mjc_Convex`` collider, the result will be approximate and likely innacurate.
This is considered a bug to be fixed in a future release.
In order to determine whether a geom pair uses ``mjc_Convex``, inspect the table at the top of
`engine_collision_driver.c <https://github.com/google-deepmind/mujoco/blob/main/src/engine/engine_collision_driver.c>`__.
.. _mj_mulM:
This function multiplies the joint-space inertia matrix stored in mjData.qM by a vector. qM has a custom sparse format
+180
View File
@@ -6723,6 +6723,186 @@ The presence of this sensor in a model triggers a call to :ref:`mj_subtreeVel` d
:at:`body`: :at-val:`string, required`
Name of the body where the kinematic subtree is rooted.
.. _collision-sensors:
collision sensors
^^^^^^^^^^^^^^^^^
The following 3 sensor types, :ref:`sensor/distance<sensor-distance>`, :ref:`sensor/normal<sensor-normal>` and
:ref:`sensor/fromto<sensor-fromto>`, respectively measure the distance, normal direction and line segment of the
smallest signed distance between the surfaces of two geoms using the narrow-phase geom-geom colliders. The collision
computation is always performed, independently of the standard collision :ref:`selection and filtering<coSelection>`
pipeline. These 3 sensors share some common properties:
.. _collision-sensors-cutoff:
:at:`cutoff`
For most sensors, the :at:`cutoff` attribute simply defines a clipping operation on sensor values. For collision
sensors, it defines the maximum distance at which collisions will be detected, corresponding to the ``dismax``
argument of :ref:`mj_geomDistance`. For example, at the default value of 0, only negative distances (corresponding
to geom-geom penetration) will be reported by :ref:`sensor/distance<sensor-distance>`.
In order to determine collision properties of non-penetrating geom pairs, a positive :at:`cutoff` is required.
.. admonition:: Positive cutoff values
:class: note
.. TODO: b/339596989 - Improve mjc_Convex.
For some colliders, a positive :at:`cutoff` will result in an accurate measurement. However, for collision
pairs which use the general ``mjc_Convex`` collider, the result will be approximate and likely innacurate.
This is considered a bug to be fixed in a future release.
In order to determine whether a geom pair uses ``mjc_Convex``, inspect the table at the top of
`engine_collision_driver.c <https://github.com/google-deepmind/mujoco/blob/main/src/engine/engine_collision_driver.c>`__.
:at:`geom1`, :at:`geom2`, :at:`body1`, :at:`body2`
For all 3 collision sensor types, the two colliding geoms can be specified explicitly using the :at:`geom1` and
:at:`geom2` attributes or implicitly, using :at:`body1`, :at:`body2`. In the latter case the sensor will iterate over
all geoms of the specified body or bodies (mixed specification like :at:`geom1`, :at:`body2` are allowed), and
select the collision with the smallest signed distance.
sequential sensors
When multiple collision sensors are defined sequentially and have identical attributes (:at:`geom1`, :at:`body1`,
:at:`geom2`, :at:`body2`, :at:`cutoff`), for example when both distance and normal are queried for the same geom
pair, the collision functions will be called once for the whole sensor block, avoiding repeated computation.
.. _sensor-distance:
:el-prefix:`sensor/` |-| **distance** (*)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This element creates a sensor that returns the smallest signed distance between the surfaces of two geoms.
See :ref:`collision-sensors` for more details about sensors of this type.
.. _sensor-distance-cutoff:
:at:`cutoff`
See :ref:`collision-sensors` for the sematics of this attribute, which is different than for other sensor catagories.
If no collision is detected, the distance sensor returns the :at:`cutoff` value, so in this case
:at:`cutoff` acts as a maximum clipping value, in addition to the special semantics.
.. _sensor-distance-geom1:
:at:`geom1`: :at-val:`string, optional`
Name of the first geom. Exactly one of (:at:`geom1`, :at:`body1`) must be specified.
.. _sensor-distance-geom2:
:at:`geom2`: :at-val:`string, optional`
Name of the second geom. Exactly one of (:at:`geom2`, :at:`body2`) must be specified.
.. _sensor-distance-body1:
:at:`body1`: :at-val:`string, optional`
Name of the first body. Exactly one of (:at:`geom1`, :at:`body1`) must be specified.
.. _sensor-distance-body2:
:at:`body2`: :at-val:`string, optional`
Name of the second body. Exactly one of (:at:`geom2`, :at:`body2`) must be specified.
.. _sensor-distance-name:
.. _sensor-distance-noise:
.. _sensor-distance-user:
:at:`name`, :at:`noise`, :at:`user`
See :ref:`CSensor`.
.. _sensor-normal:
:el-prefix:`sensor/` |-| **normal** (*)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This element creates a sensor that returns the normal direction of the smallest signed distance between the surfaces of
two geoms. It is guaranteed to point from the surface of geom1 to the surface of geom2, though note that in the case of
penetration, this direction is generally in the opposite direction to that of the centroids.
See :ref:`collision-sensors` for more details about sensors of this type.
.. _sensor-normal-cutoff:
:at:`cutoff`
See :ref:`collision-sensors` for the sematics of this attribute, which is different than for other sensor catagories.
If no collision is detected, the :ref:`normal<sensor-normal>` sensor returns (0, 0, 0), otherwise it returns a
normalized direction vector. For this sensor, :at:`cutoff` does not lead to any clamping.
.. _sensor-normal-geom1:
:at:`geom1`: :at-val:`string, optional`
Name of the first geom. Exactly one of (:at:`geom1`, :at:`body1`) must be specified.
.. _sensor-normal-geom2:
:at:`geom2`: :at-val:`string, optional`
Name of the second geom. Exactly one of (:at:`geom2`, :at:`body2`) must be specified.
.. _sensor-normal-body1:
:at:`body1`: :at-val:`string, optional`
Name of the first body. Exactly one of (:at:`geom1`, :at:`body1`) must be specified.
.. _sensor-normal-body2:
:at:`body2`: :at-val:`string, optional`
Name of the second body. Exactly one of (:at:`geom2`, :at:`body2`) must be specified.
.. _sensor-normal-name:
.. _sensor-normal-noise:
.. _sensor-normal-user:
:at:`name`, :at:`noise`, :at:`user`
See :ref:`CSensor`.
.. _sensor-fromto:
:el-prefix:`sensor/` |-| **fromto** (*)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This element creates a sensor that returns the segment defining the smallest signed distance between the surfaces of two
geoms. The segment is defined by 6 numbers (x1, y1, z1, x2, y2, z2) corresponding to two points in the world frame.
(x1, y1, z1) is on the surface of geom1, (x2, y2, z2) is on the surface of geom2. When this sensor is present and the
:ref:`mjVIS_RANGEFINDER<mjtVisFlag>` visualization flag is set, segments will be visualized as rangefinder rays.
See :ref:`collision-sensors` for more details about sensors of this type.
.. _sensor-fromto-cutoff:
:at:`cutoff`
See :ref:`collision-sensors` for the sematics of this attribute, which is different than for other sensor catagories.
If no collision is detected, the :ref:`fromto<sensor-fromto>` sensor returns 6 zeros.
For this sensor, :at:`cutoff` does not lead to any clamping.
.. _sensor-fromto-geom1:
:at:`geom1`: :at-val:`string, optional`
Name of the first geom. Exactly one of (:at:`geom1`, :at:`body1`) must be specified.
.. _sensor-fromto-geom2:
:at:`geom2`: :at-val:`string, optional`
Name of the second geom. Exactly one of (:at:`geom2`, :at:`body2`) must be specified.
.. _sensor-fromto-body1:
:at:`body1`: :at-val:`string, optional`
Name of the first body. Exactly one of (:at:`geom1`, :at:`body1`) must be specified.
.. _sensor-fromto-body2:
:at:`body2`: :at-val:`string, optional`
Name of the second body. Exactly one of (:at:`geom2`, :at:`body2`) must be specified.
.. _sensor-fromto-name:
.. _sensor-fromto-noise:
.. _sensor-fromto-user:
:at:`name`, :at:`noise`, :at:`user`
See :ref:`CSensor`.
.. _sensor-clock:
+27
View File
@@ -1163,6 +1163,33 @@
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |_| sensor |br| |_| |L| | | .. table:: |
| :ref:`distance | \* | :class: mjcf-attributes |
| <sensor-distance>` | | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`name<sensor-distance-name>` | :ref:`geom1<sensor-distance-geom1>` | :ref:`geom2<sensor-distance-geom2>` | :ref:`body1<sensor-distance-body1>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`body2<sensor-distance-body2>` | :ref:`cutoff<sensor-distance-cutoff>` | :ref:`noise<sensor-distance-noise>` | :ref:`user<sensor-distance-user>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |_| sensor |br| |_| |L| | | .. table:: |
| :ref:`normal | \* | :class: mjcf-attributes |
| <sensor-normal>` | | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`name<sensor-normal-name>` | :ref:`geom1<sensor-normal-geom1>` | :ref:`geom2<sensor-normal-geom2>` | :ref:`body1<sensor-normal-body1>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`body2<sensor-normal-body2>` | :ref:`cutoff<sensor-normal-cutoff>` | :ref:`noise<sensor-normal-noise>` | :ref:`user<sensor-normal-user>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |_| sensor |br| |_| |L| | | .. table:: |
| :ref:`fromto | \* | :class: mjcf-attributes |
| <sensor-fromto>` | | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`name<sensor-fromto-name>` | :ref:`geom1<sensor-fromto-geom1>` | :ref:`geom2<sensor-fromto-geom2>` | :ref:`body1<sensor-fromto-body1>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`body2<sensor-fromto-body2>` | :ref:`cutoff<sensor-fromto-cutoff>` | :ref:`noise<sensor-fromto-noise>` | :ref:`user<sensor-fromto-user>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |_| sensor |br| |_| |L| | | .. table:: |
| :ref:`clock | \* | :class: mjcf-attributes |
| <sensor-clock>` | | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+9 -2
View File
@@ -5,12 +5,19 @@ Changelog
Upcoming version (not yet released)
-----------------------------------
General
^^^^^^^
1. Added :ref:`mj_geomDistance` for computing the shortest signed distance between two geoms and optionally a segment
connecting them. Relatedly, added the 3 sensors: :ref:`distance<sensor-distance>`, :ref:`normal<sensor-normal>`,
:ref:`fromto<sensor-fromto>`. See the function and sensor documentation for details. Fixes :github:issue:`51`.
Bug fixes
^^^^^^^^^
1. Fixed a bug the could cause collisions to be missed when :ref:`fusestatic<compiler-fusestatic>` is enabled, as is
2. Fixed a bug the could cause collisions to be missed when :ref:`fusestatic<compiler-fusestatic>` is enabled, as is
often the case for URDF imports. Fixes :github:issue:`1069`, :github:issue:`1577`.
2. Fixed a bug that was causing the visualization of SDF iterations to write outside the size of the vector storing
3. Fixed a bug that was causing the visualization of SDF iterations to write outside the size of the vector storing
them. Fixes :github:issue:`1539`.
Version 3.1.5 (May 7, 2024)
+7
View File
@@ -643,6 +643,11 @@ typedef enum mjtSensor_ { // type of sensor
mjSENS_SUBTREELINVEL, // 3D linear velocity of subtree
mjSENS_SUBTREEANGMOM, // 3D angular momentum of subtree
// sensors for geometric distance; attached to geoms or bodies
mjSENS_GEOMDIST, // signed distance between two geoms
mjSENS_GEOMNORMAL, // normal direction between two geoms
mjSENS_GEOMFROMTO, // segment between two geoms
// global sensors
mjSENS_CLOCK, // simulation time
@@ -2542,6 +2547,8 @@ void mj_objectVelocity(const mjModel* m, const mjData* d,
int objtype, int objid, mjtNum res[6], int flg_local);
void mj_objectAcceleration(const mjModel* m, const mjData* d,
int objtype, int objid, mjtNum res[6], int flg_local);
mjtNum mj_geomDistance(const mjModel* m, const mjData* d, int geom1, int geom2,
mjtNum distmax, mjtNum fromto[6]);
void mj_contactForce(const mjModel* m, const mjData* d, int id, mjtNum result[6]);
void mj_differentiatePos(const mjModel* m, mjtNum* qvel, mjtNum dt,
const mjtNum* qpos1, const mjtNum* qpos2);