@@ -2561,10 +2561,14 @@ static int replanForward(TP_STRUCT *tp, double v0_override, double budget_sec)
25612561 // the limit, matching the two-stage brake pattern in computeBranch().
25622562 double scaled_v_entry = prev_exit_vel_known
25632563 ? prev_exit_vel : 0.0 ;
2564- // Cap entry by previous segment's kink_vel
2564+ // Cap entry by previous segment's kink_vel.
2565+ // Skip when predecessor is active: RT delivers its old-feed profile
2566+ // exit velocity regardless of kink_vel. Capping here just creates a
2567+ // v0 mismatch (spike) while the junction jerk is unavoidable either way.
2568+ // The corridor handles deceleration from the real entry velocity.
25652569 {
25662570 TC_STRUCT *prev_tc = (i > 0 ) ? tcqItem_user (queue, i - 1 ) : NULL ;
2567- if (prev_tc && prev_tc->kink_vel > 0 )
2571+ if (prev_tc && prev_tc->kink_vel > 0 && !prev_tc-> active )
25682572 scaled_v_entry = fmin (scaled_v_entry, prev_tc->kink_vel );
25692573 }
25702574
@@ -2575,8 +2579,18 @@ static int replanForward(TP_STRUCT *tp, double v0_override, double budget_sec)
25752579 scaled_v_exit = applyKinkVelCap (scaled_v_exit, v_exit, max_vel, tc->kink_vel );
25762580 double desired_fvel = scaled_v_exit;
25772581
2578- // Cross-feed deceleration corridor detection
2582+ // Cross-feed deceleration corridor detection: entry exceeds
2583+ // feed-scaled max_vel (classic case), OR predecessor was profiled
2584+ // at a different feed and entry is at/above max_vel (edge case where
2585+ // old-feed exit ≈ new-feed max_vel, missed by the 1% threshold).
25792586 bool cross_feed_corridor = (scaled_v_entry > max_vel * 1.01 );
2587+ if (!cross_feed_corridor && scaled_v_entry > max_vel && i > 0 ) {
2588+ TC_STRUCT *prev_tc = tcqItem_user (queue, i - 1 );
2589+ if (prev_tc && prev_tc->shared_9d .profile .valid &&
2590+ fabs (prev_tc->shared_9d .profile .computed_feed_scale
2591+ - feed_scale) > 0.05 )
2592+ cross_feed_corridor = true ;
2593+ }
25802594
25812595 // Forward-lookahead: cap exit by what downstream segments can
25822596 // actually handle. Walks forward until a segment is long enough
@@ -2693,7 +2707,7 @@ static int replanForward(TP_STRUCT *tp, double v0_override, double budget_sec)
26932707 if (pre_bidir_v_entry - scaled_v_entry > 0.1 && i > 0 ) {
26942708 TC_STRUCT *prev_tc = tcqItem_user (queue, i - 1 );
26952709 if (prev_tc && prev_tc->term_cond == TC_TERM_COND_TANGENT &&
2696- prev_tc->shared_9d .profile .valid && !(i == 1 && prev_tc->active ) ) {
2710+ prev_tc->shared_9d .profile .valid && !prev_tc->active ) {
26972711 double prev_feed = snap.forSegment (prev_tc);
26982712 double prev_vel_limit = getEffectiveVelLimit (tp, prev_tc);
26992713 double prev_max_vel = applyVLimit (tp, prev_tc, prev_vel_limit * prev_feed);
@@ -4416,11 +4430,6 @@ extern "C" void checkFeedOverride(TP_STRUCT *tp)
44164430 int seg_id = tc ? tc->id : -1 ;
44174431 g_feed_mgr.planning .onReplanComplete (
44184432 tcqLen_user (&tp->queue ), g_feed_mgr.committed_feed , hal, seg_id);
4419- if (FO_TRACE) {
4420- rtapi_print_msg (RTAPI_MSG_ERR,
4421- " FO cy=%d CONT_FORCE_OPEN qlen=%d (converged, gate was closed)\n " ,
4422- g_fo_cycle, tcqLen_user (&tp->queue ));
4423- }
44244433 }
44254434 }
44264435}
0 commit comments