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.