mirror of
https://github.com/MarlinFirmware/Marlin.git
synced 2025-12-28 10:20:36 -07:00
🧑💻 FT Motion accessors, G-code style
This commit is contained in:
parent
291a90ace4
commit
3ee18bc667
6 changed files with 79 additions and 65 deletions
|
|
@ -129,15 +129,14 @@
|
|||
#if ENABLED(Z_SAFE_HOMING)
|
||||
|
||||
inline void home_z_safely() {
|
||||
|
||||
// Potentially disable Fixed-Time Motion for homing
|
||||
TERN_(FT_MOTION, FTM_DISABLE_IN_SCOPE());
|
||||
|
||||
DEBUG_SECTION(log_G28, "home_z_safely", DEBUGGING(LEVELING));
|
||||
|
||||
// Disallow Z homing if X or Y homing is needed
|
||||
if (homing_needed_error(_BV(X_AXIS) | _BV(Y_AXIS))) return;
|
||||
|
||||
// Potentially disable Fixed-Time Motion for homing
|
||||
TERN_(FT_MOTION, FTM_DISABLE_IN_SCOPE());
|
||||
|
||||
sync_plan_position();
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -208,12 +208,14 @@ void GcodeSuite::M493() {
|
|||
if (!parser.seen_any())
|
||||
flag.report = true;
|
||||
|
||||
ft_config_t &c = ftMotion.cfg;
|
||||
|
||||
// Parse 'S' mode parameter.
|
||||
if (parser.seen('S')) {
|
||||
const bool active = parser.value_bool();
|
||||
if (active != ftMotion.cfg.active) {
|
||||
if (active != c.active) {
|
||||
stepper.ftMotion_syncPosition();
|
||||
ftMotion.cfg.active = active;
|
||||
c.active = active;
|
||||
flag.report = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -228,8 +230,8 @@ void GcodeSuite::M493() {
|
|||
return;
|
||||
}
|
||||
auto set_shaper = [&](const AxisEnum axis, ftMotionShaper_t newsh) {
|
||||
if (newsh != ftMotion.cfg.shaper[axis]) {
|
||||
ftMotion.cfg.shaper[axis] = newsh;
|
||||
if (newsh != c.shaper[axis]) {
|
||||
c.shaper[axis] = newsh;
|
||||
flag.update = flag.report = true;
|
||||
}
|
||||
};
|
||||
|
|
@ -243,8 +245,8 @@ void GcodeSuite::M493() {
|
|||
// Parse 'H' Axis Synchronization parameter.
|
||||
if (parser.seenval('H')) {
|
||||
const bool enabled = parser.value_bool();
|
||||
if (enabled != ftMotion.cfg.axis_sync_enabled) {
|
||||
ftMotion.cfg.axis_sync_enabled = enabled;
|
||||
if (enabled != c.axis_sync_enabled) {
|
||||
c.axis_sync_enabled = enabled;
|
||||
flag.report = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -263,7 +265,7 @@ void GcodeSuite::M493() {
|
|||
case dynFreqMode_MASS_BASED:
|
||||
#endif
|
||||
case dynFreqMode_DISABLED:
|
||||
ftMotion.cfg.dynFreqMode = val;
|
||||
c.dynFreqMode = val;
|
||||
flag.report = true;
|
||||
break;
|
||||
default:
|
||||
|
|
@ -271,22 +273,18 @@ void GcodeSuite::M493() {
|
|||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
SERIAL_ECHOLNPGM("?Wrong shaper for (D)ynamic Frequency Mode ", ftMotion.cfg.dynFreqMode, ".");
|
||||
}
|
||||
else
|
||||
SERIAL_ECHOLNPGM("?Shaper required for (D)ynamic Frequency Mode ", c.dynFreqMode, ".");
|
||||
}
|
||||
|
||||
const bool modeUsesDynFreq = (
|
||||
TERN0(HAS_DYNAMIC_FREQ_MM, ftMotion.cfg.dynFreqMode == dynFreqMode_Z_BASED)
|
||||
|| TERN0(HAS_DYNAMIC_FREQ_G, ftMotion.cfg.dynFreqMode == dynFreqMode_MASS_BASED)
|
||||
);
|
||||
const bool modeUsesDynFreq = c.modeUsesDynFreq();
|
||||
|
||||
#endif // HAS_DYNAMIC_FREQ
|
||||
|
||||
// Frequency parameter
|
||||
const bool seenA = parser.seenval('A');
|
||||
const float baseFreqVal = seenA ? parser.value_float() : 0.0f;
|
||||
const bool goodBaseFreq = seenA && WITHIN(baseFreqVal, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2);
|
||||
const bool goodBaseFreq = seenA && c.goodBaseFreq(baseFreqVal);
|
||||
if (seenA && !goodBaseFreq)
|
||||
SERIAL_ECHOLN(F("?Invalid "), F("(A) Base Frequency value. ("), int(FTM_MIN_SHAPE_FREQ), C('-'), int((FTM_FS) / 2), C(')'));
|
||||
|
||||
|
|
@ -301,14 +299,14 @@ void GcodeSuite::M493() {
|
|||
// Zeta parameter
|
||||
const bool seenI = parser.seenval('I');
|
||||
const float zetaVal = seenI ? parser.value_float() : 0.0f;
|
||||
const bool goodZeta = seenI && WITHIN(zetaVal, 0.01f, 1.0f);
|
||||
const bool goodZeta = seenI && c.goodZeta(zetaVal);
|
||||
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 && WITHIN(vtolVal, 0.00f, 1.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
|
||||
|
||||
|
|
@ -323,18 +321,18 @@ void GcodeSuite::M493() {
|
|||
if (AXIS_IS_SHAPING(X)) {
|
||||
// TODO: Frequency minimum is dependent on the shaper used; the above check isn't always correct.
|
||||
if (goodBaseFreq) {
|
||||
ftMotion.cfg.baseFreq.x = baseFreqVal;
|
||||
c.baseFreq.x = baseFreqVal;
|
||||
flag.update = flag.report = true;
|
||||
}
|
||||
}
|
||||
else // Mode doesn't use frequency.
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " [A] frequency.");
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " (A) frequency.");
|
||||
}
|
||||
|
||||
#if HAS_DYNAMIC_FREQ
|
||||
// Parse X frequency scaling parameter
|
||||
if (seenF && modeUsesDynFreq) {
|
||||
ftMotion.cfg.dynFreqK.x = baseDynFreqVal;
|
||||
c.dynFreqK.x = baseDynFreqVal;
|
||||
flag.report = true;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -343,24 +341,24 @@ void GcodeSuite::M493() {
|
|||
if (seenI) {
|
||||
if (AXIS_IS_SHAPING(X)) {
|
||||
if (goodZeta) {
|
||||
ftMotion.cfg.zeta.x = zetaVal;
|
||||
c.zeta.x = zetaVal;
|
||||
flag.update = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " zeta parameter.");
|
||||
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) {
|
||||
ftMotion.cfg.vtol.x = vtolVal;
|
||||
c.vtol.x = vtolVal;
|
||||
flag.update = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " vtol parameter.");
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_A_NAME), " (Q) vtol parameter.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -374,18 +372,18 @@ void GcodeSuite::M493() {
|
|||
if (seenA) {
|
||||
if (AXIS_IS_SHAPING(Y)) {
|
||||
if (goodBaseFreq) {
|
||||
ftMotion.cfg.baseFreq.y = baseFreqVal;
|
||||
c.baseFreq.y = baseFreqVal;
|
||||
flag.update = flag.report = true;
|
||||
}
|
||||
}
|
||||
else // Mode doesn't use frequency.
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " [A] frequency.");
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " (A) frequency.");
|
||||
}
|
||||
|
||||
#if HAS_DYNAMIC_FREQ
|
||||
// Parse Y frequency scaling parameter
|
||||
if (seenF && modeUsesDynFreq) {
|
||||
ftMotion.cfg.dynFreqK.y = baseDynFreqVal;
|
||||
c.dynFreqK.y = baseDynFreqVal;
|
||||
flag.report = true;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -394,24 +392,24 @@ void GcodeSuite::M493() {
|
|||
if (seenI) {
|
||||
if (AXIS_IS_SHAPING(Y)) {
|
||||
if (goodZeta) {
|
||||
ftMotion.cfg.zeta.y = zetaVal;
|
||||
c.zeta.y = zetaVal;
|
||||
flag.update = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " zeta parameter.");
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " (I) zeta parameter.");
|
||||
}
|
||||
|
||||
// Parse Y vtol parameter
|
||||
if (seenQ) {
|
||||
if (AXIS_IS_EISHAPING(Y)) {
|
||||
if (goodVtol) {
|
||||
ftMotion.cfg.vtol.y = vtolVal;
|
||||
c.vtol.y = vtolVal;
|
||||
flag.update = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " vtol parameter.");
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_B_NAME), " (Q) vtol parameter.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -425,18 +423,18 @@ void GcodeSuite::M493() {
|
|||
if (seenA) {
|
||||
if (AXIS_IS_SHAPING(Z)) {
|
||||
if (goodBaseFreq) {
|
||||
ftMotion.cfg.baseFreq.z = baseFreqVal;
|
||||
c.baseFreq.z = baseFreqVal;
|
||||
flag.update = flag.report = true;
|
||||
}
|
||||
}
|
||||
else // Mode doesn't use frequency.
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " [A] frequency.");
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " (A) frequency.");
|
||||
}
|
||||
|
||||
#if HAS_DYNAMIC_FREQ
|
||||
// Parse Z frequency scaling parameter
|
||||
if (seenF && modeUsesDynFreq) {
|
||||
ftMotion.cfg.dynFreqK.z = baseDynFreqVal;
|
||||
c.dynFreqK.z = baseDynFreqVal;
|
||||
flag.report = true;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -445,24 +443,24 @@ void GcodeSuite::M493() {
|
|||
if (seenI) {
|
||||
if (AXIS_IS_SHAPING(Z)) {
|
||||
if (goodZeta) {
|
||||
ftMotion.cfg.zeta.z = zetaVal;
|
||||
c.zeta.z = zetaVal;
|
||||
flag.update = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " zeta parameter.");
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " (I) zeta parameter.");
|
||||
}
|
||||
|
||||
// Parse Z vtol parameter
|
||||
if (seenQ) {
|
||||
if (AXIS_IS_EISHAPING(Z)) {
|
||||
if (goodVtol) {
|
||||
ftMotion.cfg.vtol.z = vtolVal;
|
||||
c.vtol.z = vtolVal;
|
||||
flag.update = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " vtol parameter.");
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C(STEPPER_C_NAME), " (Q) vtol parameter.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -476,18 +474,18 @@ void GcodeSuite::M493() {
|
|||
if (seenA) {
|
||||
if (AXIS_IS_SHAPING(E)) {
|
||||
if (goodBaseFreq) {
|
||||
ftMotion.cfg.baseFreq.e = baseFreqVal;
|
||||
c.baseFreq.e = baseFreqVal;
|
||||
flag.update = flag.report = true;
|
||||
}
|
||||
}
|
||||
else // Mode doesn't use frequency.
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " [A] frequency.");
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " (A) frequency.");
|
||||
}
|
||||
|
||||
#if HAS_DYNAMIC_FREQ
|
||||
// Parse E frequency scaling parameter
|
||||
if (seenF && modeUsesDynFreq) {
|
||||
ftMotion.cfg.dynFreqK.e = baseDynFreqVal;
|
||||
c.dynFreqK.e = baseDynFreqVal;
|
||||
flag.report = true;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -496,24 +494,24 @@ void GcodeSuite::M493() {
|
|||
if (seenI) {
|
||||
if (AXIS_IS_SHAPING(E)) {
|
||||
if (goodZeta) {
|
||||
ftMotion.cfg.zeta.e = zetaVal;
|
||||
c.zeta.e = zetaVal;
|
||||
flag.update = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " zeta parameter.");
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " (I) zeta parameter.");
|
||||
}
|
||||
|
||||
// Parse E vtol parameter
|
||||
if (seenQ) {
|
||||
if (AXIS_IS_EISHAPING(E)) {
|
||||
if (goodVtol) {
|
||||
ftMotion.cfg.vtol.e = vtolVal;
|
||||
c.vtol.e = vtolVal;
|
||||
flag.update = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " vtol parameter.");
|
||||
SERIAL_ECHOLNPGM("?Wrong mode for ", C('E'), " (Q) vtol parameter.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,19 +55,18 @@ void GcodeSuite::M494_report(const bool forReplay/*=true*/) {
|
|||
SERIAL_ECHOPGM(" M494 T", (uint8_t)ftMotion.getTrajectoryType());
|
||||
|
||||
#if ENABLED(FTM_SMOOTHING)
|
||||
SERIAL_ECHOPGM(
|
||||
CARTES_PAIRED_LIST(
|
||||
" X", c.smoothingTime.X, " Y", c.smoothingTime.Y,
|
||||
" Z", c.smoothingTime.Z, " E", c.smoothingTime.E
|
||||
)
|
||||
);
|
||||
#endif // FTM_SMOOTHING
|
||||
SERIAL_ECHOPGM(CARTES_PAIRED_LIST(
|
||||
" X", c.smoothingTime.X,
|
||||
" Y", c.smoothingTime.Y,
|
||||
" Z", c.smoothingTime.Z,
|
||||
" E", c.smoothingTime.E
|
||||
));
|
||||
#endif
|
||||
|
||||
#if ENABLED(FTM_POLYS)
|
||||
|
||||
if (ftMotion.getTrajectoryType() == TrajectoryType::POLY6)
|
||||
SERIAL_ECHOPGM(" O", c.poly6_acceleration_overshoot);
|
||||
#endif // FTM_POLYS
|
||||
#endif
|
||||
|
||||
SERIAL_EOL();
|
||||
}
|
||||
|
|
@ -97,8 +96,9 @@ void GcodeSuite::M494() {
|
|||
report = true;
|
||||
}
|
||||
else
|
||||
SERIAL_ECHOLN(F("?Invalid "), F("trajectory type [T] value. Use 0=TRAPEZOIDAL, 1=POLY5, 2=POLY6"));
|
||||
SERIAL_ECHOLN(F("?Invalid "), F("(T)rajectory type value. Use 0=TRAPEZOIDAL, 1=POLY5, 2=POLY6"));
|
||||
}
|
||||
|
||||
// Parse overshoot parameter.
|
||||
if (parser.seenval('O')) {
|
||||
const float val = parser.value_float();
|
||||
|
|
@ -107,7 +107,7 @@ void GcodeSuite::M494() {
|
|||
report = true;
|
||||
}
|
||||
else
|
||||
SERIAL_ECHOLN(F("?Invalid "), F("overshoot [O] value. Range 1.25-1.875"));
|
||||
SERIAL_ECHOLN(F("?Invalid "), F("(O)vershoot value. Range 1.25-1.875"));
|
||||
}
|
||||
|
||||
#endif // FTM_POLYS
|
||||
|
|
@ -122,7 +122,7 @@ void GcodeSuite::M494() {
|
|||
report = true; \
|
||||
} \
|
||||
else \
|
||||
SERIAL_ECHOLNPGM("?Invalid ", C(N), " smoothing time [", C(CHARIFY(A)), "] value."); \
|
||||
SERIAL_ECHOLNPGM("?Invalid ", C(N), " smoothing time (", C(CHARIFY(A)), ") value."); \
|
||||
}
|
||||
|
||||
CARTES_GANG(
|
||||
|
|
|
|||
|
|
@ -542,6 +542,7 @@ void menu_move() {
|
|||
} // menu_ft_motion
|
||||
|
||||
void menu_tune_ft_motion() {
|
||||
|
||||
// Define stuff ahead of the menu loop
|
||||
ft_config_t &c = ftMotion.cfg;
|
||||
|
||||
|
|
@ -551,10 +552,10 @@ void menu_move() {
|
|||
// For U8G paged rendering check and skip extra string copy
|
||||
|
||||
#if HAS_X_AXIS
|
||||
MString<20> shaper_name;
|
||||
#if CACHE_FOR_SPEED
|
||||
int8_t prev_a = -1;
|
||||
#endif
|
||||
MString<20> shaper_name;
|
||||
auto _shaper_name = [&](const AxisEnum a) {
|
||||
if (TERN1(CACHE_FOR_SPEED, a != prev_a)) {
|
||||
TERN_(CACHE_FOR_SPEED, prev_a = a);
|
||||
|
|
@ -565,10 +566,10 @@ void menu_move() {
|
|||
#endif
|
||||
|
||||
#if HAS_DYNAMIC_FREQ
|
||||
MString<20> dmode;
|
||||
#if CACHE_FOR_SPEED
|
||||
bool got_d = false;
|
||||
#endif
|
||||
MString<20> dmode;
|
||||
auto _dmode = [&]{
|
||||
if (TERN1(CACHE_FOR_SPEED, !got_d)) {
|
||||
TERN_(CACHE_FOR_SPEED, got_d = true);
|
||||
|
|
@ -579,10 +580,10 @@ void menu_move() {
|
|||
#endif
|
||||
|
||||
#if ENABLED(FTM_POLYS)
|
||||
MString<20> traj_name;
|
||||
#if CACHE_FOR_SPEED
|
||||
bool got_t = false;
|
||||
#endif
|
||||
MString<20> traj_name;
|
||||
auto _traj_name = [&]{
|
||||
if (TERN1(CACHE_FOR_SPEED, !got_t)) {
|
||||
TERN_(CACHE_FOR_SPEED, got_t = true);
|
||||
|
|
|
|||
|
|
@ -81,7 +81,9 @@ TrapezoidalTrajectoryGenerator FTMotion::trapezoidalGenerator;
|
|||
#endif
|
||||
|
||||
// Resonance Test
|
||||
TERN_(FTM_RESONANCE_TEST,ResonanceGenerator FTMotion::rtg;) // Resonance trajectory generator instance
|
||||
#if ENABLED(FTM_RESONANCE_TEST)
|
||||
ResonanceGenerator FTMotion::rtg; // Resonance trajectory generator instance
|
||||
#endif
|
||||
|
||||
#if FTM_HAS_LIN_ADVANCE
|
||||
bool FTMotion::use_advance_lead;
|
||||
|
|
|
|||
|
|
@ -90,6 +90,20 @@ typedef struct FTConfig {
|
|||
#else
|
||||
static constexpr TrajectoryType trajectory_type = TrajectoryType::TRAPEZOIDAL;
|
||||
#endif
|
||||
|
||||
#if HAS_FTM_SHAPING
|
||||
constexpr bool goodZeta(const float z) { return WITHIN(z, 0.01f, 1.0f); }
|
||||
constexpr bool goodVtol(const float v) { return WITHIN(v, 0.00f, 1.0f); }
|
||||
#if HAS_DYNAMIC_FREQ
|
||||
bool modeUsesDynFreq() const {
|
||||
return (TERN0(HAS_DYNAMIC_FREQ_MM, dynFreqMode == dynFreqMode_Z_BASED)
|
||||
|| TERN0(HAS_DYNAMIC_FREQ_G, dynFreqMode == dynFreqMode_MASS_BASED));
|
||||
}
|
||||
#endif
|
||||
#endif // HAS_FTM_SHAPING
|
||||
|
||||
constexpr bool goodBaseFreq(const float f) { return WITHIN(f, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2); }
|
||||
|
||||
} ft_config_t;
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue