Loading...
Searching...
No Matches
OptimalPlanning.py
1#!/usr/bin/env python3
2
3
36
37# Author: Luis G. Torres, Mark Moll, Weihang Guo
38
39import sys
40from ompl import util as ou
41from ompl import base as ob
42from ompl import geometric as og
43from math import sqrt
44import argparse
45
46
47
52class ValidityChecker(ob.StateValidityChecker):
53 # Returns whether the given state's position overlaps the
54 # circular obstacle
55 def isValid(self, state):
56 return self.clearance(state) > 0.0
57
58 # Returns the distance from the given state's position to the
59 # boundary of the circular obstacle.
60 def clearance(self, state):
61 # Extract the robot's (x,y) position from its state
62 x = state[0]
63 y = state[1]
64
65 # Distance formula between two points, offset by the circle's
66 # radius
67 return sqrt((x - 0.5) * (x - 0.5) + (y - 0.5) * (y - 0.5)) - 0.25
68
69
70
74def getPathLengthObjective(si):
76
77
78
81def getThresholdPathLengthObj(si):
83 obj.setCostThreshold(ob.Cost(1.51))
84 return obj
85
86
87
99class ClearanceObjective(ob.StateCostIntegralObjective):
100 def __init__(self, si):
101 super(ClearanceObjective, self).__init__(si, True)
102 self.si_ = si
103
104 # Our requirement is to maximize path clearance from obstacles,
105 # but we want to represent the objective as a path cost
106 # minimization. Therefore, we set each state's cost to be the
107 # reciprocal of its clearance, so that as state clearance
108 # increases, the state cost decreases.
109 def stateCost(self, s):
110 return ob.Cost(
111 1 / (self.si_.getStateValidityChecker().clearance(s) + sys.float_info.min)
112 )
113
114
115
117def getClearanceObjective(si):
118 return ClearanceObjective(si)
119
120
121
132def getBalancedObjective1(si):
134 clearObj = ClearanceObjective(si)
135
137 opt.addObjective(lengthObj, 5.0)
138 opt.addObjective(clearObj, 1.0)
139
140 return opt
141
142
143
151
152
153
156def getPathLengthObjWithCostToGo(si):
158 obj.setCostToGoHeuristic(ob.CostToGoHeuristic(ob.goalRegionCostToGo))
159 return obj
160
161
162# Keep these in alphabetical order and all lower case
163def allocatePlanner(si, plannerType):
164 if plannerType.lower() == "aorrtc":
165 return og.AORRTC(si)
166 elif plannerType.lower() == "bfmtstar":
167 return og.BFMT(si)
168 elif plannerType.lower() == "bitstar":
169 return og.BITstar(si)
170 elif plannerType.lower() == "fmtstar":
171 return og.FMT(si)
172 elif plannerType.lower() == "informedrrtstar":
173 return og.InformedRRTstar(si)
174 elif plannerType.lower() == "prmstar":
175 return og.PRMstar(si)
176 elif plannerType.lower() == "rrtstar":
177 return og.RRTstar(si)
178 elif plannerType.lower() == "sorrtstar":
179 return og.SORRTstar(si)
180 else:
181 ou.OMPL_ERROR("Planner-type is not implemented in allocation function.")
182
183
184# Keep these in alphabetical order and all lower case
185def allocateObjective(si, objectiveType):
186 if objectiveType.lower() == "pathclearance":
187 return getClearanceObjective(si)
188 elif objectiveType.lower() == "pathlength":
189 return getPathLengthObjective(si)
190 elif objectiveType.lower() == "thresholdpathlength":
191 return getThresholdPathLengthObj(si)
192 elif objectiveType.lower() == "weightedlengthandclearancecombo":
193 return getBalancedObjective1(si)
194 else:
195 ou.OMPL_ERROR(
196 "Optimization-objective is not implemented in allocation function."
197 )
198
199
200def plan(runTime, plannerType, objectiveType, fname):
201 # Construct the robot state space in which we're planning. We're
202 # planning in [0,1]x[0,1], a subset of R^2.
203 space = ob.RealVectorStateSpace(2)
204
205 # Set the bounds of space to be in [0,1].
206 space.setBounds(0.0, 1.0)
207
208 # Construct a space information instance for this state space
209 si = ob.SpaceInformation(space)
210
211 # Set the object used to check which states in the space are valid
212 validityChecker = ValidityChecker(si)
213 si.setStateValidityChecker(validityChecker)
214
215 si.setup()
216
217 # Set our robot's starting state to be the bottom-left corner of
218 # the environment, or (0,0).
219 start = space.allocState()
220 start[0] = 0.0
221 start[1] = 0.0
222
223 # Set our robot's goal state to be the top-right corner of the
224 # environment, or (1,1).
225 goal = space.allocState()
226 goal[0] = 1.0
227 goal[1] = 1.0
228
229 # Create a problem instance
230 pdef = ob.ProblemDefinition(si)
231
232 # Set the start and goal states
233 pdef.setStartAndGoalStates(start, goal)
234
235 # Create the optimization objective specified by our command-line argument.
236 # This helper function is simply a switch statement.
237 pdef.setOptimizationObjective(allocateObjective(si, objectiveType))
238
239 # Construct the optimal planner specified by our command line argument.
240 # This helper function is simply a switch statement.
241 optimizingPlanner = allocatePlanner(si, plannerType)
242
243 # Set the problem instance for our planner to solve
244 optimizingPlanner.setProblemDefinition(pdef)
245 optimizingPlanner.setup()
246
247 # attempt to solve the planning problem in the given runtime
248 solved = optimizingPlanner.solve(runTime)
249
250 if solved:
251 # Output the length of the path found
252 print(
253 "{0} found solution of path length {1:.4f} with an optimization "
254 "objective value of {2:.4f}".format(
255 optimizingPlanner.getName(),
256 pdef.getSolutionPath().length(),
257 pdef.getSolutionPath().cost(pdef.getOptimizationObjective()).value(),
258 )
259 )
260
261 # If a filename was specified, output the path as a matrix to
262 # that file for visualization
263 if fname:
264 with open(fname, "w") as outFile:
265 outFile.write(pdef.getSolutionPath().printAsMatrix())
266 else:
267 print("No solution found.")
268
269
270if __name__ == "__main__":
271 # Create an argument parser
272 parser = argparse.ArgumentParser(
273 description="Optimal motion planning demo program."
274 )
275
276 # Add a filename argument
277 parser.add_argument(
278 "-t",
279 "--runtime",
280 type=float,
281 default=1.0,
282 help="(Optional) Specify the runtime in seconds. Defaults to 1 and must be greater than 0.",
283 )
284 parser.add_argument(
285 "-p",
286 "--planner",
287 default="RRTstar",
288 choices=[
289 "AORRTC",
290 "BFMTstar",
291 "BITstar",
292 "FMTstar",
293 "InformedRRTstar",
294 "PRMstar",
295 "RRTstar",
296 "SORRTstar",
297 ],
298 help="(Optional) Specify the optimal planner to use, defaults to RRTstar if not given.",
299 )
300 parser.add_argument(
301 "-o",
302 "--objective",
303 default="PathLength",
304 choices=[
305 "PathClearance",
306 "PathLength",
307 "ThresholdPathLength",
308 "WeightedLengthAndClearanceCombo",
309 ],
310 help="(Optional) Specify the optimization objective, defaults to PathLength if not given.",
311 )
312 parser.add_argument(
313 "-f",
314 "--file",
315 default=None,
316 help="(Optional) Specify an output path for the found solution path.",
317 )
318 parser.add_argument(
319 "-i",
320 "--info",
321 type=int,
322 default=0,
323 choices=[0, 1, 2],
324 help="(Optional) Set the OMPL log level. 0 for WARN, 1 for INFO, 2 for DEBUG."
325 " Defaults to WARN.",
326 )
327
328 # Parse the arguments
329 args = parser.parse_args()
330
331 # Check that time is positive
332 if args.runtime <= 0:
333 raise argparse.ArgumentTypeError(
334 "argument -t/--runtime: invalid choice: %r (choose a positive number greater than 0)"
335 % (args.runtime,)
336 )
337
338 # Set the log level
339 if args.info == 0:
340 ou.setLogLevel(ou.LOG_WARN)
341 elif args.info == 1:
342 ou.setLogLevel(ou.LOG_INFO)
343 elif args.info == 2:
344 ou.setLogLevel(ou.LOG_DEBUG)
345 else:
346 ou.OMPL_ERROR("Invalid log-level integer.")
347
348 # Solve the planning problem
349 plan(args.runtime, args.planner, args.objective, args.file)
350
351
Definition of a cost value. Can represent the cost of a motion or the cost of a state.
Definition Cost.h:48
This class allows for the definition of multiobjective optimal planning problems. Objectives are adde...
An optimization objective which corresponds to optimizing path length.
Definition of a problem to be solved. This includes the start state(s) for the system and a goal spec...
A state space representing Rn. The distance function is the L2 norm.
The base class for space information. This contains all the information about the space planning is d...
Defines optimization objectives where path cost can be represented as a path integral over a cost fun...
Abstract definition for a class checking the validity of states. The implementation of this class mus...
Asymptotically Optimal RRT-Connect.
Definition AORRTC.h:75
Bidirectional Asymptotically Optimal Fast Marching Tree algorithm developed by J. Starek,...
Definition BFMT.h:83
Batch Informed Trees (BIT*).
Definition BITstar.h:93
Asymptotically Optimal Fast Marching Tree algorithm developed by L. Janson and M. Pavone.
Definition FMT.h:91
PRM* planner.
Definition PRMstar.h:66
Optimal Rapidly-exploring Random Trees.
Definition RRTstar.h:75
std::function< Cost(const State *, const Goal *)> CostToGoHeuristic
The definition of a function which returns an admissible estimate of the optimal path cost from a giv...