diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index c88f4b639..7d5cf729a 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -122,6 +122,7 @@ * M119 - Report endstops status. * M120 - Enable endstops detection. * M121 - Disable endstops detection. + * M125 - Save current position and move to filament change position. (Requires PARK_HEAD_ON_PAUSE) * M126 - Solenoid Air Valve Open. (Requires BARICUDA) * M127 - Solenoid Air Valve Closed. (Requires BARICUDA) * M128 - EtoP Open. (Requires BARICUDA) @@ -150,7 +151,7 @@ * M208 - Set Recover (unretract) Additional (!) Length: S and Feedrate: F. (Requires FWRETRACT) * M209 - Turn Automatic Retract Detection on/off: S<0|1> (For slicers that don't support G10/11). (Requires FWRETRACT) Every normal extrude-only move will be classified as retract depending on the direction. - * M211 - Enable, Disable, and/or Report software endstops: S<0|1> + * M211 - Enable, Disable, and/or Report software endstops: S<0|1> (Requires MIN_SOFTWARE_ENDSTOPS or MAX_SOFTWARE_ENDSTOPS) * M218 - Set a tool offset: "M218 T X Y". (Requires 2 or more extruders) * M220 - Set Feedrate Percentage: "M220 S" (i.e., "FR" on the LCD) * M221 - Set Flow Percentage: "M221 S" @@ -199,13 +200,11 @@ * M350 - Set microstepping mode. (Requires digital microstepping pins.) * M351 - Toggle MS1 MS2 pins directly. (Requires digital microstepping pins.) * - * ************ SCARA Specific - This can change to suit future G-code regulations * M360 - SCARA calibration: Move to cal-position ThetaA (0 deg calibration) * M361 - SCARA calibration: Move to cal-position ThetaB (90 deg calibration - steps per degree) * M362 - SCARA calibration: Move to cal-position PsiA (0 deg calibration) * M363 - SCARA calibration: Move to cal-position PsiB (90 deg calibration - steps per degree) * M364 - SCARA calibration: Move to cal-position PSIC (90 deg to Theta calibration position) - * ************* SCARA End *************** * * ************ Custom codes - This can change to suit future G-code regulations * M100 - Watch Free Memory (For Debugging). (Requires M100_FREE_MEMORY_WATCHER) @@ -4667,6 +4666,45 @@ inline void gcode_M17() { enable_all_steppers(); } +#if IS_KINEMATIC + #define RUNPLAN(RATE_MM_S) planner.buffer_line_kinematic(destination, RATE_MM_S, active_extruder) +#else + #define RUNPLAN(RATE_MM_S) line_to_destination(RATE_MM_S) +#endif + +#if ENABLED(PARK_HEAD_ON_PAUSE) + float resume_position[XYZE]; + bool move_away_flag = false; + + inline void move_back_on_resume() { + if (!move_away_flag) return; + move_away_flag = false; + + // Set extruder to saved position + destination[E_AXIS] = current_position[E_AXIS] = resume_position[E_AXIS]; + planner.set_e_position_mm(current_position[E_AXIS]); + + #if IS_KINEMATIC + // Move XYZ to starting position + planner.buffer_line_kinematic(lastpos, FILAMENT_CHANGE_XY_FEEDRATE, active_extruder); + #else + // Move XY to starting position, then Z + destination[X_AXIS] = resume_position[X_AXIS]; + destination[Y_AXIS] = resume_position[Y_AXIS]; + RUNPLAN(FILAMENT_CHANGE_XY_FEEDRATE); + destination[Z_AXIS] = resume_position[Z_AXIS]; + RUNPLAN(FILAMENT_CHANGE_Z_FEEDRATE); + #endif + stepper.synchronize(); + + #if ENABLED(FILAMENT_RUNOUT_SENSOR) + filament_ran_out = false; + #endif + set_current_to_destination(); + } + +#endif // PARK_HEAD_ON_PAUSE + #if ENABLED(SDSUPPORT) /** @@ -4694,9 +4732,13 @@ inline void gcode_M17() { inline void gcode_M23() { card.openFile(current_command_args, true); } /** - * M24: Start SD Print + * M24: Start or Resume SD Print */ inline void gcode_M24() { + #if ENABLED(PARK_HEAD_ON_PAUSE) + move_back_on_resume(); + #endif + card.startFileprint(); print_job_timer.start(); } @@ -4704,7 +4746,14 @@ inline void gcode_M17() { /** * M25: Pause SD Print */ - inline void gcode_M25() { card.pauseSDPrint(); } + inline void gcode_M25() { + card.pauseSDPrint(); + print_job_timer.pause(); + + #if ENABLED(PARK_HEAD_ON_PAUSE) + enqueue_and_echo_commands_P(PSTR("M125")); // Must be enqueued with pauseSDPrint set to be last in the buffer + #endif + } /** * M26: Set SD Card file index @@ -6084,6 +6133,111 @@ inline void gcode_M120() { endstops.enable_globally(true); } */ inline void gcode_M121() { endstops.enable_globally(false); } +#if ENABLED(PARK_HEAD_ON_PAUSE) + + /** + * M125: Store current position and move to filament change position. + * Called on pause (by M25) to prevent material leaking onto the + * object. On resume (M24) the head will be moved back and the + * print will resume. + * + * If Marlin is compiled without SD Card support, M125 can be + * used directly to pause the print and move to park position, + * resuming with a button click or M108. + * + * L = override retract length + * X = override X + * Y = override Y + * Z = override Z raise + */ + inline void gcode_M125() { + if (move_away_flag) return; // already paused + + const bool job_running = print_job_timer.isRunning(); + + // there are blocks after this one, or sd printing + move_away_flag = job_running || planner.blocks_queued() + #if ENABLED(SDSUPPORT) + || card.sdprinting + #endif + ; + + if (!move_away_flag) return; // nothing to pause + + // M125 can be used to pause a print too + #if ENABLED(SDSUPPORT) + card.pauseSDPrint(); + #endif + print_job_timer.pause(); + + // Save current position + COPY(resume_position, current_position); + + set_destination_to_current(); + + // Initial retract before move to filament change position + destination[E_AXIS] += code_seen('L') ? code_value_axis_units(E_AXIS) : 0 + #if defined(FILAMENT_CHANGE_RETRACT_LENGTH) && FILAMENT_CHANGE_RETRACT_LENGTH > 0 + - (FILAMENT_CHANGE_RETRACT_LENGTH) + #endif + ; + RUNPLAN(FILAMENT_CHANGE_RETRACT_FEEDRATE); + + // Lift Z axis + const float z_lift = code_seen('Z') ? code_value_axis_units(Z_AXIS) : + #if defined(FILAMENT_CHANGE_Z_ADD) && FILAMENT_CHANGE_Z_ADD > 0 + FILAMENT_CHANGE_Z_ADD + #else + 0 + #endif + ; + if (z_lift > 0) { + destination[Z_AXIS] += z_lift; + NOMORE(destination[Z_AXIS], Z_MAX_POS); + RUNPLAN(FILAMENT_CHANGE_Z_FEEDRATE); + } + + // Move XY axes to filament change position or given position + destination[X_AXIS] = code_seen('X') ? code_value_axis_units(X_AXIS) : 0 + #ifdef FILAMENT_CHANGE_X_POS + + FILAMENT_CHANGE_X_POS + #endif + ; + destination[Y_AXIS] = code_seen('Y') ? code_value_axis_units(Y_AXIS) : 0 + #ifdef FILAMENT_CHANGE_Y_POS + + FILAMENT_CHANGE_Y_POS + #endif + ; + + #if HOTENDS > 1 && DISABLED(DUAL_X_CARRIAGE) + if (active_extruder > 0) { + if (!code_seen('X')) destination[X_AXIS] += hotend_offset[X_AXIS][active_extruder]; + if (!code_seen('Y')) destination[Y_AXIS] += hotend_offset[Y_AXIS][active_extruder]; + } + #endif + + clamp_to_software_endstops(destination); + RUNPLAN(FILAMENT_CHANGE_XY_FEEDRATE); + set_current_to_destination(); + stepper.synchronize(); + disable_e_steppers(); + + #if DISABLED(SDSUPPORT) + // Wait for lcd click or M108 + wait_for_user = true; + KEEPALIVE_STATE(PAUSED_FOR_USER); + while (wait_for_user) idle(); + KEEPALIVE_STATE(IN_HANDLER); + + // Return to print position and continue + move_back_on_resume(); + if (job_running) print_job_timer.start(); + move_away_flag = false; + #endif + } + +#endif // PARK_HEAD_ON_PAUSE + #if ENABLED(BLINKM) || ENABLED(RGB_LED) void set_led_color(const uint8_t r, const uint8_t g, const uint8_t b) { @@ -7253,25 +7407,18 @@ inline void gcode_M503() { busy_doing_M600 = true; // Stepper Motors can't timeout when this is set // Pause the print job timer - bool job_running = print_job_timer.isRunning(); + const bool job_running = print_job_timer.isRunning(); + print_job_timer.pause(); // Show initial message and wait for synchronize steppers lcd_filament_change_show_message(FILAMENT_CHANGE_MESSAGE_INIT); stepper.synchronize(); - float lastpos[NUM_AXIS]; - // Save current position of all axes - LOOP_XYZE(i) - lastpos[i] = destination[i] = current_position[i]; - - // Define runplan for move axes - #if IS_KINEMATIC - #define RUNPLAN(RATE_MM_S) planner.buffer_line_kinematic(destination, RATE_MM_S, active_extruder); - #else - #define RUNPLAN(RATE_MM_S) line_to_destination(RATE_MM_S); - #endif + float lastpos[XYZE]; + COPY(lastpos, current_position); + set_destination_to_current(); // Initial retract before move to filament change position destination[E_AXIS] += code_seen('E') ? code_value_axis_units(E_AXIS) : 0 @@ -8555,6 +8702,11 @@ void process_next_command() { break; #endif // FAN_COUNT > 0 + #if ENABLED(PARK_HEAD_ON_PAUSE) + case 125: // M125: Store current position and move to filament change position + gcode_M125(); break; + #endif + #if ENABLED(BARICUDA) // PWM for HEATER_1_PIN #if HAS_HEATER_1 diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 4ce684ddf..7b04d2805 100755 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -615,11 +615,18 @@ void kill_screen(const char* lcd_msg) { void lcd_sdcard_pause() { card.pauseSDPrint(); print_job_timer.pause(); + #if ENABLED(PARK_HEAD_ON_PAUSE) + enqueue_and_echo_commands_P(PSTR("M125")) + #endif } void lcd_sdcard_resume() { - card.startFileprint(); - print_job_timer.start(); + #if ENABLED(PARK_HEAD_ON_PAUSE) + enqueue_and_echo_commands_P(PSTR("M24")) + #else + card.startFileprint(); + print_job_timer.start(); + #endif } void lcd_sdcard_stop() { @@ -634,7 +641,7 @@ void kill_screen(const char* lcd_msg) { lcd_setstatus(MSG_PRINT_ABORTED, true); } - #endif //SDSUPPORT + #endif // SDSUPPORT #if ENABLED(MENU_ITEM_CASE_LIGHT)