/** * Marlin 3D Printer Firmware * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] * * Based on Sprinter and grbl. * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "../../inc/MarlinConfig.h" #include "../gcode.h" #include "../../module/stepper.h" #include "../../module/endstops.h" #if HOTENDS > 1 #include "../../module/tool_change.h" #endif #if HAS_LEVELING #include "../../feature/bedlevel/bedlevel.h" #endif #include "../../lcd/ultralcd.h" #if ENABLED(QUICK_HOME) static void quick_home_xy() { // Pretend the current position is 0,0 current_position[X_AXIS] = current_position[Y_AXIS] = 0.0; sync_plan_position(); const int x_axis_home_dir = #if ENABLED(DUAL_X_CARRIAGE) x_home_dir(active_extruder) #else home_dir(X_AXIS) #endif ; const float mlx = max_length(X_AXIS), mly = max_length(Y_AXIS), mlratio = mlx > mly ? mly / mlx : mlx / mly, fr_mm_s = min(homing_feedrate(X_AXIS), homing_feedrate(Y_AXIS)) * SQRT(sq(mlratio) + 1.0); do_blocking_move_to_xy(1.5 * mlx * x_axis_home_dir, 1.5 * mly * home_dir(Y_AXIS), fr_mm_s); endstops.hit_on_purpose(); // clear endstop hit flags current_position[X_AXIS] = current_position[Y_AXIS] = 0.0; } #endif // QUICK_HOME #if ENABLED(Z_SAFE_HOMING) inline void home_z_safely() { // Disallow Z homing if X or Y are unknown if (!axis_known_position[X_AXIS] || !axis_known_position[Y_AXIS]) { LCD_MESSAGEPGM(MSG_ERR_Z_HOMING); SERIAL_ECHO_START(); SERIAL_ECHOLNPGM(MSG_ERR_Z_HOMING); return; } #if ENABLED(DEBUG_LEVELING_FEATURE) if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("Z_SAFE_HOMING >>>"); #endif SYNC_PLAN_POSITION_KINEMATIC(); /** * Move the Z probe (or just the nozzle) to the safe homing point */ destination[X_AXIS] = Z_SAFE_HOMING_X_POINT; destination[Y_AXIS] = Z_SAFE_HOMING_Y_POINT; destination[Z_AXIS] = current_position[Z_AXIS]; // Z is already at the right height #if HOMING_Z_WITH_PROBE destination[X_AXIS] -= X_PROBE_OFFSET_FROM_EXTRUDER; destination[Y_AXIS] -= Y_PROBE_OFFSET_FROM_EXTRUDER; #endif if (position_is_reachable(destination[X_AXIS], destination[Y_AXIS])) { #if ENABLED(DEBUG_LEVELING_FEATURE) if (DEBUGGING(LEVELING)) DEBUG_POS("Z_SAFE_HOMING", destination); #endif // This causes the carriage on Dual X to unpark #if ENABLED(DUAL_X_CARRIAGE) active_extruder_parked = false; #endif do_blocking_move_to_xy(destination[X_AXIS], destination[Y_AXIS]); HOMEAXIS(Z); } else { LCD_MESSAGEPGM(MSG_ZPROBE_OUT); SERIAL_ECHO_START(); SERIAL_ECHOLNPGM(MSG_ZPROBE_OUT); } #if ENABLED(DEBUG_LEVELING_FEATURE) if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< Z_SAFE_HOMING"); #endif } #endif // Z_SAFE_HOMING /** * G28: Home all axes according to settings * * Parameters * * None Home to all axes with no parameters. * With QUICK_HOME enabled XY will home together, then Z. * * Cartesian parameters * * X Home to the X endstop * Y Home to the Y endstop * Z Home to the Z endstop * */ void GcodeSuite::G28(const bool always_home_all) { #if ENABLED(DEBUG_LEVELING_FEATURE) if (DEBUGGING(LEVELING)) { SERIAL_ECHOLNPGM(">>> G28"); log_machine_info(); } #endif // Wait for planner moves to finish! stepper.synchronize(); // Cancel the active G29 session #if ENABLED(PROBE_MANUALLY) g29_in_progress = false; #endif // Disable the leveling matrix before homing #if HAS_LEVELING #if ENABLED(AUTO_BED_LEVELING_UBL) const bool ubl_state_at_entry = planner.leveling_active; #endif set_bed_leveling_enabled(false); #endif #if ENABLED(CNC_WORKSPACE_PLANES) workspace_plane = PLANE_XY; #endif // Always home with tool 0 active #if HOTENDS > 1 const uint8_t old_tool_index = active_extruder; tool_change(0, 0, true); #endif #if ENABLED(DUAL_X_CARRIAGE) || ENABLED(DUAL_NOZZLE_DUPLICATION_MODE) extruder_duplication_enabled = false; #endif setup_for_endstop_or_probe_move(); #if ENABLED(DEBUG_LEVELING_FEATURE) if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("> endstops.enable(true)"); #endif endstops.enable(true); // Enable endstops for next homing move #if ENABLED(DELTA) home_delta(); UNUSED(always_home_all); #else // NOT DELTA const bool homeX = always_home_all || parser.seen('X'), homeY = always_home_all || parser.seen('Y'), homeZ = always_home_all || parser.seen('Z'), home_all = (!homeX && !homeY && !homeZ) || (homeX && homeY && homeZ); set_destination_from_current(); #if Z_HOME_DIR > 0 // If homing away from BED do Z first if (home_all || homeZ) { HOMEAXIS(Z); #if ENABLED(DEBUG_LEVELING_FEATURE) if (DEBUGGING(LEVELING)) DEBUG_POS("> HOMEAXIS(Z)", current_position); #endif } #else if (home_all || homeX || homeY) { // Raise Z before homing any other axes and z is not already high enough (never lower z) destination[Z_AXIS] = Z_HOMING_HEIGHT; if (destination[Z_AXIS] > current_position[Z_AXIS]) { #if ENABLED(DEBUG_LEVELING_FEATURE) if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPAIR("Raise Z (before homing) to ", destination[Z_AXIS]); #endif do_blocking_move_to_z(destination[Z_AXIS]); } } #endif #if ENABLED(QUICK_HOME) if (home_all || (homeX && homeY)) quick_home_xy(); #endif #if ENABLED(HOME_Y_BEFORE_X) // Home Y if (home_all || homeY) { HOMEAXIS(Y); #if ENABLED(DEBUG_LEVELING_FEATURE) if (DEBUGGING(LEVELING)) DEBUG_POS("> homeY", current_position); #endif } #endif // Home X if (home_all || homeX) { #if ENABLED(DUAL_X_CARRIAGE) // Always home the 2nd (right) extruder first active_extruder = 1; HOMEAXIS(X); // Remember this extruder's position for later tool change inactive_extruder_x_pos = current_position[X_AXIS]; // Home the 1st (left) extruder active_extruder = 0; HOMEAXIS(X); // Consider the active extruder to be parked COPY(raised_parked_position, current_position); delayed_move_time = 0; active_extruder_parked = true; #else HOMEAXIS(X); #endif #if ENABLED(DEBUG_LEVELING_FEATURE) if (DEBUGGING(LEVELING)) DEBUG_POS("> homeX", current_position); #endif } #if DISABLED(HOME_Y_BEFORE_X) // Home Y if (home_all || homeY) { HOMEAXIS(Y); #if ENABLED(DEBUG_LEVELING_FEATURE) if (DEBUGGING(LEVELING)) DEBUG_POS("> homeY", current_position); #endif } #endif // Home Z last if homing towards the bed #if Z_HOME_DIR < 0 if (home_all || homeZ) { #if ENABLED(Z_SAFE_HOMING) home_z_safely(); #else HOMEAXIS(Z); #endif #if ENABLED(DEBUG_LEVELING_FEATURE) if (DEBUGGING(LEVELING)) DEBUG_POS("> (home_all || homeZ) > final", current_position); #endif } // home_all || homeZ #endif // Z_HOME_DIR < 0 SYNC_PLAN_POSITION_KINEMATIC(); #endif // !DELTA (G28) endstops.not_homing(); #if ENABLED(DELTA) && ENABLED(DELTA_HOME_TO_SAFE_ZONE) // move to a height where we can use the full xy-area do_blocking_move_to_z(delta_clip_start_height); #endif #if ENABLED(AUTO_BED_LEVELING_UBL) set_bed_leveling_enabled(ubl_state_at_entry); #endif clean_up_after_endstop_or_probe_move(); // Restore the active tool after homing #if HOTENDS > 1 #if ENABLED(PARKING_EXTRUDER) #define NO_FETCH false // fetch the previous toolhead #else #define NO_FETCH true #endif tool_change(old_tool_index, 0, NO_FETCH); #endif lcd_refresh(); report_current_position(); #if ENABLED(DEBUG_LEVELING_FEATURE) if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< G28"); #endif }