From 3ee18bc6676e00e31aec06246d7982bcd70b46a6 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 2 Dec 2025 16:10:49 -0600 Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20FT=20Motion?= =?UTF-8?q?=20accessors,=20G-code=20style?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/src/gcode/calibrate/G28.cpp | 7 +- Marlin/src/gcode/feature/ft_motion/M493.cpp | 88 ++++++++++----------- Marlin/src/gcode/feature/ft_motion/M494.cpp | 24 +++--- Marlin/src/lcd/menu/menu_motion.cpp | 7 +- Marlin/src/module/ft_motion.cpp | 4 +- Marlin/src/module/ft_motion.h | 14 ++++ 6 files changed, 79 insertions(+), 65 deletions(-) diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp index 20b50cd7f1..4d3d7841e7 100644 --- a/Marlin/src/gcode/calibrate/G28.cpp +++ b/Marlin/src/gcode/calibrate/G28.cpp @@ -129,15 +129,14 @@ #if ENABLED(Z_SAFE_HOMING) inline void home_z_safely() { - - // Potentially disable Fixed-Time Motion for homing - TERN_(FT_MOTION, FTM_DISABLE_IN_SCOPE()); - DEBUG_SECTION(log_G28, "home_z_safely", DEBUGGING(LEVELING)); // Disallow Z homing if X or Y homing is needed if (homing_needed_error(_BV(X_AXIS) | _BV(Y_AXIS))) return; + // Potentially disable Fixed-Time Motion for homing + TERN_(FT_MOTION, FTM_DISABLE_IN_SCOPE()); + sync_plan_position(); /** diff --git a/Marlin/src/gcode/feature/ft_motion/M493.cpp b/Marlin/src/gcode/feature/ft_motion/M493.cpp index 6696ae64af..e3f4bea8cb 100644 --- a/Marlin/src/gcode/feature/ft_motion/M493.cpp +++ b/Marlin/src/gcode/feature/ft_motion/M493.cpp @@ -208,12 +208,14 @@ void GcodeSuite::M493() { if (!parser.seen_any()) flag.report = true; + ft_config_t &c = ftMotion.cfg; + // Parse 'S' mode parameter. if (parser.seen('S')) { const bool active = parser.value_bool(); - if (active != ftMotion.cfg.active) { + if (active != c.active) { stepper.ftMotion_syncPosition(); - ftMotion.cfg.active = active; + c.active = active; flag.report = true; } } @@ -228,8 +230,8 @@ void GcodeSuite::M493() { return; } auto set_shaper = [&](const AxisEnum axis, ftMotionShaper_t newsh) { - if (newsh != ftMotion.cfg.shaper[axis]) { - ftMotion.cfg.shaper[axis] = newsh; + if (newsh != c.shaper[axis]) { + c.shaper[axis] = newsh; flag.update = flag.report = true; } }; @@ -243,8 +245,8 @@ void GcodeSuite::M493() { // 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; + if (enabled != c.axis_sync_enabled) { + c.axis_sync_enabled = enabled; flag.report = true; } } @@ -263,7 +265,7 @@ void GcodeSuite::M493() { case dynFreqMode_MASS_BASED: #endif case dynFreqMode_DISABLED: - ftMotion.cfg.dynFreqMode = val; + c.dynFreqMode = val; flag.report = true; break; default: @@ -271,22 +273,18 @@ void GcodeSuite::M493() { break; } } - else { - SERIAL_ECHOLNPGM("?Wrong shaper for (D)ynamic Frequency Mode ", ftMotion.cfg.dynFreqMode, "."); - } + else + SERIAL_ECHOLNPGM("?Shaper required for (D)ynamic Frequency Mode ", c.dynFreqMode, "."); } - const bool modeUsesDynFreq = ( - TERN0(HAS_DYNAMIC_FREQ_MM, ftMotion.cfg.dynFreqMode == dynFreqMode_Z_BASED) - || TERN0(HAS_DYNAMIC_FREQ_G, ftMotion.cfg.dynFreqMode == dynFreqMode_MASS_BASED) - ); + const bool modeUsesDynFreq = c.modeUsesDynFreq(); #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); + const bool goodBaseFreq = seenA && c.goodBaseFreq(baseFreqVal); if (seenA && !goodBaseFreq) SERIAL_ECHOLN(F("?Invalid "), F("(A) Base Frequency value. ("), int(FTM_MIN_SHAPE_FREQ), C('-'), int((FTM_FS) / 2), C(')')); @@ -301,14 +299,14 @@ void GcodeSuite::M493() { // 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); + const bool goodZeta = seenI && c.goodZeta(zetaVal); if (seenI && !goodZeta) SERIAL_ECHOLN(F("?Invalid "), F("(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); + const bool goodVtol = seenQ && c.goodVtol(vtolVal); if (seenQ && !goodVtol) SERIAL_ECHOLN(F("?Invalid "), F("(Q) Vibration Tolerance value. (0.0-1.0)")); // VTol out of range @@ -323,18 +321,18 @@ void GcodeSuite::M493() { 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; + c.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."); + 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; + c.dynFreqK.x = baseDynFreqVal; flag.report = true; } #endif @@ -343,24 +341,24 @@ void GcodeSuite::M493() { if (seenI) { if (AXIS_IS_SHAPING(X)) { if (goodZeta) { - ftMotion.cfg.zeta.x = zetaVal; + c.zeta.x = zetaVal; flag.update = true; } } else - SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " zeta parameter."); + SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " (I) zeta parameter."); } // Parse X vtol parameter if (seenQ) { if (AXIS_IS_EISHAPING(X)) { if (goodVtol) { - ftMotion.cfg.vtol.x = vtolVal; + c.vtol.x = vtolVal; flag.update = true; } } else - SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " vtol parameter."); + SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " (Q) vtol parameter."); } } @@ -374,18 +372,18 @@ void GcodeSuite::M493() { if (seenA) { if (AXIS_IS_SHAPING(Y)) { if (goodBaseFreq) { - ftMotion.cfg.baseFreq.y = baseFreqVal; + c.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."); + 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; + c.dynFreqK.y = baseDynFreqVal; flag.report = true; } #endif @@ -394,24 +392,24 @@ void GcodeSuite::M493() { if (seenI) { if (AXIS_IS_SHAPING(Y)) { if (goodZeta) { - ftMotion.cfg.zeta.y = zetaVal; + c.zeta.y = zetaVal; flag.update = true; } } else - SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " zeta parameter."); + SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " (I) zeta parameter."); } // Parse Y vtol parameter if (seenQ) { if (AXIS_IS_EISHAPING(Y)) { if (goodVtol) { - ftMotion.cfg.vtol.y = vtolVal; + c.vtol.y = vtolVal; flag.update = true; } } else - SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " vtol parameter."); + SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " (Q) vtol parameter."); } } @@ -425,18 +423,18 @@ void GcodeSuite::M493() { if (seenA) { if (AXIS_IS_SHAPING(Z)) { if (goodBaseFreq) { - ftMotion.cfg.baseFreq.z = baseFreqVal; + c.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."); + 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; + c.dynFreqK.z = baseDynFreqVal; flag.report = true; } #endif @@ -445,24 +443,24 @@ void GcodeSuite::M493() { if (seenI) { if (AXIS_IS_SHAPING(Z)) { if (goodZeta) { - ftMotion.cfg.zeta.z = zetaVal; + c.zeta.z = zetaVal; flag.update = true; } } else - SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " zeta parameter."); + SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " (I) zeta parameter."); } // Parse Z vtol parameter if (seenQ) { if (AXIS_IS_EISHAPING(Z)) { if (goodVtol) { - ftMotion.cfg.vtol.z = vtolVal; + c.vtol.z = vtolVal; flag.update = true; } } else - SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " vtol parameter."); + SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " (Q) vtol parameter."); } } @@ -476,18 +474,18 @@ void GcodeSuite::M493() { if (seenA) { if (AXIS_IS_SHAPING(E)) { if (goodBaseFreq) { - ftMotion.cfg.baseFreq.e = baseFreqVal; + c.baseFreq.e = baseFreqVal; flag.update = flag.report = true; } } else // Mode doesn't use frequency. - SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " [A] 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; + c.dynFreqK.e = baseDynFreqVal; flag.report = true; } #endif @@ -496,24 +494,24 @@ void GcodeSuite::M493() { if (seenI) { if (AXIS_IS_SHAPING(E)) { if (goodZeta) { - ftMotion.cfg.zeta.e = zetaVal; + c.zeta.e = zetaVal; flag.update = true; } } else - SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " zeta parameter."); + SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " (I) zeta parameter."); } // Parse E vtol parameter if (seenQ) { if (AXIS_IS_EISHAPING(E)) { if (goodVtol) { - ftMotion.cfg.vtol.e = vtolVal; + c.vtol.e = vtolVal; flag.update = true; } } else - SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " vtol parameter."); + SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " (Q) vtol parameter."); } } diff --git a/Marlin/src/gcode/feature/ft_motion/M494.cpp b/Marlin/src/gcode/feature/ft_motion/M494.cpp index 6573716b6d..26d2b7d2b8 100644 --- a/Marlin/src/gcode/feature/ft_motion/M494.cpp +++ b/Marlin/src/gcode/feature/ft_motion/M494.cpp @@ -55,19 +55,18 @@ void GcodeSuite::M494_report(const bool forReplay/*=true*/) { SERIAL_ECHOPGM(" M494 T", (uint8_t)ftMotion.getTrajectoryType()); #if ENABLED(FTM_SMOOTHING) - SERIAL_ECHOPGM( - CARTES_PAIRED_LIST( - " X", c.smoothingTime.X, " Y", c.smoothingTime.Y, - " Z", c.smoothingTime.Z, " E", c.smoothingTime.E - ) - ); - #endif // FTM_SMOOTHING + SERIAL_ECHOPGM(CARTES_PAIRED_LIST( + " X", c.smoothingTime.X, + " Y", c.smoothingTime.Y, + " Z", c.smoothingTime.Z, + " E", c.smoothingTime.E + )); + #endif #if ENABLED(FTM_POLYS) - if (ftMotion.getTrajectoryType() == TrajectoryType::POLY6) SERIAL_ECHOPGM(" O", c.poly6_acceleration_overshoot); - #endif // FTM_POLYS + #endif SERIAL_EOL(); } @@ -97,8 +96,9 @@ void GcodeSuite::M494() { report = true; } else - SERIAL_ECHOLN(F("?Invalid "), F("trajectory type [T] value. Use 0=TRAPEZOIDAL, 1=POLY5, 2=POLY6")); + SERIAL_ECHOLN(F("?Invalid "), F("(T)rajectory type value. Use 0=TRAPEZOIDAL, 1=POLY5, 2=POLY6")); } + // Parse overshoot parameter. if (parser.seenval('O')) { const float val = parser.value_float(); @@ -107,7 +107,7 @@ void GcodeSuite::M494() { report = true; } else - SERIAL_ECHOLN(F("?Invalid "), F("overshoot [O] value. Range 1.25-1.875")); + SERIAL_ECHOLN(F("?Invalid "), F("(O)vershoot value. Range 1.25-1.875")); } #endif // FTM_POLYS @@ -122,7 +122,7 @@ void GcodeSuite::M494() { report = true; \ } \ else \ - SERIAL_ECHOLNPGM("?Invalid ", C(N), " smoothing time [", C(CHARIFY(A)), "] value."); \ + SERIAL_ECHOLNPGM("?Invalid ", C(N), " smoothing time (", C(CHARIFY(A)), ") value."); \ } CARTES_GANG( diff --git a/Marlin/src/lcd/menu/menu_motion.cpp b/Marlin/src/lcd/menu/menu_motion.cpp index 4cc22f6c3b..8f644361f4 100644 --- a/Marlin/src/lcd/menu/menu_motion.cpp +++ b/Marlin/src/lcd/menu/menu_motion.cpp @@ -542,6 +542,7 @@ void menu_move() { } // menu_ft_motion void menu_tune_ft_motion() { + // Define stuff ahead of the menu loop ft_config_t &c = ftMotion.cfg; @@ -551,10 +552,10 @@ void menu_move() { // For U8G paged rendering check and skip extra string copy #if HAS_X_AXIS - MString<20> shaper_name; #if CACHE_FOR_SPEED int8_t prev_a = -1; #endif + MString<20> shaper_name; auto _shaper_name = [&](const AxisEnum a) { if (TERN1(CACHE_FOR_SPEED, a != prev_a)) { TERN_(CACHE_FOR_SPEED, prev_a = a); @@ -565,10 +566,10 @@ void menu_move() { #endif #if HAS_DYNAMIC_FREQ - MString<20> dmode; #if CACHE_FOR_SPEED bool got_d = false; #endif + MString<20> dmode; auto _dmode = [&]{ if (TERN1(CACHE_FOR_SPEED, !got_d)) { TERN_(CACHE_FOR_SPEED, got_d = true); @@ -579,10 +580,10 @@ void menu_move() { #endif #if ENABLED(FTM_POLYS) - MString<20> traj_name; #if CACHE_FOR_SPEED bool got_t = false; #endif + MString<20> traj_name; auto _traj_name = [&]{ if (TERN1(CACHE_FOR_SPEED, !got_t)) { TERN_(CACHE_FOR_SPEED, got_t = true); diff --git a/Marlin/src/module/ft_motion.cpp b/Marlin/src/module/ft_motion.cpp index 2310b111ed..d402439c04 100644 --- a/Marlin/src/module/ft_motion.cpp +++ b/Marlin/src/module/ft_motion.cpp @@ -81,7 +81,9 @@ TrapezoidalTrajectoryGenerator FTMotion::trapezoidalGenerator; #endif // Resonance Test -TERN_(FTM_RESONANCE_TEST,ResonanceGenerator FTMotion::rtg;) // Resonance trajectory generator instance +#if ENABLED(FTM_RESONANCE_TEST) + ResonanceGenerator FTMotion::rtg; // Resonance trajectory generator instance +#endif #if FTM_HAS_LIN_ADVANCE bool FTMotion::use_advance_lead; diff --git a/Marlin/src/module/ft_motion.h b/Marlin/src/module/ft_motion.h index 60f3a67b9a..497c04e474 100644 --- a/Marlin/src/module/ft_motion.h +++ b/Marlin/src/module/ft_motion.h @@ -90,6 +90,20 @@ typedef struct FTConfig { #else static constexpr TrajectoryType trajectory_type = TrajectoryType::TRAPEZOIDAL; #endif + + #if HAS_FTM_SHAPING + constexpr bool goodZeta(const float z) { return WITHIN(z, 0.01f, 1.0f); } + constexpr bool goodVtol(const float v) { return WITHIN(v, 0.00f, 1.0f); } + #if HAS_DYNAMIC_FREQ + bool modeUsesDynFreq() const { + return (TERN0(HAS_DYNAMIC_FREQ_MM, dynFreqMode == dynFreqMode_Z_BASED) + || TERN0(HAS_DYNAMIC_FREQ_G, dynFreqMode == dynFreqMode_MASS_BASED)); + } + #endif + #endif // HAS_FTM_SHAPING + + constexpr bool goodBaseFreq(const float f) { return WITHIN(f, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2); } + } ft_config_t; /**