From 7ca5ef915aa2a81d6a69e183a71641c0c6c032a7 Mon Sep 17 00:00:00 2001 From: DerAndere <26200979+DerAndere1@users.noreply.github.com> Date: Tue, 14 Oct 2025 22:58:00 +0200 Subject: [PATCH 01/14] FEEDRATE_MODE_SUPPORT. Adds G93 inverse time mode and G94 units per minute mode --- Marlin/Configuration.h | 5 ++ Marlin/src/core/language.h | 1 + Marlin/src/feature/bedlevel/abl/bbl.cpp | 29 ++++++- .../bedlevel/mbl/mesh_bed_leveling.cpp | 17 +++-- Marlin/src/feature/bedlevel/ubl/ubl.h | 2 +- .../src/feature/bedlevel/ubl/ubl_motion.cpp | 76 ++++++++++++++++--- Marlin/src/gcode/bedlevel/G42.cpp | 8 +- Marlin/src/gcode/feature/camera/M240.cpp | 6 +- Marlin/src/gcode/gcode.cpp | 7 +- Marlin/src/gcode/gcode.h | 6 ++ Marlin/src/gcode/motion/G0_G1.cpp | 12 +++ Marlin/src/gcode/motion/G2_G3.cpp | 22 ++++-- Marlin/src/gcode/motion/G5.cpp | 7 ++ Marlin/src/gcode/parser.cpp | 5 ++ Marlin/src/gcode/parser.h | 13 +++- Marlin/src/gcode/units/G93_G94.cpp | 47 ++++++++++++ Marlin/src/module/motion.cpp | 34 ++++++--- Marlin/src/module/planner.cpp | 62 +++++++++++---- ini/features.ini | 1 + 19 files changed, 302 insertions(+), 58 deletions(-) create mode 100644 Marlin/src/gcode/units/G93_G94.cpp diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index b2e29a1c9473..234fc02fd802 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -2519,6 +2519,11 @@ // //#define INCH_MODE_SUPPORT +// +// G93/G94 Feedrate mode support +// +//#define FEEDRATE_MODE_SUPPORT + // // M149 Set temperature units support // diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h index 00181b602fb5..cac7c0642211 100644 --- a/Marlin/src/core/language.h +++ b/Marlin/src/core/language.h @@ -150,6 +150,7 @@ #define STR_ERR_MATERIAL_INDEX "M145 S out of range (0-1)" #define STR_ERR_M421_PARAMETERS "M421 incorrect parameter usage" #define STR_ERR_BAD_PLANE_MODE "G5 requires XY plane mode" +#define STR_ERR_BAD_FEEDRATE_MODE "G5 currently requires units/min feedrate mode" #define STR_ERR_MESH_XY "Mesh point out of range" #define STR_ERR_ARC_ARGS "G2/G3 bad parameters" #define STR_ERR_PROTECTED_PIN "Protected Pin" diff --git a/Marlin/src/feature/bedlevel/abl/bbl.cpp b/Marlin/src/feature/bedlevel/abl/bbl.cpp index 0e8c4a273ef9..3a5ebf58d97a 100644 --- a/Marlin/src/feature/bedlevel/abl/bbl.cpp +++ b/Marlin/src/feature/bedlevel/abl/bbl.cpp @@ -78,7 +78,7 @@ void LevelingBilinear::extrapolate_one_point(const uint8_t x, const uint8_t y, c const float a = 2 * a1 - a2, b = 2 * b1 - b2, c = 2 * c1 - c2; // Take the average instead of the median - z_values[x][y] = (a + b + c) / 3.0; + z_values[x][y] = (a + b + c) / 3.0f; TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, z_values[x][y])); // Median is robust (ignores outliers). @@ -377,7 +377,7 @@ float LevelingBilinear::get_z_correction(const xy_pos_t &raw) { * Prepare a bilinear-leveled linear move on Cartesian, * splitting the move where it crosses grid borders. */ - void LevelingBilinear::line_to_destination(const feedRate_t scaled_fr_mm_s, uint16_t x_splits, uint16_t y_splits) { + void LevelingBilinear::line_to_destination(const feedRate_t scaled_fr, uint16_t x_splits, uint16_t y_splits) { // Get current and destination cells for this line xy_int_t c1 { CELL_INDEX(x, motion.position.x), CELL_INDEX(y, motion.position.y) }, c2 { CELL_INDEX(x, motion.destination.x), CELL_INDEX(y, motion.destination.y) }; @@ -393,6 +393,27 @@ float LevelingBilinear::get_z_correction(const xy_pos_t &raw) { return; } + const xyze_pos_t total = motion.destination - motion.position; + + #if ENABLED(FEEDRATE_MODE_SUPPORT) + // Get the linear distance in XYZ + #if HAS_ROTATIONAL_AXES + bool cartes_move = true; + #endif + float cartesian_mm = get_move_distance(total OPTARG(HAS_ROTATIONAL_AXES, cartes_move)); + + // If the move is very short, check the E move distance + TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = ABS(total.e)); + + const bool old_inverse_time_enabled = parser.inverse_time_enabled; + + const feedrate_t scaled_fr_mm_s = (old_inverse_time_enabled && parser.print_move) ? cartesian_mm * scaled_fr : scaled_fr; + parser.inverse_time_enabled = false; + + #else + const feedrate_t scaled_fr_mm_s = scaled_fr; + #endif + #define LINE_SEGMENT_END(A) (motion.position.A + (motion.destination.A - motion.position.A) * normalized_dist) float normalized_dist; @@ -422,7 +443,8 @@ float LevelingBilinear::get_z_correction(const xy_pos_t &raw) { // Must already have been split on these border(s) // This should be a rare case. motion.position = motion.destination; - motion.goto_current_position(scaled_fr_mm_s); + motion.line_to_current_position(scaled_fr_mm_s); + parser.inverse_time_enabled = old_inverse_time_enabled; return; } @@ -435,6 +457,7 @@ float LevelingBilinear::get_z_correction(const xy_pos_t &raw) { // Restore destination from stack motion.destination = end; line_to_destination(scaled_fr_mm_s, x_splits, y_splits); + parser.inverse_time_enabled = old_inverse_time_enabled; } #endif // IS_CARTESIAN && !SEGMENT_LEVELED_MOVES diff --git a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp index 93e50b649857..858b4fddac30 100644 --- a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp +++ b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp @@ -71,15 +71,16 @@ void mesh_bed_leveling::line_to_destination(const feedRate_t scaled_fr_mm_s, uint8_t x_splits, uint8_t y_splits) { // Get current and destination cells for this line xy_uint8_t scel = cell_indexes(motion.position), ecel = cell_indexes(motion.destination); - NOMORE(scel.x, GRID_MAX_CELLS_X - 1); - NOMORE(scel.y, GRID_MAX_CELLS_Y - 1); - NOMORE(ecel.x, GRID_MAX_CELLS_X - 1); - NOMORE(ecel.y, GRID_MAX_CELLS_Y - 1); + + segments = ecel - scel; + NOLESS(segments, 1); + + segment_fr = (parser.inverse_time_enabled && parser.print_move) ? scaled_fr_mm_s * segments : scaled_fr_mm_s; // Start and end in the same cell? No split needed. if (scel == ecel) { motion.position = motion.destination; - motion.goto_current_position(scaled_fr_mm_s); + motion.line_to_current_position(segment_fr); return; } @@ -112,7 +113,7 @@ // Must already have been split on these border(s) // This should be a rare case. motion.position = motion.destination; - motion.goto_current_position(scaled_fr_mm_s); + motion.line_to_current_position(segment_fr); return; } @@ -120,11 +121,11 @@ motion.destination.e = MBL_SEGMENT_END(e); // Do the split and look for more borders - line_to_destination(scaled_fr_mm_s, x_splits, y_splits); + line_to_destination(segment_fr, x_splits, y_splits); // Restore destination from stack motion.destination = dest; - line_to_destination(scaled_fr_mm_s, x_splits, y_splits); + line_to_destination(segment_fr, x_splits, y_splits); } #endif // IS_CARTESIAN && !SEGMENT_LEVELED_MOVES diff --git a/Marlin/src/feature/bedlevel/ubl/ubl.h b/Marlin/src/feature/bedlevel/ubl/ubl.h index da8bd887c370..5170f29f64f0 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl.h +++ b/Marlin/src/feature/bedlevel/ubl/ubl.h @@ -315,7 +315,7 @@ class unified_bed_leveling { #if UBL_SEGMENTED static bool line_to_destination_segmented(const feedRate_t scaled_fr_mm_s); #else - static void line_to_destination_cartesian(const feedRate_t scaled_fr_mm_s, const uint8_t e); + static void line_to_destination_cartesian(const feedRate_t scaled_fr, const uint8_t e); #endif static bool mesh_is_valid() { diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp index 40c308e39a7d..c7f54378b465 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp @@ -46,7 +46,7 @@ // corners of cells. To fix the issue, simply check if the start/end of the line // is very close to a cell boundary in advance and don't split the line there. - void unified_bed_leveling::line_to_destination_cartesian(const feedRate_t scaled_fr_mm_s, const uint8_t extruder) { + void unified_bed_leveling::line_to_destination_cartesian(const feedRate_t scaled_fr, const uint8_t extruder) { /** * Much of the nozzle movement will be within the same cell. So we will do as little computation * as possible to determine if this is the case. If this move is within the same cell, we will @@ -60,6 +60,27 @@ const xyze_pos_t &start = motion.position, &end = motion.destination; #endif + const xyze_pos_t total = end - start; + + #if ENABLED(FEEDRATE_MODE_SUPPORT) + // Get the linear distance in XYZ + #if HAS_ROTATIONAL_AXES + bool cartes_move = true; + #endif + float cartesian_mm = get_move_distance(total OPTARG(HAS_ROTATIONAL_AXES, cartes_move)); + + // If the move is very short, check the E move distance + TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = ABS(total.e)); + + const bool old_inverse_time_enabled = parser.inverse_time_enabled; + + const feedRate_t scaled_fr_mm_s = (old_inverse_time_enabled && parser.print_move) ? cartesian_mm * scaled_fr : scaled_fr; + parser.inverse_time_enabled = false; + + #else + const feedRate_t scaled_fr_mm_s = scaled_fr; + #endif + const xy_uint8_t istart = cell_indexes(start), iend = cell_indexes(end); // A move within the same cell needs no splitting @@ -79,6 +100,7 @@ end.z += UBL_Z_RAISE_WHEN_OFF_MESH; planner.buffer_segment(end, scaled_fr_mm_s, extruder); motion.position = motion.destination; + TERN_(FEEDRATE_MODE_SUPPORT, parser.inverse_time_enabled = old_inverse_time_enabled); return; } #endif @@ -97,6 +119,7 @@ if (!isnan(z0)) end.z += z0; planner.buffer_segment(end, scaled_fr_mm_s, extruder); motion.position = motion.destination; + TERN_(FEEDRATE_MODE_SUPPORT, parser.inverse_time_enabled = old_inverse_time_enabled); return; } @@ -105,7 +128,7 @@ * case - crossing only one X or Y line - after details are worked out to reduce computation. */ - const xy_float_t dist = end - start; + const xy_float_t dist = xy_float_t(total); const xy_bool_t neg { dist.x < 0, dist.y < 0 }; const xy_uint8_t ineg { uint8_t(neg.x), uint8_t(neg.y) }; const xy_float_t sign { neg.x ? -1.0f : 1.0f, neg.y ? -1.0f : 1.0f }; @@ -194,6 +217,7 @@ goto FINAL_MOVE; motion.position = motion.destination; + TERN_(FEEDRATE_MODE_SUPPORT, parser.inverse_time_enabled = old_inverse_time_enabled); return; } @@ -357,24 +381,58 @@ const xyze_pos_t total = motion.destination - motion.position; - const float cart_xy_mm_2 = HYPOT2(total.x, total.y), - cart_xy_mm = SQRT(cart_xy_mm_2); // Total XY distance + // If the move is only in Z/E don't split up the move + if (!total.x && !total.y) { + planner.buffer_line(destination, scaled_fr_mm_s); + return false; // caller will update current_position + } + + #if HAS_ROTATIONAL_AXES + bool cartes_move = true; + #endif + float cartesian_mm = get_move_distance(total OPTARG(HAS_ROTATIONAL_AXES, cartes_move)); + + // If the move is very short, check the E move distance + TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = ABS(total.e)); + + // No E move either? Game over. + if (UNEAR_ZERO(cartesian_mm)) return true; #if IS_KINEMATIC - const float seconds = cart_xy_mm / scaled_fr_mm_s; // Duration of XY move at requested rate + // Minimum number of seconds to move the given distance + #if ENABLED(FEEDRATE_MODE_SUPPORT) + const float seconds = (parser.print_move && parser.inverse_time_enabled) ? RECIPROCAL(scaled_fr_mm_s) : cartesian_mm / ( + #if ALL(HAS_ROTATIONAL_AXES, INCH_MODE_SUPPORT) + cartes_move ? scaled_fr_mm_s : LINEAR_UNIT(scaled_fr_mm_s) + #else + scaled_fr_mm_s + #endif + ); + #else + const float seconds = cartesian_mm / ( + #if ALL(HAS_ROTATIONAL_AXES, INCH_MODE_SUPPORT) + cartes_move ? scaled_fr_mm_s : LINEAR_UNIT(scaled_fr_mm_s) + #else + scaled_fr_mm_s + #endif + ); + #endif uint16_t segments = LROUND(segments_per_second * seconds), // Preferred number of segments for distance @ feedrate - seglimit = LROUND(cart_xy_mm * RECIPROCAL(SEGMENT_MIN_LENGTH)); // Number of segments at minimum segment length + seglimit = LROUND(cartesian_mm * RECIPROCAL(SEGMENT_MIN_LENGTH)); // Number of segments at minimum segment length + NOMORE(segments, seglimit); // Limit to minimum segment length (fewer segments) #else - uint16_t segments = LROUND(cart_xy_mm * RECIPROCAL(SEGMENT_MIN_LENGTH)); // Cartesian fixed segment length + uint16_t segments = LROUND(cartesian_mm * RECIPROCAL(SEGMENT_MIN_LENGTH)); // Cartesian fixed segment length #endif NOLESS(segments, 1U); // Must have at least one segment const float inv_segments = 1.0f / segments; // Reciprocal to save calculation // Add hints to help optimize the move - PlannerHints hints(SQRT(cart_xy_mm_2 + sq(total.z)) * inv_segments); // Length of each segment - #if ENABLED(FEEDRATE_SCALING) + PlannerHints hints(cartesian_mm * inv_segments); // Length of each segment + #if IS_KINEMATIC && ENABLED(FEEDRATE_MODE_SUPPORT) + hints.inv_duration = segments / seconds; + #elif ENABLED(FEEDRATE_SCALING) hints.inv_duration = scaled_fr_mm_s / hints.millimeters; #endif diff --git a/Marlin/src/gcode/bedlevel/G42.cpp b/Marlin/src/gcode/bedlevel/G42.cpp index 8383dd1a8de5..0cc8db5e06cb 100644 --- a/Marlin/src/gcode/bedlevel/G42.cpp +++ b/Marlin/src/gcode/bedlevel/G42.cpp @@ -54,6 +54,8 @@ void GcodeSuite::G42() { return; } + TERN_(FEEDRATE_MODE_SUPPORT, parser.print_move = true); + // Move to motion.position, as modified by I, J, P parameters motion.destination = motion.position; @@ -67,8 +69,8 @@ void GcodeSuite::G42() { } #endif - const feedRate_t fval = parser.linearval('F'), - fr_mm_s = MMM_TO_MMS(fval > 0 ? fval : 0.0f); + const feedRate_t fval = parser.feedrateval('F'), + fr_mm_s = MMM_TO_MMS(fval); // SCARA kinematic has "safe" XY raw moves #if IS_SCARA @@ -76,6 +78,8 @@ void GcodeSuite::G42() { #else motion.prepare_internal_move_to_destination(fr_mm_s); #endif + + TERN_(FEEDRATE_MODE_SUPPORT, parser.print_move = false); } #endif // HAS_MESH diff --git a/Marlin/src/gcode/feature/camera/M240.cpp b/Marlin/src/gcode/feature/camera/M240.cpp index 7ce0a1934cac..19c8f7769ce8 100644 --- a/Marlin/src/gcode/feature/camera/M240.cpp +++ b/Marlin/src/gcode/feature/camera/M240.cpp @@ -134,12 +134,12 @@ void GcodeSuite::M240() { #ifdef PHOTO_RETRACT_MM const float rval = parser.linearval('R', _PHOTO_RETRACT_MM); - const feedRate_t sval = parser.feedrateval('S', TERN(ADVANCED_PAUSE_FEATURE, PAUSE_PARK_RETRACT_FEEDRATE, TERN(FWRETRACT, RETRACT_FEEDRATE, 45))); + const feedRate_t sval = MMM_TO_MMS(parser.feedrateval('S', TERN(ADVANCED_PAUSE_FEATURE, PAUSE_PARK_RETRACT_FEEDRATE, TERN(FWRETRACT, RETRACT_FEEDRATE, 45)))); e_move_m240(-rval, sval); #endif - feedRate_t fr_mm_s = parser.feedrateval('F'); - if (fr_mm_s) NOLESS(fr_mm_s, 10.0f); + feedRate_t fr_mm_s = MMM_TO_MMS(parser.feedrateval('F')); + if (fr_mm_s) NOLESS(fr_mm_s, TERN(FEEDRATE_MODE_SUPPORT, 0.01f, 10.0f)); constexpr xyz_pos_t photo_position = PHOTO_POSITION; xyz_pos_t raw = { diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index e84b367e7af4..e433f11d3145 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -206,7 +206,7 @@ void GcodeSuite::get_destination_from_command() { #endif if (parser.floatval('F') > 0) { - const float fr_mm_min = parser.value_linear_units(); + const float fr_mm_min = parser.value_feedrate(); motion.feedrate_mm_s = MMM_TO_MMS(fr_mm_min); // Update the cutter feed rate for use by M4 I set inline moves. TERN_(LASER_FEATURE, cutter.feedrate_mm_m = fr_mm_min); @@ -468,6 +468,11 @@ void GcodeSuite::process_parsed_command(bool no_ok/*=false*/) { case 92: G92(); break; // G92: Set current axis position(s) + #if ENABLED(FEEDRATE_MODE_SUPPORT) + case 93: G93(); break; // G93: Set feedrate mode to inverse time + case 94: G94(); break; // G94: Set feedrate mode to length units per minute + #endif + #if ENABLED(CALIBRATION_GCODE) case 425: G425(); break; // G425: Perform calibration with calibration cube #endif diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index d80305fb7556..638afe513167 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -649,6 +649,12 @@ class GcodeSuite { static void G92(); + + #if ENABLED(FEEDRATE_MODE_SUPPORT) + static void G93(); + static void G94(); + #endif + #if ENABLED(CALIBRATION_GCODE) static void G425(); #endif diff --git a/Marlin/src/gcode/motion/G0_G1.cpp b/Marlin/src/gcode/motion/G0_G1.cpp index 1106ce0acc13..370c278a3370 100644 --- a/Marlin/src/gcode/motion/G0_G1.cpp +++ b/Marlin/src/gcode/motion/G0_G1.cpp @@ -54,11 +54,21 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) { #ifdef G0_FEEDRATE feedRate_t old_feedrate; #if ENABLED(VARIABLE_G0_FEEDRATE) + TERN_(FEEDRATE_MODE_SUPPORT, parser.print_move = true); if (fast_move) { old_feedrate = motion.feedrate_mm_s; // Back up the (old) motion mode feedrate motion.feedrate_mm_s = fast_move_feedrate; // Get G0 feedrate from last usage } + #elif defined(FEEDRATE_MODE_SUPPORT) + if (fast_move) { + parser.print_move = false; + } + else { + parser.print_move = true; + } #endif + #elif ENABLED(FEEDRATE_MODE_SUPPORT) + parser.print_move = true; #endif get_destination_from_command(); // Get X Y [Z[I[J[K]]]] [E] F (and set cutter power) @@ -104,6 +114,8 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) { if (fast_move) motion.feedrate_mm_s = old_feedrate; #endif + TERN_(FEEDRATE_MODE_SUPPORT, parser.print_move = false); + #if ENABLED(NANODLP_Z_SYNC) #if ENABLED(NANODLP_ALL_AXIS) #define _MOVE_SYNC parser.seenval('X') || parser.seenval('Y') || parser.seenval('Z') // For any move wait and output sync message diff --git a/Marlin/src/gcode/motion/G2_G3.cpp b/Marlin/src/gcode/motion/G2_G3.cpp index 384a90fe6d09..f8f44d2f1a95 100644 --- a/Marlin/src/gcode/motion/G2_G3.cpp +++ b/Marlin/src/gcode/motion/G2_G3.cpp @@ -212,7 +212,13 @@ void plan_arc( } // Feedrate for the move, scaled by the feedrate multiplier - const feedRate_t scaled_fr_mm_s = motion.mms_scaled(); + #if ENABLED(FEEDRATE_MODE_SUPPORT) + const feedRate_t scaled_fr = motion.mms_scaled(); + const feedRate_t scaled_fr_mm_s = parser.inverse_time_enabled ? scaled_fr * flat_mm : scaled_fr; + #else + const feedRate_t scaled_fr = motion.mms_scaled(); + const feedRate_t scaled_fr_mm_s = scaled_fr; + #endif // Get the ideal segment length for the move based on settings const float ideal_segment_mm = ( @@ -235,8 +241,10 @@ void plan_arc( // Add hints to help optimize the move PlannerHints hints; - #if ENABLED(FEEDRATE_SCALING) - hints.inv_duration = (scaled_fr_mm_s / flat_mm) * segments; + #if IS_KINEMATIC && ENABLED(FEEDRATE_MODE_SUPPORT) + hints.inv_duration = segments * (parser.inverse_time_enabled ? scaled_fr : (scaled_fr_mm_s / flat_mm)); + #elif ENABLED(FEEDRATE_SCALING) + hints.inv_duration = segments * (scaled_fr_mm_s / flat_mm); #endif /** @@ -371,7 +379,7 @@ void plan_arc( const float arc_mm_remaining = flat_mm - segment_mm * i; hints.safe_exit_speed_sqr = _MIN(limiting_speed_sqr, 2 * limiting_accel * arc_mm_remaining); - if (!planner.buffer_line(raw, scaled_fr_mm_s, motion.extruder, hints)) + if (!planner.buffer_line(raw, scaled_fr, motion.extruder, hints)) break; hints.curve_radius = radius; @@ -389,7 +397,7 @@ void plan_arc( hints.curve_radius = 0; hints.safe_exit_speed_sqr = 0.0f; - planner.buffer_line(raw, scaled_fr_mm_s, motion.extruder, hints); + planner.buffer_line(raw, scaled_fr, motion.extruder, hints); motion.position = cart; @@ -427,6 +435,8 @@ void GcodeSuite::G2_G3(const bool clockwise) { TERN_(FULL_REPORT_TO_HOST_FEATURE, motion.set_and_report_grblstate(M_RUNNING)); + TERN_(FEEDRATE_MODE_SUPPORT, parser.print_move = true); + #if ENABLED(SF_ARC_FIX) const bool relative_mode_backup = motion.relative_mode; motion.relative_mode = true; @@ -486,6 +496,8 @@ void GcodeSuite::G2_G3(const bool clockwise) { else SERIAL_ERROR_MSG(STR_ERR_ARC_ARGS); + TERN_(FEEDRATE_MODE_SUPPORT, parser.print_move = false); + TERN_(FULL_REPORT_TO_HOST_FEATURE, motion.set_and_report_grblstate(M_IDLE)); } diff --git a/Marlin/src/gcode/motion/G5.cpp b/Marlin/src/gcode/motion/G5.cpp index 6ffb65b95941..0a39a96f571e 100644 --- a/Marlin/src/gcode/motion/G5.cpp +++ b/Marlin/src/gcode/motion/G5.cpp @@ -53,6 +53,13 @@ void GcodeSuite::G5() { } #endif + #if ENABLED(FEEDRATE_MODE_SUPPORT) + if (parser.inverse_time_enabled) { + SERIAL_ERROR_MSG(STR_ERR_BAD_FEEDRATE_MODE); + return; + } + #endif + get_destination_from_command(); const xy_pos_t offsets[2] = { diff --git a/Marlin/src/gcode/parser.cpp b/Marlin/src/gcode/parser.cpp index b692c818aae6..6c7565491a40 100644 --- a/Marlin/src/gcode/parser.cpp +++ b/Marlin/src/gcode/parser.cpp @@ -37,6 +37,11 @@ bool GCodeParser::volumetric_enabled; float GCodeParser::linear_unit_factor, GCodeParser::volumetric_unit_factor; #endif +#if ENABLED(FEEDRATE_MODE_SUPPORT) + bool GCodeParser::inverse_time_enabled; + bool GCodeParser::print_move; +#endif + #if ENABLED(TEMPERATURE_UNITS_SUPPORT) TempUnit GCodeParser::input_temp_units = TEMPUNIT_C; #endif diff --git a/Marlin/src/gcode/parser.h b/Marlin/src/gcode/parser.h index 71cad6857dce..06d1cc36535b 100644 --- a/Marlin/src/gcode/parser.h +++ b/Marlin/src/gcode/parser.h @@ -76,6 +76,11 @@ class GCodeParser { static float linear_unit_factor, volumetric_unit_factor; #endif + #if ENABLED(FEEDRATE_MODE_SUPPORT) + static bool inverse_time_enabled; + static bool print_move; + #endif + #if ENABLED(TEMPERATURE_UNITS_SUPPORT) static TempUnit input_temp_units; #endif @@ -415,7 +420,13 @@ class GCodeParser { #endif // !TEMPERATURE_UNITS_SUPPORT - static feedRate_t value_feedrate() { return MMM_TO_MMS(value_linear_units()); } + static feedRate_t value_feedrate() { + #if ENABLED(FEEDRATE_MODE_SUPPORT) + return (inverse_time_enabled && print_move) ? value_float() : value_linear_units(); + #else + return value_linear_units(); + #endif + } void unknown_command_warning(); diff --git a/Marlin/src/gcode/units/G93_G94.cpp b/Marlin/src/gcode/units/G93_G94.cpp new file mode 100644 index 000000000000..ee98be274dde --- /dev/null +++ b/Marlin/src/gcode/units/G93_G94.cpp @@ -0,0 +1,47 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file G93_G94.cpp + * @author DerAndere + * @brief G93 (inverse time mode) and G94 (units per minute feedrate mode). + * + * Copyright 2025 DerAndere + */ + +#include "../../inc/MarlinConfig.h" + +#if ENABLED(FEEDRATE_MODE_SUPPORT) + +#include "../gcode.h" + +/** + * G93: Set feedrate mode to inverse time + */ +void GcodeSuite::G93() { parser.inverse_time_enabled = true; } + +/** + * G94: Set feedrate mode to length units per minute + */ +void GcodeSuite::G94() { parser.inverse_time_enabled = false; } + +#endif // FEEDRATE_MODE_SUPPORT diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index b401090d8722..e0b11a6ea7c5 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -167,6 +167,7 @@ xyz_pos_t Motion::cartes; #ifndef DEFAULT_FEEDRATE_MM_M #define DEFAULT_FEEDRATE_MM_M 4000 #endif + feedRate_t Motion::feedrate_mm_s = MMM_TO_MMS(DEFAULT_FEEDRATE_MM_M); int16_t Motion::feedrate_percentage = 100; @@ -1632,13 +1633,23 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE if (UNEAR_ZERO(cartesian_mm)) return true; // Minimum number of seconds to move the given distance - const float seconds = cartesian_mm / ( - #if ALL(HAS_ROTATIONAL_AXES, INCH_MODE_SUPPORT) - cartes_move ? scaled_fr_mm_s : LINEAR_UNIT(scaled_fr_mm_s) - #else - scaled_fr_mm_s - #endif - ); + #if ENABLED(FEEDRATE_MODE_SUPPORT) + const float seconds = (parser.print_move && parser.inverse_time_enabled) ? RECIPROCAL(scaled_fr_mm_s) : cartesian_mm / ( + #if ALL(HAS_ROTATIONAL_AXES, INCH_MODE_SUPPORT) + cartes_move ? scaled_fr_mm_s : LINEAR_UNIT(scaled_fr_mm_s) + #else + scaled_fr_mm_s + #endif + ); + #else + const float seconds = cartesian_mm / ( + #if ALL(HAS_ROTATIONAL_AXES, INCH_MODE_SUPPORT) + cartes_move ? scaled_fr_mm_s : LINEAR_UNIT(scaled_fr_mm_s) + #else + scaled_fr_mm_s + #endif + ); + #endif // The number of segments-per-second times the duration // gives the number of segments @@ -1661,8 +1672,11 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE // Add hints to help optimize the move PlannerHints hints(cartesian_mm * inv_segments); TERN_(HAS_ROTATIONAL_AXES, hints.cartesian_move = cartes_move); - TERN_(FEEDRATE_SCALING, hints.inv_duration = scaled_fr_mm_s / hints.millimeters); - + #if ENABLED(FEEDRATE_MODE_SUPPORT) + hints.inv_duration = (parser.inverse_time_enabled && parser.print_move) ? (scaled_fr_mm_s * segments) : (scaled_fr_mm_s / hints.millimeters); + #elif ENABLED(FEEDRATE_SCALING) + hints.inv_duration = scaled_fr_mm_s / hints.millimeters; + #endif /* SERIAL_ECHOPGM("mm=", cartesian_mm); SERIAL_ECHOPGM(" seconds=", seconds); @@ -1734,7 +1748,7 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE // Add hints to help optimize the move PlannerHints hints(cartesian_mm * inv_segments); TERN_(HAS_ROTATIONAL_AXES, hints.cartesian_move = cartes_move); - TERN_(FEEDRATE_SCALING, hints.inv_duration = scaled_fr_mm_s / hints.millimeters); + TERN_(FEEDRATE_SCALING, hints.inv_duration = scaled_fr_mm_s / hints.millimeters); // TODO (DerAndere): Fix inverse time mode for FEEDRATE_MODE_SUPPORT //SERIAL_ECHOPGM("mm=", cartesian_mm); //SERIAL_ECHOLNPGM(" segments=", segments); diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 8f3815a3fcbc..a844d3962ec5 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -2172,11 +2172,22 @@ bool Planner::_populate_block( } #endif // HAS_EXTRUDERS - if (esteps) - NOLESS(fr_mm_s, settings.min_feedrate_mm_s); - else - NOLESS(fr_mm_s, settings.min_travel_feedrate_mm_s); - + if (esteps) { + if (TERN0(FEEDRATE_MODE_SUPPORT, parser.inverse_time_enabled && parser.print_move)) { + NOLESS(fr_mm_s, RECIPROCAL(settings.min_feedrate_mm_s)); + } + else { + NOLESS(fr_mm_s, settings.min_feedrate_mm_s); + } + } + else { + if (TERN0(FEEDRATE_MODE_SUPPORT, parser.inverse_time_enabled && parser.print_move)) { + NOLESS(fr_mm_s, RECIPROCAL(settings.min_travel_feedrate_mm_s)); + } + else { + NOLESS(fr_mm_s, settings.min_travel_feedrate_mm_s); + } + } const float inverse_millimeters = 1.0f / block->millimeters; // Inverse millimeters to remove multiple divides /** @@ -2184,17 +2195,38 @@ bool Planner::_populate_block( * EXAMPLE: At 120mm/s a 60mm move involving XYZ axes takes 0.5s. So this will give 2.0. * EXAMPLE: At 120°/s a 60° move involving only rotational axes takes 0.5s. So this will give 2.0. */ - float inverse_secs = inverse_millimeters * ( - #if ALL(HAS_ROTATIONAL_AXES, INCH_MODE_SUPPORT) - /** - * Workaround for premature feedrate conversion - * from in/s to mm/s by get_distance_from_command. - */ - cartesian_move ? fr_mm_s : LINEAR_UNIT(fr_mm_s) + + float inverse_secs; + if (TERN0(FEEDRATE_MODE_SUPPORT, parser.inverse_time_enabled && parser.print_move)) { + #if IS_KINEMATIC && ENABLED(FEEDRATE_MODE_SUPPORT) + inverse_secs = hints.inv_duration ? : fr_mm_s; #else - fr_mm_s + inverse_secs = fr_mm_s; #endif - ); + float min_inverse_secs; + if (esteps) + min_inverse_secs = settings.min_feedrate_mm_s * inverse_millimeters; + else + min_inverse_secs = settings.min_travel_feedrate_mm_s * inverse_millimeters; + NOLESS(inverse_secs, min_inverse_secs); + } + else { + #if IS_KINEMATIC && ENABLED(FEEDRATE_MODE_SUPPORT) + inverse_secs = hints.inv_duration ? : inverse_millimeters * ( + #else + inverse_secs = inverse_millimeters * ( + #endif + #if ALL(HAS_ROTATIONAL_AXES, INCH_MODE_SUPPORT) + /** + * Workaround for premature feedrate conversion + * from in/s to mm/s by get_distance_from_command. + */ + cartesian_move ? fr_mm_s : LINEAR_UNIT(fr_mm_s) + #else + fr_mm_s + #endif + ); + } // Get the number of non busy movements in queue (non busy means that they can be altered) const uint8_t moves_queued = nonbusy_movesplanned(); @@ -2202,7 +2234,7 @@ bool Planner::_populate_block( // Slow down when the buffer starts to empty, rather than wait at the corner for a buffer refill #if ANY(SLOWDOWN, HAS_WIRED_LCD) || defined(XY_FREQUENCY_LIMIT) // Segment time in microseconds - int32_t segment_time_us = LROUND(1000000.0f / inverse_secs); + int32_t segment_time_us = LROUND(1000000.0f * RECIPROCAL(inverse_secs)); #endif #if ENABLED(SLOWDOWN) diff --git a/ini/features.ini b/ini/features.ini index 03a9bdbba8d1..fbbeacd7bb2d 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -368,6 +368,7 @@ HAS_TEMP_PROBE = build_src_filter=+ MPCTEMP = build_src_filter=+ INCH_MODE_SUPPORT = build_src_filter=+ +FEEDRATE_MODE_SUPPORT = build_src_filter=+ TEMPERATURE_UNITS_SUPPORT = build_src_filter=+ NEED_HEX_PRINT = build_src_filter=+ NEED_LSF = build_src_filter=+ From d6d63bd54ee79908740d49436c04e468fed646a9 Mon Sep 17 00:00:00 2001 From: DerAndere <26200979+DerAndere1@users.noreply.github.com> Date: Sun, 14 Dec 2025 01:33:09 +0100 Subject: [PATCH 02/14] improve --- Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp | 4 ++-- Marlin/src/gcode/motion/G2_G3.cpp | 2 +- Marlin/src/module/planner.cpp | 4 ++-- Marlin/src/module/planner.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp index c7f54378b465..ab0c03a1214c 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp @@ -430,8 +430,8 @@ // Add hints to help optimize the move PlannerHints hints(cartesian_mm * inv_segments); // Length of each segment - #if IS_KINEMATIC && ENABLED(FEEDRATE_MODE_SUPPORT) - hints.inv_duration = segments / seconds; + #if ENABLED(FEEDRATE_MODE_SUPPORT) + hints.inv_duration = (parser.print_move && parser.inverse_time_enabled) ? (segments * scaled_fr_mm_s) : (scaled_fr_mm_s) / hints.millimeters); #elif ENABLED(FEEDRATE_SCALING) hints.inv_duration = scaled_fr_mm_s / hints.millimeters; #endif diff --git a/Marlin/src/gcode/motion/G2_G3.cpp b/Marlin/src/gcode/motion/G2_G3.cpp index f8f44d2f1a95..88a766b99d23 100644 --- a/Marlin/src/gcode/motion/G2_G3.cpp +++ b/Marlin/src/gcode/motion/G2_G3.cpp @@ -241,7 +241,7 @@ void plan_arc( // Add hints to help optimize the move PlannerHints hints; - #if IS_KINEMATIC && ENABLED(FEEDRATE_MODE_SUPPORT) + #if ENABLED(FEEDRATE_MODE_SUPPORT) hints.inv_duration = segments * (parser.inverse_time_enabled ? scaled_fr : (scaled_fr_mm_s / flat_mm)); #elif ENABLED(FEEDRATE_SCALING) hints.inv_duration = segments * (scaled_fr_mm_s / flat_mm); diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index a844d3962ec5..39f90daafab1 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -2198,7 +2198,7 @@ bool Planner::_populate_block( float inverse_secs; if (TERN0(FEEDRATE_MODE_SUPPORT, parser.inverse_time_enabled && parser.print_move)) { - #if IS_KINEMATIC && ENABLED(FEEDRATE_MODE_SUPPORT) + #if ENABLED(FEEDRATE_MODE_SUPPORT) inverse_secs = hints.inv_duration ? : fr_mm_s; #else inverse_secs = fr_mm_s; @@ -2211,7 +2211,7 @@ bool Planner::_populate_block( NOLESS(inverse_secs, min_inverse_secs); } else { - #if IS_KINEMATIC && ENABLED(FEEDRATE_MODE_SUPPORT) + #if ENABLED(FEEDRATE_MODE_SUPPORT) inverse_secs = hints.inv_duration ? : inverse_millimeters * ( #else inverse_secs = inverse_millimeters * ( diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index a9d4c37afacb..26491bc237d7 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -469,7 +469,7 @@ typedef struct PlannerSettings { struct PlannerHints { float millimeters = 0.0; // Move Length, if known, else 0. - #if ENABLED(FEEDRATE_SCALING) + #if ANY(FEEDRATE_SCALING, FEEDRATE_MODE_SUPPORT) float inv_duration = 0.0; // Reciprocal of the move duration, if known #endif #if ENABLED(HINTS_CURVE_RADIUS) From 4ee476bca6c4a13d27b42b249cd990ecf3185eeb Mon Sep 17 00:00:00 2001 From: DerAndere <26200979+DerAndere1@users.noreply.github.com> Date: Sun, 14 Dec 2025 04:41:47 +0100 Subject: [PATCH 03/14] simplify --- Marlin/src/core/language.h | 1 - Marlin/src/feature/bedlevel/abl/bbl.cpp | 23 +------- .../bedlevel/mbl/mesh_bed_leveling.cpp | 2 +- Marlin/src/feature/bedlevel/ubl/ubl.h | 2 +- .../src/feature/bedlevel/ubl/ubl_motion.cpp | 56 ++----------------- Marlin/src/gcode/bedlevel/G42.cpp | 4 +- Marlin/src/gcode/feature/camera/M240.cpp | 2 +- Marlin/src/gcode/gcode.cpp | 20 ++++++- Marlin/src/gcode/motion/G0_G1.cpp | 21 ++++--- Marlin/src/gcode/motion/G2_G3.cpp | 29 ++++------ Marlin/src/gcode/motion/G5.cpp | 12 ++-- Marlin/src/gcode/parser.cpp | 8 ++- Marlin/src/gcode/parser.h | 12 +++- Marlin/src/gcode/sd/M24_M25.cpp | 4 +- .../src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp | 2 +- .../src/lcd/extui/dgus/mks/DGUSDisplayDef.h | 4 +- Marlin/src/lcd/marlinui.cpp | 13 +---- Marlin/src/module/motion.cpp | 43 ++++---------- Marlin/src/module/motion.h | 3 + Marlin/src/module/planner.cpp | 51 ++++------------- Marlin/src/module/planner.h | 5 -- 21 files changed, 108 insertions(+), 209 deletions(-) diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h index cac7c0642211..00181b602fb5 100644 --- a/Marlin/src/core/language.h +++ b/Marlin/src/core/language.h @@ -150,7 +150,6 @@ #define STR_ERR_MATERIAL_INDEX "M145 S out of range (0-1)" #define STR_ERR_M421_PARAMETERS "M421 incorrect parameter usage" #define STR_ERR_BAD_PLANE_MODE "G5 requires XY plane mode" -#define STR_ERR_BAD_FEEDRATE_MODE "G5 currently requires units/min feedrate mode" #define STR_ERR_MESH_XY "Mesh point out of range" #define STR_ERR_ARC_ARGS "G2/G3 bad parameters" #define STR_ERR_PROTECTED_PIN "Protected Pin" diff --git a/Marlin/src/feature/bedlevel/abl/bbl.cpp b/Marlin/src/feature/bedlevel/abl/bbl.cpp index 3a5ebf58d97a..6b2d1fe4abb4 100644 --- a/Marlin/src/feature/bedlevel/abl/bbl.cpp +++ b/Marlin/src/feature/bedlevel/abl/bbl.cpp @@ -377,7 +377,7 @@ float LevelingBilinear::get_z_correction(const xy_pos_t &raw) { * Prepare a bilinear-leveled linear move on Cartesian, * splitting the move where it crosses grid borders. */ - void LevelingBilinear::line_to_destination(const feedRate_t scaled_fr, uint16_t x_splits, uint16_t y_splits) { + void LevelingBilinear::line_to_destination(const feedRate_t scaled_fr_mm_s, uint16_t x_splits, uint16_t y_splits) { // Get current and destination cells for this line xy_int_t c1 { CELL_INDEX(x, motion.position.x), CELL_INDEX(y, motion.position.y) }, c2 { CELL_INDEX(x, motion.destination.x), CELL_INDEX(y, motion.destination.y) }; @@ -393,27 +393,6 @@ float LevelingBilinear::get_z_correction(const xy_pos_t &raw) { return; } - const xyze_pos_t total = motion.destination - motion.position; - - #if ENABLED(FEEDRATE_MODE_SUPPORT) - // Get the linear distance in XYZ - #if HAS_ROTATIONAL_AXES - bool cartes_move = true; - #endif - float cartesian_mm = get_move_distance(total OPTARG(HAS_ROTATIONAL_AXES, cartes_move)); - - // If the move is very short, check the E move distance - TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = ABS(total.e)); - - const bool old_inverse_time_enabled = parser.inverse_time_enabled; - - const feedrate_t scaled_fr_mm_s = (old_inverse_time_enabled && parser.print_move) ? cartesian_mm * scaled_fr : scaled_fr; - parser.inverse_time_enabled = false; - - #else - const feedrate_t scaled_fr_mm_s = scaled_fr; - #endif - #define LINE_SEGMENT_END(A) (motion.position.A + (motion.destination.A - motion.position.A) * normalized_dist) float normalized_dist; diff --git a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp index 858b4fddac30..0bd181756fe5 100644 --- a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp +++ b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp @@ -75,7 +75,7 @@ segments = ecel - scel; NOLESS(segments, 1); - segment_fr = (parser.inverse_time_enabled && parser.print_move) ? scaled_fr_mm_s * segments : scaled_fr_mm_s; + segment_fr = (parser.inverse_time_enabled && parser.apply_feedrate_mode) ? scaled_fr_mm_s * segments : scaled_fr_mm_s; // Start and end in the same cell? No split needed. if (scel == ecel) { diff --git a/Marlin/src/feature/bedlevel/ubl/ubl.h b/Marlin/src/feature/bedlevel/ubl/ubl.h index 5170f29f64f0..da8bd887c370 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl.h +++ b/Marlin/src/feature/bedlevel/ubl/ubl.h @@ -315,7 +315,7 @@ class unified_bed_leveling { #if UBL_SEGMENTED static bool line_to_destination_segmented(const feedRate_t scaled_fr_mm_s); #else - static void line_to_destination_cartesian(const feedRate_t scaled_fr, const uint8_t e); + static void line_to_destination_cartesian(const feedRate_t scaled_fr_mm_s, const uint8_t e); #endif static bool mesh_is_valid() { diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp index ab0c03a1214c..86dc5ff04168 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp @@ -46,7 +46,7 @@ // corners of cells. To fix the issue, simply check if the start/end of the line // is very close to a cell boundary in advance and don't split the line there. - void unified_bed_leveling::line_to_destination_cartesian(const feedRate_t scaled_fr, const uint8_t extruder) { + void unified_bed_leveling::line_to_destination_cartesian(const feedRate_t scaled_fr_mm_s, const uint8_t extruder) { /** * Much of the nozzle movement will be within the same cell. So we will do as little computation * as possible to determine if this is the case. If this move is within the same cell, we will @@ -60,27 +60,6 @@ const xyze_pos_t &start = motion.position, &end = motion.destination; #endif - const xyze_pos_t total = end - start; - - #if ENABLED(FEEDRATE_MODE_SUPPORT) - // Get the linear distance in XYZ - #if HAS_ROTATIONAL_AXES - bool cartes_move = true; - #endif - float cartesian_mm = get_move_distance(total OPTARG(HAS_ROTATIONAL_AXES, cartes_move)); - - // If the move is very short, check the E move distance - TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = ABS(total.e)); - - const bool old_inverse_time_enabled = parser.inverse_time_enabled; - - const feedRate_t scaled_fr_mm_s = (old_inverse_time_enabled && parser.print_move) ? cartesian_mm * scaled_fr : scaled_fr; - parser.inverse_time_enabled = false; - - #else - const feedRate_t scaled_fr_mm_s = scaled_fr; - #endif - const xy_uint8_t istart = cell_indexes(start), iend = cell_indexes(end); // A move within the same cell needs no splitting @@ -100,7 +79,6 @@ end.z += UBL_Z_RAISE_WHEN_OFF_MESH; planner.buffer_segment(end, scaled_fr_mm_s, extruder); motion.position = motion.destination; - TERN_(FEEDRATE_MODE_SUPPORT, parser.inverse_time_enabled = old_inverse_time_enabled); return; } #endif @@ -119,7 +97,6 @@ if (!isnan(z0)) end.z += z0; planner.buffer_segment(end, scaled_fr_mm_s, extruder); motion.position = motion.destination; - TERN_(FEEDRATE_MODE_SUPPORT, parser.inverse_time_enabled = old_inverse_time_enabled); return; } @@ -128,7 +105,7 @@ * case - crossing only one X or Y line - after details are worked out to reduce computation. */ - const xy_float_t dist = xy_float_t(total); + const xy_float_t dist = xy_float_t(end) - xy_float_t(start); const xy_bool_t neg { dist.x < 0, dist.y < 0 }; const xy_uint8_t ineg { uint8_t(neg.x), uint8_t(neg.y) }; const xy_float_t sign { neg.x ? -1.0f : 1.0f, neg.y ? -1.0f : 1.0f }; @@ -217,7 +194,6 @@ goto FINAL_MOVE; motion.position = motion.destination; - TERN_(FEEDRATE_MODE_SUPPORT, parser.inverse_time_enabled = old_inverse_time_enabled); return; } @@ -387,11 +363,6 @@ return false; // caller will update current_position } - #if HAS_ROTATIONAL_AXES - bool cartes_move = true; - #endif - float cartesian_mm = get_move_distance(total OPTARG(HAS_ROTATIONAL_AXES, cartes_move)); - // If the move is very short, check the E move distance TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = ABS(total.e)); @@ -400,23 +371,8 @@ #if IS_KINEMATIC // Minimum number of seconds to move the given distance - #if ENABLED(FEEDRATE_MODE_SUPPORT) - const float seconds = (parser.print_move && parser.inverse_time_enabled) ? RECIPROCAL(scaled_fr_mm_s) : cartesian_mm / ( - #if ALL(HAS_ROTATIONAL_AXES, INCH_MODE_SUPPORT) - cartes_move ? scaled_fr_mm_s : LINEAR_UNIT(scaled_fr_mm_s) - #else - scaled_fr_mm_s - #endif - ); - #else - const float seconds = cartesian_mm / ( - #if ALL(HAS_ROTATIONAL_AXES, INCH_MODE_SUPPORT) - cartes_move ? scaled_fr_mm_s : LINEAR_UNIT(scaled_fr_mm_s) - #else - scaled_fr_mm_s - #endif - ); - #endif + const float seconds = cartesian_mm / scaled_fr_mm_s; + uint16_t segments = LROUND(segments_per_second * seconds), // Preferred number of segments for distance @ feedrate seglimit = LROUND(cartesian_mm * RECIPROCAL(SEGMENT_MIN_LENGTH)); // Number of segments at minimum segment length @@ -430,9 +386,7 @@ // Add hints to help optimize the move PlannerHints hints(cartesian_mm * inv_segments); // Length of each segment - #if ENABLED(FEEDRATE_MODE_SUPPORT) - hints.inv_duration = (parser.print_move && parser.inverse_time_enabled) ? (segments * scaled_fr_mm_s) : (scaled_fr_mm_s) / hints.millimeters); - #elif ENABLED(FEEDRATE_SCALING) + #if ENABLED(FEEDRATE_SCALING) hints.inv_duration = scaled_fr_mm_s / hints.millimeters; #endif diff --git a/Marlin/src/gcode/bedlevel/G42.cpp b/Marlin/src/gcode/bedlevel/G42.cpp index 0cc8db5e06cb..86b80735f833 100644 --- a/Marlin/src/gcode/bedlevel/G42.cpp +++ b/Marlin/src/gcode/bedlevel/G42.cpp @@ -54,7 +54,7 @@ void GcodeSuite::G42() { return; } - TERN_(FEEDRATE_MODE_SUPPORT, parser.print_move = true); + TERN_(FEEDRATE_MODE_SUPPORT, parser.apply_feedrate_mode = true); // Move to motion.position, as modified by I, J, P parameters motion.destination = motion.position; @@ -79,7 +79,7 @@ void GcodeSuite::G42() { motion.prepare_internal_move_to_destination(fr_mm_s); #endif - TERN_(FEEDRATE_MODE_SUPPORT, parser.print_move = false); + TERN_(FEEDRATE_MODE_SUPPORT, parser.apply_feedrate_mode = false); } #endif // HAS_MESH diff --git a/Marlin/src/gcode/feature/camera/M240.cpp b/Marlin/src/gcode/feature/camera/M240.cpp index 19c8f7769ce8..bccae9268302 100644 --- a/Marlin/src/gcode/feature/camera/M240.cpp +++ b/Marlin/src/gcode/feature/camera/M240.cpp @@ -139,7 +139,7 @@ void GcodeSuite::M240() { #endif feedRate_t fr_mm_s = MMM_TO_MMS(parser.feedrateval('F')); - if (fr_mm_s) NOLESS(fr_mm_s, TERN(FEEDRATE_MODE_SUPPORT, 0.01f, 10.0f)); + if (fr_mm_s) NOLESS(fr_mm_s, 10.0f); constexpr xyz_pos_t photo_position = PHOTO_POSITION; xyz_pos_t raw = { diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index e433f11d3145..5aceba5f5199 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -199,6 +199,18 @@ void GcodeSuite::get_destination_from_command() { motion.destination.e = motion.position.e; #endif + #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) + const xyze_pos_t displacement = destination - current_position; + + cartesian_mm = get_move_distance(displacement OPTARG(HAS_ROTATIONAL_AXES, parser.cartes_move)); + + #if HAS_EXTRUDERS + if (NEAR_ZERO(cartesian_mm)) { + cartesian_mm = ABS(displacement.e); + } + #endif + #endif + #if ENABLED(POWER_LOSS_RECOVERY) && !PIN_EXISTS(POWER_LOSS) // Only update power loss recovery on moves with E if (recovery.enabled && card.isStillPrinting() && seen.e && (seen.x || seen.y)) @@ -206,7 +218,13 @@ void GcodeSuite::get_destination_from_command() { #endif if (parser.floatval('F') > 0) { - const float fr_mm_min = parser.value_feedrate(); + #if ENABLED(FEEDRATE_MODE_SUPPORT) + float fr_mm_min = parser.value_feedrate(); + if (parser.inverse_time_enabled && parser.apply_feedrate_mode) + fr_mm_min *= cartesian_mm; + #else + const float fr_mm_min = parser.value_feedrate(); + #endif motion.feedrate_mm_s = MMM_TO_MMS(fr_mm_min); // Update the cutter feed rate for use by M4 I set inline moves. TERN_(LASER_FEATURE, cutter.feedrate_mm_m = fr_mm_min); diff --git a/Marlin/src/gcode/motion/G0_G1.cpp b/Marlin/src/gcode/motion/G0_G1.cpp index 370c278a3370..cc1093733cd0 100644 --- a/Marlin/src/gcode/motion/G0_G1.cpp +++ b/Marlin/src/gcode/motion/G0_G1.cpp @@ -54,27 +54,32 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) { #ifdef G0_FEEDRATE feedRate_t old_feedrate; #if ENABLED(VARIABLE_G0_FEEDRATE) - TERN_(FEEDRATE_MODE_SUPPORT, parser.print_move = true); + #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) + parser.apply_feedrate_mode = true; + #endif if (fast_move) { old_feedrate = motion.feedrate_mm_s; // Back up the (old) motion mode feedrate motion.feedrate_mm_s = fast_move_feedrate; // Get G0 feedrate from last usage } - #elif defined(FEEDRATE_MODE_SUPPORT) + #elif HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) if (fast_move) { - parser.print_move = false; + parser.apply_feedrate_mode = false; } else { - parser.print_move = true; + parser.apply_feedrate_mode = true; } #endif - #elif ENABLED(FEEDRATE_MODE_SUPPORT) - parser.print_move = true; + #elif HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) + parser.apply_feedrate_mode = true; #endif get_destination_from_command(); // Get X Y [Z[I[J[K]]]] [E] F (and set cutter power) #ifdef G0_FEEDRATE if (fast_move) { + #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) + parser.apply_feedrate_mode = false; + #endif #if ENABLED(VARIABLE_G0_FEEDRATE) fast_move_feedrate = motion.feedrate_mm_s; // Save feedrate for the next G0 #else @@ -114,7 +119,9 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) { if (fast_move) motion.feedrate_mm_s = old_feedrate; #endif - TERN_(FEEDRATE_MODE_SUPPORT, parser.print_move = false); + #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) + parser.apply_feedrate_mode = false; + #endif #if ENABLED(NANODLP_Z_SYNC) #if ENABLED(NANODLP_ALL_AXIS) diff --git a/Marlin/src/gcode/motion/G2_G3.cpp b/Marlin/src/gcode/motion/G2_G3.cpp index 88a766b99d23..93e53cf7eaf0 100644 --- a/Marlin/src/gcode/motion/G2_G3.cpp +++ b/Marlin/src/gcode/motion/G2_G3.cpp @@ -212,13 +212,7 @@ void plan_arc( } // Feedrate for the move, scaled by the feedrate multiplier - #if ENABLED(FEEDRATE_MODE_SUPPORT) - const feedRate_t scaled_fr = motion.mms_scaled(); - const feedRate_t scaled_fr_mm_s = parser.inverse_time_enabled ? scaled_fr * flat_mm : scaled_fr; - #else - const feedRate_t scaled_fr = motion.mms_scaled(); - const feedRate_t scaled_fr_mm_s = scaled_fr; - #endif + const feedRate_t scaled_fr_mm_s = motion.mms_scaled(); // Get the ideal segment length for the move based on settings const float ideal_segment_mm = ( @@ -241,10 +235,8 @@ void plan_arc( // Add hints to help optimize the move PlannerHints hints; - #if ENABLED(FEEDRATE_MODE_SUPPORT) - hints.inv_duration = segments * (parser.inverse_time_enabled ? scaled_fr : (scaled_fr_mm_s / flat_mm)); - #elif ENABLED(FEEDRATE_SCALING) - hints.inv_duration = segments * (scaled_fr_mm_s / flat_mm); + #if ENABLED(FEEDRATE_SCALING) + hints.inv_duration = (scaled_fr_mm_s / flat_mm) * segments; #endif /** @@ -379,7 +371,7 @@ void plan_arc( const float arc_mm_remaining = flat_mm - segment_mm * i; hints.safe_exit_speed_sqr = _MIN(limiting_speed_sqr, 2 * limiting_accel * arc_mm_remaining); - if (!planner.buffer_line(raw, scaled_fr, motion.extruder, hints)) + if (!planner.buffer_line(raw, scaled_fr_mm_s, motion.extruder, hints)) break; hints.curve_radius = radius; @@ -397,7 +389,7 @@ void plan_arc( hints.curve_radius = 0; hints.safe_exit_speed_sqr = 0.0f; - planner.buffer_line(raw, scaled_fr, motion.extruder, hints); + planner.buffer_line(raw, scaled_fr_mm_s, motion.extruder, hints); motion.position = cart; @@ -434,9 +426,10 @@ void GcodeSuite::G2_G3(const bool clockwise) { if (motion.gcode_motion_ignored()) return; TERN_(FULL_REPORT_TO_HOST_FEATURE, motion.set_and_report_grblstate(M_RUNNING)); - - TERN_(FEEDRATE_MODE_SUPPORT, parser.print_move = true); - + #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) + parser.apply_feedrate_mode = true; + #endif + #if ENABLED(SF_ARC_FIX) const bool relative_mode_backup = motion.relative_mode; motion.relative_mode = true; @@ -496,7 +489,9 @@ void GcodeSuite::G2_G3(const bool clockwise) { else SERIAL_ERROR_MSG(STR_ERR_ARC_ARGS); - TERN_(FEEDRATE_MODE_SUPPORT, parser.print_move = false); + #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) + parser.apply_feedrate_mode = false; + #endif TERN_(FULL_REPORT_TO_HOST_FEATURE, motion.set_and_report_grblstate(M_IDLE)); } diff --git a/Marlin/src/gcode/motion/G5.cpp b/Marlin/src/gcode/motion/G5.cpp index 0a39a96f571e..47785d509163 100644 --- a/Marlin/src/gcode/motion/G5.cpp +++ b/Marlin/src/gcode/motion/G5.cpp @@ -52,14 +52,9 @@ void GcodeSuite::G5() { return; } #endif - - #if ENABLED(FEEDRATE_MODE_SUPPORT) - if (parser.inverse_time_enabled) { - SERIAL_ERROR_MSG(STR_ERR_BAD_FEEDRATE_MODE); - return; - } + #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) + parser.apply_feedrate_mode = true; #endif - get_destination_from_command(); const xy_pos_t offsets[2] = { @@ -69,6 +64,9 @@ void GcodeSuite::G5() { cubic_b_spline(motion.position, motion.destination, offsets, motion.mms_scaled(), motion.extruder); motion.position = motion.destination; + #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) + parser.apply_feedrate_mode = false; + #endif } #endif // BEZIER_CURVE_SUPPORT diff --git a/Marlin/src/gcode/parser.cpp b/Marlin/src/gcode/parser.cpp index 6c7565491a40..8d1a5af6cf86 100644 --- a/Marlin/src/gcode/parser.cpp +++ b/Marlin/src/gcode/parser.cpp @@ -39,7 +39,13 @@ bool GCodeParser::volumetric_enabled; #if ENABLED(FEEDRATE_MODE_SUPPORT) bool GCodeParser::inverse_time_enabled; - bool GCodeParser::print_move; +#endif +#if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) + bool GCodeParser::apply_feedrate_mode; +#endif + +#if HAS_ROTATIONAL_AXES + bool GCodeParser::cartes_move; #endif #if ENABLED(TEMPERATURE_UNITS_SUPPORT) diff --git a/Marlin/src/gcode/parser.h b/Marlin/src/gcode/parser.h index 06d1cc36535b..2193f51ccf2b 100644 --- a/Marlin/src/gcode/parser.h +++ b/Marlin/src/gcode/parser.h @@ -78,7 +78,13 @@ class GCodeParser { #if ENABLED(FEEDRATE_MODE_SUPPORT) static bool inverse_time_enabled; - static bool print_move; + #endif + #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) + static bool apply_feedrate_mode; + #endif + + #if HAS_ROTATIONAL_AXES + static bool cartes_move; #endif #if ENABLED(TEMPERATURE_UNITS_SUPPORT) @@ -421,8 +427,8 @@ class GCodeParser { #endif // !TEMPERATURE_UNITS_SUPPORT static feedRate_t value_feedrate() { - #if ENABLED(FEEDRATE_MODE_SUPPORT) - return (inverse_time_enabled && print_move) ? value_float() : value_linear_units(); + #if HAS_ROTATIONAL_AXES || ENABLED(FEEDRATE_MODE_SUPPORT) + return ((TERN0(FEEDRATE_MODE_SUPPORT, inverse_time_enabled && apply_feedrate_mode)) || TERN0(HAS_ROTATIONAL_AXES, (!cartes_move))) ? value_float() : value_linear_units(); #else return value_linear_units(); #endif diff --git a/Marlin/src/gcode/sd/M24_M25.cpp b/Marlin/src/gcode/sd/M24_M25.cpp index 6eb1375db444..33f2107e675b 100644 --- a/Marlin/src/gcode/sd/M24_M25.cpp +++ b/Marlin/src/gcode/sd/M24_M25.cpp @@ -57,7 +57,7 @@ void GcodeSuite::M24() { #if DGUS_LCD_UI_MKS if ((print_job_timer.isPaused() || print_job_timer.isRunning()) && !parser.seen("ST")) - MKS_resume_print_move(); + MKS_resume_apply_feedrate_mode(); #endif #if ENABLED(POWER_LOSS_RECOVERY) @@ -112,7 +112,7 @@ void GcodeSuite::M25() { print_job_timer.pause(); - TERN_(DGUS_LCD_UI_MKS, MKS_pause_print_move()); + TERN_(DGUS_LCD_UI_MKS, MKS_pause_apply_feedrate_mode()); IF_DISABLED(DWIN_CREALITY_LCD, ui.reset_status()); diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp index e2f43efa212a..a0798f8bedc3 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp @@ -79,7 +79,7 @@ xyz_pos_t position_before_pause; constexpr feedRate_t park_speed_xy = TERN(NOZZLE_PARK_FEATURE, NOZZLE_PARK_XY_FEEDRATE, 100), park_speed_z = TERN(NOZZLE_PARK_FEATURE, NOZZLE_PARK_Z_FEEDRATE, 5); -void MKS_pause_print_move() { +void MKS_pause_apply_feedrate_mode() { queue.exhaust(); position_before_pause = motion.position; diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h index ba5508e44199..3ec016b8b009 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h @@ -44,8 +44,8 @@ extern celsius_t mks_min_extrusion_temp; void MKS_reset_settings(); // Restore persistent settings to defaults -void MKS_pause_print_move(); -void MKS_resume_print_move(); +void MKS_pause_apply_feedrate_mode(); +void MKS_resume_apply_feedrate_mode(); extern float z_offset_add; diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index f475b52efc31..78718bce9ad9 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -857,13 +857,6 @@ void MarlinUI::init() { const feedRate_t fr_mm_s = (axis < LOGICAL_AXES) ? manual_feedrate_mm_s[axis] : PLANNER_XY_FEEDRATE_MM_S; - /** - * For a rotational axis apply the "inch" to "mm" conversion factor. This mimics behaviour of the G-code G1 - * (see get_destination_from_command). For moves involving only rotational axes, the planner will convert - * back to the feedrate in degrees-per-time unit. - */ - const feedRate_t fr = parser.axis_is_rotational(axis) && parser.using_inch_units() ? IN_TO_MM(fr_mm_s) : fr_mm_s; - #if IS_KINEMATIC #if HAS_MULTI_EXTRUDER @@ -890,13 +883,13 @@ void MarlinUI::init() { // previous invocation is being blocked. Modifications to offset shouldn't be made while // processing is true or the planner will get out of sync. processing = true; - motion.prepare_internal_move_to_destination(fr); // will set motion.position from destination + motion.prepare_internal_move_to_destination(fr_mm_s); // will set current_position from destination processing = false; #else - // For Cartesian / Core motion simply move to the motion.position - planner.buffer_line(motion.position, fr, + // For Cartesian / Core motion simply move to the current_position + planner.buffer_line(motion.position, fr_mm_s, TERN_(MULTI_E_MANUAL, axis == E_AXIS ? e_index :) motion.extruder ); diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index e0b11a6ea7c5..81972cef3128 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -200,6 +200,10 @@ int16_t Motion::feedrate_percentage = 100; #endif // IS_KINEMATIC +#if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) + float cartesian_mm = 0.0f; +#endif + /** * The workspace can be offset by some commands, or * these offsets may be omitted to save on computation. @@ -1620,12 +1624,6 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE // Fail if attempting move outside printable radius if (!can_reach(destination)) return true; - // Get the linear distance in XYZ - #if HAS_ROTATIONAL_AXES - bool cartes_move = true; - #endif - float cartesian_mm = get_move_distance(diff OPTARG(HAS_ROTATIONAL_AXES, cartes_move)); - // If the move is very short, check the E move distance TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = ABS(diff.e)); @@ -1633,23 +1631,7 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE if (UNEAR_ZERO(cartesian_mm)) return true; // Minimum number of seconds to move the given distance - #if ENABLED(FEEDRATE_MODE_SUPPORT) - const float seconds = (parser.print_move && parser.inverse_time_enabled) ? RECIPROCAL(scaled_fr_mm_s) : cartesian_mm / ( - #if ALL(HAS_ROTATIONAL_AXES, INCH_MODE_SUPPORT) - cartes_move ? scaled_fr_mm_s : LINEAR_UNIT(scaled_fr_mm_s) - #else - scaled_fr_mm_s - #endif - ); - #else - const float seconds = cartesian_mm / ( - #if ALL(HAS_ROTATIONAL_AXES, INCH_MODE_SUPPORT) - cartes_move ? scaled_fr_mm_s : LINEAR_UNIT(scaled_fr_mm_s) - #else - scaled_fr_mm_s - #endif - ); - #endif + const float seconds = cartesian_mm / scaled_fr_mm_s; // The number of segments-per-second times the duration // gives the number of segments @@ -1671,10 +1653,7 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE // Add hints to help optimize the move PlannerHints hints(cartesian_mm * inv_segments); - TERN_(HAS_ROTATIONAL_AXES, hints.cartesian_move = cartes_move); - #if ENABLED(FEEDRATE_MODE_SUPPORT) - hints.inv_duration = (parser.inverse_time_enabled && parser.print_move) ? (scaled_fr_mm_s * segments) : (scaled_fr_mm_s / hints.millimeters); - #elif ENABLED(FEEDRATE_SCALING) + #if ENABLED(FEEDRATE_SCALING) hints.inv_duration = scaled_fr_mm_s / hints.millimeters; #endif /* @@ -1725,10 +1704,10 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE } // Get the linear distance in XYZ - #if HAS_ROTATIONAL_AXES - bool cartes_move = true; + #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) + if (!parser.apply_feedrate_mode) #endif - float cartesian_mm = get_move_distance(diff OPTARG(HAS_ROTATIONAL_AXES, cartes_move)); + cartesian_mm = get_move_distance(diff OPTARG(HAS_ROTATIONAL_AXES, parser.cartes_move)); // If the move is very short, check the E move distance TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = ABS(diff.e)); @@ -1747,9 +1726,7 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE // Add hints to help optimize the move PlannerHints hints(cartesian_mm * inv_segments); - TERN_(HAS_ROTATIONAL_AXES, hints.cartesian_move = cartes_move); - TERN_(FEEDRATE_SCALING, hints.inv_duration = scaled_fr_mm_s / hints.millimeters); // TODO (DerAndere): Fix inverse time mode for FEEDRATE_MODE_SUPPORT - + TERN_(FEEDRATE_SCALING, hints.inv_duration = scaled_fr_mm_s / hints.millimeters); //SERIAL_ECHOPGM("mm=", cartesian_mm); //SERIAL_ECHOLNPGM(" segments=", segments); //SERIAL_ECHOLNPGM(" segment_mm=", hints.millimeters); diff --git a/Marlin/src/module/motion.h b/Marlin/src/module/motion.h index e6a8e232540e..4c11f566e857 100644 --- a/Marlin/src/module/motion.h +++ b/Marlin/src/module/motion.h @@ -120,6 +120,9 @@ class Motion { #if HAS_SCARA_OFFSET static abc_pos_t scara_home_offset; // A and B angular offsets, Z mm offset #endif + #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) + static float cartesian_mm; + #endif #if HAS_HOTEND_OFFSET static xyz_pos_t hotend_offset[HOTENDS]; diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 39f90daafab1..c8c6b50e81b1 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -2022,7 +2022,7 @@ bool Planner::_populate_block( TERN_(FT_MOTION, block->ext_distance_mm = dist_mm); // Store the distance for all axes in mm for this block #if HAS_ROTATIONAL_AXES - bool cartesian_move = hints.cartesian_move; + bool cartesian_move; #endif // Determine linear distance for block->millimeters @@ -2173,20 +2173,10 @@ bool Planner::_populate_block( #endif // HAS_EXTRUDERS if (esteps) { - if (TERN0(FEEDRATE_MODE_SUPPORT, parser.inverse_time_enabled && parser.print_move)) { - NOLESS(fr_mm_s, RECIPROCAL(settings.min_feedrate_mm_s)); - } - else { NOLESS(fr_mm_s, settings.min_feedrate_mm_s); - } } else { - if (TERN0(FEEDRATE_MODE_SUPPORT, parser.inverse_time_enabled && parser.print_move)) { - NOLESS(fr_mm_s, RECIPROCAL(settings.min_travel_feedrate_mm_s)); - } - else { NOLESS(fr_mm_s, settings.min_travel_feedrate_mm_s); - } } const float inverse_millimeters = 1.0f / block->millimeters; // Inverse millimeters to remove multiple divides @@ -2196,37 +2186,13 @@ bool Planner::_populate_block( * EXAMPLE: At 120°/s a 60° move involving only rotational axes takes 0.5s. So this will give 2.0. */ - float inverse_secs; - if (TERN0(FEEDRATE_MODE_SUPPORT, parser.inverse_time_enabled && parser.print_move)) { - #if ENABLED(FEEDRATE_MODE_SUPPORT) - inverse_secs = hints.inv_duration ? : fr_mm_s; + float inverse_secs = ( + #if ANY(FEEDRATE_SCALING, FEEDRATE_MODE_SUPPORT) + hints.inv_duration ? : inverse_millimeters * fr_mm_s #else - inverse_secs = fr_mm_s; + inverse_millimeters * fr_mm_s #endif - float min_inverse_secs; - if (esteps) - min_inverse_secs = settings.min_feedrate_mm_s * inverse_millimeters; - else - min_inverse_secs = settings.min_travel_feedrate_mm_s * inverse_millimeters; - NOLESS(inverse_secs, min_inverse_secs); - } - else { - #if ENABLED(FEEDRATE_MODE_SUPPORT) - inverse_secs = hints.inv_duration ? : inverse_millimeters * ( - #else - inverse_secs = inverse_millimeters * ( - #endif - #if ALL(HAS_ROTATIONAL_AXES, INCH_MODE_SUPPORT) - /** - * Workaround for premature feedrate conversion - * from in/s to mm/s by get_distance_from_command. - */ - cartesian_move ? fr_mm_s : LINEAR_UNIT(fr_mm_s) - #else - fr_mm_s - #endif - ); - } + ); // Get the number of non busy movements in queue (non busy means that they can be altered) const uint8_t moves_queued = nonbusy_movesplanned(); @@ -3015,8 +2981,11 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const feedRate_t fr_mm_s // Provide known Cartesian length in the hints structure PlannerHints ph = hints; + #if HAS_ROTATIONAL_AXES + bool cartesian_move; + #endif if (!hints.millimeters) - ph.millimeters = motion.get_move_distance(xyze_pos_t(cart_dist_mm) OPTARG(HAS_ROTATIONAL_AXES, ph.cartesian_move)); + ph.millimeters = motion.get_move_distance(xyze_pos_t(motion.cart_dist_mm) OPTARG(HAS_ROTATIONAL_AXES, cartesian_move)); #if DISABLED(FEEDRATE_SCALING) diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index 26491bc237d7..0af227778090 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -483,11 +483,6 @@ struct PlannerHints { // would calculate if it knew the as-yet-unbuffered path #endif - #if HAS_ROTATIONAL_AXES - bool cartesian_move = true; // True if linear motion of the tool centerpoint relative to the workpiece occurs. - // False if no movement of the tool center point relative to the work piece occurs - // (i.e. the tool rotates around the tool centerpoint) - #endif PlannerHints(const float mm=0.0f) : millimeters(mm) {} }; From 6ff5f2c19c426dd5a8c207ebba2e80d1e0c14692 Mon Sep 17 00:00:00 2001 From: DerAndere <26200979+DerAndere1@users.noreply.github.com> Date: Thu, 18 Dec 2025 01:27:57 +0100 Subject: [PATCH 04/14] fixup --- .../bedlevel/mbl/mesh_bed_leveling.cpp | 5 ++- .../src/feature/bedlevel/ubl/ubl_motion.cpp | 14 ++++---- Marlin/src/gcode/bedlevel/G42.cpp | 4 +-- Marlin/src/gcode/gcode.cpp | 14 +++----- Marlin/src/gcode/motion/G0_G1.cpp | 22 ++++++------ Marlin/src/gcode/motion/G2_G3.cpp | 10 +++--- Marlin/src/gcode/motion/G5.cpp | 7 +--- Marlin/src/gcode/parser.cpp | 15 ++++---- Marlin/src/gcode/parser.h | 21 ++++++----- Marlin/src/gcode/sd/M24_M25.cpp | 4 +-- Marlin/src/inc/SanityCheck.h | 7 ++++ .../src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp | 2 +- .../src/lcd/extui/dgus/mks/DGUSDisplayDef.h | 4 +-- Marlin/src/module/motion.cpp | 36 +++++++++---------- Marlin/src/module/motion.h | 3 -- Marlin/src/module/planner.cpp | 7 ++-- 16 files changed, 83 insertions(+), 92 deletions(-) diff --git a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp index 0bd181756fe5..1f462fd2f91f 100644 --- a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp +++ b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp @@ -75,12 +75,11 @@ segments = ecel - scel; NOLESS(segments, 1); - segment_fr = (parser.inverse_time_enabled && parser.apply_feedrate_mode) ? scaled_fr_mm_s * segments : scaled_fr_mm_s; // Start and end in the same cell? No split needed. if (scel == ecel) { - motion.position = motion.destination; - motion.line_to_current_position(segment_fr); + motion.position = motion.destination; + motion.line_to_current_position(scaled_fr_mm_s); return; } diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp index 86dc5ff04168..d44f345e3392 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp @@ -362,30 +362,32 @@ planner.buffer_line(destination, scaled_fr_mm_s); return false; // caller will update current_position } + if (!parser.process_motion_gcode) + parser.cartesian_mm = get_move_distance(total OPTARG(HAS_ROTATIONAL_AXES, parser.cartes_move)); // If the move is very short, check the E move distance - TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = ABS(total.e)); + TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(parser.cartesian_mm)) parser.cartesian_mm = ABS(total.e)); // No E move either? Game over. - if (UNEAR_ZERO(cartesian_mm)) return true; + if (UNEAR_ZERO(parser.cartesian_mm)) return true; #if IS_KINEMATIC // Minimum number of seconds to move the given distance - const float seconds = cartesian_mm / scaled_fr_mm_s; + const float seconds = parser.cartesian_mm / scaled_fr_mm_s; uint16_t segments = LROUND(segments_per_second * seconds), // Preferred number of segments for distance @ feedrate - seglimit = LROUND(cartesian_mm * RECIPROCAL(SEGMENT_MIN_LENGTH)); // Number of segments at minimum segment length + seglimit = LROUND(parser.cartesian_mm * RECIPROCAL(SEGMENT_MIN_LENGTH)); // Number of segments at minimum segment length NOMORE(segments, seglimit); // Limit to minimum segment length (fewer segments) #else - uint16_t segments = LROUND(cartesian_mm * RECIPROCAL(SEGMENT_MIN_LENGTH)); // Cartesian fixed segment length + uint16_t segments = LROUND(parser.cartesian_mm * RECIPROCAL(SEGMENT_MIN_LENGTH)); // Cartesian fixed segment length #endif NOLESS(segments, 1U); // Must have at least one segment const float inv_segments = 1.0f / segments; // Reciprocal to save calculation // Add hints to help optimize the move - PlannerHints hints(cartesian_mm * inv_segments); // Length of each segment + PlannerHints hints(parser.cartesian_mm * inv_segments); // Length of each segment #if ENABLED(FEEDRATE_SCALING) hints.inv_duration = scaled_fr_mm_s / hints.millimeters; #endif diff --git a/Marlin/src/gcode/bedlevel/G42.cpp b/Marlin/src/gcode/bedlevel/G42.cpp index 86b80735f833..308426b5b763 100644 --- a/Marlin/src/gcode/bedlevel/G42.cpp +++ b/Marlin/src/gcode/bedlevel/G42.cpp @@ -54,7 +54,7 @@ void GcodeSuite::G42() { return; } - TERN_(FEEDRATE_MODE_SUPPORT, parser.apply_feedrate_mode = true); + TERN_(FEEDRATE_MODE_SUPPORT, parser.process_motion_gcode = true); // Move to motion.position, as modified by I, J, P parameters motion.destination = motion.position; @@ -79,7 +79,7 @@ void GcodeSuite::G42() { motion.prepare_internal_move_to_destination(fr_mm_s); #endif - TERN_(FEEDRATE_MODE_SUPPORT, parser.apply_feedrate_mode = false); + TERN_(FEEDRATE_MODE_SUPPORT, parser.process_motion_gcode = false); } #endif // HAS_MESH diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 5aceba5f5199..cadb411174ca 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -202,11 +202,11 @@ void GcodeSuite::get_destination_from_command() { #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) const xyze_pos_t displacement = destination - current_position; - cartesian_mm = get_move_distance(displacement OPTARG(HAS_ROTATIONAL_AXES, parser.cartes_move)); + parser.cartesian_mm = get_move_distance(displacement OPTARG(HAS_ROTATIONAL_AXES, parser.cartes_move)); #if HAS_EXTRUDERS - if (NEAR_ZERO(cartesian_mm)) { - cartesian_mm = ABS(displacement.e); + if (NEAR_ZERO(parser.cartesian_mm)) { + parser.cartesian_mm = ABS(displacement.e); } #endif #endif @@ -218,13 +218,7 @@ void GcodeSuite::get_destination_from_command() { #endif if (parser.floatval('F') > 0) { - #if ENABLED(FEEDRATE_MODE_SUPPORT) - float fr_mm_min = parser.value_feedrate(); - if (parser.inverse_time_enabled && parser.apply_feedrate_mode) - fr_mm_min *= cartesian_mm; - #else - const float fr_mm_min = parser.value_feedrate(); - #endif + const float fr_mm_min = parser.value_feedrate(); motion.feedrate_mm_s = MMM_TO_MMS(fr_mm_min); // Update the cutter feed rate for use by M4 I set inline moves. TERN_(LASER_FEATURE, cutter.feedrate_mm_m = fr_mm_min); diff --git a/Marlin/src/gcode/motion/G0_G1.cpp b/Marlin/src/gcode/motion/G0_G1.cpp index cc1093733cd0..d8306c4f9dfa 100644 --- a/Marlin/src/gcode/motion/G0_G1.cpp +++ b/Marlin/src/gcode/motion/G0_G1.cpp @@ -54,31 +54,31 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) { #ifdef G0_FEEDRATE feedRate_t old_feedrate; #if ENABLED(VARIABLE_G0_FEEDRATE) - #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) - parser.apply_feedrate_mode = true; + #if ENABLED(FEEDRATE_MODE_SUPPORT) + parser.process_motion_gcode = true; #endif if (fast_move) { old_feedrate = motion.feedrate_mm_s; // Back up the (old) motion mode feedrate motion.feedrate_mm_s = fast_move_feedrate; // Get G0 feedrate from last usage } - #elif HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) + #elif ENABLED(FEEDRATE_MODE_SUPPORT) if (fast_move) { - parser.apply_feedrate_mode = false; + parser.process_motion_gcode = false; } else { - parser.apply_feedrate_mode = true; + parser.process_motion_gcode = true; } #endif - #elif HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) - parser.apply_feedrate_mode = true; + #elif ENABLED(FEEDRATE_MODE_SUPPORT) + parser.process_motion_gcode = true; #endif get_destination_from_command(); // Get X Y [Z[I[J[K]]]] [E] F (and set cutter power) #ifdef G0_FEEDRATE if (fast_move) { - #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) - parser.apply_feedrate_mode = false; + #if ENABLED(FEEDRATE_MODE_SUPPORT) + parser.process_motion_gcode = false; #endif #if ENABLED(VARIABLE_G0_FEEDRATE) fast_move_feedrate = motion.feedrate_mm_s; // Save feedrate for the next G0 @@ -119,8 +119,8 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) { if (fast_move) motion.feedrate_mm_s = old_feedrate; #endif - #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) - parser.apply_feedrate_mode = false; + #if ENABLED(FEEDRATE_MODE_SUPPORT) + parser.process_motion_gcode = false; #endif #if ENABLED(NANODLP_Z_SYNC) diff --git a/Marlin/src/gcode/motion/G2_G3.cpp b/Marlin/src/gcode/motion/G2_G3.cpp index 93e53cf7eaf0..a627025816a3 100644 --- a/Marlin/src/gcode/motion/G2_G3.cpp +++ b/Marlin/src/gcode/motion/G2_G3.cpp @@ -235,7 +235,9 @@ void plan_arc( // Add hints to help optimize the move PlannerHints hints; - #if ENABLED(FEEDRATE_SCALING) + #if ENABLED(FEEDRATE_MODE_SUPPORT) + hints.inv_duration = segments * (parser.inverse_time_enabled ? scaled_fr_mm_s : (scaled_fr_mm_s / flat_mm)); + #elif ENABLED(FEEDRATE_SCALING) hints.inv_duration = (scaled_fr_mm_s / flat_mm) * segments; #endif @@ -427,7 +429,7 @@ void GcodeSuite::G2_G3(const bool clockwise) { TERN_(FULL_REPORT_TO_HOST_FEATURE, motion.set_and_report_grblstate(M_RUNNING)); #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) - parser.apply_feedrate_mode = true; + parser.process_motion_gcode = false; #endif #if ENABLED(SF_ARC_FIX) @@ -489,10 +491,6 @@ void GcodeSuite::G2_G3(const bool clockwise) { else SERIAL_ERROR_MSG(STR_ERR_ARC_ARGS); - #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) - parser.apply_feedrate_mode = false; - #endif - TERN_(FULL_REPORT_TO_HOST_FEATURE, motion.set_and_report_grblstate(M_IDLE)); } diff --git a/Marlin/src/gcode/motion/G5.cpp b/Marlin/src/gcode/motion/G5.cpp index 47785d509163..d625b2538184 100644 --- a/Marlin/src/gcode/motion/G5.cpp +++ b/Marlin/src/gcode/motion/G5.cpp @@ -52,9 +52,6 @@ void GcodeSuite::G5() { return; } #endif - #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) - parser.apply_feedrate_mode = true; - #endif get_destination_from_command(); const xy_pos_t offsets[2] = { @@ -64,9 +61,7 @@ void GcodeSuite::G5() { cubic_b_spline(motion.position, motion.destination, offsets, motion.mms_scaled(), motion.extruder); motion.position = motion.destination; - #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) - parser.apply_feedrate_mode = false; - #endif + } #endif // BEZIER_CURVE_SUPPORT diff --git a/Marlin/src/gcode/parser.cpp b/Marlin/src/gcode/parser.cpp index 8d1a5af6cf86..9c5a74a8e347 100644 --- a/Marlin/src/gcode/parser.cpp +++ b/Marlin/src/gcode/parser.cpp @@ -37,15 +37,16 @@ bool GCodeParser::volumetric_enabled; float GCodeParser::linear_unit_factor, GCodeParser::volumetric_unit_factor; #endif -#if ENABLED(FEEDRATE_MODE_SUPPORT) - bool GCodeParser::inverse_time_enabled; -#endif #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) - bool GCodeParser::apply_feedrate_mode; -#endif + bool GCodeParser::process_motion_gcode; + float GCodeParser::cartesian_mm; + #if ENABLED(FEEDRATE_MODE_SUPPORT) + bool GCodeParser::inverse_time_enabled; + #endif + #if HAS_ROTATIONAL_AXES + bool GCodeParser::cartes_move; + #endif -#if HAS_ROTATIONAL_AXES - bool GCodeParser::cartes_move; #endif #if ENABLED(TEMPERATURE_UNITS_SUPPORT) diff --git a/Marlin/src/gcode/parser.h b/Marlin/src/gcode/parser.h index 2193f51ccf2b..5b208b6d2ea2 100644 --- a/Marlin/src/gcode/parser.h +++ b/Marlin/src/gcode/parser.h @@ -76,15 +76,15 @@ class GCodeParser { static float linear_unit_factor, volumetric_unit_factor; #endif - #if ENABLED(FEEDRATE_MODE_SUPPORT) - static bool inverse_time_enabled; - #endif #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) - static bool apply_feedrate_mode; - #endif - - #if HAS_ROTATIONAL_AXES + static float cartesian_mm; + static bool process_motion_gcode; + #if ENABLED(FEEDRATE_MODE_SUPPORT) + static bool inverse_time_enabled; + #endif + #if HAS_ROTATIONAL_AXES static bool cartes_move; + #endif #endif #if ENABLED(TEMPERATURE_UNITS_SUPPORT) @@ -428,7 +428,12 @@ class GCodeParser { static feedRate_t value_feedrate() { #if HAS_ROTATIONAL_AXES || ENABLED(FEEDRATE_MODE_SUPPORT) - return ((TERN0(FEEDRATE_MODE_SUPPORT, inverse_time_enabled && apply_feedrate_mode)) || TERN0(HAS_ROTATIONAL_AXES, (!cartes_move))) ? value_float() : value_linear_units(); + float fr = ((TERN0(FEEDRATE_MODE_SUPPORT, inverse_time_enabled && process_motion_gcode)) || TERN0(HAS_ROTATIONAL_AXES, (!cartes_move))) ? value_float() : value_linear_units(); + #if ENABLED(FEEDRATE_MODE_SUPPORT) + if (inverse_time_enabled && process_motion_gcode) + fr *= cartesian_mm; + #endif + return fr #else return value_linear_units(); #endif diff --git a/Marlin/src/gcode/sd/M24_M25.cpp b/Marlin/src/gcode/sd/M24_M25.cpp index 33f2107e675b..6eb1375db444 100644 --- a/Marlin/src/gcode/sd/M24_M25.cpp +++ b/Marlin/src/gcode/sd/M24_M25.cpp @@ -57,7 +57,7 @@ void GcodeSuite::M24() { #if DGUS_LCD_UI_MKS if ((print_job_timer.isPaused() || print_job_timer.isRunning()) && !parser.seen("ST")) - MKS_resume_apply_feedrate_mode(); + MKS_resume_print_move(); #endif #if ENABLED(POWER_LOSS_RECOVERY) @@ -112,7 +112,7 @@ void GcodeSuite::M25() { print_job_timer.pause(); - TERN_(DGUS_LCD_UI_MKS, MKS_pause_apply_feedrate_mode()); + TERN_(DGUS_LCD_UI_MKS, MKS_pause_print_move()); IF_DISABLED(DWIN_CREALITY_LCD, ui.reset_status()); diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 0e96c355f5a0..77df0d8863c1 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -875,6 +875,13 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L #endif #endif +/** + * Feedrate mode requirements + */ +#if ALL(FEEDRATE_MODE_SUPPORT, BEZIER_CURVE_SUPPORT) + #error "FEEDRATE_MODE_SUPPORT is currently incompatible with BEZIER_CURVE_SUPPORT." +#endif + /** * Special tool-changing options */ diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp index a0798f8bedc3..e2f43efa212a 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp @@ -79,7 +79,7 @@ xyz_pos_t position_before_pause; constexpr feedRate_t park_speed_xy = TERN(NOZZLE_PARK_FEATURE, NOZZLE_PARK_XY_FEEDRATE, 100), park_speed_z = TERN(NOZZLE_PARK_FEATURE, NOZZLE_PARK_Z_FEEDRATE, 5); -void MKS_pause_apply_feedrate_mode() { +void MKS_pause_print_move() { queue.exhaust(); position_before_pause = motion.position; diff --git a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h index 3ec016b8b009..ba5508e44199 100644 --- a/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h +++ b/Marlin/src/lcd/extui/dgus/mks/DGUSDisplayDef.h @@ -44,8 +44,8 @@ extern celsius_t mks_min_extrusion_temp; void MKS_reset_settings(); // Restore persistent settings to defaults -void MKS_pause_apply_feedrate_mode(); -void MKS_resume_apply_feedrate_mode(); +void MKS_pause_print_move(); +void MKS_resume_print_move(); extern float z_offset_add; diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 81972cef3128..f863040d8858 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -200,10 +200,6 @@ int16_t Motion::feedrate_percentage = 100; #endif // IS_KINEMATIC -#if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) - float cartesian_mm = 0.0f; -#endif - /** * The workspace can be offset by some commands, or * these offsets may be omitted to save on computation. @@ -1623,15 +1619,17 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE // Fail if attempting move outside printable radius if (!can_reach(destination)) return true; + if (!parser.process_motion_gcode) + parser.cartesian_mm = motion.get_move_distance(diff OPTARG(HAS_ROTATIONAL_AXES, parser.cartes_move)); // If the move is very short, check the E move distance - TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = ABS(diff.e)); + TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(parser.cartesian_mm)) parser.cartesian_mm = ABS(diff.e)); // No E move either? Game over. - if (UNEAR_ZERO(cartesian_mm)) return true; + if (UNEAR_ZERO(parser.cartesian_mm)) return true; // Minimum number of seconds to move the given distance - const float seconds = cartesian_mm / scaled_fr_mm_s; + const float seconds = parser.cartesian_mm / scaled_fr_mm_s; // The number of segments-per-second times the duration // gives the number of segments @@ -1639,9 +1637,9 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE // For SCARA enforce a minimum segment size #if IS_SCARA - NOMORE(segments, cartesian_mm * RECIPROCAL(SCARA_MIN_SEGMENT_LENGTH)); + NOMORE(segments, parser.cartesian_mm * RECIPROCAL(SCARA_MIN_SEGMENT_LENGTH)); #elif ENABLED(POLAR) - NOMORE(segments, cartesian_mm * RECIPROCAL(POLAR_MIN_SEGMENT_LENGTH)); + NOMORE(segments, parser.cartesian_mm * RECIPROCAL(POLAR_MIN_SEGMENT_LENGTH)); #endif // At least one segment is required @@ -1652,9 +1650,9 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE const xyze_float_t segment_distance = diff * inv_segments; // Add hints to help optimize the move - PlannerHints hints(cartesian_mm * inv_segments); + PlannerHints hints(parser.cartesian_mm * inv_segments); #if ENABLED(FEEDRATE_SCALING) - hints.inv_duration = scaled_fr_mm_s / hints.millimeters; + hints.inv_duration = scaled_fr_mm_s / hints.millimeters; #endif /* SERIAL_ECHOPGM("mm=", cartesian_mm); @@ -1703,21 +1701,19 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE return; } - // Get the linear distance in XYZ - #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) - if (!parser.apply_feedrate_mode) - #endif - cartesian_mm = get_move_distance(diff OPTARG(HAS_ROTATIONAL_AXES, parser.cartes_move)); + // Get the move distance + if (parser.process_motion_gcode) + parser.cartesian_mm = get_move_distance(diff OPTARG(HAS_ROTATIONAL_AXES, parser.cartes_move)); // If the move is very short, check the E move distance - TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = ABS(diff.e)); + TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(parser.cartesian_mm)) parser.cartesian_mm = ABS(diff.e)); // No E move either? Game over. - if (UNEAR_ZERO(cartesian_mm)) return; + if (UNEAR_ZERO(parser.cartesian_mm)) return; // The length divided by the segment size // At least one segment is required - uint16_t segments = cartesian_mm / segment_size; + uint16_t segments = parser.cartesian_mm / segment_size; NOLESS(segments, 1U); // The approximate length of each segment @@ -1725,7 +1721,7 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE const xyze_float_t segment_distance = diff * inv_segments; // Add hints to help optimize the move - PlannerHints hints(cartesian_mm * inv_segments); + PlannerHints hints(parser.cartesian_mm * inv_segments); TERN_(FEEDRATE_SCALING, hints.inv_duration = scaled_fr_mm_s / hints.millimeters); //SERIAL_ECHOPGM("mm=", cartesian_mm); //SERIAL_ECHOLNPGM(" segments=", segments); diff --git a/Marlin/src/module/motion.h b/Marlin/src/module/motion.h index 4c11f566e857..e6a8e232540e 100644 --- a/Marlin/src/module/motion.h +++ b/Marlin/src/module/motion.h @@ -120,9 +120,6 @@ class Motion { #if HAS_SCARA_OFFSET static abc_pos_t scara_home_offset; // A and B angular offsets, Z mm offset #endif - #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) - static float cartesian_mm; - #endif #if HAS_HOTEND_OFFSET static xyz_pos_t hotend_offset[HOTENDS]; diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index c8c6b50e81b1..48a282f30c6c 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -2043,7 +2043,7 @@ bool Planner::_populate_block( dist_mm.u, dist_mm.v, dist_mm.w ); - block->millimeters = motion.get_move_distance(displacement OPTARG(HAS_ROTATIONAL_AXES, cartesian_move)); + block->millimeters = motion.get_move_distance(displacement OPTARG(HAS_ROTATIONAL_AXES, parser.cartes_move)); } /** @@ -2981,11 +2981,8 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const feedRate_t fr_mm_s // Provide known Cartesian length in the hints structure PlannerHints ph = hints; - #if HAS_ROTATIONAL_AXES - bool cartesian_move; - #endif if (!hints.millimeters) - ph.millimeters = motion.get_move_distance(xyze_pos_t(motion.cart_dist_mm) OPTARG(HAS_ROTATIONAL_AXES, cartesian_move)); + ph.millimeters = motion.get_move_distance(xyze_pos_t(cart_dist_mm) OPTARG(HAS_ROTATIONAL_AXES, parser.cartesian_move)); #if DISABLED(FEEDRATE_SCALING) From b071f22d9e2794fd387f21cf50a7c4cb1a0531d5 Mon Sep 17 00:00:00 2001 From: DerAndere <26200979+DerAndere1@users.noreply.github.com> Date: Thu, 18 Dec 2025 22:05:31 +0100 Subject: [PATCH 05/14] fixup --- Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp | 18 +++++++++--------- Marlin/src/gcode/bedlevel/G42.cpp | 4 ++-- Marlin/src/gcode/motion/G0_G1.cpp | 12 ++++++------ Marlin/src/gcode/motion/G2_G3.cpp | 2 +- Marlin/src/gcode/parser.cpp | 2 +- Marlin/src/gcode/parser.h | 8 ++++---- Marlin/src/module/motion.cpp | 4 ++-- Marlin/src/module/planner.cpp | 2 +- 8 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp index d44f345e3392..d74262ad152b 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp @@ -105,7 +105,7 @@ * case - crossing only one X or Y line - after details are worked out to reduce computation. */ - const xy_float_t dist = xy_float_t(end) - xy_float_t(start); + const xy_float_t dist = end - start; const xy_bool_t neg { dist.x < 0, dist.y < 0 }; const xy_uint8_t ineg { uint8_t(neg.x), uint8_t(neg.y) }; const xy_float_t sign { neg.x ? -1.0f : 1.0f, neg.y ? -1.0f : 1.0f }; @@ -362,32 +362,32 @@ planner.buffer_line(destination, scaled_fr_mm_s); return false; // caller will update current_position } - if (!parser.process_motion_gcode) - parser.cartesian_mm = get_move_distance(total OPTARG(HAS_ROTATIONAL_AXES, parser.cartes_move)); + bool cartes_move = true; + float cartesian_mm = get_move_distance(total OPTARG(HAS_ROTATIONAL_AXES, cartes_move)); // If the move is very short, check the E move distance - TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(parser.cartesian_mm)) parser.cartesian_mm = ABS(total.e)); + TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = ABS(total.e)); // No E move either? Game over. - if (UNEAR_ZERO(parser.cartesian_mm)) return true; + if (UNEAR_ZERO(cartesian_mm)) return true; #if IS_KINEMATIC // Minimum number of seconds to move the given distance - const float seconds = parser.cartesian_mm / scaled_fr_mm_s; + const float seconds = cartesian_mm / scaled_fr_mm_s; uint16_t segments = LROUND(segments_per_second * seconds), // Preferred number of segments for distance @ feedrate - seglimit = LROUND(parser.cartesian_mm * RECIPROCAL(SEGMENT_MIN_LENGTH)); // Number of segments at minimum segment length + seglimit = LROUND(cartesian_mm * RECIPROCAL(SEGMENT_MIN_LENGTH)); // Number of segments at minimum segment length NOMORE(segments, seglimit); // Limit to minimum segment length (fewer segments) #else - uint16_t segments = LROUND(parser.cartesian_mm * RECIPROCAL(SEGMENT_MIN_LENGTH)); // Cartesian fixed segment length + uint16_t segments = LROUND(cartesian_mm * RECIPROCAL(SEGMENT_MIN_LENGTH)); // Cartesian fixed segment length #endif NOLESS(segments, 1U); // Must have at least one segment const float inv_segments = 1.0f / segments; // Reciprocal to save calculation // Add hints to help optimize the move - PlannerHints hints(parser.cartesian_mm * inv_segments); // Length of each segment + PlannerHints hints(cartesian_mm * inv_segments); // Length of each segment #if ENABLED(FEEDRATE_SCALING) hints.inv_duration = scaled_fr_mm_s / hints.millimeters; #endif diff --git a/Marlin/src/gcode/bedlevel/G42.cpp b/Marlin/src/gcode/bedlevel/G42.cpp index 308426b5b763..0621802cf6ad 100644 --- a/Marlin/src/gcode/bedlevel/G42.cpp +++ b/Marlin/src/gcode/bedlevel/G42.cpp @@ -54,7 +54,7 @@ void GcodeSuite::G42() { return; } - TERN_(FEEDRATE_MODE_SUPPORT, parser.process_motion_gcode = true); + TERN_(FEEDRATE_MODE_SUPPORT, parser.linear_motion_gcode = true); // Move to motion.position, as modified by I, J, P parameters motion.destination = motion.position; @@ -79,7 +79,7 @@ void GcodeSuite::G42() { motion.prepare_internal_move_to_destination(fr_mm_s); #endif - TERN_(FEEDRATE_MODE_SUPPORT, parser.process_motion_gcode = false); + TERN_(FEEDRATE_MODE_SUPPORT, parser.linear_motion_gcode = false); } #endif // HAS_MESH diff --git a/Marlin/src/gcode/motion/G0_G1.cpp b/Marlin/src/gcode/motion/G0_G1.cpp index d8306c4f9dfa..8b7c8e647d93 100644 --- a/Marlin/src/gcode/motion/G0_G1.cpp +++ b/Marlin/src/gcode/motion/G0_G1.cpp @@ -55,7 +55,7 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) { feedRate_t old_feedrate; #if ENABLED(VARIABLE_G0_FEEDRATE) #if ENABLED(FEEDRATE_MODE_SUPPORT) - parser.process_motion_gcode = true; + parser.linear_motion_gcode = true; #endif if (fast_move) { old_feedrate = motion.feedrate_mm_s; // Back up the (old) motion mode feedrate @@ -63,14 +63,14 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) { } #elif ENABLED(FEEDRATE_MODE_SUPPORT) if (fast_move) { - parser.process_motion_gcode = false; + parser.linear_motion_gcode = false; } else { - parser.process_motion_gcode = true; + parser.linear_motion_gcode = true; } #endif #elif ENABLED(FEEDRATE_MODE_SUPPORT) - parser.process_motion_gcode = true; + parser.linear_motion_gcode = true; #endif get_destination_from_command(); // Get X Y [Z[I[J[K]]]] [E] F (and set cutter power) @@ -78,7 +78,7 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) { #ifdef G0_FEEDRATE if (fast_move) { #if ENABLED(FEEDRATE_MODE_SUPPORT) - parser.process_motion_gcode = false; + parser.linear_motion_gcode = false; #endif #if ENABLED(VARIABLE_G0_FEEDRATE) fast_move_feedrate = motion.feedrate_mm_s; // Save feedrate for the next G0 @@ -120,7 +120,7 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) { #endif #if ENABLED(FEEDRATE_MODE_SUPPORT) - parser.process_motion_gcode = false; + parser.linear_motion_gcode = false; #endif #if ENABLED(NANODLP_Z_SYNC) diff --git a/Marlin/src/gcode/motion/G2_G3.cpp b/Marlin/src/gcode/motion/G2_G3.cpp index a627025816a3..af0812d2806e 100644 --- a/Marlin/src/gcode/motion/G2_G3.cpp +++ b/Marlin/src/gcode/motion/G2_G3.cpp @@ -429,7 +429,7 @@ void GcodeSuite::G2_G3(const bool clockwise) { TERN_(FULL_REPORT_TO_HOST_FEATURE, motion.set_and_report_grblstate(M_RUNNING)); #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) - parser.process_motion_gcode = false; + parser.linear_motion_gcode = false; #endif #if ENABLED(SF_ARC_FIX) diff --git a/Marlin/src/gcode/parser.cpp b/Marlin/src/gcode/parser.cpp index 9c5a74a8e347..760aa9324d03 100644 --- a/Marlin/src/gcode/parser.cpp +++ b/Marlin/src/gcode/parser.cpp @@ -38,7 +38,7 @@ bool GCodeParser::volumetric_enabled; #endif #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) - bool GCodeParser::process_motion_gcode; + bool GCodeParser::linear_motion_gcode; float GCodeParser::cartesian_mm; #if ENABLED(FEEDRATE_MODE_SUPPORT) bool GCodeParser::inverse_time_enabled; diff --git a/Marlin/src/gcode/parser.h b/Marlin/src/gcode/parser.h index 5b208b6d2ea2..440d8bf38063 100644 --- a/Marlin/src/gcode/parser.h +++ b/Marlin/src/gcode/parser.h @@ -78,7 +78,7 @@ class GCodeParser { #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) static float cartesian_mm; - static bool process_motion_gcode; + static bool linear_motion_gcode; #if ENABLED(FEEDRATE_MODE_SUPPORT) static bool inverse_time_enabled; #endif @@ -428,12 +428,12 @@ class GCodeParser { static feedRate_t value_feedrate() { #if HAS_ROTATIONAL_AXES || ENABLED(FEEDRATE_MODE_SUPPORT) - float fr = ((TERN0(FEEDRATE_MODE_SUPPORT, inverse_time_enabled && process_motion_gcode)) || TERN0(HAS_ROTATIONAL_AXES, (!cartes_move))) ? value_float() : value_linear_units(); + float fr = ((TERN0(FEEDRATE_MODE_SUPPORT, inverse_time_enabled && linear_motion_gcode)) || TERN0(HAS_ROTATIONAL_AXES, (!cartes_move))) ? value_float() : value_linear_units(); #if ENABLED(FEEDRATE_MODE_SUPPORT) - if (inverse_time_enabled && process_motion_gcode) + if (inverse_time_enabled && linear_motion_gcode) fr *= cartesian_mm; #endif - return fr + return fr; #else return value_linear_units(); #endif diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index f863040d8858..87c33b09267e 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -1619,7 +1619,7 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE // Fail if attempting move outside printable radius if (!can_reach(destination)) return true; - if (!parser.process_motion_gcode) + if (!parser.linear_motion_gcode) parser.cartesian_mm = motion.get_move_distance(diff OPTARG(HAS_ROTATIONAL_AXES, parser.cartes_move)); // If the move is very short, check the E move distance @@ -1702,7 +1702,7 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE } // Get the move distance - if (parser.process_motion_gcode) + if (!parser.linear_motion_gcode) parser.cartesian_mm = get_move_distance(diff OPTARG(HAS_ROTATIONAL_AXES, parser.cartes_move)); // If the move is very short, check the E move distance diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 48a282f30c6c..29f4f923f273 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -2982,7 +2982,7 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const feedRate_t fr_mm_s // Provide known Cartesian length in the hints structure PlannerHints ph = hints; if (!hints.millimeters) - ph.millimeters = motion.get_move_distance(xyze_pos_t(cart_dist_mm) OPTARG(HAS_ROTATIONAL_AXES, parser.cartesian_move)); + ph.millimeters = motion.get_move_distance(xyze_pos_t(cart_dist_mm) OPTARG(HAS_ROTATIONAL_AXES, parser.cartes_move)); #if DISABLED(FEEDRATE_SCALING) From d26bd312f969305cc11cd10daa1674495cc85e00 Mon Sep 17 00:00:00 2001 From: DerAndere <26200979+DerAndere1@users.noreply.github.com> Date: Sat, 27 Dec 2025 23:38:48 +0100 Subject: [PATCH 06/14] cleanup --- Marlin/src/feature/bedlevel/abl/bbl.cpp | 4 +--- .../src/feature/bedlevel/mbl/mesh_bed_leveling.cpp | 12 ++++-------- Marlin/src/gcode/bedlevel/G42.cpp | 2 +- Marlin/src/gcode/motion/G5.cpp | 1 + 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/Marlin/src/feature/bedlevel/abl/bbl.cpp b/Marlin/src/feature/bedlevel/abl/bbl.cpp index 6b2d1fe4abb4..545af97f8eab 100644 --- a/Marlin/src/feature/bedlevel/abl/bbl.cpp +++ b/Marlin/src/feature/bedlevel/abl/bbl.cpp @@ -422,8 +422,7 @@ float LevelingBilinear::get_z_correction(const xy_pos_t &raw) { // Must already have been split on these border(s) // This should be a rare case. motion.position = motion.destination; - motion.line_to_current_position(scaled_fr_mm_s); - parser.inverse_time_enabled = old_inverse_time_enabled; + motion.goto_current_position(scaled_fr_mm_s); return; } @@ -436,7 +435,6 @@ float LevelingBilinear::get_z_correction(const xy_pos_t &raw) { // Restore destination from stack motion.destination = end; line_to_destination(scaled_fr_mm_s, x_splits, y_splits); - parser.inverse_time_enabled = old_inverse_time_enabled; } #endif // IS_CARTESIAN && !SEGMENT_LEVELED_MOVES diff --git a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp index 1f462fd2f91f..5ad04a3e3adb 100644 --- a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp +++ b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp @@ -71,15 +71,11 @@ void mesh_bed_leveling::line_to_destination(const feedRate_t scaled_fr_mm_s, uint8_t x_splits, uint8_t y_splits) { // Get current and destination cells for this line xy_uint8_t scel = cell_indexes(motion.position), ecel = cell_indexes(motion.destination); - - segments = ecel - scel; - NOLESS(segments, 1); - // Start and end in the same cell? No split needed. if (scel == ecel) { motion.position = motion.destination; - motion.line_to_current_position(scaled_fr_mm_s); + motion.goto_current_position(scaled_fr_mm_s); return; } @@ -112,7 +108,7 @@ // Must already have been split on these border(s) // This should be a rare case. motion.position = motion.destination; - motion.line_to_current_position(segment_fr); + motion.goto_current_position(scaled_fr_mm_s); return; } @@ -120,11 +116,11 @@ motion.destination.e = MBL_SEGMENT_END(e); // Do the split and look for more borders - line_to_destination(segment_fr, x_splits, y_splits); + line_to_destination(scaled_fr_mm_s, x_splits, y_splits); // Restore destination from stack motion.destination = dest; - line_to_destination(segment_fr, x_splits, y_splits); + motion.line_to_destination(scaled_fr_mm_s, x_splits, y_splits); } #endif // IS_CARTESIAN && !SEGMENT_LEVELED_MOVES diff --git a/Marlin/src/gcode/bedlevel/G42.cpp b/Marlin/src/gcode/bedlevel/G42.cpp index 0621802cf6ad..54ddd90f9212 100644 --- a/Marlin/src/gcode/bedlevel/G42.cpp +++ b/Marlin/src/gcode/bedlevel/G42.cpp @@ -70,7 +70,7 @@ void GcodeSuite::G42() { #endif const feedRate_t fval = parser.feedrateval('F'), - fr_mm_s = MMM_TO_MMS(fval); + fr_mm_s = MMM_TO_MMS(fval > 0 ? fval : 0.0f); // SCARA kinematic has "safe" XY raw moves #if IS_SCARA diff --git a/Marlin/src/gcode/motion/G5.cpp b/Marlin/src/gcode/motion/G5.cpp index d625b2538184..528ef86913b5 100644 --- a/Marlin/src/gcode/motion/G5.cpp +++ b/Marlin/src/gcode/motion/G5.cpp @@ -52,6 +52,7 @@ void GcodeSuite::G5() { return; } #endif + get_destination_from_command(); const xy_pos_t offsets[2] = { From 61ba202095128da2d02bbf80c7ee77d8e9c6882c Mon Sep 17 00:00:00 2001 From: DerAndere <26200979+DerAndere1@users.noreply.github.com> Date: Sun, 15 Mar 2026 14:17:36 +0100 Subject: [PATCH 07/14] fixup --- Marlin/src/gcode/gcode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index cadb411174ca..32ee47e3c0aa 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -200,9 +200,9 @@ void GcodeSuite::get_destination_from_command() { #endif #if HAS_ROTATIONAL_AXES || IS_KINEMATIC || HAS_LEVELING || ENABLED(FEEDRATE_MODE_SUPPORT) - const xyze_pos_t displacement = destination - current_position; + const xyze_pos_t displacement = motion.destination - motion.position; - parser.cartesian_mm = get_move_distance(displacement OPTARG(HAS_ROTATIONAL_AXES, parser.cartes_move)); + parser.cartesian_mm = motion.get_move_distance(displacement OPTARG(HAS_ROTATIONAL_AXES, parser.cartes_move)); #if HAS_EXTRUDERS if (NEAR_ZERO(parser.cartesian_mm)) { From 77852e39b0207c151bd0275c72aaacf48464add3 Mon Sep 17 00:00:00 2001 From: DerAndere <26200979+DerAndere1@users.noreply.github.com> Date: Sun, 15 Mar 2026 14:32:24 +0100 Subject: [PATCH 08/14] fixup --- Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp index d74262ad152b..ecff6fe82ba7 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp @@ -359,13 +359,13 @@ // If the move is only in Z/E don't split up the move if (!total.x && !total.y) { - planner.buffer_line(destination, scaled_fr_mm_s); + planner.buffer_line(motion.destination, scaled_fr_mm_s); return false; // caller will update current_position } bool cartes_move = true; - float cartesian_mm = get_move_distance(total OPTARG(HAS_ROTATIONAL_AXES, cartes_move)); + float cartesian_mm = motion.get_move_distance(total OPTARG(HAS_ROTATIONAL_AXES, cartes_move)); - // If the move is very short, check the E move distance + // If the move is very short, check the E move distance TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = ABS(total.e)); // No E move either? Game over. From 272091993dea5f2fff02ae613a2420151276220f Mon Sep 17 00:00:00 2001 From: DerAndere <26200979+DerAndere1@users.noreply.github.com> Date: Sun, 15 Mar 2026 14:55:34 +0100 Subject: [PATCH 09/14] modify feedrate mode --- Marlin/src/module/motion.cpp | 24 +++++++++++++++--------- Marlin/src/module/planner.cpp | 5 ++++- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 87c33b09267e..e84e80484637 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -1619,17 +1619,21 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE // Fail if attempting move outside printable radius if (!can_reach(destination)) return true; + #if HAS_ROTATIONAL_AXES + bool cartesian_move = true; + #endif + float cartesian_mm = parser.cartesian_mm; if (!parser.linear_motion_gcode) - parser.cartesian_mm = motion.get_move_distance(diff OPTARG(HAS_ROTATIONAL_AXES, parser.cartes_move)); + cartesian_mm = motion.get_move_distance(diff OPTARG(HAS_ROTATIONAL_AXES, cartesian_move)); // If the move is very short, check the E move distance - TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(parser.cartesian_mm)) parser.cartesian_mm = ABS(diff.e)); + TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = ABS(diff.e)); // No E move either? Game over. - if (UNEAR_ZERO(parser.cartesian_mm)) return true; + if (UNEAR_ZERO(cartesian_mm)) return true; // Minimum number of seconds to move the given distance - const float seconds = parser.cartesian_mm / scaled_fr_mm_s; + const float seconds = cartesian_mm / scaled_fr_mm_s; // The number of segments-per-second times the duration // gives the number of segments @@ -1637,9 +1641,9 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE // For SCARA enforce a minimum segment size #if IS_SCARA - NOMORE(segments, parser.cartesian_mm * RECIPROCAL(SCARA_MIN_SEGMENT_LENGTH)); + NOMORE(segments, cartesian_mm * RECIPROCAL(SCARA_MIN_SEGMENT_LENGTH)); #elif ENABLED(POLAR) - NOMORE(segments, parser.cartesian_mm * RECIPROCAL(POLAR_MIN_SEGMENT_LENGTH)); + NOMORE(segments, cartesian_mm * RECIPROCAL(POLAR_MIN_SEGMENT_LENGTH)); #endif // At least one segment is required @@ -1650,7 +1654,7 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE const xyze_float_t segment_distance = diff * inv_segments; // Add hints to help optimize the move - PlannerHints hints(parser.cartesian_mm * inv_segments); + PlannerHints hints(cartesian_mm * inv_segments); #if ENABLED(FEEDRATE_SCALING) hints.inv_duration = scaled_fr_mm_s / hints.millimeters; #endif @@ -1700,10 +1704,12 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE planner.buffer_line(destination, fr_mm_s); return; } - + #if HAS_ROTATIONAL_AXES + cartesian_move = true; + #endif // Get the move distance if (!parser.linear_motion_gcode) - parser.cartesian_mm = get_move_distance(diff OPTARG(HAS_ROTATIONAL_AXES, parser.cartes_move)); + parser.cartesian_mm = get_move_distance(diff OPTARG(HAS_ROTATIONAL_AXES, cartesian_move)); // If the move is very short, check the E move distance TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(parser.cartesian_mm)) parser.cartesian_mm = ABS(diff.e)); diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 29f4f923f273..23a0f14c3fd9 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -2979,10 +2979,13 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const feedRate_t fr_mm_s // Cartesian XYZ to kinematic ABC, stored in global 'delta' inverse_kinematics(machine); + #if HAS_ROTATIONAL_AXES + bool cartesian_move; + #endif // Provide known Cartesian length in the hints structure PlannerHints ph = hints; if (!hints.millimeters) - ph.millimeters = motion.get_move_distance(xyze_pos_t(cart_dist_mm) OPTARG(HAS_ROTATIONAL_AXES, parser.cartes_move)); + ph.millimeters = motion.get_move_distance(xyze_pos_t(cart_dist_mm) OPTARG(HAS_ROTATIONAL_AXES, cartesian_move)); #if DISABLED(FEEDRATE_SCALING) From af8bbb0542a8b47e42ec78404da8644185c72e06 Mon Sep 17 00:00:00 2001 From: DerAndere <26200979+DerAndere1@users.noreply.github.com> Date: Mon, 16 Mar 2026 03:01:29 +0100 Subject: [PATCH 10/14] improve --- Marlin/src/module/motion.cpp | 13 +++++++------ Marlin/src/module/planner.cpp | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index e84e80484637..2b8a04105c99 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -1705,21 +1705,22 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE return; } #if HAS_ROTATIONAL_AXES - cartesian_move = true; + xyze_pos_t cartesian_mm; + bool cartesian_move = true; #endif // Get the move distance if (!parser.linear_motion_gcode) - parser.cartesian_mm = get_move_distance(diff OPTARG(HAS_ROTATIONAL_AXES, cartesian_move)); + cartesian_mm = get_move_distance(diff OPTARG(HAS_ROTATIONAL_AXES, cartesian_move)); // If the move is very short, check the E move distance - TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(parser.cartesian_mm)) parser.cartesian_mm = ABS(diff.e)); + TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = ABS(diff.e)); // No E move either? Game over. - if (UNEAR_ZERO(parser.cartesian_mm)) return; + if (UNEAR_ZERO(cartesian_mm)) return; // The length divided by the segment size // At least one segment is required - uint16_t segments = parser.cartesian_mm / segment_size; + uint16_t segments = cartesian_mm / segment_size; NOLESS(segments, 1U); // The approximate length of each segment @@ -1727,7 +1728,7 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE const xyze_float_t segment_distance = diff * inv_segments; // Add hints to help optimize the move - PlannerHints hints(parser.cartesian_mm * inv_segments); + PlannerHints hints(cartesian_mm * inv_segments); TERN_(FEEDRATE_SCALING, hints.inv_duration = scaled_fr_mm_s / hints.millimeters); //SERIAL_ECHOPGM("mm=", cartesian_mm); //SERIAL_ECHOLNPGM(" segments=", segments); diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 23a0f14c3fd9..5f57d4d23ed8 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -2043,7 +2043,7 @@ bool Planner::_populate_block( dist_mm.u, dist_mm.v, dist_mm.w ); - block->millimeters = motion.get_move_distance(displacement OPTARG(HAS_ROTATIONAL_AXES, parser.cartes_move)); + block->millimeters = motion.get_move_distance(displacement OPTARG(HAS_ROTATIONAL_AXES, cartesian_move)); } /** From 63ce25878c69b9991cd6ce42d858a7a22d56e477 Mon Sep 17 00:00:00 2001 From: DerAndere <26200979+DerAndere1@users.noreply.github.com> Date: Mon, 16 Mar 2026 02:44:44 +0100 Subject: [PATCH 11/14] Fixup --- Marlin/src/feature/e_parser.cpp | 2 +- Marlin/src/inc/SanityCheck.h | 4 ++-- Marlin/src/module/stepper.cpp | 4 +--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Marlin/src/feature/e_parser.cpp b/Marlin/src/feature/e_parser.cpp index 0e0bbc17527c..e31ce9a295da 100644 --- a/Marlin/src/feature/e_parser.cpp +++ b/Marlin/src/feature/e_parser.cpp @@ -224,7 +224,7 @@ void EmergencyParser::update(EmergencyParser::State &state, const uint8_t c) { #endif #if ENABLED(REALTIME_REPORTING_COMMANDS) case EP_GRBL_STATUS: motion.report_position_moving(); break; - case EP_GRBL_PAUSE: TERN(SOFT_FEED_HOLD, realtime_ramping_pause_flag = true, motion.quickpause_stepper()); break; + case EP_GRBL_PAUSE: TERN(SOFT_FEED_HOLD, realtime_ramping_pause_flag = true, motion.quickpause_stepper()); break; case EP_GRBL_RESUME: TERN(SOFT_FEED_HOLD, realtime_ramping_pause_flag = false, motion.quickresume_stepper()); break; #endif #if ENABLED(SOFT_RESET_VIA_SERIAL) diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 77df0d8863c1..0c1e041baebb 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -583,8 +583,8 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L #error "SOFT_FEED_HOLD requires FREEZE_JERK." #elif ENABLED(FREEZE_FEATURE) && DISABLED(NO_FREEZE_PIN) && !(defined(FREEZE_PIN) && defined(FREEZE_STATE)) #error "FREEZE_FEATURE requires FREEZE_PIN and FREEZE_STATE." -#elif ENABLED(NO_FREEZE_PIN) && !(defined(REALTIME_REPORTING_COMMANDS)) - #error "NO_FREEZE_PIN requires REALTIME_REPORTING_COMMANDS." +#elif ENABLED(REALTIME_REPORTING_COMMANDS) && DISABLED(EMERGENCY_PARSER) + #error "REALTIME_REPORTING_COMMANDS requires EMERGENCY_PARSER." #endif /** diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index b92d8981577b..c9c2e4e71bdb 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -3921,9 +3921,7 @@ void Stepper::report_positions() { cutter.apply_power(frozen_last_laser_power); // Restore frozen laser power #endif - #if ENABLED(REALTIME_REPORTING_COMMANDS) - set_and_report_grblstate(state ? M_HOLD : M_RUNNING); - #endif + TERN_(FULL_REPORT_TO_HOST_FEATURE, motion.set_and_report_grblstate(state ? M_HOLD : M_RUNNING)); } void Stepper::check_frozen_time(uint32_t &step_rate) { From fedb4b8050159108c7c3b09aba38c61af6e4e94d Mon Sep 17 00:00:00 2001 From: DerAndere <26200979+DerAndere1@users.noreply.github.com> Date: Mon, 16 Mar 2026 03:55:36 +0100 Subject: [PATCH 12/14] fiixup feedrate mode --- Marlin/src/module/motion.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 2b8a04105c99..5161241013de 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -1705,9 +1705,9 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE return; } #if HAS_ROTATIONAL_AXES - xyze_pos_t cartesian_mm; bool cartesian_move = true; #endif + float cartesian_mm; // Get the move distance if (!parser.linear_motion_gcode) cartesian_mm = get_move_distance(diff OPTARG(HAS_ROTATIONAL_AXES, cartesian_move)); From adf4035ef10bed0be520e3de68859638c1132dc3 Mon Sep 17 00:00:00 2001 From: DerAndere <26200979+DerAndere1@users.noreply.github.com> Date: Mon, 16 Mar 2026 04:09:38 +0100 Subject: [PATCH 13/14] remove snity check --- Marlin/src/inc/SanityCheck.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 0c1e041baebb..a160fc2de718 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -583,8 +583,6 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L #error "SOFT_FEED_HOLD requires FREEZE_JERK." #elif ENABLED(FREEZE_FEATURE) && DISABLED(NO_FREEZE_PIN) && !(defined(FREEZE_PIN) && defined(FREEZE_STATE)) #error "FREEZE_FEATURE requires FREEZE_PIN and FREEZE_STATE." -#elif ENABLED(REALTIME_REPORTING_COMMANDS) && DISABLED(EMERGENCY_PARSER) - #error "REALTIME_REPORTING_COMMANDS requires EMERGENCY_PARSER." #endif /** From 388e5d2b64a980dd97c8523bcae3c62bbf4657cc Mon Sep 17 00:00:00 2001 From: DerAndere <26200979+DerAndere1@users.noreply.github.com> Date: Mon, 16 Mar 2026 22:38:06 +0100 Subject: [PATCH 14/14] Cleanup --- Marlin/src/MarlinCore.cpp | 7 ++++-- .../bedlevel/mbl/mesh_bed_leveling.cpp | 6 ++--- .../src/feature/bedlevel/ubl/ubl_motion.cpp | 4 +++- Marlin/src/feature/e_parser.cpp | 2 +- Marlin/src/gcode/motion/G5.cpp | 1 - Marlin/src/inc/SanityCheck.h | 2 +- Marlin/src/module/motion.cpp | 22 ++++++++++++------- Marlin/src/module/planner.cpp | 4 ++-- 8 files changed, 29 insertions(+), 19 deletions(-) diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index 3aa430db20ec..06cfd41c7268 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -1231,7 +1231,7 @@ void setup() { #endif #endif - #if ENABLED(FREEZE_FEATURE) && DISABLED(NO_FREEZE_PIN) + #if ENABLED(FREEZE_FEATURE) SETUP_LOG("FREEZE_PIN"); #if FREEZE_STATE SET_INPUT_PULLDOWN(FREEZE_PIN); @@ -1334,7 +1334,10 @@ void setup() { #endif SERIAL_ECHO_MSG(" Compiled: " __DATE__); SERIAL_ECHO_MSG(STR_FREE_MEMORY, hal.freeMemory(), STR_PLANNER_BUFFER_BYTES, sizeof(block_t) * (BLOCK_BUFFER_SIZE)); - + + #if HAS_ROTATIONAL_AXES + parser.cartes_move = true; + #endif // Some HAL need precise delay adjustment calibrate_delay_loop(); diff --git a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp index 5ad04a3e3adb..90bb162849f1 100644 --- a/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp +++ b/Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp @@ -74,8 +74,8 @@ // Start and end in the same cell? No split needed. if (scel == ecel) { - motion.position = motion.destination; - motion.goto_current_position(scaled_fr_mm_s); + motion.position = motion.destination; + motion.goto_current_position(scaled_fr_mm_s); return; } @@ -120,7 +120,7 @@ // Restore destination from stack motion.destination = dest; - motion.line_to_destination(scaled_fr_mm_s, x_splits, y_splits); + line_to_destination(scaled_fr_mm_s, x_splits, y_splits); } #endif // IS_CARTESIAN && !SEGMENT_LEVELED_MOVES diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp index ecff6fe82ba7..851ad4df99a9 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp @@ -362,7 +362,9 @@ planner.buffer_line(motion.destination, scaled_fr_mm_s); return false; // caller will update current_position } - bool cartes_move = true; + #if HAS_ROTATIONAL_AXES + bool cartes_move = true; + #endif float cartesian_mm = motion.get_move_distance(total OPTARG(HAS_ROTATIONAL_AXES, cartes_move)); // If the move is very short, check the E move distance diff --git a/Marlin/src/feature/e_parser.cpp b/Marlin/src/feature/e_parser.cpp index e31ce9a295da..0e0bbc17527c 100644 --- a/Marlin/src/feature/e_parser.cpp +++ b/Marlin/src/feature/e_parser.cpp @@ -224,7 +224,7 @@ void EmergencyParser::update(EmergencyParser::State &state, const uint8_t c) { #endif #if ENABLED(REALTIME_REPORTING_COMMANDS) case EP_GRBL_STATUS: motion.report_position_moving(); break; - case EP_GRBL_PAUSE: TERN(SOFT_FEED_HOLD, realtime_ramping_pause_flag = true, motion.quickpause_stepper()); break; + case EP_GRBL_PAUSE: TERN(SOFT_FEED_HOLD, realtime_ramping_pause_flag = true, motion.quickpause_stepper()); break; case EP_GRBL_RESUME: TERN(SOFT_FEED_HOLD, realtime_ramping_pause_flag = false, motion.quickresume_stepper()); break; #endif #if ENABLED(SOFT_RESET_VIA_SERIAL) diff --git a/Marlin/src/gcode/motion/G5.cpp b/Marlin/src/gcode/motion/G5.cpp index 528ef86913b5..6ffb65b95941 100644 --- a/Marlin/src/gcode/motion/G5.cpp +++ b/Marlin/src/gcode/motion/G5.cpp @@ -62,7 +62,6 @@ void GcodeSuite::G5() { cubic_b_spline(motion.position, motion.destination, offsets, motion.mms_scaled(), motion.extruder); motion.position = motion.destination; - } #endif // BEZIER_CURVE_SUPPORT diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index a160fc2de718..4611c3953195 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -581,7 +581,7 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L */ #if ENABLED(SOFT_FEED_HOLD) && !defined(FREEZE_JERK) #error "SOFT_FEED_HOLD requires FREEZE_JERK." -#elif ENABLED(FREEZE_FEATURE) && DISABLED(NO_FREEZE_PIN) && !(defined(FREEZE_PIN) && defined(FREEZE_STATE)) +#elif ENABLED(FREEZE_FEATURE) && !(defined(FREEZE_PIN) && defined(FREEZE_STATE)) #error "FREEZE_FEATURE requires FREEZE_PIN and FREEZE_STATE." #endif diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 5161241013de..519d0712514b 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -167,7 +167,6 @@ xyz_pos_t Motion::cartes; #ifndef DEFAULT_FEEDRATE_MM_M #define DEFAULT_FEEDRATE_MM_M 4000 #endif - feedRate_t Motion::feedrate_mm_s = MMM_TO_MMS(DEFAULT_FEEDRATE_MM_M); int16_t Motion::feedrate_percentage = 100; @@ -1545,16 +1544,23 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE #endif #if HAS_ROTATIONAL_AXES + if (UNEAR_ZERO(distance_sqr)) { // Move involves no linear axes. Calculate angular distance in accordance with LinuxCNC distance_sqr = ROTATIONAL_AXIS_GANG(sq(diff.i), + sq(diff.j), + sq(diff.k), + sq(diff.u), + sq(diff.v), + sq(diff.w)); + if (!UNEAR_ZERO(distance_sqr)) { + // Move involves rotational axes, not just the extruder + is_cartesian_move = false; + } + else { + // Move involves just the extruder + is_cartesian_move = true; + } } - if (!UNEAR_ZERO(distance_sqr)) { - // Move involves rotational axes, not just the extruder - is_cartesian_move = false; + else { + is_cartesian_move = true; } #endif - #endif return SQRT(distance_sqr); @@ -1704,13 +1710,12 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE planner.buffer_line(destination, fr_mm_s); return; } + #if HAS_ROTATIONAL_AXES bool cartesian_move = true; #endif - float cartesian_mm; // Get the move distance - if (!parser.linear_motion_gcode) - cartesian_mm = get_move_distance(diff OPTARG(HAS_ROTATIONAL_AXES, cartesian_move)); + float cartesian_mm = get_move_distance(diff OPTARG(HAS_ROTATIONAL_AXES, cartesian_move)); // If the move is very short, check the E move distance TERN_(HAS_EXTRUDERS, if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = ABS(diff.e)); @@ -1730,6 +1735,7 @@ float Motion::get_move_distance(const xyze_pos_t &diff OPTARG(HAS_ROTATIONAL_AXE // Add hints to help optimize the move PlannerHints hints(cartesian_mm * inv_segments); TERN_(FEEDRATE_SCALING, hints.inv_duration = scaled_fr_mm_s / hints.millimeters); + //SERIAL_ECHOPGM("mm=", cartesian_mm); //SERIAL_ECHOLNPGM(" segments=", segments); //SERIAL_ECHOLNPGM(" segment_mm=", hints.millimeters); diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 5f57d4d23ed8..a7021955517e 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -2022,7 +2022,7 @@ bool Planner::_populate_block( TERN_(FT_MOTION, block->ext_distance_mm = dist_mm); // Store the distance for all axes in mm for this block #if HAS_ROTATIONAL_AXES - bool cartesian_move; + bool cartesian_move = true; #endif // Determine linear distance for block->millimeters @@ -2980,7 +2980,7 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const feedRate_t fr_mm_s inverse_kinematics(machine); #if HAS_ROTATIONAL_AXES - bool cartesian_move; + bool cartesian_move = true; #endif // Provide known Cartesian length in the hints structure PlannerHints ph = hints;