@@ -1174,9 +1174,24 @@ static double computeChainExitCap(TP_STRUCT *tp, TC_STRUCT *active_tc,
11741174 double seg_jrk = seg->maxjerk > 0 ? seg->maxjerk : default_jerk;
11751175 double seg_fv = readFinalVelCapped (seg);
11761176 double seg_exit = fmin (seg_fv * seg_feed, seg_max_vel);
1177-
1177+
11781178 if (seg->kink_vel > 0 ) seg_exit = fmin (seg_exit, seg->kink_vel );
11791179
1180+ // When the next segment is STOP/EXACT (v_f≈0), the backward pass
1181+ // uses trapezoidal formula sqrt(2*a*d) which ignores jerk limits.
1182+ // This inflates final_vel beyond what Ruckig can achieve. Cap to
1183+ // profile exit so the chain propagates physically consistent limits.
1184+ TC_STRUCT *next_in_chain = tcqItem_user (&tp->queue , i + 1 );
1185+ if (next_in_chain &&
1186+ (next_in_chain->term_cond == TC_TERM_COND_STOP ||
1187+ next_in_chain->term_cond == TC_TERM_COND_EXACT) &&
1188+ seg->shared_9d .profile .valid &&
1189+ seg->term_cond == TC_TERM_COND_TANGENT) {
1190+ double prof_exit = profileExitVelUnscaled (&seg->shared_9d .profile )
1191+ * seg->shared_9d .profile .computed_feed_scale ;
1192+ seg_exit = fmin (seg_exit, prof_exit);
1193+ }
1194+
11801195 double seg_acc = tcGetTangentialMaxAccel_9D_user (seg);
11811196 double brake_dist = jerkLimitedBrakingDistance (
11821197 seg_max_vel, seg_exit, seg_acc, seg_jrk);
@@ -1204,9 +1219,24 @@ static double computeChainExitCap(TP_STRUCT *tp, TC_STRUCT *active_tc,
12041219 double seg_fv = readFinalVelCapped (seg);
12051220 double seg_exit = (seg->term_cond == TC_TERM_COND_TANGENT)
12061221 ? fmin (seg_fv * seg_feed, seg_max_vel) : 0.0 ;
1207-
1222+
12081223 if (seg->kink_vel > 0 ) seg_exit = fmin (seg_exit, seg->kink_vel );
12091224
1225+ // When the next segment is STOP/EXACT (v_f≈0), the backward pass
1226+ // uses trapezoidal formula sqrt(2*a*d) which ignores jerk limits.
1227+ // This inflates final_vel beyond what Ruckig can achieve. Cap to
1228+ // profile exit so the chain propagates physically consistent limits.
1229+ TC_STRUCT *next_in_chain_p2 = tcqItem_user (&tp->queue , i + 1 );
1230+ if (next_in_chain_p2 &&
1231+ (next_in_chain_p2->term_cond == TC_TERM_COND_STOP ||
1232+ next_in_chain_p2->term_cond == TC_TERM_COND_EXACT) &&
1233+ seg->shared_9d .profile .valid &&
1234+ seg->term_cond == TC_TERM_COND_TANGENT) {
1235+ double prof_exit = profileExitVelUnscaled (&seg->shared_9d .profile )
1236+ * seg->shared_9d .profile .computed_feed_scale ;
1237+ seg_exit = fmin (seg_exit, prof_exit);
1238+ }
1239+
12101240 // Cap exit by what next segment can accept (cascading backward)
12111241 seg_exit = fmin (seg_exit, next_entry_cap);
12121242
0 commit comments