From 02a36c498cfb087fc4d1e470a7490d08a10484a5 Mon Sep 17 00:00:00 2001 From: Yuri D'Elia Date: Wed, 8 Apr 2020 22:49:48 +0200 Subject: [PATCH] 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. --- Firmware/planner.cpp | 17 ++++++++++------- Firmware/stepper.cpp | 19 ++++++++++++++++++- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index 57d7b89b..35031ab2 100644 --- a/Firmware/planner.cpp +++ b/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) { diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index bc860b14..de068166 100644 --- a/Firmware/stepper.cpp +++ b/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); }