🐛 Fix Tool Change priming (#21142)

This commit is contained in:
Robert Brenckman
2022-04-10 01:24:07 -04:00
committed by Scott Lahteine
parent 2086cc9f4e
commit b2b5b85045
7 changed files with 199 additions and 112 deletions

View File

@ -32,6 +32,7 @@
#include "../MarlinCore.h"
//#define DEBUG_TOOL_CHANGE
//#define DEBUG_TOOLCHANGE_FILAMENT_SWAP
#define DEBUG_OUT ENABLED(DEBUG_TOOL_CHANGE)
#include "../core/debug_out.h"
@ -42,7 +43,6 @@
#if ENABLED(TOOLCHANGE_MIGRATION_FEATURE)
migration_settings_t migration = migration_defaults;
bool enable_first_prime;
#endif
#if ENABLED(TOOLCHANGE_FS_INIT_BEFORE_SWAP)
@ -150,6 +150,7 @@
#endif // SWITCHING_NOZZLE
// Move to position routines
void _line_to_current(const AxisEnum fr_axis, const float fscale=1) {
line_to_current_position(planner.settings.max_feedrate_mm_s[fr_axis] * fscale);
}
@ -899,10 +900,135 @@ void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_axis, 0.
*/
#if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
#ifdef DEBUG_TOOLCHANGE_FILAMENT_SWAP
#define FS_DEBUG(V...) SERIAL_ECHOLNPGM("DEBUG: " V)
#else
#define FS_DEBUG(...) NOOP
#endif
// Define any variables required
static Flags<EXTRUDERS> extruder_was_primed; // Extruders primed status
#if ENABLED(TOOLCHANGE_FS_PRIME_FIRST_USED)
bool enable_first_prime; // As set by M217 V
#endif
// Cool down with fan
inline void filament_swap_cooling() {
#if HAS_FAN && TOOLCHANGE_FS_FAN >= 0
thermalManager.fan_speed[TOOLCHANGE_FS_FAN] = toolchange_settings.fan_speed;
gcode.dwell(SEC_TO_MS(toolchange_settings.fan_time));
thermalManager.fan_speed[TOOLCHANGE_FS_FAN] = 0;
#endif
}
/**
* Check if too cold to move the specified tool
*
* Returns TRUE if too cold to move (also echos message: STR_ERR_HOTEND_TOO_COLD)
* Returns FALSE if able to move.
*/
bool too_cold(uint8_t toolID){
if (TERN0(PREVENT_COLD_EXTRUSION, !DEBUGGING(DRYRUN) && thermalManager.targetTooColdToExtrude(toolID))) {
SERIAL_ECHO_MSG(STR_ERR_HOTEND_TOO_COLD);
return true;
}
return false;
}
/**
* Cutting recovery -- Recover from cutting retraction that occurs at the end of nozzle priming
*
* If the active_extruder is up to temp (!too_cold):
* Extrude filament distance = toolchange_settings.extra_resume + TOOLCHANGE_FS_WIPE_RETRACT
* current_position.e = e;
* sync_plan_position_e();
*/
void extruder_cutting_recover(const_float_t e) {
if (!too_cold(active_extruder)) {
const float dist = toolchange_settings.extra_resume + (TOOLCHANGE_FS_WIPE_RETRACT);
FS_DEBUG("Performing Cutting Recover | Distance: ", dist, " | Speed: ", MMM_TO_MMS(toolchange_settings.unretract_speed), "mm/s");
unscaled_e_move(dist, MMM_TO_MMS(toolchange_settings.unretract_speed));
planner.synchronize();
FS_DEBUG("Set position to: ", e);
current_position.e = e;
sync_plan_position_e(); // Resume new E Position
}
}
/**
* Prime the currently selected extruder (Filament loading only)
*
* If too_cold(toolID) returns TRUE -> returns without moving extruder.
* Extruders filament = swap_length + extra prime, then performs cutting retraction if enabled.
* If cooling fan is enabled, calls filament_swap_cooling();
*/
void extruder_prime() {
if (too_cold(active_extruder)) {
FS_DEBUG("Priming Aborted - Nozzle Too Cold!");
return; // Extruder too cold to prime
}
float fr = toolchange_settings.unretract_speed; // Set default speed for unretract
#if ENABLED(TOOLCHANGE_FS_SLOW_FIRST_PRIME)
/*
* Perform first unretract movement at the slower Prime_Speed to avoid breakage on first prime
*/
static Flags<EXTRUDERS> extruder_did_first_prime; // Extruders first priming status
if (!extruder_did_first_prime[active_extruder]) {
extruder_did_first_prime.set(active_extruder); // Log first prime complete
// new nozzle - prime at user-specified speed.
FS_DEBUG("First time priming T", active_extruder, ", reducing speed from ", MMM_TO_MMS(fr), " to ", MMM_TO_MMS(toolchange_settings.prime_speed), "mm/s");
fr = toolchange_settings.prime_speed;
unscaled_e_move(0, MMM_TO_MMS(fr)); // Init planner with 0 length move
}
#endif
//Calculate and perform the priming distance
if (toolchange_settings.extra_prime >= 0) {
// Positive extra_prime value
// - Return filament at speed (fr) then extra_prime at prime speed
FS_DEBUG("Loading Filament for T", active_extruder, " | Distance: ", toolchange_settings.swap_length, " | Speed: ", MMM_TO_MMS(fr), "mm/s");
unscaled_e_move(toolchange_settings.swap_length, MMM_TO_MMS(fr)); // Prime (Unretract) filament by extruding equal to Swap Length (Unretract)
if (toolchange_settings.extra_prime > 0) {
FS_DEBUG("Performing Extra Priming for T", active_extruder, " | Distance: ", toolchange_settings.extra_prime, " | Speed: ", MMM_TO_MMS(toolchange_settings.prime_speed), "mm/s");
unscaled_e_move(toolchange_settings.extra_prime, MMM_TO_MMS(toolchange_settings.prime_speed)); // Extra Prime Distance
}
}
else {
// Negative extra_prime value
// - Unretract distance (swap length) is reduced by the value of extra_prime
const float eswap = toolchange_settings.swap_length + toolchange_settings.extra_prime;
FS_DEBUG("Negative ExtraPrime value - Swap Return Length has been reduced from ", toolchange_settings.swap_length, " to ", eswap);
FS_DEBUG("Loading Filament for T", active_extruder, " | Distance: ", eswap, " | Speed: ", MMM_TO_MMS(fr), "mm/s");
unscaled_e_move(eswap, MMM_TO_MMS(fr));
}
extruder_was_primed.set(active_extruder); // Log that this extruder has been primed
// Cutting retraction
#if TOOLCHANGE_FS_WIPE_RETRACT
FS_DEBUG("Performing Cutting Retraction | Distance: ", -(TOOLCHANGE_FS_WIPE_RETRACT), " | Speed: ", MMM_TO_MMS(toolchange_settings.retract_speed), "mm/s");
unscaled_e_move(-(TOOLCHANGE_FS_WIPE_RETRACT), MMM_TO_MMS(toolchange_settings.retract_speed));
#endif
// Cool down with fan
filament_swap_cooling();
}
/**
* Sequence to Prime the currently selected extruder
* Raise Z, move the ToolChange_Park if enabled, prime the extruder, move back.
*/
void tool_change_prime() {
if (toolchange_settings.extra_prime > 0
&& TERN(PREVENT_COLD_EXTRUSION, !thermalManager.targetTooColdToExtrude(active_extruder), 1)
) {
FS_DEBUG(">>> tool_change_prime()");
if (!too_cold(active_extruder)) {
destination = current_position; // Remember the old position
const bool ok = TERN1(TOOLCHANGE_PARK, all_axes_homed() && toolchange_settings.enable_park);
@ -931,20 +1057,7 @@ void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_axis, 0.
}
#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 HAS_FAN && TOOLCHANGE_FS_FAN >= 0
thermalManager.fan_speed[TOOLCHANGE_FS_FAN] = toolchange_settings.fan_speed;
gcode.dwell(SEC_TO_MS(toolchange_settings.fan_time));
thermalManager.fan_speed[TOOLCHANGE_FS_FAN] = 0;
#endif
extruder_prime();
// Move back
#if ENABLED(TOOLCHANGE_PARK)
@ -958,13 +1071,11 @@ void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_axis, 0.
}
#endif
// Cutting recover
unscaled_e_move(toolchange_settings.extra_resume + TOOLCHANGE_FS_WIPE_RETRACT, MMM_TO_MMS(toolchange_settings.unretract_speed));
// Resume at the old E position
current_position.e = destination.e;
sync_plan_position_e();
extruder_cutting_recover(destination.e); // Cutting recover
}
FS_DEBUG("<<< tool_change_prime");
}
#endif // TOOLCHANGE_FILAMENT_SWAP
@ -1041,12 +1152,10 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
TEMPORARY_BED_LEVELING_STATE(false);
#endif
// First tool priming. To prime again, reboot the machine.
// First tool priming. To prime again, reboot the machine. -- Should only occur for first T0 after powerup!
#if ENABLED(TOOLCHANGE_FS_PRIME_FIRST_USED)
static bool first_tool_is_primed = false;
if (new_tool == old_tool && !first_tool_is_primed && enable_first_prime) {
if (enable_first_prime && old_tool == 0 && new_tool == 0 && !extruder_was_primed[0]) {
tool_change_prime();
first_tool_is_primed = true;
TERN_(TOOLCHANGE_FS_INIT_BEFORE_SWAP, toolchange_extruder_ready.set(old_tool)); // Primed and initialized
}
#endif
@ -1072,20 +1181,17 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
// 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))
);
const bool should_swap = can_move_away && toolchange_settings.swap_length;
if (should_swap) {
if (too_cold) {
SERIAL_ECHO_MSG(STR_ERR_HOTEND_TOO_COLD);
if (too_cold(old_tool)) {
// If SingleNozzle setup is too cold, unable to perform tool_change.
if (ENABLED(SINGLENOZZLE)) { active_extruder = new_tool; return; }
}
else {
// For first new tool, change without unloading the old. 'Just prime/init the new'
if (TERN1(TOOLCHANGE_FS_PRIME_FIRST_USED, first_tool_is_primed))
unscaled_e_move(-toolchange_settings.swap_length, MMM_TO_MMS(toolchange_settings.retract_speed));
TERN_(TOOLCHANGE_FS_PRIME_FIRST_USED, first_tool_is_primed = true); // The first new tool will be primed by toolchanging
else if (extruder_was_primed[old_tool]) {
// Retract the old extruder if it was previously primed
// To-Do: Should SingleNozzle always retract?
FS_DEBUG("Retracting Filament for T", old_tool, ". | Distance: ", toolchange_settings.swap_length, " | Speed: ", MMM_TO_MMS(toolchange_settings.retract_speed), "mm/s");
unscaled_e_move(-toolchange_settings.swap_length, MMM_TO_MMS(toolchange_settings.retract_speed));
}
}
#endif
@ -1190,36 +1296,8 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
#endif
#if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
if (should_swap && !too_cold) {
float fr = toolchange_settings.unretract_speed;
#if ENABLED(TOOLCHANGE_FS_INIT_BEFORE_SWAP)
if (!toolchange_extruder_ready[new_tool]) {
toolchange_extruder_ready.set(new_tool);
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 HAS_FAN && TOOLCHANGE_FS_FAN >= 0
thermalManager.fan_speed[TOOLCHANGE_FS_FAN] = toolchange_settings.fan_speed;
gcode.dwell(SEC_TO_MS(toolchange_settings.fan_time));
thermalManager.fan_speed[TOOLCHANGE_FS_FAN] = 0;
#endif
}
if (should_swap && !too_cold(active_extruder))
extruder_prime(); // Prime selected Extruder
#endif
// Prevent a move outside physical bounds
@ -1260,11 +1338,8 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
else 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
if (should_swap && !too_cold(active_extruder)) {
extruder_cutting_recover(0); // New extruder primed and set to 0
// Restart Fan
#if HAS_FAN && TOOLCHANGE_FS_FAN >= 0
@ -1322,7 +1397,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
#endif
}
SERIAL_ECHO_MSG(STR_ACTIVE_EXTRUDER, active_extruder);
SERIAL_ECHOLNPGM(STR_ACTIVE_EXTRUDER, active_extruder);
#endif // HAS_MULTI_EXTRUDER
}

View File

@ -29,24 +29,30 @@
typedef struct {
#if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
float swap_length, extra_prime, extra_resume;
int16_t prime_speed, retract_speed, unretract_speed, fan, fan_speed, fan_time;
float swap_length; // M217 S
float extra_prime; // M217 E
float extra_resume; // M217 B
int16_t prime_speed; // M217 P
int16_t retract_speed; // M217 R
int16_t unretract_speed; // M217 U
uint8_t fan_speed; // M217 F
uint8_t fan_time; // M217 D
#endif
#if ENABLED(TOOLCHANGE_PARK)
bool enable_park;
xy_pos_t change_point;
bool enable_park; // M217 W
xyz_pos_t change_point; // M217 X Y I J K
#endif
float z_raise;
float z_raise; // M217 Z
} toolchange_settings_t;
extern toolchange_settings_t toolchange_settings;
#if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
void tool_change_prime();
#if ENABLED(TOOLCHANGE_FS_PRIME_FIRST_USED)
extern bool enable_first_prime; // M217 V
#endif
#if ENABLED(TOOLCHANGE_FS_PRIME_FIRST_USED)
extern bool enable_first_prime;
#if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
void tool_change_prime(); // Prime the currently selected extruder
#endif
#if ENABLED(TOOLCHANGE_FS_INIT_BEFORE_SWAP)