diff --git a/Marlin/src/feature/solenoid.cpp b/Marlin/src/feature/solenoid.cpp index 8646ec872..659b64226 100644 --- a/Marlin/src/feature/solenoid.cpp +++ b/Marlin/src/feature/solenoid.cpp @@ -28,22 +28,29 @@ #include "../module/motion.h" // for active_extruder -#if ENABLED(MANUAL_SOLENOID_CONTROL) - #define HAS_SOLENOID(N) HAS_SOLENOID_##N +// PARKING_EXTRUDER options alter the default behavior of solenoids, this ensures compliance of M380-381 + +#if ENABLED(PARKING_EXTRUDER) + #include "../module/tool_change.h" + #define SOLENOID_MAGNETIZED_STATE (TERN_(PARKING_EXTRUDER_SOLENOIDS_INVERT,!)PARKING_EXTRUDER_SOLENOIDS_PINS_ACTIVE) #else - #define HAS_SOLENOID(N) (HAS_SOLENOID_##N && EXTRUDERS > N) + #define SOLENOID_MAGNETIZED_STATE HIGH #endif +#define HAS_SOLENOID(N) (HAS_SOLENOID_##N && TERN(MANUAL_SOLENOID_CONTROL, true, EXTRUDERS > N)) + // Used primarily with MANUAL_SOLENOID_CONTROL static void set_solenoid(const uint8_t num, const bool active) { - const uint8_t value = active ? HIGH : LOW; + const uint8_t value = active ? SOLENOID_MAGNETIZED_STATE : !SOLENOID_MAGNETIZED_STATE; switch (num) { case 0: OUT_WRITE(SOL0_PIN, value); + TERN_(PARKING_EXTRUDER, if (!active && active_extruder == 0) parking_extruder_set_parked()); // If active extruder's solenoid is disabled, carriage is considered parked break; #if HAS_SOLENOID(1) case 1: OUT_WRITE(SOL1_PIN, value); + TERN_(PARKING_EXTRUDER, if (!active && active_extruder == 1) parking_extruder_set_parked()); // If active extruder's solenoid is disabled, carriage is considered parked break; #endif #if HAS_SOLENOID(2) diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp index e63f60994..7c13587a6 100644 --- a/Marlin/src/gcode/calibrate/G28.cpp +++ b/Marlin/src/gcode/calibrate/G28.cpp @@ -290,6 +290,10 @@ void GcodeSuite::G28() { #if DISABLED(DELTA) || ENABLED(DELTA_HOME_TO_SAFE_ZONE) const uint8_t old_tool_index = active_extruder; #endif + // PARKING_EXTRUDER homing requires different handling of movement / solenoid activation, depending on the side of homing + #if ENABLED(PARKING_EXTRUDER) + const bool pe_final_change_must_unpark = parking_extruder_unpark_after_homing(old_tool_index, X_HOME_DIR + 1 == old_tool_index * 2); + #endif tool_change(0, true); #endif @@ -443,7 +447,7 @@ void GcodeSuite::G28() { // Restore the active tool after homing #if HAS_MULTI_HOTEND && (DISABLED(DELTA) || ENABLED(DELTA_HOME_TO_SAFE_ZONE)) - tool_change(old_tool_index, NONE(PARKING_EXTRUDER, DUAL_X_CARRIAGE)); // Do move if one of these + tool_change(old_tool_index, TERN(PARKING_EXTRUDER, !pe_final_change_must_unpark, DISABLED(DUAL_X_CARRIAGE))); // Do move if one of these #endif #if HAS_HOMING_CURRENT diff --git a/Marlin/src/gcode/control/T.cpp b/Marlin/src/gcode/control/T.cpp index 592b2b3dc..3ce284f82 100644 --- a/Marlin/src/gcode/control/T.cpp +++ b/Marlin/src/gcode/control/T.cpp @@ -61,16 +61,10 @@ void GcodeSuite::T(const int8_t tool_index) { } #endif - #if EXTRUDERS < 2 - - tool_change(tool_index); - - #else - - tool_change( - tool_index, - (tool_index == active_extruder) || parser.boolval('S') - ); - - #endif + tool_change(tool_index + #if HAS_MULTI_EXTRUDER + , TERN(PARKING_EXTRUDER, false, tool_index == active_extruder) // For PARKING_EXTRUDER motion is decided in tool_change() + || parser.boolval('S') + #endif + ); } diff --git a/Marlin/src/module/tool_change.cpp b/Marlin/src/module/tool_change.cpp index a98193191..a31044212 100644 --- a/Marlin/src/module/tool_change.cpp +++ b/Marlin/src/module/tool_change.cpp @@ -277,6 +277,28 @@ inline void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_a #endif } + bool extruder_parked = true, do_solenoid_activation = true; + + // Modifies tool_change() behavior based on homing side + bool parking_extruder_unpark_after_homing(const uint8_t final_tool, bool homed_towards_final_tool) { + do_solenoid_activation = false; // Tell parking_extruder_tool_change to skip solenoid activation + + if (!extruder_parked) return false; // nothing to do + + if (homed_towards_final_tool) { + pe_deactivate_solenoid(1 - final_tool); + DEBUG_ECHOLNPAIR("Disengage magnet", (int)(1 - final_tool)); + pe_activate_solenoid(final_tool); + DEBUG_ECHOLNPAIR("Engage magnet", (int)final_tool); + extruder_parked = false; + return false; + } + + return true; + } + + void parking_extruder_set_parked() { extruder_parked = true; } + inline void parking_extruder_tool_change(const uint8_t new_tool, bool no_move) { if (!no_move) { @@ -304,27 +326,30 @@ inline void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_a DEBUG_POS("Start PE Tool-Change", current_position); - current_position.x = parkingposx[active_extruder] + x_offset; + // Don't park the active_extruder unless unparked + if (!extruder_parked) { + current_position.x = parkingposx[active_extruder] + x_offset; - DEBUG_ECHOLNPAIR("(1) Park extruder ", int(active_extruder)); - DEBUG_POS("Moving ParkPos", current_position); + DEBUG_ECHOLNPAIR("(1) Park extruder ", int(active_extruder)); + DEBUG_POS("Moving ParkPos", current_position); - fast_line_to_current(X_AXIS); + fast_line_to_current(X_AXIS); - // STEP 2 + // STEP 2 - planner.synchronize(); - DEBUG_ECHOLNPGM("(2) Disengage magnet"); - pe_deactivate_solenoid(active_extruder); + planner.synchronize(); + DEBUG_ECHOLNPGM("(2) Disengage magnet"); + pe_deactivate_solenoid(active_extruder); - // STEP 3 + // STEP 3 - current_position.x += active_extruder ? -10 : 10; // move 10mm away from parked extruder + current_position.x += active_extruder ? -10 : 10; // move 10mm away from parked extruder - DEBUG_ECHOLNPGM("(3) Move near new extruder"); - DEBUG_POS("Move away from parked extruder", current_position); + DEBUG_ECHOLNPGM("(3) Move near new extruder"); + DEBUG_POS("Move away from parked extruder", current_position); - fast_line_to_current(X_AXIS); + fast_line_to_current(X_AXIS); + } // STEP 4 @@ -358,13 +383,16 @@ inline void fast_line_to_current(const AxisEnum fr_axis) { _line_to_current(fr_a planner.synchronize(); // Always sync the final move DEBUG_POS("PE Tool-Change done.", current_position); + extruder_parked = false; } - else { // nomove == true + else if (do_solenoid_activation) { // && nomove == true + // Deactivate old extruder solenoid + TERN(PARKING_EXTRUDER_SOLENOIDS_INVERT, pe_activate_solenoid, pe_deactivate_solenoid)(active_extruder); // Only engage magnetic field for new extruder - pe_activate_solenoid(new_tool); - // Just save power for inverted magnets - TERN_(PARKING_EXTRUDER_SOLENOIDS_INVERT, pe_activate_solenoid(active_extruder)); + TERN(PARKING_EXTRUDER_SOLENOIDS_INVERT, pe_deactivate_solenoid, pe_activate_solenoid)(new_tool); } + + do_solenoid_activation = true; // Activate solenoid for subsequent tool_change() } #endif // PARKING_EXTRUDER @@ -922,7 +950,7 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) { } #endif - if (new_tool != old_tool) { + if (new_tool != old_tool || TERN0(PARKING_EXTRUDER, extruder_parked)) { // PARKING_EXTRUDER may need to attach old_tool when homing destination = current_position; #if BOTH(TOOLCHANGE_FILAMENT_SWAP, HAS_FAN) && TOOLCHANGE_FS_FAN >= 0 diff --git a/Marlin/src/module/tool_change.h b/Marlin/src/module/tool_change.h index 0b22f8b6f..fc953ddf8 100644 --- a/Marlin/src/module/tool_change.h +++ b/Marlin/src/module/tool_change.h @@ -93,6 +93,9 @@ void pe_solenoid_init(); + bool parking_extruder_unpark_after_homing(const uint8_t final_tool, bool homed_towards_final_tool); + void parking_extruder_set_parked(); + #elif ENABLED(MAGNETIC_PARKING_EXTRUDER) typedef struct MPESettings {