From 5107b59c8755c258ddb24daec0faeb0ca0ee273a Mon Sep 17 00:00:00 2001 From: Ted Hess Date: Fri, 17 Nov 2017 17:06:41 -0500 Subject: [PATCH 1/2] Make M110 command compatible with Marlin, etc. --- Firmware/Marlin_main.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 208ac7254..32e1d34e1 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -4633,8 +4633,6 @@ Sigma_Exit: case 110: // M110 - reset line pos if (code_seen('N')) gcode_LastN = code_value_long(); - else - gcode_LastN = 0; break; #ifdef HOST_KEEPALIVE_FEATURE case 113: // M113 - Get or set Host Keepalive interval From 3ec9d9dcd09dce3262323e941767c5559ab6c741 Mon Sep 17 00:00:00 2001 From: Sebastianv650 Date: Sun, 25 Feb 2018 12:46:22 +0100 Subject: [PATCH 2/2] Linear Advance v1.5 implementation Ported from Marlin, only usable for non-kinematic XYZ printers! --- Firmware/Configuration_adv.h | 48 +++++---------- Firmware/Marlin_main.cpp | 21 +------ Firmware/planner.cpp | 111 ++++++++++++++++++++++------------- Firmware/planner.h | 7 ++- Firmware/stepper.cpp | 87 +++++++++++++++++---------- 5 files changed, 147 insertions(+), 127 deletions(-) diff --git a/Firmware/Configuration_adv.h b/Firmware/Configuration_adv.h index b25de5ffd..68b3649dd 100644 --- a/Firmware/Configuration_adv.h +++ b/Firmware/Configuration_adv.h @@ -319,43 +319,25 @@ #endif /** - * Implementation of linear pressure control + * Linear Pressure Control v1.5 * - * Assumption: advance = k * (delta velocity) + * Assumption: advance [steps] = k * (delta velocity [steps/s]) * K=0 means advance disabled. - * See Marlin documentation for calibration instructions. + * + * 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 - +//#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: diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 32e1d34e1..8f52b2051 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -1918,34 +1918,19 @@ 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 Set advance K factor - * R Set ratio directly (overrides WH/D) - * W H D 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) extruder_advance_K = newK; 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 diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index 7dd79903a..0e0a22712 100644 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -127,8 +127,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 @@ -395,6 +394,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; } @@ -408,6 +414,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"); @@ -714,11 +727,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*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]) { @@ -727,7 +735,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(MSG_ERR_COLD_EXTRUDE_STOP); @@ -739,7 +746,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(MSG_ERR_LONG_EXTRUDE_STOP); @@ -1011,10 +1017,50 @@ Having the real displacement of the head, we can calculate the total movement le if(block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0) { block->acceleration_st = ceil(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(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 / (float)block->step_event_count) > axis_steps_per_sqr_second[X_AXIS]) @@ -1051,6 +1097,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; @@ -1167,37 +1225,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 - && (block->steps_x || block->steps_y) - && extruder_advance_k - && (uint32_t)block->steps_e != block->step_event_count - && 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) - * 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); @@ -1289,7 +1316,7 @@ void plan_set_position(float x, float y, float z, const float &e) void plan_set_z_position(const float &z) { #ifdef LIN_ADVANCE - position_float[Z_AXIS] = z; + position_float[Z_AXIS] = z; #endif position[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]); st_set_position(position[X_AXIS], position[Y_AXIS], position[Z_AXIS], position[E_AXIS]); @@ -1298,7 +1325,7 @@ void plan_set_z_position(const float &z) void plan_set_e_position(const float &e) { #ifdef LIN_ADVANCE - position_float[E_AXIS] = e; + position_float[E_AXIS] = e; #endif position[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]); st_set_e_position(position[E_AXIS]); diff --git a/Firmware/planner.h b/Firmware/planner.h index 0858bda30..66b75bfd7 100644 --- a/Firmware/planner.h +++ b/Firmware/planner.h @@ -91,12 +91,15 @@ 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 } block_t; #ifdef LIN_ADVANCE - extern float extruder_advance_k, advance_ed_ratio; + extern float extruder_advance_K; #endif #ifdef ENABLE_AUTO_BED_LEVELING diff --git a/Firmware/stepper.cpp b/Firmware/stepper.cpp index 0605e3abb..ced6ee9ab 100644 --- a/Firmware/stepper.cpp +++ b/Firmware/stepper.cpp @@ -97,18 +97,21 @@ volatile signed char count_direction[NUM_AXIS] = { 1, 1, 1, 1}; #ifdef LIN_ADVANCE - uint16_t ADV_NEVER = 65535; + static uint32_t LA_decelerate_after; + + static const uint16_t ADV_NEVER = 65535; static uint16_t nextMainISR = 0; static uint16_t nextAdvanceISR = ADV_NEVER; static uint16_t eISR_Rate = ADV_NEVER; + static uint16_t current_adv_steps = 0; + static uint16_t final_adv_steps; + static uint16_t max_adv_steps; - static volatile int e_steps; //Extrusion steps to be executed by the stepper - static int final_estep_rate; //Speed of extruder at cruising speed - static int current_estep_rate; //The current speed of the extruder - static int current_adv_steps; //The current pretension of filament expressed in steps + static volatile int8_t e_steps = 0; + + static bool use_advance_lead; - #define ADV_RATE(T, L) (e_steps ? (T) * (L) / abs(e_steps) : ADV_NEVER) #define _NEXT_ISR(T) nextMainISR = T #else @@ -339,9 +342,13 @@ FORCE_INLINE void trapezoid_generator_reset() { #ifdef LIN_ADVANCE if (current_block->use_advance_lead) { - current_estep_rate = ((unsigned long)acc_step_rate * current_block->abs_adv_steps_multiplier8) >> 17; - final_estep_rate = (current_block->nominal_rate * current_block->abs_adv_steps_multiplier8) >> 17; + LA_decelerate_after = current_block->decelerate_after; + final_adv_steps = current_block->final_adv_steps; + max_adv_steps = current_block->max_adv_steps; + use_advance_lead = true; } + else + use_advance_lead = false; #endif } @@ -647,16 +654,6 @@ void isr() { step_events_completed += 1; if(step_events_completed >= current_block->step_event_count) break; } - - #ifdef LIN_ADVANCE - if (current_block->use_advance_lead) { - const int delta_adv_steps = current_estep_rate - current_adv_steps; - current_adv_steps += delta_adv_steps; - e_steps += delta_adv_steps; - } - // If we have esteps to execute, fire the next advance_isr "now" - if (e_steps) nextAdvanceISR = 0; - #endif // Calculare new timer value unsigned short timer; @@ -677,9 +674,15 @@ void isr() { #ifdef LIN_ADVANCE if (current_block->use_advance_lead) { - current_estep_rate = ((uint32_t)acc_step_rate * current_block->abs_adv_steps_multiplier8) >> 17; + if (step_events_completed == step_loops || (e_steps && eISR_Rate != current_block->advance_speed)) { + nextAdvanceISR = 0; // Wake up eISR on first acceleration loop and fire ISR if final adv_rate is reached + eISR_Rate = current_block->advance_speed; + } + } + else { + eISR_Rate = ADV_NEVER; + if (e_steps) nextAdvanceISR = 0; } - eISR_Rate = ADV_RATE(timer, step_loops); #endif } else if (step_events_completed > (unsigned long int)current_block->decelerate_after) { @@ -703,17 +706,21 @@ void isr() { #ifdef LIN_ADVANCE if (current_block->use_advance_lead) { - current_estep_rate = ((uint32_t)step_rate * current_block->abs_adv_steps_multiplier8) >> 17; + if (step_events_completed <= (uint32_t)current_block->decelerate_after + step_loops || (e_steps && eISR_Rate != current_block->advance_speed)) { + nextAdvanceISR = 0; // Wake up eISR on first deceleration loop + eISR_Rate = current_block->advance_speed; + } + } + else { + eISR_Rate = ADV_NEVER; + if (e_steps) nextAdvanceISR = 0; } - eISR_Rate = ADV_RATE(timer, step_loops); #endif } else { #ifdef LIN_ADVANCE - if (current_block->use_advance_lead) - current_estep_rate = final_estep_rate; - - eISR_Rate = ADV_RATE(OCR1A_nominal, step_loops_nominal); + // If we have esteps to execute, fire the next advance_isr "now" + if (e_steps && eISR_Rate != current_block->advance_speed) nextAdvanceISR = 0; #endif _NEXT_ISR(OCR1A_nominal); @@ -735,6 +742,26 @@ void isr() { void advance_isr() { + if (current_block->use_advance_lead) { + if (step_events_completed > LA_decelerate_after && current_adv_steps > final_adv_steps) { + e_steps--; + current_adv_steps--; + nextAdvanceISR = eISR_Rate; + } + else if (step_events_completed < LA_decelerate_after && current_adv_steps < max_adv_steps) { + //step_events_completed <= (uint32_t)current_block->accelerate_until) { + e_steps++; + current_adv_steps++; + nextAdvanceISR = eISR_Rate; + } + else { + nextAdvanceISR = ADV_NEVER; + eISR_Rate = ADV_NEVER; + } + } + else + nextAdvanceISR = ADV_NEVER; + if (e_steps) { bool dir = #ifdef SNMM @@ -745,16 +772,12 @@ void isr() { ? INVERT_E0_DIR : !INVERT_E0_DIR; //If we have SNMM, reverse every second extruder. WRITE(E0_DIR_PIN, dir); - for (uint8_t i = step_loops; e_steps && i--;) { + while (e_steps) { WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN); e_steps < 0 ? ++e_steps : --e_steps; WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); } - } - else{ - eISR_Rate = ADV_NEVER; - } - nextAdvanceISR = eISR_Rate; + } } void advance_isr_scheduler() {