-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathcollision_detection_example.py
executable file
·152 lines (123 loc) · 4.29 KB
/
collision_detection_example.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/usr/bin/env python
"""Example demonstrating collision detection and shortest distance queries."""
import time
import numpy as np
import pybullet as pyb
import pybullet_data
import pyb_utils
TIMESTEP = 1.0 / 60
def load_environment(client_id):
pyb.setTimeStep(TIMESTEP, physicsClientId=client_id)
pyb.setAdditionalSearchPath(
pybullet_data.getDataPath(), physicsClientId=client_id
)
# ground plane
ground_id = pyb.loadURDF(
"plane.urdf", [0, 0, 0], useFixedBase=True, physicsClientId=client_id
)
# KUKA iiwa robot arm
kuka_id = pyb.loadURDF(
"kuka_iiwa/model.urdf",
[0, 0, 0],
useFixedBase=True,
physicsClientId=client_id,
)
robot = pyb_utils.Robot(kuka_id, client_id=client_id)
# some cubes for obstacles
cube1_id = pyb.loadURDF(
"cube.urdf", [1, 1, 0.5], useFixedBase=True, physicsClientId=client_id
)
cube2_id = pyb.loadURDF(
"cube.urdf", [-1, -1, 0.5], useFixedBase=True, physicsClientId=client_id
)
cube3_id = pyb.loadURDF(
"cube.urdf", [1, -1, 0.5], useFixedBase=True, physicsClientId=client_id
)
# store body indices in a dict with more convenient key names
obstacles = {
"ground": ground_id,
"cube1": cube1_id,
"cube2": cube2_id,
"cube3": cube3_id,
}
return robot, obstacles
def create_robot_params_gui(robot):
"""Create debug params to set the robot joint positions from the GUI."""
params = {}
for name in robot.moveable_joint_names:
params[name] = pyb.addUserDebugParameter(
name,
rangeMin=-2 * np.pi,
rangeMax=2 * np.pi,
startValue=0,
physicsClientId=robot.client_id,
)
return params
def read_robot_params_gui(robot_params_gui, client_id):
"""Read robot configuration from the GUI."""
return np.array(
[
pyb.readUserDebugParameter(
param,
physicsClientId=client_id,
)
for param in robot_params_gui.values()
]
)
def main():
# main simulation server, with a GUI
gui_id = pyb.connect(pyb.GUI)
# simulation server only used for collision detection
col_id = pyb.connect(pyb.DIRECT)
# add bodies to both of the environments
robot, _ = load_environment(gui_id)
col_robot, col_obstacles = load_environment(col_id)
# create user debug parameters
collision_margin_param_gui = pyb.addUserDebugParameter(
"collision_margin",
rangeMin=0,
rangeMax=0.2,
startValue=0.01,
physicsClientId=gui_id,
)
robot_params_gui = create_robot_params_gui(robot)
# define bodies (and links) to use for shortest distance computations and
# collision checking
ground = col_obstacles["ground"]
cube1 = col_obstacles["cube1"]
cube2 = col_obstacles["cube2"]
cube3 = col_obstacles["cube3"]
link7 = (col_robot.uid, "lbr_iiwa_link_7")
col_detector = pyb_utils.CollisionDetector(
col_id,
[(link7, ground), (link7, cube1), (link7, cube2), (link7, cube3)],
)
last_dists = 0
while True:
q = read_robot_params_gui(robot_params_gui, client_id=gui_id)
# move to the requested configuration if it is not in collision,
# otherwise display a warning
# the key is that we can check collisions using the separate physics
# client, so we don't have to set the robot to a configuration in the
# main GUI sim to check if that configuration is in collision
col_robot.reset_joint_configuration(q)
if not col_detector.in_collision(
margin=pyb.readUserDebugParameter(collision_margin_param_gui),
):
robot.reset_joint_configuration(q)
else:
pyb.addUserDebugText(
"Avoiding collision",
textPosition=[0, 0, 1.5],
textColorRGB=[1, 0, 0],
textSize=2,
lifeTime=0.2,
)
# compute shortest distances for user-selected configuration
dists = col_detector.compute_distances()
if not np.allclose(last_dists, dists):
print(f"Distance to obstacles = {dists}")
last_dists = dists
time.sleep(TIMESTEP)
if __name__ == "__main__":
main()