Browse Source

Partial LA15 support

Yuri D'Elia 5 years ago
parent
commit
eeea2725cb
5 changed files with 99 additions and 98 deletions
  1. 2 2
      Firmware/ConfigurationStore.cpp
  2. 17 34
      Firmware/Configuration_adv.h
  3. 8 20
      Firmware/Marlin_main.cpp
  4. 67 40
      Firmware/planner.cpp
  5. 5 2
      Firmware/planner.h

+ 2 - 2
Firmware/ConfigurationStore.cpp

@@ -165,8 +165,8 @@ void Config_PrintSettings(uint8_t level)
 #endif
 	if (level >= 10) {
 #ifdef LIN_ADVANCE
-		printf_P(PSTR("%SLinear advance settings:\n   M900 K%.2f   E/D = %.2f\n"),
-			echomagic, extruder_advance_k, advance_ed_ratio);
+		printf_P(PSTR("%SLinear advance settings:\n   M900 K%.2f\n"),
+			echomagic, extruder_advance_K);
 #endif //LIN_ADVANCE
 	}
 }

+ 17 - 34
Firmware/Configuration_adv.h

@@ -276,43 +276,26 @@
 #endif
 
 /**
-    * Implementation of linear pressure control
-    *
-    * Assumption: advance = k * (delta velocity)
-    * K=0 means advance disabled.
-    * See Marlin documentation for calibration instructions.
-    */
+ * Linear Pressure Control v1.5
+ *
+ * Assumption: advance [steps] = k * (delta velocity [steps/s])
+ * K=0 means advance disabled.
+ *
+ * NOTE: K values for LIN_ADVANCE 1.5 differ from earlier versions!
+ *
+ * Set K around 0.22 for 3mm PLA Direct Drive with ~6.5cm between the drive gear and heatbreak.
+ * Larger K values will be needed for flexible filament and greater distances.
+ * If this algorithm produces a higher speed offset than the extruder can handle (compared to E jerk)
+ * print acceleration will be reduced during the affected moves to keep within the limit.
+ *
+ * See http://marlinfw.org/docs/features/lin_advance.html for full instructions.
+ * Mention @Sebastianv650 on GitHub to alert the author of any issues.
+ */
 #define LIN_ADVANCE
 
 #ifdef LIN_ADVANCE
-  #define LIN_ADVANCE_K 0 //Try around 45 for PLA, around 25 for ABS.
-
- /**
-        * Some Slicers produce Gcode with randomly jumping extrusion widths occasionally.
-        * For example within a 0.4mm perimeter it may produce a single segment of 0.05mm width.
-        * While this is harmless for normal printing (the fluid nature of the filament will
-        * close this very, very tiny gap), it throws off the LIN_ADVANCE pressure adaption.
-        *
-        * For this case LIN_ADVANCE_E_D_RATIO can be used to set the extrusion:distance ratio
-        * to a fixed value. Note that using a fixed ratio will lead to wrong nozzle pressures
-        * if the slicer is using variable widths or layer heights within one print!
-        *
-        * This option sets the default E:D ratio at startup. Use `M900` to override this value.
-        *
-        * Example: `M900 W0.4 H0.2 D1.75`, where:
-        *   - W is the extrusion width in mm
-        *   - H is the layer height in mm
-        *   - D is the filament diameter in mm
-        *
-        * Example: `M900 R0.0458` to set the ratio directly.
-        *
-        * Set to 0 to auto-detect the ratio based on given Gcode G1 print moves.
-        *
-        * Slic3r (including Prusa Slic3r) produces Gcode compatible with the automatic mode.
-        * Cura (as of this writing) may produce Gcode incompatible with the automatic mode.
-        */
-#define LIN_ADVANCE_E_D_RATIO 0 // The calculated ratio (or 0) according to the formula W * H / ((D / 2) ^ 2 * PI)
-                                // Example: 0.4 * 0.2 / ((1.75 / 2) ^ 2 * PI) = 0.033260135
+  #define LIN_ADVANCE_K 0 // Unit: mm compression per 1mm/s extruder speed
+  //#define LA_DEBUG      // If enabled, this will generate debug information output over USB.
 #endif
 
 // Arc interpretation settings:

+ 8 - 20
Firmware/Marlin_main.cpp

@@ -2073,35 +2073,23 @@ static float probe_pt(float x, float y, float z_before) {
 
 #ifdef LIN_ADVANCE
    /**
-    * M900: Set and/or Get advance K factor and WH/D ratio
+    * M900: Set and/or Get advance K factor
     *
     *  K<factor>                  Set advance K factor
-    *  R<ratio>                   Set ratio directly (overrides WH/D)
-    *  W<width> H<height> D<diam> Set ratio from WH/D
     */
 inline void gcode_M900() {
     st_synchronize();
     
     const float newK = code_seen('K') ? code_value_float() : -1;
-    if (newK >= 0) extruder_advance_k = newK;
-    
-    float newR = code_seen('R') ? code_value_float() : -1;
-    if (newR < 0) {
-        const float newD = code_seen('D') ? code_value_float() : -1,
-        newW = code_seen('W') ? code_value_float() : -1,
-        newH = code_seen('H') ? code_value_float() : -1;
-        if (newD >= 0 && newW >= 0 && newH >= 0)
-            newR = newD ? (newW * newH) / (sq(newD * 0.5) * M_PI) : 0;
-    }
-    if (newR >= 0) advance_ed_ratio = newR;
-    
+    if (newK >= 0 && newK < 10)
+      extruder_advance_K = newK;
+    else
+      SERIAL_ECHOLNPGM("K out of allowed range!");
+
     SERIAL_ECHO_START;
     SERIAL_ECHOPGM("Advance K=");
-    SERIAL_ECHOLN(extruder_advance_k);
-    SERIAL_ECHOPGM(" E/D=");
-    const float ratio = advance_ed_ratio;
-    if (ratio) SERIAL_ECHOLN(ratio); else SERIAL_ECHOLNPGM("Auto");
-    }
+    SERIAL_ECHOLN(extruder_advance_K);
+}
 #endif // LIN_ADVANCE
 
 bool check_commands() {

+ 67 - 40
Firmware/planner.cpp

@@ -126,8 +126,7 @@ float extrude_min_temp=EXTRUDE_MINTEMP;
 #endif
 
 #ifdef LIN_ADVANCE
-    float extruder_advance_k = LIN_ADVANCE_K,
-    advance_ed_ratio = LIN_ADVANCE_E_D_RATIO,
+    float extruder_advance_K = LIN_ADVANCE_K,
     position_float[NUM_AXIS] = { 0 };
 #endif
 
@@ -402,6 +401,13 @@ void planner_recalculate(const float &safe_final_speed)
             if ((prev->flag | current->flag) & BLOCK_FLAG_RECALCULATE) {
                 // NOTE: Entry and exit factors always > 0 by all previous logic operations.
                 calculate_trapezoid_for_block(prev, prev->entry_speed, current->entry_speed);
+                #ifdef LIN_ADVANCE
+                  if (current->use_advance_lead) {
+                    const float comp = current->e_D_ratio * extruder_advance_K * axis_steps_per_unit[E_AXIS];
+                    current->max_adv_steps = current->nominal_speed * comp;
+                    current->final_adv_steps = next->entry_speed * comp;
+                  }
+                #endif
                 // Reset current only to ensure next trapezoid is computed.
                 prev->flag &= ~BLOCK_FLAG_RECALCULATE;
             }
@@ -415,6 +421,13 @@ void planner_recalculate(const float &safe_final_speed)
     // Last/newest block in buffer. Exit speed is set with safe_final_speed. Always recalculated.
     current = block_buffer + prev_block_index(block_buffer_head);
     calculate_trapezoid_for_block(current, current->entry_speed, safe_final_speed);
+    #ifdef LIN_ADVANCE
+      if (current->use_advance_lead) {
+        const float comp = current->e_D_ratio * extruder_advance_K * axis_steps_per_unit[E_AXIS];
+        current->max_adv_steps = current->nominal_speed * comp;
+        current->final_adv_steps = safe_final_speed * comp;
+      }
+    #endif
     current->flag &= ~BLOCK_FLAG_RECALCULATE;
 
 //    SERIAL_ECHOLNPGM("planner_recalculate - 4");
@@ -748,11 +761,6 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate
 #endif // ENABLE_MESH_BED_LEVELING
   target[E_AXIS] = lround(e*cs.axis_steps_per_unit[E_AXIS]);
   
-#ifdef LIN_ADVANCE
-    const float mm_D_float = sqrt(sq(x - position_float[X_AXIS]) + sq(y - position_float[Y_AXIS]));
-    float de_float = e - position_float[E_AXIS];
-#endif
-    
   #ifdef PREVENT_DANGEROUS_EXTRUDE
   if(target[E_AXIS]!=position[E_AXIS])
   {
@@ -761,7 +769,6 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate
       position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part
 #ifdef LIN_ADVANCE
       position_float[E_AXIS] = e;
-      de_float = 0;
 #endif
       SERIAL_ECHO_START;
       SERIAL_ECHOLNRPGM(_n(" cold extrusion prevented"));////MSG_ERR_COLD_EXTRUDE_STOP
@@ -773,7 +780,6 @@ void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate
       position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part
 #ifdef LIN_ADVANCE
         position_float[E_AXIS] = e;
-        de_float = 0;
 #endif
       SERIAL_ECHO_START;
       SERIAL_ECHOLNRPGM(_n(" too long extrusion prevented"));////MSG_ERR_LONG_EXTRUDE_STOP
@@ -1001,10 +1007,50 @@ Having the real displacement of the head, we can calculate the total movement le
   if(block->steps_x.wide == 0 && block->steps_y.wide == 0 && block->steps_z.wide == 0)
   {
     block->acceleration_st = ceil(cs.retract_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
+    #ifdef LIN_ADVANCE
+      block->use_advance_lead = false;
+    #endif
   }
   else
   {
     block->acceleration_st = ceil(cs.acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
+
+    #ifdef LIN_ADVANCE
+      /**
+       *
+       * Use LIN_ADVANCE for blocks if all these are true:
+       *
+       * block->steps_e             : This is a print move, because we checked for X, Y, Z steps before.
+       *
+       * extruder_advance_K : There is an advance factor set.
+       *
+       * delta_mm[E_AXIS] > 0             : Extruder is running forward (e.g., for "Wipe while retracting" (Slic3r) or "Combing" (Cura) moves)
+       */
+      block->use_advance_lead =  block->steps_e
+                              && extruder_advance_K
+                              && delta_mm[E_AXIS] > 0;
+
+      if (block->use_advance_lead) {
+        block->e_D_ratio = (e - position_float[E_AXIS]) /
+            sqrt(sq(x - position_float[X_AXIS])
+               + sq(y - position_float[Y_AXIS])
+               + sq(z - position_float[Z_AXIS]));
+
+        // Check for unusual high e_D ratio to detect if a retract move was combined with the last print move due to min. steps per segment. Never execute this with advance!
+        // This assumes no one will use a retract length of 0mm < retr_length < ~0.2mm and no one will print 100mm wide lines using 3mm filament or 35mm wide lines using 1.75mm filament.
+        if (block->e_D_ratio > 3.0)
+          block->use_advance_lead = false;
+        else {
+          const uint32_t max_accel_steps_per_s2 = max_jerk[E_AXIS] / (extruder_advance_K * block->e_D_ratio) * steps_per_mm;
+          #ifdef LA_DEBUG
+            if (block->acceleration_st > max_accel_steps_per_s2)
+              SERIAL_ECHOLNPGM("Acceleration limited.");
+          #endif
+          NOMORE(block->acceleration_st, max_accel_steps_per_s2);
+        }
+      }
+    #endif
+
     // Limit acceleration per axis
     //FIXME Vojtech: One shall rather limit a projection of the acceleration vector instead of using the limit.
     if(((float)block->acceleration_st * (float)block->steps_x.wide / (float)block->step_event_count.wide) > axis_steps_per_sqr_second[X_AXIS])
@@ -1037,6 +1083,18 @@ Having the real displacement of the head, we can calculate the total movement le
 
   block->acceleration_rate = (long)((float)block->acceleration_st * (16777216.0 / (F_CPU / 8.0)));
 
+  #ifdef LIN_ADVANCE
+    if (block->use_advance_lead) {
+      block->advance_speed = ((F_CPU) * 0.125) / (extruder_advance_K * block->e_D_ratio * block->acceleration * axis_steps_per_unit[E_AXIS]);
+      #ifdef LA_DEBUG
+        if (extruder_advance_K * block->e_D_ratio * block->acceleration * 2 < block->nominal_speed * block->e_D_ratio)
+          SERIAL_ECHOLNPGM("More than 2 steps per eISR loop executed.");
+        if (block->advance_speed < 200)
+          SERIAL_ECHOLNPGM("eISR running at > 10kHz.");
+      #endif
+    }
+  #endif
+
   // Start with a safe speed.
   // Safe speed is the speed, from which the machine may halt to stop immediately.
   float safe_speed = block->nominal_speed;
@@ -1153,37 +1211,6 @@ Having the real displacement of the head, we can calculate the total movement le
   previous_nominal_speed = block->nominal_speed;
   previous_safe_speed = safe_speed;
 
-#ifdef LIN_ADVANCE
-
-    //
-    // Use LIN_ADVANCE for blocks if all these are true:
-    //
-    // esteps                                          : We have E steps todo (a printing move)
-    //
-    // block->steps[X_AXIS] || block->steps[Y_AXIS]    : We have a movement in XY direction (i.e., not retract / prime).
-    //
-    // extruder_advance_k                              : There is an advance factor set.
-    //
-    // block->steps[E_AXIS] != block->step_event_count : A problem occurs if the move before a retract is too small.
-    //                                                   In that case, the retract and move will be executed together.
-    //                                                   This leads to too many advance steps due to a huge e_acceleration.
-    //                                                   The math is good, but we must avoid retract moves with advance!
-    // de_float > 0.0                                  : Extruder is running forward (e.g., for "Wipe while retracting" (Slic3r) or "Combing" (Cura) moves)
-    //
-    block->use_advance_lead =  block->steps_e.wide
-                           && (block->steps_x.wide || block->steps_y.wide)
-                           && extruder_advance_k
-                           && (uint32_t)block->steps_e.wide != block->step_event_count.wide
-                           && de_float > 0.0;
-    if (block->use_advance_lead)
-        block->abs_adv_steps_multiplier8 = lround(
-                          extruder_advance_k
-                          * ((advance_ed_ratio < 0.000001) ? de_float / mm_D_float : advance_ed_ratio) // Use the fixed ratio, if set
-                          * (block->nominal_speed / (float)block->nominal_rate)
-                          * cs.axis_steps_per_unit[E_AXIS] * 256.0
-                          );
-#endif
-    
   // Precalculate the division, so when all the trapezoids in the planner queue get recalculated, the division is not repeated.
   block->speed_factor = block->nominal_rate / block->nominal_speed;
   calculate_trapezoid_for_block(block, block->entry_speed, safe_speed);

+ 5 - 2
Firmware/planner.h

@@ -113,14 +113,17 @@ typedef struct {
     
 #ifdef LIN_ADVANCE
   bool use_advance_lead;
-  unsigned long abs_adv_steps_multiplier8; // Factorised by 2^8 to avoid float
+  uint16_t advance_speed,                 // Timer value for extruder speed offset
+           max_adv_steps,                 // max. advance steps to get cruising speed pressure (not always nominal_speed!)
+           final_adv_steps;               // advance steps due to exit speed
+  float e_D_ratio;
 #endif
 
   uint16_t sdlen;
 } block_t;
 
 #ifdef LIN_ADVANCE
-  extern float extruder_advance_k, advance_ed_ratio;
+  extern float extruder_advance_K;
 #endif
 
 #ifdef ENABLE_AUTO_BED_LEVELING