Skip to content

Commit 67d7562

Browse files
narno2202thinkyhead
andcommitted
🐛⚡️ FT_MOTION improvements (MarlinFirmware#26074)
Co-Authored-By: Scott Lahteine <thinkyhead@users.noreply.github.com>
1 parent 0ede16c commit 67d7562

File tree

16 files changed

+654
-645
lines changed

16 files changed

+654
-645
lines changed

Marlin/Configuration_adv.h

+52-32
Original file line numberDiff line numberDiff line change
@@ -1121,42 +1121,62 @@
11211121
#if ENABLED(FT_MOTION)
11221122
#define FTM_DEFAULT_MODE ftMotionMode_DISABLED // Default mode of fixed time control. (Enums in ft_types.h)
11231123
#define FTM_DEFAULT_DYNFREQ_MODE dynFreqMode_DISABLED // Default mode of dynamic frequency calculation. (Enums in ft_types.h)
1124-
#define FTM_SHAPING_DEFAULT_X_FREQ 37.0f // (Hz) Default peak frequency used by input shapers.
1125-
#define FTM_SHAPING_DEFAULT_Y_FREQ 37.0f // (Hz) Default peak frequency used by input shapers.
1126-
#define FTM_LINEAR_ADV_DEFAULT_ENA false // Default linear advance enable (true) or disable (false).
1127-
#define FTM_LINEAR_ADV_DEFAULT_K 0.0f // Default linear advance gain.
1128-
#define FTM_SHAPING_ZETA 0.1f // Zeta used by input shapers.
1129-
#define FTM_SHAPING_V_TOL 0.05f // Vibration tolerance used by EI input shapers.
1124+
#define FTM_SHAPING_DEFAULT_X_FREQ 37.0f // (Hz) Default peak frequency used by input shapers
1125+
#define FTM_SHAPING_DEFAULT_Y_FREQ 37.0f // (Hz) Default peak frequency used by input shapers
1126+
#define FTM_LINEAR_ADV_DEFAULT_ENA false // Default linear advance enable (true) or disable (false)
1127+
#define FTM_LINEAR_ADV_DEFAULT_K 0.0f // Default linear advance gain
1128+
#define FTM_SHAPING_ZETA_X 0.1f // Zeta used by input shapers for X axis
1129+
#define FTM_SHAPING_ZETA_Y 0.1f // Zeta used by input shapers for Y axis
1130+
1131+
#define FTM_SHAPING_V_TOL_X 0.05f // Vibration tolerance used by EI input shapers for X axis
1132+
#define FTM_SHAPING_V_TOL_Y 0.05f // Vibration tolerance used by EI input shapers for Y axis
1133+
1134+
//#define FT_MOTION_MENU // Provide a MarlinUI menu to set M493 parameters
11301135

11311136
/**
11321137
* Advanced configuration
11331138
*/
1134-
#define FTM_BATCH_SIZE 100 // Batch size for trajectory generation;
1135-
#define FTM_WINDOW_SIZE 200 // Window size for trajectory generation.
1136-
#define FTM_FS 1000 // (Hz) Frequency for trajectory generation. (1 / FTM_TS)
1137-
#define FTM_TS 0.001f // (s) Time step for trajectory generation. (1 / FTM_FS)
1138-
#define FTM_STEPPER_FS 20000 // (Hz) Frequency for stepper I/O update.
1139-
#define FTM_MIN_TICKS ((STEPPER_TIMER_RATE) / (FTM_STEPPER_FS)) // Minimum stepper ticks between steps.
1140-
#define FTM_MIN_SHAPE_FREQ 10 // Minimum shaping frequency.
1141-
#define FTM_ZMAX 100 // Maximum delays for shaping functions (even numbers only!).
1142-
// Calculate as:
1143-
// 1/2 * (FTM_FS / FTM_MIN_SHAPE_FREQ) for ZV.
1144-
// (FTM_FS / FTM_MIN_SHAPE_FREQ) for ZVD, MZV.
1145-
// 3/2 * (FTM_FS / FTM_MIN_SHAPE_FREQ) for 2HEI.
1146-
// 2 * (FTM_FS / FTM_MIN_SHAPE_FREQ) for 3HEI.
1147-
#define FTM_STEPS_PER_UNIT_TIME 20 // Interpolated stepper commands per unit time.
1148-
// Calculate as (FTM_STEPPER_FS / FTM_FS).
1149-
#define FTM_CTS_COMPARE_VAL 10 // Comparison value used in interpolation algorithm.
1150-
// Calculate as (FTM_STEPS_PER_UNIT_TIME / 2).
1151-
// These values may be configured to adjust duration of loop().
1152-
#define FTM_STEPS_PER_LOOP 60 // Number of stepper commands to generate each loop().
1153-
#define FTM_POINTS_PER_LOOP 100 // Number of trajectory points to generate each loop().
1154-
1155-
// This value may be configured to adjust duration to consume the command buffer.
1156-
// Try increasing this value if stepper motion is not smooth.
1157-
#define FTM_STEPPERCMD_BUFF_SIZE 1000 // Size of the stepper command buffers.
1158-
1159-
//#define FT_MOTION_MENU // Provide a MarlinUI menu to set M493 parameters.
1139+
#define FTM_UNIFIED_BWS // DON'T DISABLE unless you use Ulendo FBS (not implemented)
1140+
#if ENABLED(FTM_UNIFIED_BWS)
1141+
#define FTM_BW_SIZE 100 // Unified Window and Batch size with a ratio of 2
1142+
#else
1143+
#define FTM_WINDOW_SIZE 200 // Custom Window size for trajectory generation needed by Ulendo FBS
1144+
#define FTM_BATCH_SIZE 100 // Custom Batch size for trajectory generation needed by Ulendo FBS
1145+
#endif
1146+
1147+
#define FTM_FS 1000 // (Hz) Frequency for trajectory generation. (Reciprocal of FTM_TS)
1148+
#define FTM_TS 0.001f // (s) Time step for trajectory generation. (Reciprocal of FTM_FS)
1149+
1150+
// These values may be configured to adjust the duration of loop().
1151+
#define FTM_STEPS_PER_LOOP 60 // Number of stepper commands to generate each loop()
1152+
#define FTM_POINTS_PER_LOOP 100 // Number of trajectory points to generate each loop()
1153+
1154+
#if DISABLED(COREXY)
1155+
#define FTM_STEPPER_FS 20000 // (Hz) Frequency for stepper I/O update
1156+
1157+
// Use this to adjust the time required to consume the command buffer.
1158+
// Try increasing this value if stepper motion is choppy.
1159+
#define FTM_STEPPERCMD_BUFF_SIZE 3000 // Size of the stepper command buffers
1160+
// (FTM_STEPS_PER_LOOP * FTM_POINTS_PER_LOOP) is a good start
1161+
// If you run out of memory, fall back to 3000 and increase progressively
1162+
#else
1163+
// CoreXY motion needs a larger buffer size. These values are based on our testing.
1164+
#define FTM_STEPPER_FS 30000
1165+
#define FTM_STEPPERCMD_BUFF_SIZE 6000
1166+
#endif
1167+
1168+
#define FTM_STEPS_PER_UNIT_TIME (FTM_STEPPER_FS / FTM_FS) // Interpolated stepper commands per unit time
1169+
#define FTM_CTS_COMPARE_VAL (FTM_STEPS_PER_UNIT_TIME / 2) // Comparison value used in interpolation algorithm
1170+
#define FTM_MIN_TICKS ((STEPPER_TIMER_RATE) / (FTM_STEPPER_FS)) // Minimum stepper ticks between steps
1171+
1172+
#define FTM_MIN_SHAPE_FREQ 10 // Minimum shaping frequency
1173+
#define FTM_RATIO (FTM_FS / FTM_MIN_SHAPE_FREQ) // Factor for use in FTM_ZMAX. DON'T CHANGE.
1174+
#define FTM_ZMAX (FTM_RATIO * 2) // Maximum delays for shaping functions (even numbers only!)
1175+
// Calculate as:
1176+
// ZV : FTM_RATIO / 2
1177+
// ZVD, MZV : FTM_RATIO
1178+
// 2HEI : FTM_RATIO * 3 / 2
1179+
// 3HEI : FTM_RATIO * 2
11601180
#endif
11611181

11621182
/**

Marlin/src/gcode/bedlevel/G35.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@
5757
* 41 - Counter-Clockwise M4
5858
* 50 - Clockwise M5
5959
* 51 - Counter-Clockwise M5
60-
*
61-
*/
60+
**/
6261
void GcodeSuite::G35() {
62+
6363
DEBUG_SECTION(log_G35, "G35", DEBUGGING(LEVELING));
6464

6565
if (DEBUGGING(LEVELING)) log_machine_info();

Marlin/src/gcode/bedlevel/abl/G29.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ class G29_State {
225225
* There's no extra effect if you have a fixed Z probe.
226226
*/
227227
G29_TYPE GcodeSuite::G29() {
228+
228229
DEBUG_SECTION(log_G29, "G29", DEBUGGING(LEVELING));
229230

230231
// Leveling state is persistent when done manually with multiple G29 commands

Marlin/src/gcode/bedlevel/mbl/G29.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ inline void echo_not_entered(const char c) { SERIAL_CHAR(c); SERIAL_ECHOLNPGM("
6464
* S5 Reset and disable mesh
6565
*/
6666
void GcodeSuite::G29() {
67+
6768
DEBUG_SECTION(log_G29, "G29", true);
6869

6970
// G29 Q is also available if debugging

Marlin/src/gcode/calibrate/G34_M422.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
* R Flag to recalculate points based on current probe offsets
8080
*/
8181
void GcodeSuite::G34() {
82+
8283
DEBUG_SECTION(log_G34, "G34", DEBUGGING(LEVELING));
8384
if (DEBUGGING(LEVELING)) log_machine_info();
8485

Marlin/src/gcode/feature/ft_motion/M493.cpp

+84-23
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
#include "../../gcode.h"
2828
#include "../../../module/ft_motion.h"
29+
#include "../../../module/stepper.h"
2930

3031
void say_shaping() {
3132
// FT Enabled
@@ -39,6 +40,8 @@ void say_shaping() {
3940
default: break;
4041
case ftMotionMode_ZV: SERIAL_ECHOPGM("ZV"); break;
4142
case ftMotionMode_ZVD: SERIAL_ECHOPGM("ZVD"); break;
43+
case ftMotionMode_ZVDD: SERIAL_ECHOPGM("ZVDD"); break;
44+
case ftMotionMode_ZVDDD: SERIAL_ECHOPGM("ZVDDD"); break;
4245
case ftMotionMode_EI: SERIAL_ECHOPGM("EI"); break;
4346
case ftMotionMode_2HEI: SERIAL_ECHOPGM("2 Hump EI"); break;
4447
case ftMotionMode_3HEI: SERIAL_ECHOPGM("3 Hump EI"); break;
@@ -155,20 +158,19 @@ void GcodeSuite::M493() {
155158

156159
if (!parser.seen_any())
157160
flag.report_h = true;
158-
else
159-
planner.synchronize();
160161

161162
// Parse 'S' mode parameter.
162163
if (parser.seenval('S')) {
163-
const ftMotionMode_t oldmm = ftMotion.cfg.mode,
164-
newmm = (ftMotionMode_t)parser.value_byte();
164+
const ftMotionMode_t newmm = (ftMotionMode_t)parser.value_byte();
165165

166-
if (newmm != oldmm) {
166+
if (newmm != ftMotion.cfg.mode) {
167167
switch (newmm) {
168168
default: SERIAL_ECHOLNPGM("?Invalid control mode [S] value."); return;
169169
#if HAS_X_AXIS
170170
case ftMotionMode_ZV:
171171
case ftMotionMode_ZVD:
172+
case ftMotionMode_ZVDD:
173+
case ftMotionMode_ZVDDD:
172174
case ftMotionMode_EI:
173175
case ftMotionMode_2HEI:
174176
case ftMotionMode_3HEI:
@@ -177,11 +179,10 @@ void GcodeSuite::M493() {
177179
//case ftMotionMode_DISCTF:
178180
flag.update_n = flag.update_a = true;
179181
#endif
180-
case ftMotionMode_DISABLED:
182+
case ftMotionMode_DISABLED: flag.reset_ft = true;
181183
case ftMotionMode_ENABLED:
182184
ftMotion.cfg.mode = newmm;
183185
flag.report_h = true;
184-
if (oldmm == ftMotionMode_DISABLED) flag.reset_ft = true;
185186
break;
186187
}
187188
}
@@ -193,6 +194,7 @@ void GcodeSuite::M493() {
193194
if (parser.seen('P')) {
194195
const bool val = parser.value_bool();
195196
ftMotion.cfg.linearAdvEna = val;
197+
flag.report_h = true;
196198
SERIAL_ECHO_TERNARY(val, "Linear Advance ", "en", "dis", "abled.\n");
197199
}
198200

@@ -216,22 +218,16 @@ void GcodeSuite::M493() {
216218
if (ftMotion.cfg.modeHasShaper()) {
217219
const dynFreqMode_t val = dynFreqMode_t(parser.value_byte());
218220
switch (val) {
219-
case dynFreqMode_DISABLED:
220-
ftMotion.cfg.dynFreqMode = val;
221-
flag.report_h = true;
222-
break;
223221
#if HAS_DYNAMIC_FREQ_MM
224222
case dynFreqMode_Z_BASED:
225-
ftMotion.cfg.dynFreqMode = val;
226-
flag.report_h = true;
227-
break;
228223
#endif
229224
#if HAS_DYNAMIC_FREQ_G
230225
case dynFreqMode_MASS_BASED:
231-
ftMotion.cfg.dynFreqMode = val;
232-
flag.report_h = true;
233-
break;
234226
#endif
227+
case dynFreqMode_DISABLED:
228+
ftMotion.cfg.dynFreqMode = val;
229+
flag.report_h = true;
230+
break;
235231
default:
236232
SERIAL_ECHOLNPGM("?Invalid Dynamic Frequency Mode [D] value.");
237233
break;
@@ -279,6 +275,36 @@ void GcodeSuite::M493() {
279275
}
280276
#endif
281277

278+
// Parse zeta parameter (X axis).
279+
if (parser.seenval('I')) {
280+
const float val = parser.value_float();
281+
if (ftMotion.cfg.modeHasShaper()) {
282+
if (WITHIN(val, 0.01f, 1.0f)) {
283+
ftMotion.cfg.zeta[0] = val;
284+
flag.update_n = flag.update_a = true;
285+
}
286+
else
287+
SERIAL_ECHOLNPGM("Invalid X zeta [", AS_CHAR('I'), "] value."); // Zeta out of range.
288+
}
289+
else
290+
SERIAL_ECHOLNPGM("Wrong mode for zeta parameter.");
291+
}
292+
293+
// Parse vtol parameter (X axis).
294+
if (parser.seenval('Q')) {
295+
const float val = parser.value_float();
296+
if (ftMotion.cfg.modeHasShaper() && IS_EI_MODE(ftMotion.cfg.mode)) {
297+
if (WITHIN(val, 0.00f, 1.0f)) {
298+
ftMotion.cfg.vtol[0] = val;
299+
flag.update_a = true;
300+
}
301+
else
302+
SERIAL_ECHOLNPGM("Invalid X vtol [", AS_CHAR('Q'), "] value."); // VTol out of range.
303+
}
304+
else
305+
SERIAL_ECHOLNPGM("Wrong mode for vtol parameter.");
306+
}
307+
282308
#endif // HAS_X_AXIS
283309

284310
#if HAS_Y_AXIS
@@ -310,15 +336,50 @@ void GcodeSuite::M493() {
310336
}
311337
#endif
312338

339+
// Parse zeta parameter (Y axis).
340+
if (parser.seenval('J')) {
341+
const float val = parser.value_float();
342+
if (ftMotion.cfg.modeHasShaper()) {
343+
if (WITHIN(val, 0.01f, 1.0f)) {
344+
ftMotion.cfg.zeta[1] = val;
345+
flag.update_n = flag.update_a = true;
346+
}
347+
else
348+
SERIAL_ECHOLNPGM("Invalid Y zeta [", AS_CHAR('J'), "] value."); // Zeta Out of range
349+
}
350+
else
351+
SERIAL_ECHOLNPGM("Wrong mode for zeta parameter.");
352+
}
353+
354+
// Parse vtol parameter (Y axis).
355+
if (parser.seenval('R')) {
356+
const float val = parser.value_float();
357+
if (ftMotion.cfg.modeHasShaper() && IS_EI_MODE(ftMotion.cfg.mode)) {
358+
if (WITHIN(val, 0.00f, 1.0f)) {
359+
ftMotion.cfg.vtol[1] = val;
360+
flag.update_a = true;
361+
}
362+
else
363+
SERIAL_ECHOLNPGM("Invalid Y vtol [", AS_CHAR('R'), "] value."); // VTol out of range.
364+
}
365+
else
366+
SERIAL_ECHOLNPGM("Wrong mode for vtol parameter.");
367+
}
368+
313369
#endif // HAS_Y_AXIS
314370

315-
#if HAS_X_AXIS
316-
if (flag.update_n) ftMotion.refreshShapingN();
317-
if (flag.update_a) ftMotion.updateShapingA();
318-
#endif
319-
if (flag.reset_ft) ftMotion.reset();
320-
if (flag.report_h) say_shaping();
371+
planner.synchronize();
321372

373+
if (flag.update_n) ftMotion.refreshShapingN();
374+
375+
if (flag.update_a) ftMotion.updateShapingA();
376+
377+
if (flag.reset_ft) {
378+
stepper.ftMotion_syncPosition();
379+
ftMotion.reset();
380+
}
381+
382+
if (flag.report_h) say_shaping();
322383
}
323384

324385
#endif // FT_MOTION

Marlin/src/gcode/probe/G38.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ inline bool G38_run_probe() {
105105
* G38.5 - Probe away from workpiece, stop on contact break
106106
*/
107107
void GcodeSuite::G38(const int8_t subcode) {
108+
108109
// Get X Y Z E F
109110
get_destination_from_command();
110111

Marlin/src/inc/Conditionals_adv.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1144,7 +1144,7 @@
11441144
#elif HAS_DRIVER(A4988)
11451145
#define MINIMUM_STEPPER_POST_DIR_DELAY 200
11461146
#elif HAS_TRINAMIC_CONFIG || HAS_TRINAMIC_STANDALONE
1147-
#define MINIMUM_STEPPER_POST_DIR_DELAY 60
1147+
#define MINIMUM_STEPPER_POST_DIR_DELAY 70
11481148
#else
11491149
#define MINIMUM_STEPPER_POST_DIR_DELAY 0 // Expect at least 10µS since one Stepper ISR must transpire
11501150
#endif

Marlin/src/lcd/language/language_en.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,8 @@ namespace LanguageNarrow_en {
802802
LSTR MSG_FTM_MODE = _UxGT("Motion Mode:");
803803
LSTR MSG_FTM_ZV = _UxGT("ZV");
804804
LSTR MSG_FTM_ZVD = _UxGT("ZVD");
805+
LSTR MSG_FTM_ZVDD = _UxGT("ZVDD");
806+
LSTR MSG_FTM_ZVDDD = _UxGT("ZVDDD");
805807
LSTR MSG_FTM_EI = _UxGT("EI");
806808
LSTR MSG_FTM_2HEI = _UxGT("2HEI");
807809
LSTR MSG_FTM_3HEI = _UxGT("3HEI");
@@ -813,8 +815,8 @@ namespace LanguageNarrow_en {
813815
LSTR MSG_FTM_MASS_BASED = _UxGT("Mass-based");
814816
LSTR MSG_FTM_BASE_FREQ_N = _UxGT("@ Base Freq.");
815817
LSTR MSG_FTM_DFREQ_K_N = _UxGT("@ Dyn. Freq.");
816-
LSTR MSG_FTM_ZETA = _UxGT("Damping");
817-
LSTR MSG_FTM_VTOL = _UxGT("Vib. Level");
818+
LSTR MSG_FTM_ZETA_N = _UxGT("@ Damping");
819+
LSTR MSG_FTM_VTOL_N = _UxGT("@ Vib. Level");
818820

819821
LSTR MSG_LEVEL_X_AXIS = _UxGT("Level X Axis");
820822
LSTR MSG_AUTO_CALIBRATE = _UxGT("Auto Calibrate");

0 commit comments

Comments
 (0)