4 コミット c59b8c1c6c ... ef8787a6c1

作者 SHA1 メッセージ 日付
  tuanchris ef8787a6c1 Revert retry timeout - wait indefinitely for GRBL 'ok' 1 週間 前
  tuanchris fc4287a1cc Add retry logic for motion commands with 1-second timeout 1 週間 前
  tuanchris d103a6fb90 Fix NoneType context manager error in connection manager 1 週間 前
  tuanchris 2c75c085a7 update DAGGKAPRIFOL config 2 週間 前

+ 100 - 0
firmware/dune_weaver_gold/config (DAGGKAPRIFOL).yaml

@@ -0,0 +1,100 @@
+board: MKS-DLC32 V2.1
+name: Dune Weaver Gold
+meta: By Tuan Nguyen (2025-12-25)
+kinematics: {}
+stepping:
+  engine: I2S_STATIC
+  idle_ms: 0
+  pulse_us: 4
+  dir_delay_us: 1
+  disable_delay_us: 0
+axes:
+  shared_stepper_disable_pin: i2so.0
+  x:
+    steps_per_mm: 200
+    max_rate_mm_per_min: 500
+    acceleration_mm_per_sec2: 10
+    max_travel_mm: 325
+    soft_limits: false
+    motor0:
+      limit_neg_pin: gpio.36
+      hard_limits: false
+      pulloff_mm: 2
+      stepstick:
+        step_pin: i2so.1
+        direction_pin: i2so.2
+        disable_pin: NO_PIN
+        ms1_pin: NO_PIN
+        ms2_pin: NO_PIN
+        ms3_pin: NO_PIN
+      limit_pos_pin: NO_PIN
+      limit_all_pin: NO_PIN
+  y:
+    steps_per_mm: 250
+    max_rate_mm_per_min: 500
+    acceleration_mm_per_sec2: 10
+    max_travel_mm: 6.25
+    soft_limits: false
+    motor0:
+      limit_neg_pin: gpio.35
+      hard_limits: false
+      pulloff_mm: 2
+      stepstick:
+        step_pin: i2so.5
+        direction_pin: i2so.6:low
+        disable_pin: NO_PIN
+        ms1_pin: NO_PIN
+        ms2_pin: NO_PIN
+        ms3_pin: NO_PIN
+      limit_pos_pin: NO_PIN
+      limit_all_pin: NO_PIN
+i2so:
+  bck_pin: gpio.16
+  data_pin: gpio.21
+  ws_pin: gpio.17
+sdcard:
+  cs_pin: gpio.15
+  card_detect_pin: NO_PIN
+control:
+  safety_door_pin: NO_PIN
+  reset_pin: NO_PIN
+  feed_hold_pin: NO_PIN
+  cycle_start_pin: NO_PIN
+  macro0_pin: gpio.33:pu:low
+  macro1_pin: NO_PIN
+  macro2_pin: NO_PIN
+  macro3_pin: NO_PIN
+  fault_pin: NO_PIN
+  estop_pin: NO_PIN
+macros:
+  macro0: G90
+coolant:
+  flood_pin: NO_PIN
+  mist_pin: NO_PIN
+  delay_ms: 0
+user_outputs:
+  analog0_pin: NO_PIN
+  analog1_pin: NO_PIN
+  analog2_pin: NO_PIN
+  analog3_pin: NO_PIN
+  analog0_hz: 5000
+  analog1_hz: 5000
+  analog2_hz: 5000
+  analog3_hz: 5000
+  digital0_pin: NO_PIN
+  digital1_pin: NO_PIN
+  digital2_pin: NO_PIN
+  digital3_pin: NO_PIN
+start:
+  must_home: false
+spi:
+  miso_pin: gpio.12
+  mosi_pin: gpio.13
+  sck_pin: gpio.14
+uart1:
+  txd_pin: gpio.19
+  rxd_pin: gpio.18
+  baud: 115200
+  mode: 8N1
+uart_channel1:
+  uart_num: 1

+ 6 - 5
modules/connection/connection_manager.py

@@ -116,8 +116,6 @@ class SerialConnection(BaseConnection):
         with self.lock:
             if self.ser.is_open:
                 self.ser.close()
-        # Release the lock resources
-        self.lock = None
 
 ###############################################################################
 # WebSocket Connection Implementation
@@ -181,8 +179,7 @@ class WebSocketConnection(BaseConnection):
         with self.lock:
             if self.ws:
                 self.ws.close()
-        # Release the lock resources
-        self.lock = None
+                self.ws = None
                 
 def list_serial_ports():
     """Return a list of available serial ports."""
@@ -360,6 +357,10 @@ def get_status_response() -> str:
     """
     Send a status query ('?') and return the response if available.
     """
+    if state.conn is None or not state.conn.is_connected():
+        logger.warning("Cannot get status response: no active connection")
+        return False
+
     while True:
         try:
             state.conn.send('?')
@@ -834,7 +835,7 @@ def get_machine_steps(timeout=10):
             state.table_type = 'dune_weaver_mini'
         elif y_steps_per_mm == 210 and x_steps_per_mm == 256:
             state.table_type = 'dune_weaver_mini_pro_byj'
-        elif y_steps_per_mm == 270 and x_steps_per_mm == 200:
+        elif (y_steps_per_mm == 270 or y_steps_per_mm == 250) and x_steps_per_mm == 200:
             state.table_type = 'dune_weaver_gold'
         elif y_steps_per_mm == 287:
             state.table_type = 'dune_weaver'

+ 23 - 12
modules/core/pattern_manager.py

@@ -371,25 +371,35 @@ class MotionControlThread:
         state.machine_y = new_y_abs
 
     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."""
-        logger.debug(f"Motion thread sending G-code: X{x} Y{y} at F{speed}")
+        """Synchronous version of send_grbl_coordinates for motion thread.
 
-        # Track overall attempt time
-        overall_start_time = time.time()
+        Waits indefinitely for 'ok' because GRBL only responds after the move completes,
+        which can take many seconds at slow speeds.
+        """
+        gcode = f"$J=G91 G21 Y{y} F{speed}" if home else f"G1 G53 X{x} Y{y} F{speed}"
 
         while True:
+            # Check stop_requested at the start of each iteration
+            if state.stop_requested:
+                logger.debug("Motion thread: Stop requested, aborting command")
+                return False
+
             try:
-                gcode = f"$J=G91 G21 Y{y} F{speed}" if home else f"G1 G53 X{x} Y{y} F{speed}"
+                logger.debug(f"Motion thread sending G-code: {gcode}")
                 state.conn.send(gcode + "\n")
-                logger.debug(f"Motion thread sent command: {gcode}")
 
-                start_time = time.time()
+                # Wait indefinitely for 'ok' - GRBL sends it after move completes
                 while True:
+                    # Check stop_requested while waiting
+                    if state.stop_requested:
+                        logger.debug("Motion thread: Stop requested while waiting for response")
+                        return False
                     response = state.conn.readline()
-                    logger.debug(f"Motion thread response: {response}")
-                    if response.lower() == "ok":
-                        logger.debug("Motion thread: Command execution confirmed.")
-                        return
+                    if response:
+                        logger.debug(f"Motion thread response: {response}")
+                        if response.lower() == "ok":
+                            logger.debug("Motion thread: Command execution confirmed.")
+                            return True
 
             except Exception as e:
                 error_str = str(e)
@@ -404,7 +414,8 @@ class MotionControlThread:
                     logger.info("Connection marked as disconnected due to device error")
                     return False
 
-            logger.warning(f"Motion thread: No 'ok' received for X{x} Y{y}, speed {speed}. Retrying...")
+            # Only retry on exception (not on timeout)
+            logger.warning(f"Motion thread: Error sending {gcode}, retrying...")
             time.sleep(0.1)
 
 # Global motion control thread instance