diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h
index f1f65942284c..0dbbc60d6aa5 100644
--- a/Marlin/Configuration_adv.h
+++ b/Marlin/Configuration_adv.h
@@ -4436,6 +4436,34 @@
#define FREEZE_STATE LOW // State of pin indicating freeze
#endif
+/**
+ * Adds canned drilling cycle G Codes:
+ * G73: Shallow peck drill cycle
+ * G80: End drill cycle
+ * G81: Basic drill cycle
+ * G82: Normal drill cycle (Basic with dwell)
+ * G83: Deep drill cycle (Normal with peck)
+ * G98: Start drill - retract to initial
+ * G99: Start drill - retract to specified
+ * or when DRILL_USE_81_ONLY is specified:
+ * G81.4: Shallow peck drill cycle
+ * G81.0: End drill cycle
+ * G81.1: Basic drill cycle
+ * G81.2: Normal drill cycle (Basic with dwell)
+ * G81.3: Deep drill cycle (Normal with peck)
+ * G81.18: Start drill - retract to initial
+ * G81.19: Start drill - retract to specified
+ */
+//#define DRILL_CYCLES
+#if ENABLED(DRILL_CYCLES)
+ //#define DRILL_USE_81_ONLY //Uses G81.x sub commands
+ #define DRILL_CYCLES_XY_FEEDRATE 1600 //Feedrate for xy operations
+ #define DRILL_CYCLES_RETRACT_FEEDRATE 1200 //Feedrate while retracting
+ #define DRILL_CYCLES_DEFAULT_FEEDRATE 300 //Default drilling freedrate if one is not specified
+ #define DRILL_CYCLES_DEFAULT_PECK 2.0 //Default pecking distance if one is not specified
+ #define DRILL_CYCLES_DEFAULT_DWELL 0 //Default dwell distance if one is not specified
+#endif
+
/**
* MAX7219 Debug Matrix
*
diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp
index 10a6f3d65b72..6043ed062fbb 100644
--- a/Marlin/src/gcode/gcode.cpp
+++ b/Marlin/src/gcode/gcode.cpp
@@ -463,6 +463,20 @@ void GcodeSuite::process_parsed_command(bool no_ok/*=false*/) {
case 80: G80(); break; // G80: Reset the current motion mode
#endif
+ #if ENABLED(DRILL_CYCLES)
+ #if ENABLED(DRILL_USE_81_ONLY) || ENABLED(GCODE_MOTION_MODES)
+ case 81: G81(parser.subcode); break; // G81: Drill cycle G81: End, G81.18 G81.19 Start, G81.1 G81.2 G81.3 G81.4 Cycles
+ #else
+ case 73: G81(4); break; // G73: Shallow peck drill cycle
+ case 80: G81(0); break; // G80: End drill cycle
+ case 81: G81(1); break; // G81: Basic drill cycle
+ case 82: G81(2); break; // G82: Normal drill cycle (Basic with dwell)
+ case 83: G81(3); break; // G83: Deep drill cycle (Normal with peck)
+ case 98: G81(18); break; // G98: Retract to initial
+ case 99: G81(19); break; // G99: Retract to specified
+ #endif
+ #endif
+
case 90: G90(); break; // G90: Absolute Mode
case 91: G91(); break; // G91: Relative Mode
diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h
index 378a1a73f47f..5d4f377718a8 100644
--- a/Marlin/src/gcode/gcode.h
+++ b/Marlin/src/gcode/gcode.h
@@ -66,11 +66,18 @@
* G42 - Coordinated move to a mesh point (Requires MESH_BED_LEVELING, AUTO_BED_LEVELING_BLINEAR, or AUTO_BED_LEVELING_UBL)
* G60 - Save current position. (Requires SAVED_POSITIONS)
* G61 - Apply/Restore saved coordinates. (Requires SAVED_POSITIONS)
+ * G73 - Shallow peck drill cycle
* G76 - Calibrate first layer temperature offsets. (Requires PTC_PROBE and PTC_BED)
* G80 - Cancel current motion mode (Requires GCODE_MOTION_MODES)
+ * G80 - Cancel drill cancel
+ * G81 - Basic drill cycle
+ * G82 - Normal drill cycle
+ * G83 - Deep drill cycle
* G90 - Use Absolute Coordinates
* G91 - Use Relative Coordinates
* G92 - Set current position to coordinates given
+ * G98 - Start drill - retract to initial
+ * G99 - Start drill - retract to specified
*
* "M" Codes
*
@@ -644,6 +651,10 @@ class GcodeSuite {
static void G80();
#endif
+ #if ENABLED(DRILL_CYCLES)
+ static void G81(uint8_t mode);
+ #endif
+
static void G90() { set_relative_mode(false); }
static void G91() { set_relative_mode(true); }
diff --git a/Marlin/src/gcode/host/M115.cpp b/Marlin/src/gcode/host/M115.cpp
index 19d0ae9b63e6..462542d65dc3 100644
--- a/Marlin/src/gcode/host/M115.cpp
+++ b/Marlin/src/gcode/host/M115.cpp
@@ -226,6 +226,9 @@ void GcodeSuite::M115() {
// MOTION_MODES (M80-M89)
cap_line(F("MOTION_MODES"), ENABLED(GCODE_MOTION_MODES));
+ // DRILL CYCLES (G73-99)
+ cap_line(F("DRILL_CYCLES"), ENABLED(DRILL_CYCLES));
+
// ARC_SUPPORT (G2-G3)
cap_line(F("ARCS"), ENABLED(ARC_SUPPORT));
diff --git a/Marlin/src/gcode/motion/G81.cpp b/Marlin/src/gcode/motion/G81.cpp
new file mode 100644
index 000000000000..2c2e4ff67f50
--- /dev/null
+++ b/Marlin/src/gcode/motion/G81.cpp
@@ -0,0 +1,186 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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"
+
+#if ENABLED(DRILL_CYCLES)
+
+#include "../gcode.h"
+#include "../../module/motion.h"
+#include "../../module/planner.h"
+
+/**
+ * G73: Shallow peck drill cycle
+ * G80: End drill cycle
+ * G81: Basic drill cycle
+ * G82: Normal drill cycle (Basic with dwell)
+ * G83: Deep drill cycle (Normal with peck)
+ * G98: Start drill - retract to initial
+ * G99: Start drill - retract to specified
+ */
+
+bool retract_to_initial = true;
+feedRate_t drill_feedrate = NAN;
+float drill_rapid_z = NAN;
+float drill_finish_depth = NAN;
+
+bool move_to(xyze_pos_t position, float z, feedRate_t f) {
+ if(planner.cleaning_buffer_counter) return false;
+
+ LOOP_NUM_AXES(i) {
+ destination[i] = position[i];
+ }
+
+ destination[Z_AXIS] = z;
+ feedrate_mm_s = f;
+
+ prepare_line_to_destination();
+
+ return true;
+ }
+
+void drill_cycle(uint8_t mode) {
+ //get input values and build positional variables
+ bool allow_peck = mode == 83 || mode == 73;
+ bool allow_dwell = mode == 82 || mode == 83 || mode == 73;
+
+ //drill depth, must not be NAN
+ if(parser.seenval(AXIS_CHAR(Z_AXIS))) {
+ const float v = parser.value_axis_units(Z_AXIS);
+ drill_finish_depth = gcode.axis_is_relative(AxisEnum(Z_AXIS)) ? current_position[Z_AXIS] + v : LOGICAL_TO_NATIVE(v, Z_AXIS);
+ }
+ if(drill_finish_depth == NAN) return;
+
+ //get position of all axes
+ xyze_pos_t drill_position;
+ LOOP_NUM_AXES(i) {
+ if(i == Z_AXIS) {
+ drill_position[i] = current_position.z;
+ } else if (parser.seenval(AXIS_CHAR(i))) {
+ const float v = parser.value_axis_units((AxisEnum)i);
+ drill_position[i] = gcode.axis_is_relative(AxisEnum(i)) ? current_position[i] + v : LOGICAL_TO_NATIVE(v, i);
+ } else {
+ drill_position[i] = current_position[i];
+ }
+ }
+
+ //rapid, retract planes
+ if(parser.seenval('R')) drill_rapid_z = LOGICAL_TO_NATIVE(parser.value_axis_units(Z_AXIS), Z_AXIS);
+ else if(drill_rapid_z == NAN) drill_rapid_z = drill_position[Z_AXIS];
+ float drill_retract_z = retract_to_initial ? drill_position[Z_AXIS] : drill_rapid_z;
+
+ //feedrate
+ if(parser.seenval('F')) drill_feedrate = parser.value_feedrate();
+ else if(drill_feedrate == NAN) drill_feedrate = MMM_TO_MMS(DRILL_CYCLES_DEFAULT_FEEDRATE);
+
+ //peck
+ float drill_peck_distance = parser.axis_value_to_mm(Z_AXIS, 1000.0f);
+ if(allow_peck) {
+ drill_peck_distance = parser.seenval('Q') ? parser.value_axis_units(Z_AXIS) : parser.axis_value_to_mm(Z_AXIS, DRILL_CYCLES_DEFAULT_PECK);
+ }
+
+ //dwell
+ int16_t drill_dwell_time = 0;
+ if(allow_dwell) {
+ drill_dwell_time = parser.seenval('P') ? parser.value_int() : DRILL_CYCLES_DEFAULT_DWELL;
+ }
+
+ //move to initial xy position
+ if(!move_to(drill_position,
+ drill_position[Z_AXIS],
+ DRILL_CYCLES_XY_FEEDRATE)) return;
+
+ //move to rapid z position
+ if(!move_to(drill_position,
+ drill_rapid_z,
+ DRILL_CYCLES_RETRACT_FEEDRATE)) return;
+
+ //start drill cycle
+ float drill_current_depth = drill_rapid_z;
+ float drill_last_z = drill_current_depth;
+ while(drill_current_depth > drill_finish_depth) {
+ //calculate new drill depth
+ drill_current_depth -= drill_peck_distance;
+ if(drill_current_depth < drill_finish_depth) drill_current_depth = drill_finish_depth;
+
+ //drill into material
+ if(!move_to(drill_position,
+ drill_current_depth,
+ drill_feedrate)) return;
+
+ //do dwell
+ if(drill_dwell_time > 0) {
+ if(planner.cleaning_buffer_counter) return;
+ planner.synchronize();
+ gcode.dwell(drill_dwell_time);
+ }
+
+ //move to rapid z position
+ if(!move_to(drill_position,
+ mode == 73 ? drill_last_z : drill_rapid_z,
+ DRILL_CYCLES_RETRACT_FEEDRATE)) return;
+
+ //store current depth
+ drill_last_z = drill_current_depth;
+ }
+
+ //retract to final z
+ if(!move_to(drill_position,
+ drill_retract_z,
+ DRILL_CYCLES_RETRACT_FEEDRATE)) return;
+}
+
+void GcodeSuite::G81(uint8_t mode) {
+ switch(mode) {
+ case 0: //End cycle and clear variables
+ drill_feedrate = NAN;
+ drill_rapid_z = NAN;
+ drill_finish_depth = NAN;
+ break;
+
+ case 1: //Start basic cycle
+ drill_cycle(81);
+ break;
+
+ case 2: //Start normal cycle
+ drill_cycle(82);
+ break;
+
+ case 3: //Start deep cycle
+ drill_cycle(83);
+ break;
+
+ case 4: //Start peck cycle
+ drill_cycle(73);
+ break;
+
+ case 18: //Set retract type
+ retract_to_initial = true;
+ break;
+
+ case 19: //Set retract type
+ retract_to_initial = false;
+ break;
+ }
+}
+
+#endif // DRILL_CYCLES
diff --git a/ini/features.ini b/ini/features.ini
index 03a9bdbba8d1..4dda225f8a47 100644
--- a/ini/features.ini
+++ b/ini/features.ini
@@ -349,6 +349,7 @@ HAS_MULTI_LANGUAGE = build_src_filter=+
ARC_SUPPORT = build_src_filter=+
GCODE_MOTION_MODES = build_src_filter=+
+DRILL_CYCLES = build_src_filter=+
BABYSTEPPING = build_src_filter=+ +
OTA_FIRMWARE_UPDATE = build_src_filter=+
Z_PROBE_SLED = build_src_filter=+