Change tactile sensor normal component to report penetration depth.
The normal component of the tactile sensor now reports the maximum penetration depth at each taxel, instead of a derived normal force. The depth is negated so that positive values indicate penetration. PiperOrigin-RevId: 921980899 Change-Id: Ide4103c0aff465e25a81cfdda650f6a0e2da9e0b
This commit is contained in:
committed by
Copybara-Service
parent
583aa5ad4f
commit
f6cd0234fd
@@ -8514,15 +8514,14 @@ Extraction
|
||||
:width: 30%
|
||||
:target: https://github.com/google-deepmind/mujoco/blob/main/model/tactile/tactile.xml
|
||||
|
||||
The tactile sensor returns the penetration pressure and the sliding velocities in the tangent frame at given points
|
||||
between the geom associated with the sensor and the SDF geoms in contact with it. We define the penetration pressure as
|
||||
a function of the penetration depth :math:`p(d) = \frac{d}{d_{max}-d}`, which is zero at the surface and goes to
|
||||
infinity as the maximum depth is reached. The sensor is associated with a geom and a mesh. It is activated by the
|
||||
contact between its associated geom and other geoms. The vertices of the mesh, when positioned in the geom frame, are
|
||||
the points at which sensor values are computed, so the dimension of the output is 3 times the number of vertices in the
|
||||
mesh. The mesh must have 3 normal vectors per vertex, which are used to compute the tangent frame. If the penetration
|
||||
depth is positive (no contact), then all values are 0 for the corresponding vertex. Only contacts with geoms of type SDF
|
||||
contribute to the sensor output. The sensor can be visualized by enabling the visualization of contact points.
|
||||
The tactile sensor returns the maximum penetration depth and the sliding velocities in the tangent frame at given points
|
||||
between the geom associated with the sensor and the SDF geoms in contact with it. The sensor is associated with a geom
|
||||
and a mesh. It is activated by the contact between its associated geom and other geoms. The vertices of the mesh, when
|
||||
positioned in the geom frame, are the points at which sensor values are computed, so the dimension of the output is 3
|
||||
times the number of vertices in the mesh. The mesh must have 3 normal vectors per vertex, which are used to compute the
|
||||
tangent frame. If the penetration depth is positive (no contact), then all values are 0 for the corresponding vertex.
|
||||
Only contacts with geoms of type SDF contribute to the sensor output. The sensor can be visualized by enabling the
|
||||
visualization of contact points.
|
||||
|
||||
.. _sensor-tactile-geom:
|
||||
|
||||
|
||||
@@ -79,6 +79,8 @@ General
|
||||
`mjtype.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjtype.h>` and now includes all
|
||||
enum type definitions.
|
||||
|
||||
- The :ref:`tactile<sensor-tactile>` sensor now reports raw depth instead of an estimated pressure.
|
||||
|
||||
- MJX: Removed the deprecated ``nconmax`` argument from ``mjx.make_data`` and ``mjx.put_data`` in favor of
|
||||
``naconmax``.
|
||||
|
||||
|
||||
+2
-6
@@ -2252,18 +2252,14 @@ def _sensor_tactile(
|
||||
)
|
||||
vel_rel = vel_sensor - vel_other
|
||||
|
||||
kMaxDepth = 0.05
|
||||
pressure = depth / wp.max(kMaxDepth - depth, MJ_MINVAL)
|
||||
force = wp.mul(normal, pressure)
|
||||
|
||||
forceT = wp.vec3(0.0, 0.0, 0.0)
|
||||
forceT[0] = wp.dot(force, normal)
|
||||
forceT[0] = -depth
|
||||
if has_frame:
|
||||
forceT[1] = wp.abs(wp.dot(vel_rel, tang1))
|
||||
forceT[2] = wp.abs(wp.dot(vel_rel, tang2))
|
||||
|
||||
dim = sensor_dim[sensor_id] // 3
|
||||
wp.atomic_add(sensordata_out, worldid, sensor_adr[sensor_id] + 0 * dim + vertid, forceT[0])
|
||||
wp.atomic_max(sensordata_out, worldid, sensor_adr[sensor_id] + 0 * dim + vertid, forceT[0])
|
||||
wp.atomic_add(sensordata_out, worldid, sensor_adr[sensor_id] + 1 * dim + vertid, forceT[1])
|
||||
wp.atomic_add(sensordata_out, worldid, sensor_adr[sensor_id] + 2 * dim + vertid, forceT[2])
|
||||
|
||||
|
||||
@@ -172,14 +172,8 @@ static void* tactile_taxel_batch(void* args) {
|
||||
mesh_normal[normal_stride*j + 2]};
|
||||
mju_rotVecQuat(normal, normal, m->mesh_quat + 4 * mesh_id);
|
||||
|
||||
// get contact force
|
||||
mjtNum force[3];
|
||||
mjtNum kMaxDepth = 0.05;
|
||||
mjtNum pressure = depth / mju_max(kMaxDepth - depth, mjMINVAL);
|
||||
mju_scl3(force, normal, pressure);
|
||||
|
||||
// accumulate into forcesT (disjoint writes per taxel j)
|
||||
t->forcesT[0*ncon + j] += mju_dot3(force, normal);
|
||||
// take max penetration depth (SDF distance is negative; negate for positive output)
|
||||
t->forcesT[0*ncon + j] = mju_max(t->forcesT[0*ncon + j], -depth);
|
||||
|
||||
if (has_frame) {
|
||||
mjtNum tang1[3] = {mesh_normal[normal_stride*j + 3],
|
||||
|
||||
@@ -1702,7 +1702,7 @@ TEST_F(SensorTest, TactileSkipTangents) {
|
||||
EXPECT_EQ(data->time, 0.0);
|
||||
EXPECT_GT(data->ncon, 0) << "No contacts generated";
|
||||
|
||||
// Tactile sensor layout: [normal_forces..., tang1_forces..., tang2_forces...]
|
||||
// Tactile sensor layout: [depths..., tang1_vel..., tang2_vel...]
|
||||
int ntaxel = model->nsensordata / 3;
|
||||
ASSERT_EQ(model->nsensordata % 3, 0) << "Sensor dim should be divisible by 3";
|
||||
|
||||
@@ -1712,13 +1712,13 @@ TEST_F(SensorTest, TactileSkipTangents) {
|
||||
<< "Tangent component at index " << i << " should be 0";
|
||||
}
|
||||
|
||||
// Normal force components: verify count, sign, and magnitude ~-0.8
|
||||
// Penetration depth components: verify count, sign, and magnitude ~0.2
|
||||
int nonzero_count = 0;
|
||||
for (int i = 0; i < ntaxel; i++) {
|
||||
if (data->sensordata[i] != 0) {
|
||||
nonzero_count++;
|
||||
EXPECT_NEAR(data->sensordata[i], -0.8, 0.1)
|
||||
<< "Normal force at taxel " << i;
|
||||
EXPECT_NEAR(data->sensordata[i], 0.2, 0.1)
|
||||
<< "Penetration depth at taxel " << i;
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(nonzero_count, 2) << "Expected 2 taxels in contact";
|
||||
|
||||
Reference in New Issue
Block a user