FT_MOTION > FTM_POLYS (#28197)

This commit is contained in:
Harald Wagener
2025-12-01 03:05:45 +01:00
committed by GitHub
parent 544cde20fb
commit 35319049fe
9 changed files with 114 additions and 75 deletions

View File

@@ -1201,14 +1201,17 @@
// smoothing acceleration peaks, which may also smooth curved surfaces.
#endif
#define FTM_TRAJECTORY_TYPE TRAPEZOIDAL // Block acceleration profile (TRAPEZOIDAL, POLY5, POLY6)
// TRAPEZOIDAL: Continuous Velocity. Max acceleration is respected.
// POLY5: Like POLY6 with 1.5x but uses less CPU.
// POLY6: Continuous Acceleration (aka S_CURVE).
// POLY trajectories not only reduce resonances without rounding corners, but also
// reduce extruder strain due to linear advance.
#define FTM_POLYS // Disable POLY5/6 to save ~3k of Flash. Preserves TRAPEZOIDAL.
#if ENABLED(FTM_POLYS)
#define FTM_TRAJECTORY_TYPE TRAPEZOIDAL // Block acceleration profile (TRAPEZOIDAL, POLY5, POLY6)
// TRAPEZOIDAL: Continuous Velocity. Max acceleration is respected.
// POLY5: Like POLY6 with 1.5x but uses less CPU.
// POLY6: Continuous Acceleration (aka S_CURVE).
// POLY trajectories not only reduce resonances without rounding corners, but also
// reduce extruder strain due to linear advance.
#define FTM_POLY6_ACCELERATION_OVERSHOOT 1.875f // Max acceleration overshoot factor for POLY6 (1.25 to 1.875)
#define FTM_POLY6_ACCELERATION_OVERSHOOT 1.875f // Max acceleration overshoot factor for POLY6 (1.25 to 1.875)
#endif
/**
* Advanced configuration

View File

@@ -38,12 +38,16 @@ static FSTR_P get_trajectory_type_name() {
}
void say_ftm_settings() {
SERIAL_ECHOLN(F(" Trajectory: "), get_trajectory_type_name(), C('('), (uint8_t)ftMotion.getTrajectoryType(), C(')'));
#if ENABLED(FTM_POLYS)
SERIAL_ECHOLN(F(" Trajectory: "), get_trajectory_type_name(), C('('), (uint8_t)ftMotion.getTrajectoryType(), C(')'));
#endif
const ft_config_t &c = ftMotion.cfg;
if (ftMotion.getTrajectoryType() == TrajectoryType::POLY6)
SERIAL_ECHOLNPGM(" Poly6 Overshoot: ", p_float_t(c.poly6_acceleration_overshoot, 3));
#if ENABLED(FTM_POLYS)
if (ftMotion.getTrajectoryType() == TrajectoryType::POLY6)
SERIAL_ECHOLNPGM(" Poly6 Overshoot: ", p_float_t(c.poly6_acceleration_overshoot, 3));
#endif
#if ENABLED(FTM_SMOOTHING)
#define _SMOO_REPORT(A) SERIAL_ECHOLN(F(" "), C(IAXIS_CHAR(_AXIS(A))), F(" smoothing time: "), p_float_t(c.smoothingTime.A, 3), C('s'));
@@ -66,10 +70,13 @@ void GcodeSuite::M494_report(const bool forReplay/*=true*/) {
" Z", c.smoothingTime.Z, " E", c.smoothingTime.E
)
);
#endif
#endif // FTM_SMOOTHING
if (ftMotion.getTrajectoryType() == TrajectoryType::POLY6)
SERIAL_ECHOPGM(" O", c.poly6_acceleration_overshoot);
#if ENABLED(FTM_POLYS)
if (ftMotion.getTrajectoryType() == TrajectoryType::POLY6)
SERIAL_ECHOPGM(" O", c.poly6_acceleration_overshoot);
#endif // FTM_POLYS
SERIAL_EOL();
}
@@ -88,28 +95,31 @@ void GcodeSuite::M494_report(const bool forReplay/*=true*/) {
void GcodeSuite::M494() {
bool report = !parser.seen_any();
// Parse trajectory type parameter.
if (parser.seenval('T')) {
const int val = parser.value_int();
if (WITHIN(val, 0, 2)) {
planner.synchronize();
ftMotion.setTrajectoryType((TrajectoryType)val);
report = true;
}
else
SERIAL_ECHOLN(F("?Invalid "), F("trajectory type [T] value. Use 0=TRAPEZOIDAL, 1=POLY5, 2=POLY6"));
}
#if ENABLED(FTM_POLYS)
// Parse overshoot parameter.
if (parser.seenval('O')) {
const float val = parser.value_float();
if (WITHIN(val, 1.25f, 1.875f)) {
ftMotion.cfg.poly6_acceleration_overshoot = val;
report = true;
// Parse trajectory type parameter.
if (parser.seenval('T')) {
const int val = parser.value_int();
if (WITHIN(val, 0, 2)) {
planner.synchronize();
ftMotion.setTrajectoryType((TrajectoryType)val);
report = true;
}
else
SERIAL_ECHOLN(F("?Invalid "), F("trajectory type [T] value. Use 0=TRAPEZOIDAL, 1=POLY5, 2=POLY6"));
}
else
SERIAL_ECHOLN(F("?Invalid "), F("overshoot [O] value. Range 1.25-1.875"));
}
// Parse overshoot parameter.
if (parser.seenval('O')) {
const float val = parser.value_float();
if (WITHIN(val, 1.25f, 1.875f)) {
ftMotion.cfg.poly6_acceleration_overshoot = val;
report = true;
}
else
SERIAL_ECHOLN(F("?Invalid "), F("overshoot [O] value. Range 1.25-1.875"));
}
#endif // FTM_POLYS
#if ENABLED(FTM_SMOOTHING)

View File

@@ -926,8 +926,8 @@ void GcodeSuite::process_parsed_command(bool no_ok/*=false*/) {
#endif
#if ENABLED(FT_MOTION)
case 493: M493(); break; // M493: Fixed-Time Motion control
#if ENABLED(FTM_SMOOTHING)
case 493: M493(); break; // M493: Fixed-Time Motion control
#if ANY(FTM_SMOOTHING, FTM_POLYS)
case 494: M494(); break; // M494: Fixed-Time Motion extras
#endif
#if ENABLED(FTM_RESONANCE_TEST)

View File

@@ -1541,6 +1541,9 @@
#if !HAS_EXTRUDERS
#undef FTM_SHAPER_E
#endif
#if DISABLED(FTM_POLYS)
#define FTM_TRAJECTORY_TYPE TRAPEZOIDAL
#endif
#endif
// Multi-Stepping Limit

View File

@@ -327,14 +327,17 @@ void menu_move() {
}
}
FSTR_P get_trajectory_name() {
switch (ftMotion.getTrajectoryType()) {
default:
case TrajectoryType::TRAPEZOIDAL: return GET_TEXT_F(MSG_FTM_TRAPEZOIDAL);
case TrajectoryType::POLY5: return GET_TEXT_F(MSG_FTM_POLY5);
case TrajectoryType::POLY6: return GET_TEXT_F(MSG_FTM_POLY6);
#if ENABLED(FTM_POLYS)
FSTR_P get_trajectory_name() {
switch (ftMotion.getTrajectoryType()) {
default:
case TrajectoryType::TRAPEZOIDAL: return GET_TEXT_F(MSG_FTM_TRAPEZOIDAL);
case TrajectoryType::POLY5: return GET_TEXT_F(MSG_FTM_POLY5);
case TrajectoryType::POLY6: return GET_TEXT_F(MSG_FTM_POLY6);
}
}
}
#endif // FTM_POLYS
#if HAS_DYNAMIC_FREQ
FSTR_P get_dyn_freq_mode_name() {
@@ -371,16 +374,17 @@ void menu_move() {
}
SHAPED_MAP(MENU_FTM_SHAPER);
void menu_ftm_trajectory_generator() {
const TrajectoryType current_type = ftMotion.getTrajectoryType();
START_MENU();
BACK_ITEM(MSG_FIXED_TIME_MOTION);
if (current_type != TrajectoryType::TRAPEZOIDAL) ACTION_ITEM(MSG_FTM_TRAPEZOIDAL, []{ planner.synchronize(); ftMotion.setTrajectoryType(TrajectoryType::TRAPEZOIDAL); ui.go_back(); });
if (current_type != TrajectoryType::POLY5) ACTION_ITEM(MSG_FTM_POLY5, []{ planner.synchronize(); ftMotion.setTrajectoryType(TrajectoryType::POLY5); ui.go_back(); });
if (current_type != TrajectoryType::POLY6) ACTION_ITEM(MSG_FTM_POLY6, []{ planner.synchronize(); ftMotion.setTrajectoryType(TrajectoryType::POLY6); ui.go_back(); });
#if ENABLED(FTM_POLYS)
void menu_ftm_trajectory_generator() {
const TrajectoryType current_type = ftMotion.getTrajectoryType();
START_MENU();
BACK_ITEM(MSG_FIXED_TIME_MOTION);
if (current_type != TrajectoryType::TRAPEZOIDAL) ACTION_ITEM(MSG_FTM_TRAPEZOIDAL, []{ planner.synchronize(); ftMotion.setTrajectoryType(TrajectoryType::TRAPEZOIDAL); ui.go_back(); });
if (current_type != TrajectoryType::POLY5) ACTION_ITEM(MSG_FTM_POLY5, []{ planner.synchronize(); ftMotion.setTrajectoryType(TrajectoryType::POLY5); ui.go_back(); });
if (current_type != TrajectoryType::POLY6) ACTION_ITEM(MSG_FTM_POLY6, []{ planner.synchronize(); ftMotion.setTrajectoryType(TrajectoryType::POLY6); ui.go_back(); });
END_MENU();
}
#endif // FTM_POLYS
#if ENABLED(FTM_RESONANCE_TEST)
@@ -497,7 +501,9 @@ void menu_move() {
#else
auto _shaper_name = [](const AxisEnum a) { return get_shaper_name(a); };
auto _dmode = []{ return get_dyn_freq_mode_name(); };
auto _traj_name = []{ return get_trajectory_name(); };
#if ENABLED(FTM_POLYS)
auto _traj_name = []{ return get_trajectory_name(); };
#endif
#endif
START_MENU();
@@ -508,6 +514,12 @@ void menu_move() {
// Show only when FT Motion is active (or optionally always show)
if (c.active || ENABLED(FT_MOTION_NO_MENU_TOGGLE)) {
#if ENABLED(FTM_POLYS)
SUBMENU_S(_traj_name(), MSG_FTM_TRAJECTORY, menu_ftm_trajectory_generator);
if (ftMotion.getTrajectoryType() == TrajectoryType::POLY6)
EDIT_ITEM(float42_52, MSG_FTM_POLY6_OVERSHOOT, &c.poly6_acceleration_overshoot, 1.25f, 1.875f);
#endif
#define SHAPER_MENU_ITEM(A) \
SUBMENU_N_S(_AXIS(A), _shaper_name(_AXIS(A)), MSG_FTM_CMPN_MODE, menu_ftm_shaper_##A); \
if (AXIS_IS_SHAPING(A)) { \
@@ -516,11 +528,6 @@ void menu_move() {
if (AXIS_IS_EISHAPING(A)) \
EDIT_ITEM_FAST_N(float42_52, _AXIS(A), MSG_FTM_VTOL_N, &c.vtol.A, 0.0f, 1.0f, ftMotion.update_shaping_params); \
}
SUBMENU_S(_traj_name(), MSG_FTM_TRAJECTORY, menu_ftm_trajectory_generator);
if (ftMotion.getTrajectoryType() == TrajectoryType::POLY6)
EDIT_ITEM(float42_52, MSG_FTM_POLY6_OVERSHOOT, &c.poly6_acceleration_overshoot, 1.25f, 1.875f);
SHAPED_MAP(SHAPER_MENU_ITEM);
#if HAS_DYNAMIC_FREQ
@@ -596,10 +603,11 @@ void menu_move() {
START_MENU();
BACK_ITEM(MSG_TUNE);
SUBMENU_S(_traj_name(), MSG_FTM_TRAJECTORY, menu_ftm_trajectory_generator);
if (ftMotion.getTrajectoryType() == TrajectoryType::POLY6)
EDIT_ITEM(float42_52, MSG_FTM_POLY6_OVERSHOOT, &c.poly6_acceleration_overshoot, 1.25f, 1.875f);
#if ENABLED(FTM_POLYS)
SUBMENU_S(_traj_name(), MSG_FTM_TRAJECTORY, menu_ftm_trajectory_generator);
if (ftMotion.getTrajectoryType() == TrajectoryType::POLY6)
EDIT_ITEM(float42_52, MSG_FTM_POLY6_OVERSHOOT, &c.poly6_acceleration_overshoot, 1.25f, 1.875f);
#endif
#define _CMPM_MENU_ITEM(A) SUBMENU_N_S(_AXIS(A), _shaper_name(_AXIS(A)), MSG_FTM_CMPN_MODE, menu_ftm_shaper_##A);
SHAPED_MAP(_CMPM_MENU_ITEM);

View File

@@ -33,8 +33,10 @@
#include "ft_motion.h"
#include "ft_motion/trajectory_trapezoidal.h"
#include "ft_motion/trajectory_poly5.h"
#include "ft_motion/trajectory_poly6.h"
#if ENABLED(FTM_POLYS)
#include "ft_motion/trajectory_poly5.h"
#include "ft_motion/trajectory_poly6.h"
#endif
#if ENABLED(FTM_RESONANCE_TEST)
#include "ft_motion/resonance_generator.h"
#include "../gcode/gcode.h" // for home_all_axes
@@ -71,8 +73,10 @@ float FTMotion::tau = 0.0f; // (s) Time since start of b
// Trajectory generators
TrapezoidalTrajectoryGenerator FTMotion::trapezoidalGenerator;
Poly5TrajectoryGenerator FTMotion::poly5Generator;
Poly6TrajectoryGenerator FTMotion::poly6Generator;
#if ENABLED(FTM_POLYS)
Poly5TrajectoryGenerator FTMotion::poly5Generator;
Poly6TrajectoryGenerator FTMotion::poly6Generator;
#endif
TrajectoryGenerator* FTMotion::currentGenerator = &FTMotion::trapezoidalGenerator;
TrajectoryType FTMotion::trajectoryType = TrajectoryType::FTM_TRAJECTORY_TYPE;
@@ -307,8 +311,10 @@ void FTMotion::setTrajectoryType(const TrajectoryType type) {
switch (type) {
default: cfg.trajectory_type = trajectoryType = TrajectoryType::FTM_TRAJECTORY_TYPE;
case TrajectoryType::TRAPEZOIDAL: currentGenerator = &trapezoidalGenerator; break;
case TrajectoryType::POLY5: currentGenerator = &poly5Generator; break;
case TrajectoryType::POLY6: currentGenerator = &poly6Generator; break;
#if ENABLED(FTM_POLYS)
case TrajectoryType::POLY5: currentGenerator = &poly5Generator; break;
case TrajectoryType::POLY6: currentGenerator = &poly6Generator; break;
#endif
}
}

View File

@@ -26,8 +26,10 @@
#include "stepper.h" // For stepper motion and direction
#include "ft_motion/trajectory_trapezoidal.h"
#include "ft_motion/trajectory_poly5.h"
#include "ft_motion/trajectory_poly6.h"
#if ENABLED(FTM_POLYS)
#include "ft_motion/trajectory_poly5.h"
#include "ft_motion/trajectory_poly6.h"
#endif
#if ENABLED(FTM_RESONANCE_TEST)
#include "ft_motion/resonance_generator.h"
#endif
@@ -83,7 +85,9 @@ typedef struct FTConfig {
#endif
TrajectoryType trajectory_type = TrajectoryType::FTM_TRAJECTORY_TYPE; // Trajectory generator type
float poly6_acceleration_overshoot; // Overshoot factor for Poly6 (1.25 to 2.0)
#if ENABLED(FTM_POLYS)
float poly6_acceleration_overshoot; // Overshoot factor for Poly6 (1.25 to 2.0)
#endif
} ft_config_t;
/**
@@ -134,7 +138,9 @@ class FTMotion {
#undef _SET_SMOOTH
#endif
cfg.poly6_acceleration_overshoot = FTM_POLY6_ACCELERATION_OVERSHOOT;
#if ENABLED(FTM_POLYS)
cfg.poly6_acceleration_overshoot = FTM_POLY6_ACCELERATION_OVERSHOOT;
#endif
setTrajectoryType(TrajectoryType::FTM_TRAJECTORY_TYPE);
@@ -219,8 +225,10 @@ class FTMotion {
// Trajectory generators
static TrapezoidalTrajectoryGenerator trapezoidalGenerator;
static Poly5TrajectoryGenerator poly5Generator;
static Poly6TrajectoryGenerator poly6Generator;
#if ENABLED(FTM_POLYS)
static Poly5TrajectoryGenerator poly5Generator;
static Poly6TrajectoryGenerator poly6Generator;
#endif
static TrajectoryGenerator* currentGenerator;
static TrajectoryType trajectoryType;

View File

@@ -22,7 +22,7 @@
#include "../../inc/MarlinConfig.h"
#if ENABLED(FT_MOTION)
#if ENABLED(FTM_POLYS)
#include "trajectory_poly6.h"
#include "../ft_motion.h"
@@ -140,4 +140,4 @@ void Poly6TrajectoryGenerator::reset() {
acc_c6 = dec_c6 = 0.0f;
}
#endif // FT_MOTION
#endif // FTM_POLYS

View File

@@ -311,9 +311,10 @@ HAS_DUPLICATION_MODE = build_src_filter=+<src/gcode/control/M6
SPI_FLASH_BACKUP = build_src_filter=+<src/gcode/control/M993_M994.cpp>
PLATFORM_M997_SUPPORT = build_src_filter=+<src/gcode/control/M997.cpp>
HAS_TOOLCHANGE = build_src_filter=+<src/gcode/control/T.cpp>
FT_MOTION = build_src_filter=+<src/module/ft_motion.cpp> +<src/module/ft_motion> -<src/module/ft_motion/smoothing.cpp> +<src/gcode/feature/ft_motion> -<src/gcode/feature/ft_motion/M495_M496.cpp>
FT_MOTION = build_src_filter=+<src/module/ft_motion.cpp> +<src/module/ft_motion> -<src/module/ft_motion/smoothing.cpp> +<src/gcode/feature/ft_motion> -<src/gcode/feature/ft_motion/M495_M496.cpp> -<src/module/ft_motion/trajectory_poly6.cpp>
FTM_SMOOTHING = build_src_filter=+<src/module/ft_motion/smoothing.cpp>
FTM_RESONANCE_TEST = build_src_filter=+<src/gcode/feature/ft_motion/M495_M496.cpp>
FTM_POLYS = build_src_filter=+<src/module/ft_motion/trajectory_poly6.cpp>
HAS_LIN_ADVANCE_K = build_src_filter=+<src/gcode/feature/advance>
PHOTO_GCODE = build_src_filter=+<src/gcode/feature/camera>
CONTROLLER_FAN_EDITABLE = build_src_filter=+<src/gcode/feature/controllerfan>