From ed66f498eb713f59f14d000f8bfa550b34ce8528 Mon Sep 17 00:00:00 2001 From: Scott Lahteine <thinkyhead@users.noreply.github.com> Date: Tue, 16 May 2023 02:38:24 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=B8=20Fixed-Time=20Motion=20EEPROM=20a?= =?UTF-8?q?nd=20Menu=20(#25835)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Marlin/Configuration_adv.h | 2 + Marlin/src/core/language.h | 1 + Marlin/src/gcode/feature/ft_motion/M493.cpp | 290 +++++++++++------- Marlin/src/gcode/gcode.h | 1 + .../ftdi_eve_touch_ui/language/language_en.h | 1 - Marlin/src/lcd/language/language_en.h | 17 + Marlin/src/lcd/menu/menu_motion.cpp | 136 ++++++++ Marlin/src/module/ft_motion.cpp | 68 ++-- Marlin/src/module/ft_motion.h | 68 +++- Marlin/src/module/ft_types.h | 4 +- Marlin/src/module/planner.cpp | 8 +- Marlin/src/module/settings.cpp | 47 ++- Marlin/src/module/stepper.cpp | 2 +- buildroot/tests/STM32F103RC_btt | 2 +- 14 files changed, 474 insertions(+), 173 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 587a368301d..b68557cb289 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -1148,6 +1148,8 @@ // This value may be configured to adjust duration to consume the command buffer. // Try increasing this value if stepper motion is not smooth. #define FTM_STEPPERCMD_BUFF_SIZE 1000 // Size of the stepper command buffers. + + //#define FT_MOTION_MENU // Provide a MarlinUI menu to set M493 parameters. #endif /** diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h index c951012b6df..388e7cd820e 100644 --- a/Marlin/src/core/language.h +++ b/Marlin/src/core/language.h @@ -277,6 +277,7 @@ // Settings Report Strings #define STR_Z_AUTO_ALIGN "Z Auto-Align" #define STR_BACKLASH_COMPENSATION "Backlash compensation" +#define STR_FT_MOTION "Fixed-Time Motion" #define STR_S_SEG_PER_SEC "S<seg-per-sec>" #define STR_DELTA_SETTINGS "Delta (L<diagonal-rod> R<radius> H<height> S<seg-per-sec> XYZ<tower-angle-trim> ABC<rod-trim>)" #define STR_SCARA_SETTINGS "SCARA" diff --git a/Marlin/src/gcode/feature/ft_motion/M493.cpp b/Marlin/src/gcode/feature/ft_motion/M493.cpp index f7b8f1e752c..83c6a9a5dac 100644 --- a/Marlin/src/gcode/feature/ft_motion/M493.cpp +++ b/Marlin/src/gcode/feature/ft_motion/M493.cpp @@ -28,26 +28,109 @@ #include "../../../module/ft_motion.h" void say_shaping() { - SERIAL_ECHO_TERNARY(fxdTiCtrl.cfg_mode, "Fixed time controller ", "en", "dis", "abled"); - if (fxdTiCtrl.cfg_mode == ftMotionMode_DISABLED || fxdTiCtrl.cfg_mode == ftMotionMode_ENABLED) { - SERIAL_ECHOLNPGM("."); - return; - } + // FT Enabled + SERIAL_ECHO_TERNARY(fxdTiCtrl.cfg.mode, "Fixed-Time Motion ", "en", "dis", "abled"); + + // FT Shaping #if HAS_X_AXIS - SERIAL_ECHOPGM(" with "); - switch (fxdTiCtrl.cfg_mode) { - default: break; - //case ftMotionMode_ULENDO_FBS: SERIAL_ECHOLNPGM("Ulendo FBS."); return; - case ftMotionMode_ZV: SERIAL_ECHOLNPGM("ZV"); break; - case ftMotionMode_ZVD: SERIAL_ECHOLNPGM("ZVD"); break; - case ftMotionMode_EI: SERIAL_ECHOLNPGM("EI"); break; - case ftMotionMode_2HEI: SERIAL_ECHOLNPGM("2 Hump EI"); break; - case ftMotionMode_3HEI: SERIAL_ECHOLNPGM("3 Hump EI"); break; - case ftMotionMode_MZV: SERIAL_ECHOLNPGM("MZV"); break; - //case ftMotionMode_DISCTF: SERIAL_ECHOLNPGM("discrete transfer functions"); break; + if (fxdTiCtrl.cfg.mode > ftMotionMode_ENABLED) { + SERIAL_ECHOPGM(" with "); + switch (fxdTiCtrl.cfg.mode) { + default: break; + case ftMotionMode_ZV: SERIAL_ECHOPGM("ZV"); break; + case ftMotionMode_ZVD: SERIAL_ECHOPGM("ZVD"); break; + case ftMotionMode_EI: SERIAL_ECHOPGM("EI"); break; + case ftMotionMode_2HEI: SERIAL_ECHOPGM("2 Hump EI"); break; + case ftMotionMode_3HEI: SERIAL_ECHOPGM("3 Hump EI"); break; + case ftMotionMode_MZV: SERIAL_ECHOPGM("MZV"); break; + //case ftMotionMode_DISCTF: SERIAL_ECHOPGM("discrete transfer functions"); break; + //case ftMotionMode_ULENDO_FBS: SERIAL_ECHOPGM("Ulendo FBS."); return; + } + SERIAL_ECHOPGM(" shaping"); } - SERIAL_ECHOLNPGM(" shaping."); #endif + SERIAL_ECHOLNPGM("."); + + const bool z_based = TERN0(HAS_DYNAMIC_FREQ_MM, fxdTiCtrl.cfg.dynFreqMode == dynFreqMode_Z_BASED), + g_based = TERN0(HAS_DYNAMIC_FREQ_G, fxdTiCtrl.cfg.dynFreqMode == dynFreqMode_MASS_BASED), + dynamic = z_based || g_based; + + // FT Dynamic Frequency Mode + if (fxdTiCtrl.cfg.modeHasShaper()) { + #if HAS_DYNAMIC_FREQ + SERIAL_ECHOPGM("Dynamic Frequency Mode "); + switch (fxdTiCtrl.cfg.dynFreqMode) { + default: + case dynFreqMode_DISABLED: SERIAL_ECHOPGM("disabled"); break; + #if HAS_DYNAMIC_FREQ_MM + case dynFreqMode_Z_BASED: SERIAL_ECHOPGM("Z-based"); break; + #endif + #if HAS_DYNAMIC_FREQ_G + case dynFreqMode_MASS_BASED: SERIAL_ECHOPGM("Mass-based"); break; + #endif + } + SERIAL_ECHOLNPGM("."); + #endif + + #if HAS_X_AXIS + SERIAL_ECHO_TERNARY(dynamic, "X/A ", "base dynamic", "static", " compensator frequency: "); + SERIAL_ECHO_F(fxdTiCtrl.cfg.baseFreq[X_AXIS], 2); + SERIAL_ECHOPGM("Hz"); + #if HAS_DYNAMIC_FREQ + if (dynamic) { + SERIAL_ECHOPGM(" scaling: "); + SERIAL_ECHO_F(fxdTiCtrl.cfg.dynFreqK[X_AXIS], 8); + serial_ternary(F("Hz/"), z_based, F("mm"), F("g")); + } + #endif + SERIAL_EOL(); + #endif + + #if HAS_Y_AXIS + SERIAL_ECHO_TERNARY(dynamic, "Y/B ", "base dynamic", "static", " compensator frequency: "); + SERIAL_ECHO_F(fxdTiCtrl.cfg.baseFreq[Y_AXIS], 2); + SERIAL_ECHOLNPGM(" Hz"); + #if HAS_DYNAMIC_FREQ + if (dynamic) { + SERIAL_ECHOPGM(" scaling: "); + SERIAL_ECHO_F(fxdTiCtrl.cfg.dynFreqK[Y_AXIS], 8); + serial_ternary(F("Hz/"), z_based, F("mm"), F("g")); + } + #endif + SERIAL_EOL(); + #endif + } + + #if HAS_EXTRUDERS + SERIAL_ECHO_TERNARY(fxdTiCtrl.cfg.linearAdvEna, "Linear Advance ", "en", "dis", "abled"); + SERIAL_ECHOLNPGM(". Gain: "); SERIAL_ECHO_F(fxdTiCtrl.cfg.linearAdvK, 5); + #endif + +} + +void GcodeSuite::M493_report(const bool forReplay/*=true*/) { + report_heading_etc(forReplay, F(STR_FT_MOTION)); + const ft_config_t &c = fxdTiCtrl.cfg; + SERIAL_ECHOPGM(" M493 S", c.mode); + #if HAS_X_AXIS + SERIAL_ECHOPGM(" A", c.baseFreq[X_AXIS]); + #if HAS_Y_AXIS + SERIAL_ECHOPGM(" B", c.baseFreq[Y_AXIS]); + #endif + #endif + #if HAS_DYNAMIC_FREQ + SERIAL_ECHOPGM(" D", c.dynFreqMode); + #if HAS_X_AXIS + SERIAL_ECHOPGM(" F", c.dynFreqK[X_AXIS]); + #if HAS_Y_AXIS + SERIAL_ECHOPGM(" H", c.dynFreqK[Y_AXIS]); + #endif + #endif + #endif + #if HAS_EXTRUDERS + SERIAL_ECHOPGM(" P", c.linearAdvEna, " K", c.linearAdvK); + #endif + SERIAL_EOL(); } /** @@ -79,29 +162,36 @@ void say_shaping() { * H<Hz> Set frequency scaling for the Y axis */ void GcodeSuite::M493() { + struct { bool update_n:1, update_a:1, reset_ft:1, report_h:1; } flag = { false }; + + if (!parser.seen_any()) flag.report_h = true; + // Parse 'S' mode parameter. if (parser.seenval('S')) { - const ftMotionMode_t val = (ftMotionMode_t)parser.value_byte(); - switch (val) { - case ftMotionMode_DISABLED: - case ftMotionMode_ENABLED: + const ftMotionMode_t oldmm = fxdTiCtrl.cfg.mode, + newmm = (ftMotionMode_t)parser.value_byte(); + switch (newmm) { #if HAS_X_AXIS + case ftMotionMode_ZV: case ftMotionMode_ZVD: case ftMotionMode_2HEI: case ftMotionMode_3HEI: case ftMotionMode_MZV: //case ftMotionMode_ULENDO_FBS: //case ftMotionMode_DISCTF: - fxdTiCtrl.cfg_mode = val; - say_shaping(); - break; #endif + case ftMotionMode_DISABLED: + case ftMotionMode_ENABLED: + fxdTiCtrl.cfg.mode = newmm; + flag.report_h = true; + break; default: SERIAL_ECHOLNPGM("?Invalid control mode [M] value."); return; } - switch (val) { + if (fxdTiCtrl.cfg.mode != oldmm) switch (newmm) { + default: break; #if HAS_X_AXIS //case ftMotionMode_ULENDO_FBS: //case ftMotionMode_DISCTF: @@ -112,15 +202,11 @@ void GcodeSuite::M493() { case ftMotionMode_2HEI: case ftMotionMode_3HEI: case ftMotionMode_MZV: - fxdTiCtrl.updateShapingN(fxdTiCtrl.cfg_baseFreq[0] OPTARG(HAS_Y_AXIS, fxdTiCtrl.cfg_baseFreq[1])); - fxdTiCtrl.updateShapingA(); - fxdTiCtrl.reset(); - break; + flag.update_n = flag.update_a = true; #endif case ftMotionMode_ENABLED: - fxdTiCtrl.reset(); + flag.reset_ft = true; break; - default: break; } } @@ -129,47 +215,44 @@ void GcodeSuite::M493() { // Pressure control (linear advance) parameter. if (parser.seen('P')) { const bool val = parser.value_bool(); - fxdTiCtrl.cfg_linearAdvEna = val; - SERIAL_ECHO_TERNARY(val, "Pressure control: Linear Advance ", "en", "dis", "abled.\n"); + fxdTiCtrl.cfg.linearAdvEna = val; + SERIAL_ECHO_TERNARY(val, "Linear Advance ", "en", "dis", "abled.\n"); } // Pressure control (linear advance) gain parameter. if (parser.seenval('K')) { const float val = parser.value_float(); if (val >= 0.0f) { - fxdTiCtrl.cfg_linearAdvK = val; - SERIAL_ECHOPGM("Pressure control: Linear Advance gain set to: "); - SERIAL_ECHO_F(val, 5); - SERIAL_ECHOLNPGM("."); - } - else { // Value out of range. - SERIAL_ECHOLNPGM("Pressure control: Linear Advance gain out of range."); + fxdTiCtrl.cfg.linearAdvK = val; + flag.report_h = true; } + else // Value out of range. + SERIAL_ECHOLNPGM("Linear Advance gain out of range."); } #endif // HAS_EXTRUDERS - #if HAS_Z_AXIS || HAS_EXTRUDERS + #if HAS_DYNAMIC_FREQ // Dynamic frequency mode parameter. if (parser.seenval('D')) { - if (WITHIN(fxdTiCtrl.cfg_mode, 10U, 19U)) { + if (fxdTiCtrl.cfg.modeHasShaper()) { const dynFreqMode_t val = dynFreqMode_t(parser.value_byte()); switch (val) { case dynFreqMode_DISABLED: - fxdTiCtrl.cfg_dynFreqMode = val; - SERIAL_ECHOLNPGM("Dynamic frequency mode disabled."); + fxdTiCtrl.cfg.dynFreqMode = val; + flag.report_h = true; break; - #if HAS_Z_AXIS + #if HAS_DYNAMIC_FREQ_MM case dynFreqMode_Z_BASED: - fxdTiCtrl.cfg_dynFreqMode = val; - SERIAL_ECHOLNPGM("Z-based Dynamic Frequency Mode."); + fxdTiCtrl.cfg.dynFreqMode = val; + flag.report_h = true; break; #endif - #if HAS_EXTRUDERS + #if HAS_DYNAMIC_FREQ_G case dynFreqMode_MASS_BASED: - fxdTiCtrl.cfg_dynFreqMode = val; - SERIAL_ECHOLNPGM("Mass-based Dynamic Frequency Mode."); + fxdTiCtrl.cfg.dynFreqMode = val; + flag.report_h = true; break; #endif default: @@ -178,58 +261,46 @@ void GcodeSuite::M493() { } } else { - SERIAL_ECHOLNPGM("Incompatible shaper for [D] Dynamic Frequency mode."); + SERIAL_ECHOLNPGM("?Wrong shaper for [D] Dynamic Frequency mode."); } } - #endif // HAS_Z_AXIS || HAS_EXTRUDERS + const bool modeUsesDynFreq = ( + TERN0(HAS_DYNAMIC_FREQ_MM, fxdTiCtrl.cfg.dynFreqMode == dynFreqMode_Z_BASED) + || TERN0(HAS_DYNAMIC_FREQ_G, fxdTiCtrl.cfg.dynFreqMode == dynFreqMode_MASS_BASED) + ); + + #endif // HAS_DYNAMIC_FREQ #if HAS_X_AXIS // Parse frequency parameter (X axis). if (parser.seenval('A')) { - if (WITHIN(fxdTiCtrl.cfg_mode, 10U, 19U)) { + if (fxdTiCtrl.cfg.modeHasShaper()) { const float val = parser.value_float(); - const bool frequencyInRange = WITHIN(val, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2); // TODO: Frequency minimum is dependent on the shaper used; the above check isn't always correct. - if (frequencyInRange) { - fxdTiCtrl.cfg_baseFreq[0] = val; - fxdTiCtrl.updateShapingN(fxdTiCtrl.cfg_baseFreq[0] OPTARG(HAS_Y_AXIS, fxdTiCtrl.cfg_baseFreq[1])); - fxdTiCtrl.reset(); - if (fxdTiCtrl.cfg_dynFreqMode) { SERIAL_ECHOPGM("Compensator base dynamic frequency (X/A axis) set to:"); } - else { SERIAL_ECHOPGM("Compensator static frequency (X/A axis) set to: "); } - SERIAL_ECHO_F(fxdTiCtrl.cfg_baseFreq[0], 2); - SERIAL_ECHOLNPGM("."); - } - else { // Frequency out of range. - SERIAL_ECHOLNPGM("Invalid [A] frequency value."); + if (WITHIN(val, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2)) { + fxdTiCtrl.cfg.baseFreq[X_AXIS] = val; + flag.update_n = flag.reset_ft = flag.report_h = true; } + else // Frequency out of range. + SERIAL_ECHOLNPGM("Invalid [", AS_CHAR('A'), "] frequency value."); } - else { // Mode doesn't use frequency. - SERIAL_ECHOLNPGM("Incompatible mode for [A] frequency."); - } + else // Mode doesn't use frequency. + SERIAL_ECHOLNPGM("Wrong mode for [", AS_CHAR('A'), "] frequency."); } - #if HAS_Z_AXIS || HAS_EXTRUDERS + #if HAS_DYNAMIC_FREQ // Parse frequency scaling parameter (X axis). if (parser.seenval('F')) { - const bool modeUsesDynFreq = ( - TERN0(HAS_Z_AXIS, fxdTiCtrl.cfg_dynFreqMode == dynFreqMode_Z_BASED) - || TERN0(HAS_EXTRUDERS, fxdTiCtrl.cfg_dynFreqMode == dynFreqMode_MASS_BASED) - ); - if (modeUsesDynFreq) { - const float val = parser.value_float(); - fxdTiCtrl.cfg_dynFreqK[0] = val; - SERIAL_ECHOPGM("Frequency scaling (X/A axis) set to: "); - SERIAL_ECHO_F(fxdTiCtrl.cfg_dynFreqK[0], 8); - SERIAL_ECHOLNPGM("."); - } - else { - SERIAL_ECHOLNPGM("Incompatible mode for [F] frequency scaling."); + fxdTiCtrl.cfg.dynFreqK[X_AXIS] = parser.value_float(); + flag.report_h = true; } + else + SERIAL_ECHOLNPGM("Wrong mode for [", AS_CHAR('F'), "] frequency scaling."); } - #endif // HAS_Z_AXIS || HAS_EXTRUDERS + #endif #endif // HAS_X_AXIS @@ -237,49 +308,40 @@ void GcodeSuite::M493() { // Parse frequency parameter (Y axis). if (parser.seenval('B')) { - if (WITHIN(fxdTiCtrl.cfg_mode, 10U, 19U)) { + if (fxdTiCtrl.cfg.modeHasShaper()) { const float val = parser.value_float(); - const bool frequencyInRange = WITHIN(val, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2); - if (frequencyInRange) { - fxdTiCtrl.cfg_baseFreq[1] = val; - fxdTiCtrl.updateShapingN(fxdTiCtrl.cfg_baseFreq[0] OPTARG(HAS_Y_AXIS, fxdTiCtrl.cfg_baseFreq[1])); - fxdTiCtrl.reset(); - if (fxdTiCtrl.cfg_dynFreqMode) { SERIAL_ECHOPGM("Compensator base dynamic frequency (Y/B axis) set to:"); } - else { SERIAL_ECHOPGM("Compensator static frequency (Y/B axis) set to: "); } - SERIAL_ECHO_F(fxdTiCtrl.cfg_baseFreq[1], 2); - SERIAL_ECHOLNPGM("."); - } - else { // Frequency out of range. - SERIAL_ECHOLNPGM("Invalid frequency [B] value."); + if (WITHIN(val, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2)) { + fxdTiCtrl.cfg.baseFreq[Y_AXIS] = val; + flag.update_n = flag.reset_ft = flag.report_h = true; } + else // Frequency out of range. + SERIAL_ECHOLNPGM("Invalid frequency [", AS_CHAR('B'), "] value."); } - else { // Mode doesn't use frequency. - SERIAL_ECHOLNPGM("Incompatible mode for [B] frequency."); - } + else // Mode doesn't use frequency. + SERIAL_ECHOLNPGM("Wrong mode for [", AS_CHAR('B'), "] frequency."); } - #if HAS_Z_AXIS || HAS_EXTRUDERS + #if HAS_DYNAMIC_FREQ // Parse frequency scaling parameter (Y axis). if (parser.seenval('H')) { - const bool modeUsesDynFreq = ( - TERN0(HAS_Z_AXIS, fxdTiCtrl.cfg_dynFreqMode == dynFreqMode_Z_BASED) - || TERN0(HAS_EXTRUDERS, fxdTiCtrl.cfg_dynFreqMode == dynFreqMode_MASS_BASED) - ); - if (modeUsesDynFreq) { - const float val = parser.value_float(); - fxdTiCtrl.cfg_dynFreqK[1] = val; - SERIAL_ECHOPGM("Frequency scaling (Y/B axis) set to: "); - SERIAL_ECHO_F(val, 8); - SERIAL_ECHOLNPGM("."); - } - else { - SERIAL_ECHOLNPGM("Incompatible mode for [H] frequency scaling."); + fxdTiCtrl.cfg.dynFreqK[Y_AXIS] = parser.value_float(); + flag.report_h = true; } + else + SERIAL_ECHOLNPGM("Wrong mode for [", AS_CHAR('H'), "] frequency scaling."); } - #endif // HAS_Z_AXIS || HAS_EXTRUDERS + #endif #endif // HAS_Y_AXIS + + #if HAS_X_AXIS + if (flag.update_n) fxdTiCtrl.refreshShapingN(); + if (flag.update_a) fxdTiCtrl.updateShapingA(); + #endif + if (flag.reset_ft) fxdTiCtrl.reset(); + if (flag.report_h) say_shaping(); + } #endif // FT_MOTION diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index eb465ea7c39..9283a92e396 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -1047,6 +1047,7 @@ private: #if ENABLED(FT_MOTION) static void M493(); + static void M493_report(const bool forReplay=true); #endif static void M500(); diff --git a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/language/language_en.h b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/language/language_en.h index 05e625842ad..9c069d9d246 100644 --- a/Marlin/src/lcd/extui/ftdi_eve_touch_ui/language/language_en.h +++ b/Marlin/src/lcd/extui/ftdi_eve_touch_ui/language/language_en.h @@ -91,7 +91,6 @@ namespace Language_en { LSTR MSG_IDLE = u8"idle"; LSTR MSG_SET_MAXIMUM = u8"Set Maximum"; LSTR MSG_PRINT_SPEED = u8"Print Speed"; - LSTR MSG_LINEAR_ADVANCE = u8"Linear Advance"; LSTR MSG_LINEAR_ADVANCE_K = u8"K"; LSTR MSG_LINEAR_ADVANCE_K1 = u8"K E1"; LSTR MSG_LINEAR_ADVANCE_K2 = u8"K E2"; diff --git a/Marlin/src/lcd/language/language_en.h b/Marlin/src/lcd/language/language_en.h index 0cfd2f8beae..bc97407fc22 100644 --- a/Marlin/src/lcd/language/language_en.h +++ b/Marlin/src/lcd/language/language_en.h @@ -446,6 +446,7 @@ namespace Language_en { LSTR MSG_DRAW_MIN_Y = _UxGT("Draw Min Y"); LSTR MSG_DRAW_MAX_Y = _UxGT("Draw Max Y"); LSTR MSG_MAX_BELT_LEN = _UxGT("Max Belt Len"); + LSTR MSG_LINEAR_ADVANCE = _UxGT("Linear Advance"); LSTR MSG_ADVANCE_K = _UxGT("Advance K"); LSTR MSG_ADVANCE_K_E = _UxGT("Advance K *"); LSTR MSG_CONTRAST = _UxGT("LCD Contrast"); @@ -836,6 +837,22 @@ namespace Language_en { LSTR MSG_BACKLASH_CORRECTION = _UxGT("Correction"); LSTR MSG_BACKLASH_SMOOTHING = _UxGT("Smoothing"); + LSTR MSG_FIXED_TIME_MOTION = _UxGT("Fixed-Time Motion"); + LSTR MSG_FTM_MODE = _UxGT("Motion Mode:"); + LSTR MSG_FTM_ZV = _UxGT("ZV"); + LSTR MSG_FTM_ZVD = _UxGT("ZVD"); + LSTR MSG_FTM_EI = _UxGT("EI"); + LSTR MSG_FTM_2HEI = _UxGT("2HEI"); + LSTR MSG_FTM_3HEI = _UxGT("3HEI"); + LSTR MSG_FTM_MZV = _UxGT("MZV"); + //LSTR MSG_FTM_ULENDO_FBS = _UxGT("Ulendo FBS"); + //LSTR MSG_FTM_DISCTF = _UxGT("DISCTF"); + LSTR MSG_FTM_DYN_MODE = _UxGT("DF Mode:"); + LSTR MSG_FTM_Z_BASED = _UxGT("Z-based"); + LSTR MSG_FTM_MASS_BASED = _UxGT("Mass-based"); + LSTR MSG_FTM_BASE_FREQ_N = _UxGT("@ Base Freq."); + LSTR MSG_FTM_DFREQ_K_N = _UxGT("@ Dyn. Freq."); + LSTR MSG_LEVEL_X_AXIS = _UxGT("Level X Axis"); LSTR MSG_AUTO_CALIBRATE = _UxGT("Auto Calibrate"); #if ENABLED(TOUCH_UI_FTDI_EVE) diff --git a/Marlin/src/lcd/menu/menu_motion.cpp b/Marlin/src/lcd/menu/menu_motion.cpp index 8caa1e52640..bab03db6062 100644 --- a/Marlin/src/lcd/menu/menu_motion.cpp +++ b/Marlin/src/lcd/menu/menu_motion.cpp @@ -313,7 +313,136 @@ void menu_move() { void goto_tramming_wizard(); #endif +#if ENABLED(FT_MOTION_MENU) + + #include "../../module/ft_motion.h" + #include "../../gcode/gcode.h" + + void _M493_S(const ftMotionMode_t s) { + char cmd[10]; + sprintf_P(cmd, PSTR("M493S%i"), int(s)); + gcode.process_subcommands_now(cmd); + ui.go_back(); + } + + inline void menu_ftm_mode() { + const ftMotionMode_t mode = fxdTiCtrl.cfg.mode; + + START_MENU(); + BACK_ITEM(MSG_FIXED_TIME_MOTION); + + if (mode != ftMotionMode_DISABLED) ACTION_ITEM(MSG_LCD_OFF, []{ _M493_S(ftMotionMode_DISABLED); }); + if (mode != ftMotionMode_ENABLED) ACTION_ITEM(MSG_LCD_ON, []{ _M493_S(ftMotionMode_ENABLED); }); + #if HAS_X_AXIS + if (mode != ftMotionMode_ZV) ACTION_ITEM(MSG_FTM_ZV, []{ _M493_S(ftMotionMode_ZV); }); + if (mode != ftMotionMode_ZVD) ACTION_ITEM(MSG_FTM_ZVD, []{ _M493_S(ftMotionMode_ZVD); }); + if (mode != ftMotionMode_EI) ACTION_ITEM(MSG_FTM_EI, []{ _M493_S(ftMotionMode_EI); }); + if (mode != ftMotionMode_2HEI) ACTION_ITEM(MSG_FTM_2HEI, []{ _M493_S(ftMotionMode_2HEI); }); + if (mode != ftMotionMode_3HEI) ACTION_ITEM(MSG_FTM_3HEI, []{ _M493_S(ftMotionMode_3HEI); }); + if (mode != ftMotionMode_MZV) ACTION_ITEM(MSG_FTM_MZV, []{ _M493_S(ftMotionMode_MZV); }); + //if (mode != ftMotionMode_ULENDO_FBS) ACTION_ITEM(MSG_FTM_ULENDO_FBS, []{ _M493_S(ftMotionMode_ULENDO_FBS); }); + //if (mode != ftMotionMode_DISCTF) ACTION_ITEM(MSG_FTM_DISCTF, []{ _M493_S(ftMotionMode_DISCTF); }); + #endif + + END_MENU(); + } + + #if HAS_DYNAMIC_FREQ + + void _M493_D(const dynFreqMode_t d) { + char cmd[10]; + sprintf_P(cmd, PSTR("M493D%i"), int(d)); + gcode.process_subcommands_now(cmd); + ui.go_back(); + } + + inline void menu_ftm_dyn_mode() { + const dynFreqMode_t dmode = fxdTiCtrl.cfg.dynFreqMode; + + START_MENU(); + BACK_ITEM(MSG_FIXED_TIME_MOTION); + + if (dmode != dynFreqMode_DISABLED) ACTION_ITEM(MSG_LCD_OFF, []{ _M493_D(dynFreqMode_DISABLED); }); + #if HAS_DYNAMIC_FREQ_MM + if (dmode != dynFreqMode_Z_BASED) ACTION_ITEM(MSG_FTM_Z_BASED, []{ _M493_D(dynFreqMode_Z_BASED); }); + #endif + #if HAS_DYNAMIC_FREQ_G + if (dmode != dynFreqMode_MASS_BASED) ACTION_ITEM(MSG_FTM_MASS_BASED, []{ _M493_D(dynFreqMode_MASS_BASED); }); + #endif + + END_MENU(); + } + + #endif // HAS_DYNAMIC_FREQ + + void menu_ft_motion() { + ft_config_t &c = fxdTiCtrl.cfg; + + FSTR_P ftmode; + switch (c.mode) { + default: + case ftMotionMode_DISABLED: ftmode = GET_TEXT_F(MSG_LCD_OFF); break; + case ftMotionMode_ENABLED: ftmode = GET_TEXT_F(MSG_LCD_ON); break; + case ftMotionMode_ZV: ftmode = GET_TEXT_F(MSG_FTM_ZV); break; + case ftMotionMode_ZVD: ftmode = GET_TEXT_F(MSG_FTM_ZVD); break; + case ftMotionMode_EI: ftmode = GET_TEXT_F(MSG_FTM_EI); break; + case ftMotionMode_2HEI: ftmode = GET_TEXT_F(MSG_FTM_2HEI); break; + case ftMotionMode_3HEI: ftmode = GET_TEXT_F(MSG_FTM_3HEI); break; + case ftMotionMode_MZV: ftmode = GET_TEXT_F(MSG_FTM_MZV); break; + //case ftMotionMode_ULENDO_FBS: ftmode = GET_TEXT_F(MSG_FTM_ULENDO_FBS); break; + //case ftMotionMode_DISCTF: ftmode = GET_TEXT_F(MSG_FTM_DISCTF); break; + } + + #if HAS_DYNAMIC_FREQ + FSTR_P dmode; + switch (c.dynFreqMode) { + default: + case dynFreqMode_DISABLED: dmode = GET_TEXT_F(MSG_LCD_OFF); break; + case dynFreqMode_Z_BASED: dmode = GET_TEXT_F(MSG_FTM_Z_BASED); break; + case dynFreqMode_MASS_BASED: dmode = GET_TEXT_F(MSG_FTM_MASS_BASED); break; + } + #endif + + START_MENU(); + BACK_ITEM(MSG_ADVANCED_SETTINGS); + + SUBMENU(MSG_FTM_MODE, menu_ftm_mode); + MENU_ITEM_ADDON_START_RJ(5); lcd_put_u8str(ftmode); MENU_ITEM_ADDON_END(); + + #if HAS_X_AXIS + EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_FTM_BASE_FREQ_N, &c.baseFreq[X_AXIS], FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2, fxdTiCtrl.refreshShapingN); + #endif + #if HAS_Y_AXIS + EDIT_ITEM_FAST_N(float42_52, Y_AXIS, MSG_FTM_BASE_FREQ_N, &c.baseFreq[Y_AXIS], FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2, fxdTiCtrl.refreshShapingN); + #endif + + #if HAS_DYNAMIC_FREQ + if (c.modeHasShaper()) { + SUBMENU(MSG_FTM_DYN_MODE, menu_ftm_dyn_mode); + MENU_ITEM_ADDON_START_RJ(11); lcd_put_u8str(dmode); MENU_ITEM_ADDON_END(); + #if HAS_X_AXIS + EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_FTM_DFREQ_K_N, &c.dynFreqK[X_AXIS], 0.0f, 20.0f); + #endif + #if HAS_Y_AXIS + EDIT_ITEM_FAST_N(float42_52, Y_AXIS, MSG_FTM_DFREQ_K_N, &c.dynFreqK[Y_AXIS], 0.0f, 20.0f); + #endif + } + #endif + #if HAS_EXTRUDERS + EDIT_ITEM(bool, MSG_LINEAR_ADVANCE, &c.linearAdvEna); + EDIT_ITEM(float42_52, MSG_ADVANCE_K, &c.linearAdvK, 0, 10); + #endif + + END_MENU(); + } + +#endif // FT_MOTION_MENU + void menu_motion() { + #if ENABLED(FT_MOTION_MENU) + const bool is_busy = printer_busy(); + #endif + START_MENU(); // @@ -339,6 +468,13 @@ void menu_motion() { #endif #endif + // + // M493 - Fixed-Time Motion + // + #if ENABLED(FT_MOTION_MENU) + if (!is_busy) SUBMENU(MSG_FIXED_TIME_MOTION, menu_ft_motion); + #endif + // // Pen up/down menu // diff --git a/Marlin/src/module/ft_motion.cpp b/Marlin/src/module/ft_motion.cpp index 407296f0303..d6c834cbc48 100644 --- a/Marlin/src/module/ft_motion.cpp +++ b/Marlin/src/module/ft_motion.cpp @@ -29,32 +29,28 @@ FxdTiCtrl fxdTiCtrl; +#if !HAS_X_AXIS + static_assert(FTM_DEFAULT_MODE == ftMotionMode_ZV, "ftMotionMode_ZV requires at least one linear axis."); + static_assert(FTM_DEFAULT_MODE == ftMotionMode_ZVD, "ftMotionMode_ZVD requires at least one linear axis."); + static_assert(FTM_DEFAULT_MODE == ftMotionMode_EI, "ftMotionMode_EI requires at least one linear axis."); + static_assert(FTM_DEFAULT_MODE == ftMotionMode_2HEI, "ftMotionMode_2HEI requires at least one linear axis."); + static_assert(FTM_DEFAULT_MODE == ftMotionMode_3HEI, "ftMotionMode_3HEI requires at least one linear axis."); + static_assert(FTM_DEFAULT_MODE == ftMotionMode_MZV, "ftMotionMode_MZV requires at least one linear axis."); +#endif +#if !HAS_DYNAMIC_FREQ_MM + static_assert(FTM_DEFAULT_DYNFREQ_MODE != dynFreqMode_Z_BASED, "dynFreqMode_Z_BASED requires a Z axis."); +#endif +#if !HAS_DYNAMIC_FREQ_G + static_assert(FTM_DEFAULT_DYNFREQ_MODE != dynFreqMode_MASS_BASED, "dynFreqMode_MASS_BASED requires an X axis and an extruder."); +#endif + //-----------------------------------------------------------------// // Variables. //-----------------------------------------------------------------// // Public variables. -ftMotionMode_t FxdTiCtrl::cfg_mode = FTM_DEFAULT_MODE; // Mode / active compensation mode configuration. - -#if HAS_EXTRUDERS - bool FxdTiCtrl::cfg_linearAdvEna = FTM_LINEAR_ADV_DEFAULT_ENA; // Linear advance enable configuration. - float FxdTiCtrl::cfg_linearAdvK = FTM_LINEAR_ADV_DEFAULT_K; // Linear advance gain. -#endif - -dynFreqMode_t FxdTiCtrl::cfg_dynFreqMode = FTM_DEFAULT_DYNFREQ_MODE; // Dynamic frequency mode configuration. -#if !HAS_Z_AXIS - static_assert(FTM_DEFAULT_DYNFREQ_MODE != dynFreqMode_Z_BASED, "dynFreqMode_Z_BASED requires a Z axis."); -#endif -#if !(HAS_X_AXIS && HAS_EXTRUDERS) - static_assert(FTM_DEFAULT_DYNFREQ_MODE != dynFreqMode_MASS_BASED, "dynFreqMode_MASS_BASED requires an X axis and an extruder."); -#endif - -#if HAS_X_AXIS - float FxdTiCtrl::cfg_baseFreq[] = { FTM_SHAPING_DEFAULT_X_FREQ // Base frequency. [Hz] - OPTARG(HAS_Y_AXIS, FTM_SHAPING_DEFAULT_Y_FREQ) }; - float FxdTiCtrl::cfg_dynFreqK[] = { 0.0f OPTARG(HAS_Y_AXIS, 0.0f) }; // Scaling / gain for dynamic frequency. [Hz/mm] or [Hz/g] -#endif +ft_config_t FxdTiCtrl::cfg; ft_command_t FxdTiCtrl::stepperCmdBuff[FTM_STEPPERCMD_BUFF_SIZE] = {0U}; // Buffer of stepper commands. hal_timer_t FxdTiCtrl::stepperCmdBuff_StepRelativeTi[FTM_STEPPERCMD_BUFF_SIZE] = {0U}; // Buffer of the stepper command timing. uint8_t FxdTiCtrl::stepperCmdBuff_ApplyDir[FTM_STEPPERCMD_DIR_SIZE] = {0U}; // Buffer of whether DIR needs to be updated. @@ -209,7 +205,7 @@ void FxdTiCtrl::runoutBlock() { // Controller main, to be invoked from non-isr task. void FxdTiCtrl::loop() { - if (!cfg_mode) return; + if (!cfg.mode) return; // Handle block abort with the following sequence: // 1. Zero out commands in stepper ISR. @@ -291,7 +287,7 @@ void FxdTiCtrl::loop() { const float K = exp( -zeta * M_PI / sqrt(1.0f - sq(zeta)) ), K2 = sq(K); - switch (cfg_mode) { + switch (cfg.mode) { case ftMotionMode_ZV: xy_max_i = 1U; @@ -363,7 +359,7 @@ void FxdTiCtrl::loop() { const float df = sqrt(1.0f - sq(zeta)); - switch (cfg_mode) { + switch (cfg.mode) { case ftMotionMode_ZV: x_Ni[1] = round((0.5f / xf / df) * (FTM_FS)); #if HAS_Y_AXIS @@ -472,8 +468,8 @@ uint32_t FxdTiCtrl::stepperCmdBuffItems() { // Initializes storage variables before startup. void FxdTiCtrl::init() { #if HAS_X_AXIS - updateShapingN(cfg_baseFreq[0] OPTARG(HAS_Y_AXIS, cfg_baseFreq[1])); - updateShapingA(FTM_SHAPING_ZETA, FTM_SHAPING_V_TOL); + refreshShapingN(); + updateShapingA(); #endif reset(); // Precautionary. } @@ -606,9 +602,9 @@ void FxdTiCtrl::makeVector() { #if HAS_EXTRUDERS const float new_raw_z1 = e_startPosn + e_Ratio * dist; - if (cfg_linearAdvEna) { + if (cfg.linearAdvEna) { float dedt_adj = (new_raw_z1 - e_raw_z1) * (FTM_FS); - if (e_Ratio > 0.0f) dedt_adj += accel_k * cfg_linearAdvK; + if (e_Ratio > 0.0f) dedt_adj += accel_k * cfg.linearAdvK; e_advanced_z1 += dedt_adj * (FTM_TS); ed[makeVector_batchIdx] = e_advanced_z1; @@ -622,28 +618,28 @@ void FxdTiCtrl::makeVector() { #endif // Update shaping parameters if needed. - #if HAS_Z_AXIS + #if HAS_DYNAMIC_FREQ_MM static float zd_z1 = 0.0f; #endif - switch (cfg_dynFreqMode) { + switch (cfg.dynFreqMode) { - #if HAS_Z_AXIS + #if HAS_DYNAMIC_FREQ_MM case dynFreqMode_Z_BASED: if (zd[makeVector_batchIdx] != zd_z1) { // Only update if Z changed. - const float xf = cfg_baseFreq[0] + cfg_dynFreqK[0] * zd[makeVector_batchIdx], - yf = cfg_baseFreq[1] + cfg_dynFreqK[1] * zd[makeVector_batchIdx]; + const float xf = cfg.baseFreq[X_AXIS] + cfg.dynFreqK[X_AXIS] * zd[makeVector_batchIdx], + yf = cfg.baseFreq[Y_AXIS] + cfg.dynFreqK[Y_AXIS] * zd[makeVector_batchIdx]; updateShapingN(_MAX(xf, FTM_MIN_SHAPE_FREQ), _MAX(yf, FTM_MIN_SHAPE_FREQ)); zd_z1 = zd[makeVector_batchIdx]; } break; #endif - #if HAS_X_AXIS && HAS_EXTRUDERS + #if HAS_DYNAMIC_FREQ_G case dynFreqMode_MASS_BASED: // Update constantly. The optimization done for Z value makes // less sense for E, as E is expected to constantly change. - updateShapingN( cfg_baseFreq[0] + cfg_dynFreqK[0] * ed[makeVector_batchIdx] - OPTARG(HAS_Y_AXIS, cfg_baseFreq[1] + cfg_dynFreqK[1] * ed[makeVector_batchIdx]) ); + updateShapingN( cfg.baseFreq[X_AXIS] + cfg.dynFreqK[X_AXIS] * ed[makeVector_batchIdx] + OPTARG(HAS_Y_AXIS, cfg.baseFreq[Y_AXIS] + cfg.dynFreqK[Y_AXIS] * ed[makeVector_batchIdx]) ); break; #endif @@ -652,7 +648,7 @@ void FxdTiCtrl::makeVector() { // Apply shaping if in mode. #if HAS_X_AXIS - if (WITHIN(cfg_mode, 10U, 19U)) { + if (WITHIN(cfg.mode, 10U, 19U)) { xd_zi[xy_zi_idx] = xd[makeVector_batchIdx]; xd[makeVector_batchIdx] *= x_Ai[0]; #if HAS_Y_AXIS diff --git a/Marlin/src/module/ft_motion.h b/Marlin/src/module/ft_motion.h index a277f3ac26e..232d191cda6 100644 --- a/Marlin/src/module/ft_motion.h +++ b/Marlin/src/module/ft_motion.h @@ -28,20 +28,69 @@ #define FTM_STEPPERCMD_DIR_SIZE ((FTM_STEPPERCMD_BUFF_SIZE + 7) / 8) +#if HAS_X_AXIS && (HAS_Z_AXIS || HAS_EXTRUDERS) + #define HAS_DYNAMIC_FREQ 1 + #if HAS_Z_AXIS + #define HAS_DYNAMIC_FREQ_MM 1 + #endif + #if HAS_EXTRUDERS + #define HAS_DYNAMIC_FREQ_G 1 + #endif +#endif + +typedef struct FTConfig { + ftMotionMode_t mode = FTM_DEFAULT_MODE; // Mode / active compensation mode configuration. + + bool modeHasShaper() { return WITHIN(mode, 10U, 19U); } + + #if HAS_X_AXIS + float baseFreq[1 + ENABLED(HAS_Y_AXIS)] = // Base frequency. [Hz] + { FTM_SHAPING_DEFAULT_X_FREQ OPTARG(HAS_Y_AXIS, FTM_SHAPING_DEFAULT_Y_FREQ) }; + #endif + + #if HAS_DYNAMIC_FREQ + dynFreqMode_t dynFreqMode = FTM_DEFAULT_DYNFREQ_MODE; // Dynamic frequency mode configuration. + float dynFreqK[1 + ENABLED(HAS_Y_AXIS)] = { 0.0f }; // Scaling / gain for dynamic frequency. [Hz/mm] or [Hz/g] + #else + static constexpr dynFreqMode_t dynFreqMode = dynFreqMode_DISABLED; + #endif + + #if HAS_EXTRUDERS + bool linearAdvEna = FTM_LINEAR_ADV_DEFAULT_ENA; // Linear advance enable configuration. + float linearAdvK = FTM_LINEAR_ADV_DEFAULT_K; // Linear advance gain. + #endif +} ft_config_t; + class FxdTiCtrl { public: // Public variables - static ftMotionMode_t cfg_mode; // Mode / active compensation mode configuration. - static bool cfg_linearAdvEna; // Linear advance enable configuration. - static float cfg_linearAdvK; // Linear advance gain. - static dynFreqMode_t cfg_dynFreqMode; // Dynamic frequency mode configuration. + static ft_config_t cfg; - #if HAS_X_AXIS - static float cfg_baseFreq[1 + ENABLED(HAS_Y_AXIS)]; // Base frequency. [Hz] - static float cfg_dynFreqK[1 + ENABLED(HAS_Y_AXIS)]; // Scaling / gain for dynamic frequency. [Hz/mm] or [Hz/g] - #endif + static void set_defaults() { + cfg.mode = FTM_DEFAULT_MODE; + + TERN_(HAS_X_AXIS, cfg.baseFreq[X_AXIS] = FTM_SHAPING_DEFAULT_X_FREQ); + TERN_(HAS_Y_AXIS, cfg.baseFreq[Y_AXIS] = FTM_SHAPING_DEFAULT_Y_FREQ); + + #if HAS_DYNAMIC_FREQ + cfg.dynFreqMode = FTM_DEFAULT_DYNFREQ_MODE; + cfg.dynFreqK[X_AXIS] = TERN_(HAS_Y_AXIS, cfg.dynFreqK[Y_AXIS]) = 0.0f; + #endif + + #if HAS_EXTRUDERS + cfg.linearAdvEna = FTM_LINEAR_ADV_DEFAULT_ENA; + cfg.linearAdvK = FTM_LINEAR_ADV_DEFAULT_K; + #endif + + #if HAS_X_AXIS + refreshShapingN(); + updateShapingA(); + #endif + + reset(); + } static ft_command_t stepperCmdBuff[FTM_STEPPERCMD_BUFF_SIZE]; // Buffer of stepper commands. static hal_timer_t stepperCmdBuff_StepRelativeTi[FTM_STEPPERCMD_BUFF_SIZE]; // Buffer of the stepper command timing. @@ -68,6 +117,9 @@ class FxdTiCtrl { // Refresh the indices used by shaping functions. // To be called when frequencies change. static void updateShapingN(const_float_t xf OPTARG(HAS_Y_AXIS, const_float_t yf), const_float_t zeta=FTM_SHAPING_ZETA); + + static void refreshShapingN() { updateShapingN(cfg.baseFreq[X_AXIS] OPTARG(HAS_Y_AXIS, cfg.baseFreq[Y_AXIS])); } + #endif static void reset(); // Resets all states of the fixed time conversion to defaults. diff --git a/Marlin/src/module/ft_types.h b/Marlin/src/module/ft_types.h index 613e177a391..a3239a92464 100644 --- a/Marlin/src/module/ft_types.h +++ b/Marlin/src/module/ft_types.h @@ -26,14 +26,14 @@ typedef enum FXDTICtrlMode : uint8_t { ftMotionMode_DISABLED = 0U, ftMotionMode_ENABLED = 1U, - ftMotionMode_ULENDO_FBS = 2U, + //ftMotionMode_ULENDO_FBS = 2U, ftMotionMode_ZV = 10U, ftMotionMode_ZVD = 11U, ftMotionMode_EI = 12U, ftMotionMode_2HEI = 13U, ftMotionMode_3HEI = 14U, ftMotionMode_MZV = 15U, - ftMotionMode_DISCTF = 20U + //ftMotionMode_DISCTF = 20U } ftMotionMode_t; enum dynFreqMode_t : uint8_t { diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index b0d0b3e353c..02a7d05cae3 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -1692,7 +1692,7 @@ void Planner::quick_stop() { // Restart the block delay for the first movement - As the queue was // forced to empty, there's no risk the ISR will touch this. - delay_before_delivering = TERN_(FT_MOTION, fxdTiCtrl.cfg_mode ? BLOCK_DELAY_NONE :) BLOCK_DELAY_FOR_1ST_MOVE; + delay_before_delivering = TERN_(FT_MOTION, fxdTiCtrl.cfg.mode ? BLOCK_DELAY_NONE :) BLOCK_DELAY_FOR_1ST_MOVE; TERN_(HAS_WIRED_LCD, clear_block_buffer_runtime()); // Clear the accumulated runtime @@ -1851,7 +1851,7 @@ bool Planner::_buffer_steps(const xyze_long_t &target // As there are no queued movements, the Stepper ISR will not touch this // variable, so there is no risk setting this here (but it MUST be done // before the following line!!) - delay_before_delivering = TERN_(FT_MOTION, fxdTiCtrl.cfg_mode ? BLOCK_DELAY_NONE :) BLOCK_DELAY_FOR_1ST_MOVE; + delay_before_delivering = TERN_(FT_MOTION, fxdTiCtrl.cfg.mode ? BLOCK_DELAY_NONE :) BLOCK_DELAY_FOR_1ST_MOVE; } // Move buffer head @@ -2924,7 +2924,7 @@ void Planner::buffer_sync_block(const BlockFlagBit sync_flag/*=BLOCK_BIT_SYNC_PO // As there are no queued movements, the Stepper ISR will not touch this // variable, so there is no risk setting this here (but it MUST be done // before the following line!!) - delay_before_delivering = TERN_(FT_MOTION, fxdTiCtrl.cfg_mode ? BLOCK_DELAY_NONE :) BLOCK_DELAY_FOR_1ST_MOVE; + delay_before_delivering = TERN_(FT_MOTION, fxdTiCtrl.cfg.mode ? BLOCK_DELAY_NONE :) BLOCK_DELAY_FOR_1ST_MOVE; } block_buffer_head = next_buffer_head; @@ -3217,7 +3217,7 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s // As there are no queued movements, the Stepper ISR will not touch this // variable, so there is no risk setting this here (but it MUST be done // before the following line!!) - delay_before_delivering = TERN_(FT_MOTION, fxdTiCtrl.cfg_mode ? BLOCK_DELAY_NONE :) BLOCK_DELAY_FOR_1ST_MOVE; + delay_before_delivering = TERN_(FT_MOTION, fxdTiCtrl.cfg.mode ? BLOCK_DELAY_NONE :) BLOCK_DELAY_FOR_1ST_MOVE; } // Move buffer head diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index 53e98a46265..b6e605e853e 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -111,6 +111,10 @@ #include "../feature/backlash.h" #endif +#if ENABLED(FT_MOTION) + #include "../module/ft_motion.h" +#endif + #if HAS_FILAMENT_SENSOR #include "../feature/runout.h" #ifndef FIL_RUNOUT_ENABLED_DEFAULT @@ -594,16 +598,23 @@ typedef struct SettingsDataStruct { MPC_t mpc_constants[HOTENDS]; // M306 #endif + // + // Fixed-Time Motion + // + #if ENABLED(FT_MOTION) + ft_config_t fxdTiCtrl_cfg; // M493 + #endif + // // Input Shaping // #if ENABLED(INPUT_SHAPING_X) - float shaping_x_frequency, // M593 X F - shaping_x_zeta; // M593 X D + float shaping_x_frequency, // M593 X F + shaping_x_zeta; // M593 X D #endif #if ENABLED(INPUT_SHAPING_Y) - float shaping_y_frequency, // M593 Y F - shaping_y_zeta; // M593 Y D + float shaping_y_frequency, // M593 Y F + shaping_y_zeta; // M593 Y D #endif } SettingsData; @@ -1648,6 +1659,14 @@ void MarlinSettings::postprocess() { HOTEND_LOOP() EEPROM_WRITE(thermalManager.temp_hotend[e].mpc); #endif + // + // Fixed-Time Motion + // + #if ENABLED(FT_MOTION) + _FIELD_TEST(fxdTiCtrl_cfg); + EEPROM_WRITE(fxdTiCtrl.cfg); + #endif + // // Input Shaping /// @@ -2646,9 +2665,15 @@ void MarlinSettings::postprocess() { // Model predictive control // #if ENABLED(MPCTEMP) - { HOTEND_LOOP() EEPROM_READ(thermalManager.temp_hotend[e].mpc); - } + #endif + + // + // Fixed-Time Motion + // + #if ENABLED(FT_MOTION) + _FIELD_TEST(fxdTiCtrl_cfg); + EEPROM_READ(fxdTiCtrl.cfg); #endif // @@ -3445,6 +3470,11 @@ void MarlinSettings::reset() { } #endif + // + // Fixed-Time Motion + // + TERN_(FT_MOTION, fxdTiCtrl.set_defaults()); + // // Input Shaping // @@ -3706,6 +3736,11 @@ void MarlinSettings::reset() { // TERN_(HAS_STEALTHCHOP, gcode.M569_report(forReplay)); + // + // Fixed-Time Motion + // + TERN_(FT_MOTION, gcode.M493_report(forReplay)); + // // Input Shaping // diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index b23667b8201..3188f77da8b 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -1497,7 +1497,7 @@ void Stepper::isr() { #if ENABLED(FT_MOTION) // NOTE STEPPER_TIMER_RATE is equal to 2000000, not what VSCode shows - const bool using_fxtictrl = fxdTiCtrl.cfg_mode; + const bool using_fxtictrl = fxdTiCtrl.cfg.mode; if (using_fxtictrl) { if (!nextMainISR) { if (abort_current_block) { diff --git a/buildroot/tests/STM32F103RC_btt b/buildroot/tests/STM32F103RC_btt index 95a18c615ff..d0da6305e53 100755 --- a/buildroot/tests/STM32F103RC_btt +++ b/buildroot/tests/STM32F103RC_btt @@ -12,7 +12,7 @@ set -e restore_configs opt_set MOTHERBOARD BOARD_BTT_SKR_MINI_E3_V1_0 SERIAL_PORT 1 SERIAL_PORT_2 -1 \ X_DRIVER_TYPE TMC2209 Y_DRIVER_TYPE TMC2209 Z_DRIVER_TYPE TMC2209 E0_DRIVER_TYPE TMC2209 -opt_enable PINS_DEBUGGING Z_IDLE_HEIGHT FT_MOTION +opt_enable CR10_STOCKDISPLAY PINS_DEBUGGING Z_IDLE_HEIGHT FT_MOTION FT_MOTION_MENU exec_test $1 $2 "BigTreeTech SKR Mini E3 1.0 - TMC2209 HW Serial, FT_MOTION" "$3" # clean up