FTM_SHAPER_* options (#28217)

Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
This commit is contained in:
Harald Wagener 2025-12-12 03:50:13 +01:00 committed by GitHub
parent 7816f5dc46
commit e434fd0aef
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 211 additions and 143 deletions

View file

@ -1171,6 +1171,16 @@
#define FTM_DEFAULT_DYNFREQ_MODE dynFreqMode_DISABLED // Default mode of dynamic frequency calculation. (DISABLED, Z_BASED, MASS_BASED)
#endif
// Disable unused shapers if you need more free space
#define FTM_SHAPER_ZV
#define FTM_SHAPER_ZVD
#define FTM_SHAPER_ZVDD
#define FTM_SHAPER_ZVDDD
#define FTM_SHAPER_EI
#define FTM_SHAPER_2HEI
#define FTM_SHAPER_3HEI
#define FTM_SHAPER_MZV
#define FTM_DEFAULT_SHAPER_X ftMotionShaper_NONE // Default shaper mode on X axis (NONE, ZV, ZVD, ZVDD, ZVDDD, EI, 2HEI, 3HEI, MZV)
#define FTM_SHAPING_DEFAULT_FREQ_X 37.0f // (Hz) Default peak frequency used by input shapers
#define FTM_SHAPING_ZETA_X 0.1f // Zeta used by input shapers for X axis

View file

@ -136,13 +136,18 @@ void GcodeSuite::M493_report(const bool forReplay/*=true*/) {
#else
#define F_REPORT(A)
#endif
#if HAS_FTM_EI_SHAPING
#define Q_REPORT(A) , F(" Q"), c.vtol.A
#else
#define Q_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 \
Q_REPORT(A) \
);
// Shaper type for each axis
SHAPED_MAP(_REPORT_M493_AXIS);
@ -293,12 +298,14 @@ void GcodeSuite::M493() {
if (seenI && !goodZeta)
SERIAL_ECHOLN(F("?Invalid "), F("(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 && c.goodVtol(vtolVal);
if (seenQ && !goodVtol)
SERIAL_ECHOLN(F("?Invalid "), F("(Q) Vibration Tolerance value. (0.0-1.0)")); // VTol out of range
#if HAS_FTM_EI_SHAPING
// Vibration Tolerance parameter
const bool seenQ = parser.seenval('Q');
const float vtolVal = seenQ ? parser.value_float() : 0.0f;
const bool goodVtol = seenQ && c.goodVtol(vtolVal);
if (seenQ && !goodVtol)
SERIAL_ECHOLN(F("?Invalid "), F("(Q) Vibration Tolerance value. (0.0-1.0)")); // VTol out of range
#endif
const bool apply_xy = !parser.seen("XYZE");
@ -339,17 +346,19 @@ void GcodeSuite::M493() {
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " (I) zeta parameter.");
}
// Parse X vtol parameter
if (seenQ) {
if (AXIS_IS_EISHAPING(X)) {
if (goodVtol) {
c.vtol.x = vtolVal;
flag.update = true;
#if HAS_FTM_EI_SHAPING
// Parse X vtol parameter
if (seenQ) {
if (AXIS_IS_EISHAPING(X)) {
if (goodVtol) {
c.vtol.x = vtolVal;
flag.update = true;
}
}
else
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " (Q) vtol parameter.");
}
else
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " (Q) vtol parameter.");
}
#endif
}
#endif // HAS_X_AXIS
@ -391,16 +400,18 @@ void GcodeSuite::M493() {
}
// Parse Y vtol parameter
if (seenQ) {
if (AXIS_IS_EISHAPING(Y)) {
if (goodVtol) {
c.vtol.y = vtolVal;
flag.update = true;
#if HAS_FTM_EI_SHAPING
if (seenQ) {
if (AXIS_IS_EISHAPING(Y)) {
if (goodVtol) {
c.vtol.y = vtolVal;
flag.update = true;
}
}
else
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " (Q) vtol parameter.");
}
else
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " (Q) vtol parameter.");
}
#endif
}
#endif // HAS_Y_AXIS
@ -442,16 +453,18 @@ void GcodeSuite::M493() {
}
// Parse Z vtol parameter
if (seenQ) {
if (AXIS_IS_EISHAPING(Z)) {
if (goodVtol) {
c.vtol.z = vtolVal;
flag.update = true;
#if HAS_FTM_EI_SHAPING
if (seenQ) {
if (AXIS_IS_EISHAPING(Z)) {
if (goodVtol) {
c.vtol.z = vtolVal;
flag.update = true;
}
}
else
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " (Q) vtol parameter.");
}
else
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " (Q) vtol parameter.");
}
#endif
}
#endif // FTM_SHAPER_Z
@ -493,16 +506,18 @@ void GcodeSuite::M493() {
}
// Parse E vtol parameter
if (seenQ) {
if (AXIS_IS_EISHAPING(E)) {
if (goodVtol) {
c.vtol.e = vtolVal;
flag.update = true;
#if HAS_FTM_EI_SHAPING
if (seenQ) {
if (AXIS_IS_EISHAPING(E)) {
if (goodVtol) {
c.vtol.e = vtolVal;
flag.update = true;
}
}
else
SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " (Q) vtol parameter.");
}
else
SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " (Q) vtol parameter.");
}
#endif
}
#endif // FTM_SHAPER_E

View file

@ -29,13 +29,12 @@
#include "../../../module/planner.h"
void say_ftm_settings() {
#if ENABLED(FTM_POLYS)
SERIAL_ECHOLN(F(" Trajectory: "), ftMotion.getTrajectoryName(), C('('), (uint8_t)ftMotion.getTrajectoryType(), C(')'));
#if ANY(FTM_POLYS, FTM_SMOOTHING)
const ft_config_t &c = ftMotion.cfg;
#endif
const ft_config_t &c = ftMotion.cfg;
#if ENABLED(FTM_POLYS)
SERIAL_ECHOLN(F(" Trajectory: "), ftMotion.getTrajectoryName(), C('('), (uint8_t)ftMotion.getTrajectoryType(), C(')'));
if (ftMotion.getTrajectoryType() == TrajectoryType::POLY6)
SERIAL_ECHOLNPGM(" Poly6 Overshoot: ", p_float_t(c.poly6_acceleration_overshoot, 3));
#endif

View file

@ -375,6 +375,9 @@
#undef MULTISTEPPING_LIMIT
#define MULTISTEPPING_LIMIT 1
#endif
#if ANY(FTM_SHAPER_EI, FTM_SHAPER_2HEI, FTM_SHAPER_3HEI)
#define HAS_FTM_EI_SHAPING 1
#endif
#endif
#if DISABLED(NO_STANDARD_MOTION)
#define HAS_STANDARD_MOTION 1

View file

@ -3690,13 +3690,16 @@
#define FTM_TS (1.0f / FTM_FS) // (s) Time step for trajectory generation. (Reciprocal of FTM_FS)
#define FTM_RATIO (FTM_FS / FTM_MIN_SHAPE_FREQ) // Factor for use in FTM_ZMAX. DON'T CHANGE.
#define FTM_SMOOTH_MAX_I uint32_t(TERN0(FTM_SMOOTHING, CEIL(FTM_FS * FTM_MAX_SMOOTHING_TIME))) // Max delays for smoothing
#define FTM_ZMAX (FTM_RATIO * 2 + FTM_SMOOTH_MAX_I) // Maximum delays for shaping functions (even numbers only!)
// Calculate as:
// ZV : FTM_RATIO / 2
// ZVD, MZV : FTM_RATIO
// 2HEI : FTM_RATIO * 3 / 2
// 3HEI : FTM_RATIO * 2
#define FTM_SMOOTHING_ORDER 5 // 3 to 5 is closest to gaussian
// Maximum delays for shaping functions (even numbers only!)
#define FTM_ZMAX (TERN(HAS_FTM_EI_SHAPING, 2, 1) * FTM_RATIO + FTM_SMOOTH_MAX_I)
#define FTM_SMOOTHING_ORDER 5 // 3 to 5 is closest to Gaussian
// Calculate as:
// ZV : FTM_RATIO / 2
// ZVD, MZV : FTM_RATIO
// 2HEI : FTM_RATIO * 3 / 2
// 3HEI : FTM_RATIO * 2
#ifndef FTM_BUFFER_SIZE
#define FTM_BUFFER_SIZE 128
#endif

View file

@ -4519,7 +4519,10 @@ static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive."
#error "Z_LATE_ENABLE is not yet available in FT_MOTION. Disable NO_STANDARD_MOTION if you require it."
#endif
#endif
#endif
#if HAS_FTM_SHAPING && NONE(FTM_SHAPER_ZV, FTM_SHAPER_ZVD, FTM_SHAPER_ZVDD, FTM_SHAPER_ZVDDD, FTM_SHAPER_EI, FTM_SHAPER_2HEI, FTM_SHAPER_3HEI, FTM_SHAPER_MZV)
#error "For FT_MOTION at least one FTM_SHAPER_* type must be enabled."
#endif
#endif // FT_MOTION
// Multi-Stepping Limit
static_assert(WITHIN(MULTISTEPPING_LIMIT, 1, 128) && IS_POWER_OF_2(MULTISTEPPING_LIMIT), "MULTISTEPPING_LIMIT must be 1, 2, 4, 8, 16, 32, 64, or 128.");

View file

@ -444,13 +444,20 @@ void menu_move() {
START_MENU();
BACK_ITEM(MSG_FIXED_TIME_MOTION);
if (axis == X_AXIS || axis == Y_AXIS || TERN0(FTM_SHAPER_Z, axis == Z_AXIS) || TERN0(FTM_SHAPER_E, axis == E_AXIS)) {
#if HAS_FTM_EI_SHAPING
#define EISHAPER_MENU_ITEM(A) \
if (AXIS_IS_EISHAPING(A)) \
EDIT_ITEM_FAST_N(float42_52, axis, MSG_FTM_VTOL_N, &c.vtol[axis], 0.0f, 1.0f, ftMotion.update_shaping_params);
#else
#define EISHAPER_MENU_ITEM(A) NOOP
#endif
if (false SHAPED_GANG(|| axis == X_AXIS, || axis == Y_AXIS, || axis == Z_AXIS, || axis == E_AXIS)) {
SUBMENU_N_S(axis, get_shaper_name(axis), MSG_FTM_CMPN_MODE, menu_ftm_shaper);
if (IS_SHAPING(c.shaper[axis])) {
if (AXIS_IS_SHAPING(axis)) {
EDIT_ITEM_FAST_N(float42_52, axis, MSG_FTM_BASE_FREQ_N, &c.baseFreq[axis], FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2, ftMotion.update_shaping_params);
EDIT_ITEM_FAST_N(float42_52, axis, MSG_FTM_ZETA_N, &c.zeta[axis], 0.0f, 1.0f, ftMotion.update_shaping_params);
if (IS_EISHAPING(c.shaper[axis]))
EDIT_ITEM_FAST_N(float42_52, axis, MSG_FTM_VTOL_N, &c.vtol[axis], 0.0f, 1.0f, ftMotion.update_shaping_params);
EISHAPER_MENU_ITEM(axis);
}
}

View file

@ -193,7 +193,7 @@ void FTMotion::loop() {
void FTMotion::update_shaping_params() {
#define UPDATE_SHAPER(A) \
shaping.A.ena = IS_SHAPING(ftMotion.cfg.shaper.A); \
shaping.A.set_axis_shaping_A(cfg.shaper.A, cfg.zeta.A, cfg.vtol.A); \
shaping.A.set_axis_shaping_A(cfg.shaper.A, cfg.zeta.A OPTARG(HAS_FTM_EI_SHAPING, cfg.vtol.A)); \
shaping.A.set_axis_shaping_N(cfg.shaper.A, cfg.baseFreq.A, cfg.zeta.A);
SHAPED_MAP(UPDATE_SHAPER);

View file

@ -72,8 +72,11 @@ typedef struct FTConfig {
SHAPED_ARRAY(FTM_SHAPING_DEFAULT_FREQ_X, FTM_SHAPING_DEFAULT_FREQ_Y, FTM_SHAPING_DEFAULT_FREQ_Z, FTM_SHAPING_DEFAULT_FREQ_E);
ft_shaped_float_t zeta = // Damping factor
SHAPED_ARRAY(FTM_SHAPING_ZETA_X, FTM_SHAPING_ZETA_Y, FTM_SHAPING_ZETA_Z, FTM_SHAPING_ZETA_E);
ft_shaped_float_t vtol = // Vibration Level
SHAPED_ARRAY(FTM_SHAPING_V_TOL_X, FTM_SHAPING_V_TOL_Y, FTM_SHAPING_V_TOL_Z, FTM_SHAPING_V_TOL_E);
#if HAS_FTM_EI_SHAPING
ft_shaped_float_t vtol = // Vibration Level
SHAPED_ARRAY(FTM_SHAPING_V_TOL_X, FTM_SHAPING_V_TOL_Y, FTM_SHAPING_V_TOL_Z, FTM_SHAPING_V_TOL_E);
#endif
#if HAS_DYNAMIC_FREQ
dynFreqMode_t dynFreqMode = FTM_DEFAULT_DYNFREQ_MODE; // Dynamic frequency mode configuration.
@ -147,7 +150,7 @@ typedef struct FTConfig {
shaper.A = FTM_DEFAULT_SHAPER_##A; \
baseFreq.A = FTM_SHAPING_DEFAULT_FREQ_##A; \
zeta.A = FTM_SHAPING_ZETA_##A; \
vtol.A = FTM_SHAPING_V_TOL_##A; \
TERN_(HAS_FTM_EI_SHAPING, vtol.A = FTM_SHAPING_V_TOL_##A); \
}while(0);
SHAPED_MAP(_SET_CFG_DEFAULTS);

View file

@ -27,7 +27,11 @@
#include "shaping.h"
// Refresh the gains used by shaping functions.
void AxisShaping::set_axis_shaping_A(const ftMotionShaper_t shaper, const float zeta, const float vtol) {
void AxisShaping::set_axis_shaping_A(
const ftMotionShaper_t shaper,
const float zeta
OPTARG(HAS_FTM_EI_SHAPING, const float vtol)
) {
const float K = exp(-zeta * M_PI / sqrt(1.f - sq(zeta))),
K2 = sq(K),
@ -36,79 +40,95 @@ void AxisShaping::set_axis_shaping_A(const ftMotionShaper_t shaper, const float
switch (shaper) {
case ftMotionShaper_ZV:
max_i = 1U;
Ai[0] = 1.0f / (1.0f + K);
Ai[1] = Ai[0] * K;
#if ENABLED(FTM_SHAPER_ZV)
case ftMotionShaper_ZV:
max_i = 1U;
Ai[0] = 1.0f / (1.0f + K);
Ai[1] = Ai[0] * K;
break;
#endif
#if ENABLED(FTM_SHAPER_ZVD)
case ftMotionShaper_ZVD:
max_i = 2U;
Ai[0] = 1.0f / (1.0f + 2.0f * K + K2);
Ai[1] = Ai[0] * 2.0f * K;
Ai[2] = Ai[0] * K2;
break;
#endif
#if ENABLED(FTM_SHAPER_ZVDD)
case ftMotionShaper_ZVDD:
max_i = 3U;
Ai[0] = 1.0f / (1.0f + 3.0f * K + 3.0f * K2 + K3);
Ai[1] = Ai[0] * 3.0f * K;
Ai[2] = Ai[0] * 3.0f * K2;
Ai[3] = Ai[0] * K3;
break;
#endif
#if ENABLED(FTM_SHAPER_ZVDDD)
case ftMotionShaper_ZVDDD:
max_i = 4U;
Ai[0] = 1.0f / (1.0f + 4.0f * K + 6.0f * K2 + 4.0f * K3 + K4);
Ai[1] = Ai[0] * 4.0f * K;
Ai[2] = Ai[0] * 6.0f * K2;
Ai[3] = Ai[0] * 4.0f * K3;
Ai[4] = Ai[0] * K4;
break;
#endif
#if ENABLED(FTM_SHAPER_EI)
case ftMotionShaper_EI: {
max_i = 2U;
Ai[0] = 0.25f * (1.0f + vtol);
Ai[1] = 0.50f * (1.0f - vtol) * K;
Ai[2] = Ai[0] * K2;
const float adj = 1.0f / (Ai[0] + Ai[1] + Ai[2]);
for (uint32_t i = 0; i < 3U; i++) Ai[i] *= adj;
} break;
#endif
#if ENABLED(FTM_SHAPER_H2EI)
case ftMotionShaper_2HEI: {
max_i = 3U;
const float vtolx2 = sq(vtol);
const float X = POW(vtolx2 * (sqrt(1.0f - vtolx2) + 1.0f), 1.0f / 3.0f);
Ai[0] = (3.0f * sq(X) + 2.0f * X + 3.0f * vtolx2) / (16.0f * X);
Ai[1] = (0.5f - Ai[0]) * K;
Ai[2] = Ai[1] * K;
Ai[3] = Ai[0] * K3;
const float adj = 1.0f / (Ai[0] + Ai[1] + Ai[2] + Ai[3]);
for (uint32_t i = 0; i < 4U; i++) Ai[i] *= adj;
} break;
#endif
#if ENABLED(FTM_SHAPER_3HEI)
case ftMotionShaper_3HEI: {
max_i = 4U;
Ai[0] = 0.0625f * ( 1.0f + 3.0f * vtol + 2.0f * sqrt( 2.0f * ( vtol + 1.0f ) * vtol ) );
Ai[1] = 0.25f * ( 1.0f - vtol ) * K;
Ai[2] = ( 0.5f * ( 1.0f + vtol ) - 2.0f * Ai[0] ) * K2;
Ai[3] = Ai[1] * K2;
Ai[4] = Ai[0] * K4;
const float adj = 1.0f / (Ai[0] + Ai[1] + Ai[2] + Ai[3] + Ai[4]);
for (uint32_t i = 0; i < 5U; i++) Ai[i] *= adj;
} break;
#endif
#if ENABLED(FTM_SHAPER_MZV)
case ftMotionShaper_MZV: {
max_i = 2U;
const float Bx = 1.4142135623730950488016887242097f * K;
Ai[0] = 1.0f / (1.0f + Bx + K2);
Ai[1] = Ai[0] * Bx;
Ai[2] = Ai[0] * K2;
}
break;
case ftMotionShaper_ZVD:
max_i = 2U;
Ai[0] = 1.0f / (1.0f + 2.0f * K + K2);
Ai[1] = Ai[0] * 2.0f * K;
Ai[2] = Ai[0] * K2;
break;
case ftMotionShaper_ZVDD:
max_i = 3U;
Ai[0] = 1.0f / (1.0f + 3.0f * K + 3.0f * K2 + K3);
Ai[1] = Ai[0] * 3.0f * K;
Ai[2] = Ai[0] * 3.0f * K2;
Ai[3] = Ai[0] * K3;
break;
case ftMotionShaper_ZVDDD:
max_i = 4U;
Ai[0] = 1.0f / (1.0f + 4.0f * K + 6.0f * K2 + 4.0f * K3 + K4);
Ai[1] = Ai[0] * 4.0f * K;
Ai[2] = Ai[0] * 6.0f * K2;
Ai[3] = Ai[0] * 4.0f * K3;
Ai[4] = Ai[0] * K4;
break;
case ftMotionShaper_EI: {
max_i = 2U;
Ai[0] = 0.25f * (1.0f + vtol);
Ai[1] = 0.50f * (1.0f - vtol) * K;
Ai[2] = Ai[0] * K2;
const float adj = 1.0f / (Ai[0] + Ai[1] + Ai[2]);
for (uint32_t i = 0; i < 3U; i++) Ai[i] *= adj;
} break;
case ftMotionShaper_2HEI: {
max_i = 3U;
const float vtolx2 = sq(vtol);
const float X = POW(vtolx2 * (sqrt(1.0f - vtolx2) + 1.0f), 1.0f / 3.0f);
Ai[0] = (3.0f * sq(X) + 2.0f * X + 3.0f * vtolx2) / (16.0f * X);
Ai[1] = (0.5f - Ai[0]) * K;
Ai[2] = Ai[1] * K;
Ai[3] = Ai[0] * K3;
const float adj = 1.0f / (Ai[0] + Ai[1] + Ai[2] + Ai[3]);
for (uint32_t i = 0; i < 4U; i++) Ai[i] *= adj;
} break;
case ftMotionShaper_3HEI: {
max_i = 4U;
Ai[0] = 0.0625f * ( 1.0f + 3.0f * vtol + 2.0f * sqrt( 2.0f * ( vtol + 1.0f ) * vtol ) );
Ai[1] = 0.25f * ( 1.0f - vtol ) * K;
Ai[2] = ( 0.5f * ( 1.0f + vtol ) - 2.0f * Ai[0] ) * K2;
Ai[3] = Ai[1] * K2;
Ai[4] = Ai[0] * K4;
const float adj = 1.0f / (Ai[0] + Ai[1] + Ai[2] + Ai[3] + Ai[4]);
for (uint32_t i = 0; i < 5U; i++) Ai[i] *= adj;
} break;
case ftMotionShaper_MZV: {
max_i = 2U;
const float Bx = 1.4142135623730950488016887242097f * K;
Ai[0] = 1.0f / (1.0f + Bx + K2);
Ai[1] = Ai[0] * Bx;
Ai[2] = Ai[0] * K2;
}
break;
#endif
case ftMotionShaper_NONE:
max_i = 0;

View file

@ -41,8 +41,8 @@ enum dynFreqMode_t : uint8_t {
dynFreqMode_MASS_BASED = 2
};
#define IS_SHAPING(S) (S != ftMotionShaper_NONE)
#define IS_EISHAPING(S) WITHIN(S, ftMotionShaper_EI, ftMotionShaper_3HEI)
#define IS_SHAPING(S) ((S) != ftMotionShaper_NONE)
#define IS_EISHAPING(S) TERN0(HAS_FTM_EI_SHAPING, WITHIN(S, ftMotionShaper_EI, ftMotionShaper_3HEI))
#define AXIS_IS_SHAPING(A) TERN0(FTM_SHAPER_##A, IS_SHAPING(ftMotion.cfg.shaper.A))
#define AXIS_IS_EISHAPING(A) TERN0(FTM_SHAPER_##A, IS_EISHAPING(ftMotion.cfg.shaper.A))
@ -104,7 +104,11 @@ typedef struct AxisShaping {
void set_axis_shaping_N(const ftMotionShaper_t shaper, const float f, const float zeta);
// Set the indices (per pulse delays) used by shaping functions
void set_axis_shaping_A(const ftMotionShaper_t shaper, const float zeta, const float vtol);
void set_axis_shaping_A(
const ftMotionShaper_t shaper,
const float zeta
OPTARG(HAS_FTM_EI_SHAPING, const float vtol)
);
} axis_shaping_t;

View file

@ -1569,10 +1569,14 @@ HAL_STEP_TIMER_ISR() {
void Stepper::isr() {
static hal_timer_t nextMainISR = 0; // Interval until the next main Stepper Pulse phase (0 = Now)
#if HAS_STANDARD_MOTION
static hal_timer_t nextMainISR = 0; // Interval until the next main Stepper Pulse phase (0 = Now)
#endif
#if ENABLED(SMOOTH_LIN_ADVANCE)
static hal_timer_t smoothLinAdvISR = 0;
static hal_timer_t smoothLinAdvISR = 0; // Interval until the next Smooth Linear Advance phase (0 = Now)
#endif
#if ENABLED(FT_MOTION)
static uint32_t ftMotion_nextStepperISR = 0; // Interval until the next FT Motion phase (0 = Now)
#endif
// Program timer compare for the maximum period, so it does NOT
@ -1586,10 +1590,6 @@ void Stepper::isr() {
// Limit the amount of iterations
uint8_t max_loops = 10;
#if ENABLED(FT_MOTION)
static uint32_t ftMotion_nextStepperISR = 0U; // Storage for the next ISR for stepping.
#endif
// FT Motion can be toggled if Standard Motion is also active
const bool using_ftMotion = ENABLED(NO_STANDARD_MOTION) || TERN0(FT_MOTION, ftMotion.cfg.active);

View file

@ -75,6 +75,7 @@ opt_set MOTHERBOARD BOARD_RAMBO EXTRUDERS 0 TEMP_SENSOR_BED 1 TEMP_SENSOR_PROBE
AXIS_RELATIVE_MODES '{ false, false, false }'
opt_enable REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER FIX_MOUNTED_PROBE Z_SAFE_HOMING \
FT_MOTION FTM_SMOOTHING FTM_HOME_AND_PROBE NO_STANDARD_MOTION
opt_disable FTM_SHAPER_EI FTM_SHAPER_2HEI FTM_SHAPER_3HEI
exec_test $1 $2 "Rambo with ZERO EXTRUDERS, heated bed, FT_MOTION" "$3"
#