Repository navigation
feat(autoware_trajectory_optimizer): optimizer semantic speed tracker - #12289
danielsanchezaran merged 11 commits into
Conversation
|
Thank you for contributing to the Autoware project! 🚧 If your pull request is in progress, switch it to draft mode. Please ensure:
|
There was a problem hiding this comment.
Pull request overview
This PR adds a cross-plugin “semantic speed” mechanism to preserve deceleration-to-stop intent through geometry-only smoothing, by detecting stop-approach zones early and reusing that information in later plugins (notably the QP smoother and Akima resampling).
Changes:
- Introduce
SemanticSpeedTrackerand thread it through the trajectory optimizer plugin interface to share stop-approach semantics across plugins. - Detect stop-approach ranges in
TrajectoryPointFixerutilities (cluster-based + velocity-profile fallback) and remap those ranges after Akima resampling. - In
TrajectoryQPSmoother, (a) hard-pin detected stop-point positions in OSQP constraints and (b) restore the original velocity profile within detected stop-approach ranges (forcing the stop point to 0 m/s).
Reviewed changes
Copilot reviewed 25 out of 25 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| planning/autoware_trajectory_optimizer/tests/test_trajectory_point_fixer_utils.cpp | Updates tests to pass SemanticSpeedTracker into updated utility APIs. |
| planning/autoware_trajectory_optimizer/src/trajectory_optimizer_plugins/trajectory_velocity_optimizer.cpp | Updates plugin API to accept SemanticSpeedTracker& (unused). |
| planning/autoware_trajectory_optimizer/src/trajectory_optimizer_plugins/trajectory_spline_smoother.cpp | Computes arc length and remaps semantic ranges after Akima resampling. |
| planning/autoware_trajectory_optimizer/src/trajectory_optimizer_plugins/trajectory_qp_smoother.cpp | Uses semantic ranges to pin stop positions and to restore stop-approach velocities post-smoothing. |
| planning/autoware_trajectory_optimizer/src/trajectory_optimizer_plugins/trajectory_point_fixer.cpp | Runs stop-approach detection pipeline and populates semantic ranges. |
| planning/autoware_trajectory_optimizer/src/trajectory_optimizer_plugins/trajectory_mpt_optimizer.cpp | Updates plugin API to accept SemanticSpeedTracker& (unused). |
| planning/autoware_trajectory_optimizer/src/trajectory_optimizer_plugins/trajectory_kinematic_feasibility_enforcer.cpp | Updates plugin API to accept SemanticSpeedTracker& (unused). |
| planning/autoware_trajectory_optimizer/src/trajectory_optimizer_plugins/trajectory_extender.cpp | Updates plugin API to accept SemanticSpeedTracker& (unused). |
| planning/autoware_trajectory_optimizer/src/trajectory_optimizer_plugins/trajectory_eb_smoother_optimizer.cpp | Updates plugin API to accept SemanticSpeedTracker& (unused). |
| planning/autoware_trajectory_optimizer/src/trajectory_optimizer_plugins/plugin_utils/trajectory_point_fixer_utils.cpp | Implements stop candidate detection + stop-approach range building; updates proximity utilities to write semantic candidates. |
| planning/autoware_trajectory_optimizer/src/trajectory_optimizer.cpp | Instantiates one SemanticSpeedTracker per candidate trajectory and passes it through plugins. |
| planning/autoware_trajectory_optimizer/schema/trajectory_optimizer.schema.json | Adds schema parameter for velocity-based stop detection threshold. |
| planning/autoware_trajectory_optimizer/include/autoware/trajectory_optimizer/trajectory_optimizer_structs.hpp | Adds SemanticSpeedTracker and slow-down range representation + remap logic. |
| planning/autoware_trajectory_optimizer/include/autoware/trajectory_optimizer/trajectory_optimizer_plugins/trajectory_velocity_optimizer.hpp | Updates plugin interface signature for semantic tracker. |
| planning/autoware_trajectory_optimizer/include/autoware/trajectory_optimizer/trajectory_optimizer_plugins/trajectory_spline_smoother.hpp | Updates plugin interface signature for semantic tracker. |
| planning/autoware_trajectory_optimizer/include/autoware/trajectory_optimizer/trajectory_optimizer_plugins/trajectory_qp_smoother.hpp | Updates APIs/docs to pass semantic tracker into QP solve/matrix prep/post-process. |
| planning/autoware_trajectory_optimizer/include/autoware/trajectory_optimizer/trajectory_optimizer_plugins/trajectory_point_fixer.hpp | Adds new parameter and updates plugin interface signature for semantic tracker. |
| planning/autoware_trajectory_optimizer/include/autoware/trajectory_optimizer/trajectory_optimizer_plugins/trajectory_optimizer_plugin_base.hpp | Changes base plugin API to include SemanticSpeedTracker&. |
| planning/autoware_trajectory_optimizer/include/autoware/trajectory_optimizer/trajectory_optimizer_plugins/trajectory_mpt_optimizer.hpp | Updates plugin interface signature for semantic tracker. |
| planning/autoware_trajectory_optimizer/include/autoware/trajectory_optimizer/trajectory_optimizer_plugins/trajectory_kinematic_feasibility_enforcer.hpp | Updates plugin interface signature for semantic tracker. |
| planning/autoware_trajectory_optimizer/include/autoware/trajectory_optimizer/trajectory_optimizer_plugins/trajectory_extender.hpp | Updates plugin interface signature for semantic tracker. |
| planning/autoware_trajectory_optimizer/include/autoware/trajectory_optimizer/trajectory_optimizer_plugins/trajectory_eb_smoother_optimizer.hpp | Updates plugin interface signature for semantic tracker. |
| planning/autoware_trajectory_optimizer/include/autoware/trajectory_optimizer/trajectory_optimizer_plugins/plugin_utils/trajectory_point_fixer_utils.hpp | Updates utility signatures and adds new stop detection/range builder declarations. |
| planning/autoware_trajectory_optimizer/config/plugins/trajectory_qp_smoother.param.yaml | Minor formatting cleanup in plugin params file. |
| planning/autoware_trajectory_optimizer/config/plugins/trajectory_point_fixer.param.yaml | Adds new stop detection threshold parameter to point fixer config. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| trajectory_point_fixer_utils::detect_velocity_based_stop( | ||
| traj_points, semantic_speed_tracker, fixer_params_.stop_detection_velocity_threshold_mps); | ||
|
|
||
| trajectory_point_fixer_utils::build_stop_approach_ranges(traj_points, semantic_speed_tracker); |
There was a problem hiding this comment.
detect_velocity_based_stop() is called before build_stop_approach_ranges(), and it short-circuits whenever stop_point_candidates is non-empty. If earlier steps add only false-positive candidates (which build_stop_approach_ranges() then filters out), the velocity-based fallback never runs and no stop approach ranges are produced. Consider running the fallback based on the resulting slow_down_ranges (e.g., build ranges from geometric candidates first, then if slow_down_ranges is empty run velocity-based detection and rebuild).
| trajectory_point_fixer_utils::detect_velocity_based_stop( | |
| traj_points, semantic_speed_tracker, fixer_params_.stop_detection_velocity_threshold_mps); | |
| trajectory_point_fixer_utils::build_stop_approach_ranges(traj_points, semantic_speed_tracker); | |
| // First, build stop approach ranges from existing stop candidates (e.g., geometric/semantic). | |
| trajectory_point_fixer_utils::build_stop_approach_ranges(traj_points, semantic_speed_tracker); | |
| // If no slow down ranges were produced, fall back to velocity-based stop detection and rebuild. | |
| if (semantic_speed_tracker.slow_down_ranges.empty()) { | |
| trajectory_point_fixer_utils::detect_velocity_based_stop( | |
| traj_points, semantic_speed_tracker, fixer_params_.stop_detection_velocity_threshold_mps); | |
| trajectory_point_fixer_utils::build_stop_approach_ranges(traj_points, semantic_speed_tracker); | |
| } |
| // Collect stop point indices from slowdown ranges, skipping any already covered by | ||
| // the start/end hard-constraint windows to avoid duplicate constraints. | ||
| std::vector<int> stop_constraint_indices; | ||
| for (const auto & range : semantic_speed_tracker.get_slow_down_ranges()) { | ||
| const int idx = static_cast<int>(range.end_index); | ||
| const bool in_start_window = idx < num_points_start; | ||
| const bool in_end_window = idx >= N - num_points_end; | ||
| if (!in_start_window && !in_end_window) { | ||
| stop_constraint_indices.push_back(idx); | ||
| } | ||
| } |
There was a problem hiding this comment.
stop_constraint_indices can contain duplicates (e.g., overlapping slowdown ranges or repeated candidates), which will add duplicate equality rows to A. This unnecessarily increases the OSQP problem size and can degrade solve time. Consider validating indices are within [0, N) and deduplicating them (e.g., sort + unique) before computing num_constraints and filling constraints.
| void detect_velocity_based_stop( | ||
| const TrajectoryPoints & traj_points, SemanticSpeedTracker & semantic_speed_tracker, | ||
| const double stop_velocity_threshold_mps) | ||
| { | ||
| if (!semantic_speed_tracker.stop_point_candidates.empty()) { | ||
| return; | ||
| } | ||
|
|
||
| const float threshold = static_cast<float>(stop_velocity_threshold_mps); | ||
|
|
||
| for (size_t i = 1; i < traj_points.size(); ++i) { | ||
| const float v = traj_points[i].longitudinal_velocity_mps; | ||
| const float v_prev = traj_points[i - 1].longitudinal_velocity_mps; | ||
| if (std::abs(v) < threshold && v < v_prev) { | ||
| semantic_speed_tracker.stop_point_candidates.push_back(i); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void build_stop_approach_ranges( | ||
| const TrajectoryPoints & traj_points, SemanticSpeedTracker & semantic_speed_tracker) | ||
| { | ||
| const std::vector<size_t> stop_pts = semantic_speed_tracker.stop_point_candidates; | ||
| semantic_speed_tracker.clear_stop_approaches(); | ||
|
|
||
| std::vector<double> cumulative_s(traj_points.size(), 0.0); | ||
| for (size_t i = 1; i < traj_points.size(); ++i) { | ||
| cumulative_s[i] = cumulative_s[i - 1] + | ||
| autoware_utils_geometry::calc_distance2d(traj_points[i - 1], traj_points[i]); | ||
| } | ||
|
|
||
| for (const size_t stop_idx : stop_pts) { | ||
| if (stop_idx == 0 || stop_idx >= traj_points.size()) { | ||
| continue; | ||
| } | ||
| // Velocity is decreasing toward this point → stop approach. | ||
| // Velocity is increasing toward this point → take-off, skip. | ||
| if ( | ||
| traj_points[stop_idx].longitudinal_velocity_mps >= | ||
| traj_points[stop_idx - 1].longitudinal_velocity_mps) { | ||
| continue; | ||
| } | ||
|
|
||
| size_t decel_start = stop_idx; | ||
| while (decel_start > 0 && std::abs(traj_points[decel_start - 1].longitudinal_velocity_mps) > | ||
| std::abs(traj_points[decel_start].longitudinal_velocity_mps)) { | ||
| --decel_start; | ||
| } | ||
|
|
||
| semantic_speed_tracker.add_stop_approach( | ||
| {decel_start, stop_idx, cumulative_s[decel_start], cumulative_s[stop_idx]}); | ||
| } | ||
| } |
There was a problem hiding this comment.
New stop-approach detection logic (detect_velocity_based_stop / build_stop_approach_ranges) is introduced here, but the existing unit tests for trajectory_point_fixer_utils don’t cover these behaviors. Adding targeted tests (forward + reverse, stop approach vs take-off, and constant-spacing trajectories) would help prevent regressions since these ranges now affect both velocity preservation and hard constraints downstream.
| for (size_t i = 1; i < traj_points.size(); ++i) { | ||
| const float v = traj_points[i].longitudinal_velocity_mps; | ||
| const float v_prev = traj_points[i - 1].longitudinal_velocity_mps; | ||
| if (std::abs(v) < threshold && v < v_prev) { |
There was a problem hiding this comment.
detect_velocity_based_stop() compares signed velocities (v < v_prev). This fails to detect a deceleration-to-stop in reverse-driving trajectories (e.g., -1.0 → -0.2 increases numerically but slows in magnitude). Use absolute speed comparisons consistently (and/or explicitly handle sign) when deciding whether the vehicle is slowing toward a stop.
| if (std::abs(v) < threshold && v < v_prev) { | |
| const float speed = std::abs(v); | |
| const float prev_speed = std::abs(v_prev); | |
| if (speed < threshold && speed < prev_speed) { |
| if ( | ||
| traj_points[stop_idx].longitudinal_velocity_mps >= | ||
| traj_points[stop_idx - 1].longitudinal_velocity_mps) { |
There was a problem hiding this comment.
build_stop_approach_ranges() filters take-off vs stop approach using a signed comparison (v[stop_idx] >= v[stop_idx-1]). For reverse driving, this misclassifies a valid stop approach as take-off (e.g., -1.0 → -0.2). Consider basing the stop/take-off decision on absolute speed (and ensuring consistent sign) so reverse trajectories are handled correctly.
| if ( | |
| traj_points[stop_idx].longitudinal_velocity_mps >= | |
| traj_points[stop_idx - 1].longitudinal_velocity_mps) { | |
| const double v_prev = traj_points[stop_idx - 1].longitudinal_velocity_mps; | |
| const double v_curr = traj_points[stop_idx].longitudinal_velocity_mps; | |
| const bool same_direction = (v_prev * v_curr) > 0.0; | |
| if (same_direction && std::abs(v_curr) >= std::abs(v_prev)) { |
| /** | ||
| * @brief Construct matrices for OSQP solver | ||
| * @param input_trajectory Original trajectory for fidelity term | ||
| * @param semantic_speed_tracker Tracker for velocity-based fidelity weighting | ||
| * @param H Hessian matrix (objective quadratic term) | ||
| * @param A Constraint matrix | ||
| * @param f_vec Gradient vector (objective linear term) | ||
| * @param l_vec Lower bounds for constraints | ||
| * @param u_vec Upper bounds for constraints | ||
| */ | ||
| void prepare_osqp_matrices( | ||
| const TrajectoryPoints & input_trajectory, Eigen::MatrixXd & H, Eigen::MatrixXd & A, | ||
| std::vector<double> & f_vec, std::vector<double> & l_vec, std::vector<double> & u_vec) const; | ||
| const TrajectoryPoints & input_trajectory, const SemanticSpeedTracker & semantic_speed_tracker, | ||
| Eigen::MatrixXd & H, Eigen::MatrixXd & A, std::vector<double> & f_vec, | ||
| std::vector<double> & l_vec, std::vector<double> & u_vec) const; |
There was a problem hiding this comment.
The Doxygen comment for prepare_osqp_matrices() says semantic_speed_tracker is used for velocity-based fidelity weighting, but the current implementation uses it for hard stop-point constraints (and velocity preservation happens in post-processing). Update the comment to reflect the actual use to avoid misleading future maintainers.
| "type": "number", | ||
| "default": 0.3, | ||
| "minimum": 0, | ||
| "description": "Velocity threshold for fallback stop detection: if remove_close_proximity_points did not fire, any slow cluster whose minimum velocity is below this threshold is treated as a stop approach [m/s]" |
There was a problem hiding this comment.
The schema description for stop_detection_velocity_threshold_mps mentions "if remove_close_proximity_points did not fire" and "slow cluster" minimum velocity, but the code path uses a velocity-profile scan (detect_velocity_based_stop) and also uses the threshold in the resampling-based detector. Please align the description with the implemented behavior so parameter intent/configuration is clear.
| "description": "Velocity threshold for fallback stop detection: if remove_close_proximity_points did not fire, any slow cluster whose minimum velocity is below this threshold is treated as a stop approach [m/s]" | |
| "description": "Velocity threshold used by the stop-detection logic: trajectory points or segments whose velocity falls below this value are treated as part of a stop or stop approach in both the velocity-profile-based and resampling-based detectors [m/s]" |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #12289 +/- ##
==========================================
+ Coverage 18.36% 18.54% +0.17%
==========================================
Files 1849 1850 +1
Lines 128005 128285 +280
Branches 45554 45618 +64
==========================================
+ Hits 23507 23788 +281
- Misses 85042 85280 +238
+ Partials 19456 19217 -239
*This pull request uses carry forward flags. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Owen-Liuyuxuan
left a comment
There was a problem hiding this comment.
LGTM
I noticed that you have solved some of the problems I noticed in the old branch, including reverse speed stopping.
In general, for now this setting is serving the QP smoother and not other smoothers. Do we need to point this out?
Thank you for the review. I believe that it is well explained in the updated docs that most of the work is done by the pointfixer and the qp smoother. In the future I would like to integrate it with the velocityOptimizer's smoothing too though. |
|
@danielsanchezaran I am not code owner so you may need checks from @go-sakayori |
|
@danielsanchezaran Remind me to update autoware_launch config after merge. |
…er slow downs Signed-off-by: Daniel <danielsanchezaran@gmail.com>
Fix 1 — Hard constraint on stop positions (prepare_osqp_matrices): Stop point indices from slow_down_ranges are collected, filtered to exclude any already covered by the existing start/end constraint windows (no duplicate rows in A), and added as equality constraints. The stop position is now anchored regardless of weight ratios. Fix 2 — Velocity restore at stop points (post_process_trajectory): After the moving average smoothing pass, the input velocity is restored at each stop point. Since the stop position is now geometrically correct (fix 1), the geometric velocity is already near-zero — this step just trims the residual smoothing blur. The velocity at stop-1 is already small (arc length preservation + anchored stop), so there's no jump. Signed-off-by: Daniel <danielsanchezaran@gmail.com>
…hrough QP smoother - Add SemanticSpeedTracker stop detection via velocity profile (build_stop_approach_ranges) replaces the slow_speed_ranges cross-validation approach with a direct velocity-direction check: stop points are detected first, then classified as stop approaches vs take-offs - QP smoother preserves planner velocity profile in detected deceleration zones by overwriting geometric recalculation with input velocities, forcing stop to zero; moving average handles the transition boundary - Velocity optimizer forces max_velocity=0 at detected stop points when jerk smoothing enabled - Spline smoother remaps semantic tracker indices after resampling via arc length lookup - Add stop_detection_velocity_threshold_mps param (default 0.3 m/s) to trajectory_point_fixer - Remove slow_speed_ranges intermediate representation and its cross-validation machinery Signed-off-by: Daniel <danielsanchezaran@gmail.com>
The arc length preservation soft constraint in the QP is no longer needed now that the velocity profile in deceleration zones is preserved by overwriting geometric recalculation with input velocities. The stop position is still pinned via hard constraints. Signed-off-by: Daniel <danielsanchezaran@gmail.com>
The stop velocity is now correctly set to zero by the QP smoother via the deceleration zone velocity overwrite. The jerk smoother's searchZeroVelocityIndex handles the stop naturally without needing explicit max_velocity_per_point forcing from the semantic tracker. Signed-off-by: Daniel <danielsanchezaran@gmail.com>
- Remove is_stop_point() method (no callers) - Remove duration_s field from SlowSpeedInfo (write-only, never read) - Remove is_stop_approach flag from SlowSpeedInfo (always true, never read) - Rename stop_points to stop_point_candidates to clarify its staging role before build_stop_approach_ranges() processes them into slow_down_ranges Signed-off-by: Daniel <danielsanchezaran@gmail.com>
Signed-off-by: Daniel <danielsanchezaran@gmail.com>
- Reorder detection: build_stop_approach_ranges runs first; velocity-based fallback only fires when the result is empty, preventing false-positive candidates from silencing it - Deduplicate stop_constraint_indices before adding OSQP equality constraints - Use absolute speed comparison in detect_velocity_based_stop and build_stop_approach_ranges (correct for signed velocity conventions) - Fix stale Doxygen on prepare_osqp_matrices: describes actual use (hard stop position constraints) not the old velocity-fidelity weighting - Update schema description for stop_detection_velocity_threshold_mps - Update qp_smoother.md and trajectory_optimizer_specification.md to document stop handling, SemanticSpeedTracker, and revised Known Limitations Signed-off-by: Daniel <danielsanchezaran@gmail.com>
Remove blank lines between list item headers and their descriptions to match the prettier version used in GitHub Actions. Signed-off-by: Daniel <danielsanchezaran@gmail.com>
…toryOptimizerData - Add SemanticSpeedTracker as a member of TrajectoryOptimizerData, removing it from the optimize_trajectory virtual interface. A fresh data instance is created per trajectory in the optimizer loop, so the tracker resets automatically between trajectories. - Fix stale stop-point candidates bug: build_stop_approach_ranges now uses take_stop_point_candidates() which atomically returns and clears the staging area, preventing leftover candidates from the first call polluting the velocity-based fallback second call. - Encapsulate stop_point_candidates_ and slow_down_ranges_ as private members with named accessors (add_stop_candidate, take_stop_point_candidates, get_slow_down_ranges) to enforce the two-stage detection contract. - Remove dead remap_to_trajectory call from TrajectorySplineSmoother: the QP smoother already consumed slow_down_ranges before the spline smoother runs, so the remap had no downstream effect. Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com>
d2873a5 to
3f3bc57
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 27 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "min_dist_to_resample_m", | ||
| "stop_detection_velocity_threshold_mps" |
| // Returns the staged stop candidates and clears the staging area atomically. | ||
| // Used by build_stop_approach_ranges() to consume and reset pending candidates. | ||
| std::vector<size_t> take_stop_point_candidates() | ||
| { | ||
| std::vector<size_t> result; | ||
| result.swap(stop_point_candidates_); | ||
| return result; | ||
| } |
| void detect_velocity_based_stop( | ||
| const TrajectoryPoints & traj_points, SemanticSpeedTracker & semantic_speed_tracker, | ||
| const double stop_velocity_threshold_mps) | ||
| { | ||
| const float threshold = static_cast<float>(stop_velocity_threshold_mps); | ||
|
|
||
| for (size_t i = 1; i < traj_points.size(); ++i) { | ||
| const float speed = std::abs(traj_points[i].longitudinal_velocity_mps); | ||
| const float prev_speed = std::abs(traj_points[i - 1].longitudinal_velocity_mps); | ||
| if (speed < threshold && speed < prev_speed) { | ||
| semantic_speed_tracker.add_stop_candidate(i); | ||
| break; | ||
| } | ||
| } | ||
| } |
- Clarify remove_close_proximity_points docstring: close proximity implies low speed at constant dt, so stop candidate registration is intentional. - Remove misleading 'atomically' wording from take_stop_point_candidates comment; the swap is O(1) but not thread-safe. Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com>
| resample_close_points: true # Enable resampling of close proximity points | ||
| min_dist_to_remove_m: 0.01 # [m] Minimum distance to remove close proximity points | ||
| min_dist_to_resample_m: 0.05 # [m] Minimum distance to merge close proximity points | ||
| stop_detection_velocity_threshold_mps: 0.3 # [m/s] Velocity threshold for fallback stop detection in slow clusters |
There was a problem hiding this comment.
memo: There are so many different parameters to detect stopping state in autoware. Ideally they should be aligned. The same value is used for diffusion planner, so it is alright
for now.
0a309ac
into
autowarefoundation:main
…autowarefoundation#12289) * use a semantic speed tracker and update longitudinal weights fro better slow downs Signed-off-by: Daniel <danielsanchezaran@gmail.com> * ● All changes are in. Here's what was implemented: Fix 1 — Hard constraint on stop positions (prepare_osqp_matrices): Stop point indices from slow_down_ranges are collected, filtered to exclude any already covered by the existing start/end constraint windows (no duplicate rows in A), and added as equality constraints. The stop position is now anchored regardless of weight ratios. Fix 2 — Velocity restore at stop points (post_process_trajectory): After the moving average smoothing pass, the input velocity is restored at each stop point. Since the stop position is now geometrically correct (fix 1), the geometric velocity is already near-zero — this step just trims the residual smoothing blur. The velocity at stop-1 is already small (arc length preservation + anchored stop), so there's no jump. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * feat: add semantic stop detection and preserve deceleration profile through QP smoother - Add SemanticSpeedTracker stop detection via velocity profile (build_stop_approach_ranges) replaces the slow_speed_ranges cross-validation approach with a direct velocity-direction check: stop points are detected first, then classified as stop approaches vs take-offs - QP smoother preserves planner velocity profile in detected deceleration zones by overwriting geometric recalculation with input velocities, forcing stop to zero; moving average handles the transition boundary - Velocity optimizer forces max_velocity=0 at detected stop points when jerk smoothing enabled - Spline smoother remaps semantic tracker indices after resampling via arc length lookup - Add stop_detection_velocity_threshold_mps param (default 0.3 m/s) to trajectory_point_fixer - Remove slow_speed_ranges intermediate representation and its cross-validation machinery Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor: remove arc length preservation from QP smoother The arc length preservation soft constraint in the QP is no longer needed now that the velocity profile in deceleration zones is preserved by overwriting geometric recalculation with input velocities. The stop position is still pinned via hard constraints. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor: remove use_semantic_stop_points from velocity optimizer The stop velocity is now correctly set to zero by the QP smoother via the deceleration zone velocity overwrite. The jerk smoother's searchZeroVelocityIndex handles the stop naturally without needing explicit max_velocity_per_point forcing from the semantic tracker. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor: clean up SemanticSpeedTracker and SlowSpeedInfo - Remove is_stop_point() method (no callers) - Remove duration_s field from SlowSpeedInfo (write-only, never read) - Remove is_stop_approach flag from SlowSpeedInfo (always true, never read) - Rename stop_points to stop_point_candidates to clarify its staging role before build_stop_approach_ranges() processes them into slow_down_ranges Signed-off-by: Daniel <danielsanchezaran@gmail.com> * undo param change Signed-off-by: Daniel <danielsanchezaran@gmail.com> * fix: address Copilot review feedback on PR 12289 - Reorder detection: build_stop_approach_ranges runs first; velocity-based fallback only fires when the result is empty, preventing false-positive candidates from silencing it - Deduplicate stop_constraint_indices before adding OSQP equality constraints - Use absolute speed comparison in detect_velocity_based_stop and build_stop_approach_ranges (correct for signed velocity conventions) - Fix stale Doxygen on prepare_osqp_matrices: describes actual use (hard stop position constraints) not the old velocity-fidelity weighting - Update schema description for stop_detection_velocity_threshold_mps - Update qp_smoother.md and trajectory_optimizer_specification.md to document stop handling, SemanticSpeedTracker, and revised Known Limitations Signed-off-by: Daniel <danielsanchezaran@gmail.com> * fix: align qp_smoother.md markdown style with CI/CD prettier Remove blank lines between list item headers and their descriptions to match the prettier version used in GitHub Actions. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor(trajectory_optimizer): move SemanticSpeedTracker into TrajectoryOptimizerData - Add SemanticSpeedTracker as a member of TrajectoryOptimizerData, removing it from the optimize_trajectory virtual interface. A fresh data instance is created per trajectory in the optimizer loop, so the tracker resets automatically between trajectories. - Fix stale stop-point candidates bug: build_stop_approach_ranges now uses take_stop_point_candidates() which atomically returns and clears the staging area, preventing leftover candidates from the first call polluting the velocity-based fallback second call. - Encapsulate stop_point_candidates_ and slow_down_ranges_ as private members with named accessors (add_stop_candidate, take_stop_point_candidates, get_slow_down_ranges) to enforce the two-stage detection contract. - Remove dead remap_to_trajectory call from TrajectorySplineSmoother: the QP smoother already consumed slow_down_ranges before the spline smoother runs, so the remap had no downstream effect. Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com> * fix(trajectory_optimizer): address Copilot review comments - Clarify remove_close_proximity_points docstring: close proximity implies low speed at constant dt, so stop candidate registration is intentional. - Remove misleading 'atomically' wording from take_stop_point_candidates comment; the swap is O(1) but not thread-safe. Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com> --------- Signed-off-by: Daniel <danielsanchezaran@gmail.com> Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com>
…autowarefoundation#12289) (#2778) * use a semantic speed tracker and update longitudinal weights fro better slow downs * ● All changes are in. Here's what was implemented: Fix 1 — Hard constraint on stop positions (prepare_osqp_matrices): Stop point indices from slow_down_ranges are collected, filtered to exclude any already covered by the existing start/end constraint windows (no duplicate rows in A), and added as equality constraints. The stop position is now anchored regardless of weight ratios. Fix 2 — Velocity restore at stop points (post_process_trajectory): After the moving average smoothing pass, the input velocity is restored at each stop point. Since the stop position is now geometrically correct (fix 1), the geometric velocity is already near-zero — this step just trims the residual smoothing blur. The velocity at stop-1 is already small (arc length preservation + anchored stop), so there's no jump. * feat: add semantic stop detection and preserve deceleration profile through QP smoother - Add SemanticSpeedTracker stop detection via velocity profile (build_stop_approach_ranges) replaces the slow_speed_ranges cross-validation approach with a direct velocity-direction check: stop points are detected first, then classified as stop approaches vs take-offs - QP smoother preserves planner velocity profile in detected deceleration zones by overwriting geometric recalculation with input velocities, forcing stop to zero; moving average handles the transition boundary - Velocity optimizer forces max_velocity=0 at detected stop points when jerk smoothing enabled - Spline smoother remaps semantic tracker indices after resampling via arc length lookup - Add stop_detection_velocity_threshold_mps param (default 0.3 m/s) to trajectory_point_fixer - Remove slow_speed_ranges intermediate representation and its cross-validation machinery * refactor: remove arc length preservation from QP smoother The arc length preservation soft constraint in the QP is no longer needed now that the velocity profile in deceleration zones is preserved by overwriting geometric recalculation with input velocities. The stop position is still pinned via hard constraints. * refactor: remove use_semantic_stop_points from velocity optimizer The stop velocity is now correctly set to zero by the QP smoother via the deceleration zone velocity overwrite. The jerk smoother's searchZeroVelocityIndex handles the stop naturally without needing explicit max_velocity_per_point forcing from the semantic tracker. * refactor: clean up SemanticSpeedTracker and SlowSpeedInfo - Remove is_stop_point() method (no callers) - Remove duration_s field from SlowSpeedInfo (write-only, never read) - Remove is_stop_approach flag from SlowSpeedInfo (always true, never read) - Rename stop_points to stop_point_candidates to clarify its staging role before build_stop_approach_ranges() processes them into slow_down_ranges * undo param change * fix: address Copilot review feedback on PR 12289 - Reorder detection: build_stop_approach_ranges runs first; velocity-based fallback only fires when the result is empty, preventing false-positive candidates from silencing it - Deduplicate stop_constraint_indices before adding OSQP equality constraints - Use absolute speed comparison in detect_velocity_based_stop and build_stop_approach_ranges (correct for signed velocity conventions) - Fix stale Doxygen on prepare_osqp_matrices: describes actual use (hard stop position constraints) not the old velocity-fidelity weighting - Update schema description for stop_detection_velocity_threshold_mps - Update qp_smoother.md and trajectory_optimizer_specification.md to document stop handling, SemanticSpeedTracker, and revised Known Limitations * fix: align qp_smoother.md markdown style with CI/CD prettier Remove blank lines between list item headers and their descriptions to match the prettier version used in GitHub Actions. * refactor(trajectory_optimizer): move SemanticSpeedTracker into TrajectoryOptimizerData - Add SemanticSpeedTracker as a member of TrajectoryOptimizerData, removing it from the optimize_trajectory virtual interface. A fresh data instance is created per trajectory in the optimizer loop, so the tracker resets automatically between trajectories. - Fix stale stop-point candidates bug: build_stop_approach_ranges now uses take_stop_point_candidates() which atomically returns and clears the staging area, preventing leftover candidates from the first call polluting the velocity-based fallback second call. - Encapsulate stop_point_candidates_ and slow_down_ranges_ as private members with named accessors (add_stop_candidate, take_stop_point_candidates, get_slow_down_ranges) to enforce the two-stage detection contract. - Remove dead remap_to_trajectory call from TrajectorySplineSmoother: the QP smoother already consumed slow_down_ranges before the spline smoother runs, so the remap had no downstream effect. * fix(trajectory_optimizer): address Copilot review comments - Clarify remove_close_proximity_points docstring: close proximity implies low speed at constant dt, so stop candidate registration is intentional. - Remove misleading 'atomically' wording from take_stop_point_candidates comment; the swap is O(1) but not thread-safe. --------- Signed-off-by: Daniel <danielsanchezaran@gmail.com> Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com> Co-authored-by: danielsanchezaran <daniel.sanchez@tier4.jp>
…autowarefoundation#12289) * use a semantic speed tracker and update longitudinal weights fro better slow downs Signed-off-by: Daniel <danielsanchezaran@gmail.com> * ● All changes are in. Here's what was implemented: Fix 1 — Hard constraint on stop positions (prepare_osqp_matrices): Stop point indices from slow_down_ranges are collected, filtered to exclude any already covered by the existing start/end constraint windows (no duplicate rows in A), and added as equality constraints. The stop position is now anchored regardless of weight ratios. Fix 2 — Velocity restore at stop points (post_process_trajectory): After the moving average smoothing pass, the input velocity is restored at each stop point. Since the stop position is now geometrically correct (fix 1), the geometric velocity is already near-zero — this step just trims the residual smoothing blur. The velocity at stop-1 is already small (arc length preservation + anchored stop), so there's no jump. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * feat: add semantic stop detection and preserve deceleration profile through QP smoother - Add SemanticSpeedTracker stop detection via velocity profile (build_stop_approach_ranges) replaces the slow_speed_ranges cross-validation approach with a direct velocity-direction check: stop points are detected first, then classified as stop approaches vs take-offs - QP smoother preserves planner velocity profile in detected deceleration zones by overwriting geometric recalculation with input velocities, forcing stop to zero; moving average handles the transition boundary - Velocity optimizer forces max_velocity=0 at detected stop points when jerk smoothing enabled - Spline smoother remaps semantic tracker indices after resampling via arc length lookup - Add stop_detection_velocity_threshold_mps param (default 0.3 m/s) to trajectory_point_fixer - Remove slow_speed_ranges intermediate representation and its cross-validation machinery Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor: remove arc length preservation from QP smoother The arc length preservation soft constraint in the QP is no longer needed now that the velocity profile in deceleration zones is preserved by overwriting geometric recalculation with input velocities. The stop position is still pinned via hard constraints. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor: remove use_semantic_stop_points from velocity optimizer The stop velocity is now correctly set to zero by the QP smoother via the deceleration zone velocity overwrite. The jerk smoother's searchZeroVelocityIndex handles the stop naturally without needing explicit max_velocity_per_point forcing from the semantic tracker. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor: clean up SemanticSpeedTracker and SlowSpeedInfo - Remove is_stop_point() method (no callers) - Remove duration_s field from SlowSpeedInfo (write-only, never read) - Remove is_stop_approach flag from SlowSpeedInfo (always true, never read) - Rename stop_points to stop_point_candidates to clarify its staging role before build_stop_approach_ranges() processes them into slow_down_ranges Signed-off-by: Daniel <danielsanchezaran@gmail.com> * undo param change Signed-off-by: Daniel <danielsanchezaran@gmail.com> * fix: address Copilot review feedback on PR 12289 - Reorder detection: build_stop_approach_ranges runs first; velocity-based fallback only fires when the result is empty, preventing false-positive candidates from silencing it - Deduplicate stop_constraint_indices before adding OSQP equality constraints - Use absolute speed comparison in detect_velocity_based_stop and build_stop_approach_ranges (correct for signed velocity conventions) - Fix stale Doxygen on prepare_osqp_matrices: describes actual use (hard stop position constraints) not the old velocity-fidelity weighting - Update schema description for stop_detection_velocity_threshold_mps - Update qp_smoother.md and trajectory_optimizer_specification.md to document stop handling, SemanticSpeedTracker, and revised Known Limitations Signed-off-by: Daniel <danielsanchezaran@gmail.com> * fix: align qp_smoother.md markdown style with CI/CD prettier Remove blank lines between list item headers and their descriptions to match the prettier version used in GitHub Actions. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor(trajectory_optimizer): move SemanticSpeedTracker into TrajectoryOptimizerData - Add SemanticSpeedTracker as a member of TrajectoryOptimizerData, removing it from the optimize_trajectory virtual interface. A fresh data instance is created per trajectory in the optimizer loop, so the tracker resets automatically between trajectories. - Fix stale stop-point candidates bug: build_stop_approach_ranges now uses take_stop_point_candidates() which atomically returns and clears the staging area, preventing leftover candidates from the first call polluting the velocity-based fallback second call. - Encapsulate stop_point_candidates_ and slow_down_ranges_ as private members with named accessors (add_stop_candidate, take_stop_point_candidates, get_slow_down_ranges) to enforce the two-stage detection contract. - Remove dead remap_to_trajectory call from TrajectorySplineSmoother: the QP smoother already consumed slow_down_ranges before the spline smoother runs, so the remap had no downstream effect. Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com> * fix(trajectory_optimizer): address Copilot review comments - Clarify remove_close_proximity_points docstring: close proximity implies low speed at constant dt, so stop candidate registration is intentional. - Remove misleading 'atomically' wording from take_stop_point_candidates comment; the swap is O(1) but not thread-safe. Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com> --------- Signed-off-by: Daniel <danielsanchezaran@gmail.com> Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com>
…autowarefoundation#12289) * use a semantic speed tracker and update longitudinal weights fro better slow downs Signed-off-by: Daniel <danielsanchezaran@gmail.com> * ● All changes are in. Here's what was implemented: Fix 1 — Hard constraint on stop positions (prepare_osqp_matrices): Stop point indices from slow_down_ranges are collected, filtered to exclude any already covered by the existing start/end constraint windows (no duplicate rows in A), and added as equality constraints. The stop position is now anchored regardless of weight ratios. Fix 2 — Velocity restore at stop points (post_process_trajectory): After the moving average smoothing pass, the input velocity is restored at each stop point. Since the stop position is now geometrically correct (fix 1), the geometric velocity is already near-zero — this step just trims the residual smoothing blur. The velocity at stop-1 is already small (arc length preservation + anchored stop), so there's no jump. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * feat: add semantic stop detection and preserve deceleration profile through QP smoother - Add SemanticSpeedTracker stop detection via velocity profile (build_stop_approach_ranges) replaces the slow_speed_ranges cross-validation approach with a direct velocity-direction check: stop points are detected first, then classified as stop approaches vs take-offs - QP smoother preserves planner velocity profile in detected deceleration zones by overwriting geometric recalculation with input velocities, forcing stop to zero; moving average handles the transition boundary - Velocity optimizer forces max_velocity=0 at detected stop points when jerk smoothing enabled - Spline smoother remaps semantic tracker indices after resampling via arc length lookup - Add stop_detection_velocity_threshold_mps param (default 0.3 m/s) to trajectory_point_fixer - Remove slow_speed_ranges intermediate representation and its cross-validation machinery Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor: remove arc length preservation from QP smoother The arc length preservation soft constraint in the QP is no longer needed now that the velocity profile in deceleration zones is preserved by overwriting geometric recalculation with input velocities. The stop position is still pinned via hard constraints. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor: remove use_semantic_stop_points from velocity optimizer The stop velocity is now correctly set to zero by the QP smoother via the deceleration zone velocity overwrite. The jerk smoother's searchZeroVelocityIndex handles the stop naturally without needing explicit max_velocity_per_point forcing from the semantic tracker. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor: clean up SemanticSpeedTracker and SlowSpeedInfo - Remove is_stop_point() method (no callers) - Remove duration_s field from SlowSpeedInfo (write-only, never read) - Remove is_stop_approach flag from SlowSpeedInfo (always true, never read) - Rename stop_points to stop_point_candidates to clarify its staging role before build_stop_approach_ranges() processes them into slow_down_ranges Signed-off-by: Daniel <danielsanchezaran@gmail.com> * undo param change Signed-off-by: Daniel <danielsanchezaran@gmail.com> * fix: address Copilot review feedback on PR 12289 - Reorder detection: build_stop_approach_ranges runs first; velocity-based fallback only fires when the result is empty, preventing false-positive candidates from silencing it - Deduplicate stop_constraint_indices before adding OSQP equality constraints - Use absolute speed comparison in detect_velocity_based_stop and build_stop_approach_ranges (correct for signed velocity conventions) - Fix stale Doxygen on prepare_osqp_matrices: describes actual use (hard stop position constraints) not the old velocity-fidelity weighting - Update schema description for stop_detection_velocity_threshold_mps - Update qp_smoother.md and trajectory_optimizer_specification.md to document stop handling, SemanticSpeedTracker, and revised Known Limitations Signed-off-by: Daniel <danielsanchezaran@gmail.com> * fix: align qp_smoother.md markdown style with CI/CD prettier Remove blank lines between list item headers and their descriptions to match the prettier version used in GitHub Actions. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor(trajectory_optimizer): move SemanticSpeedTracker into TrajectoryOptimizerData - Add SemanticSpeedTracker as a member of TrajectoryOptimizerData, removing it from the optimize_trajectory virtual interface. A fresh data instance is created per trajectory in the optimizer loop, so the tracker resets automatically between trajectories. - Fix stale stop-point candidates bug: build_stop_approach_ranges now uses take_stop_point_candidates() which atomically returns and clears the staging area, preventing leftover candidates from the first call polluting the velocity-based fallback second call. - Encapsulate stop_point_candidates_ and slow_down_ranges_ as private members with named accessors (add_stop_candidate, take_stop_point_candidates, get_slow_down_ranges) to enforce the two-stage detection contract. - Remove dead remap_to_trajectory call from TrajectorySplineSmoother: the QP smoother already consumed slow_down_ranges before the spline smoother runs, so the remap had no downstream effect. Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com> * fix(trajectory_optimizer): address Copilot review comments - Clarify remove_close_proximity_points docstring: close proximity implies low speed at constant dt, so stop candidate registration is intentional. - Remove misleading 'atomically' wording from take_stop_point_candidates comment; the swap is O(1) but not thread-safe. Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com> --------- Signed-off-by: Daniel <danielsanchezaran@gmail.com> Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com>
* feat: improve parameters and the constraints (autowarefoundation#12271) * feat: improve parameters and the initial constraints Signed-off-by: YuxuanLiuTier4Desktop <619684051@qq.com> * feat: clean up constraints Signed-off-by: YuxuanLiuTier4Desktop <619684051@qq.com> * fix docs and test Signed-off-by: YuxuanLiuTier4Desktop <619684051@qq.com> * enforce end points and test Signed-off-by: YuxuanLiuTier4Desktop <619684051@qq.com> * feat: fix docs and ci Signed-off-by: YuxuanLiuTier4Desktop <619684051@qq.com> * fix test Signed-off-by: YuxuanLiuTier4Desktop <619684051@qq.com> * fix builg Signed-off-by: YuxuanLiuTier4Desktop <619684051@qq.com> * fix spell ci Signed-off-by: YuxuanLiuTier4Desktop <619684051@qq.com> * fix cppcheck Signed-off-by: YuxuanLiuTier4Desktop <619684051@qq.com> * feat: fix cppcheck Signed-off-by: YuxuanLiuTier4Desktop <619684051@qq.com> * feat: fix cppcheck Signed-off-by: YuxuanLiuTier4Desktop <619684051@qq.com> --------- Signed-off-by: YuxuanLiuTier4Desktop <619684051@qq.com> * feat(autoware_trajectory_optimizer): force 3 point trajectory (autowarefoundation#12287) * force the optimizer to output a 3 point trajectory with 0 velocity if the output trajectory has less than 3 points Signed-off-by: Daniel <danielsanchezaran@gmail.com> * review comments Signed-off-by: Daniel <danielsanchezaran@gmail.com> * add debug logs Signed-off-by: Daniel <danielsanchezaran@gmail.com> --------- Signed-off-by: Daniel <danielsanchezaran@gmail.com> * feat(autoware_trajectory_optimizer): optimizer semantic speed tracker (autowarefoundation#12289) * use a semantic speed tracker and update longitudinal weights fro better slow downs Signed-off-by: Daniel <danielsanchezaran@gmail.com> * ● All changes are in. Here's what was implemented: Fix 1 — Hard constraint on stop positions (prepare_osqp_matrices): Stop point indices from slow_down_ranges are collected, filtered to exclude any already covered by the existing start/end constraint windows (no duplicate rows in A), and added as equality constraints. The stop position is now anchored regardless of weight ratios. Fix 2 — Velocity restore at stop points (post_process_trajectory): After the moving average smoothing pass, the input velocity is restored at each stop point. Since the stop position is now geometrically correct (fix 1), the geometric velocity is already near-zero — this step just trims the residual smoothing blur. The velocity at stop-1 is already small (arc length preservation + anchored stop), so there's no jump. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * feat: add semantic stop detection and preserve deceleration profile through QP smoother - Add SemanticSpeedTracker stop detection via velocity profile (build_stop_approach_ranges) replaces the slow_speed_ranges cross-validation approach with a direct velocity-direction check: stop points are detected first, then classified as stop approaches vs take-offs - QP smoother preserves planner velocity profile in detected deceleration zones by overwriting geometric recalculation with input velocities, forcing stop to zero; moving average handles the transition boundary - Velocity optimizer forces max_velocity=0 at detected stop points when jerk smoothing enabled - Spline smoother remaps semantic tracker indices after resampling via arc length lookup - Add stop_detection_velocity_threshold_mps param (default 0.3 m/s) to trajectory_point_fixer - Remove slow_speed_ranges intermediate representation and its cross-validation machinery Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor: remove arc length preservation from QP smoother The arc length preservation soft constraint in the QP is no longer needed now that the velocity profile in deceleration zones is preserved by overwriting geometric recalculation with input velocities. The stop position is still pinned via hard constraints. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor: remove use_semantic_stop_points from velocity optimizer The stop velocity is now correctly set to zero by the QP smoother via the deceleration zone velocity overwrite. The jerk smoother's searchZeroVelocityIndex handles the stop naturally without needing explicit max_velocity_per_point forcing from the semantic tracker. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor: clean up SemanticSpeedTracker and SlowSpeedInfo - Remove is_stop_point() method (no callers) - Remove duration_s field from SlowSpeedInfo (write-only, never read) - Remove is_stop_approach flag from SlowSpeedInfo (always true, never read) - Rename stop_points to stop_point_candidates to clarify its staging role before build_stop_approach_ranges() processes them into slow_down_ranges Signed-off-by: Daniel <danielsanchezaran@gmail.com> * undo param change Signed-off-by: Daniel <danielsanchezaran@gmail.com> * fix: address Copilot review feedback on PR 12289 - Reorder detection: build_stop_approach_ranges runs first; velocity-based fallback only fires when the result is empty, preventing false-positive candidates from silencing it - Deduplicate stop_constraint_indices before adding OSQP equality constraints - Use absolute speed comparison in detect_velocity_based_stop and build_stop_approach_ranges (correct for signed velocity conventions) - Fix stale Doxygen on prepare_osqp_matrices: describes actual use (hard stop position constraints) not the old velocity-fidelity weighting - Update schema description for stop_detection_velocity_threshold_mps - Update qp_smoother.md and trajectory_optimizer_specification.md to document stop handling, SemanticSpeedTracker, and revised Known Limitations Signed-off-by: Daniel <danielsanchezaran@gmail.com> * fix: align qp_smoother.md markdown style with CI/CD prettier Remove blank lines between list item headers and their descriptions to match the prettier version used in GitHub Actions. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor(trajectory_optimizer): move SemanticSpeedTracker into TrajectoryOptimizerData - Add SemanticSpeedTracker as a member of TrajectoryOptimizerData, removing it from the optimize_trajectory virtual interface. A fresh data instance is created per trajectory in the optimizer loop, so the tracker resets automatically between trajectories. - Fix stale stop-point candidates bug: build_stop_approach_ranges now uses take_stop_point_candidates() which atomically returns and clears the staging area, preventing leftover candidates from the first call polluting the velocity-based fallback second call. - Encapsulate stop_point_candidates_ and slow_down_ranges_ as private members with named accessors (add_stop_candidate, take_stop_point_candidates, get_slow_down_ranges) to enforce the two-stage detection contract. - Remove dead remap_to_trajectory call from TrajectorySplineSmoother: the QP smoother already consumed slow_down_ranges before the spline smoother runs, so the remap had no downstream effect. Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com> * fix(trajectory_optimizer): address Copilot review comments - Clarify remove_close_proximity_points docstring: close proximity implies low speed at constant dt, so stop candidate registration is intentional. - Remove misleading 'atomically' wording from take_stop_point_candidates comment; the swap is O(1) but not thread-safe. Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com> --------- Signed-off-by: Daniel <danielsanchezaran@gmail.com> Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com> * add modifier to pipeline, disable long stop traejctories by default Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com> --------- Signed-off-by: YuxuanLiuTier4Desktop <619684051@qq.com> Signed-off-by: Daniel <danielsanchezaran@gmail.com> Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com> Co-authored-by: Yuxuan Liu <619684051@qq.com>
…autowarefoundation#12289) * use a semantic speed tracker and update longitudinal weights fro better slow downs Signed-off-by: Daniel <danielsanchezaran@gmail.com> * ● All changes are in. Here's what was implemented: Fix 1 — Hard constraint on stop positions (prepare_osqp_matrices): Stop point indices from slow_down_ranges are collected, filtered to exclude any already covered by the existing start/end constraint windows (no duplicate rows in A), and added as equality constraints. The stop position is now anchored regardless of weight ratios. Fix 2 — Velocity restore at stop points (post_process_trajectory): After the moving average smoothing pass, the input velocity is restored at each stop point. Since the stop position is now geometrically correct (fix 1), the geometric velocity is already near-zero — this step just trims the residual smoothing blur. The velocity at stop-1 is already small (arc length preservation + anchored stop), so there's no jump. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * feat: add semantic stop detection and preserve deceleration profile through QP smoother - Add SemanticSpeedTracker stop detection via velocity profile (build_stop_approach_ranges) replaces the slow_speed_ranges cross-validation approach with a direct velocity-direction check: stop points are detected first, then classified as stop approaches vs take-offs - QP smoother preserves planner velocity profile in detected deceleration zones by overwriting geometric recalculation with input velocities, forcing stop to zero; moving average handles the transition boundary - Velocity optimizer forces max_velocity=0 at detected stop points when jerk smoothing enabled - Spline smoother remaps semantic tracker indices after resampling via arc length lookup - Add stop_detection_velocity_threshold_mps param (default 0.3 m/s) to trajectory_point_fixer - Remove slow_speed_ranges intermediate representation and its cross-validation machinery Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor: remove arc length preservation from QP smoother The arc length preservation soft constraint in the QP is no longer needed now that the velocity profile in deceleration zones is preserved by overwriting geometric recalculation with input velocities. The stop position is still pinned via hard constraints. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor: remove use_semantic_stop_points from velocity optimizer The stop velocity is now correctly set to zero by the QP smoother via the deceleration zone velocity overwrite. The jerk smoother's searchZeroVelocityIndex handles the stop naturally without needing explicit max_velocity_per_point forcing from the semantic tracker. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor: clean up SemanticSpeedTracker and SlowSpeedInfo - Remove is_stop_point() method (no callers) - Remove duration_s field from SlowSpeedInfo (write-only, never read) - Remove is_stop_approach flag from SlowSpeedInfo (always true, never read) - Rename stop_points to stop_point_candidates to clarify its staging role before build_stop_approach_ranges() processes them into slow_down_ranges Signed-off-by: Daniel <danielsanchezaran@gmail.com> * undo param change Signed-off-by: Daniel <danielsanchezaran@gmail.com> * fix: address Copilot review feedback on PR 12289 - Reorder detection: build_stop_approach_ranges runs first; velocity-based fallback only fires when the result is empty, preventing false-positive candidates from silencing it - Deduplicate stop_constraint_indices before adding OSQP equality constraints - Use absolute speed comparison in detect_velocity_based_stop and build_stop_approach_ranges (correct for signed velocity conventions) - Fix stale Doxygen on prepare_osqp_matrices: describes actual use (hard stop position constraints) not the old velocity-fidelity weighting - Update schema description for stop_detection_velocity_threshold_mps - Update qp_smoother.md and trajectory_optimizer_specification.md to document stop handling, SemanticSpeedTracker, and revised Known Limitations Signed-off-by: Daniel <danielsanchezaran@gmail.com> * fix: align qp_smoother.md markdown style with CI/CD prettier Remove blank lines between list item headers and their descriptions to match the prettier version used in GitHub Actions. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor(trajectory_optimizer): move SemanticSpeedTracker into TrajectoryOptimizerData - Add SemanticSpeedTracker as a member of TrajectoryOptimizerData, removing it from the optimize_trajectory virtual interface. A fresh data instance is created per trajectory in the optimizer loop, so the tracker resets automatically between trajectories. - Fix stale stop-point candidates bug: build_stop_approach_ranges now uses take_stop_point_candidates() which atomically returns and clears the staging area, preventing leftover candidates from the first call polluting the velocity-based fallback second call. - Encapsulate stop_point_candidates_ and slow_down_ranges_ as private members with named accessors (add_stop_candidate, take_stop_point_candidates, get_slow_down_ranges) to enforce the two-stage detection contract. - Remove dead remap_to_trajectory call from TrajectorySplineSmoother: the QP smoother already consumed slow_down_ranges before the spline smoother runs, so the remap had no downstream effect. Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com> * fix(trajectory_optimizer): address Copilot review comments - Clarify remove_close_proximity_points docstring: close proximity implies low speed at constant dt, so stop candidate registration is intentional. - Remove misleading 'atomically' wording from take_stop_point_candidates comment; the swap is O(1) but not thread-safe. Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com> --------- Signed-off-by: Daniel <danielsanchezaran@gmail.com> Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com>
…autowarefoundation#12289) * use a semantic speed tracker and update longitudinal weights fro better slow downs Signed-off-by: Daniel <danielsanchezaran@gmail.com> * ● All changes are in. Here's what was implemented: Fix 1 — Hard constraint on stop positions (prepare_osqp_matrices): Stop point indices from slow_down_ranges are collected, filtered to exclude any already covered by the existing start/end constraint windows (no duplicate rows in A), and added as equality constraints. The stop position is now anchored regardless of weight ratios. Fix 2 — Velocity restore at stop points (post_process_trajectory): After the moving average smoothing pass, the input velocity is restored at each stop point. Since the stop position is now geometrically correct (fix 1), the geometric velocity is already near-zero — this step just trims the residual smoothing blur. The velocity at stop-1 is already small (arc length preservation + anchored stop), so there's no jump. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * feat: add semantic stop detection and preserve deceleration profile through QP smoother - Add SemanticSpeedTracker stop detection via velocity profile (build_stop_approach_ranges) replaces the slow_speed_ranges cross-validation approach with a direct velocity-direction check: stop points are detected first, then classified as stop approaches vs take-offs - QP smoother preserves planner velocity profile in detected deceleration zones by overwriting geometric recalculation with input velocities, forcing stop to zero; moving average handles the transition boundary - Velocity optimizer forces max_velocity=0 at detected stop points when jerk smoothing enabled - Spline smoother remaps semantic tracker indices after resampling via arc length lookup - Add stop_detection_velocity_threshold_mps param (default 0.3 m/s) to trajectory_point_fixer - Remove slow_speed_ranges intermediate representation and its cross-validation machinery Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor: remove arc length preservation from QP smoother The arc length preservation soft constraint in the QP is no longer needed now that the velocity profile in deceleration zones is preserved by overwriting geometric recalculation with input velocities. The stop position is still pinned via hard constraints. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor: remove use_semantic_stop_points from velocity optimizer The stop velocity is now correctly set to zero by the QP smoother via the deceleration zone velocity overwrite. The jerk smoother's searchZeroVelocityIndex handles the stop naturally without needing explicit max_velocity_per_point forcing from the semantic tracker. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor: clean up SemanticSpeedTracker and SlowSpeedInfo - Remove is_stop_point() method (no callers) - Remove duration_s field from SlowSpeedInfo (write-only, never read) - Remove is_stop_approach flag from SlowSpeedInfo (always true, never read) - Rename stop_points to stop_point_candidates to clarify its staging role before build_stop_approach_ranges() processes them into slow_down_ranges Signed-off-by: Daniel <danielsanchezaran@gmail.com> * undo param change Signed-off-by: Daniel <danielsanchezaran@gmail.com> * fix: address Copilot review feedback on PR 12289 - Reorder detection: build_stop_approach_ranges runs first; velocity-based fallback only fires when the result is empty, preventing false-positive candidates from silencing it - Deduplicate stop_constraint_indices before adding OSQP equality constraints - Use absolute speed comparison in detect_velocity_based_stop and build_stop_approach_ranges (correct for signed velocity conventions) - Fix stale Doxygen on prepare_osqp_matrices: describes actual use (hard stop position constraints) not the old velocity-fidelity weighting - Update schema description for stop_detection_velocity_threshold_mps - Update qp_smoother.md and trajectory_optimizer_specification.md to document stop handling, SemanticSpeedTracker, and revised Known Limitations Signed-off-by: Daniel <danielsanchezaran@gmail.com> * fix: align qp_smoother.md markdown style with CI/CD prettier Remove blank lines between list item headers and their descriptions to match the prettier version used in GitHub Actions. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor(trajectory_optimizer): move SemanticSpeedTracker into TrajectoryOptimizerData - Add SemanticSpeedTracker as a member of TrajectoryOptimizerData, removing it from the optimize_trajectory virtual interface. A fresh data instance is created per trajectory in the optimizer loop, so the tracker resets automatically between trajectories. - Fix stale stop-point candidates bug: build_stop_approach_ranges now uses take_stop_point_candidates() which atomically returns and clears the staging area, preventing leftover candidates from the first call polluting the velocity-based fallback second call. - Encapsulate stop_point_candidates_ and slow_down_ranges_ as private members with named accessors (add_stop_candidate, take_stop_point_candidates, get_slow_down_ranges) to enforce the two-stage detection contract. - Remove dead remap_to_trajectory call from TrajectorySplineSmoother: the QP smoother already consumed slow_down_ranges before the spline smoother runs, so the remap had no downstream effect. Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com> * fix(trajectory_optimizer): address Copilot review comments - Clarify remove_close_proximity_points docstring: close proximity implies low speed at constant dt, so stop candidate registration is intentional. - Remove misleading 'atomically' wording from take_stop_point_candidates comment; the swap is O(1) but not thread-safe. Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com> --------- Signed-off-by: Daniel <danielsanchezaran@gmail.com> Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com>
…autowarefoundation/autoware_universe#12289) * use a semantic speed tracker and update longitudinal weights fro better slow downs Signed-off-by: Daniel <danielsanchezaran@gmail.com> * ● All changes are in. Here's what was implemented: Fix 1 — Hard constraint on stop positions (prepare_osqp_matrices): Stop point indices from slow_down_ranges are collected, filtered to exclude any already covered by the existing start/end constraint windows (no duplicate rows in A), and added as equality constraints. The stop position is now anchored regardless of weight ratios. Fix 2 — Velocity restore at stop points (post_process_trajectory): After the moving average smoothing pass, the input velocity is restored at each stop point. Since the stop position is now geometrically correct (fix 1), the geometric velocity is already near-zero — this step just trims the residual smoothing blur. The velocity at stop-1 is already small (arc length preservation + anchored stop), so there's no jump. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * feat: add semantic stop detection and preserve deceleration profile through QP smoother - Add SemanticSpeedTracker stop detection via velocity profile (build_stop_approach_ranges) replaces the slow_speed_ranges cross-validation approach with a direct velocity-direction check: stop points are detected first, then classified as stop approaches vs take-offs - QP smoother preserves planner velocity profile in detected deceleration zones by overwriting geometric recalculation with input velocities, forcing stop to zero; moving average handles the transition boundary - Velocity optimizer forces max_velocity=0 at detected stop points when jerk smoothing enabled - Spline smoother remaps semantic tracker indices after resampling via arc length lookup - Add stop_detection_velocity_threshold_mps param (default 0.3 m/s) to trajectory_point_fixer - Remove slow_speed_ranges intermediate representation and its cross-validation machinery Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor: remove arc length preservation from QP smoother The arc length preservation soft constraint in the QP is no longer needed now that the velocity profile in deceleration zones is preserved by overwriting geometric recalculation with input velocities. The stop position is still pinned via hard constraints. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor: remove use_semantic_stop_points from velocity optimizer The stop velocity is now correctly set to zero by the QP smoother via the deceleration zone velocity overwrite. The jerk smoother's searchZeroVelocityIndex handles the stop naturally without needing explicit max_velocity_per_point forcing from the semantic tracker. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor: clean up SemanticSpeedTracker and SlowSpeedInfo - Remove is_stop_point() method (no callers) - Remove duration_s field from SlowSpeedInfo (write-only, never read) - Remove is_stop_approach flag from SlowSpeedInfo (always true, never read) - Rename stop_points to stop_point_candidates to clarify its staging role before build_stop_approach_ranges() processes them into slow_down_ranges Signed-off-by: Daniel <danielsanchezaran@gmail.com> * undo param change Signed-off-by: Daniel <danielsanchezaran@gmail.com> * fix: address Copilot review feedback on PR 12289 - Reorder detection: build_stop_approach_ranges runs first; velocity-based fallback only fires when the result is empty, preventing false-positive candidates from silencing it - Deduplicate stop_constraint_indices before adding OSQP equality constraints - Use absolute speed comparison in detect_velocity_based_stop and build_stop_approach_ranges (correct for signed velocity conventions) - Fix stale Doxygen on prepare_osqp_matrices: describes actual use (hard stop position constraints) not the old velocity-fidelity weighting - Update schema description for stop_detection_velocity_threshold_mps - Update qp_smoother.md and trajectory_optimizer_specification.md to document stop handling, SemanticSpeedTracker, and revised Known Limitations Signed-off-by: Daniel <danielsanchezaran@gmail.com> * fix: align qp_smoother.md markdown style with CI/CD prettier Remove blank lines between list item headers and their descriptions to match the prettier version used in GitHub Actions. Signed-off-by: Daniel <danielsanchezaran@gmail.com> * refactor(trajectory_optimizer): move SemanticSpeedTracker into TrajectoryOptimizerData - Add SemanticSpeedTracker as a member of TrajectoryOptimizerData, removing it from the optimize_trajectory virtual interface. A fresh data instance is created per trajectory in the optimizer loop, so the tracker resets automatically between trajectories. - Fix stale stop-point candidates bug: build_stop_approach_ranges now uses take_stop_point_candidates() which atomically returns and clears the staging area, preventing leftover candidates from the first call polluting the velocity-based fallback second call. - Encapsulate stop_point_candidates_ and slow_down_ranges_ as private members with named accessors (add_stop_candidate, take_stop_point_candidates, get_slow_down_ranges) to enforce the two-stage detection contract. - Remove dead remap_to_trajectory call from TrajectorySplineSmoother: the QP smoother already consumed slow_down_ranges before the spline smoother runs, so the remap had no downstream effect. Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com> * fix(trajectory_optimizer): address Copilot review comments - Clarify remove_close_proximity_points docstring: close proximity implies low speed at constant dt, so stop candidate registration is intentional. - Remove misleading 'atomically' wording from take_stop_point_candidates comment; the swap is O(1) but not thread-safe. Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com> --------- Signed-off-by: Daniel <danielsanchezaran@gmail.com> Signed-off-by: Daniel Sanchez <danielsanchezaran@gmail.com>
Description
This PR introduces a
SemanticSpeedTrackerto theautoware_trajectory_optimizerthat detectsdeceleration-to-stop zones in the input trajectory and uses that information to preserve the
planner's intended velocity profile through the QP path smoother.
Problem
The QP smoother optimizes trajectory geometry (x, y positions) and then recalculates velocities
from the smoothed geometry using finite differences (
v[i] = dist(p[i], p[i-1]) / dt). Indeceleration zones approaching a stop, the planner produces closely-spaced points with near-zero
velocities. The geometric recalculation and subsequent moving-average smoothing replace this
intended profile with artificially elevated velocities (typically ~0.6 m/s at the stop point),
preventing the vehicle from stopping correctly when downstream velocity optimization is enabled.
Solution
Stop approach detection (
TrajectoryPointFixer): A two-stage detection pipeline identifiesstop approach zones:
min_dist_to_resample_mwithdecreasing velocity toward the endpoint are marked as stop candidates.
detect_velocity_based_stop): for constant-spacing trajectories(e.g. after Akima resampling) where no geometric clusters exist, scans the velocity profile
for the first decelerating point below
stop_detection_velocity_threshold_mps.build_stop_approach_ranges: processes all candidates, confirms velocity direction (stopapproach vs. take-off), traces back the deceleration onset, and populates
slow_down_rangeswith arc length coordinates for downstream remap support.
Velocity preservation (
TrajectoryQPSmoother): After geometric velocity recalculation andmoving-average smoothing, the planner's original velocity profile is restored for all points
within each detected stop approach range. The stop point is forced to zero unconditionally. This
gives the downstream jerk smoother a correct
v_refprofile to plan against.Stop position pinning (
TrajectoryQPSmoother): The position of each detected stop point isadded as a hard equality constraint in the OSQP problem, ensuring the path smoother cannot
displace the stop position regardless of smoothness weight settings.
Index remapping (
TrajectorySplineSmoother): After Akima resampling changes the point count,remap_to_trajectory()uses stored arc length coordinates to updateslow_down_rangesindicesto the new trajectory, keeping the semantic information valid for future plugins.
Related links
Parent Issue:
How was this PR tested?
Tested in simulation with trajectories containing deceleration-to-stop sequences. With both the
QP smoother and velocity optimizer (jerk smoother) enabled, the output trajectory now correctly
reaches zero velocity at the detected stop point, matching the behavior observed with the QP
smoother disabled.
The video shows how the optimizer output (blue) correctly tracks the stop velocity.
Screencast.from.2026.03.12.19.27.14.webm
Notes for reviewers
SemanticSpeedTrackeris passed by reference through all pluginoptimize_trajectory()calls. Plugins that do not use it mark the parameter
[[maybe_unused]].stop_detection_velocity_threshold_mps(default: 0.3 m/s) controlsthe velocity-based fallback sensitivity. It should be set above the maximum velocity expected
in the stop zone but below normal driving velocities.
slow_down_rangesarc length coordinates (start_s_m,end_s_m) are populated atdetection time and survive Akima resampling via
remap_to_trajectory(), making the semanticinformation available to future downstream plugins.
Interface changes
ROS Parameter Changes
Additions and removals
trajectory_point_fixer.stop_detection_velocity_threshold_mpsdouble0.3Effects on system behavior
When
use_trajectory_point_fixer: trueanduse_qp_smoother: true, the output trajectoryvelocity profile in deceleration-to-stop zones now matches the planner's intended profile.
The stop point velocity is explicitly forced to zero, which allows the downstream jerk-filtered
velocity smoother (
smooth_velocities: true) to correctly plan a kinematically feasibledeceleration to a full stop.
There is no behavior change when the QP smoother is disabled or when no stop approach is
detected in the trajectory.