diff --git a/docs/src/gcode/g-code.adoc b/docs/src/gcode/g-code.adoc index 6253e57afb2..19e519dc480 100644 --- a/docs/src/gcode/g-code.adoc +++ b/docs/src/gcode/g-code.adoc @@ -1073,14 +1073,19 @@ threads. [[gcode:g33-tech-info]] .Technical Info -At the beginning of each G33 pass, LinuxCNC uses the spindle speed and -the machine acceleration limits to calculate how long it will take Z to -accelerate after the index pulse, and determines how many degrees the -spindle will rotate during that time. It then adds that angle to the -index position and computes the Z position using the corrected spindle -angle. That means that Z will reach the correct position just as it -finishes accelerating to the proper speed, and can immediately begin -cutting a good thread. +A G33 move waits for the spindle index, then accelerates from rest to the +synchronized feed. The commanded position follows the spindle angle measured +from that index, so a given thread is cut in the same place whatever the +spindle speed. + +While the axis is still accelerating it falls behind that position, by roughly +the pitch squared times the spindle speed squared over twice the axis +acceleration limit, and it makes the distance up over the rest of the move. +Allow enough lead-in for it to catch up before the cut begins, or the start of +the thread is cut with the wrong lead. LinuxCNC reports 'lead-in too short to +reach sync' when the move ends before the axis has caught up. A small lag +proportional to speed remains for the rest of the move, which is why the +spindle speed must not change while a thread is being cut. .HAL Connections The pin 'spindle.N.at-speed' must be set or driven true for the motion to diff --git a/src/emc/tp/tp.c b/src/emc/tp/tp.c index b193b76fb83..f7d58f50e47 100644 --- a/src/emc/tp/tp.c +++ b/src/emc/tp/tp.c @@ -3567,6 +3567,29 @@ STATIC void tpSyncVelocityMode(TP_STRUCT * const tp, TC_STRUCT * const tc, TC_ST } +/** + * Warn when the segment is too short to absorb the lead-in lag. + * The tracking loop below closes an error e with v = v_spindle + sqrt(e * a), + * which takes 2 * sqrt(e / a) seconds. + */ +STATIC void tpCheckSyncLeadIn(TC_STRUCT const * const tc, double pos_error) +{ + double accel = tcGetTangentialMaxAccel(tc); + if (accel <= 0.0) { + return; + } + double err = fabs(pos_error); + double catchup = tc->currentvel * 2.0 * pmSqrt(err / accel) + err; + double remaining = tc->target - tc->progress; + if (catchup > remaining) { + rtapi_print_msg(RTAPI_MSG_ERR, + "spindle-synchronized move %d: lead-in too short to reach sync, " + "need %f more travel\n", + tc->id, catchup - remaining); + } +} + + /** * Run position mode synchronization. * Updates requested velocity for a trajectory segment to track the spindle's position. @@ -3603,10 +3626,13 @@ STATIC void tpSyncPositionMode(TP_STRUCT * const tp, TC_STRUCT * const tc, target_vel = spindle_vel * tc->uu_per_rev; if(tc->currentvel >= target_vel) { tc_debug_print("Hit accel target in pos sync\n"); - // move target so as to drive pos_error to 0 next cycle - tp->spindle.offset = tp->spindle.revs - tc->progress / tc->uu_per_rev; + // Leave the sync origin on the spindle index. The lag built up + // while ramping to sync speed is a real position error, so hand it + // to the tracking loop below; folding it into the origin instead + // shifts the thread by an amount that grows with spindle speed. tc->sync_accel = 0; tc->target_vel = target_vel; + tpCheckSyncLeadIn(tc, pos_error); } else { tc_debug_print("accelerating in pos_sync\n"); // beginning of move and we are behind: accel as fast as we can