Skip to content

Commit c56b887

Browse files
authored
contact sensor maxforce reduction (#602)
* contact sensor maxforce reduction * update test_contact_sensor * update test_contact_sensor * update test_contact_sensor to test fewer contact sensor instances
1 parent 382eb65 commit c56b887

File tree

4 files changed

+55
-24
lines changed

4 files changed

+55
-24
lines changed

mujoco_warp/_src/io.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,8 @@ def put_model(mjm: mujoco.MjModel) -> types.Model:
129129
raise NotImplementedError("Contact sensor: only geom1-geom2 matching is implemented.")
130130

131131
# reduction
132-
if (mjm.sensor_intprm[is_contact_sensor, 1] != 1).any():
133-
raise NotImplementedError(f"Contact sensor: only mindist reduction is implemented.")
132+
if (~((mjm.sensor_intprm[is_contact_sensor, 1] == 1) | (mjm.sensor_intprm[is_contact_sensor, 1] == 2))).any():
133+
raise NotImplementedError(f"Contact sensor: only mindist and maxforce reduction are implemented.")
134134

135135
# TODO(team): remove after _update_gradient for Newton uses tile operations for islands
136136
nv_max = 60

mujoco_warp/_src/io_test.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,6 @@ def test_make_put_data_dims_match(self, xml):
366366
'<contact geom1="plane"/>',
367367
'<contact geom2="plane"/>',
368368
'<contact site="site"/>',
369-
'<contact reduce="maxforce"/>',
370369
'<contact reduce="netforce"/>',
371370
'<contact geom1="plane" geom2="sphere"/>',
372371
)

mujoco_warp/_src/sensor.py

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1986,14 +1986,22 @@ def _sensor_tactile(
19861986
@wp.kernel
19871987
def _contact_match(
19881988
# Model:
1989+
opt_cone: int,
19891990
sensor_objid: wp.array(dtype=int),
19901991
sensor_refid: wp.array(dtype=int),
1992+
sensor_intprm: wp.array2d(dtype=int),
19911993
sensor_contact_adr: wp.array(dtype=int),
19921994
# Data in:
1995+
njmax_in: int,
19931996
ncon_in: wp.array(dtype=int),
19941997
contact_dist_in: wp.array(dtype=float),
1998+
contact_frame_in: wp.array(dtype=wp.mat33),
1999+
contact_friction_in: wp.array(dtype=vec5),
2000+
contact_dim_in: wp.array(dtype=int),
19952001
contact_geom_in: wp.array(dtype=wp.vec2i),
2002+
contact_efc_address_in: wp.array2d(dtype=int),
19962003
contact_worldid_in: wp.array(dtype=int),
2004+
efc_force_in: wp.array2d(dtype=float),
19972005
# Data out:
19982006
sensor_contact_nmatch_out: wp.array2d(dtype=int),
19992007
sensor_contact_matchid_out: wp.array3d(dtype=int),
@@ -2009,6 +2017,7 @@ def _contact_match(
20092017
# sensor information
20102018
objid = sensor_objid[sensorid]
20112019
refid = sensor_refid[sensorid]
2020+
reduce = sensor_intprm[sensorid, 1]
20122021

20132022
# contact information
20142023
geom = contact_geom_in[contactid]
@@ -2022,8 +2031,27 @@ def _contact_match(
20222031
contactmatchid = wp.atomic_add(sensor_contact_nmatch_out[worldid], contactsensorid, 1)
20232032
sensor_contact_matchid_out[worldid, contactsensorid, contactmatchid] = contactid
20242033

2025-
# TODO(thowell): alternative criteria
2026-
sensor_contact_criteria_out[worldid, contactsensorid, contactmatchid] = contact_dist_in[contactid]
2034+
if reduce == 1: # mindist
2035+
sensor_contact_criteria_out[worldid, contactsensorid, contactmatchid] = contact_dist_in[contactid]
2036+
elif reduce == 2: # maxforce
2037+
contact_force = support.contact_force_fn(
2038+
opt_cone,
2039+
njmax_in,
2040+
ncon_in,
2041+
contact_frame_in,
2042+
contact_friction_in,
2043+
contact_dim_in,
2044+
contact_efc_address_in,
2045+
efc_force_in,
2046+
worldid,
2047+
contactid,
2048+
False,
2049+
)
2050+
force_magnitude = (
2051+
contact_force[0] * contact_force[0] + contact_force[1] * contact_force[1] + contact_force[2] * contact_force[2]
2052+
)
2053+
sensor_contact_criteria_out[worldid, contactsensorid, contactmatchid] = -force_magnitude
2054+
# TODO(thowell): netforce
20272055

20282056
# contact direction
20292057
if geom1geom0:
@@ -2155,20 +2183,28 @@ def sensor_acc(m: Model, d: Data):
21552183
if m.sensor_contact_adr.size:
21562184
# match criteria
21572185
d.sensor_contact_nmatch.zero_()
2158-
d.sensor_contact_matchid.zero_()
2159-
d.sensor_contact_criteria.zero_()
2186+
d.sensor_contact_matchid.fill_(-1)
2187+
d.sensor_contact_criteria.fill_(1.0e32)
21602188

21612189
wp.launch(
21622190
_contact_match,
21632191
dim=(m.sensor_contact_adr.size, d.nconmax),
21642192
inputs=[
2193+
m.opt.cone,
21652194
m.sensor_objid,
21662195
m.sensor_refid,
2196+
m.sensor_intprm,
21672197
m.sensor_contact_adr,
2198+
d.njmax,
21682199
d.ncon,
21692200
d.contact.dist,
2201+
d.contact.frame,
2202+
d.contact.friction,
2203+
d.contact.dim,
21702204
d.contact.geom,
2205+
d.contact.efc_address,
21712206
d.contact.worldid,
2207+
d.efc.force,
21722208
],
21732209
outputs=[
21742210
d.sensor_contact_nmatch,

mujoco_warp/_src/sensor_test.py

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -411,30 +411,26 @@ def test_energy(self, xml):
411411
@parameterized.parameters(
412412
'type="sphere" size=".1"',
413413
'type="capsule" size=".1 .1" euler="0 89 89"',
414-
'type="box" size=".1 .1 .1" euler=".02 .05 .1"',
414+
'type="box" size=".1 .11 .12" euler=".02 .05 .1"',
415415
)
416416
def test_contact_sensor(self, geom):
417417
"""Test contact sensor."""
418418
# create contact sensors
419419
contact_sensor = ""
420420

421421
# data combinations
422-
field = ["found", "force", "torque", "dist", "pos", "normal", "tangent"]
423-
datas = itertools.chain.from_iterable([itertools.combinations(field, i) for i in range(len(field))])
424-
datas = list(datas)
425-
426-
for num in [1, 2, 3, 4, 5]:
427-
for geoms in [
428-
'geom1="plane" geom2="geom"',
429-
'geom1="geom" geom2="plane"',
430-
'geom1="plane" geom2="sphere"',
431-
'geom1="sphere" geom2="plane"',
432-
'geom1="geom" geom2="sphere"',
433-
'geom1="sphere" geom2="geom"',
434-
]:
435-
for data in datas:
436-
data = " ".join(data)
437-
contact_sensor += f'<contact {geoms} num="{num}" reduce="mindist" data="{data}"/>'
422+
datas = ["found", "force dist normal", "torque pos tangent", "found force torque dist pos normal tangent"]
423+
424+
for geoms in [
425+
'geom1="plane" geom2="geom"',
426+
'geom1="geom" geom2="plane"',
427+
'geom1="sphere" geom2="plane"',
428+
'geom1="geom" geom2="sphere"',
429+
]:
430+
for num in [1, 3, 5]:
431+
for reduce in ["mindist", "maxforce"]:
432+
for data in datas:
433+
contact_sensor += f'<contact {geoms} num="{num}" reduce="{reduce}" data="{data}"/>'
438434

439435
_MJCF = f"""
440436
<mujoco>

0 commit comments

Comments
 (0)