@@ -507,6 +507,22 @@ void emcmotCommandHandler_locked(void *arg, long servo_period)
507507 if (GET_MOTION_TELEOP_FLAG ()) {
508508 axis_jog_abort_all (0 );
509509 } else if (GET_MOTION_COORD_FLAG ()) {
510+ /* If motion was being held waiting for spindle at-speed, the
511+ operator most likely aborted because the machine sat idle
512+ with no obvious reason. Tell them why, loudly. A wait that
513+ never released after a spindle stop almost always means
514+ spindle.N.at-speed is not wired, or does not go true once the
515+ spindle has actually stopped. */
516+ if (MOTION_ID_VALID (emcmotInternal -> coord_tp .spindle .waiting_for_atspeed )) {
517+ for (spindle_num = 0 ; spindle_num < emcmotConfig -> numSpindles ; spindle_num ++ ) {
518+ if (emcmotStatus -> spindle_status [spindle_num ].state == 0 && !emcmotStatus -> spindle_status [spindle_num ].at_speed ) {
519+ reportError (_ ("Aborted while waiting for spindle %d at-speed after a spindle stop. "
520+ "Check that spindle.%d.at-speed is connected and goes true once the spindle has stopped." ),
521+ spindle_num , spindle_num );
522+ break ;
523+ }
524+ }
525+ }
510526 tpAbort (& emcmotInternal -> coord_tp );
511527 } else {
512528 for (joint_num = 0 ; joint_num < ALL_JOINTS ; joint_num ++ ) {
@@ -530,6 +546,8 @@ void emcmotCommandHandler_locked(void *arg, long servo_period)
530546 SET_JOINT_FAULT_FLAG (joint , 0 );
531547 }
532548 emcmotStatus -> paused = 0 ;
549+ /* Drop any pending at-speed barrier so it can't strand a later move. */
550+ emcmotStatus -> atspeed_next_feed = 0 ;
533551 // Clear pins on abort so tests see a clean state
534552 if (emcmot_hal_data ) {
535553 * (emcmot_hal_data -> interp_arc_radius ) = 0.0 ;
@@ -1496,6 +1514,14 @@ void emcmotCommandHandler_locked(void *arg, long servo_period)
14961514 }
14971515 }
14981516
1517+ /* A probe is a feed-type move, so honor any pending at-speed
1518+ barrier just like G1: wait for spindle.N.at-speed (spin-up after
1519+ M3, or stop after M5) before the probe starts. */
1520+ if (emcmotStatus -> atspeed_next_feed ) {
1521+ issue_atspeed = 1 ;
1522+ emcmotStatus -> atspeed_next_feed = 0 ;
1523+ }
1524+
14991525 /* append it to the emcmotInternal->coord_tp */
15001526 tpSetId (& emcmotInternal -> coord_tp , emcmotCommand -> id );
15011527 if (-1 == tpAddLine (& emcmotInternal -> coord_tp ,
@@ -1506,7 +1532,7 @@ void emcmotCommandHandler_locked(void *arg, long servo_period)
15061532 emcmotCommand -> acc ,
15071533 emcmotCommand -> ini_maxjerk ,
15081534 emcmotStatus -> enables_new ,
1509- 0 ,
1535+ issue_atspeed ,
15101536 -1 ,
15111537 emcmotCommand -> tag )) {
15121538 reportError (_ ("can't add probe move" ));
@@ -1702,6 +1728,10 @@ void emcmotCommandHandler_locked(void *arg, long servo_period)
17021728 * (emcmot_hal_data -> spindle [n ].spindle_orient ) = 0 ;
17031729 emcmotStatus -> spindle_status [n ].orient_state = EMCMOT_ORIENT_NONE ;
17041730 }
1731+ /* Optionally make the spindle stop an at-speed barrier: the next feed
1732+ move waits until at-speed reflects the stopped state. Safe when
1733+ unwired since at-speed defaults to 1 (see motion.c). */
1734+ emcmotStatus -> atspeed_next_feed = emcmotCommand -> wait_for_spindle_at_speed ;
17051735 break ;
17061736
17071737 case EMCMOT_SPINDLE_ORIENT :
0 commit comments