mirror of
https://github.com/MarlinFirmware/Marlin.git
synced 2025-12-27 09:59:52 -07:00
✨ FTM_SHAPER_* options (#28217)
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
This commit is contained in:
parent
7816f5dc46
commit
e434fd0aef
13 changed files with 211 additions and 143 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
#
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue