🚸 Fixed-Time Motion EEPROM and Menu (#25835)
This commit is contained in:
parent
fadd60441e
commit
ed66f498eb
|
@ -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
|
||||
|
||||
/**
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1047,6 +1047,7 @@ private:
|
|||
|
||||
#if ENABLED(FT_MOTION)
|
||||
static void M493();
|
||||
static void M493_report(const bool forReplay=true);
|
||||
#endif
|
||||
|
||||
static void M500();
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue