Skip to content

Commit c0458e6

Browse files
authored
Remove fallback logic from motionplanning now that RRTstar has been removed (#5245)
1 parent a7715b2 commit c0458e6

File tree

2 files changed

+7
-106
lines changed

2 files changed

+7
-106
lines changed

motionplan/armplanning/plan_manager.go

Lines changed: 5 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,10 @@ import (
1919

2020
const (
2121
defaultOptimalityMultiple = 2.0
22-
defaultFallbackTimeout = 1.5
2322
defaultTPspaceOrientationScale = 500.
2423
)
2524

26-
// planManager is intended to be the single entry point to motion planners, wrapping all others, dealing with fallbacks, etc.
27-
// Intended information flow should be:
28-
// motionplan.PlanMotion() -> SolvableFrameSystem.SolveWaypointsWithOptions() -> planManager.planSingleWaypoint().
25+
// planManager is intended to be the single entry point to motion planners.
2926
type planManager struct {
3027
*planner // TODO: This should probably be removed
3128
// We store the request because we want to be able to inspect the original state of the plan
@@ -280,8 +277,7 @@ func (pm *planManager) planSingleAtomicWaypoint(
280277
return seed, &resultPromise{steps: planReturn.steps}, nil
281278
}
282279
} else {
283-
// This ctx is used exclusively for the running of the new planner and timing it out. It may be different from the main `ctx`
284-
// timeout due to planner fallbacks.
280+
// This ctx is used exclusively for the running of the new planner and timing it out.
285281
plannerctx, cancel := context.WithTimeout(ctx, time.Duration(wp.mp.opt().Timeout*float64(time.Second)))
286282
defer cancel()
287283
plan, err := wp.mp.plan(plannerctx, wp.startState, wp.goalState)
@@ -297,8 +293,7 @@ func (pm *planManager) planSingleAtomicWaypoint(
297293
}
298294
}
299295

300-
// planParallelRRTMotion will handle planning a single atomic waypoint using a parallel-enabled RRT solver. It will handle fallbacks
301-
// as necessary.
296+
// planParallelRRTMotion will handle planning a single atomic waypoint using a parallel-enabled RRT solver.
302297
func (pm *planManager) planParallelRRTMotion(
303298
ctx context.Context,
304299
wp atomicWaypoint,
@@ -308,7 +303,6 @@ func (pm *planManager) planParallelRRTMotion(
308303
) {
309304
pathPlanner := wp.mp.(rrtParallelPlanner)
310305
var rrtBackground sync.WaitGroup
311-
var err error
312306
if maps == nil {
313307
solutionChan <- &rrtSolution{err: errors.New("nil maps")}
314308
return
@@ -326,8 +320,7 @@ func (pm *planManager) planParallelRRTMotion(
326320
}
327321
}
328322

329-
// This ctx is used exclusively for the running of the new planner and timing it out. It may be different from the main `ctx` timeout
330-
// due to planner fallbacks.
323+
// This ctx is used exclusively for the running of the new planner and timing it out.
331324
plannerctx, cancel := context.WithTimeout(ctx, time.Duration(wp.mp.opt().Timeout*float64(time.Second)))
332325
defer cancel()
333326

@@ -340,7 +333,7 @@ func (pm *planManager) planParallelRRTMotion(
340333
pathPlanner.rrtBackgroundRunner(plannerctx, &rrtParallelPlannerShared{maps, endpointPreview, plannerChan})
341334
})
342335

343-
// Wait for results from the planner. This will also handle calling the fallback if needed, and will ultimately return the best path
336+
// Wait for results from the planner.
344337
select {
345338
case <-ctx.Done():
346339
// Error will be caught by monitoring loop
@@ -353,85 +346,15 @@ func (pm *planManager) planParallelRRTMotion(
353346
select {
354347
case finalSteps := <-plannerChan:
355348
// We didn't get a solution preview (possible error), so we get and process the full step set and error.
356-
357-
mapSeed := finalSteps.maps
358-
359-
// Create fallback planner
360-
var fallbackPlanner motionPlanner
361-
if pathPlanner.opt().Fallback != nil {
362-
//nolint: gosec
363-
fallbackPlanner, err = newMotionPlanner(
364-
pm.fs,
365-
rand.New(rand.NewSource(int64(pm.randseed.Int()))),
366-
pm.logger,
367-
pathPlanner.opt().Fallback,
368-
pm.ConstraintHandler,
369-
pm.motionChains,
370-
)
371-
if err != nil {
372-
fallbackPlanner = nil
373-
}
374-
}
375-
376-
// If there was no error, check path quality. If sufficiently good, move on.
377-
// If there *was* an error, then either the fallback will not error and will replace it, or the error will be returned
378-
if finalSteps.err == nil {
379-
if fallbackPlanner != nil {
380-
if ok, score := pm.goodPlan(finalSteps); ok {
381-
pm.logger.CDebugf(ctx, "got path with score %f, close enough to optimal %f", score, maps.optNode.Cost())
382-
fallbackPlanner = nil
383-
} else {
384-
pm.logger.CDebugf(ctx, "path with score %f not close enough to optimal %f, falling back", score, maps.optNode.Cost())
385-
386-
// If we have a connected but bad path, we recreate new IK solutions and start from scratch
387-
// rather than seeding with a completed, known-bad tree
388-
mapSeed = nil
389-
}
390-
}
391-
}
392-
393-
// Start smoothing before initializing the fallback plan. This allows both to run simultaneously.
394349
smoothChan := make(chan []node, 1)
395350
rrtBackground.Add(1)
396351
utils.PanicCapturingGo(func() {
397352
defer rrtBackground.Done()
398353
smoothChan <- pathPlanner.smoothPath(ctx, finalSteps.steps)
399354
})
400-
var alternateFuture *resultPromise
401-
402-
// Run fallback only if we don't have a very good path
403-
if fallbackPlanner != nil {
404-
fallbackWP := wp
405-
fallbackWP.mp = fallbackPlanner
406-
_, alternateFuture, err = pm.planSingleAtomicWaypoint(ctx, fallbackWP, mapSeed)
407-
if err != nil {
408-
alternateFuture = nil
409-
}
410-
}
411355

412356
// Receive the newly smoothed path from our original solve, and score it
413357
finalSteps.steps = <-smoothChan
414-
score := math.Inf(1)
415-
416-
if finalSteps.steps != nil {
417-
score = nodesToTrajectory(finalSteps.steps).EvaluateCost(wp.mp.getScoringFunction())
418-
}
419-
420-
// If we ran a fallback, retrieve the result and compare to the smoothed path
421-
if alternateFuture != nil {
422-
alternate, err := alternateFuture.result()
423-
if err == nil {
424-
// If the fallback successfully found a path, check if it is better than our smoothed previous path.
425-
// The fallback should emerge pre-smoothed, so that should be a non-issue
426-
altCost := nodesToTrajectory(alternate).EvaluateCost(wp.mp.getScoringFunction())
427-
if altCost < score {
428-
pm.logger.CDebugf(ctx, "replacing path with score %f with better score %f", score, altCost)
429-
finalSteps = &rrtSolution{steps: alternate}
430-
} else {
431-
pm.logger.CDebugf(ctx, "fallback path with score %f worse than original score %f; using original", altCost, score)
432-
}
433-
}
434-
}
435358

436359
solutionChan <- finalSteps
437360
return
@@ -624,22 +547,6 @@ func (pm *planManager) generateWaypoints(seedPlan motionplan.Plan, wpi int) ([]a
624547
return waypoints, nil
625548
}
626549

627-
// check whether the solution is within some amount of the optimal.
628-
func (pm *planManager) goodPlan(pr *rrtSolution) (bool, float64) {
629-
solutionCost := math.Inf(1)
630-
if pr.steps != nil {
631-
if pr.maps.optNode.Cost() <= 0 {
632-
return true, solutionCost
633-
}
634-
solutionCost = nodesToTrajectory(pr.steps).EvaluateCost(pm.scoringFunction)
635-
if solutionCost < pr.maps.optNode.Cost()*defaultOptimalityMultiple {
636-
return true, solutionCost
637-
}
638-
}
639-
640-
return false, solutionCost
641-
}
642-
643550
func (pm *planManager) planToRRTGoalMap(plan motionplan.Plan, goal atomicWaypoint) (*rrtMaps, error) {
644551
traj := plan.Trajectory()
645552
path := plan.Path()

motionplan/armplanning/planner_options.go

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,7 @@ type PlannerOptions struct {
183183
CollisionBufferMM float64 `json:"collision_buffer_mm"`
184184

185185
// The algorithm used for pathfinding along with any configurable settings for that algorithm. If this
186-
// object is not provided, motion planning will attempt to use RRT* and, in the event of failure
187-
// to find an acceptable path, it will fallback to cBiRRT.
186+
// object is not provided, motion planning will use cBiRRT. If you have a 2d base, set this to TPSpace.
188187
PlanningAlgorithmSettings AlgorithmSettings `json:"planning_algorithm_settings"`
189188

190189
// The random seed used by motion algorithms during planning. This parameter guarantees deterministic
@@ -198,11 +197,6 @@ type PlannerOptions struct {
198197
// Setting indicating that all mesh geometries should be converted into octrees.
199198
MeshesAsOctrees bool `json:"meshes_as_octrees"`
200199

201-
// A set of fallback options to use on initial planning failure. This is used to facilitate the default
202-
// behavior described above in the comment for `PlanningAlgorithmSettings`. This will be populated
203-
// automatically if needed and is not meant to be set by users of the library.
204-
Fallback *PlannerOptions `json:"fallback_options"`
205-
206200
// For inverse kinematics, the time within which each pending solution must finish its computation is
207201
// a multiple of the time taken to compute the first solution. This parameter is a way to
208202
// set that multiplicative factor.
@@ -233,7 +227,7 @@ func NewPlannerOptionsFromExtra(extra map[string]interface{}) (*PlannerOptions,
233227

234228
// Returns an updated PlannerOptions taking into account whether TP-Space is being used and whether
235229
// a Free or Position-Only motion profile was requested with an unspecified algorithm (indicating the desire
236-
// to let motionplan handle what algorithm to use and allow for a fallback).
230+
// to let motionplan handle what algorithm to use).
237231
func updateOptionsForPlanning(opt *PlannerOptions, useTPSpace bool) (*PlannerOptions, error) {
238232
optCopy := *opt
239233
planningAlgorithm := optCopy.PlanningAlgorithm()

0 commit comments

Comments
 (0)