newton.sensors.SensorContact#

class newton.sensors.SensorContact(model, *, sensing_obj_bodies=None, sensing_obj_shapes=None, counterpart_bodies=None, counterpart_shapes=None, include_total=True, verbose=None, request_contact_attributes=True)[source]#

Bases: object

Measures net contact forces on a set of sensing objects (bodies or shapes).

In its simplest form the sensor reports the total contact force acting on each sensing object. Optionally, specify counterparts to break the force down per contacting body or shape. With include_total=True (default) a total-force column is prepended.

The result is a force matrix: one row per sensing object, one column per counterpart reading.

Multi-world behaviour

When the model contains multiple worlds, pair tables are built per-world. Cross-world shape pairs are excluded – only within-world and global counterparts (e.g. ground plane) contribute. Global bodies and shapes cannot be sensing objects.

The force matrix has shape (sum_of_sensors_across_worlds, max_readings) where max_readings is the maximum counterpart count of any single world. Rows are world-contiguous (world 0 first, then world 1, …). Columns beyond a world’s own reading count are zero-padded.

sensing_objs, counterparts, and reading_indices are per-world nested lists indexed as attr[world][i].

Terms

  • Sensing object – body or shape carrying a contact sensor.

  • Counterpart – the other body or shape in a contact interaction.

  • Force reading – one entry of the force matrix (vec3).

Construction and update order

SensorContact requests the force extended attribute from the model at init, so a Contacts object created afterwards (via Model.contacts() or directly) will include it automatically.

update() reads from contacts.force. Call solver.update_contacts(contacts) before sensor.update() so that contact forces are current.

Parameters that select bodies or shapes accept label patterns – see Label Matching.

Example

Measure net contact force on a sphere resting on the ground:

import warp as wp
import newton
from newton.sensors import SensorContact

builder = newton.ModelBuilder()
builder.add_ground_plane()
body = builder.add_body(xform=wp.transform((0, 0, 0.1), wp.quat_identity()))
builder.add_shape_sphere(body, radius=0.1, label="ball")
model = builder.finalize()

sensor = SensorContact(model, sensing_obj_shapes="ball")
solver = newton.solvers.SolverMuJoCo(model)
state = model.state()
contacts = model.contacts()

solver.step(state, state, None, None, dt=1.0 / 60.0)
solver.update_contacts(contacts)
sensor.update(state, contacts)
force = sensor.net_force.numpy()  # (n_sensing_objs, max_readings, 3)
Raises:

ValueError – If the configuration of sensing/counterpart objects is invalid.

class ObjectType(*values)#

Bases: Enum

Type tag for entries in sensing_objs and counterparts.

BODY = 2#

Individual body.

SHAPE = 1#

Individual shape.

TOTAL = 0#

Total force entry. Only applies to counterparts.

__init__(model, *, sensing_obj_bodies=None, sensing_obj_shapes=None, counterpart_bodies=None, counterpart_shapes=None, include_total=True, verbose=None, request_contact_attributes=True)#

Initialize the SensorContact.

Exactly one of sensing_obj_bodies or sensing_obj_shapes must be specified to define the sensing objects. At most one of counterpart_bodies or counterpart_shapes may be specified. If neither is specified, the sensor will read the net contact force for each sensing object.

Parameters:
  • sensing_obj_bodies (str | list[str] | list[int] | None) – List of body indices, single pattern to match against body labels, or list of patterns where any one matches.

  • sensing_obj_shapes (str | list[str] | list[int] | None) – List of shape indices, single pattern to match against shape labels, or list of patterns where any one matches.

  • counterpart_bodies (str | list[str] | list[int] | None) – List of body indices, single pattern to match against body labels, or list of patterns where any one matches.

  • counterpart_shapes (str | list[str] | list[int] | None) – List of shape indices, single pattern to match against shape labels, or list of patterns where any one matches.

  • include_total (bool) – If True and counterparts are specified, add a reading for the total contact force for each sensing object. Does nothing when no counterparts are specified.

  • verbose (bool | None) – If True, print details. If None, uses wp.config.verbose.

  • request_contact_attributes (bool) – If True (default), transparently request the extended contact attribute force from the model.

update(state, contacts)#

Update the contact sensor readings based on the provided state and contacts.

Computes world-frame transforms for all sensing objects and evaluates net contact forces for each sensing-object/counterpart pair.

Parameters:
  • state (State | None) – The simulation state providing body transforms, or None to skip the transform update.

  • contacts (Contacts) – The contact data to evaluate.

counterparts: list[list[tuple[int, ObjectType]]]#

Index and type of each counterpart, per world. Columns of the force matrix.

net_force: array(ndim=2, dtype=vec3f)#

Net contact forces [N], shape (n_sensing_objs, max_readings), dtype vec3. Entry [i, j] is the force on sensing object i from counterpart j, in world frame.

reading_indices: list[list[list[int]]]#

Active counterpart indices per sensing object, per world.

sensing_obj_transforms: array(ndim=1, dtype=transformf)#

World-frame transforms of sensing objects [m, unitless quaternion], shape (n_sensing_objs,), dtype transform.

sensing_objs: list[list[tuple[int, ObjectType]]]#

Index and type of each sensing object, per world. Rows of the force matrix.

shape: tuple[int, int]#

Dimensions of the force matrix (n_sensing_objs, max_readings).