🚸 Simplified M493

Part of #21827
This commit is contained in:
Scott Lahteine 2025-10-20 16:01:13 -05:00
parent 05a64e2013
commit 40beddeaa3
2 changed files with 251 additions and 317 deletions

View file

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

View file

@ -31,6 +31,8 @@
#include "ft_motion/poly5_trajectory_generator.h"
#include "ft_motion/poly6_trajectory_generator.h"
#define FTM_VERSION 2 // Change version when hosts need to know
#if HAS_X_AXIS && (HAS_Z_AXIS || HAS_EXTRUDERS)
#define HAS_DYNAMIC_FREQ 1
#if HAS_Z_AXIS