From 40beddeaa397cf8bb7b324209f86bb47e1d50f7f Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Mon, 20 Oct 2025 16:01:13 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=B8=20Simplified=20M493?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part of #21827 --- Marlin/src/gcode/feature/ft_motion/M493.cpp | 566 +++++++++----------- Marlin/src/module/ft_motion.h | 2 + 2 files changed, 251 insertions(+), 317 deletions(-) diff --git a/Marlin/src/gcode/feature/ft_motion/M493.cpp b/Marlin/src/gcode/feature/ft_motion/M493.cpp index c9b056d7d1..796676bf57 100644 --- a/Marlin/src/gcode/feature/ft_motion/M493.cpp +++ b/Marlin/src/gcode/feature/ft_motion/M493.cpp @@ -46,8 +46,10 @@ void say_shaper_type(const AxisEnum a, bool &sep, const char axis_name) { } void say_shaping() { + const ft_config_t &c = ftMotion.cfg; + // FT Enabled - SERIAL_ECHO_TERNARY(ftMotion.cfg.active, "Fixed-Time Motion ", "en", "dis", "abled"); + SERIAL_ECHO_TERNARY(c.active, "Fixed-Time Motion ", "en", "dis", "abled"); // FT Shaping const bool is_shaping = AXIS_IS_SHAPING(X) || AXIS_IS_SHAPING(Y) || AXIS_IS_SHAPING(Z) || AXIS_IS_SHAPING(E); @@ -61,15 +63,15 @@ void say_shaping() { } SERIAL_EOL(); - const bool z_based = TERN0(HAS_DYNAMIC_FREQ_MM, ftMotion.cfg.dynFreqMode == dynFreqMode_Z_BASED), - g_based = TERN0(HAS_DYNAMIC_FREQ_G, ftMotion.cfg.dynFreqMode == dynFreqMode_MASS_BASED), + const bool z_based = TERN0(HAS_DYNAMIC_FREQ_MM, c.dynFreqMode == dynFreqMode_Z_BASED), + g_based = TERN0(HAS_DYNAMIC_FREQ_G, c.dynFreqMode == dynFreqMode_MASS_BASED), dynamic = z_based || g_based; // FT Dynamic Frequency Mode if (is_shaping) { #if HAS_DYNAMIC_FREQ SERIAL_ECHOPGM("Dynamic Frequency Mode "); - switch (ftMotion.cfg.dynFreqMode) { + switch (c.dynFreqMode) { default: case dynFreqMode_DISABLED: SERIAL_ECHOPGM("disabled"); break; #if HAS_DYNAMIC_FREQ_MM @@ -85,9 +87,9 @@ void say_shaping() { #if HAS_X_AXIS SERIAL_CHAR(STEPPER_A_NAME); SERIAL_ECHO_TERNARY(dynamic, " ", "base dynamic", "static", " shaper frequency: "); - SERIAL_ECHO(p_float_t(ftMotion.cfg.baseFreq.x, 2), F("Hz")); + SERIAL_ECHO(p_float_t(c.baseFreq.x, 2), F("Hz")); #if HAS_DYNAMIC_FREQ - if (dynamic) SERIAL_ECHO(F(" scaling: "), p_float_t(ftMotion.cfg.dynFreqK.x, 2), F("Hz/"), z_based ? F("mm") : F("g")); + if (dynamic) SERIAL_ECHO(F(" scaling: "), p_float_t(c.dynFreqK.x, 2), F("Hz/"), z_based ? F("mm") : F("g")); #endif SERIAL_EOL(); #endif @@ -95,9 +97,9 @@ void say_shaping() { #if HAS_Y_AXIS SERIAL_CHAR(STEPPER_B_NAME); SERIAL_ECHO_TERNARY(dynamic, " ", "base dynamic", "static", " shaper frequency: "); - SERIAL_ECHO(p_float_t(ftMotion.cfg.baseFreq.y, 2), F(" Hz")); + SERIAL_ECHO(p_float_t(c.baseFreq.y, 2), F(" Hz")); #if HAS_DYNAMIC_FREQ - if (dynamic) SERIAL_ECHO(F(" scaling: "), p_float_t(ftMotion.cfg.dynFreqK.y, 2), F("Hz/"), z_based ? F("mm") : F("g")); + if (dynamic) SERIAL_ECHO(F(" scaling: "), p_float_t(c.dynFreqK.y, 2), F("Hz/"), z_based ? F("mm") : F("g")); #endif SERIAL_EOL(); #endif @@ -105,18 +107,18 @@ void say_shaping() { #if ENABLED(FTM_SHAPER_Z) SERIAL_CHAR(STEPPER_C_NAME); SERIAL_ECHO_TERNARY(dynamic, " ", "base dynamic", "static", " shaper frequency: "); - SERIAL_ECHO(p_float_t(ftMotion.cfg.baseFreq.z, 2), F(" Hz")); + SERIAL_ECHO(p_float_t(c.baseFreq.z, 2), F(" Hz")); #if HAS_DYNAMIC_FREQ - if (dynamic) SERIAL_ECHO(F(" scaling: "), p_float_t(ftMotion.cfg.dynFreqK.z, 2), F("Hz/"), z_based ? F("mm") : F("g")); + if (dynamic) SERIAL_ECHO(F(" scaling: "), p_float_t(c.dynFreqK.z, 2), F("Hz/"), z_based ? F("mm") : F("g")); #endif SERIAL_EOL(); #endif } #if HAS_EXTRUDERS - if (ftMotion.cfg.active) { - SERIAL_ECHO_TERNARY(ftMotion.cfg.linearAdvEna, "Linear Advance ", "en", "dis", "abled"); - SERIAL_ECHOLNPGM(". Gain: ", ftMotion.cfg.linearAdvK); + if (c.active) { + SERIAL_ECHO_TERNARY(c.linearAdvEna, "Linear Advance ", "en", "dis", "abled"); + SERIAL_ECHOLNPGM(". Gain: ", c.linearAdvK); } #endif } @@ -126,90 +128,34 @@ void GcodeSuite::M493_report(const bool forReplay/*=true*/) { report_heading_etc(forReplay, F(STR_FT_MOTION)); const ft_config_t &c = ftMotion.cfg; + SERIAL_ECHOLNPGM( " M493 S", c.active - - // Shaper type for each axis - #if HAS_X_AXIS - , " X", c.shaper.x - #endif - #if HAS_Y_AXIS - , " Y", c.shaper.y - #endif - #if ENABLED(FTM_SHAPER_Z) - , " Z", c.shaper.z - #endif - #if ENABLED(FTM_SHAPER_E) - , " E", c.shaper.e - #endif - - // Base Frequency for axis shapers - #if HAS_X_AXIS - , " A", c.baseFreq.x - #endif - #if HAS_Y_AXIS - , " B", c.baseFreq.y - #endif - #if ENABLED(FTM_SHAPER_Z) - , " C", c.baseFreq.z - #endif - #if ENABLED(FTM_SHAPER_E) - , " W", c.baseFreq.e - #endif - - // Dynamic Frequency Mode and Axis K Factors #if HAS_DYNAMIC_FREQ , " D", c.dynFreqMode - #if HAS_X_AXIS - , " F", c.dynFreqK.x - #endif - #if HAS_Y_AXIS - , " H", c.dynFreqK.y - #endif - #if ENABLED(FTM_SHAPER_Z) - , " L", c.dynFreqK.z - #endif - #if ENABLED(FTM_SHAPER_E) - , " N", c.dynFreqK.e - #endif #endif - - // Zeta Value - #if HAS_X_AXIS - , " I", c.zeta.x - #endif - #if HAS_Y_AXIS - , " J", c.zeta.y - #endif - #if ENABLED(FTM_SHAPER_Z) - , " O", c.zeta.z - #endif - #if ENABLED(FTM_SHAPER_E) - , " U", c.zeta.e - #endif - - // Vibration Tolerance - #if HAS_X_AXIS - , " Q", c.vtol.x - #endif - #if HAS_Y_AXIS - , " R", c.vtol.y - #endif - #if ENABLED(FTM_SHAPER_Z) - , " T", c.vtol.z - #endif - #if ENABLED(FTM_SHAPER_E) - , " V", c.vtol.e - #endif - - // Axis Synchronization - , " G", c.axis_sync_enabled - #if HAS_EXTRUDERS , " P", c.linearAdvEna, " K", c.linearAdvK #endif - + // Axis Synchronization + , " H", c.axis_sync_enabled ); + + #if HAS_DYNAMIC_FREQ + #define F_REPORT(A) , F(" F"), c.dynFreqK.A + #else + #define F_REPORT(A) + #endif + #define _REPORT_M493_AXIS(A) \ + SERIAL_ECHOLN(F(" M493 "), C(AXIS_CHAR(_AXIS(A))) \ + , F(" C"), c.shaper.A \ + , F(" A"), c.baseFreq.A \ + F_REPORT(A) \ + , F(" I"), c.zeta.A \ + , F(" Q"), c.vtol.A \ + ); + // Shaper type for each axis + SHAPED_MAP(_REPORT_M493_AXIS); } /** @@ -219,7 +165,23 @@ void GcodeSuite::M493_report(const bool forReplay/*=true*/) { * 0: Fixed-Time Motion OFF (Standard Motion) * 1: Fixed-Time Motion ON * - * X/Y/Z/E Set the vibration compensator [input shaper] mode for an axis. + * V Flag to request version (Version 2+). (No reply = Version < 2) + * + * H Enable (1) or Disable (0) Axis Synchronization. + * + * Linear / Pressure Advance: + * + * P Enable (1) or Disable (0) Linear Advance pressure control + * K Set Linear Advance gain + * + * Specifying Axes (for A,C,F,I,Q): + * + * X/Y/Z/E : Flag the axes (or core steppers) on which to apply the given parameters + * If none are given then XY is assumed. + * + * Compensator / Input Shaper: + * + * C Set Compensator Mode (Input Shaper) for the specified axes * Users / slicers must remember to set the mode for all relevant axes! * 0: NONE : No input shaper * 1: ZV : Zero Vibration @@ -231,41 +193,27 @@ void GcodeSuite::M493_report(const bool forReplay/*=true*/) { * 7: 3HEI : 3-Hump Extra-Intensive * 8: MZV : Mass-based Zero Vibration * - * P Enable (1) or Disable (0) Linear Advance pressure control + * A Set static/base frequency for the specified axes + * I Set damping ratio for the specified axes + * Q Set vibration tolerance (vtol) for the specified axes * - * K Set Linear Advance gain + * Dynamic Frequency Mode: * - * G Enable (1) or Disable (0) axis synchronization. - * - * D Set Dynamic Frequency mode + * D Set Dynamic Frequency mode (for all axis compensators) * 0: DISABLED * 1: Z-based (Requires a Z axis) * 2: Mass-based (Requires X and E axes) * - * A Set X static/base frequency - * F Set X frequency scaling - * I Set X damping ratio - * Q Set X vibration tolerance (vtol) - * - * B Set Y static/base frequency - * H Set Y frequency scaling - * J Set Y damping ratio - * R Set Y vibration tolerance - * - * With FTM_SHAPER_Z: - * C Set Z static/base frequency - * L Set Z frequency scaling - * O Set Z damping ratio - * T Set Z vibration tolerance - * - * With FTM_SHAPER_E: - * W Set E static/base frequency - * N Set E frequency scaling - * U Set E damping ratio - * V Set E vibration tolerance + * F Set frequency scaling for the specified axes * */ void GcodeSuite::M493() { + // Request version of FTM. (No response = Version < 2) + if (parser.seen('V') && !parser.has_value()) { + SERIAL_ECHOLNPGM("FTM V" STRINGIFY(FTM_VERSION)); + return; + } + struct { bool update:1, report:1; } flag = { false }; if (!parser.seen_any()) @@ -283,30 +231,23 @@ void GcodeSuite::M493() { #if NUM_AXES_SHAPED > 0 - auto set_shaper = [&](const AxisEnum axis, const char c) { - const ftMotionShaper_t newsh = (ftMotionShaper_t)parser.value_byte(); + const bool seenC = parser.seenval('C'); + const ftMotionShaper_t shaperVal = seenC ? (ftMotionShaper_t)parser.value_byte() : ftMotionShaper_NONE; + const bool goodShaper = WITHIN(shaperVal, ftMotionShaper_NONE, ftMotionShaper_MZV); + if (seenC && !goodShaper) { + SERIAL_ECHOLNPGM("?Invalid (C)ompensator value. (0-", int(ftMotionShaper_MZV)); + return; + } + auto set_shaper = [&](const AxisEnum axis, ftMotionShaper_t newsh) { if (newsh != ftMotion.cfg.shaper[axis]) { - switch (newsh) { - default: SERIAL_ECHOLNPGM("?Invalid [", C(c), "] shaper."); return true; - case ftMotionShaper_NONE: - case ftMotionShaper_ZV: - case ftMotionShaper_ZVD: - case ftMotionShaper_ZVDD: - case ftMotionShaper_ZVDDD: - case ftMotionShaper_EI: - case ftMotionShaper_2HEI: - case ftMotionShaper_3HEI: - case ftMotionShaper_MZV: - ftMotion.cfg.shaper[axis] = newsh; - flag.update = flag.report = true; - break; - } + ftMotion.cfg.shaper[axis] = newsh; + flag.update = flag.report = true; } - return false; }; - - #define _SET_SHAPER(A) if (parser.seenval(CHARIFY(A)) && set_shaper(_AXIS(A), CHARIFY(A))) return; - SHAPED_MAP(_SET_SHAPER); + if (seenC) { + #define _SET_SHAPER(A) set_shaper(_AXIS(A), shaperVal); + SHAPED_MAP(_SET_SHAPER); + } #endif // NUM_AXES_SHAPED > 0 @@ -332,8 +273,8 @@ void GcodeSuite::M493() { #endif // HAS_EXTRUDERS - // Parse 'G' axis synchronization parameter. - if (parser.seenval('G')) { + // Parse 'H' Axis Synchronization parameter. + if (parser.seenval('H')) { const bool enabled = parser.value_bool(); if (enabled != ftMotion.cfg.axis_sync_enabled) { ftMotion.cfg.axis_sync_enabled = enabled; @@ -359,12 +300,12 @@ void GcodeSuite::M493() { flag.report = true; break; default: - SERIAL_ECHOLNPGM("?Invalid Dynamic Frequency Mode [D] value."); + SERIAL_ECHOLNPGM("?Invalid (D)ynamic Frequency Mode value."); break; } } else { - SERIAL_ECHOLNPGM("?Wrong shaper for [D] Dynamic Frequency mode."); + SERIAL_ECHOLNPGM("?Wrong shaper for (D)ynamic Frequency mode ", ftMotion.cfg.dynFreqMode, "."); } } @@ -375,247 +316,238 @@ void GcodeSuite::M493() { #endif // HAS_DYNAMIC_FREQ + // Frequency parameter + const bool seenA = parser.seenval('A'); + const float baseFreqVal = seenA ? parser.value_float() : 0.0f; + const bool goodBaseFreq = seenA && WITHIN(baseFreqVal, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2); + if (seenA && !goodBaseFreq) + SERIAL_ECHOLN(F("?Invalid (A) Base Frequency value. ("), int(FTM_MIN_SHAPE_FREQ), C('-'), int((FTM_FS) / 2), C(')')); + + #if HAS_DYNAMIC_FREQ + // Dynamic Frequency parameter + const bool seenF = parser.seenval('F'); + const float baseDynFreqVal = seenF ? parser.value_float() : 0.0f; + if (seenF && !modeUsesDynFreq) + SERIAL_ECHOLNPGM("?Wrong mode for (F)requency scaling."); + #endif + + // Zeta parameter + const bool seenI = parser.seenval('I'); + const float zetaVal = seenI ? parser.value_float() : 0.0f; + const bool goodZeta = seenI && WITHIN(zetaVal, 0.01f, 1.0f); + if (seenI && !goodZeta) + SERIAL_ECHOLNPGM("?Invalid (I) Zeta value. (0.01-1.0)"); // Zeta out of range + + // Vibration Tolerance parameter + const bool seenQ = parser.seenval('Q'); + const float vtolVal = seenQ ? parser.value_float() : 0.0f; + const bool goodVtol = seenQ && WITHIN(vtolVal, 0.00f, 1.0f); + if (seenQ && !goodVtol) + SERIAL_ECHOLNPGM("?Invalid (Q) Vibration Tolerance value. (0.0-1.0)"); // VTol out of range + + const bool apply_xy = !parser.seen("XYZE"); + #if HAS_X_AXIS - // Parse X frequency parameter - if (parser.seenval('A')) { - if (AXIS_IS_SHAPING(X)) { - const float val = parser.value_float(); - // TODO: Frequency minimum is dependent on the shaper used; the above check isn't always correct. - if (WITHIN(val, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2)) { - ftMotion.cfg.baseFreq.x = val; - flag.update = flag.report = true; - } - else // Frequency out of range. - SERIAL_ECHOLNPGM("?Invalid ", C(STEPPER_A_NAME), " [", C('A'), "] frequency value."); - } - else // Mode doesn't use frequency. - SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " [", C('A'), "] frequency."); - } + if (apply_xy || parser.seen_test('X')) { - #if HAS_DYNAMIC_FREQ - // Parse X frequency scaling parameter - if (parser.seenval('F')) { - if (modeUsesDynFreq) { - ftMotion.cfg.dynFreqK.x = parser.value_float(); + // Parse X frequency parameter + if (seenA) { + if (AXIS_IS_SHAPING(X)) { + // TODO: Frequency minimum is dependent on the shaper used; the above check isn't always correct. + if (goodBaseFreq) { + ftMotion.cfg.baseFreq.x = baseFreqVal; + flag.update = flag.report = true; + } + } + else // Mode doesn't use frequency. + SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " [A] frequency."); + } + + #if HAS_DYNAMIC_FREQ + // Parse X frequency scaling parameter + if (seenF && modeUsesDynFreq) { + ftMotion.cfg.dynFreqK.x = baseDynFreqVal; flag.report = true; } - else - SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " [", C('F'), "] frequency scaling."); - } - #endif + #endif - // Parse X zeta parameter - if (parser.seenval('I')) { - const float val = parser.value_float(); - if (AXIS_IS_SHAPING(X)) { - if (WITHIN(val, 0.01f, 1.0f)) { - ftMotion.cfg.zeta.x = val; - flag.update = true; + // Parse X zeta parameter + if (seenI) { + if (AXIS_IS_SHAPING(X)) { + if (goodZeta) { + ftMotion.cfg.zeta.x = zetaVal; + flag.update = true; + } } else - SERIAL_ECHOLNPGM("?Invalid ", C(STEPPER_A_NAME), " zeta [", C('I'), "] value."); // Zeta out of range + SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " zeta parameter."); } - else - SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " zeta parameter."); - } - // Parse X vtol parameter - if (parser.seenval('Q')) { - const float val = parser.value_float(); - if (AXIS_IS_EISHAPING(X)) { - if (WITHIN(val, 0.00f, 1.0f)) { - ftMotion.cfg.vtol.x = val; - flag.update = true; + // Parse X vtol parameter + if (seenQ) { + if (AXIS_IS_EISHAPING(X)) { + if (goodVtol) { + ftMotion.cfg.vtol.x = vtolVal; + flag.update = true; + } } else - SERIAL_ECHOLNPGM("?Invalid ", C(STEPPER_A_NAME), " vtol [", C('Q'), "] value."); // VTol out of range. + SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " vtol parameter."); } - else - SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " vtol parameter."); } #endif // HAS_X_AXIS #if HAS_Y_AXIS - // Parse Y frequency parameter - if (parser.seenval('B')) { - if (AXIS_IS_SHAPING(Y)) { - const float val = parser.value_float(); - if (WITHIN(val, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2)) { - ftMotion.cfg.baseFreq.y = val; - flag.update = flag.report = true; - } - else // Frequency out of range. - SERIAL_ECHOLNPGM("?Invalid ", C(STEPPER_B_NAME), " frequency [", C('B'), "] value."); - } - else // Mode doesn't use frequency. - SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " [", C('B'), "] frequency."); - } + if (apply_xy || parser.seen_test('Y')) { - #if HAS_DYNAMIC_FREQ - // Parse Y frequency scaling parameter - if (parser.seenval('H')) { - if (modeUsesDynFreq) { - ftMotion.cfg.dynFreqK.y = parser.value_float(); + // Parse Y frequency parameter + if (seenA) { + if (AXIS_IS_SHAPING(Y)) { + if (goodBaseFreq) { + ftMotion.cfg.baseFreq.y = baseFreqVal; + flag.update = flag.report = true; + } + } + else // Mode doesn't use frequency. + SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " [A] frequency."); + } + + #if HAS_DYNAMIC_FREQ + // Parse Y frequency scaling parameter + if (seenF && modeUsesDynFreq) { + ftMotion.cfg.dynFreqK.y = baseDynFreqVal; flag.report = true; } - else - SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " [", C('H'), "] frequency scaling."); - } - #endif + #endif - // Parse Y zeta parameter - if (parser.seenval('J')) { - const float val = parser.value_float(); - if (AXIS_IS_SHAPING(Y)) { - if (WITHIN(val, 0.01f, 1.0f)) { - ftMotion.cfg.zeta.y = val; - flag.update = true; + // Parse Y zeta parameter + if (seenI) { + if (AXIS_IS_SHAPING(Y)) { + if (goodZeta) { + ftMotion.cfg.zeta.y = zetaVal; + flag.update = true; + } } else - SERIAL_ECHOLNPGM("?Invalid ", C(STEPPER_B_NAME), " zeta [", C('J'), "] value."); // Zeta out of range + SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " zeta parameter."); } - else - SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " zeta parameter."); - } - // Parse Y vtol parameter - if (parser.seenval('R')) { - const float val = parser.value_float(); - if (AXIS_IS_EISHAPING(Y)) { - if (WITHIN(val, 0.00f, 1.0f)) { - ftMotion.cfg.vtol.y = val; - flag.update = true; + // Parse Y vtol parameter + if (seenQ) { + if (AXIS_IS_EISHAPING(Y)) { + if (goodVtol) { + ftMotion.cfg.vtol.y = vtolVal; + flag.update = true; + } } else - SERIAL_ECHOLNPGM("?Invalid ", C(STEPPER_B_NAME), " vtol [", C('R'), "] value."); // VTol out of range. + SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " vtol parameter."); } - else - SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " vtol parameter."); } #endif // HAS_Y_AXIS #if ENABLED(FTM_SHAPER_Z) - // Parse Z frequency parameter - if (parser.seenval('C')) { - if (AXIS_IS_SHAPING(Z)) { - const float val = parser.value_float(); - if (WITHIN(val, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2)) { - ftMotion.cfg.baseFreq.z = val; - flag.update = flag.report = true; - } - else // Frequency out of range. - SERIAL_ECHOLNPGM("?Invalid ", C(STEPPER_C_NAME), " frequency [", C('C'), "] value."); - } - else // Mode doesn't use frequency. - SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " [", C('C'), "] frequency."); - } + if (parser.seen_test('Z')) { - #if HAS_DYNAMIC_FREQ - // Parse Z frequency scaling parameter - if (parser.seenval('L')) { - if (modeUsesDynFreq) { - ftMotion.cfg.dynFreqK.z = parser.value_float(); + // Parse Z frequency parameter + if (seenA) { + if (AXIS_IS_SHAPING(Z)) { + if (goodBaseFreq) { + ftMotion.cfg.baseFreq.z = baseFreqVal; + flag.update = flag.report = true; + } + } + else // Mode doesn't use frequency. + SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " [A] frequency."); + } + + #if HAS_DYNAMIC_FREQ + // Parse Z frequency scaling parameter + if (seenF && modeUsesDynFreq) { + ftMotion.cfg.dynFreqK.z = baseDynFreqVal; flag.report = true; } - else - SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " [", C('L'), "] frequency scaling."); - } - #endif + #endif - // Parse Z zeta parameter - if (parser.seenval('O')) { - const float val = parser.value_float(); - if (AXIS_IS_SHAPING(Z)) { - if (WITHIN(val, 0.01f, 1.0f)) { - ftMotion.cfg.zeta.z = val; - flag.update = true; + // Parse Z zeta parameter + if (seenI) { + if (AXIS_IS_SHAPING(Z)) { + if (goodZeta) { + ftMotion.cfg.zeta.z = zetaVal; + flag.update = true; + } } else - SERIAL_ECHOLNPGM("?Invalid ", C(STEPPER_C_NAME), " zeta [", C('O'), "] value."); // Zeta out of range + SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " zeta parameter."); } - else - SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " zeta parameter."); - } - // Parse Z vtol parameter - if (parser.seenval('T')) { - const float val = parser.value_float(); - if (AXIS_IS_EISHAPING(Z)) { - if (WITHIN(val, 0.00f, 1.0f)) { - ftMotion.cfg.vtol.z = val; - flag.update = true; + // Parse Z vtol parameter + if (seenQ) { + if (AXIS_IS_EISHAPING(Z)) { + if (goodVtol) { + ftMotion.cfg.vtol.z = vtolVal; + flag.update = true; + } } else - SERIAL_ECHOLNPGM("?Invalid ", C(STEPPER_C_NAME), " vtol [", C('T'), "] value."); // VTol out of range. + SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " vtol parameter."); } - else - SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " vtol parameter."); } #endif // FTM_SHAPER_Z #if ENABLED(FTM_SHAPER_E) - // Parse E frequency parameter - if (parser.seenval('W')) { - if (AXIS_IS_SHAPING(E)) { - const float val = parser.value_float(); - if (WITHIN(val, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2)) { - ftMotion.cfg.baseFreq.e = val; - flag.update = flag.report = true; - } - else // Frequency out of range. - SERIAL_ECHOLNPGM("?Invalid ", C('E'), " frequency [", C('W'), "] value."); - } - else // Mode doesn't use frequency. - SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " [", C('W'), "] frequency."); - } + if (parser.seen_test('E')) { - #if HAS_DYNAMIC_FREQ - // Parse E frequency scaling parameter - if (parser.seenval('N')) { - if (modeUsesDynFreq) { - ftMotion.cfg.dynFreqK.e = parser.value_float(); + // Parse E frequency parameter + if (seenA) { + if (AXIS_IS_SHAPING(E)) { + if (goodBaseFreq) { + ftMotion.cfg.baseFreq.e = baseFreqVal; + flag.update = flag.report = true; + } + } + else // Mode doesn't use frequency. + SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " [A] frequency."); + } + + #if HAS_DYNAMIC_FREQ + // Parse E frequency scaling parameter + if (seenF && modeUsesDynFreq) { + ftMotion.cfg.dynFreqK.e = baseDynFreqVal; flag.report = true; } - else - SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " [", C('N'), "] frequency scaling."); - } - #endif + #endif - // Parse E zeta parameter - if (parser.seenval('U')) { - const float val = parser.value_float(); - if (AXIS_IS_SHAPING(E)) { - if (WITHIN(val, 0.01f, 1.0f)) { - ftMotion.cfg.zeta.e = val; - flag.update = true; + // Parse E zeta parameter + if (seenI) { + if (AXIS_IS_SHAPING(E)) { + if (goodZeta) { + ftMotion.cfg.zeta.e = zetaVal; + flag.update = true; + } } else - SERIAL_ECHOLNPGM("?Invalid ", C('E'), " zeta [", C('U'), "] value."); // Zeta out of range + SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " zeta parameter."); } - else - SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " zeta parameter."); - } - // Parse E vtol parameter - if (parser.seenval('V')) { - const float val = parser.value_float(); - if (AXIS_IS_EISHAPING(E)) { - if (WITHIN(val, 0.00f, 1.0f)) { - ftMotion.cfg.vtol.e = val; - flag.update = true; + // Parse E vtol parameter + if (seenQ) { + if (AXIS_IS_EISHAPING(E)) { + if (goodVtol) { + ftMotion.cfg.vtol.e = vtolVal; + flag.update = true; + } } else - SERIAL_ECHOLNPGM("?Invalid ", C('E'), " vtol [", C('V'), "] value."); // VTol out of range. + SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " vtol parameter."); } - else - SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " vtol parameter."); } #endif // FTM_SHAPER_E diff --git a/Marlin/src/module/ft_motion.h b/Marlin/src/module/ft_motion.h index dfe10282e1..4254680fbf 100644 --- a/Marlin/src/module/ft_motion.h +++ b/Marlin/src/module/ft_motion.h @@ -31,6 +31,8 @@ #include "ft_motion/poly5_trajectory_generator.h" #include "ft_motion/poly6_trajectory_generator.h" +#define FTM_VERSION 2 // Change version when hosts need to know + #if HAS_X_AXIS && (HAS_Z_AXIS || HAS_EXTRUDERS) #define HAS_DYNAMIC_FREQ 1 #if HAS_Z_AXIS