Skip to content

Commit f08f460

Browse files
authored
[FEATURE] More robust MPR+SDF collision detection algorithm. (#1985)
* Fix errno error message. * Further reduce max number of collision pairs by default. * Improve runtime speed by optimizing memory locality. * Cleanup collision examples. * More robust MPR+SDF collision detection algorithm.
1 parent 4e7f970 commit f08f460

File tree

9 files changed

+145
-148
lines changed

9 files changed

+145
-148
lines changed

examples/collision/pyramid.py

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,57 +5,42 @@
55

66
def main():
77
parser = argparse.ArgumentParser()
8-
parser.add_argument("--pile_type", type=str, default="falling", choices=["static", "falling"])
9-
parser.add_argument("--num_cubes", type=int, default=5, choices=range(5, 11))
10-
parser.add_argument("--cpu", action="store_true", help="Use CPU backend instead of GPU")
11-
parser.add_argument("--steps", type=int, default=100)
8+
parser.add_argument("--pile_type", type=str, default="falling", choices=("static", "falling"))
9+
parser.add_argument("--num_cubes", type=int, default=5, choices=(5, 6, 7, 8, 9, 10))
10+
parser.add_argument("--cpu", action="store_true", help="Use CPU backend instead of GPU", default=True)
11+
parser.add_argument("--steps", type=int, default=150)
1212
parser.add_argument("-v", "--vis", action="store_true", default=False)
13-
1413
args = parser.parse_args()
1514

16-
pile_type = args.pile_type
17-
num_cubes = args.num_cubes
18-
cpu = args.cpu
19-
backend = gs.cpu if cpu else gs.gpu
20-
21-
gs.init(backend=backend, precision="32")
15+
gs.init(backend=gs.cpu if args.cpu else gs.gpu, precision="32")
2216

2317
scene = gs.Scene(
2418
sim_options=gs.options.SimOptions(
2519
dt=0.01,
2620
),
27-
rigid_options=gs.options.RigidOptions(
28-
box_box_detection=False,
29-
max_collision_pairs=1000,
30-
use_gjk_collision=True,
31-
enable_mujoco_compatibility=False,
32-
),
3321
viewer_options=gs.options.ViewerOptions(
3422
camera_pos=(0, -5.5, 2.5),
3523
camera_lookat=(0, 0.0, 1.5),
36-
camera_fov=30,
3724
max_FPS=60,
3825
),
3926
show_viewer=args.vis,
4027
)
4128

42-
plane = scene.add_entity(gs.morphs.Plane(pos=(0, 0, 0)))
29+
plane = scene.add_entity(gs.morphs.Plane())
4330

4431
# create pyramid of boxes
4532
box_size = 0.25
46-
if pile_type == "static":
47-
box_spacing = box_size
48-
else:
49-
box_spacing = 1.1 * box_size
50-
vec_one = np.array([1.0, 1.0, 1.0])
51-
box_pos_offset = (0 - 0.5, 1, 0.0) + 0.5 * box_size * vec_one
33+
box_spacing = (1.0 - 1e-3 + 0.1 * (args.pile_type == "static")) * box_size
34+
box_pos_offset = (0 - 0.5, 1, 0.0) + 0.5 * np.array([box_size, box_size, box_size])
5235
boxes = {}
53-
for i in range(num_cubes):
54-
for j in range(num_cubes - i):
36+
for i in range(args.num_cubes):
37+
for j in range(args.num_cubes - i):
5538
box = scene.add_entity(
5639
gs.morphs.Box(
57-
size=box_size * vec_one, pos=box_pos_offset + box_spacing * np.array([i + 0.5 * j, 0, j])
40+
size=[box_size, box_size, box_size],
41+
pos=box_pos_offset + box_spacing * np.array([i + 0.5 * j, 0, j]),
5842
),
43+
# visualize_contact=True,
5944
)
6045

6146
scene.build()

examples/collision/tower.py

Lines changed: 22 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,7 @@
55

66
def main():
77
parser = argparse.ArgumentParser()
8-
parser.add_argument(
9-
"--object",
10-
type=str,
11-
default="cylinder",
12-
choices=["sphere", "cylinder", "duck"],
13-
)
8+
parser.add_argument("--object", type=str, default="cylinder", choices=("sphere", "cylinder", "duck"))
149
parser.add_argument("-v", "--vis", action="store_true", default=False)
1510
args = parser.parse_args()
1611
object_type = args.object
@@ -22,46 +17,37 @@ def main():
2217
dt=0.005,
2318
),
2419
rigid_options=gs.options.RigidOptions(
25-
box_box_detection=False,
26-
max_collision_pairs=2000,
27-
use_gjk_collision=True,
28-
enable_mujoco_compatibility=False,
20+
max_collision_pairs=200,
2921
),
3022
viewer_options=gs.options.ViewerOptions(
3123
camera_pos=(20, -20, 20),
3224
camera_lookat=(0.0, 0.0, 5.0),
33-
camera_fov=30,
3425
max_FPS=60,
3526
),
3627
show_viewer=args.vis,
3728
)
3829

39-
plane = scene.add_entity(gs.morphs.Plane(pos=(0, 0, 0)))
30+
plane = scene.add_entity(gs.morphs.Plane())
4031

4132
# create pyramid of boxes
42-
box_width = 0.25
43-
box_length = 2.0
44-
box_height = 0.1
33+
box_width, box_length, box_height = 0.25, 2.0, 0.1
4534
num_stacks = 50
46-
height_offset = 0.0
4735
for i in range(num_stacks):
48-
horizontal = i % 2 == 0
49-
50-
if horizontal:
36+
if i % 2 == 0: # horizontal stack
5137
box_size = np.array([box_width, box_length, box_height])
52-
box_pos_0 = (-0.4 * box_length, 0, i * (height_offset + box_size[2]) + 0.5 * box_size[2])
53-
box_pos_1 = (+0.4 * box_length, 0, i * (height_offset + box_size[2]) + 0.5 * box_size[2])
54-
else:
38+
box_pos_0 = (-0.4 * box_length, 0, i * (box_height - 1e-3) + 0.5 * box_height)
39+
box_pos_1 = (+0.4 * box_length, 0, i * (box_height - 1e-3) + 0.5 * box_height)
40+
else: # vertical stack
5541
box_size = np.array([box_length, box_width, box_height])
56-
box_pos_0 = (0, -0.4 * box_length, i * (height_offset + box_size[2]) + 0.5 * box_size[2])
57-
box_pos_1 = (0, +0.4 * box_length, i * (height_offset + box_size[2]) + 0.5 * box_size[2])
58-
59-
scene.add_entity(
60-
gs.morphs.Box(size=box_size, pos=box_pos_0),
61-
)
62-
scene.add_entity(
63-
gs.morphs.Box(size=box_size, pos=box_pos_1),
64-
)
42+
box_pos_0 = (0, -0.4 * box_length, i * (box_height - 1e-3) + 0.5 * box_height)
43+
box_pos_1 = (0, +0.4 * box_length, i * (box_height - 1e-3) + 0.5 * box_height)
44+
for box_pos in (box_pos_0, box_pos_1):
45+
scene.add_entity(
46+
gs.morphs.Box(
47+
size=box_size,
48+
pos=box_pos,
49+
),
50+
)
6551

6652
# Drop a huge mesh
6753
if object_type == "duck":
@@ -70,14 +56,15 @@ def main():
7056
morph=gs.morphs.Mesh(
7157
file="meshes/duck.obj",
7258
scale=duck_scale,
73-
pos=(0, 0, num_stacks * (height_offset + box_height) + 10 * duck_scale),
59+
pos=(0, 0, num_stacks * box_height + 10 * duck_scale),
7460
),
7561
)
7662
elif object_type == "sphere":
7763
sphere_radius = 2.0
7864
scene.add_entity(
7965
morph=gs.morphs.Sphere(
80-
radius=sphere_radius, pos=(0.0, 0.0, num_stacks * (height_offset + box_height) + 5 * sphere_radius)
66+
radius=sphere_radius,
67+
pos=(0.0, 0.0, num_stacks * box_height + 5 * sphere_radius),
8168
),
8269
)
8370
elif object_type == "cylinder":
@@ -87,12 +74,12 @@ def main():
8774
morph=gs.morphs.Cylinder(
8875
radius=cylinder_radius,
8976
height=cylinder_height,
90-
pos=(0.0, 0.0, num_stacks * (height_offset + box_height) + 5 * cylinder_height),
77+
pos=(0.0, 0.0, num_stacks * box_height + 5 * cylinder_height),
9178
),
9279
)
9380

9481
scene.build()
95-
for i in range(500):
82+
for i in range(600):
9683
scene.step()
9784

9885

genesis/engine/simulator.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@
4444
from .solvers.base_solver import Solver
4545

4646

47+
RATE_CHECK_ERRNO = 10
48+
49+
4750
@ti.data_oriented
4851
class Simulator(RBC):
4952
"""
@@ -287,7 +290,7 @@ def step(self, in_backward=False):
287290

288291
if self.rigid_solver.is_active:
289292
self.rigid_solver.clear_external_force()
290-
if self._cur_substep_global % 10 == 0:
293+
if self._cur_substep_global % RATE_CHECK_ERRNO == 0:
291294
self.rigid_solver.check_errno()
292295

293296
self._sensor_manager.step()

0 commit comments

Comments
 (0)