Skip to content

Commit d35cbe5

Browse files
committed
Queue depth gate: eliminate velocity spike at segment activation
Extend the RT queue depth gate to all non-EXACT segments, not just id==0. When a segment is alone in the queue, its profile is computed with v_exit=0 (no successor yet). Previously, RT would activate it immediately, and the optimizer's active-segment skip prevented correction when the successor arrived — causing a velocity spike at the junction. The gate holds activation until queue_len >= 2 or 20ms timeout, giving the optimizer time to recompute with the correct exit velocity while the segment is still inactive. EXACT segments (last of program) skip the gate since their v_exit=0 is always correct. Also removes investigation debug probes (FIX4_DBG, STUCK_FORCE).
1 parent 4e5ceea commit d35cbe5

2 files changed

Lines changed: 24 additions & 30 deletions

File tree

src/emc/motion_planning/motion_planning_9d.cc

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4339,16 +4339,6 @@ int computeRuckigProfiles_9D(TP_STRUCT *tp, TC_QUEUE_STRUCT *queue, int optimiza
43394339
}
43404340
if (is_first_profile && v_exit > 0.0) {
43414341
v_exit = 0.0;
4342-
// Debug: log Fix 4 pessimistic override
4343-
{
4344-
static int fix4_dbg_count = 0;
4345-
if (fix4_dbg_count < 30) {
4346-
fix4_dbg_count++;
4347-
rtapi_print_msg(RTAPI_MSG_ERR,
4348-
"FIX4_DBG[id=%d]: first_profile v_exit forced 0 (was %.3f) type=%d target=%.3f\n",
4349-
tc->id, atomicLoadDouble(&tc->shared_9d.final_vel), tc->motion_type, tc->target);
4350-
}
4351-
}
43524342
}
43534343

43544344
// prev_exit_vel is updated AFTER Ruckig compute (below) to use
@@ -4449,8 +4439,6 @@ int computeRuckigProfiles_9D(TP_STRUCT *tp, TC_QUEUE_STRUCT *queue, int optimiza
44494439
prev_exit_feed_scale = feed_scale;
44504440
prev_exit_vel_known = true;
44514441

4452-
4453-
44544442
// One-step backtrack: fix backward reachability gap
44554443
// Skip active segment — rewriting triggers STOPWATCH_RESET
44564444
// with velocity discontinuity worse than the chain gap.

src/emc/tp/tp.c

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4557,11 +4557,6 @@ STATIC int tpCheckEndCondition(TP_STRUCT const * const tp, TC_STRUCT * const tc,
45574557

45584558
if (stuck_cycles > 10) { // Stuck for 10ms
45594559
// Force to target
4560-
printf("STUCK_FORCE seg=%d progress=%.6f target=%.6f dx=%.6f "
4561-
"vel=%.6f elapsed=%.6f dur=%.6f pos_base=%.6f\n",
4562-
tc->id, tc->progress, tc->target, dx,
4563-
tc->currentvel, tc->elapsed_time,
4564-
tc->shared_9d.profile.duration, tc->position_base);
45654560
dx = 0.0;
45664561
tc->progress = tc->target;
45674562
stuck_cycles = 0;
@@ -5024,7 +5019,7 @@ STATIC int tpHandleRegularCycle(TP_STRUCT * const tp,
50245019
//Run with full cycle time
50255020
tc_debug_print("Normal cycle\n");
50265021
tc->cycle_time = tp->cycleTime;
5027-
5022+
50285023
int mode = 0;
50295024
tpUpdateCycle(tp, tc, nexttc, &mode);
50305025

@@ -5133,24 +5128,35 @@ int tpRunCycle(TP_STRUCT * const tp, long period)
51335128
profile_wait_count = 0;
51345129
}
51355130

5136-
/* Only delay on the FIRST segment of a program (id == 0).
5137-
* Without the id check, this also triggers on the LAST segment
5138-
* (which also has progress=0, queue_len=1, nexttc=NULL) causing
5139-
* a 100-cycle delay before the final move executes. */
5140-
if (tc->id == 0 && tc->progress < TP_POS_EPSILON && queue_len < 2 && nexttc == NULL) {
5141-
static int startup_wait_count = 0;
5142-
startup_wait_count++;
5131+
/* Queue depth gate: wait for at least 2 segments before activating.
5132+
* When a segment is alone in the queue (queue_len < 2), its profile
5133+
* may have been computed with v_exit=0 (no successor/blend yet).
5134+
* The gate holds RT until the interpreter adds the next segment,
5135+
* giving the optimizer a chance to recompute with the correct
5136+
* exit velocity. The segment is NOT active during the gate,
5137+
* so the optimizer's active-segment skip doesn't prevent correction.
5138+
*
5139+
* Skip the gate for EXACT segments (last segment of program) —
5140+
* their v_exit=0 is always correct, no correction needed. */
5141+
if (tc->progress < TP_POS_EPSILON && queue_len < 2 && nexttc == NULL
5142+
&& tc->term_cond != TC_TERM_COND_EXACT) {
5143+
static int gate_seg_id = -1;
5144+
static int gate_wait_count = 0;
5145+
/* Reset counter for each new segment */
5146+
if (tc->id != gate_seg_id) {
5147+
gate_seg_id = tc->id;
5148+
gate_wait_count = 0;
5149+
}
5150+
gate_wait_count++;
51435151

5144-
/* Wait up to 100 cycles (100ms) for more segments */
5145-
if (startup_wait_count < 100) {
5152+
/* Wait up to 20 cycles (20ms at 1kHz) for a successor */
5153+
if (gate_wait_count < 20) {
51465154
return TP_ERR_WAITING;
51475155
}
5148-
startup_wait_count = 0; // Reset for next program
5156+
gate_wait_count = 0;
51495157
}
51505158
}
51515159

5152-
/* Removed verbose segment debug - now proven to work */
5153-
51545160
tc_debug_print("-------------------\n");
51555161

51565162
/* Apply pre-computed 9D optimizer velocities if planner_type == 2

0 commit comments

Comments
 (0)