-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathplan_example.py
More file actions
248 lines (213 loc) · 8.3 KB
/
plan_example.py
File metadata and controls
248 lines (213 loc) · 8.3 KB
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
import sys
sys.path.append('pddlstream/')
from ss.algorithms.dual_focused import dual_focused
import numpy as np
import kitchen2d.kitchen_stuff as ks
from kitchen_tasks.kitchen_utils import print_plan, execute_plan, step_plan, kitchen_creation_methods, initialize_objects_in_kitchen, update_sizes
from kitchen_tasks.kitchen_problem import create_problem
from kitchen_tasks.kitchen_predicates import *
##################################################
DEFAULT_TASK = {
'kitchen_params': {
'do_gui': False,
'sink_w': 10.,
'sink_h': 5.,
'sink_d': 1.,
'sink_pos_x': 20.,
'left_table_width': 100.,
'right_table_width': 100.,
'faucet_h': 15.,
'faucet_w': 5.,
'faucet_d': 0.5,
'obstacles': [],
'liquid_name': 'coffee',
'overclock': 100 # Set overclock higher if run visualization faster
},
'initial_poses': {
'gripper': (0., 15., 0.),
'cup': (7.5, 0., 0.),
'sugar_cup': (-10., 0., 0.),
'cream_cup': (15., 0, 0),
'spoon': (0.5, 0.5, 0),
'stirrer': (20, 0.5, 0),
'block': (-20., 0, 0),
},
'object_sizes': {
'spoon': (0.2, 3, 1.),
'stirrer': (0.2, 5., 0.5),
'block': (5, 1, 0),
'holder': (1., 2., 0.5), # default size of a holder
},
'expid_pour': 0,
'expid_scoop': 0,
}
'''
We use a holder for each spoon and stirrer object to
ensure that these objects can be grasped.
The size and location of each holder depends on the
spoon or stirrer it is holding. See function make_kitchen
in kitchen_tasks/kitchen_utils.py for how these holders
are created.
'''
##################################################
def sample_task_instance():
'''
Randomly sample a task instance, which has the same
format as DEFAULT_TASK.
'''
task = DEFAULT_TASK.copy()
expid_pour = task['expid_pour']
expid_scoop = task['expid_scoop']
sizes = task['object_sizes']
sizes = update_sizes(expid_pour, expid_scoop, sizes)
faucet_w = task['kitchen_params']['faucet_w']
holder_d = task['object_sizes']['holder'][2]
delta_dist = 2.
grasp_dist = 3.
left = -ks.SCREEN_WIDTH/2 + delta_dist + grasp_dist
right = ks.SCREEN_WIDTH/2 - delta_dist - grasp_dist
def sample_kitchen():
while True:
sink_pos_x = np.random.uniform(left, right)
sink_w = np.random.uniform(faucet_w+delta_dist, faucet_w*2)
if sink_pos_x + sink_w < right:
return sink_pos_x, sink_w
sink_pos_x, sink_w = sample_kitchen()
task['kitchen_params']['sink_pos_x'] = sink_pos_x
task['kitchen_params']['sink_w'] = sink_w
x_intervals = [[left, sink_pos_x - grasp_dist],
[sink_pos_x + sink_w + grasp_dist, right]]
gripper_x = np.random.uniform(left, right)
names = ['cup', 'sugar_cup', 'cream_cup', 'spoon', 'stirrer', 'block']
def sample_from_region(region):
weight = [np.prod(a[1]-a[0]) for a in region]
weight = weight / np.sum(weight)
rid = np.random.choice(len(weight), p=weight)
return np.random.uniform(region[rid][0], region[rid][1])
def test_feasible(x_poses, debug=False):
'''
We use the following constraints:
1, the distance between two objects is at least delta_dist.
The distance between two objects is measured by the Euclidean
distance from the right side of the left object to the left side
of the right object.
2, The distance from the center of any object to any side of other
objects is at least grasp_dist.
3, The objects are put on the table (table y axis is 0), but not in
the sink (sink y axis is -sink_h).
4, block is to the left of everything.
'''
for i in range(len(names)):
if names[i] == 'block':
if x_poses[i] > sink_pos_x:
return False
for j in range(len(names)):
if names[i] == 'block':
if x_poses[i] > x_poses[j]:
return False
if i <= j:
continue
if (i == 1 or j == 1) and debug:
import pdb; pdb.set_trace()
if x_poses[i] > x_poses[j]:
# ensure object i is to the left of j
i_ = j; j_ = i
else:
i_ = i; j_ = j
r_i = x_poses[i_] + max(sizes[names[i_]][0], sizes[names[i_]][2])
l_j = x_poses[j_] - max(sizes[names[j_]][0], sizes[names[i_]][2])
if l_j - r_i < delta_dist:
return False
if x_poses[j_] - r_i < grasp_dist:
return False
if l_j - x_poses[i_] < grasp_dist:
return False
return True
while True:
x_poses = [sample_from_region(x_intervals) for i in range(len(names))]
if test_feasible(x_poses):
break
test_feasible(x_poses, False)
cup_x, sugar_x, cream_x, spoon_x, stir_x, block_x = x_poses
initial_poses = {
'gripper': (gripper_x, 20., 0.),
'cup': (cup_x, 0., 0.),
'sugar_cup': (sugar_x, 0., 0.),
'cream_cup': (cream_x, 0, 0),
# Notice that spoons and stirrers will be put in a holder cup
'spoon': (spoon_x, holder_d, 0),
'stirrer': (stir_x, holder_d, 0),
'block': (block_x, 0, 0),
}
task['initial_poses'] = initial_poses
return task
##################################################
def solve_task(kitchen_params, initial_poses, object_sizes, expid_pour, expid_scoop):
'''
Solve for a plan of a task and visualize the results.
Args:
kitchen_params: init parameters of a Kitchen2D object. See Kitchen2D in
kitchen2d/kitchen_stuff.py
initial_poses: a dictionary mapping from the object names to their poses.
object_sizes: a dictionary mapping from the object names to their sizes.
expid_pour: experiment ID for learning to pour.
expid_scoop: experiment ID for learning to scoop.
'''
make_kitchen, make_body = kitchen_creation_methods(expid_pour, expid_scoop,
kitchen_params, initial_poses, object_sizes)
block_goal = (-ks.SCREEN_WIDTH/2 + 5, 0, 0)
'''
Initial state of the system.
Poses of the objects will be added
later in create_problem.
'''
initial_atoms = [
# Static atoms
IsPose('block', block_goal),
# Fluent atoms
Empty('gripper'),
CanMove('gripper'),
HasSugar('sugar_cup'),
HasCream('cream_cup'),
IsPourable('cream_cup'),
Stackable('cup', 'block'),
Clear('block')
]
# Goal literals (list of conjunctive literals)
goal_literals = [
AtPose('block', block_goal),
On('cup', 'block'),
HasCoffee('cup'),
HasCream('cup'),
HasSugar('cup'),
Mixed('cup'),
Empty('gripper'),
]
# Construct the simulator
kitchen = make_kitchen(planning=False)
body_from_name = initialize_objects_in_kitchen(kitchen, make_body, initial_poses, initial_atoms)
kitchen.enable_gui()
# Create a problem for STRIPStream
problem = create_problem(initial_poses, initial_atoms, goal_literals, make_kitchen, make_body,
expid_pour, expid_scoop, do_motion=False, do_collisions=True, do_grasp=True)
# Solve the problem in STRIPStream
raw_input('Start running STRIPStream solver?')
plan, evaluations = dual_focused(problem, planner='ff-wastar3', max_time=600, verbose=True,
max_planner_time=100, bind=True, use_context=True)
print_plan(plan, evaluations)
if plan is None:
return
if raw_input('Show plan? [y/n]') in ['y', 'Y']:
# Show plan simulation
step_plan(plan, kitchen, body_from_name)
if raw_input('Show plan execution? [y/n]') in ['y', 'Y']:
# Show execution simulation
kitchen = make_kitchen(planning=False)
body_from_name = initialize_objects_in_kitchen(kitchen, make_body, initial_poses, initial_atoms)
kitchen.enable_gui()
execute_plan(plan, kitchen, body_from_name)
raw_input('Done!')
if __name__ == '__main__':
print 'Sampling task instances...'
task = sample_task_instance()
solve_task(**task)