Skip to content

Commit 2d60948

Browse files
committed
👷 FT Motion refactor, minor fix
1 parent 295f503 commit 2d60948

File tree

6 files changed

+101
-82
lines changed

6 files changed

+101
-82
lines changed

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -98,18 +98,18 @@ void say_shaping() {
9898

9999
#if HAS_X_AXIS
100100
SERIAL_ECHO_TERNARY(dynamic, AXIS_0_NAME " ", "base dynamic", "static", " shaper frequency: ");
101-
SERIAL_ECHO(p_float_t(ftMotion.cfg.baseFreq[X_AXIS], 2), F("Hz"));
101+
SERIAL_ECHO(p_float_t(ftMotion.cfg.baseFreq.x, 2), F("Hz"));
102102
#if HAS_DYNAMIC_FREQ
103-
if (dynamic) SERIAL_ECHO(F(" scaling: "), p_float_t(ftMotion.cfg.dynFreqK[X_AXIS], 2), F("Hz/"), z_based ? F("mm") : F("g"));
103+
if (dynamic) SERIAL_ECHO(F(" scaling: "), p_float_t(ftMotion.cfg.dynFreqK.x, 2), F("Hz/"), z_based ? F("mm") : F("g"));
104104
#endif
105105
SERIAL_EOL();
106106
#endif
107107

108108
#if HAS_Y_AXIS
109109
SERIAL_ECHO_TERNARY(dynamic, AXIS_1_NAME " ", "base dynamic", "static", " shaper frequency: ");
110-
SERIAL_ECHO(p_float_t(ftMotion.cfg.baseFreq[Y_AXIS], 2), F(" Hz"));
110+
SERIAL_ECHO(p_float_t(ftMotion.cfg.baseFreq.y, 2), F(" Hz"));
111111
#if HAS_DYNAMIC_FREQ
112-
if (dynamic) SERIAL_ECHO(F(" scaling: "), p_float_t(ftMotion.cfg.dynFreqK[Y_AXIS], 2), F("Hz/"), z_based ? F("mm") : F("g"));
112+
if (dynamic) SERIAL_ECHO(F(" scaling: "), p_float_t(ftMotion.cfg.dynFreqK.y, 2), F("Hz/"), z_based ? F("mm") : F("g"));
113113
#endif
114114
SERIAL_EOL();
115115
#endif
@@ -131,17 +131,17 @@ void GcodeSuite::M493_report(const bool forReplay/*=true*/) {
131131
const ft_config_t &c = ftMotion.cfg;
132132
SERIAL_ECHOPGM(" M493 S", c.active);
133133
#if HAS_X_AXIS
134-
SERIAL_ECHOPGM(" A", c.baseFreq[X_AXIS]);
134+
SERIAL_ECHOPGM(" A", c.baseFreq.x);
135135
#if HAS_Y_AXIS
136-
SERIAL_ECHOPGM(" B", c.baseFreq[Y_AXIS]);
136+
SERIAL_ECHOPGM(" B", c.baseFreq.y);
137137
#endif
138138
#endif
139139
#if HAS_DYNAMIC_FREQ
140140
SERIAL_ECHOPGM(" D", c.dynFreqMode);
141141
#if HAS_X_AXIS
142-
SERIAL_ECHOPGM(" F", c.dynFreqK[X_AXIS]);
142+
SERIAL_ECHOPGM(" F", c.dynFreqK.x);
143143
#if HAS_Y_AXIS
144-
SERIAL_ECHOPGM(" H", c.dynFreqK[Y_AXIS]);
144+
SERIAL_ECHOPGM(" H", c.dynFreqK.y);
145145
#endif
146146
#endif
147147
#endif
@@ -308,7 +308,7 @@ void GcodeSuite::M493() {
308308
const float val = parser.value_float();
309309
// TODO: Frequency minimum is dependent on the shaper used; the above check isn't always correct.
310310
if (WITHIN(val, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2)) {
311-
ftMotion.cfg.baseFreq[X_AXIS] = val;
311+
ftMotion.cfg.baseFreq.x = val;
312312
flag.update = flag.reset_ft = flag.report_h = true;
313313
}
314314
else // Frequency out of range.
@@ -322,7 +322,7 @@ void GcodeSuite::M493() {
322322
// Parse frequency scaling parameter (X axis).
323323
if (parser.seenval('F')) {
324324
if (modeUsesDynFreq) {
325-
ftMotion.cfg.dynFreqK[X_AXIS] = parser.value_float();
325+
ftMotion.cfg.dynFreqK.x = parser.value_float();
326326
flag.report_h = true;
327327
}
328328
else
@@ -369,7 +369,7 @@ void GcodeSuite::M493() {
369369
if (AXIS_HAS_SHAPER(Y)) {
370370
const float val = parser.value_float();
371371
if (WITHIN(val, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2)) {
372-
ftMotion.cfg.baseFreq[Y_AXIS] = val;
372+
ftMotion.cfg.baseFreq.y = val;
373373
flag.update = flag.reset_ft = flag.report_h = true;
374374
}
375375
else // Frequency out of range.
@@ -383,7 +383,7 @@ void GcodeSuite::M493() {
383383
// Parse frequency scaling parameter (Y axis).
384384
if (parser.seenval('H')) {
385385
if (modeUsesDynFreq) {
386-
ftMotion.cfg.dynFreqK[Y_AXIS] = parser.value_float();
386+
ftMotion.cfg.dynFreqK.y = parser.value_float();
387387
flag.report_h = true;
388388
}
389389
else

Marlin/src/inc/SanityCheck.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4381,7 +4381,7 @@ static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive."
43814381
#error "FT_MOTION requires FTM_UNIFIED_BWS to be enabled because FBS is not yet implemented."
43824382
#endif
43834383
#if !HAS_X_AXIS
4384-
static_assert(FTM_DEFAULT_X_COMPENSATOR != ftMotionShaper_NONE, "Without any linear axes FTM_DEFAULT_X_COMPENSATOR must be ftMotionShaper_NONE.");
4384+
static_assert(FTM_DEFAULT_SHAPER_X != ftMotionShaper_NONE, "Without any linear axes FTM_DEFAULT_SHAPER_X must be ftMotionShaper_NONE.");
43854385
#endif
43864386
#if HAS_DYNAMIC_FREQ_MM
43874387
static_assert(FTM_DEFAULT_DYNFREQ_MODE != dynFreqMode_Z_BASED, "dynFreqMode_Z_BASED requires a Z axis.");

Marlin/src/lcd/menu/menu_motion.cpp

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ void menu_move() {
358358
}
359359

360360
inline void menu_ftm_cmpn_x() {
361-
const ftMotionShaper_t shaper = ftMotion.cfg.shaper[X_AXIS];
361+
const ftMotionShaper_t shaper = ftMotion.cfg.shaper.x;
362362
START_MENU();
363363
BACK_ITEM(MSG_FIXED_TIME_MOTION);
364364

@@ -376,7 +376,7 @@ void menu_move() {
376376
}
377377

378378
inline void menu_ftm_cmpn_y() {
379-
const ftMotionShaper_t shaper = ftMotion.cfg.shaper[Y_AXIS];
379+
const ftMotionShaper_t shaper = ftMotion.cfg.shaper.y;
380380
START_MENU();
381381
BACK_ITEM(MSG_FIXED_TIME_MOTION);
382382

@@ -442,21 +442,21 @@ void menu_move() {
442442
MENU_ITEM_ADDON_START_RJ(5); lcd_put_u8str(shaper_name[X_AXIS]); MENU_ITEM_ADDON_END();
443443

444444
if (AXIS_HAS_SHAPER(X)) {
445-
EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_FTM_BASE_FREQ_N, &c.baseFreq[X_AXIS], FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2, ftMotion.update_shaping_params);
446-
EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_FTM_ZETA_N, &c.zeta[0], 0.0f, 1.0f, ftMotion.update_shaping_params);
445+
EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_FTM_BASE_FREQ_N, &c.baseFreq.x, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2, ftMotion.update_shaping_params);
446+
EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_FTM_ZETA_N, &c.zeta.x, 0.0f, 1.0f, ftMotion.update_shaping_params);
447447
if (AXIS_HAS_EISHAPER(X))
448-
EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_FTM_VTOL_N, &c.vtol[0], 0.0f, 1.0f, ftMotion.update_shaping_params);
448+
EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_FTM_VTOL_N, &c.vtol.x, 0.0f, 1.0f, ftMotion.update_shaping_params);
449449
}
450450
#endif
451451
#if HAS_Y_AXIS
452452
SUBMENU_N(Y_AXIS, MSG_FTM_CMPN_MODE, menu_ftm_cmpn_y);
453453
MENU_ITEM_ADDON_START_RJ(5); lcd_put_u8str(shaper_name[Y_AXIS]); MENU_ITEM_ADDON_END();
454454

455455
if (AXIS_HAS_SHAPER(Y)) {
456-
EDIT_ITEM_FAST_N(float42_52, Y_AXIS, MSG_FTM_BASE_FREQ_N, &c.baseFreq[Y_AXIS], FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2, ftMotion.update_shaping_params);
457-
EDIT_ITEM_FAST_N(float42_52, Y_AXIS, MSG_FTM_ZETA_N, &c.zeta[1], 0.0f, 1.0f, ftMotion.update_shaping_params);
456+
EDIT_ITEM_FAST_N(float42_52, Y_AXIS, MSG_FTM_BASE_FREQ_N, &c.baseFreq.y, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2, ftMotion.update_shaping_params);
457+
EDIT_ITEM_FAST_N(float42_52, Y_AXIS, MSG_FTM_ZETA_N, &c.zeta.y, 0.0f, 1.0f, ftMotion.update_shaping_params);
458458
if (AXIS_HAS_EISHAPER(Y))
459-
EDIT_ITEM_FAST_N(float42_52, Y_AXIS, MSG_FTM_VTOL_N, &c.vtol[1], 0.0f, 1.0f, ftMotion.update_shaping_params);
459+
EDIT_ITEM_FAST_N(float42_52, Y_AXIS, MSG_FTM_VTOL_N, &c.vtol.y, 0.0f, 1.0f, ftMotion.update_shaping_params);
460460
}
461461
#endif
462462

@@ -465,10 +465,10 @@ void menu_move() {
465465
MENU_ITEM_ADDON_START_RJ(11); lcd_put_u8str(dmode); MENU_ITEM_ADDON_END();
466466
if (c.dynFreqMode != dynFreqMode_DISABLED) {
467467
#if HAS_X_AXIS
468-
EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_FTM_DFREQ_K_N, &c.dynFreqK[X_AXIS], 0.0f, 20.0f);
468+
EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_FTM_DFREQ_K_N, &c.dynFreqK.x, 0.0f, 20.0f);
469469
#endif
470470
#if HAS_Y_AXIS
471-
EDIT_ITEM_FAST_N(float42_52, Y_AXIS, MSG_FTM_DFREQ_K_N, &c.dynFreqK[Y_AXIS], 0.0f, 20.0f);
471+
EDIT_ITEM_FAST_N(float42_52, Y_AXIS, MSG_FTM_DFREQ_K_N, &c.dynFreqK.y, 0.0f, 20.0f);
472472
#endif
473473
}
474474
#endif
@@ -492,8 +492,6 @@ void menu_move() {
492492
MString<20> dmode = get_dyn_freq_mode_name();
493493
#endif
494494

495-
ft_config_t &c = ftMotion.cfg;
496-
497495
START_MENU();
498496

499497
#if HAS_X_AXIS
@@ -514,7 +512,6 @@ void menu_move() {
514512
#endif
515513

516514
END_MENU();
517-
518515
}
519516

520517
#endif // FT_MOTION_MENU

Marlin/src/module/ft_motion.cpp

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ void FTMotion::loop() {
134134
}
135135

136136
while (!blockProcRdy && (stepper.current_block = planner.get_current_block())) {
137-
if (stepper.current_block->is_sync()) { // Sync block?
137+
if (stepper.current_block->is_sync()) { // Sync block?
138138
if (stepper.current_block->is_sync_pos()) // Position sync? Set the position.
139139
stepper._set_position(stepper.current_block->position);
140140
discard_planner_block_protected();
@@ -166,7 +166,7 @@ void FTMotion::loop() {
166166
discard_planner_block_protected();
167167

168168
// Check if the block needs to be runout:
169-
if (!batchRdy && !planner.movesplanned()){
169+
if (!batchRdy && !planner.movesplanned()) {
170170
runoutBlock();
171171
makeVector(); // Do an additional makeVector call to guarantee batchRdy set this loop.
172172
}
@@ -196,7 +196,7 @@ void FTMotion::loop() {
196196
batchRdy = false; // Clear so makeVector() can resume generating points.
197197
}
198198

199-
// Interpolation.
199+
// Interpolation (generation of step commands from fixed time trajectory).
200200
while (batchRdyForInterp
201201
&& (stepperCmdBuffItems() < (FTM_STEPPERCMD_BUFF_SIZE) - (FTM_STEPS_PER_UNIT_TIME))) {
202202
convertToSteps(interpIdx);
@@ -350,14 +350,14 @@ void FTMotion::loop() {
350350
void FTMotion::update_shaping_params() {
351351
#if HAS_X_AXIS
352352
if ((shaping.x.ena = AXIS_HAS_SHAPER(X))) {
353-
shaping.x.set_axis_shaping_A(cfg.shaper[X_AXIS], cfg.zeta[X_AXIS], cfg.vtol[X_AXIS]);
354-
shaping.x.set_axis_shaping_N(cfg.shaper[X_AXIS], cfg.baseFreq[X_AXIS], cfg.zeta[X_AXIS]);
353+
shaping.x.set_axis_shaping_A(cfg.shaper.x, cfg.zeta.x, cfg.vtol.x);
354+
shaping.x.set_axis_shaping_N(cfg.shaper.x, cfg.baseFreq.x, cfg.zeta.x);
355355
}
356356
#endif
357357
#if HAS_Y_AXIS
358358
if ((shaping.y.ena = AXIS_HAS_SHAPER(Y))) {
359-
shaping.y.set_axis_shaping_A(cfg.shaper[Y_AXIS], cfg.zeta[Y_AXIS], cfg.vtol[Y_AXIS]);
360-
shaping.y.set_axis_shaping_N(cfg.shaper[Y_AXIS], cfg.baseFreq[Y_AXIS], cfg.zeta[Y_AXIS]);
359+
shaping.y.set_axis_shaping_A(cfg.shaper.y, cfg.zeta.y, cfg.vtol.y);
360+
shaping.y.set_axis_shaping_N(cfg.shaper.y, cfg.baseFreq.y, cfg.zeta.y);
361361
}
362362
#endif
363363
}
@@ -407,27 +407,29 @@ void FTMotion::discard_planner_block_protected() {
407407
}
408408
}
409409

410-
// Sets up a pseudo block to allow motion to settle buffers to empty. This is
411-
// called when the planner has only one block left. The buffers will be filled
412-
// with the last commanded position by setting the startPosn block variable to
413-
// the last position of the previous block and all ratios to zero such that no
414-
// axes' positions are incremented.
410+
/**
411+
* Set up a pseudo block to allow motion to settle and buffers to empty.
412+
* Called when the planner has one block left. The buffers will be filled
413+
* with the last commanded position by setting the startPosn block variable to
414+
* the last position of the previous block and all ratios to zero such that no
415+
* axes' positions are incremented.
416+
*/
415417
void FTMotion::runoutBlock() {
416418

417419
startPosn = endPosn_prevBlock;
418420
ratio.reset();
419421

420-
int32_t n_to_fill_batch = FTM_WINDOW_SIZE - makeVector_batchIdx;
422+
const int32_t n_to_fill_batch = (FTM_WINDOW_SIZE) - makeVector_batchIdx;
421423

422-
// This line is to be modified for FBS use; do not optimize out.
423-
int32_t n_to_settle_cmpnstr = (TERN_(HAS_X_AXIS, shaping.x.ena) || TERN_(HAS_Y_AXIS, shaping.y.ena )) ? FTM_ZMAX : 0;
424+
// This line or function is to be modified for FBS use; do not optimize out.
425+
const int32_t n_to_settle_shaper = num_samples_shaper_settle();
424426

425-
int32_t n_to_fill_batch_after_settling = (n_to_settle_cmpnstr > n_to_fill_batch) ?
426-
FTM_BATCH_SIZE - ((n_to_settle_cmpnstr - n_to_fill_batch) % FTM_BATCH_SIZE) : n_to_fill_batch - n_to_settle_cmpnstr;
427+
const int32_t n_diff = n_to_settle_shaper - n_to_fill_batch,
428+
n_to_fill_batch_after_settling = n_diff > 0 ? (FTM_BATCH_SIZE) - (n_diff % (FTM_BATCH_SIZE)) : -n_diff;
427429

428-
int32_t n_to_settle_and_fill_batch = n_to_settle_cmpnstr + n_to_fill_batch_after_settling;
430+
const int32_t n_to_settle_and_fill_batch = n_to_settle_shaper + n_to_fill_batch_after_settling;
429431

430-
max_intervals = PROP_BATCHES * FTM_BATCH_SIZE + n_to_settle_and_fill_batch;
432+
max_intervals = (PROP_BATCHES) * (FTM_BATCH_SIZE) + n_to_settle_and_fill_batch;
431433

432434
blockProcRdy = true;
433435
}
@@ -571,13 +573,13 @@ void FTMotion::makeVector() {
571573
accel_k = decel_P; // (mm/s^2) Acceleration K factor from Decel phase
572574
}
573575

574-
#define _FTM_TRAJ(A) traj.A[makeVector_batchIdx] = startPosn.A + ratio.A * dist;
575-
LOGICAL_AXIS_MAP_LC(_FTM_TRAJ);
576+
#define _SET_TRAJ(q) traj.q[makeVector_batchIdx] = startPosn.q + ratio.q * dist;
577+
LOGICAL_AXIS_MAP_LC(_SET_TRAJ);
576578

577579
#if HAS_EXTRUDERS
578580
if (cfg.linearAdvEna) {
579581
float dedt_adj = (traj.e[makeVector_batchIdx] - e_raw_z1) * (FTM_FS);
580-
if (ratio.e > 0.0f) dedt_adj += accel_k * cfg.linearAdvK * 0.0001f;
582+
if (ratio.e > 0.0f) dedt_adj += accel_k * cfg.linearAdvK;
581583

582584
e_raw_z1 = traj.e[makeVector_batchIdx];
583585
e_advanced_z1 += dedt_adj * (FTM_TS);
@@ -590,29 +592,32 @@ void FTMotion::makeVector() {
590592
switch (cfg.dynFreqMode) {
591593

592594
#if HAS_DYNAMIC_FREQ_MM
593-
case dynFreqMode_Z_BASED:
594-
if (traj.z[makeVector_batchIdx] != 0.0f) { // Only update if Z changed.
595+
case dynFreqMode_Z_BASED: {
596+
static float oldz = 0.0f;
597+
const float z = traj.z[makeVector_batchIdx];
598+
if (z != oldz) { // Only update if Z changed.
599+
oldz = z;
595600
#if HAS_X_AXIS
596-
const float xf = cfg.baseFreq[X_AXIS] + cfg.dynFreqK[X_AXIS] * traj.z[makeVector_batchIdx];
597-
shaping.x.set_axis_shaping_N(cfg.shaper[X_AXIS], _MAX(xf, FTM_MIN_SHAPE_FREQ), cfg.zeta[X_AXIS]);
601+
const float xf = cfg.baseFreq.x + cfg.dynFreqK.x * z;
602+
shaping.x.set_axis_shaping_N(cfg.shaper.x, _MAX(xf, FTM_MIN_SHAPE_FREQ), cfg.zeta.x);
598603
#endif
599604
#if HAS_Y_AXIS
600-
const float yf = cfg.baseFreq[Y_AXIS] + cfg.dynFreqK[Y_AXIS] * traj.z[makeVector_batchIdx];
601-
shaping.y.set_axis_shaping_N(cfg.shaper[Y_AXIS], _MAX(yf, FTM_MIN_SHAPE_FREQ), cfg.zeta[Y_AXIS]);
605+
const float yf = cfg.baseFreq.y + cfg.dynFreqK.y * z;
606+
shaping.y.set_axis_shaping_N(cfg.shaper.y, _MAX(yf, FTM_MIN_SHAPE_FREQ), cfg.zeta.y);
602607
#endif
603608
}
604-
break;
609+
} break;
605610
#endif
606611

607612
#if HAS_DYNAMIC_FREQ_G
608613
case dynFreqMode_MASS_BASED:
609614
// Update constantly. The optimization done for Z value makes
610615
// less sense for E, as E is expected to constantly change.
611616
#if HAS_X_AXIS
612-
shaping.x.set_axis_shaping_N(cfg.shaper[X_AXIS], cfg.baseFreq[X_AXIS] + cfg.dynFreqK[X_AXIS] * traj.e[makeVector_batchIdx], cfg.zeta[X_AXIS]);
617+
shaping.x.set_axis_shaping_N(cfg.shaper.x, cfg.baseFreq.x + cfg.dynFreqK.x * traj.e[makeVector_batchIdx], cfg.zeta.x);
613618
#endif
614619
#if HAS_Y_AXIS
615-
shaping.y.set_axis_shaping_N(cfg.shaper[Y_AXIS], cfg.baseFreq[Y_AXIS] + cfg.dynFreqK[Y_AXIS] * traj.e[makeVector_batchIdx], cfg.zeta[Y_AXIS]);
620+
shaping.y.set_axis_shaping_N(cfg.shaper.y, cfg.baseFreq.y + cfg.dynFreqK.y * traj.e[makeVector_batchIdx], cfg.zeta.y);
616621
#endif
617622
break;
618623
#endif
@@ -722,7 +727,7 @@ void FTMotion::convertToSteps(const uint32_t idx) {
722727
err_P += delta;
723728

724729
// Set up step/dir bits for all axes
725-
#define _COMMAND_RUN(AXIS) command_set[_AXIS(AXIS)](err_P[_AXIS(AXIS)], steps[_AXIS(AXIS)], cmd, _BV(FT_BIT_DIR_##AXIS), _BV(FT_BIT_STEP_##AXIS));
730+
#define _COMMAND_RUN(A) command_set[_AXIS(A)](err_P.A, steps.A, cmd, _BV(FT_BIT_DIR_##A), _BV(FT_BIT_STEP_##A));
726731
LOGICAL_AXIS_MAP(_COMMAND_RUN);
727732

728733
// Next circular buffer index

0 commit comments

Comments
 (0)