Skip to content

Commit c1f0f26

Browse files
tombrazierthinkyhead
authored andcommitted
🚀 ZV Input Shaping (MarlinFirmware#24797)
1 parent 5765449 commit c1f0f26

File tree

15 files changed

+657
-42
lines changed

15 files changed

+657
-42
lines changed

Marlin/Configuration_adv.h

+29
Original file line numberDiff line numberDiff line change
@@ -1055,6 +1055,35 @@
10551055

10561056
// @section motion
10571057

1058+
/**
1059+
* Input Shaping -- EXPERIMENTAL
1060+
*
1061+
* Zero Vibration (ZV) Input Shaping for X and/or Y movements.
1062+
*
1063+
* This option uses a lot of SRAM for the step buffer, which is proportional
1064+
* to the largest step rate possible for any axis. If the build fails due to
1065+
* low SRAM the buffer size may be reduced by setting smaller values for
1066+
* DEFAULT_AXIS_STEPS_PER_UNIT and/or DEFAULT_MAX_FEEDRATE. Runtime editing
1067+
* of max feedrate (M203) or resonant frequency (M593) may result feedrate
1068+
* being capped to prevent buffer overruns.
1069+
*
1070+
* Tune with M593 D<factor> F<frequency>:
1071+
*
1072+
* D<factor> Set the zeta/damping factor. If axes (X, Y, etc.) are not specified, set for all axes.
1073+
* F<frequency> Set the frequency. If axes (X, Y, etc.) are not specified, set for all axes.
1074+
* T[map] Input Shaping type, 0:ZV, 1:EI, 2:2H EI (not implemented yet)
1075+
* X<1> Set the given parameters only for the X axis.
1076+
* Y<1> Set the given parameters only for the Y axis.
1077+
*/
1078+
//#define INPUT_SHAPING
1079+
#if ENABLED(INPUT_SHAPING)
1080+
#define SHAPING_FREQ_X 40 // (Hz) The dominant resonant frequency of the X axis.
1081+
#define SHAPING_FREQ_Y 40 // (Hz) The dominant resonant frequency of the Y axis.
1082+
#define SHAPING_ZETA_X 0.3f // Damping ratio of the X axis (range: 0.0 = no damping to 1.0 = critical damping).
1083+
#define SHAPING_ZETA_Y 0.3f // Damping ratio of the Y axis (range: 0.0 = no damping to 1.0 = critical damping).
1084+
//#define SHAPING_MENU // Add a menu to the LCD to set shaping parameters.
1085+
#endif
1086+
10581087
#define AXIS_RELATIVE_MODES { false, false, false, false }
10591088

10601089
// Add a Duplicate option for well-separated conjoined nozzles
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/**
2+
* Marlin 3D Printer Firmware
3+
* Copyright (c) 2022 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
4+
*
5+
* Based on Sprinter and grbl.
6+
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
7+
*
8+
* This program is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU General Public License as published by
10+
* the Free Software Foundation, either version 3 of the License, or
11+
* (at your option) any later version.
12+
*
13+
* This program is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
* GNU General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU General Public License
19+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
20+
*
21+
*/
22+
23+
#include "../../../inc/MarlinConfig.h"
24+
25+
#if ENABLED(INPUT_SHAPING)
26+
27+
#include "../../gcode.h"
28+
#include "../../../module/stepper.h"
29+
30+
void GcodeSuite::M593_report(const bool forReplay/*=true*/) {
31+
report_heading_etc(forReplay, F("Input Shaping"));
32+
#if HAS_SHAPING_X
33+
SERIAL_ECHO_MSG("M593 X"
34+
" F", stepper.get_shaping_frequency(X_AXIS),
35+
" D", stepper.get_shaping_damping_ratio(X_AXIS)
36+
);
37+
#endif
38+
#if HAS_SHAPING_Y
39+
SERIAL_ECHO_MSG("M593 Y"
40+
" F", stepper.get_shaping_frequency(Y_AXIS),
41+
" D", stepper.get_shaping_damping_ratio(Y_AXIS)
42+
);
43+
#endif
44+
}
45+
46+
/**
47+
* M593: Get or Set Input Shaping Parameters
48+
* D<factor> Set the zeta/damping factor. If axes (X, Y, etc.) are not specified, set for all axes.
49+
* F<frequency> Set the frequency. If axes (X, Y, etc.) are not specified, set for all axes.
50+
* T[map] Input Shaping type, 0:ZV, 1:EI, 2:2H EI (not implemented yet)
51+
* X<1> Set the given parameters only for the X axis.
52+
* Y<1> Set the given parameters only for the Y axis.
53+
*/
54+
void GcodeSuite::M593() {
55+
if (!parser.seen_any()) return M593_report();
56+
57+
const bool seen_X = TERN0(HAS_SHAPING_X, parser.seen_test('X')),
58+
seen_Y = TERN0(HAS_SHAPING_Y, parser.seen_test('Y')),
59+
for_X = seen_X || TERN0(HAS_SHAPING_X, (!seen_X && !seen_Y)),
60+
for_Y = seen_Y || TERN0(HAS_SHAPING_Y, (!seen_X && !seen_Y));
61+
62+
if (parser.seen('D')) {
63+
const float zeta = parser.value_float();
64+
if (WITHIN(zeta, 0, 1)) {
65+
if (for_X) stepper.set_shaping_damping_ratio(X_AXIS, zeta);
66+
if (for_Y) stepper.set_shaping_damping_ratio(Y_AXIS, zeta);
67+
}
68+
else
69+
SERIAL_ECHO_MSG("?Zeta (D) value out of range (0-1)");
70+
}
71+
72+
if (parser.seen('F')) {
73+
const float freq = parser.value_float();
74+
if (freq > 0) {
75+
if (for_X) stepper.set_shaping_frequency(X_AXIS, freq);
76+
if (for_Y) stepper.set_shaping_frequency(Y_AXIS, freq);
77+
}
78+
else
79+
SERIAL_ECHO_MSG("?Frequency (F) must be greater than 0");
80+
}
81+
}
82+
83+
#endif

Marlin/src/gcode/gcode.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,10 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
933933
case 575: M575(); break; // M575: Set serial baudrate
934934
#endif
935935

936+
#if ENABLED(INPUT_SHAPING)
937+
case 593: M593(); break; // M593: Set Input Shaping parameters
938+
#endif
939+
936940
#if ENABLED(ADVANCED_PAUSE_FEATURE)
937941
case 600: M600(); break; // M600: Pause for Filament Change
938942
case 603: M603(); break; // M603: Configure Filament Change

Marlin/src/gcode/gcode.h

+6
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@
259259
* M554 - Get or set IP gateway. (Requires enabled Ethernet port)
260260
* M569 - Enable stealthChop on an axis. (Requires at least one _DRIVER_TYPE to be TMC2130/2160/2208/2209/5130/5160)
261261
* M575 - Change the serial baud rate. (Requires BAUD_RATE_GCODE)
262+
* M593 - Get or set input shaping parameters. (Requires INPUT_SHAPING)
262263
* M600 - Pause for filament change: "M600 X<pos> Y<pos> Z<raise> E<first_retract> L<later_retract>". (Requires ADVANCED_PAUSE_FEATURE)
263264
* M603 - Configure filament change: "M603 T<tool> U<unload_length> L<load_length>". (Requires ADVANCED_PAUSE_FEATURE)
264265
* M605 - Set Dual X-Carriage movement mode: "M605 S<mode> [X<x_offset>] [R<temp_offset>]". (Requires DUAL_X_CARRIAGE)
@@ -1080,6 +1081,11 @@ class GcodeSuite {
10801081
static void M575();
10811082
#endif
10821083

1084+
#if ENABLED(INPUT_SHAPING)
1085+
static void M593();
1086+
static void M593_report(const bool forReplay=true);
1087+
#endif
1088+
10831089
#if ENABLED(ADVANCED_PAUSE_FEATURE)
10841090
static void M600();
10851091
static void M603();

Marlin/src/inc/Conditionals_adv.h

+14
Original file line numberDiff line numberDiff line change
@@ -1085,3 +1085,17 @@
10851085
#else
10861086
#define CALC_FAN_SPEED(f) (f ? map(f, 1, 255, FAN_MIN_PWM, FAN_MAX_PWM) : FAN_OFF_PWM)
10871087
#endif
1088+
1089+
// Input shaping
1090+
#if ENABLED(INPUT_SHAPING)
1091+
#if !HAS_Y_AXIS
1092+
#undef SHAPING_FREQ_Y
1093+
#undef SHAPING_BUFFER_Y
1094+
#endif
1095+
#ifdef SHAPING_FREQ_X
1096+
#define HAS_SHAPING_X 1
1097+
#endif
1098+
#ifdef SHAPING_FREQ_Y
1099+
#define HAS_SHAPING_Y 1
1100+
#endif
1101+
#endif

Marlin/src/inc/SanityCheck.h

+30-5
Original file line numberDiff line numberDiff line change
@@ -4238,11 +4238,6 @@ static_assert(_PLUS_TEST(4), "HOMING_FEEDRATE_MM_M values must be positive.");
42384238
#endif
42394239
#endif
42404240

4241-
// Misc. Cleanup
4242-
#undef _TEST_PWM
4243-
#undef _NUM_AXES_STR
4244-
#undef _LOGICAL_AXES_STR
4245-
42464241
// JTAG support in the HAL
42474242
#if ENABLED(DISABLE_DEBUG) && !defined(JTAGSWD_DISABLE)
42484243
#error "DISABLE_DEBUG is not supported for the selected MCU/Board."
@@ -4254,3 +4249,33 @@ static_assert(_PLUS_TEST(4), "HOMING_FEEDRATE_MM_M values must be positive.");
42544249
#if ENABLED(XFER_BUILD) && !BOTH(BINARY_FILE_TRANSFER, CUSTOM_FIRMWARE_UPLOAD)
42554250
#error "BINARY_FILE_TRANSFER and CUSTOM_FIRMWARE_UPLOAD are required for custom upload."
42564251
#endif
4252+
4253+
// Check requirements for Input Shaping
4254+
#if ENABLED(INPUT_SHAPING) && defined(__AVR__)
4255+
#if HAS_SHAPING_X
4256+
#if F_CPU > 16000000
4257+
static_assert((SHAPING_FREQ_X) * 2 * 0x10000 >= (STEPPER_TIMER_RATE), "SHAPING_FREQ_X is below the minimum (20) for AVR 20MHz.");
4258+
#else
4259+
static_assert((SHAPING_FREQ_X) * 2 * 0x10000 >= (STEPPER_TIMER_RATE), "SHAPING_FREQ_X is below the minimum (16) for AVR 16MHz.");
4260+
#endif
4261+
#elif HAS_SHAPING_Y
4262+
#if F_CPU > 16000000
4263+
static_assert((SHAPING_FREQ_Y) * 2 * 0x10000 >= (STEPPER_TIMER_RATE), "SHAPING_FREQ_Y is below the minimum (20) for AVR 20MHz.");
4264+
#else
4265+
static_assert((SHAPING_FREQ_Y) * 2 * 0x10000 >= (STEPPER_TIMER_RATE), "SHAPING_FREQ_Y is below the minimum (16) for AVR 16MHz.");
4266+
#endif
4267+
#endif
4268+
#endif
4269+
4270+
#if ENABLED(INPUT_SHAPING)
4271+
#if ENABLED(DIRECT_STEPPING)
4272+
#error "INPUT_SHAPING cannot currently be used with DIRECT_STEPPING."
4273+
#elif ENABLED(LASER_FEATURE)
4274+
#error "INPUT_SHAPING cannot currently be used with LASER_FEATURE."
4275+
#endif
4276+
#endif
4277+
4278+
// Misc. Cleanup
4279+
#undef _TEST_PWM
4280+
#undef _NUM_AXES_STR
4281+
#undef _LOGICAL_AXES_STR

Marlin/src/lcd/language/language_en.h

+5
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,11 @@ namespace Language_en {
399399
LSTR MSG_AMAX_EN = _UxGT("Max * Accel");
400400
LSTR MSG_A_RETRACT = _UxGT("Retract Accel");
401401
LSTR MSG_A_TRAVEL = _UxGT("Travel Accel");
402+
LSTR MSG_INPUT_SHAPING = _UxGT("Input Shaping");
403+
LSTR MSG_SHAPING_X_FREQ = STR_X _UxGT(" frequency");
404+
LSTR MSG_SHAPING_Y_FREQ = STR_Y _UxGT(" frequency");
405+
LSTR MSG_SHAPING_X_ZETA = STR_X _UxGT(" damping");
406+
LSTR MSG_SHAPING_Y_ZETA = STR_Y _UxGT(" damping");
402407
LSTR MSG_XY_FREQUENCY_LIMIT = _UxGT("XY Freq Limit");
403408
LSTR MSG_XY_FREQUENCY_FEEDRATE = _UxGT("Min FR Factor");
404409
LSTR MSG_STEPS_PER_MM = _UxGT("Steps/mm");

Marlin/src/lcd/menu/menu_advanced.cpp

+39-2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "menu_item.h"
3232
#include "../../MarlinCore.h"
3333
#include "../../module/planner.h"
34+
#include "../../module/stepper.h"
3435

3536
#if DISABLED(NO_VOLUMETRICS)
3637
#include "../../gcode/parser.h"
@@ -80,8 +81,6 @@ void menu_backlash();
8081

8182
#if HAS_MOTOR_CURRENT_PWM
8283

83-
#include "../../module/stepper.h"
84-
8584
void menu_pwm() {
8685
START_MENU();
8786
BACK_ITEM(MSG_ADVANCED_SETTINGS);
@@ -538,6 +537,39 @@ void menu_backlash();
538537
END_MENU();
539538
}
540539

540+
#if ENABLED(SHAPING_MENU)
541+
542+
void menu_advanced_input_shaping() {
543+
constexpr float min_frequency = TERN(__AVR__, float(STEPPER_TIMER_RATE) / 2 / 0x10000, 1.0f);
544+
545+
START_MENU();
546+
BACK_ITEM(MSG_ADVANCED_SETTINGS);
547+
548+
// M593 F Frequency
549+
#if HAS_SHAPING_X
550+
editable.decimal = stepper.get_shaping_frequency(X_AXIS);
551+
EDIT_ITEM_FAST(float61, MSG_SHAPING_X_FREQ, &editable.decimal, min_frequency, 200.0f, []{ stepper.set_shaping_frequency(X_AXIS, editable.decimal); });
552+
#endif
553+
#if HAS_SHAPING_Y
554+
editable.decimal = stepper.get_shaping_frequency(Y_AXIS);
555+
EDIT_ITEM_FAST(float61, MSG_SHAPING_Y_FREQ, &editable.decimal, min_frequency, 200.0f, []{ stepper.set_shaping_frequency(Y_AXIS, editable.decimal); });
556+
#endif
557+
558+
// M593 D Damping ratio
559+
#if HAS_SHAPING_X
560+
editable.decimal = stepper.get_shaping_damping_ratio(X_AXIS);
561+
EDIT_ITEM_FAST(float42_52, MSG_SHAPING_X_ZETA, &editable.decimal, 0.0f, 1.0f, []{ stepper.set_shaping_damping_ratio(X_AXIS, editable.decimal); });
562+
#endif
563+
#if HAS_SHAPING_Y
564+
editable.decimal = stepper.get_shaping_damping_ratio(Y_AXIS);
565+
EDIT_ITEM_FAST(float42_52, MSG_SHAPING_Y_ZETA, &editable.decimal, 0.0f, 1.0f, []{ stepper.set_shaping_damping_ratio(Y_AXIS, editable.decimal); });
566+
#endif
567+
568+
END_MENU();
569+
}
570+
571+
#endif
572+
541573
#if HAS_CLASSIC_JERK
542574

543575
void menu_advanced_jerk() {
@@ -657,6 +689,11 @@ void menu_advanced_settings() {
657689
// M201 - Acceleration items
658690
SUBMENU(MSG_ACCELERATION, menu_advanced_acceleration);
659691

692+
// M593 - Acceleration items
693+
#if ENABLED(SHAPING_MENU)
694+
SUBMENU(MSG_INPUT_SHAPING, menu_advanced_input_shaping);
695+
#endif
696+
660697
#if HAS_CLASSIC_JERK
661698
// M205 - Max Jerk
662699
SUBMENU(MSG_JERK, menu_advanced_jerk);

Marlin/src/module/planner.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -2483,6 +2483,14 @@ bool Planner::_populate_block(
24832483

24842484
#endif // XY_FREQUENCY_LIMIT
24852485

2486+
#if ENABLED(INPUT_SHAPING)
2487+
const float top_freq = _MIN(float(0x7FFFFFFFL)
2488+
OPTARG(HAS_SHAPING_X, stepper.get_shaping_frequency(X_AXIS))
2489+
OPTARG(HAS_SHAPING_Y, stepper.get_shaping_frequency(Y_AXIS))),
2490+
max_factor = (top_freq * float(shaping_dividends - 3) * 2.0f) / block->nominal_rate;
2491+
NOMORE(speed_factor, max_factor);
2492+
#endif
2493+
24862494
// Correct the speed
24872495
if (speed_factor < 1.0f) {
24882496
current_speed *= speed_factor;

0 commit comments

Comments
 (0)