-
Notifications
You must be signed in to change notification settings - Fork 0
/
test_python_ompl2.py
301 lines (232 loc) · 10.3 KB
/
test_python_ompl2.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
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
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
#!/usr/bin/env python
# Author: Luis G. Torres, Mark Moll
import sys
from robosuite.controllers import load_controller_config
from robosuite.utils.input_utils import choose_environment, choose_robots, choose_controller
import robosuite as suite
try:
from ompl import util as ou
from ompl import base as ob
from ompl import geometric as og
except ImportError:
# if the ompl module is not in the PYTHONPATH assume it is installed in a
# subdirectory of the parent directory called "py-bindings."
from os.path import abspath, dirname, join
sys.path.insert(0, join(dirname(dirname(abspath(__file__))), 'py-bindings'))
from ompl import util as ou
from ompl import base as ob
from ompl import geometric as og
from math import sqrt
import argparse
class ValidityChecker(ob.StateValidityChecker):
# Returns whether the given state's position overlaps the
# circular obstacle
def isValid(self, state):
return self.clearance(state) > 0.0
# Returns the distance from the given state's position to the
# boundary of the circular obstacle.
def clearance(self, state):
# Extract the robot's (x,y) position from its state
x = state[0]
y = state[1]
# Distance formula between two points, offset by the circle's
# radius
return sqrt((x - 0.5) * (x - 0.5) + (y - 0.5) * (y - 0.5)) - 0.25
def getPathLengthObjective(si):
return ob.PathLengthOptimizationObjective(si)
def getThresholdPathLengthObj(si):
obj = ob.PathLengthOptimizationObjective(si)
obj.setCostThreshold(ob.Cost(1.51))
return obj
class ClearanceObjective(ob.StateCostIntegralObjective):
def __init__(self, si):
super(ClearanceObjective, self).__init__(si, True)
self.si_ = si
# Our requirement is to maximize path clearance from obstacles,
# but we want to represent the objective as a path cost
# minimization. Therefore, we set each state's cost to be the
# reciprocal of its clearance, so that as state clearance
# increases, the state cost decreases.
def stateCost(self, s):
return ob.Cost(1 / (self.si_.getStateValidityChecker().clearance(s) +
sys.float_info.min))
def getClearanceObjective(si):
return ClearanceObjective(si)
def getBalancedObjective1(si):
lengthObj = ob.PathLengthOptimizationObjective(si)
clearObj = ClearanceObjective(si)
opt = ob.MultiOptimizationObjective(si)
opt.addObjective(lengthObj, 5.0)
opt.addObjective(clearObj, 1.0)
return opt
def getPathLengthObjWithCostToGo(si):
obj = ob.PathLengthOptimizationObjective(si)
obj.setCostToGoHeuristic(ob.CostToGoHeuristic(ob.goalRegionCostToGo))
return obj
# Keep these in alphabetical order and all lower case
def allocatePlanner(si, plannerType):
if plannerType.lower() == "bfmtstar":
return og.BFMT(si)
elif plannerType.lower() == "bitstar":
return og.BITstar(si)
elif plannerType.lower() == "fmtstar":
return og.FMT(si)
elif plannerType.lower() == "informedrrtstar":
return og.InformedRRTstar(si)
elif plannerType.lower() == "prmstar":
return og.PRMstar(si)
elif plannerType.lower() == "rrtstar":
return og.RRTstar(si)
elif plannerType.lower() == "sorrtstar":
return og.SORRTstar(si)
else:
ou.OMPL_ERROR("Planner-type is not implemented in allocation function.")
# Keep these in alphabetical order and all lower case
def allocateObjective(si, objectiveType):
if objectiveType.lower() == "pathclearance":
return getClearanceObjective(si)
elif objectiveType.lower() == "pathlength":
return getPathLengthObjective(si)
elif objectiveType.lower() == "thresholdpathlength":
return getThresholdPathLengthObj(si)
elif objectiveType.lower() == "weightedlengthandclearancecombo":
return getBalancedObjective1(si)
else:
ou.OMPL_ERROR("Optimization-objective is not implemented in allocation function.")
def plan(runTime, plannerType, objectiveType, fname):
# Construct the robot state space in which we're planning. We're
# planning in [0,1]x[0,1], a subset of R^2.
space = ob.RealVectorStateSpace(2)
# Set the bounds of space to be in [0,1].
space.setBounds(0.0, 1.0)
# Construct a space information instance for this state space
si = ob.SpaceInformation(space)
# Set the object used to check which states in the space are valid
validityChecker = ValidityChecker(si)
si.setStateValidityChecker(validityChecker)
si.setup()
# Set our robot's starting state to be the bottom-left corner of
# the environment, or (0,0).
start = ob.State(space)
start[0] = 0.0
start[1] = 0.0
# Set our robot's goal state to be the top-right corner of the
# environment, or (1,1).
goal = ob.State(space)
goal[0] = 1.0
goal[1] = 1.0
# Create a problem instance
pdef = ob.ProblemDefinition(si)
# Set the start and goal states
pdef.setStartAndGoalStates(start, goal)
# Create the optimization objective specified by our command-line argument.
# This helper function is simply a switch statement.
pdef.setOptimizationObjective(allocateObjective(si, objectiveType))
# Construct the optimal planner specified by our command line argument.
# This helper function is simply a switch statement.
optimizingPlanner = allocatePlanner(si, plannerType)
# Set the problem instance for our planner to solve
optimizingPlanner.setProblemDefinition(pdef)
optimizingPlanner.setup()
# attempt to solve the planning problem in the given runtime
solved = optimizingPlanner.solve(runTime)
if solved:
# Output the length of the path found
print('{0} found solution of path length {1:.4f} with an optimization ' \
'objective value of {2:.4f}'.format( \
optimizingPlanner.getName(), \
pdef.getSolutionPath().length(), \
pdef.getSolutionPath().cost(pdef.getOptimizationObjective()).value()))
# If a filename was specified, output the path as a matrix to
# that file for visualization
if fname:
with open(fname, 'w') as outFile:
outFile.write(pdef.getSolutionPath().printAsMatrix())
else:
print("No solution found.")
if __name__ == "__main__":
# Create an argument parser
parser = argparse.ArgumentParser(description='Optimal motion planning demo program.')
# Add a filename argument
parser.add_argument('-t', '--runtime', type=float, default=1.0, help= \
'(Optional) Specify the runtime in seconds. Defaults to 1 and must be greater than 0.')
parser.add_argument('-p', '--planner', default='RRTstar', \
choices=['BFMTstar', 'BITstar', 'FMTstar', 'InformedRRTstar', 'PRMstar', 'RRTstar', \
'SORRTstar'], \
help='(Optional) Specify the optimal planner to use, defaults to RRTstar if not given.')
parser.add_argument('-o', '--objective', default='PathLength', \
choices=['PathClearance', 'PathLength', 'ThresholdPathLength', \
'WeightedLengthAndClearanceCombo'], \
help='(Optional) Specify the optimization objective, defaults to PathLength if not given.')
parser.add_argument('-f', '--file', default=None, \
help='(Optional) Specify an output path for the found solution path.')
parser.add_argument('-i', '--info', type=int, default=0, choices=[0, 1, 2], \
help='(Optional) Set the OMPL log level. 0 for WARN, 1 for INFO, 2 for DEBUG.' \
' Defaults to WARN.')
# Parse the arguments
args = parser.parse_args()
# Check that time is positive
if args.runtime <= 0:
raise argparse.ArgumentTypeError(
"argument -t/--runtime: invalid choice: %r (choose a positive number greater than 0)" \
% (args.runtime,))
# Set the log level
if args.info == 0:
ou.setLogLevel(ou.LOG_WARN)
elif args.info == 1:
ou.setLogLevel(ou.LOG_INFO)
elif args.info == 2:
ou.setLogLevel(ou.LOG_DEBUG)
else:
ou.OMPL_ERROR("Invalid log-level integer.")
# Create dict to hold options that will be passed to env creation call
options = {}
# print welcome info
print("Welcome to robosuite v{}!".format(suite.__version__))
print(suite.__logo__)
# Choose environment and add it to options
options["env_name"] = choose_environment()
# If a multi-arm environment has been chosen, choose configuration and appropriate robot(s)
if "TwoArm" in options["env_name"]:
# Choose env config and add it to options
options["env_configuration"] = choose_multi_arm_config()
# If chosen configuration was bimanual, the corresponding robot must be Baxter. Else, have user choose robots
if options["env_configuration"] == "bimanual":
options["robots"] = "Baxter"
else:
options["robots"] = []
# Have user choose two robots
print("A multiple single-arm configuration was chosen.\n")
for i in range(2):
print("Please choose Robot {}...\n".format(i))
options["robots"].append(choose_robots(exclude_bimanual=True))
# Else, we simply choose a single (single-armed) robot to instantiate in the environment
else:
options["robots"] = choose_robots(exclude_bimanual=True)
# Choose controller
controller_name = choose_controller()
# Load the desired controller
options["controller_configs"] = load_controller_config(default_controller=controller_name)
# Help message to user
print()
print('Press "H" to show the viewer control panel.')
# initialize the task
env = suite.make(
**options,
has_renderer=True,
has_offscreen_renderer=True,
ignore_done=True,
use_camera_obs=False,
control_freq=20,
)
env.reset()
env.viewer.set_camera(camera_id=0)
# Get action limits
low, high = env.action_spec
# do visualization
for i in range(10):
action = np.random.uniform(low, high)
obs, reward, done, _ = env.step(action)
# env.render()
# Solve the planning problem
plan(args.runtime, args.planner, args.objective, args.file)