Przeglądaj źródła

handle retry better

Tuan Nguyen 1 rok temu
rodzic
commit
5d32c3bf83

+ 1 - 1
dune_weaver_flask/app.py

@@ -471,7 +471,7 @@ def entrypoint():
 
     try:
         logger.info("Starting Flask server on port 8080...")
-        app.run(debug=False, host='0.0.0.0', port=8080)
+        app.run(debug=True, host='0.0.0.0', port=8080)
     except KeyboardInterrupt:
         logger.info("Keyboard interrupt received. Shutting down.")
     except Exception as e:

+ 35 - 12
dune_weaver_flask/modules/core/pattern_manager.py

@@ -160,26 +160,49 @@ def run_theta_rho_file(file_path, schedule_hours=None):
     execution_progress = (0, total_coordinates, None)
 
     stop_actions()
+    BATCH_SIZE = 15  # Max planner buffer size
+
     with serial_manager.serial_lock:
         current_playing_file = file_path
         execution_progress = (0, 0, None)
         stop_requested = False
         logger.info(f"Starting pattern execution: {file_path}")
-        logger.info(f"t: {current_theta}, r: {current_rho}")
+        logger.debug(f"t: {current_theta}, r: {current_rho}")
         reset_theta()
-        for coordinate in tqdm(coordinates):
-            theta, rho = coordinate
-            if stop_requested:
-                logger.info("Execution stopped by user after completing the current batch")
-                break
 
-            with pause_condition:
-                while pause_requested:
-                    logger.info("Execution paused...")
-                    pause_condition.wait()
+        sent_index = 0  # Tracks how many coordinates have been sent
 
-            schedule_checker(schedule_hours)
-            interpolate_path(theta, rho, speed)
+        while sent_index < len(coordinates):
+            # Check buffer
+            buffer_status = serial_manager.check_buffer()
+            if buffer_status:
+                buffer_left = buffer_status["planner_buffer"]
+            else:
+                buffer_left = 0  # Assume empty buffer if no response
+
+            # Calculate how many new coordinates to send
+            available_slots = BATCH_SIZE - buffer_left
+            if available_slots > 0:
+                num_to_send = min(available_slots, len(coordinates) - sent_index)
+                batch = coordinates[sent_index:sent_index + num_to_send]
+
+                for theta, rho in batch:
+                    if stop_requested:
+                        logger.debug("Execution stopped by user.")
+                        break
+
+                    with pause_condition:
+                        while pause_requested:
+                            logger.debug("Execution paused...")
+                            pause_condition.wait()
+
+                    schedule_checker(schedule_hours)
+                    interpolate_path(theta, rho, speed)
+
+                sent_index += num_to_send  # Update sent index
+
+            # Wait before checking buffer again
+            time.sleep(0.1)  # Check buffer every second
 
         serial_manager.check_idle()
 

+ 52 - 16
dune_weaver_flask/modules/serial/serial_manager.py

@@ -25,6 +25,14 @@ def list_serial_ports():
     logger.debug(f"Available serial ports: {available_ports}")
     return available_ports
 
+def startup_gcodes():
+    ser.write(f"Report/Status=2".encode())
+    ser.flush()
+    while True:
+        if ser.in_waiting > 0:
+            response = ser.readline().decode().strip()
+            logger.debug(f"Response: {response}")
+
 def connect_to_serial(port=None, baudrate=115200):
     """Automatically connect to the first available serial port or a specified port."""
     global ser, ser_port, arduino_table_name, arduino_driver_type, firmware_version
@@ -41,6 +49,7 @@ def connect_to_serial(port=None, baudrate=115200):
                 ser.close()
             ser = serial.Serial(port, baudrate, timeout=2)
             ser_port = port
+        # startup_gcodes()
         home()
         logger.info(f"Connected to serial port: {port}")
         time.sleep(2)  # Allow time for the connection to establish
@@ -93,32 +102,32 @@ def get_port():
     return ser_port
 
 
-def send_grbl_coordinates(x, y, speed=600, max_retries=20, retry_interval=0.5):
-    """Send G-code command to FluidNC and retry every 0.5s if no 'ok' is received."""
-    attempt = 0  # Retry counter
+def send_grbl_coordinates(x, y, speed=600, timeout=2, retry_interval=1):
+    """
+    Send a G-code command to FluidNC and wait up to 2s for an 'ok' response.
+    If no 'ok' is received, retry every 1 second until successful.
+    """
+    logger.debug(f"Sending G-code: X{x}, Y{y} at F{speed}")
 
-    while attempt < max_retries:
+    while True:  # Keep retrying indefinitely until 'ok' is received
         with serial_lock:
             gcode = f"$J=G91 G21 X{x} Y{y} F{speed}"
             ser.write(f"{gcode}\n".encode())
             ser.flush()
-            logger.debug(f"Sent command (Attempt {attempt+1}/{max_retries}): {gcode}")
+            logger.debug(f"Sent command: {gcode}")
 
-            # Wait for response
-            while True:
+            start_time = time.time()
+            while time.time() - start_time < timeout:
                 if ser.in_waiting > 0:
                     response = ser.readline().decode().strip()
                     logger.debug(f"Response: {response}")
                     if response.lower() == "ok":
-                        logger.debug("Command execution completed")
-                        return  # Exit function if 'ok' is received
-
-        # Wait before retrying
-        attempt += 1
-        logger.warning(f"Attempt {attempt}: No 'ok' received, retrying in {retry_interval}s...")
-        time.sleep(retry_interval)
+                        logger.debug("Command execution confirmed.")
+                        return  # Exit function when 'ok' is received
 
-    logger.error(f"Failed to receive 'ok' after {max_retries} attempts. Giving up.")
+            logger.warning(f"No 'ok' received for X{x}, Y{y}. Retrying in {retry_interval}s...")
+        
+        time.sleep(retry_interval)  # Wait before retrying
 
 def home():
     logger.info("Homing")
@@ -140,4 +149,31 @@ def check_idle():
                     logger.info("Tabble is idle")
                     return True  # Exit function once 'Idle' is received
 
-        time.sleep(1)  # Wait before retrying
+        time.sleep(1)  # Wait before retrying
+        
+def check_buffer():
+    """Check the available planner and serial buffer in FluidNC."""
+    logger.debug("Checking buffer availability")
+
+    with serial_lock:
+        ser.write('?'.encode())  # Send status query
+        ser.flush()  # Ensure it's sent immediately
+
+        if ser.in_waiting > 0:
+            response = ser.readline().decode().strip()
+            logger.debug(f"Response: {response}")
+
+            # Extract buffer values from the response (Format: <Idle|MPos:...|Bf:xx,yy|FS:...>)
+            buffer_info = None
+            if "|Bf:" in response:
+                try:
+                    buffer_section = response.split("|Bf:")[1].split("|")[0]
+                    planner_buffer, serial_buffer = map(int, buffer_section.split(","))
+                    buffer_info = {"planner_buffer": planner_buffer, "serial_buffer": serial_buffer}
+                except ValueError:
+                    logger.warning("Failed to parse buffer info from response")
+
+            logger.debug(f"Buffer Left: {buffer_info}")
+            return buffer_info
+
+    return None  # Return None if no buffer data is available