diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h
index 12d1ee706490..5abb4fd729df 100644
--- a/Marlin/Configuration.h
+++ b/Marlin/Configuration.h
@@ -2936,9 +2936,9 @@
* Set this manually if there are extra servos needing manual control.
* Set to 0 to turn off servo support.
*/
-//#define NUM_SERVOS 3 // Servo index starts with 0 for M280 command
+//#define NUM_SERVOS 3 // Note: Servo index starts with 0 for M280-M282 commands
-// (ms) Delay before the next move will start, to give the servo time to reach its target angle.
+// (ms) Delay before the next move will start, to give the servo time to reach its target angle.
// 300ms is a good value but you can try less delay.
// If the servo can't reach the requested position, increase it.
#define SERVO_DELAY { 300 }
@@ -2948,3 +2948,6 @@
// Edit servo angles with M281 and save to EEPROM with M500
//#define EDITABLE_SERVO_ANGLES
+
+// Disable servo with M282 to reduce power consumption, noise, and heat when not in use
+//#define SERVO_DETACH_GCODE
diff --git a/Marlin/src/gcode/control/M280.cpp b/Marlin/src/gcode/control/M280.cpp
index 187c9a9b1998..f285adf47f00 100644
--- a/Marlin/src/gcode/control/M280.cpp
+++ b/Marlin/src/gcode/control/M280.cpp
@@ -39,7 +39,7 @@ void GcodeSuite::M280() {
if (parser.seen('S')) {
const int a = parser.value_int();
if (a == -1)
- servo[servo_index].detach();
+ DETACH_SERVO(servo_index);
else
MOVE_SERVO(servo_index, a);
}
diff --git a/Marlin/src/gcode/control/M282.cpp b/Marlin/src/gcode/control/M282.cpp
new file mode 100644
index 000000000000..5fe2e6e328a9
--- /dev/null
+++ b/Marlin/src/gcode/control/M282.cpp
@@ -0,0 +1,45 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2021 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(SERVO_DETACH_GCODE)
+
+#include "../gcode.h"
+#include "../../module/servo.h"
+
+/**
+ * M282: Detach Servo. P
+ */
+void GcodeSuite::M282() {
+
+ if (!parser.seen('P')) return;
+
+ const int servo_index = parser.value_int();
+ if (WITHIN(servo_index, 0, NUM_SERVOS - 1))
+ DETACH_SERVO(servo_index);
+ else
+ SERIAL_ECHO_MSG("Servo ", servo_index, " out of range");
+
+}
+
+#endif // SERVO_DETACH_GCODE
diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp
index e3b90b65b301..4e7c3df78d76 100644
--- a/Marlin/src/gcode/gcode.cpp
+++ b/Marlin/src/gcode/gcode.cpp
@@ -717,6 +717,9 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
#if ENABLED(EDITABLE_SERVO_ANGLES)
case 281: M281(); break; // M281: Set servo angles
#endif
+ #if ENABLED(SERVO_DETACH_GCODE)
+ case 282: M282(); break; // M282: Detach servo
+ #endif
#endif
#if ENABLED(BABYSTEPPING)
diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h
index 16cee3481db0..aa38b7de4a3d 100644
--- a/Marlin/src/gcode/gcode.h
+++ b/Marlin/src/gcode/gcode.h
@@ -192,6 +192,7 @@
* M261 - i2c Request Data (Requires EXPERIMENTAL_I2CBUS)
* M280 - Set servo position absolute: "M280 P S". (Requires servos)
* M281 - Set servo min|max position: "M281 P L U". (Requires EDITABLE_SERVO_ANGLES)
+ * M282 - Detach servo: "M282 P". (Requires SERVO_DETACH_GCODE)
* M290 - Babystepping (Requires BABYSTEPPING)
* M300 - Play beep sound S P
* M301 - Set PID parameters P I and D. (Requires PIDTEMP)
@@ -862,6 +863,9 @@ class GcodeSuite {
static void M281();
static void M281_report(const bool forReplay=true);
#endif
+ #if ENABLED(SERVO_DETACH_GCODE)
+ static void M282();
+ #endif
#endif
#if ENABLED(BABYSTEPPING)
diff --git a/Marlin/src/inc/Conditionals_post.h b/Marlin/src/inc/Conditionals_post.h
index 61a9ea2c9a8e..5b7526b74b41 100644
--- a/Marlin/src/inc/Conditionals_post.h
+++ b/Marlin/src/inc/Conditionals_post.h
@@ -2593,9 +2593,14 @@
#endif
#if NUM_SERVOS > 0
#define HAS_SERVOS 1
-#endif
-#if HAS_SERVOS && defined(PAUSE_SERVO_OUTPUT) && defined(RESUME_SERVO_OUTPUT)
- #define HAS_PAUSE_SERVO_OUTPUT 1
+ #if defined(PAUSE_SERVO_OUTPUT) && defined(RESUME_SERVO_OUTPUT)
+ #define HAS_PAUSE_SERVO_OUTPUT 1
+ #endif
+#else
+ #undef SERVO_DELAY
+ #undef DEACTIVATE_SERVOS_AFTER_MOVE
+ #undef EDITABLE_SERVO_ANGLES
+ #undef SERVO_DETACH_GCODE
#endif
// Sensors
diff --git a/Marlin/src/module/servo.cpp b/Marlin/src/module/servo.cpp
index 9b71dd390f51..231efe84e1f2 100644
--- a/Marlin/src/module/servo.cpp
+++ b/Marlin/src/module/servo.cpp
@@ -39,19 +39,19 @@ HAL_SERVO_LIB servo[NUM_SERVOS];
void servo_init() {
#if NUM_SERVOS >= 1 && HAS_SERVO_0
servo[0].attach(SERVO0_PIN);
- servo[0].detach(); // Just set up the pin. We don't have a position yet. Don't move to a random position.
+ DETACH_SERVO(0); // Just set up the pin. We don't have a position yet. Don't move to a random position.
#endif
#if NUM_SERVOS >= 2 && HAS_SERVO_1
servo[1].attach(SERVO1_PIN);
- servo[1].detach();
+ DETACH_SERVO(1);
#endif
#if NUM_SERVOS >= 3 && HAS_SERVO_2
servo[2].attach(SERVO2_PIN);
- servo[2].detach();
+ DETACH_SERVO(2);
#endif
#if NUM_SERVOS >= 4 && HAS_SERVO_3
servo[3].attach(SERVO3_PIN);
- servo[3].detach();
+ DETACH_SERVO(3);
#endif
}
diff --git a/Marlin/src/module/servo.h b/Marlin/src/module/servo.h
index 3b5a5e7e2cd2..73dbbdddb729 100644
--- a/Marlin/src/module/servo.h
+++ b/Marlin/src/module/servo.h
@@ -110,6 +110,7 @@
#endif // HAS_SERVO_ANGLES
#define MOVE_SERVO(I, P) servo[I].move(P)
+#define DETACH_SERVO(I) servo[I].detach()
extern HAL_SERVO_LIB servo[NUM_SERVOS];
void servo_init();
diff --git a/buildroot/tests/LPC1768 b/buildroot/tests/LPC1768
index 26e37108905d..92ba286693e8 100755
--- a/buildroot/tests/LPC1768
+++ b/buildroot/tests/LPC1768
@@ -28,7 +28,8 @@ restore_configs
opt_set MOTHERBOARD BOARD_MKS_SBASE \
EXTRUDERS 2 TEMP_SENSOR_1 1 \
NUM_SERVOS 2 SERVO_DELAY '{ 300, 300 }'
-opt_enable SWITCHING_NOZZLE SWITCHING_NOZZLE_E1_SERVO_NR ULTIMAKERCONTROLLER REALTIME_REPORTING_COMMANDS FULL_REPORT_TO_HOST_FEATURE
+opt_enable SWITCHING_NOZZLE SWITCHING_NOZZLE_E1_SERVO_NR EDITABLE_SERVO_ANGLES SERVO_DETACH_GCODE \
+ ULTIMAKERCONTROLLER REALTIME_REPORTING_COMMANDS FULL_REPORT_TO_HOST_FEATURE
exec_test $1 $2 "MKS SBASE with SWITCHING_NOZZLE, Grbl Realtime Report" "$3"
restore_configs
diff --git a/ini/features.ini b/ini/features.ini
index 6ad375e5946f..b4398378adac 100644
--- a/ini/features.ini
+++ b/ini/features.ini
@@ -173,6 +173,7 @@ HAS_SMART_EFF_MOD = src_filter=+
COOLANT_CONTROL|AIR_ASSIST = src_filter=+
AIR_EVACUATION = src_filter=+
HAS_SOFTWARE_ENDSTOPS = src_filter=+
+SERVO_DETACH_GCODE = src_filter=+
HAS_DUPLICATION_MODE = src_filter=+
LIN_ADVANCE = src_filter=+
PHOTO_GCODE = src_filter=+
diff --git a/platformio.ini b/platformio.ini
index 550206980092..5e4045509836 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -87,7 +87,7 @@ default_src_filter = + - - +
-
- -
-
- - - - - - - -
+ - - - - - -
-
-
-
@@ -166,7 +166,6 @@ default_src_filter = + - - +
-
-
-
- -
-
-
-
@@ -243,7 +242,7 @@ default_src_filter = + - - +
-
-
- -
- - -
+ - - - -
-
#