Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Input shaping for Z axis #27073

Merged
merged 9 commits into from
May 20, 2024
7 changes: 6 additions & 1 deletion Marlin/Configuration_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1202,7 +1202,8 @@
*/
//#define INPUT_SHAPING_X
//#define INPUT_SHAPING_Y
#if ANY(INPUT_SHAPING_X, INPUT_SHAPING_Y)
//#define INPUT_SHAPING_Z
#if ANY(INPUT_SHAPING_X, INPUT_SHAPING_Y, INPUT_SHAPING_Z)
#if ENABLED(INPUT_SHAPING_X)
#define SHAPING_FREQ_X 40.0 // (Hz) The default dominant resonant frequency on the X axis.
#define SHAPING_ZETA_X 0.15 // Damping ratio of the X axis (range: 0.0 = no damping to 1.0 = critical damping).
Expand All @@ -1211,6 +1212,10 @@
#define SHAPING_FREQ_Y 40.0 // (Hz) The default dominant resonant frequency on the Y axis.
#define SHAPING_ZETA_Y 0.15 // Damping ratio of the Y axis (range: 0.0 = no damping to 1.0 = critical damping).
#endif
#if ENABLED(INPUT_SHAPING_Z)
#define SHAPING_FREQ_Z 40.0 // (Hz) The default dominant resonant frequency on the X axis.
#define SHAPING_ZETA_Z 0.15 // Damping ratio of the X axis (range: 0.0 = no damping to 1.0 = critical damping).
#endif
//#define SHAPING_MIN_FREQ 20.0 // (Hz) By default the minimum of the shaping frequencies. Override to affect SRAM usage.
//#define SHAPING_MAX_STEPRATE 10000 // By default the maximum total step rate of the shaped axes. Override to affect SRAM usage.
//#define SHAPING_MENU // Add a menu to the LCD to set shaping parameters.
Expand Down
17 changes: 15 additions & 2 deletions Marlin/src/gcode/feature/input_shaping/M593.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ void GcodeSuite::M593_report(const bool forReplay/*=true*/) {
" D", stepper.get_shaping_damping_ratio(Y_AXIS)
);
#endif
#if ENABLED(INPUT_SHAPING_Z)
#if ANY(INPUT_SHAPING_X, INPUT_SHAPING_Y)
report_echo_start(forReplay);
#endif
SERIAL_ECHOLNPGM(" M593 Z"
" F", stepper.get_shaping_frequency(Z_AXIS),
" D", stepper.get_shaping_damping_ratio(Z_AXIS)
);
#endif
}

/**
Expand All @@ -59,14 +68,17 @@ void GcodeSuite::M593() {

const bool seen_X = TERN0(INPUT_SHAPING_X, parser.seen_test('X')),
seen_Y = TERN0(INPUT_SHAPING_Y, parser.seen_test('Y')),
for_X = seen_X || TERN0(INPUT_SHAPING_X, (!seen_X && !seen_Y)),
for_Y = seen_Y || TERN0(INPUT_SHAPING_Y, (!seen_X && !seen_Y));
seen_Z = TERN0(INPUT_SHAPING_Z, parser.seen_test('Z')),
for_X = seen_X || TERN0(INPUT_SHAPING_X, (!seen_X && !seen_Y && !seen_Z)),
for_Y = seen_Y || TERN0(INPUT_SHAPING_Y, (!seen_X && !seen_Y && !seen_Z)),
for_Z = seen_Z || TERN0(INPUT_SHAPING_Z, (!seen_X && !seen_Y && !seen_Z));

if (parser.seen('D')) {
const float zeta = parser.value_float();
if (WITHIN(zeta, 0, 1)) {
if (for_X) stepper.set_shaping_damping_ratio(X_AXIS, zeta);
if (for_Y) stepper.set_shaping_damping_ratio(Y_AXIS, zeta);
if (for_Z) stepper.set_shaping_damping_ratio(Z_AXIS, zeta);
}
else
SERIAL_ECHO_MSG("?Zeta (D) value out of range (0-1)");
Expand All @@ -78,6 +90,7 @@ void GcodeSuite::M593() {
if (freq == 0.0f || freq > min_freq) {
if (for_X) stepper.set_shaping_frequency(X_AXIS, freq);
if (for_Y) stepper.set_shaping_frequency(Y_AXIS, freq);
if (for_Z) stepper.set_shaping_frequency(Z_AXIS, freq);
}
else
SERIAL_ECHOLNPGM(GCODE_ERR_MSG("Frequency (F) must be greater than ", min_freq, " or 0 to disable"));
Expand Down
9 changes: 6 additions & 3 deletions Marlin/src/inc/Conditionals_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@
#undef DISABLE_IDLE_X
#undef INPUT_SHAPING_X
#undef SAFE_BED_LEVELING_START_X
#undef SHAPING_BUFFER_X
#undef SHAPING_FREQ_X
#undef SHAPING_ZETA_X
#undef STEALTHCHOP_X
#endif

Expand All @@ -128,8 +128,8 @@
#undef INPUT_SHAPING_Y
#undef QUICK_HOME
#undef SAFE_BED_LEVELING_START_Y
#undef SHAPING_BUFFER_Y
#undef SHAPING_FREQ_Y
#undef SHAPING_ZETA_Y
#undef STEALTHCHOP_Y
#undef STEP_STATE_Y
#endif
Expand All @@ -142,8 +142,11 @@
#undef ENABLE_LEVELING_FADE_HEIGHT
#undef HOME_Z_FIRST
#undef HOMING_Z_WITH_PROBE
#undef INPUT_SHAPING_Z
#undef NUM_Z_STEPPERS
#undef SAFE_BED_LEVELING_START_Z
#undef SHAPING_FREQ_Z
#undef SHAPING_ZETA_Z
#undef STEALTHCHOP_Z
#undef STEP_STATE_Z
#undef Z_IDLE_HEIGHT
Expand Down Expand Up @@ -1337,7 +1340,7 @@
#endif

// Input shaping
#if ANY(INPUT_SHAPING_X, INPUT_SHAPING_Y)
#if ANY(INPUT_SHAPING_X, INPUT_SHAPING_Y, INPUT_SHAPING_Z)
#define HAS_ZV_SHAPING 1
#endif

Expand Down
29 changes: 26 additions & 3 deletions Marlin/src/inc/SanityCheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -4183,7 +4183,12 @@ static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive."
*/
#if HAS_ZV_SHAPING
#if ENABLED(DELTA)
#error "Input Shaping is not compatible with DELTA kinematics."
#if !ALL(INPUT_SHAPING_X, INPUT_SHAPING_Y, INPUT_SHAPING_Z)
#error "INPUT_SHAPING_X, INPUT_SHAPING_Y and INPUT_SHAPING_Z must all be enabled for DELTA."
#else
static_assert(SHAPING_FREQ_X == SHAPING_FREQ_Y && SHAPING_FREQ_Y == SHAPING_FREQ_Z, "SHAPING_FREQ_X, SHAPING_FREQ_Y and SHAPING_FREQ_Z must be the same for DELTA.");
static_assert(SHAPING_ZETA_X == SHAPING_ZETA_Y && SHAPING_ZETA_Y == SHAPING_ZETA_Z, "SHAPING_ZETA_X, SHAPING_ZETA_Y and SHAPING_ZETA_Z must be the same for DELTA.");
#endif
#elif ENABLED(SCARA)
#error "Input Shaping is not compatible with SCARA kinematics."
#elif ENABLED(TPARA)
Expand All @@ -4195,9 +4200,19 @@ static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive."
#elif ENABLED(DIRECT_STEPPING)
#error "Input Shaping is not compatible with DIRECT_STEPPING."
#elif ALL(INPUT_SHAPING_X, CORE_IS_XZ)
#error "INPUT_SHAPING_X is not supported with COREXZ."
#if !ALL(INPUT_SHAPING_X, INPUT_SHAPING_Z)
#error "INPUT_SHAPING_X and INPUT_SHAPING_Z must both be enabled for COREXZ."
#else
static_assert(SHAPING_FREQ_X == SHAPING_FREQ_Z, "SHAPING_FREQ_X and SHAPING_FREQ_Z must be the same for COREXZ.");
static_assert(SHAPING_ZETA_X == SHAPING_ZETA_Z, "SHAPING_ZETA_X and SHAPING_ZETA_Z must be the same for COREXZ.");
#endif
#elif ALL(INPUT_SHAPING_Y, CORE_IS_YZ)
#error "INPUT_SHAPING_Y is not supported with COREYZ."
#if !ALL(INPUT_SHAPING_Y, INPUT_SHAPING_Z)
#error "INPUT_SHAPING_Y and INPUT_SHAPING_Z must both be enabled for COREYZ."
#else
static_assert(SHAPING_FREQ_Y == SHAPING_FREQ_Z, "SHAPING_FREQ_Y and SHAPING_FREQ_Z must be the same for COREYZ.");
static_assert(SHAPING_ZETA_Y == SHAPING_ZETA_Z, "SHAPING_ZETA_Y and SHAPING_ZETA_Z must be the same for COREYZ.");
#endif
#elif ANY(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX)
#if !ALL(INPUT_SHAPING_X, INPUT_SHAPING_Y)
#error "INPUT_SHAPING_X and INPUT_SHAPING_Y must both be enabled for COREXY, COREYX, or MARKFORGED_*."
Expand All @@ -4212,6 +4227,7 @@ static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive."
#else
TERN_(INPUT_SHAPING_X, static_assert((SHAPING_FREQ_X) > 0, "SHAPING_FREQ_X must be > 0 or SHAPING_MIN_FREQ must be set."));
TERN_(INPUT_SHAPING_Y, static_assert((SHAPING_FREQ_Y) > 0, "SHAPING_FREQ_Y must be > 0 or SHAPING_MIN_FREQ must be set."));
TERN_(INPUT_SHAPING_Z, static_assert((SHAPING_FREQ_Z) > 0, "SHAPING_FREQ_Z must be > 0 or SHAPING_MIN_FREQ must be set."));
#endif
#ifdef __AVR__
#if ENABLED(INPUT_SHAPING_X)
Expand All @@ -4228,6 +4244,13 @@ static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive."
static_assert((SHAPING_FREQ_Y) == 0 || (SHAPING_FREQ_Y) * 2 * 0x10000 >= (STEPPER_TIMER_RATE), "SHAPING_FREQ_Y is below the minimum (16) for AVR 16MHz.");
#endif
#endif
#if ENABLED(INPUT_SHAPING_Z)
#if F_CPU > 16000000
static_assert((SHAPING_FREQ_Z) == 0 || (SHAPING_FREQ_Z) * 2 * 0x10000 >= (STEPPER_TIMER_RATE), "SHAPING_FREQ_Z is below the minimum (20) for AVR 20MHz.");
#else
static_assert((SHAPING_FREQ_Z) == 0 || (SHAPING_FREQ_Z) * 2 * 0x10000 >= (STEPPER_TIMER_RATE), "SHAPING_FREQ_Z is below the minimum (16) for AVR 16MHz.");
#endif
#endif
#endif
#endif

Expand Down
11 changes: 11 additions & 0 deletions Marlin/src/lcd/e3v2/proui/dwin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3478,6 +3478,13 @@ void drawTuneMenu() {
void setShapingYZeta() { hmiValue.axis = Y_AXIS; setFloatOnClick(0, 1, 2, stepper.get_shaping_damping_ratio(Y_AXIS), applyShapingZeta); }
#endif

#if ENABLED(INPUT_SHAPING_Z)
void onDrawShapingZFreq(MenuItem* menuitem, int8_t line) { onDrawFloatMenu(menuitem, line, 2, stepper.get_shaping_frequency(Z_AXIS)); }
void onDrawShapingZZeta(MenuItem* menuitem, int8_t line) { onDrawFloatMenu(menuitem, line, 2, stepper.get_shaping_damping_ratio(Z_AXIS)); }
void setShapingZFreq() { hmiValue.axis = Z_AXIS; setFloatOnClick(0, 200, 2, stepper.get_shaping_frequency(Z_AXIS), applyShapingFreq); }
void setShapingZZeta() { hmiValue.axis = Z_AXIS; setFloatOnClick(0, 1, 2, stepper.get_shaping_damping_ratio(Z_AXIS), applyShapingZeta); }
#endif

void drawInputShaping_menu() {
checkkey = ID_Menu;
if (SET_MENU(inputShapingMenu, MSG_INPUT_SHAPING, 5)) {
Expand All @@ -3490,6 +3497,10 @@ void drawTuneMenu() {
MENU_ITEM(ICON_ShapingY, MSG_SHAPING_B_FREQ, onDrawShapingYFreq, setShapingYFreq);
MENU_ITEM(ICON_ShapingY, MSG_SHAPING_B_ZETA, onDrawShapingYZeta, setShapingYZeta);
#endif
#if ENABLED(INPUT_SHAPING_Z)
MENU_ITEM(ICON_ShapingZ, MSG_SHAPING_C_FREQ, onDrawShapingZFreq, setShapingZFreq);
MENU_ITEM(ICON_ShapingZ, MSG_SHAPING_C_ZETA, onDrawShapingZZeta, setShapingZZeta);
#endif
}
updateMenu(inputShapingMenu);
}
Expand Down
36 changes: 14 additions & 22 deletions Marlin/src/lcd/menu/menu_advanced.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -559,28 +559,20 @@ void menu_backlash();
BACK_ITEM(MSG_ADVANCED_SETTINGS);

// M593 F Frequency and D Damping ratio
#if ENABLED(INPUT_SHAPING_X)
editable.decimal = stepper.get_shaping_frequency(X_AXIS);
if (editable.decimal) {
ACTION_ITEM_N(X_AXIS, MSG_SHAPING_DISABLE, []{ stepper.set_shaping_frequency(X_AXIS, 0.0f); ui.refresh(); });
EDIT_ITEM_FAST_N(float41, X_AXIS, MSG_SHAPING_FREQ, &editable.decimal, min_frequency, 200.0f, []{ stepper.set_shaping_frequency(X_AXIS, editable.decimal); });
editable.decimal = stepper.get_shaping_damping_ratio(X_AXIS);
EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_SHAPING_ZETA, &editable.decimal, 0.0f, 1.0f, []{ stepper.set_shaping_damping_ratio(X_AXIS, editable.decimal); });
}
else
ACTION_ITEM_N(X_AXIS, MSG_SHAPING_ENABLE, []{ stepper.set_shaping_frequency(X_AXIS, (SHAPING_FREQ_X) ?: (SHAPING_MIN_FREQ)); ui.refresh(); });
#endif
#if ENABLED(INPUT_SHAPING_Y)
editable.decimal = stepper.get_shaping_frequency(Y_AXIS);
if (editable.decimal) {
ACTION_ITEM_N(Y_AXIS, MSG_SHAPING_DISABLE, []{ stepper.set_shaping_frequency(Y_AXIS, 0.0f); ui.refresh(); });
EDIT_ITEM_FAST_N(float41, Y_AXIS, MSG_SHAPING_FREQ, &editable.decimal, min_frequency, 200.0f, []{ stepper.set_shaping_frequency(Y_AXIS, editable.decimal); });
editable.decimal = stepper.get_shaping_damping_ratio(Y_AXIS);
EDIT_ITEM_FAST_N(float42_52, Y_AXIS, MSG_SHAPING_ZETA, &editable.decimal, 0.0f, 1.0f, []{ stepper.set_shaping_damping_ratio(Y_AXIS, editable.decimal); });
}
else
ACTION_ITEM_N(Y_AXIS, MSG_SHAPING_ENABLE, []{ stepper.set_shaping_frequency(Y_AXIS, (SHAPING_FREQ_Y) ?: (SHAPING_MIN_FREQ)); ui.refresh(); });
#endif
#define SHAPING_MENU_FOR_AXIS(AXIS) \
editable.decimal = stepper.get_shaping_frequency(AXIS); \
if (editable.decimal) { \
ACTION_ITEM_N(AXIS, MSG_SHAPING_DISABLE, []{ stepper.set_shaping_frequency(AXIS, 0.0f); ui.refresh(); }); \
EDIT_ITEM_FAST_N(float41, AXIS, MSG_SHAPING_FREQ, &editable.decimal, min_frequency, 200.0f, []{ stepper.set_shaping_frequency(AXIS, editable.decimal); }); \
editable.decimal = stepper.get_shaping_damping_ratio(AXIS); \
EDIT_ITEM_FAST_N(float42_52, AXIS, MSG_SHAPING_ZETA, &editable.decimal, 0.0f, 1.0f, []{ stepper.set_shaping_damping_ratio(AXIS, editable.decimal); }); \
} \
else \
ACTION_ITEM_N(AXIS, MSG_SHAPING_ENABLE, []{ stepper.set_shaping_frequency(AXIS, (SHAPING_FREQ_X) ?: (SHAPING_MIN_FREQ)); ui.refresh(); });

TERN_(INPUT_SHAPING_X, SHAPING_MENU_FOR_AXIS(X_AXIS))
TERN_(INPUT_SHAPING_Y, SHAPING_MENU_FOR_AXIS(Y_AXIS))
TERN_(INPUT_SHAPING_Z, SHAPING_MENU_FOR_AXIS(Z_AXIS))

END_MENU();
}
Expand Down
23 changes: 23 additions & 0 deletions Marlin/src/module/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,10 @@ typedef struct SettingsDataStruct {
float shaping_y_frequency, // M593 Y F
shaping_y_zeta; // M593 Y D
#endif
#if ENABLED(INPUT_SHAPING_Z)
float shaping_z_frequency, // M593 Z F
shaping_z_zeta; // M593 Z D
#endif

//
// HOTEND_IDLE_TIMEOUT
Expand Down Expand Up @@ -1731,6 +1735,10 @@ void MarlinSettings::postprocess() {
EEPROM_WRITE(stepper.get_shaping_frequency(Y_AXIS));
EEPROM_WRITE(stepper.get_shaping_damping_ratio(Y_AXIS));
#endif
#if ENABLED(INPUT_SHAPING_Z)
EEPROM_WRITE(stepper.get_shaping_frequency(Z_AXIS));
EEPROM_WRITE(stepper.get_shaping_damping_ratio(Z_AXIS));
#endif
#endif

//
Expand Down Expand Up @@ -2833,6 +2841,17 @@ void MarlinSettings::postprocess() {
}
#endif

#if ENABLED(INPUT_SHAPING_Z)
{
float _data[2];
EEPROM_READ(_data);
if (!validating) {
stepper.set_shaping_frequency(Z_AXIS, _data[0]);
stepper.set_shaping_damping_ratio(Z_AXIS, _data[1]);
}
}
#endif

//
// HOTEND_IDLE_TIMEOUT
//
Expand Down Expand Up @@ -3665,6 +3684,10 @@ void MarlinSettings::reset() {
stepper.set_shaping_frequency(Y_AXIS, SHAPING_FREQ_Y);
stepper.set_shaping_damping_ratio(Y_AXIS, SHAPING_ZETA_Y);
#endif
#if ENABLED(INPUT_SHAPING_Z)
stepper.set_shaping_frequency(Z_AXIS, SHAPING_FREQ_Z);
stepper.set_shaping_damping_ratio(Z_AXIS, SHAPING_ZETA_Z);
#endif
#endif

//
Expand Down
Loading