🚸 Fixed-Time Motion EEPROM and Menu (#25835)

This commit is contained in:
Scott Lahteine 2023-05-16 02:38:24 -05:00
parent fadd60441e
commit ed66f498eb
14 changed files with 474 additions and 173 deletions

View file

@ -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
/**

View file

@ -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"

View file

@ -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

View file

@ -1047,6 +1047,7 @@ private:
#if ENABLED(FT_MOTION)
static void M493();
static void M493_report(const bool forReplay=true);
#endif
static void M500();

View file

@ -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";

View file

@ -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)

View file

@ -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
//

View file

@ -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

View file

@ -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.

View file

@ -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 {

View file

@ -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

View file

@ -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
//

View file

@ -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) {

View file

@ -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