diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index cc28c050a6..75c86931c7 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1847,19 +1847,55 @@ */ #if EXTRUDERS > 1 // Z raise distance for tool-change, as needed for some extruders - #define TOOLCHANGE_ZRAISE 2 // (mm) - //#define TOOLCHANGE_NO_RETURN // Never return to the previous position on tool-change + #define TOOLCHANGE_ZRAISE 2 // (mm) + //#define TOOLCHANGE_ZRAISE_BEFORE_RETRACT // Apply raise before swap retraction (if enabled) + //#define TOOLCHANGE_NO_RETURN // Never return to previous position on tool-change #if ENABLED(TOOLCHANGE_NO_RETURN) - //#define EVENT_GCODE_AFTER_TOOLCHANGE "G12X" // G-code to run after tool-change is complete + //#define EVENT_GCODE_AFTER_TOOLCHANGE "G12X" // Extra G-code to run after tool-change #endif - // Retract and prime filament on tool-change + /** + * Retract and prime filament on tool-change to reduce + * ooze and stringing and to get cleaner transitions. + */ //#define TOOLCHANGE_FILAMENT_SWAP #if ENABLED(TOOLCHANGE_FILAMENT_SWAP) - #define TOOLCHANGE_FIL_SWAP_LENGTH 12 // (mm) - #define TOOLCHANGE_FIL_EXTRA_PRIME 2 // (mm) - #define TOOLCHANGE_FIL_SWAP_RETRACT_SPEED 3600 // (mm/m) - #define TOOLCHANGE_FIL_SWAP_PRIME_SPEED 3600 // (mm/m) + // Load / Unload + #define TOOLCHANGE_FS_LENGTH 12 // (mm) Load / Unload length + #define TOOLCHANGE_FS_EXTRA_RESUME_LENGTH 0 // (mm) Extra length for better restart, fine tune by LCD/Gcode) + #define TOOLCHANGE_FS_RETRACT_SPEED (50*60) // (mm/m) (Unloading) + #define TOOLCHANGE_FS_UNRETRACT_SPEED (25*60) // (mm/m) (On SINGLENOZZLE or Bowden loading must be slowed down) + + // Longer prime to clean out a SINGLENOZZLE + #define TOOLCHANGE_FS_EXTRA_PRIME 0 // (mm) Extra priming length + #define TOOLCHANGE_FS_PRIME_SPEED (4.6*60) // (mm/m) Extra priming feedrate + #define TOOLCHANGE_FS_WIPE_RETRACT 0 // (mm/m) Retract before cooling for less stringing, better wipe, etc. + + // Cool after prime to reduce stringing + #define TOOLCHANGE_FS_FAN -1 // Fan index or -1 to skip + #define TOOLCHANGE_FS_FAN_SPEED 255 // 0-255 + #define TOOLCHANGE_FS_FAN_TIME 10 // (seconds) + + // Swap uninitialized extruder with TOOLCHANGE_FS_PRIME_SPEED for all lengths (recover + prime) + // (May break filament if not retracted beforehand.) + //#define TOOLCHANGE_FS_INIT_BEFORE_SWAP + + // Prime on the first T command even if the same or no toolchange / swap + // Enable it (M217 V[0/1]) before printing, to avoid unwanted priming on host connect + //#define TOOLCHANGE_FS_PRIME_FIRST_USED + + /** + * Tool Change Migration + * This feature provides G-code and LCD options to switch tools mid-print. + * All applicable tool properties are migrated so the print can continue. + * Tools must be closely matching and other restrictions may apply. + * Useful to: + * - Change filament color without interruption + * - Switch spools automatically on filament runout + * - Switch to a different nozzle on an extruder jam + */ + #define TOOLCHANGE_MIGRATION_FEATURE + #endif /** @@ -1870,8 +1906,10 @@ #if ENABLED(TOOLCHANGE_PARK) #define TOOLCHANGE_PARK_XY { X_MIN_POS + 10, Y_MIN_POS + 10 } #define TOOLCHANGE_PARK_XY_FEEDRATE 6000 // (mm/m) + //#define TOOLCHANGE_PARK_X_ONLY // X axis only move + //#define TOOLCHANGE_PARK_Y_ONLY // Y axis only move #endif -#endif +#endif // EXTRUDERS > 1 /** * Advanced Pause diff --git a/Marlin/src/feature/runout.cpp b/Marlin/src/feature/runout.cpp index f74e0c741b..bba4f4b1fa 100644 --- a/Marlin/src/feature/runout.cpp +++ b/Marlin/src/feature/runout.cpp @@ -39,6 +39,10 @@ bool FilamentMonitorBase::enabled = true, bool FilamentMonitorBase::host_handling; // = false #endif +#if ENABLED(TOOLCHANGE_MIGRATION_FEATURE) + #include "../module/tool_change.h" +#endif + /** * Called by FilamentSensorSwitch::run when filament is detected. * Called by FilamentSensorEncoder::block_completed when motion is detected. @@ -76,6 +80,11 @@ void event_filament_runout() { if (TERN0(ADVANCED_PAUSE_FEATURE, did_pause_print)) return; // Action already in progress. Purge triggered repeated runout. + #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE) + if (migration.in_progress) return; // Action already in progress. Purge triggered repeated runout. + if (migration.automode) { extruder_migration(); return; } + #endif + TERN_(EXTENSIBLE_UI, ExtUI::onFilamentRunout(ExtUI::getActiveTool())); #if EITHER(HOST_PROMPT_SUPPORT, HOST_ACTION_COMMANDS) diff --git a/Marlin/src/gcode/config/M217.cpp b/Marlin/src/gcode/config/M217.cpp index 44e69c4298..6e8c899fb0 100644 --- a/Marlin/src/gcode/config/M217.cpp +++ b/Marlin/src/gcode/config/M217.cpp @@ -27,6 +27,10 @@ #include "../gcode.h" #include "../../module/tool_change.h" +#if ENABLED(TOOLCHANGE_MIGRATION_FEATURE) + #include "../../module/motion.h" +#endif + #include "../../MarlinCore.h" // for SP_X_STR, etc. extern const char SP_X_STR[], SP_Y_STR[], SP_Z_STR[]; @@ -35,16 +39,30 @@ void M217_report(const bool eeprom=false) { #if ENABLED(TOOLCHANGE_FILAMENT_SWAP) serialprintPGM(eeprom ? PSTR(" M217") : PSTR("Toolchange:")); - SERIAL_ECHOPAIR(" S", LINEAR_UNIT(toolchange_settings.swap_length)); - SERIAL_ECHOPAIR_P(SP_E_STR, LINEAR_UNIT(toolchange_settings.extra_prime)); - SERIAL_ECHOPAIR_P(SP_P_STR, LINEAR_UNIT(toolchange_settings.prime_speed)); - SERIAL_ECHOPAIR(" R", LINEAR_UNIT(toolchange_settings.retract_speed)); + SERIAL_ECHOPAIR(" S", LINEAR_UNIT(toolchange_settings.swap_length), + " B", LINEAR_UNIT(toolchange_settings.extra_resume)); + SERIAL_ECHOPAIR_P(SP_E_STR, LINEAR_UNIT(toolchange_settings.extra_prime), + SP_P_STR, LINEAR_UNIT(toolchange_settings.prime_speed)); + SERIAL_ECHOPAIR(" R", LINEAR_UNIT(toolchange_settings.retract_speed), + " U", LINEAR_UNIT(toolchange_settings.unretract_speed), + " F", toolchange_settings.fan_speed, + " G", toolchange_settings.fan_time); + + #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE) + SERIAL_ECHOPAIR(" N", int(migration.automode)); + SERIAL_ECHOPAIR(" L", LINEAR_UNIT(migration.last)); + #endif #if ENABLED(TOOLCHANGE_PARK) + SERIAL_ECHOPAIR(" W", LINEAR_UNIT(toolchange_settings.enable_park)); SERIAL_ECHOPAIR_P(SP_X_STR, LINEAR_UNIT(toolchange_settings.change_point.x)); SERIAL_ECHOPAIR_P(SP_Y_STR, LINEAR_UNIT(toolchange_settings.change_point.y)); #endif + #if ENABLED(TOOLCHANGE_FS_PRIME_FIRST_USED) + SERIAL_ECHOPAIR(" V", LINEAR_UNIT(enable_first_prime)); + #endif + #else UNUSED(eeprom); @@ -58,48 +76,98 @@ void M217_report(const bool eeprom=false) { /** * M217 - Set SINGLENOZZLE toolchange parameters * + * // Tool change command + * Q Prime active tool and exit + * + * // Tool change settings * S[linear] Swap length - * E[linear] Purge length + * B[linear] Extra Swap length + * E[linear] Prime length * P[linear/m] Prime speed * R[linear/m] Retract speed + * U[linear/m] UnRetract speed + * V[linear] 0/1 Enable auto prime first extruder used + * W[linear] 0/1 Enable park & Z Raise * X[linear] Park X (Requires TOOLCHANGE_PARK) * Y[linear] Park Y (Requires TOOLCHANGE_PARK) * Z[linear] Z Raise + * F[linear] Fan Speed 0-255 + * G[linear/s] Fan time + * + * Tool migration settings + * A[0|1] Enable auto-migration on runout + * L[index] Last extruder to use for auto-migration + * + * Tool migration command + * T[index] Migrate to next extruder or the given extruder */ void GcodeSuite::M217() { - #define SPR_PARAM - #define XY_PARAM - #if ENABLED(TOOLCHANGE_FILAMENT_SWAP) - #undef SPR_PARAM - #define SPR_PARAM "SPRE" + static constexpr float max_extrude = TERN(PREVENT_LENGTHY_EXTRUDE, EXTRUDE_MAXLENGTH, 500); - static constexpr float max_extrude = - #if ENABLED(PREVENT_LENGTHY_EXTRUDE) - EXTRUDE_MAXLENGTH - #else - 500 - #endif - ; + if (parser.seen('Q')) { tool_change_prime(); return; } if (parser.seenval('S')) { const float v = parser.value_linear_units(); toolchange_settings.swap_length = constrain(v, 0, max_extrude); } + if (parser.seenval('B')) { const float v = parser.value_linear_units(); toolchange_settings.extra_resume = constrain(v, -10, 10); } if (parser.seenval('E')) { const float v = parser.value_linear_units(); toolchange_settings.extra_prime = constrain(v, 0, max_extrude); } if (parser.seenval('P')) { const int16_t v = parser.value_linear_units(); toolchange_settings.prime_speed = constrain(v, 10, 5400); } if (parser.seenval('R')) { const int16_t v = parser.value_linear_units(); toolchange_settings.retract_speed = constrain(v, 10, 5400); } + if (parser.seenval('U')) { const int16_t v = parser.value_linear_units(); toolchange_settings.unretract_speed = constrain(v, 10, 5400); } + #if TOOLCHANGE_FS_FAN >= 0 && FAN_COUNT > 0 + if (parser.seenval('F')) { const int16_t v = parser.value_linear_units(); toolchange_settings.fan_speed = constrain(v, 0, 255); } + if (parser.seenval('G')) { const int16_t v = parser.value_linear_units(); toolchange_settings.fan_time = constrain(v, 1, 30); } + #endif + #endif + + #if ENABLED(TOOLCHANGE_FS_PRIME_FIRST_USED) + if (parser.seenval('V')) { enable_first_prime = parser.value_linear_units(); } #endif #if ENABLED(TOOLCHANGE_PARK) - #undef XY_PARAM - #define XY_PARAM "XY" - if (parser.seenval('X')) { toolchange_settings.change_point.x = parser.value_linear_units(); } - if (parser.seenval('Y')) { toolchange_settings.change_point.y = parser.value_linear_units(); } + if (parser.seenval('W')) { toolchange_settings.enable_park = parser.value_linear_units(); } + if (parser.seenval('X')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.x = constrain(v, X_MIN_POS, X_MAX_POS); } + if (parser.seenval('Y')) { const int16_t v = parser.value_linear_units(); toolchange_settings.change_point.y = constrain(v, Y_MIN_POS, Y_MAX_POS); } #endif if (parser.seenval('Z')) { toolchange_settings.z_raise = parser.value_linear_units(); } - if (!parser.seen(SPR_PARAM XY_PARAM "Z")) M217_report(); + #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE) + migration.target = 0; // 0 = disabled + + if (parser.seenval('L')) { // Last + const int16_t lval = parser.value_int(); + if (WITHIN(lval, 0, EXTRUDERS - 1)) { + migration.last = lval; + migration.automode = (active_extruder < migration.last); + } + } + + if (parser.seen('A')) // Auto on/off + migration.automode = parser.value_bool(); + + if (parser.seen('T')) { // Migrate now + if (parser.has_value()) { + const int16_t tval = parser.value_int(); + if (WITHIN(tval, 0, EXTRUDERS - 1) && tval != active_extruder) { + migration.target = tval + 1; + extruder_migration(); + migration.target = 0; // disable + return; + } + else + migration.target = 0; // disable + } + else { + extruder_migration(); + return; + } + } + + #endif + + M217_report(); } #endif // EXTRUDERS > 1 diff --git a/Marlin/src/gcode/config/M221.cpp b/Marlin/src/gcode/config/M221.cpp index 8522b544fc..7f170e012b 100644 --- a/Marlin/src/gcode/config/M221.cpp +++ b/Marlin/src/gcode/config/M221.cpp @@ -33,10 +33,8 @@ void GcodeSuite::M221() { const int8_t target_extruder = get_target_extruder_from_command(); if (target_extruder < 0) return; - if (parser.seenval('S')) { - planner.flow_percentage[target_extruder] = parser.value_int(); - planner.refresh_e_factor(target_extruder); - } + if (parser.seenval('S')) + planner.set_flow(target_extruder, parser.value_int()); else { SERIAL_ECHO_START(); SERIAL_CHAR('E', '0' + target_extruder); diff --git a/Marlin/src/gcode/sd/M1001.cpp b/Marlin/src/gcode/sd/M1001.cpp index e5082be31f..8f1427a9ab 100644 --- a/Marlin/src/gcode/sd/M1001.cpp +++ b/Marlin/src/gcode/sd/M1001.cpp @@ -31,10 +31,6 @@ #include "../queue.h" #endif -#if HAS_LEDS_OFF_FLAG - #include "../../MarlinCore.h" -#endif - #if EITHER(LCD_SET_PROGRESS_MANUALLY, SD_REPRINT_LAST_SELECTED_FILE) #include "../../lcd/ultralcd.h" #endif @@ -44,6 +40,7 @@ #endif #if HAS_LEDS_OFF_FLAG + #include "../../MarlinCore.h" // for wait_for_user_response #include "../../feature/leds/printer_event_leds.h" #endif diff --git a/Marlin/src/inc/Conditionals_post.h b/Marlin/src/inc/Conditionals_post.h index bb42c39665..9269c76b7d 100644 --- a/Marlin/src/inc/Conditionals_post.h +++ b/Marlin/src/inc/Conditionals_post.h @@ -2222,8 +2222,8 @@ #define FILAMENT_CHANGE_SLOW_LOAD_LENGTH 0 #endif -#if EXTRUDERS > 1 && !defined(TOOLCHANGE_FIL_EXTRA_PRIME) - #define TOOLCHANGE_FIL_EXTRA_PRIME 0 +#if EXTRUDERS > 1 && !defined(TOOLCHANGE_FS_EXTRA_PRIME) + #define TOOLCHANGE_FS_EXTRA_PRIME 0 #endif /** diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 6a0d0bd8e6..d1024e44ce 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -833,14 +833,15 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #endif #if ENABLED(TOOLCHANGE_FILAMENT_SWAP) - #ifndef TOOLCHANGE_FIL_SWAP_LENGTH - #error "TOOLCHANGE_FILAMENT_SWAP requires TOOLCHANGE_FIL_SWAP_LENGTH. Please update your Configuration." - #elif !defined(TOOLCHANGE_FIL_SWAP_RETRACT_SPEED) - #error "TOOLCHANGE_FILAMENT_SWAP requires TOOLCHANGE_FIL_SWAP_RETRACT_SPEED. Please update your Configuration." - #elif !defined(TOOLCHANGE_FIL_SWAP_PRIME_SPEED) - #error "TOOLCHANGE_FILAMENT_SWAP requires TOOLCHANGE_FIL_SWAP_PRIME_SPEED. Please update your Configuration." + #ifndef TOOLCHANGE_FS_LENGTH + #error "TOOLCHANGE_FILAMENT_SWAP requires TOOLCHANGE_FS_LENGTH. Please update your Configuration_adv.h." + #elif !defined(TOOLCHANGE_FS_RETRACT_SPEED) + #error "TOOLCHANGE_FILAMENT_SWAP requires TOOLCHANGE_FS_RETRACT_SPEED. Please update your Configuration_adv.h." + #elif !defined(TOOLCHANGE_FS_PRIME_SPEED) + #error "TOOLCHANGE_FILAMENT_SWAP requires TOOLCHANGE_FS_PRIME_SPEED. Please update your Configuration_adv.h." #endif #endif + #if ENABLED(TOOLCHANGE_PARK) #ifndef TOOLCHANGE_PARK_XY #error "TOOLCHANGE_PARK requires TOOLCHANGE_PARK_XY. Please update your Configuration." diff --git a/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.cpp b/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.cpp index 8bbbb231e2..91acd0a360 100644 --- a/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.cpp +++ b/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.cpp @@ -573,8 +573,7 @@ void DGUSScreenVariableHandler::HandleFlowRateChanged(DGUS_VP_Variable &var, voi #endif } - planner.flow_percentage[target_extruder] = newvalue; - planner.refresh_e_factor(target_extruder); + planner.set_flow(target_extruder, newvalue); ScreenHandler.skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel #else UNUSED(var); UNUSED(val_ptr); diff --git a/Marlin/src/lcd/extui/ui_api.cpp b/Marlin/src/lcd/extui/ui_api.cpp index b272d9d496..dd5ddd3b66 100644 --- a/Marlin/src/lcd/extui/ui_api.cpp +++ b/Marlin/src/lcd/extui/ui_api.cpp @@ -669,10 +669,7 @@ namespace ExtUI { float getRetractAcceleration_mm_s2() { return planner.settings.retract_acceleration; } float getTravelAcceleration_mm_s2() { return planner.settings.travel_acceleration; } void setFeedrate_mm_s(const feedRate_t fr) { feedrate_mm_s = fr; } - void setFlow_percent(const int16_t flow, const extruder_t extr) { - planner.flow_percentage[extr] = flow; - planner.refresh_e_factor(extr); - } + void setFlow_percent(const int16_t flow, const extruder_t extr) { planner.set_flow(extr, flow); } void setMinFeedrate_mm_s(const feedRate_t fr) { planner.settings.min_feedrate_mm_s = fr; } void setMinTravelFeedrate_mm_s(const feedRate_t fr) { planner.settings.min_travel_feedrate_mm_s = fr; } void setPrintingAcceleration_mm_s2(const float acc) { planner.settings.acceleration = acc; } diff --git a/Marlin/src/lcd/language/language_cz.h b/Marlin/src/lcd/language/language_cz.h index c8f0e6b13b..3e85224988 100644 --- a/Marlin/src/lcd/language/language_cz.h +++ b/Marlin/src/lcd/language/language_cz.h @@ -357,8 +357,8 @@ namespace Language_cz { PROGMEM Language_Str MSG_FILAMENT_PURGE_LENGTH = _UxGT("Délka zavedení"); PROGMEM Language_Str MSG_TOOL_CHANGE = _UxGT("Výměna nástroje"); PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT = _UxGT("Zdvih Z"); - PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD = _UxGT("Rychlost primár."); - PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD = _UxGT("Rychlost retrak."); + PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED = _UxGT("Rychlost primár."); + PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED = _UxGT("Rychlost retrak."); PROGMEM Language_Str MSG_NOZZLE_STANDBY = _UxGT("Tryska standby"); PROGMEM Language_Str MSG_FILAMENTCHANGE = _UxGT("Vyměnit filament"); PROGMEM Language_Str MSG_FILAMENTCHANGE_E = _UxGT("Vyměnit filament *"); diff --git a/Marlin/src/lcd/language/language_de.h b/Marlin/src/lcd/language/language_de.h index 4d0516e8d6..211869fc9c 100644 --- a/Marlin/src/lcd/language/language_de.h +++ b/Marlin/src/lcd/language/language_de.h @@ -347,9 +347,9 @@ namespace Language_de { PROGMEM Language_Str MSG_FILAMENT_PURGE_LENGTH = _UxGT("Entladelänge"); PROGMEM Language_Str MSG_TOOL_CHANGE = _UxGT("Werkzeugwechsel"); PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT = _UxGT("Z anheben"); - PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD = _UxGT("Prime-Geschwin."); - PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD = _UxGT("Einzug-Geschwin."); - + PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED = _UxGT("Prime-Geschwin."); + PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED = _UxGT("Einzug-Geschwin."); + PROGMEM Language_Str MSG_NOZZLE_STANDBY = _UxGT("Düsen-Standby"); PROGMEM Language_Str MSG_FILAMENTCHANGE = _UxGT("Filament wechseln"); PROGMEM Language_Str MSG_FILAMENTCHANGE_E = _UxGT("Filament wechseln *"); PROGMEM Language_Str MSG_FILAMENTLOAD = _UxGT("Filament laden"); diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index a3e25d9145..94d9d44cf7 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -371,11 +371,22 @@ namespace Language_en { PROGMEM Language_Str MSG_CONTROL_RETRACT_RECOVER_SWAPF = _UxGT("S UnRet V"); PROGMEM Language_Str MSG_AUTORETRACT = _UxGT("AutoRetr."); PROGMEM Language_Str MSG_FILAMENT_SWAP_LENGTH = _UxGT("Swap Length"); + PROGMEM Language_Str MSG_FILAMENT_SWAP_EXTRA = _UxGT("Swap Extra"); PROGMEM Language_Str MSG_FILAMENT_PURGE_LENGTH = _UxGT("Purge Length"); PROGMEM Language_Str MSG_TOOL_CHANGE = _UxGT("Tool Change"); PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT = _UxGT("Z Raise"); - PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD = _UxGT("Prime Speed"); - PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD = _UxGT("Retract Speed"); + PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED = _UxGT("Prime Speed"); + PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED = _UxGT("Retract Speed"); + PROGMEM Language_Str MSG_FILAMENT_PARK_ENABLED = _UxGT("Park Head"); + PROGMEM Language_Str MSG_SINGLENOZZLE_UNRETRACT_SPEED = _UxGT("Recover Speed"); + PROGMEM Language_Str MSG_SINGLENOZZLE_FAN_SPEED = _UxGT("Fan Speed"); + PROGMEM Language_Str MSG_SINGLENOZZLE_FAN_TIME = _UxGT("Fan Time"); + PROGMEM Language_Str MSG_TOOL_MIGRATION_ON = _UxGT("Auto ON"); + PROGMEM Language_Str MSG_TOOL_MIGRATION_OFF = _UxGT("Auto OFF"); + PROGMEM Language_Str MSG_TOOL_MIGRATION = _UxGT("Tool Migration"); + PROGMEM Language_Str MSG_TOOL_MIGRATION_AUTO = _UxGT("Auto-migration"); + PROGMEM Language_Str MSG_TOOL_MIGRATION_END = _UxGT("Last Extruder"); + PROGMEM Language_Str MSG_TOOL_MIGRATION_SWAP = _UxGT("Migrate to *"); PROGMEM Language_Str MSG_FILAMENTCHANGE = _UxGT("Change Filament"); PROGMEM Language_Str MSG_FILAMENTCHANGE_E = _UxGT("Change Filament *"); PROGMEM Language_Str MSG_FILAMENTLOAD = _UxGT("Load Filament"); diff --git a/Marlin/src/lcd/language/language_es.h b/Marlin/src/lcd/language/language_es.h index 015663e885..c95fd09f10 100644 --- a/Marlin/src/lcd/language/language_es.h +++ b/Marlin/src/lcd/language/language_es.h @@ -367,8 +367,8 @@ namespace Language_es { PROGMEM Language_Str MSG_FILAMENT_PURGE_LENGTH = _UxGT("Purgar longitud"); PROGMEM Language_Str MSG_TOOL_CHANGE = _UxGT("Cambiar Herramienta"); PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT = _UxGT("Aumentar Z"); - PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD = _UxGT("Vel. de Cebado"); - PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD = _UxGT("Vel. de retracción"); + PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED = _UxGT("Vel. de Cebado"); + PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED = _UxGT("Vel. de retracción"); PROGMEM Language_Str MSG_FILAMENTCHANGE = _UxGT("Cambiar filamento"); PROGMEM Language_Str MSG_FILAMENTCHANGE_E = _UxGT("Cambiar filamento *"); PROGMEM Language_Str MSG_FILAMENTLOAD = _UxGT("Cargar filamento"); diff --git a/Marlin/src/lcd/language/language_fr.h b/Marlin/src/lcd/language/language_fr.h index 2fca6adbb4..23258b9015 100644 --- a/Marlin/src/lcd/language/language_fr.h +++ b/Marlin/src/lcd/language/language_fr.h @@ -53,7 +53,7 @@ namespace Language_fr { PROGMEM Language_Str MSG_MAIN = _UxGT("Menu principal"); PROGMEM Language_Str MSG_ADVANCED_SETTINGS = _UxGT("Config. avancée"); PROGMEM Language_Str MSG_CONFIGURATION = _UxGT("Configuration"); - PROGMEM Language_Str MSG_AUTOSTART = _UxGT("Exéc. auto#.gcode"); + PROGMEM Language_Str MSG_AUTOSTART = _UxGT("Exéc. auto.gcode"); PROGMEM Language_Str MSG_DISABLE_STEPPERS = _UxGT("Arrêter moteurs"); PROGMEM Language_Str MSG_DEBUG_MENU = _UxGT("Menu debug"); PROGMEM Language_Str MSG_PROGRESS_BAR_TEST = _UxGT("Test barre progress."); @@ -329,10 +329,21 @@ namespace Language_fr { PROGMEM Language_Str MSG_AUTORETRACT = _UxGT("Rétraction auto"); PROGMEM Language_Str MSG_TOOL_CHANGE = _UxGT("Changement outil"); PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT = _UxGT("Augmenter Z"); - PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD = _UxGT("Vitesse primaire"); - PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD = _UxGT("Vitesse rétract°"); + PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED = _UxGT("Vitesse primaire"); + PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED = _UxGT("Vitesse rétract°"); + PROGMEM Language_Str MSG_FILAMENT_PARK_ENABLED = _UxGT("Garer Extrudeur"); + PROGMEM Language_Str MSG_SINGLENOZZLE_UNRETRACT_SPEED = _UxGT("Vitesse reprise"); + PROGMEM Language_Str MSG_SINGLENOZZLE_FAN_SPEED = _UxGT("Vit. ventil."); + PROGMEM Language_Str MSG_SINGLENOZZLE_FAN_TIME = _UxGT("Temps ventil."); + PROGMEM Language_Str MSG_TOOL_MIGRATION_ON = _UxGT("Auto ON"); + PROGMEM Language_Str MSG_TOOL_MIGRATION_OFF = _UxGT("Auto OFF"); + PROGMEM Language_Str MSG_TOOL_MIGRATION = _UxGT("Migration d'outil"); + PROGMEM Language_Str MSG_TOOL_MIGRATION_AUTO = _UxGT("Migration auto"); + PROGMEM Language_Str MSG_TOOL_MIGRATION_END = _UxGT("Extrudeur Final"); + PROGMEM Language_Str MSG_TOOL_MIGRATION_SWAP = _UxGT("Migrer vers *"); PROGMEM Language_Str MSG_NOZZLE_STANDBY = _UxGT("Attente buse"); PROGMEM Language_Str MSG_FILAMENT_SWAP_LENGTH = _UxGT("Longueur retrait"); + PROGMEM Language_Str MSG_FILAMENT_SWAP_EXTRA = _UxGT("Longueur Extra"); PROGMEM Language_Str MSG_FILAMENT_PURGE_LENGTH = _UxGT("Longueur de purge"); PROGMEM Language_Str MSG_FILAMENTCHANGE = _UxGT("Changer filament"); PROGMEM Language_Str MSG_FILAMENTCHANGE_E = _UxGT("Changer filament *"); diff --git a/Marlin/src/lcd/language/language_gl.h b/Marlin/src/lcd/language/language_gl.h index fa9f371971..d747b78183 100644 --- a/Marlin/src/lcd/language/language_gl.h +++ b/Marlin/src/lcd/language/language_gl.h @@ -371,8 +371,8 @@ namespace Language_gl { PROGMEM Language_Str MSG_FILAMENT_PURGE_LENGTH = _UxGT("Lonxitude de Purga"); PROGMEM Language_Str MSG_TOOL_CHANGE = _UxGT("Cambiar Ferramenta"); PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT = _UxGT("Levantar Z"); - PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD = _UxGT("Velocidade prim."); - PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD = _UxGT("Vel. de Retracción"); + PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED = _UxGT("Velocidade prim."); + PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED = _UxGT("Vel. de Retracción"); PROGMEM Language_Str MSG_FILAMENTCHANGE = _UxGT("Cambiar Filamento"); PROGMEM Language_Str MSG_FILAMENTCHANGE_E = _UxGT("Cambiar Filamento *"); PROGMEM Language_Str MSG_FILAMENTLOAD = _UxGT("Cargar Filamento"); diff --git a/Marlin/src/lcd/language/language_it.h b/Marlin/src/lcd/language/language_it.h index d17c100490..20af26be07 100644 --- a/Marlin/src/lcd/language/language_it.h +++ b/Marlin/src/lcd/language/language_it.h @@ -370,8 +370,8 @@ namespace Language_it { PROGMEM Language_Str MSG_FILAMENT_PURGE_LENGTH = _UxGT("Lunghezza spurgo"); PROGMEM Language_Str MSG_TOOL_CHANGE = _UxGT("Cambio utensile"); PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT = _UxGT("Risalita Z"); - PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD = _UxGT("Velocità innesco"); - PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD = _UxGT("Velocità retrazione"); + PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED = _UxGT("Velocità innesco"); + PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED = _UxGT("Velocità retrazione"); PROGMEM Language_Str MSG_NOZZLE_PARKED = _UxGT("Ugello Parcheggiato"); PROGMEM Language_Str MSG_NOZZLE_STANDBY = _UxGT("Standby ugello"); PROGMEM Language_Str MSG_FILAMENTCHANGE = _UxGT("Cambia filamento"); diff --git a/Marlin/src/lcd/language/language_pl.h b/Marlin/src/lcd/language/language_pl.h index 0cb4f25499..4fb2df6eec 100644 --- a/Marlin/src/lcd/language/language_pl.h +++ b/Marlin/src/lcd/language/language_pl.h @@ -339,8 +339,8 @@ namespace Language_pl { PROGMEM Language_Str MSG_FILAMENT_PURGE_LENGTH = _UxGT("Długość oczyszczania"); PROGMEM Language_Str MSG_TOOL_CHANGE = _UxGT("Zmiana narzędzia"); PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT = _UxGT("Podniesienie Z"); - PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD = _UxGT("Prędkość napełniania"); - PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD = _UxGT("Prędkość wycofania"); + PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED = _UxGT("Prędkość napełniania"); + PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED = _UxGT("Prędkość wycofania"); PROGMEM Language_Str MSG_NOZZLE_STANDBY = _UxGT("Dysza w oczekiwaniu"); PROGMEM Language_Str MSG_FILAMENTCHANGE = _UxGT("Zmień filament"); PROGMEM Language_Str MSG_FILAMENTCHANGE_E = _UxGT("Zmień filament *"); diff --git a/Marlin/src/lcd/language/language_pt_br.h b/Marlin/src/lcd/language/language_pt_br.h index 469b75e823..0d355147f8 100644 --- a/Marlin/src/lcd/language/language_pt_br.h +++ b/Marlin/src/lcd/language/language_pt_br.h @@ -286,8 +286,8 @@ namespace Language_pt_br { PROGMEM Language_Str MSG_FILAMENT_SWAP_LENGTH = _UxGT("Distancia Retração"); PROGMEM Language_Str MSG_TOOL_CHANGE = _UxGT("Mudar Ferramenta"); PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT = _UxGT("Levantar Z"); - PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD = _UxGT("Preparar Veloc."); - PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD = _UxGT("Veloc. Retração"); + PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED = _UxGT("Preparar Veloc."); + PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED = _UxGT("Veloc. Retração"); PROGMEM Language_Str MSG_FILAMENTCHANGE = _UxGT("Trocar Filamento"); PROGMEM Language_Str MSG_FILAMENTCHANGE_E = _UxGT("Trocar Filamento *"); PROGMEM Language_Str MSG_FILAMENTLOAD_E = _UxGT("Carregar Filamento *"); diff --git a/Marlin/src/lcd/language/language_tr.h b/Marlin/src/lcd/language/language_tr.h index a33b0d315d..aa68ece992 100644 --- a/Marlin/src/lcd/language/language_tr.h +++ b/Marlin/src/lcd/language/language_tr.h @@ -365,8 +365,8 @@ namespace Language_tr { PROGMEM Language_Str MSG_FILAMENT_PURGE_LENGTH = _UxGT("Tasfiye uzunluğu"); PROGMEM Language_Str MSG_TOOL_CHANGE = _UxGT("Takım Değişimi"); PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT = _UxGT("Z Yükselt"); - PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD = _UxGT("Birincil Hız"); - PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD = _UxGT("Geri Çekme Hızı"); + PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED = _UxGT("Birincil Hız"); + PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED = _UxGT("Geri Çekme Hızı"); PROGMEM Language_Str MSG_NOZZLE_STANDBY = _UxGT("Nozul Beklemede"); PROGMEM Language_Str MSG_FILAMENTCHANGE = _UxGT("Filaman Değiştir"); PROGMEM Language_Str MSG_FILAMENTCHANGE_E = _UxGT("Filaman Değiştir *"); diff --git a/Marlin/src/lcd/language/language_vi.h b/Marlin/src/lcd/language/language_vi.h index 781a1242b8..8538c81831 100644 --- a/Marlin/src/lcd/language/language_vi.h +++ b/Marlin/src/lcd/language/language_vi.h @@ -299,8 +299,8 @@ namespace Language_vi { PROGMEM Language_Str MSG_FILAMENT_SWAP_LENGTH = _UxGT("Khoảng Cách Rút"); // Retract Distance PROGMEM Language_Str MSG_TOOL_CHANGE = _UxGT("Thay Đổi Công Cụ"); // Tool Change PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT = _UxGT("Đưa Lên Z"); // Z Raise - PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD = _UxGT("Tốc Độ Tuôn Ra"); // Prime Speed - PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD = _UxGT("Tốc Độ Rút Lại"); // Retract Speed + PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED = _UxGT("Tốc Độ Tuôn Ra"); // Prime Speed + PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED = _UxGT("Tốc Độ Rút Lại"); // Retract Speed PROGMEM Language_Str MSG_FILAMENTCHANGE = _UxGT("Thay dây nhựa"); // change filament PROGMEM Language_Str MSG_FILAMENTCHANGE_E = _UxGT("Thay dây nhựa *"); // change filament PROGMEM Language_Str MSG_FILAMENTLOAD = _UxGT("Nạp dây nhựa"); // load filament diff --git a/Marlin/src/lcd/language/language_zh_TW.h b/Marlin/src/lcd/language/language_zh_TW.h index 6bb7d759f6..1019fcb03a 100644 --- a/Marlin/src/lcd/language/language_zh_TW.h +++ b/Marlin/src/lcd/language/language_zh_TW.h @@ -346,8 +346,8 @@ namespace Language_zh_TW { PROGMEM Language_Str MSG_FILAMENT_PURGE_LENGTH = _UxGT("清除長度"); //"Purge Length" PROGMEM Language_Str MSG_TOOL_CHANGE = _UxGT("交換工具"); //"Tool Change" PROGMEM Language_Str MSG_TOOL_CHANGE_ZLIFT = _UxGT("Z軸提昇"); //"Z Raise" - PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPD = _UxGT("最高速度"); //"Prime Speed" - PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPD = _UxGT("收回速度"); //"Retract Speed" + PROGMEM Language_Str MSG_SINGLENOZZLE_PRIME_SPEED = _UxGT("最高速度"); //"Prime Speed" + PROGMEM Language_Str MSG_SINGLENOZZLE_RETRACT_SPEED = _UxGT("收回速度"); //"Retract Speed" PROGMEM Language_Str MSG_NOZZLE_STANDBY = _UxGT("噴嘴待機"); //"Nozzle Standby" PROGMEM Language_Str MSG_FILAMENTCHANGE = _UxGT("更換絲料"); //"Change filament" PROGMEM Language_Str MSG_FILAMENTCHANGE_E = _UxGT("更換絲料 *"); diff --git a/Marlin/src/lcd/menu/menu_configuration.cpp b/Marlin/src/lcd/menu/menu_configuration.cpp index b0202198b7..bf7be4dbc2 100644 --- a/Marlin/src/lcd/menu/menu_configuration.cpp +++ b/Marlin/src/lcd/menu/menu_configuration.cpp @@ -104,22 +104,50 @@ void menu_advanced_settings(); START_MENU(); BACK_ITEM(MSG_CONFIGURATION); #if ENABLED(TOOLCHANGE_FILAMENT_SWAP) - static constexpr float max_extrude = - #if ENABLED(PREVENT_LENGTHY_EXTRUDE) - EXTRUDE_MAXLENGTH - #else - 500 - #endif - ; + static constexpr float max_extrude = TERN(PREVENT_LENGTHY_EXTRUDE, EXTRUDE_MAXLENGTH, 500); + #if ENABLED(TOOLCHANGE_PARK) + EDIT_ITEM(bool, MSG_FILAMENT_PARK_ENABLED, &toolchange_settings.enable_park); + #endif EDIT_ITEM(float3, MSG_FILAMENT_SWAP_LENGTH, &toolchange_settings.swap_length, 0, max_extrude); + EDIT_ITEM(float41sign, MSG_FILAMENT_SWAP_EXTRA, &toolchange_settings.extra_resume, -10, 10); + EDIT_ITEM_FAST(int4, MSG_SINGLENOZZLE_RETRACT_SPEED, &toolchange_settings.retract_speed, 10, 5400); + EDIT_ITEM_FAST(int4, MSG_SINGLENOZZLE_UNRETRACT_SPEED, &toolchange_settings.unretract_speed, 10, 5400); EDIT_ITEM(float3, MSG_FILAMENT_PURGE_LENGTH, &toolchange_settings.extra_prime, 0, max_extrude); - EDIT_ITEM_FAST(int4, MSG_SINGLENOZZLE_RETRACT_SPD, &toolchange_settings.retract_speed, 10, 5400); - EDIT_ITEM_FAST(int4, MSG_SINGLENOZZLE_PRIME_SPD, &toolchange_settings.prime_speed, 10, 5400); + EDIT_ITEM_FAST(int4, MSG_SINGLENOZZLE_PRIME_SPEED, &toolchange_settings.prime_speed, 10, 5400); + EDIT_ITEM_FAST(int4, MSG_SINGLENOZZLE_FAN_SPEED, &toolchange_settings.fan_speed, 0, 255); + EDIT_ITEM_FAST(int4, MSG_SINGLENOZZLE_FAN_TIME, &toolchange_settings.fan_time, 1, 30); #endif EDIT_ITEM(float3, MSG_TOOL_CHANGE_ZLIFT, &toolchange_settings.z_raise, 0, 10); END_MENU(); } + #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE) + + #include "../../module/motion.h" // for active_extruder + + void menu_toolchange_migration() { + START_MENU(); + BACK_ITEM(MSG_CONFIGURATION); + + // Auto mode ON/OFF + EDIT_ITEM(bool, MSG_TOOL_MIGRATION_AUTO, &migration.automode); + EDIT_ITEM(uint8, MSG_TOOL_MIGRATION_END, &migration.last, 0, EXTRUDERS - 1); + + // Migrate to a chosen extruder + PGM_P const msg_migrate = GET_TEXT(MSG_TOOL_MIGRATION_SWAP); + LOOP_L_N(s, EXTRUDERS) { + if (s != active_extruder) { + ACTION_ITEM_N_P(s, msg_migrate, []{ + char cmd[12]; + sprintf_P(cmd, PSTR("M217 T%i"), int(MenuItemBase::itemIndex)); + queue.inject(cmd); + }); + } + } + END_MENU(); + } + #endif + #endif #if HAS_HOTEND_OFFSET @@ -373,6 +401,9 @@ void menu_configuration() { // #if EXTRUDERS > 1 SUBMENU(MSG_TOOL_CHANGE, menu_tool_change); + #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE) + SUBMENU(MSG_TOOL_MIGRATION, menu_toolchange_migration); + #endif #endif // diff --git a/Marlin/src/module/configuration_store.cpp b/Marlin/src/module/configuration_store.cpp index 698447a4be..84b8c75370 100644 --- a/Marlin/src/module/configuration_store.cpp +++ b/Marlin/src/module/configuration_store.cpp @@ -2423,16 +2423,32 @@ void MarlinSettings::reset() { #if EXTRUDERS > 1 #if ENABLED(TOOLCHANGE_FILAMENT_SWAP) - toolchange_settings.swap_length = TOOLCHANGE_FIL_SWAP_LENGTH; - toolchange_settings.extra_prime = TOOLCHANGE_FIL_EXTRA_PRIME; - toolchange_settings.prime_speed = TOOLCHANGE_FIL_SWAP_PRIME_SPEED; - toolchange_settings.retract_speed = TOOLCHANGE_FIL_SWAP_RETRACT_SPEED; + toolchange_settings.swap_length = TOOLCHANGE_FS_LENGTH; + toolchange_settings.extra_resume = TOOLCHANGE_FS_EXTRA_RESUME_LENGTH; + toolchange_settings.retract_speed = TOOLCHANGE_FS_RETRACT_SPEED; + toolchange_settings.unretract_speed = TOOLCHANGE_FS_UNRETRACT_SPEED; + toolchange_settings.extra_prime = TOOLCHANGE_FS_EXTRA_PRIME; + toolchange_settings.prime_speed = TOOLCHANGE_FS_PRIME_SPEED; + toolchange_settings.fan_speed = TOOLCHANGE_FS_FAN_SPEED; + toolchange_settings.fan_time = TOOLCHANGE_FS_FAN_TIME; #endif + + #if ENABLED(TOOLCHANGE_FS_PRIME_FIRST_USED) + enable_first_prime = false; + #endif + #if ENABLED(TOOLCHANGE_PARK) constexpr xyz_pos_t tpxy = TOOLCHANGE_PARK_XY; + toolchange_settings.enable_park = true; toolchange_settings.change_point = tpxy; #endif + toolchange_settings.z_raise = TOOLCHANGE_ZRAISE; + + #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE) + migration = migration_defaults; + #endif + #endif #if ENABLED(BACKLASH_GCODE) diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index 7ac7d5ade7..87a6e7c0a8 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -423,12 +423,14 @@ class Planner { #if EXTRUDERS FORCE_INLINE static void refresh_e_factor(const uint8_t e) { - e_factor[e] = (flow_percentage[e] * 0.01f - #if DISABLED(NO_VOLUMETRICS) - * volumetric_multiplier[e] - #endif - ); + e_factor[e] = flow_percentage[e] * 0.01f * TERN(NO_VOLUMETRICS, 1.0f, volumetric_multiplier[e]); } + + static inline void set_flow(const uint8_t e, const int16_t flow) { + flow_percentage[e] = flow; + refresh_e_factor(e); + } + #endif // Manage fans, paste pressure, etc. diff --git a/Marlin/src/module/tool_change.cpp b/Marlin/src/module/tool_change.cpp index 23925d630c..210d220e7b 100644 --- a/Marlin/src/module/tool_change.cpp +++ b/Marlin/src/module/tool_change.cpp @@ -38,6 +38,15 @@ toolchange_settings_t toolchange_settings; // Initialized by settings.load() #endif +#if ENABLED(TOOLCHANGE_MIGRATION_FEATURE) + migration_settings_t migration = migration_defaults; + bool enable_first_prime; +#endif + +#if ENABLED(TOOLCHANGE_FS_INIT_BEFORE_SWAP) + bool toolchange_extruder_ready[EXTRUDERS]; +#endif + #if ENABLED(SINGLENOZZLE) uint16_t singlenozzle_temp[EXTRUDERS]; #if FAN_COUNT > 0 @@ -85,6 +94,14 @@ #include "../feature/pause.h" #endif +#if ENABLED(TOOLCHANGE_FILAMENT_SWAP) + #include "../gcode/gcode.h" + #if TOOLCHANGE_FS_WIPE_RETRACT <= 0 + #undef TOOLCHANGE_FS_WIPE_RETRACT + #define TOOLCHANGE_FS_WIPE_RETRACT 0 + #endif +#endif + #if DO_SWITCH_EXTRUDER #if EXTRUDERS > 3 @@ -759,6 +776,77 @@ inline void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_a #endif // DUAL_X_CARRIAGE +/** + * Prime active tool using TOOLCHANGE_FILAMENT_SWAP settings + */ +#if ENABLED(TOOLCHANGE_FILAMENT_SWAP) + +void tool_change_prime() { + if (toolchange_settings.extra_prime > 0 + && TERN(PREVENT_COLD_EXTRUSION, !thermalManager.targetTooColdToExtrude(active_extruder), 1) + ) { + destination = current_position; // Remember the old position + + const bool ok = TERN1(TOOLCHANGE_PARK, all_axes_homed() && toolchange_settings.enable_park); + + // Z raise + if (ok) { + // Do a small lift to avoid the workpiece in the move back (below) + current_position.z += toolchange_settings.z_raise; + #if HAS_SOFTWARE_ENDSTOPS + NOMORE(current_position.z, soft_endstop.max.z); + #endif + fast_line_to_current(Z_AXIS); + planner.synchronize(); + } + + // Park + #if ENABLED(TOOLCHANGE_PARK) + if (ok) { + TERN(TOOLCHANGE_PARK_Y_ONLY,,current_position.x = toolchange_settings.change_point.x); + TERN(TOOLCHANGE_PARK_X_ONLY,,current_position.y = toolchange_settings.change_point.y); + planner.buffer_line(current_position, MMM_TO_MMS(TOOLCHANGE_PARK_XY_FEEDRATE), active_extruder); + planner.synchronize(); + } + #endif + + // Prime (All distances are added and slowed down to ensure secure priming in all circumstances) + unscaled_e_move(toolchange_settings.swap_length + toolchange_settings.extra_prime, MMM_TO_MMS(toolchange_settings.prime_speed)); + + // Cutting retraction + #if TOOLCHANGE_FS_WIPE_RETRACT + unscaled_e_move(-(TOOLCHANGE_FS_WIPE_RETRACT), MMM_TO_MMS(toolchange_settings.retract_speed)); + #endif + + // Cool down with fan + #if TOOLCHANGE_FS_FAN >= 0 && FAN_COUNT > 0 + const int16_t fansp = thermalManager.fan_speed[TOOLCHANGE_FS_FAN]; + thermalManager.fan_speed[TOOLCHANGE_FS_FAN] = toolchange_settings.fan_speed; + safe_delay(toolchange_settings.fan_time * 1000); + thermalManager.fan_speed[TOOLCHANGE_FS_FAN] = fansp; + #endif + + // Move back + #if ENABLED(TOOLCHANGE_PARK) + if (ok) { + #if ENABLED(TOOLCHANGE_NO_RETURN) + do_blocking_move_to_z(destination.z, planner.settings.max_feedrate_mm_s[Z_AXIS]); + #else + do_blocking_move_to(destination, MMM_TO_MMS(TOOLCHANGE_PARK_XY_FEEDRATE)); + #endif + } + #endif + + // Cutting recover + unscaled_e_move(toolchange_settings.extra_resume + TOOLCHANGE_FS_WIPE_RETRACT, MMM_TO_MMS(toolchange_settings.unretract_speed)); + + planner.synchronize(); + current_position.e = destination.e; + sync_plan_position_e(); // Resume at the old E position + } +} +#endif + /** * Perform a tool-change, which may result in moving the * previous tool out of the way and the new tool into place. @@ -826,39 +914,52 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { const uint8_t old_tool = active_extruder; const bool can_move_away = !no_move && !idex_full_control; - #if ENABLED(TOOLCHANGE_FILAMENT_SWAP) - const bool should_swap = can_move_away && toolchange_settings.swap_length; - #if ENABLED(PREVENT_COLD_EXTRUSION) - const bool too_cold = !DEBUGGING(DRYRUN) && (thermalManager.targetTooColdToExtrude(old_tool) || thermalManager.targetTooColdToExtrude(new_tool)); - #else - constexpr bool too_cold = false; - #endif - if (should_swap) { - if (too_cold) { - SERIAL_ECHO_MSG(STR_ERR_HOTEND_TOO_COLD); - #if ENABLED(SINGLENOZZLE) - active_extruder = new_tool; - return; - #endif - } - else { - #if ENABLED(ADVANCED_PAUSE_FEATURE) - unscaled_e_move(-toolchange_settings.swap_length, MMM_TO_MMS(toolchange_settings.retract_speed)); - #else - current_position.e -= toolchange_settings.swap_length / planner.e_factor[old_tool]; - planner.buffer_line(current_position, MMM_TO_MMS(toolchange_settings.retract_speed), old_tool); - planner.synchronize(); - #endif - } - } - #endif // TOOLCHANGE_FILAMENT_SWAP - #if HAS_LEVELING && DISABLED(SINGLENOZZLE) // Set current position to the physical position TEMPORARY_BED_LEVELING_STATE(false); #endif + // First tool priming. To prime again, reboot the machine. + #if BOTH(TOOLCHANGE_FILAMENT_SWAP, TOOLCHANGE_FS_PRIME_FIRST_USED) + static bool first_tool_is_primed = false; + if (new_tool == old_tool && !first_tool_is_primed && enable_first_prime) { + tool_change_prime(); + first_tool_is_primed = true; + toolchange_extruder_ready[old_tool] = true; // Primed and initialized + } + #endif + if (new_tool != old_tool) { + destination = current_position; + + // Z raise before retraction + #if ENABLED(TOOLCHANGE_ZRAISE_BEFORE_RETRACT) && DISABLED(SWITCHING_NOZZLE) + if (can_move_away && TERN1(toolchange_settings.enable_park)) { + // Do a small lift to avoid the workpiece in the move back (below) + current_position.z += toolchange_settings.z_raise; + #if HAS_SOFTWARE_ENDSTOPS + NOMORE(current_position.z, soft_endstop.max.z); + #endif + fast_line_to_current(Z_AXIS); + planner.synchronize(); + } + #endif + + // Unload / Retract + #if ENABLED(TOOLCHANGE_FILAMENT_SWAP) + const bool should_swap = can_move_away && toolchange_settings.swap_length; + too_cold = TERN0(PREVENT_COLD_EXTRUSION, + !DEBUGGING(DRYRUN) && (thermalManager.targetTooColdToExtrude(old_tool) || thermalManager.targetTooColdToExtrude(new_tool)) + ); + if (should_swap) { + if (too_cold) { + SERIAL_ECHO_MSG(STR_ERR_HOTEND_TOO_COLD); + if (ENABLED(SINGLENOZZLE)) { active_extruder = new_tool; return; } + } + else + unscaled_e_move(-toolchange_settings.swap_length, MMM_TO_MMS(toolchange_settings.retract_speed)); + } + #endif TERN_(SWITCHING_NOZZLE_TWO_SERVOS, raise_nozzle(old_tool)); @@ -877,18 +978,23 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { #endif #endif - destination = current_position; - - #if DISABLED(SWITCHING_NOZZLE) - if (can_move_away) { + #if DISABLED(TOOLCHANGE_ZRAISE_BEFORE_RETRACT) && DISABLED(SWITCHING_NOZZLE) + if (can_move_away && TERN1(TOOLCHANGE_PARK, toolchange_settings.enable_park)) { // Do a small lift to avoid the workpiece in the move back (below) current_position.z += toolchange_settings.z_raise; #if HAS_SOFTWARE_ENDSTOPS NOMORE(current_position.z, soft_endstop.max.z); #endif fast_line_to_current(Z_AXIS); - TERN_(TOOLCHANGE_PARK, current_position = toolchange_settings.change_point); - planner.buffer_line(current_position, feedrate_mm_s, old_tool); + } + #endif + + // Toolchange park + #if ENABLED(TOOLCHANGE_PARK) && DISABLED(SWITCHING_NOZZLE) + if (can_move_away && toolchange_settings.enable_park) { + TERN(TOOLCHANGE_PARK_Y_ONLY,,current_position.x = toolchange_settings.change_point.x); + TERN(TOOLCHANGE_PARK_X_ONLY,,current_position.y = toolchange_settings.change_point.y); + planner.buffer_line(current_position, MMM_TO_MMS(TOOLCHANGE_PARK_XY_FEEDRATE), old_tool); planner.synchronize(); } #endif @@ -932,9 +1038,8 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { move_nozzle_servo(new_tool); #endif - #if DISABLED(DUAL_X_CARRIAGE) - active_extruder = new_tool; // Set the new active extruder - #endif + // Set the new active extruder + if (DISABLED(DUAL_X_CARRIAGE)) active_extruder = new_tool; // The newly-selected extruder XYZ is actually at... if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("Offset Tool XYZ by { ", diff.x, ", ", diff.y, ", ", diff.z, " }"); @@ -951,7 +1056,8 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { #endif // Return to position and lower again - if (safe_to_move && !no_move && IsRunning()) { + const bool should_move = safe_to_move && !no_move && IsRunning(); + if (should_move) { #if ENABLED(SINGLENOZZLE) #if FAN_COUNT > 0 @@ -969,17 +1075,35 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { #if ENABLED(TOOLCHANGE_FILAMENT_SWAP) if (should_swap && !too_cold) { - #if ENABLED(ADVANCED_PAUSE_FEATURE) - unscaled_e_move(toolchange_settings.swap_length, MMM_TO_MMS(toolchange_settings.prime_speed)); - unscaled_e_move(toolchange_settings.extra_prime, ADVANCED_PAUSE_PURGE_FEEDRATE); - #else - current_position.e += toolchange_settings.swap_length / planner.e_factor[new_tool]; - planner.buffer_line(current_position, MMM_TO_MMS(toolchange_settings.prime_speed), new_tool); - current_position.e += toolchange_settings.extra_prime / planner.e_factor[new_tool]; - planner.buffer_line(current_position, MMM_TO_MMS(toolchange_settings.prime_speed * 0.2f), new_tool); + + float fr = toolchange_settings.unretract_speed; + + #if ENABLED(TOOLCHANGE_FS_INIT_BEFORE_SWAP) + if (!toolchange_extruder_ready[new_tool]) { + toolchange_extruder_ready[new_tool] = true; + fr = toolchange_settings.prime_speed; // Next move is a prime + unscaled_e_move(0, MMM_TO_MMS(fr)); // Init planner with 0 length move + } + #endif + + // Unretract (or Prime) + unscaled_e_move(toolchange_settings.swap_length, MMM_TO_MMS(fr)); + + // Extra Prime + unscaled_e_move(toolchange_settings.extra_prime, MMM_TO_MMS(toolchange_settings.prime_speed)); + + // Cutting retraction + #if TOOLCHANGE_FS_WIPE_RETRACT + unscaled_e_move(-(TOOLCHANGE_FS_WIPE_RETRACT), MMM_TO_MMS(toolchange_settings.retract_speed)); + #endif + + // Cool down with fan + #if TOOLCHANGE_FS_FAN >= 0 && FAN_COUNT > 0 + const int16_t fansp = thermalManager.fan_speed[TOOLCHANGE_FS_FAN]; + thermalManager.fan_speed[TOOLCHANGE_FS_FAN] = toolchange_settings.fan_speed; + safe_delay(toolchange_settings.fan_time * 1000); + thermalManager.fan_speed[TOOLCHANGE_FS_FAN] = fansp; #endif - planner.synchronize(); - planner.set_e_position_mm((destination.e = current_position.e = current_position.e - (TOOLCHANGE_FIL_EXTRA_PRIME))); } #endif @@ -1000,22 +1124,43 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { #if ENABLED(TOOLCHANGE_NO_RETURN) // Just move back down if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Move back Z only"); + + #if ENABLED(TOOLCHANGE_PARK) + if (toolchange_settings.enable_park) + #endif do_blocking_move_to_z(destination.z, planner.settings.max_feedrate_mm_s[Z_AXIS]); + #else // Move back to the original (or adjusted) position if (DEBUGGING(LEVELING)) DEBUG_POS("Move back", destination); - do_blocking_move_to(destination); + + #if ENABLED(TOOLCHANGE_PARK) + if (toolchange_settings.enable_park) do_blocking_move_to_xy_z(destination, destination.z, MMM_TO_MMS(TOOLCHANGE_PARK_XY_FEEDRATE)); + #else + do_blocking_move_to_xy(destination); + #endif + #endif } + else if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Move back skipped"); + #if ENABLED(TOOLCHANGE_FILAMENT_SWAP) + if (should_swap && !too_cold) { + // Cutting recover + unscaled_e_move(toolchange_settings.extra_resume + TOOLCHANGE_FS_WIPE_RETRACT, MMM_TO_MMS(toolchange_settings.unretract_speed)); + current_position.e = 0; + sync_plan_position_e(); // New extruder primed and set to 0 + } + #endif + TERN_(DUAL_X_CARRIAGE, active_extruder_parked = false); } + #if ENABLED(SWITCHING_NOZZLE) - else { - // Move back down. (Including when the new tool is higher.) + // Move back down. (Including when the new tool is higher.) + if (!should_move) do_blocking_move_to_z(destination.z, planner.settings.max_feedrate_mm_s[Z_AXIS]); - } #endif TERN_(PRUSA_MMU2, mmu2.tool_change(new_tool)); @@ -1053,3 +1198,79 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { #endif // EXTRUDERS > 1 } + +#if ENABLED(TOOLCHANGE_MIGRATION_FEATURE) + + void extruder_migration() { + + #if ENABLED(PREVENT_COLD_EXTRUSION) + if (thermalManager.targetTooColdToExtrude(active_extruder)) return; + #endif + + // No auto-migration or specified target? + if (!migration.target && active_extruder >= migration.last) { + migration.automode = false; + return; + } + + // Migrate to a target or the next extruder + + uint8_t migration_extruder = active_extruder; + + if (migration.target) { + // Specified target ok? + const int16_t t = migration.target - 1; + if (t != active_extruder) migration_extruder = t; + } + else if (migration.automode && migration_extruder < migration.last && migration_extruder < EXTRUDERS - 1) + migration_extruder++; + + if (migration_extruder == active_extruder) return; + + // Migration begins + + migration.in_progress = true; // Prevent runout script + planner.synchronize(); + + // Remember position before migration + const float resume_current_e = current_position.e; + + // Migrate the flow + planner.set_flow(migration_extruder, planner.flow_percentage[active_extruder]); + + // Migrate the retracted state + #if ENABLED(FWRETRACT) + fwretract.retracted[migration_extruder] = fwretract.retracted[active_extruder]; + #endif + + // Migrate the temperature to the new hotend + #if HOTENDS > 1 + thermalManager.setTargetHotend(thermalManager.degTargetHotend(active_extruder), migration_extruder); + #if HAS_DISPLAY + thermalManager.set_heating_message(0); + #endif + thermalManager.wait_for_hotend(active_extruder); + #endif + + // Perform the tool change + tool_change(migration_extruder); + + // Retract if previously retracted + #if ENABLED(FWRETRACT) + if (fwretract.retracted[active_extruder]) + unscaled_e_move(-fwretract.settings.retract_length, fwretract.settings.retract_feedrate_mm_s); + #endif + + // If no available extruder + if (EXTRUDERS < 2 || active_extruder >= EXTRUDERS - 2 || active_extruder == migration.last) + migration.automode = false; + + migration.in_progress = false; + + current_position.e = resume_current_e; + + planner.synchronize(); + planner.set_e_position_mm(current_position.e); // New extruder primed and ready + } + +#endif // TOOLCHANGE_MIGRATION_FEATURE diff --git a/Marlin/src/module/tool_change.h b/Marlin/src/module/tool_change.h index 0e915a0415..534a17e946 100644 --- a/Marlin/src/module/tool_change.h +++ b/Marlin/src/module/tool_change.h @@ -28,15 +28,39 @@ typedef struct { #if ENABLED(TOOLCHANGE_FILAMENT_SWAP) - float swap_length, extra_prime; - int16_t prime_speed, retract_speed; + float swap_length, extra_prime, extra_resume; + int16_t prime_speed, retract_speed, unretract_speed, fan, fan_speed, fan_time; + #endif + #if ENABLED(TOOLCHANGE_PARK) + bool enable_park; + xy_pos_t change_point; #endif - TERN_(TOOLCHANGE_PARK, xy_pos_t change_point); float z_raise; } toolchange_settings_t; extern toolchange_settings_t toolchange_settings; + #if ENABLED(TOOLCHANGE_FILAMENT_SWAP) + extern void tool_change_prime(); + #endif + + #if ENABLED(TOOLCHANGE_FS_PRIME_FIRST_USED) + extern bool enable_first_prime; + #endif + + #if ENABLED(TOOLCHANGE_FS_INIT_BEFORE_SWAP) + extern bool toolchange_extruder_ready[EXTRUDERS]; + #endif + + #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE) + typedef struct { + uint8_t target, last; + bool automode, in_progress; + } migration_settings_t; + constexpr migration_settings_t migration_defaults = { 0, 0, false, false }; + extern migration_settings_t migration; + void extruder_migration(); + #endif #endif #if DO_SWITCH_EXTRUDER diff --git a/buildroot/share/tests/BIGTREE_GTR_V1_0-tests b/buildroot/share/tests/BIGTREE_GTR_V1_0-tests index 0738a2818b..18a6a75f6f 100644 --- a/buildroot/share/tests/BIGTREE_GTR_V1_0-tests +++ b/buildroot/share/tests/BIGTREE_GTR_V1_0-tests @@ -33,6 +33,7 @@ opt_set TEMP_SENSOR_3 1 opt_set TEMP_SENSOR_4 1 opt_set TEMP_SENSOR_5 1 opt_set NUM_Z_STEPPER_DRIVERS 3 +opt_enable TOOLCHANGE_FILAMENT_SWAP TOOLCHANGE_MIGRATION_FEATURE TOOLCHANGE_FS_INIT_BEFORE_SWAP TOOLCHANGE_FS_PRIME_FIRST_USED exec_test $1 $2 "BigTreeTech GTR 6 Extruders Triple Z" # clean up