Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
8cf9c77
Feed live IK solutions to cbirrt. Add request file that does not prod…
dgottlieb Oct 16, 2025
57f0a96
Clean up rudimentary working algorithm.
dgottlieb Oct 17, 2025
cfb4b52
revert noisy debugging
dgottlieb Oct 17, 2025
073b392
fix log line
dgottlieb Oct 17, 2025
cfe0bd5
merge in main
dgottlieb Nov 9, 2025
3197835
update scene with Inputs API change
dgottlieb Nov 9, 2025
0ea3e16
Merge remote-tracking branch 'origin/main' into live-ik-solutions-to-…
dgottlieb Nov 10, 2025
6f3579b
delete scene that is no longer relevant
dgottlieb Nov 10, 2025
111bba2
remove node names
dgottlieb Nov 11, 2025
48c50ef
lint
dgottlieb Nov 11, 2025
4ff7b6f
Revert "remove node names"
dgottlieb Nov 12, 2025
dedf5c2
merge in main
dgottlieb Nov 12, 2025
b9c464c
to match default performance, change plan max IK solutions to 10
dgottlieb Nov 12, 2025
aa739b8
More efficient waiting
dgottlieb Nov 12, 2025
80cd13f
further optimize IK cleanup waiting. batch at the end of plan manager…
dgottlieb Nov 12, 2025
4b22174
lint
dgottlieb Nov 12, 2025
49aa7f6
move debug output execution such that it waits for dependent input to…
dgottlieb Nov 12, 2025
55074ae
lint
dgottlieb Nov 12, 2025
1374f4b
lint
dgottlieb Nov 12, 2025
2f1937c
check channel close
dgottlieb Nov 12, 2025
1248e93
I was wrong, needed a copy
dgottlieb Nov 13, 2025
f48a693
move to safe spot
dgottlieb Nov 13, 2025
5e3793c
actually have "not mine" be true
dgottlieb Nov 13, 2025
c05f441
lint
dgottlieb Nov 13, 2025
d218331
Test joint to joint code paths.
dgottlieb Nov 13, 2025
d7a8613
and...add the test file
dgottlieb Nov 13, 2025
c5d8f8d
feedback
dgottlieb Nov 17, 2025
5c53c1c
remove max solutions
dgottlieb Nov 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 29 additions & 18 deletions motionplan/armplanning/cBiRRT.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,11 @@ func newCBiRRTMotionPlanner(ctx context.Context, pc *planContext, psc *planSegme

// only used for testin.
func (mp *cBiRRTMotionPlanner) planForTest(ctx context.Context) ([]referenceframe.FrameSystemInputs, error) {
initMaps, err := initRRTSolutions(ctx, mp.psc)
initMaps, bgGen, err := initRRTSolutions(ctx, mp.psc)
if err != nil {
return nil, err
}
bgGen.StopAndWait() // Assume initial solutions are good enough.

x := []referenceframe.FrameSystemInputs{mp.psc.start}

Expand All @@ -71,7 +72,7 @@ func (mp *cBiRRTMotionPlanner) planForTest(ctx context.Context) ([]referencefram
return x, nil
}

solution, err := mp.rrtRunner(ctx, initMaps.maps)
solution, err := mp.rrtRunner(ctx, initMaps.maps, bgGen)
if err != nil {
return nil, err
}
Expand All @@ -84,21 +85,19 @@ func (mp *cBiRRTMotionPlanner) planForTest(ctx context.Context) ([]referencefram
func (mp *cBiRRTMotionPlanner) rrtRunner(
ctx context.Context,
rrtMaps *rrtMaps,
bgSolutionGenerator *backgroundGenerator,
) (*rrtSolution, error) {
ctx, span := trace.StartSpan(ctx, "rrtRunner")
defer span.End()

mp.pc.logger.CDebugf(ctx, "starting cbirrt with start map len %d and goal map len %d\n", len(rrtMaps.startMap), len(rrtMaps.goalMap))
mp.pc.logger.CDebugf(ctx, "starting cbirrt with start map len %d and goal map len %d", len(rrtMaps.startMap), len(rrtMaps.goalMap))

// setup planner options
if mp.pc.planOpts == nil {
return nil, errNoPlannerOptions
}

_, cancel := context.WithCancel(ctx)
defer cancel()
startTime := time.Now()

var seed referenceframe.FrameSystemInputs

// initialize maps
Expand All @@ -109,10 +108,9 @@ func (mp *cBiRRTMotionPlanner) rrtRunner(
break
}
}
mp.pc.logger.CDebugf(ctx, "goal node: %v\n", rrtMaps.optNode.inputs)
mp.pc.logger.CDebugf(ctx, "start node: %v\n", seed)
mp.pc.logger.Debug("DOF", mp.pc.lfs.dof)

mp.pc.logger.CDebugf(ctx, "start node: %v goal node name: %v inputs: %v DOF: %v",
seed, rrtMaps.optNode.name, rrtMaps.optNode.inputs, mp.pc.lfs.dof)
interpConfig, err := referenceframe.InterpolateFS(mp.pc.fs, seed, rrtMaps.optNode.inputs, 0.5)
if err != nil {
return nil, err
Expand All @@ -121,21 +119,35 @@ func (mp *cBiRRTMotionPlanner) rrtRunner(
target := newConfigurationNode(interpConfig)

map1, map2 := rrtMaps.startMap, rrtMaps.goalMap
for i := 0; i < mp.pc.planOpts.PlanIter; i++ {
mp.pc.logger.CDebugf(ctx, "iteration: %d target: %v\n", i, target.inputs)
for iterNum := 0; iterNum < mp.pc.planOpts.PlanIter; iterNum++ {
if ctx.Err() != nil {
mp.pc.logger.CDebugf(ctx, "CBiRRT timed out after %d iterations", i)
mp.pc.logger.CDebugf(ctx, "CBiRRT timed out after %d iterations", iterNum)
return &rrtSolution{maps: rrtMaps}, fmt.Errorf("cbirrt timeout %w", ctx.Err())
}
mp.pc.logger.CDebugf(ctx, "iteration: %d target: %v target name: %v", iterNum, target.inputs, target.name)

if iterNum%20 == 0 {
// We continue to generate IK solutions in the background. New candidates can only
// succeed if given some time. Hence we will pull on a reduced cadence.
select {
case newGoal := <-bgSolutionGenerator.newSolutionsCh:
mp.pc.logger.CDebugf(ctx, "Added new goal while birrting. Goal: %v GoalName: %v", newGoal.inputs, newGoal.name)
rrtMaps.goalMap[newGoal] = nil

// Readjust the target to give the new solution a chance to succeed.
target, err = mp.sample(newGoal, iterNum)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the "unexpected" part of adding live IK solutions to cbirrt. Without this step of re-assigning the target, I was never able to see a new solution succeed at getting picked.

But if we do this too often, we waste time not advancing existing solutions. Some of which are probably perfectly fine. Hence the iterNum%20 at the top of the conditional.

Mostly just need feedback on whether this general idea is acceptable (for now) @erh or if I should be doing something substantially different here.

default:
}
}

tryExtend := func(target *node) (*node, *node) {
// attempt to extend maps 1 and 2 towards the target

nearest1 := nearestNeighbor(target, map1, nodeConfigurationDistanceFunc)
nearest2 := nearestNeighbor(target, map2, nodeConfigurationDistanceFunc)

map1reached := mp.constrainedExtend(ctx, i, map1, nearest1, target)
map2reached := mp.constrainedExtend(ctx, i, map2, nearest2, target)
map1reached := mp.constrainedExtend(ctx, iterNum, map1, nearest1, target)
map2reached := mp.constrainedExtend(ctx, iterNum, map2, nearest2, target)

map1reached.corner = true
map2reached.corner = true
Expand Down Expand Up @@ -169,14 +181,13 @@ func (mp *cBiRRTMotionPlanner) rrtRunner(

// Solved!
if reachedDelta <= mp.pc.planOpts.InputIdentDist {
mp.pc.logger.CDebugf(ctx, "CBiRRT found solution after %d iterations in %v", i, time.Since(startTime))
cancel()
mp.pc.logger.CDebugf(ctx, "CBiRRT found solution after %d iterations in %v", iterNum, time.Since(startTime))
path := extractPath(rrtMaps.startMap, rrtMaps.goalMap, &nodePair{map1reached, map2reached}, true)
return &rrtSolution{steps: path, maps: rrtMaps}, nil
}

// sample near map 1 and switch which map is which to keep adding to them even
target, err = mp.sample(map1reached, i)
target, err = mp.sample(map1reached, iterNum)
if err != nil {
return &rrtSolution{maps: rrtMaps}, err
}
Expand Down Expand Up @@ -254,7 +265,7 @@ func (mp *cBiRRTMotionPlanner) constrainedExtend(
doubled = false
}
// constrainNear will ensure path between oldNear and newNear satisfies constraints along the way
near = &node{inputs: newNear}
near = &node{name: int(nodeNameCounter.Add(1)), inputs: newNear}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not intended to be part of the final solution. But I found giving nodes a "name" to be useful. To verify, for instance, whether the goal node we eventually reached was a pregenerted IK solution or a live one fed midway.

rrtMap[near] = oldNear
}
return oldNear
Expand Down
3 changes: 2 additions & 1 deletion motionplan/armplanning/cBiRRT_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ func TestSimpleLinearMotion(t *testing.T) {

mp, err := newCBiRRTMotionPlanner(ctx, pc, psc)
test.That(t, err, test.ShouldBeNil)
solutions, err := getSolutions(ctx, psc)
solutions, bgGen, err := getSolutions(ctx, psc)
bgGen.StopAndWait() // Original solutions must be good enough.
test.That(t, err, test.ShouldBeNil)

near1 := &node{inputs: referenceframe.FrameSystemInputs{m.Name(): home7}}
Expand Down
2 changes: 2 additions & 0 deletions motionplan/armplanning/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ type planSegmentContext struct {

motionChains *motionChains
checker *motionplan.ConstraintChecker

continueGeneratingSolutions bool
}

func newPlanSegmentContext(ctx context.Context, pc *planContext, start referenceframe.FrameSystemInputs,
Expand Down
Loading
Loading