Contact#

Contact information is useful to check whether two rigid bodies collide or whether an object is grasped by a gripper. The example shows how to check the contact between two rigid objects (one box supported by another box).

In this tutorial, you will learn the following:

  • Get contact information from PhysxContact

The full script is included as follows:

 1"""A simple example for contact."""
 2
 3import sapien
 4import numpy as np
 5
 6
 7def main():
 8    scene = sapien.Scene()
 9    dt = 1 / 100.0
10    scene.set_timestep(dt)
11
12    # ---------------------------------------------------------------------------- #
13    # Add two boxes
14    # ---------------------------------------------------------------------------- #
15    actor_builder = scene.create_actor_builder()
16    actor_builder.add_box_collision(half_size=[0.5, 0.5, 0.5])
17    # actor_builder.add_box_visual(half_size=[0.5, 0.5, 0.5], color=[1, 0, 0])
18    box1 = actor_builder.build_kinematic(name="box1")
19    box1.set_pose(sapien.Pose(p=[0, 0, 1.0]))
20    print(
21        "Mass of box1:",
22        box1.find_component_by_type(sapien.physx.PhysxRigidDynamicComponent).mass,
23    )
24
25    actor_builder = scene.create_actor_builder()
26    actor_builder.add_box_collision(half_size=[0.25, 0.25, 0.25])
27    # actor_builder.add_box_visual(half_size=[0.25, 0.25, 0.25], color=[0, 1, 0])
28    box2 = actor_builder.build(name="box2")
29    box2.set_pose(sapien.Pose(p=[0, 0, 1.75]))
30    print(
31        "Mass of box1:",
32        box2.find_component_by_type(sapien.physx.PhysxRigidDynamicComponent).mass,
33    )
34
35    # step a few times to settle the scene
36    for _ in range(10):
37        scene.step()
38
39    # ---------------------------------------------------------------------------- #
40    # Check contacts
41    # ---------------------------------------------------------------------------- #
42
43    contacts = scene.get_contacts()
44    support_force = 0
45    for contact in contacts:
46        print(contact)
47        for point in contact.points:
48            print("Impulse (F * dt) on the first actor:", point.impulse)
49            print("Normal (same direction as impulse):", point.normal)
50            print("Contact position (in the world frame):", point.position)
51            print("Minimum distance between two shapes:", point.separation)
52            if contact.bodies[0].entity.name == "box2":
53                support_force += point.impulse[2] / dt
54            elif contact.bodies[0].entity.name == "box1":
55                support_force -= point.impulse[2] / dt
56            else:
57                raise RuntimeError("Impossible case in this example.")
58    # Sanity check: the support force should balance the gravity
59    np.testing.assert_allclose(
60        support_force,
61        9.81
62        * box2.find_component_by_type(sapien.physx.PhysxRigidDynamicComponent).mass,
63        rtol=1e-3,
64    )
65
66
67if __name__ == "__main__":
68    main()

You can call get_contacts to fetch all contacts after the current simulation step. It returns a list of PhysxContact. contact.components[0] and contact.components[1] refer to two PhysX rigid components involved in the contact. contact.shapes[0] and contact.shapes[1] refer to two PhysX collision shapes involved in the contact. contact.points contains a list of PhysxContactPoint.

For each contact point,

  • impulse: the impulse applied on the first actor.

  • normal: the direction of impulse.

  • position: the point of application in the world frame.

  • separation: distance between the two shapes involved in the contact (can be negative).

Note

PhysxContact in SAPIEN does not mean that two actors are touching each other. A contact will be generated when the distance between two actors are smaller than a given contact offset, which can be changed in PhysxSceneConfig before creating the scene. To check for touching and penetration, one should check the impulse of a contact point.