Sfoglia il codice sorgente

Add 120s timeout to motion thread readline loop

Previously the motion thread would wait indefinitely for 'ok' response.
If serial communication fails silently (no exception, just no data),
the pattern would hang forever.

Now after 120 seconds without 'ok', the motion thread:
- Logs an error about the timeout
- Sets stop_requested = True to stop the pattern
- Returns False to signal the failure

Also added logging for GRBL error/alarm responses for debugging.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
tuanchris 1 settimana fa
parent
commit
afb73dbad8
1 ha cambiato i file con 18 aggiunte e 3 eliminazioni
  1. 18 3
      modules/core/pattern_manager.py

+ 18 - 3
modules/core/pattern_manager.py

@@ -518,10 +518,12 @@ class MotionControlThread:
     def _send_grbl_coordinates_sync(self, x: float, y: float, speed: int = 600, timeout: int = 2, home: bool = False):
         """Synchronous version of send_grbl_coordinates for motion thread.
 
-        Waits indefinitely for 'ok' because GRBL only responds after the move completes,
-        which can take many seconds at slow speeds.
+        Waits for 'ok' with a timeout. GRBL sends 'ok' after the move completes,
+        which can take many seconds at slow speeds. We use a generous timeout
+        (120 seconds) to handle slow movements, but prevent indefinite hangs.
         """
         gcode = f"$J=G91 G21 Y{y} F{speed}" if home else f"G1 G53 X{x} Y{y} F{speed}"
+        max_wait_time = 120  # Maximum seconds to wait for 'ok' response
 
         while True:
             # Check stop_requested at the start of each iteration
@@ -533,18 +535,31 @@ class MotionControlThread:
                 logger.debug(f"Motion thread sending G-code: {gcode}")
                 state.conn.send(gcode + "\n")
 
-                # Wait indefinitely for 'ok' - GRBL sends it after move completes
+                # Wait for 'ok' with timeout
+                wait_start = time.time()
                 while True:
                     # Check stop_requested while waiting
                     if state.stop_requested:
                         logger.debug("Motion thread: Stop requested while waiting for response")
                         return False
+
+                    # Check for timeout
+                    elapsed = time.time() - wait_start
+                    if elapsed > max_wait_time:
+                        logger.error(f"Motion thread: Timeout ({max_wait_time}s) waiting for 'ok' response")
+                        logger.error("Possible serial communication issue - stopping pattern")
+                        state.stop_requested = True
+                        return False
+
                     response = state.conn.readline()
                     if response:
                         logger.debug(f"Motion thread response: {response}")
                         if response.lower() == "ok":
                             logger.debug("Motion thread: Command execution confirmed.")
                             return True
+                        # Log unexpected responses for debugging
+                        if "error" in response.lower() or "alarm" in response.lower():
+                            logger.warning(f"Motion thread: GRBL error/alarm: {response}")
                     # Small sleep to prevent CPU spin when readline() times out
                     time.sleep(0.01)