Skip to content

Commit 44a99b0

Browse files
committed
90 and 100% ok
1 parent 20425e2 commit 44a99b0

1 file changed

Lines changed: 96 additions & 28 deletions

File tree

src/emc/motion_planning/motion_planning_9d.cc

Lines changed: 96 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,9 +1177,10 @@ static double computeChainExitCap(TP_STRUCT *tp, TC_STRUCT *active_tc,
11771177

11781178
if (seg->kink_vel > 0) seg_exit = fmin(seg_exit, seg->kink_vel);
11791179

1180+
double seg_acc = tcGetTangentialMaxAccel_9D_user(seg);
11801181
double brake_dist = jerkLimitedBrakingDistance(
1181-
seg_max_vel, seg_exit, seg->maxaccel, seg_jrk);
1182-
1182+
seg_max_vel, seg_exit, seg_acc, seg_jrk);
1183+
11831184
if (seg->target > brake_dist * 1.2) break; // safe: can absorb any entry
11841185
}
11851186

@@ -1210,8 +1211,9 @@ static double computeChainExitCap(TP_STRUCT *tp, TC_STRUCT *active_tc,
12101211
seg_exit = fmin(seg_exit, next_entry_cap);
12111212

12121213
// Max entry this segment can accept
1214+
double seg_acc = tcGetTangentialMaxAccel_9D_user(seg);
12131215
double max_entry = jerkLimitedMaxEntryVelocity(
1214-
seg_exit, seg->target, seg->maxaccel, seg_jrk);
1216+
seg_exit, seg->target, seg_acc, seg_jrk);
12151217
max_entry = fmin(max_entry, seg_max_vel);
12161218

12171219
// Apply kink at the junction before this segment
@@ -2558,29 +2560,30 @@ static int replanForward(TP_STRUCT *tp, double v0_override, double budget_sec)
25582560
// Cross-feed deceleration corridor detection
25592561
bool cross_feed_corridor = (scaled_v_entry > max_vel * 1.01);
25602562

2561-
// Forward-lookahead: cap exit by what the next segment can actually
2562-
// enter (jerk-limited braking to its exit vel). The backward pass
2563-
// uses trapezoidal for v_f≈0 which overestimates; this corrects the
2564-
// junction before the profile is committed.
2563+
// Forward-lookahead: cap exit by what downstream segments can
2564+
// actually handle. Walks forward until a segment is long enough
2565+
// to absorb any entry (physics-based stop), then cascades
2566+
// reachability backward — same algorithm as computeChainExitCap.
25652567
// Skip when in cross-feed corridor — the lookahead uses backward-pass
25662568
// exits at the wrong feed scale, producing overly tight caps that
25672569
// cascade forward and crush entry velocities on short segments.
25682570
if (!cross_feed_corridor && scaled_v_exit > 0.0 && i + 1 < queue_len) {
2569-
TC_STRUCT *next_tc = tcqItem_user(queue, i + 1);
2570-
if (next_tc && next_tc->target > 1e-9) {
2571-
double nf = snap.forSegment(next_tc);
2572-
double nv_exit = (next_tc->term_cond == TC_TERM_COND_TANGENT)
2573-
? readFinalVelCapped(next_tc) * nf : 0.0;
2574-
double na = tcGetTangentialMaxAccel_9D_user(next_tc);
2575-
double nj = next_tc->maxjerk > 0 ? next_tc->maxjerk : default_jerk;
2576-
double reach = jerkLimitedMaxEntryVelocity(nv_exit, next_tc->target, na, nj);
2577-
double nvel_limit = getEffectiveVelLimit(tp, next_tc);
2578-
double next_max = applyVLimit(tp, next_tc, nvel_limit * nf);
2579-
reach = fmin(reach, next_max);
2580-
if (reach < scaled_v_exit) {
2581-
scaled_v_exit = reach;
2582-
desired_fvel = reach;
2583-
}
2571+
double chain_cap = computeChainExitCap(
2572+
tp, tc, feed_scale, default_jerk, /*max_depth=*/16,
2573+
/*start_index=*/i + 1);
2574+
if (FO_TRACE && chain_cap < 1e9) {
2575+
TC_STRUCT *next_tc = tcqItem_user(queue, i + 1);
2576+
rtapi_print_msg(RTAPI_MSG_ERR,
2577+
"FO_CHAIN i=%d seg=%d chain_cap=%.3f scaled_exit=%.3f "
2578+
"capped=%d next_type=%d next_term=%d\n",
2579+
i, tc->id, chain_cap, scaled_v_exit,
2580+
chain_cap < scaled_v_exit ? 1 : 0,
2581+
next_tc ? next_tc->motion_type : -1,
2582+
next_tc ? next_tc->term_cond : -1);
2583+
}
2584+
if (chain_cap < scaled_v_exit) {
2585+
scaled_v_exit = chain_cap;
2586+
desired_fvel = chain_cap;
25842587
}
25852588
}
25862589

@@ -2612,6 +2615,16 @@ static int replanForward(TP_STRUCT *tp, double v0_override, double budget_sec)
26122615
if (tc->term_cond == TC_TERM_COND_TANGENT) {
26132616
double pu = profileExitVelUnscaled(&tc->shared_9d.profile);
26142617
prev_exit_vel = pu * tc->shared_9d.profile.computed_feed_scale;
2618+
if (FO_TRACE && fabs(prev_exit_vel - desired_fvel) > 0.1) {
2619+
rtapi_print_msg(RTAPI_MSG_ERR,
2620+
"FO_SKIP_EXIT_GAP i=%d seg=%d type=%d "
2621+
"desired_fvel=%.3f prof_exit=%.3f gap=%.3f "
2622+
"entry=%.3f target=%.4f\n",
2623+
i, tc->id, tc->motion_type,
2624+
desired_fvel, prev_exit_vel,
2625+
desired_fvel - prev_exit_vel,
2626+
scaled_v_entry, tc->target);
2627+
}
26152628
} else {
26162629
prev_exit_vel = 0.0;
26172630
}
@@ -2677,6 +2690,57 @@ static int replanForward(TP_STRUCT *tp, double v0_override, double budget_sec)
26772690
applyBidirectionalReachability(scaled_v_entry, scaled_v_exit,
26782691
tc->target, max_acc, max_jrk);
26792692

2693+
// Backward propagation: if bidir reduced our entry, the predecessor's
2694+
// profile exit is too high. Rewrite it with the bidir-capped exit
2695+
// so RT sees a consistent junction velocity.
2696+
if (pre_bidir_v_entry - scaled_v_entry > 0.1 && i > 0) {
2697+
TC_STRUCT *prev_tc = tcqItem_user(queue, i - 1);
2698+
if (prev_tc && prev_tc->term_cond == TC_TERM_COND_TANGENT &&
2699+
prev_tc->shared_9d.profile.valid && !(i == 1 && prev_tc->active)) {
2700+
double prev_feed = snap.forSegment(prev_tc);
2701+
double prev_vel_limit = getEffectiveVelLimit(tp, prev_tc);
2702+
double prev_max_vel = applyVLimit(tp, prev_tc, prev_vel_limit * prev_feed);
2703+
double prev_max_acc = tcGetTangentialMaxAccel_9D_user(prev_tc);
2704+
double prev_max_jrk = prev_tc->maxjerk > 0 ? prev_tc->maxjerk : default_jerk;
2705+
double prev_v_entry = prev_tc->shared_9d.profile.v[0];
2706+
double prev_v_exit = scaled_v_entry;
2707+
applyBidirectionalReachability(prev_v_entry, prev_v_exit,
2708+
prev_tc->target, prev_max_acc, prev_max_jrk);
2709+
double ruckig_max = fmax(prev_v_entry, prev_max_vel);
2710+
RuckigProfileParams rp = {prev_v_entry, prev_v_exit,
2711+
ruckig_max, prev_max_acc, prev_max_jrk, prev_tc->target,
2712+
prev_feed, prev_vel_limit, tp->vLimit, prev_v_exit};
2713+
if (!computeAndStoreProfile(prev_tc, rp)) {
2714+
ruckig_max *= 1.001;
2715+
rp.max_vel = ruckig_max;
2716+
computeAndStoreProfile(prev_tc, rp);
2717+
}
2718+
if (prev_tc->shared_9d.profile.valid) {
2719+
prev_tc->shared_9d.profile.dbg_src = 2;
2720+
atomicStoreInt((int*)&prev_tc->shared_9d.optimization_state,
2721+
TC_PLAN_FINALIZED);
2722+
}
2723+
}
2724+
}
2725+
2726+
if (FO_TRACE && (pre_bidir_v_entry - scaled_v_entry > 0.1 ||
2727+
pre_bidir_v_exit - scaled_v_exit > 0.1)) {
2728+
TC_STRUCT *prev_tc = (i > 0) ? tcqItem_user(queue, i - 1) : NULL;
2729+
rtapi_print_msg(RTAPI_MSG_ERR,
2730+
"FO_BIDIR_GAP i=%d seg=%d type=%d "
2731+
"entry=%.3f->%.3f exit=%.3f->%.3f "
2732+
"target=%.4f prev_exit=%.3f "
2733+
"prev_seg=%d prev_type=%d "
2734+
"max_a=%.1f max_j=%.1f kink=%.3f\n",
2735+
i, tc->id, tc->motion_type,
2736+
pre_bidir_v_entry, scaled_v_entry,
2737+
pre_bidir_v_exit, scaled_v_exit,
2738+
tc->target, prev_exit_vel,
2739+
prev_tc ? prev_tc->id : -999,
2740+
prev_tc ? prev_tc->motion_type : -1,
2741+
max_acc, max_jrk, tc->kink_vel);
2742+
}
2743+
26802744
// Log cross-feed or zero-entry profile writes (first 5 per pass)
26812745
if (FO_TRACE && fo_dirty_count < 5 &&
26822746
(fabs(pre_bidir_v_entry) < 0.01 ||
@@ -2698,15 +2762,19 @@ static int replanForward(TP_STRUCT *tp, double v0_override, double budget_sec)
26982762
// Raise Ruckig max_velocity when entry exceeds feed-scaled limit
26992763
// (cross-feed junction). Same pattern as computeBranch() two-stage
27002764
// brake: fmax(state.velocity, new_max_vel).
2701-
// The 0.1% margin avoids Ruckig ErrorExecutionTimeCalculation
2702-
// (-110) which fires when max_velocity == current_velocity
2703-
// exactly — a degenerate case that hits every cross-feed
2704-
// corridor segment since fmax(v0, max_vel) == v0 by definition.
2705-
double ruckig_max_vel = fmax(scaled_v_entry, max_vel) * 1.001;
2765+
double ruckig_max_vel = fmax(scaled_v_entry, max_vel);
27062766
RuckigProfileParams rp = {scaled_v_entry, scaled_v_exit,
27072767
ruckig_max_vel, max_acc, max_jrk, tc->target,
27082768
feed_scale, vel_limit, tp->vLimit, desired_fvel};
2709-
if (computeAndStoreProfile(tc, rp)) {
2769+
if (!computeAndStoreProfile(tc, rp)) {
2770+
// Retry with 0.1% margin: Ruckig ErrorExecutionTimeCalculation
2771+
// (-110) fires when max_velocity == current_velocity exactly —
2772+
// a degenerate case at cross-feed corridor boundaries.
2773+
ruckig_max_vel *= 1.001;
2774+
rp.max_vel = ruckig_max_vel;
2775+
computeAndStoreProfile(tc, rp);
2776+
}
2777+
if (tc->shared_9d.profile.valid) {
27102778
fo_dirty_count++;
27112779
tc->shared_9d.profile.dbg_src = 2; // forward pass
27122780
tc->shared_9d.profile.dbg_v0_req = scaled_v_entry;

0 commit comments

Comments
 (0)