Browse Source

Release excess pressure within cruising blocks

LA assumes all the nozzle pressure is released at the end of each
extrusion, which makes calculating the required pressure advance during
travels and retracts not normally necessary.

This is not always true in our planner, since the E axis is explicitly
ignored when not in use, but also due to E-jerk allowing a non-linear
jump in speed. And since the compression factor is currently tied by XYZ
axes and not independently calculated, this can result in a wrong
estimation of final pressure in several conditions.

To avoid overburdening the planner, change the underlying assumptions
about backpressure:

1) Pressure is no longer lost when LA is disabled: if a retract is
followed by an unretract of the same length, the pressure will be likely
maintained entirely. This also holds true during travels, as long as the
retract length can overcome all the backpressure (which is the case in
all but the most noodly materials)

2) Pressure is released as soon as possible during travels: we now
enable LA also during travels, but under the sole condition of undoing
excess pressure.

We do that by checking for backpressure at the start of any segment
without an acceleration phase that doesn't have any E-steps (a result
which can happen due to the above). If pressure is not nominal, we run
the extruder in reverse at maximum jerk as long as the segment allows
us, since proper acceleration would be prohibitive at this stage. As the
pressure difference resulting by the above is still _very_ low, any wipe
or short travel will be able to equalize the nozzle pressure *before*
extrusion is resumed, avoiding ooze.
Yuri D'Elia 4 years ago
parent
commit
02a36c498c
2 changed files with 28 additions and 8 deletions
  1. 10 7
      Firmware/planner.cpp
  2. 18 1
      Firmware/stepper.cpp

+ 10 - 7
Firmware/planner.cpp

@@ -1061,14 +1061,12 @@ Having the real displacement of the head, we can calculate the total movement le
     /**
      * Use LIN_ADVANCE within this block 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)
+     * delta_mm[E_AXIS] >= 0    : Extruding or traveling, but _not_ retracting.
      * |delta_mm[Z_AXIS]| < 0.5 : Z is only moved for leveling (_not_ for priming)
      */
-    block->use_advance_lead = block->steps_e.wide
-                              && extruder_advance_K
-                              && delta_mm[E_AXIS] > 0
+    block->use_advance_lead = extruder_advance_K
+                              && delta_mm[E_AXIS] >= 0
                               && abs(delta_mm[Z_AXIS]) < 0.5;
     if (block->use_advance_lead) {
         e_D_ratio = (e - position_float[E_AXIS]) /
@@ -1082,7 +1080,7 @@ Having the real displacement of the head, we can calculate the total movement le
         // 100mm wide lines using 3mm filament or 35mm wide lines using 1.75mm filament.
         if (e_D_ratio > 3.0)
             block->use_advance_lead = false;
-        else {
+        else if (e_D_ratio > 0) {
             const uint32_t max_accel_steps_per_s2 = cs.max_jerk[E_AXIS] / (extruder_advance_K * e_D_ratio) * steps_per_mm;
             if (block->acceleration_st > max_accel_steps_per_s2) {
                 block->acceleration_st = max_accel_steps_per_s2;
@@ -1133,9 +1131,14 @@ Having the real displacement of the head, we can calculate the total movement le
       block->adv_comp = extruder_advance_K * e_D_ratio * cs.axis_steps_per_unit[E_AXIS];
       block->max_adv_steps = block->nominal_speed * block->adv_comp;
 
+      float advance_speed;
+      if (e_D_ratio > 0)
+          advance_speed = (extruder_advance_K * e_D_ratio * block->acceleration * cs.axis_steps_per_unit[E_AXIS]);
+      else
+          advance_speed = cs.max_jerk[E_AXIS] * cs.axis_steps_per_unit[E_AXIS];
+
       // to save more space we avoid another copy of calc_timer and go through slow division, but we
       // still need to replicate the *exact* same step grouping policy (see below)
-      float advance_speed = (extruder_advance_K * e_D_ratio * block->acceleration * cs.axis_steps_per_unit[E_AXIS]);
       if (advance_speed > MAX_STEP_FREQUENCY) advance_speed = MAX_STEP_FREQUENCY;
       float advance_rate = (F_CPU / 8.0) / advance_speed;
       if (advance_speed > 20000) {

+ 18 - 1
Firmware/stepper.cpp

@@ -351,7 +351,6 @@ FORCE_INLINE void stepper_next_block()
         target_adv_steps = current_block->max_adv_steps;
     } else {
         e_step_loops = 1;
-        current_adv_steps = 0;
     }
     e_steps = 0;
     nextAdvanceISR = ADV_NEVER;
@@ -840,6 +839,24 @@ FORCE_INLINE void isr() {
           // the initial interrupt blocking.
           OCR1A_nominal = calc_timer(uint16_t(current_block->nominal_rate), step_loops);
           step_loops_nominal = step_loops;
+
+#ifdef LIN_ADVANCE
+          if(current_block->use_advance_lead) {
+              if(current_adv_steps < target_adv_steps) {
+                  // after reaching cruising speed, halt compression. if we couldn't accumulate the
+                  // required pressure in the acceleration phase due to lost ticks it's unlikely we
+                  // could undo all of it during deceleration either
+                  target_adv_steps = current_adv_steps;
+              }
+              else if (!nextAdvanceISR && current_adv_steps > target_adv_steps) {
+                  // we're cruising in a block with excess backpressure and without a previous
+                  // acceleration phase - this *cannot* happen during a regular block, but it's
+                  // likely in result of chained a wipe move. release the pressure earlier by
+                  // forcedly enabling LA while cruising!
+                  la_state = ADV_INIT;
+              }
+          }
+#endif
         }
         _NEXT_ISR(OCR1A_nominal);
       }