Skip to content

Drop a held tail instead of appending a duplicate end knot - #726

Open
Yuan-Xinyi wants to merge 1 commit into
feat/differentiable-topprafrom
xinyi/toppra-drop-held-tail
Open

Yuan-Xinyi wants to merge 1 commit into
feat/differentiable-topprafrom
xinyi/toppra-drop-held-tail

Conversation

@Yuan-Xinyi

Copy link
Copy Markdown
Collaborator

Stack

Description

#724 keeps the previous waypoint cleanup exactly, including its final step: when the last sample was merged as a duplicate, it is appended again. A path that ends in repeated samples therefore keeps a zero-length last segment. The not-a-knot spline bends back through it, and because the knot count changes, every knot's uniform spacing changes too — the whole curve moves, not just the tail.

That tail is exactly what a batched NMG rollout produces: an environment that converges early holds its pose while the others finish. With the current cleanup, an environment's retimed trajectory depends on which other environments share its batch.

This PR moves the last kept knot onto the final sample instead of appending it, in both the NumPy reference (_toppra.py) and the Warp preparation kernel (_warp/toppra.py), so the two stay identical. Two edge cases are kept deliberately:

Dependencies: none.

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Measured evidence

A real NMG rollout (7 samples, Franka FR3 limits), retimed alone and with four held samples appended, on #724 as-is and with this change:

knots kept duration, alone duration, held tail
#724 7 → 8 0.9933 s 1.0553 s (+6.2%)
this PR 7 → 7 0.9933 s 0.9933 s

NumPy and Warp agree to 1e-15 in both cases.

The one-joint case [0.3, 0.3, 0.5, 0.5] shows the mechanism directly. #724 keeps three knots; the not-a-knot fit through them is a parabola that overshoots the goal to 0.525 before returning. With this change it keeps two and moves monotonically to 0.5.

one problem retimed alone and inside a batch

Measured before #724 with the external toppra package, which had the same cleanup: dashed is the same problem inside a batch, solid is the problem alone. After about 0.75 s the batched trajectory departs, gains an extra reversal before the goal, and ends 60 ms later. #724 reproduces the same knot list, so it reproduces this.

Validation

  • pytest tests/compute/test_toppra.py tests/sim/motion/planners/test_toppra_batched.py --run-gpu — 97 passed.
  • pytest tests/compute/ tests/sim/motion/ — 1151 passed, 111 skipped.
  • New tests: a held tail leaves the duration, sampled positions and fitted path unchanged, at the reference, Warp (CPU and CUDA) and planner levels; and the [0.3, 0.3, 0.5, 0.5] case no longer reverses. Four of them fail on Replace external TOPPRA with differentiable CPU/CUDA retiming #724 as-is.
  • test_legacy_waypoint_cleanup_preserves_spline_geometry fixed the old knot list; its held-tail case now expects [0, 3] instead of [0, 2, 3], it gains a move-then-hold case, and it is renamed for what it now checks. The other cases are unchanged.
  • black . — clean. check_api_docs.py — aligned, no public API change. context.py check — ok; planner-details.md no longer says the final knot is preserved and states the held-tail rule instead.

Checklist

  • I have run the black . command to format the code base.
  • I reviewed affected documentation and agent context, updated it where needed, or explained why no update was needed.
  • Public API changes are reflected in the API docs (python docs/scripts/check_api_docs.py), if applicable
  • I have added tests that prove my fix is effective or that my feature works
  • Dependencies have been updated, if applicable. No dependency changes were required.

🤖 Generated with Claude Code

Waypoint cleanup merged samples within 1e-6, then appended the final sample
whenever it had been merged. A path ending in repeated samples therefore kept
a zero-length last segment: the not-a-knot fit bends back through it, and
because the knot count changes, every knot's uniform spacing changes too.

That tail is what a batched NMG rollout produces for an environment that
converges early and holds its pose while the others finish. Retiming one such
rollout alone and with four held samples appended:

    before   0.9933 s -> 1.0553 s  (+6.2%), with a reversal before the goal
    after    identical duration and samples

so an environment's trajectory depended on which environments shared its
batch. The simplest case shows the reversal directly: [0.3, 0.3, 0.5, 0.5]
kept three knots and the fitted parabola overshot 0.5 to 0.525 before
returning; it now keeps two and moves monotonically.

When the tail is merged, move the last kept knot onto the final sample instead
of appending it, in both the NumPy reference and the Warp preparation kernel.
A lone first point still gains the final sample when they differ at all, so a
tiny move keeps a positive duration, and an all-identical row stays stationary.

The test that fixed the old knot list is updated for the one case it covered,
and new tests check that a held tail leaves the duration, samples and path
unchanged at the reference, Warp and planner levels, and that the tail no
longer reverses. They fail before this change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Yuan-Xinyi Yuan-Xinyi added bug Something isn't working motion gen Things related to motion generation for robot labels Sep 29, 2026
@greptile-apps

greptile-apps Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Medium risk] Changes trajectory path deduplication logic in motion planning.

The PR appears safe to merge; no actionable regression was identified.

Summary

The PR changes NumPy and Warp waypoint cleanup to replace the last retained knot with a held final sample instead of adding a duplicate end segment.

  • Adds reference, Warp, and planner-level coverage for held tails.
  • Updates motion-planning context to describe the new behavior.

Reviews (1) · Last reviewed commit: "fix(compute): drop a held tail instead o..."

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working motion gen Things related to motion generation for robot

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant