From 361268bf479937725a650ff09269a0c24be5cdb2 Mon Sep 17 00:00:00 2001 From: Tom Brazier Date: Sat, 18 Jun 2022 16:53:28 +0100 Subject: [PATCH 01/18] sqrt() is a lot cheaper than cos() or sin() --- Marlin/src/gcode/motion/G2_G3.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Marlin/src/gcode/motion/G2_G3.cpp b/Marlin/src/gcode/motion/G2_G3.cpp index cd8225de6902..ed2b038dc108 100644 --- a/Marlin/src/gcode/motion/G2_G3.cpp +++ b/Marlin/src/gcode/motion/G2_G3.cpp @@ -315,7 +315,10 @@ void plan_arc( // Compute exact location by applying transformation matrix from initial radius vector(=-offset). // To reduce stuttering, the sin and cos could be computed at different times. // For now, compute both at the same time. - const float cos_Ti = cos(i * theta_per_segment), sin_Ti = sin(i * theta_per_segment); + const float angle = i * theta_per_segment, + cos_Ti = cos(angle), + abs_sin_Ti = SQRT(1 - cos_Ti * cos_Ti), + sin_Ti = angle > M_PI || (angle < 0.0f && angle > -M_PI) ? -abs_sin_Ti : abs_sin_Ti; rvec.a = -offset[0] * cos_Ti + offset[1] * sin_Ti; rvec.b = -offset[0] * sin_Ti - offset[1] * cos_Ti; } From 6b46561d6e492f7e25f3544a6f4992297df6626e Mon Sep 17 00:00:00 2001 From: Tom Brazier Date: Sat, 18 Jun 2022 21:21:06 +0100 Subject: [PATCH 02/18] Use known arc radius to save time in the junction deviation code --- Marlin/Configuration_adv.h | 3 + Marlin/src/gcode/motion/G2_G3.cpp | 5 +- Marlin/src/module/planner.cpp | 209 ++++++++++++++++-------------- Marlin/src/module/planner.h | 4 + 4 files changed, 122 insertions(+), 99 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 96a3e04d0b77..8396257bb0bf 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2193,6 +2193,9 @@ #define N_ARC_CORRECTION 25 // Number of interpolated segments between corrections //#define ARC_P_CIRCLES // Enable the 'P' parameter to specify complete circles //#define SF_ARC_FIX // Enable only if using SkeinForge with "Arc Point" fillet procedure + #if HAS_JUNCTION_DEVIATION + #define ARC_ASSISTED_JD // Pass the arc radius to the junction deviation code to save processor cycles + #endif #endif // G5 Bézier Curve Support with XYZE destination and IJPQ offsets diff --git a/Marlin/src/gcode/motion/G2_G3.cpp b/Marlin/src/gcode/motion/G2_G3.cpp index ed2b038dc108..aaf69a5e6b20 100644 --- a/Marlin/src/gcode/motion/G2_G3.cpp +++ b/Marlin/src/gcode/motion/G2_G3.cpp @@ -345,7 +345,10 @@ void plan_arc( planner.apply_leveling(raw); #endif - if (!planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, 0 OPTARG(SCARA_FEEDRATE_SCALING, inv_duration))) + if (!planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, 0 + OPTARG(SCARA_FEEDRATE_SCALING, inv_duration) + OPTARG(ARC_ASSISTED_JD, i > 1 ? radius : 0.0) + )) break; } } diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 6aa363890e44..5bd0af9da324 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -1783,6 +1783,7 @@ bool Planner::_buffer_steps(const xyze_long_t &target OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters + OPTARG(ARC_ASSISTED_JD, const_float_t arc_radius/*=0.0*/) ) { // Wait for the next available block @@ -1799,6 +1800,7 @@ bool Planner::_buffer_steps(const xyze_long_t &target OPTARG(HAS_POSITION_FLOAT, target_float) OPTARG(HAS_DIST_MM_ARG, cart_dist_mm) , fr_mm_s, extruder, millimeters + OPTARG(ARC_ASSISTED_JD, arc_radius) )) { // Movement was not queued, probably because it was too short. // Simply accept that as movement queued and done @@ -1841,6 +1843,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters/*=0.0*/ + OPTARG(ARC_ASSISTED_JD, const_float_t arc_radius/*=0.0*/) ) { int32_t LOGICAL_AXIS_LIST( de = target.e - position.e, @@ -2647,104 +2650,111 @@ bool Planner::_populate_block(block_t * const block, bool split_move, vmax_junction_sqr = sq(float(MINIMUM_PLANNER_SPEED)); } else { - NOLESS(junction_cos_theta, -0.999999f); // Check for numerical round-off to avoid divide by zero. - // Convert delta vector to unit vector xyze_float_t junction_unit_vec = unit_vec - prev_unit_vec; normalize_junction_vector(junction_unit_vec); + const float junction_acceleration = limit_value_by_axis_maximum(block->acceleration, junction_unit_vec); - const float junction_acceleration = limit_value_by_axis_maximum(block->acceleration, junction_unit_vec), - sin_theta_d2 = SQRT(0.5f * (1.0f - junction_cos_theta)); // Trig half angle identity. Always positive. - - vmax_junction_sqr = junction_acceleration * junction_deviation_mm * sin_theta_d2 / (1.0f - sin_theta_d2); - - #if ENABLED(JD_HANDLE_SMALL_SEGMENTS) - - // For small moves with >135° junction (octagon) find speed for approximate arc - if (block->millimeters < 1 && junction_cos_theta < -0.7071067812f) { - - #if ENABLED(JD_USE_MATH_ACOS) - - #error "TODO: Inline maths with the MCU / FPU." - - #elif ENABLED(JD_USE_LOOKUP_TABLE) - - // Fast acos approximation (max. error +-0.01 rads) - // Based on LUT table and linear interpolation - - /** - * // Generate the JD Lookup Table - * constexpr float c = 1.00751495f; // Correction factor to center error around 0 - * for (int i = 0; i < jd_lut_count - 1; ++i) { - * const float x0 = (sq(i) - 1) / sq(i), - * y0 = acos(x0) * (i == 0 ? 1 : c), - * x1 = i < jd_lut_count - 1 ? 0.5 * x0 + 0.5 : 0.999999f, - * y1 = acos(x1) * (i < jd_lut_count - 1 ? c : 1); - * jd_lut_k[i] = (y0 - y1) / (x0 - x1); - * jd_lut_b[i] = (y1 * x0 - y0 * x1) / (x0 - x1); - * } - * - * // Compute correction factor (Set c to 1.0f first!) - * float min = INFINITY, max = -min; - * for (float t = 0; t <= 1; t += 0.0003f) { - * const float e = acos(t) / approx(t); - * if (isfinite(e)) { - * if (e < min) min = e; - * if (e > max) max = e; - * } - * } - * fprintf(stderr, "%.9gf, ", (min + max) / 2); - */ - static constexpr int16_t jd_lut_count = 16; - static constexpr uint16_t jd_lut_tll = _BV(jd_lut_count - 1); - static constexpr int16_t jd_lut_tll0 = __builtin_clz(jd_lut_tll) + 1; // i.e., 16 - jd_lut_count + 1 - static constexpr float jd_lut_k[jd_lut_count] PROGMEM = { - -1.03145837f, -1.30760646f, -1.75205851f, -2.41705704f, - -3.37769222f, -4.74888992f, -6.69649887f, -9.45661736f, - -13.3640480f, -18.8928222f, -26.7136841f, -37.7754593f, - -53.4201813f, -75.5458374f, -106.836761f, -218.532821f }; - static constexpr float jd_lut_b[jd_lut_count] PROGMEM = { - 1.57079637f, 1.70887053f, 2.04220939f, 2.62408352f, - 3.52467871f, 4.85302639f, 6.77020454f, 9.50875854f, - 13.4009285f, 18.9188995f, 26.7321243f, 37.7885055f, - 53.4293975f, 75.5523529f, 106.841369f, 218.534011f }; - - const float neg = junction_cos_theta < 0 ? -1 : 1, - t = neg * junction_cos_theta; - - const int16_t idx = (t < 0.00000003f) ? 0 : __builtin_clz(uint16_t((1.0f - t) * jd_lut_tll)) - jd_lut_tll0; - - float junction_theta = t * pgm_read_float(&jd_lut_k[idx]) + pgm_read_float(&jd_lut_b[idx]); - if (neg > 0) junction_theta = RADIANS(180) - junction_theta; // acos(-t) - - #else - - // Fast acos(-t) approximation (max. error +-0.033rad = 1.89°) - // Based on MinMax polynomial published by W. Randolph Franklin, see - // https://wrf.ecse.rpi.edu/Research/Short_Notes/arcsin/onlyelem.html - // acos( t) = pi / 2 - asin(x) - // acos(-t) = pi - acos(t) ... pi / 2 + asin(x) - - const float neg = junction_cos_theta < 0 ? -1 : 1, - t = neg * junction_cos_theta, - asinx = 0.032843707f - + t * (-1.451838349f - + t * ( 29.66153956f - + t * (-131.1123477f - + t * ( 262.8130562f - + t * (-242.7199627f - + t * ( 84.31466202f ) ))))), - junction_theta = RADIANS(90) + neg * asinx; // acos(-t) - - // NOTE: junction_theta bottoms out at 0.033 which avoids divide by 0. - - #endif - - const float limit_sqr = (block->millimeters * junction_acceleration) / junction_theta; - NOMORE(vmax_junction_sqr, limit_sqr); - } - - #endif // JD_HANDLE_SMALL_SEGMENTS + #if ENABLED(ARC_ASSISTED_JD) + if (arc_radius > 0.0) + vmax_junction_sqr = junction_acceleration * arc_radius; + else + #endif + { + NOLESS(junction_cos_theta, -0.999999f); // Check for numerical round-off to avoid divide by zero. + + const float sin_theta_d2 = SQRT(0.5f * (1.0f - junction_cos_theta)); // Trig half angle identity. Always positive. + + vmax_junction_sqr = junction_acceleration * junction_deviation_mm * sin_theta_d2 / (1.0f - sin_theta_d2); + + #if ENABLED(JD_HANDLE_SMALL_SEGMENTS) + + // For small moves with >135° junction (octagon) find speed for approximate arc + if (block->millimeters < 1 && junction_cos_theta < -0.7071067812f) { + + #if ENABLED(JD_USE_MATH_ACOS) + + #error "TODO: Inline maths with the MCU / FPU." + + #elif ENABLED(JD_USE_LOOKUP_TABLE) + + // Fast acos approximation (max. error +-0.01 rads) + // Based on LUT table and linear interpolation + + /** + * // Generate the JD Lookup Table + * constexpr float c = 1.00751495f; // Correction factor to center error around 0 + * for (int i = 0; i < jd_lut_count - 1; ++i) { + * const float x0 = (sq(i) - 1) / sq(i), + * y0 = acos(x0) * (i == 0 ? 1 : c), + * x1 = i < jd_lut_count - 1 ? 0.5 * x0 + 0.5 : 0.999999f, + * y1 = acos(x1) * (i < jd_lut_count - 1 ? c : 1); + * jd_lut_k[i] = (y0 - y1) / (x0 - x1); + * jd_lut_b[i] = (y1 * x0 - y0 * x1) / (x0 - x1); + * } + * + * // Compute correction factor (Set c to 1.0f first!) + * float min = INFINITY, max = -min; + * for (float t = 0; t <= 1; t += 0.0003f) { + * const float e = acos(t) / approx(t); + * if (isfinite(e)) { + * if (e < min) min = e; + * if (e > max) max = e; + * } + * } + * fprintf(stderr, "%.9gf, ", (min + max) / 2); + */ + static constexpr int16_t jd_lut_count = 16; + static constexpr uint16_t jd_lut_tll = _BV(jd_lut_count - 1); + static constexpr int16_t jd_lut_tll0 = __builtin_clz(jd_lut_tll) + 1; // i.e., 16 - jd_lut_count + 1 + static constexpr float jd_lut_k[jd_lut_count] PROGMEM = { + -1.03145837f, -1.30760646f, -1.75205851f, -2.41705704f, + -3.37769222f, -4.74888992f, -6.69649887f, -9.45661736f, + -13.3640480f, -18.8928222f, -26.7136841f, -37.7754593f, + -53.4201813f, -75.5458374f, -106.836761f, -218.532821f }; + static constexpr float jd_lut_b[jd_lut_count] PROGMEM = { + 1.57079637f, 1.70887053f, 2.04220939f, 2.62408352f, + 3.52467871f, 4.85302639f, 6.77020454f, 9.50875854f, + 13.4009285f, 18.9188995f, 26.7321243f, 37.7885055f, + 53.4293975f, 75.5523529f, 106.841369f, 218.534011f }; + + const float neg = junction_cos_theta < 0 ? -1 : 1, + t = neg * junction_cos_theta; + + const int16_t idx = (t < 0.00000003f) ? 0 : __builtin_clz(uint16_t((1.0f - t) * jd_lut_tll)) - jd_lut_tll0; + + float junction_theta = t * pgm_read_float(&jd_lut_k[idx]) + pgm_read_float(&jd_lut_b[idx]); + if (neg > 0) junction_theta = RADIANS(180) - junction_theta; // acos(-t) + + #else + + // Fast acos(-t) approximation (max. error +-0.033rad = 1.89°) + // Based on MinMax polynomial published by W. Randolph Franklin, see + // https://wrf.ecse.rpi.edu/Research/Short_Notes/arcsin/onlyelem.html + // acos( t) = pi / 2 - asin(x) + // acos(-t) = pi - acos(t) ... pi / 2 + asin(x) + + const float neg = junction_cos_theta < 0 ? -1 : 1, + t = neg * junction_cos_theta, + asinx = 0.032843707f + + t * (-1.451838349f + + t * ( 29.66153956f + + t * (-131.1123477f + + t * ( 262.8130562f + + t * (-242.7199627f + + t * ( 84.31466202f ) ))))), + junction_theta = RADIANS(90) + neg * asinx; // acos(-t) + + // NOTE: junction_theta bottoms out at 0.033 which avoids divide by 0. + + #endif + + const float limit_sqr = (block->millimeters * junction_acceleration) / junction_theta; + NOMORE(vmax_junction_sqr, limit_sqr); + } + + #endif // JD_HANDLE_SMALL_SEGMENTS + } } // Get the lowest speed @@ -2964,6 +2974,7 @@ void Planner::buffer_sync_block(TERN_(LASER_SYNCHRONOUS_M106_M107, uint8_t sync_ bool Planner::buffer_segment(const abce_pos_t &abce OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , const_feedRate_t fr_mm_s, const uint8_t extruder/*=active_extruder*/, const_float_t millimeters/*=0.0*/ + OPTARG(ARC_ASSISTED_JD, const_float_t arc_radius/*=0.0*/) ) { // If we are cleaning, do not accept queuing of movements @@ -3069,8 +3080,9 @@ bool Planner::buffer_segment(const abce_pos_t &abce if (!_buffer_steps(target OPTARG(HAS_POSITION_FLOAT, target_float) OPTARG(HAS_DIST_MM_ARG, cart_dist_mm) - , fr_mm_s, extruder, millimeters) - ) return false; + , fr_mm_s, extruder, millimeters + OPTARG(ARC_ASSISTED_JD, arc_radius) + )) return false; stepper.wake_up(); return true; @@ -3089,6 +3101,7 @@ bool Planner::buffer_segment(const abce_pos_t &abce */ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, const uint8_t extruder/*=active_extruder*/, const float millimeters/*=0.0*/ OPTARG(SCARA_FEEDRATE_SCALING, const_float_t inv_duration/*=0.0*/) + OPTARG(ARC_ASSISTED_JD, const_float_t arc_radius/*=0.0*/) ) { xyze_pos_t machine = cart; TERN_(HAS_POSITION_MODIFIERS, apply_modifiers(machine)); @@ -3125,13 +3138,13 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, cons const feedRate_t feedrate = fr_mm_s; #endif TERN_(HAS_EXTRUDERS, delta.e = machine.e); - if (buffer_segment(delta OPTARG(HAS_DIST_MM_ARG, cart_dist_mm), feedrate, extruder, mm)) { + if (buffer_segment(delta OPTARG(HAS_DIST_MM_ARG, cart_dist_mm), feedrate, extruder, mm OPTARG(ARC_ASSISTED_JD, arc_radius))) { position_cart = cart; return true; } return false; #else - return buffer_segment(machine, fr_mm_s, extruder, millimeters); + return buffer_segment(machine, fr_mm_s, extruder, millimeters OPTARG(ARC_ASSISTED_JD, arc_radius)); #endif } // buffer_line() diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index bef381b5c7c4..ac413f1c4e42 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -733,6 +733,7 @@ class Planner { OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters=0.0 + OPTARG(ARC_ASSISTED_JD, const_float_t arc_radius=0.0) ); /** @@ -751,6 +752,7 @@ class Planner { OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters=0.0 + OPTARG(ARC_ASSISTED_JD, const_float_t arc_radius=0.0) ); /** @@ -784,6 +786,7 @@ class Planner { static bool buffer_segment(const abce_pos_t &abce OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , const_feedRate_t fr_mm_s, const uint8_t extruder=active_extruder, const_float_t millimeters=0.0 + OPTARG(ARC_ASSISTED_JD, const_float_t arc_radius=0.0) ); public: @@ -801,6 +804,7 @@ class Planner { */ static bool buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, const uint8_t extruder=active_extruder, const float millimeters=0.0 OPTARG(SCARA_FEEDRATE_SCALING, const_float_t inv_duration=0.0) + OPTARG(ARC_ASSISTED_JD, const_float_t arc_radius=0.0) ); #if ENABLED(DIRECT_STEPPING) From eb2024d00e82643a01ef1f73dc2df6ab2720c52f Mon Sep 17 00:00:00 2001 From: Tom Brazier Date: Mon, 20 Jun 2022 09:23:39 +0100 Subject: [PATCH 03/18] Just do it! --- Marlin/Configuration_adv.h | 3 --- Marlin/src/gcode/motion/G2_G3.cpp | 4 +--- Marlin/src/module/planner.cpp | 18 +++++++++--------- Marlin/src/module/planner.h | 8 ++++---- 4 files changed, 14 insertions(+), 19 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 8396257bb0bf..96a3e04d0b77 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2193,9 +2193,6 @@ #define N_ARC_CORRECTION 25 // Number of interpolated segments between corrections //#define ARC_P_CIRCLES // Enable the 'P' parameter to specify complete circles //#define SF_ARC_FIX // Enable only if using SkeinForge with "Arc Point" fillet procedure - #if HAS_JUNCTION_DEVIATION - #define ARC_ASSISTED_JD // Pass the arc radius to the junction deviation code to save processor cycles - #endif #endif // G5 Bézier Curve Support with XYZE destination and IJPQ offsets diff --git a/Marlin/src/gcode/motion/G2_G3.cpp b/Marlin/src/gcode/motion/G2_G3.cpp index aaf69a5e6b20..9369aba7eecf 100644 --- a/Marlin/src/gcode/motion/G2_G3.cpp +++ b/Marlin/src/gcode/motion/G2_G3.cpp @@ -346,9 +346,7 @@ void plan_arc( #endif if (!planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, 0 - OPTARG(SCARA_FEEDRATE_SCALING, inv_duration) - OPTARG(ARC_ASSISTED_JD, i > 1 ? radius : 0.0) - )) + OPTARG(SCARA_FEEDRATE_SCALING, inv_duration), i > 1 ? radius : 0.0)) break; } } diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 5bd0af9da324..33a0edc700b7 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -1783,7 +1783,7 @@ bool Planner::_buffer_steps(const xyze_long_t &target OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters - OPTARG(ARC_ASSISTED_JD, const_float_t arc_radius/*=0.0*/) + OPTARG(ARC_SUPPORT, const_float_t arc_radius/*=0.0*/) ) { // Wait for the next available block @@ -1800,7 +1800,7 @@ bool Planner::_buffer_steps(const xyze_long_t &target OPTARG(HAS_POSITION_FLOAT, target_float) OPTARG(HAS_DIST_MM_ARG, cart_dist_mm) , fr_mm_s, extruder, millimeters - OPTARG(ARC_ASSISTED_JD, arc_radius) + OPTARG(ARC_SUPPORT, arc_radius) )) { // Movement was not queued, probably because it was too short. // Simply accept that as movement queued and done @@ -1843,7 +1843,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters/*=0.0*/ - OPTARG(ARC_ASSISTED_JD, const_float_t arc_radius/*=0.0*/) + OPTARG(ARC_SUPPORT, const_float_t arc_radius/*=0.0*/) ) { int32_t LOGICAL_AXIS_LIST( de = target.e - position.e, @@ -2655,7 +2655,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, normalize_junction_vector(junction_unit_vec); const float junction_acceleration = limit_value_by_axis_maximum(block->acceleration, junction_unit_vec); - #if ENABLED(ARC_ASSISTED_JD) + #if ENABLED(ARC_SUPPORT) if (arc_radius > 0.0) vmax_junction_sqr = junction_acceleration * arc_radius; else @@ -2974,7 +2974,7 @@ void Planner::buffer_sync_block(TERN_(LASER_SYNCHRONOUS_M106_M107, uint8_t sync_ bool Planner::buffer_segment(const abce_pos_t &abce OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , const_feedRate_t fr_mm_s, const uint8_t extruder/*=active_extruder*/, const_float_t millimeters/*=0.0*/ - OPTARG(ARC_ASSISTED_JD, const_float_t arc_radius/*=0.0*/) + OPTARG(ARC_SUPPORT, const_float_t arc_radius/*=0.0*/) ) { // If we are cleaning, do not accept queuing of movements @@ -3081,7 +3081,7 @@ bool Planner::buffer_segment(const abce_pos_t &abce OPTARG(HAS_POSITION_FLOAT, target_float) OPTARG(HAS_DIST_MM_ARG, cart_dist_mm) , fr_mm_s, extruder, millimeters - OPTARG(ARC_ASSISTED_JD, arc_radius) + OPTARG(ARC_SUPPORT, arc_radius) )) return false; stepper.wake_up(); @@ -3101,7 +3101,7 @@ bool Planner::buffer_segment(const abce_pos_t &abce */ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, const uint8_t extruder/*=active_extruder*/, const float millimeters/*=0.0*/ OPTARG(SCARA_FEEDRATE_SCALING, const_float_t inv_duration/*=0.0*/) - OPTARG(ARC_ASSISTED_JD, const_float_t arc_radius/*=0.0*/) + OPTARG(ARC_SUPPORT, const_float_t arc_radius/*=0.0*/) ) { xyze_pos_t machine = cart; TERN_(HAS_POSITION_MODIFIERS, apply_modifiers(machine)); @@ -3138,13 +3138,13 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, cons const feedRate_t feedrate = fr_mm_s; #endif TERN_(HAS_EXTRUDERS, delta.e = machine.e); - if (buffer_segment(delta OPTARG(HAS_DIST_MM_ARG, cart_dist_mm), feedrate, extruder, mm OPTARG(ARC_ASSISTED_JD, arc_radius))) { + if (buffer_segment(delta OPTARG(HAS_DIST_MM_ARG, cart_dist_mm), feedrate, extruder, mm OPTARG(ARC_SUPPORT, arc_radius))) { position_cart = cart; return true; } return false; #else - return buffer_segment(machine, fr_mm_s, extruder, millimeters OPTARG(ARC_ASSISTED_JD, arc_radius)); + return buffer_segment(machine, fr_mm_s, extruder, millimeters OPTARG(ARC_SUPPORT, arc_radius)); #endif } // buffer_line() diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index ac413f1c4e42..987bbe116445 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -733,7 +733,7 @@ class Planner { OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters=0.0 - OPTARG(ARC_ASSISTED_JD, const_float_t arc_radius=0.0) + OPTARG(ARC_SUPPORT, const_float_t arc_radius=0.0) ); /** @@ -752,7 +752,7 @@ class Planner { OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters=0.0 - OPTARG(ARC_ASSISTED_JD, const_float_t arc_radius=0.0) + OPTARG(ARC_SUPPORT, const_float_t arc_radius=0.0) ); /** @@ -786,7 +786,7 @@ class Planner { static bool buffer_segment(const abce_pos_t &abce OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , const_feedRate_t fr_mm_s, const uint8_t extruder=active_extruder, const_float_t millimeters=0.0 - OPTARG(ARC_ASSISTED_JD, const_float_t arc_radius=0.0) + OPTARG(ARC_SUPPORT, const_float_t arc_radius=0.0) ); public: @@ -804,7 +804,7 @@ class Planner { */ static bool buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, const uint8_t extruder=active_extruder, const float millimeters=0.0 OPTARG(SCARA_FEEDRATE_SCALING, const_float_t inv_duration=0.0) - OPTARG(ARC_ASSISTED_JD, const_float_t arc_radius=0.0) + OPTARG(ARC_SUPPORT, const_float_t arc_radius=0.0) ); #if ENABLED(DIRECT_STEPPING) From 73521a8f12494c70238337e3090ab9b8f2549e4d Mon Sep 17 00:00:00 2001 From: Tom Brazier Date: Mon, 20 Jun 2022 09:24:02 +0100 Subject: [PATCH 04/18] Revert "sqrt() is a lot cheaper than cos() or sin()" This reverts commit 361268bf479937725a650ff09269a0c24be5cdb2. The CPU time saved does not justify the extra code complexity. --- Marlin/src/gcode/motion/G2_G3.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Marlin/src/gcode/motion/G2_G3.cpp b/Marlin/src/gcode/motion/G2_G3.cpp index 9369aba7eecf..f8f0a8ca6cac 100644 --- a/Marlin/src/gcode/motion/G2_G3.cpp +++ b/Marlin/src/gcode/motion/G2_G3.cpp @@ -315,10 +315,7 @@ void plan_arc( // Compute exact location by applying transformation matrix from initial radius vector(=-offset). // To reduce stuttering, the sin and cos could be computed at different times. // For now, compute both at the same time. - const float angle = i * theta_per_segment, - cos_Ti = cos(angle), - abs_sin_Ti = SQRT(1 - cos_Ti * cos_Ti), - sin_Ti = angle > M_PI || (angle < 0.0f && angle > -M_PI) ? -abs_sin_Ti : abs_sin_Ti; + const float cos_Ti = cos(i * theta_per_segment), sin_Ti = sin(i * theta_per_segment); rvec.a = -offset[0] * cos_Ti + offset[1] * sin_Ti; rvec.b = -offset[0] * sin_Ti - offset[1] * cos_Ti; } From 9d1d54d3a55cdb20b8ecc45d1b58aa1967d5662f Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 23 Jun 2022 04:56:02 -0500 Subject: [PATCH 05/18] Ti --- Marlin/src/gcode/motion/G2_G3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/gcode/motion/G2_G3.cpp b/Marlin/src/gcode/motion/G2_G3.cpp index f8f0a8ca6cac..e7889f391840 100644 --- a/Marlin/src/gcode/motion/G2_G3.cpp +++ b/Marlin/src/gcode/motion/G2_G3.cpp @@ -315,7 +315,7 @@ void plan_arc( // Compute exact location by applying transformation matrix from initial radius vector(=-offset). // To reduce stuttering, the sin and cos could be computed at different times. // For now, compute both at the same time. - const float cos_Ti = cos(i * theta_per_segment), sin_Ti = sin(i * theta_per_segment); + const float Ti = i * theta_per_segment, cos_Ti = cos(Ti), sin_Ti = sin(Ti); rvec.a = -offset[0] * cos_Ti + offset[1] * sin_Ti; rvec.b = -offset[0] * sin_Ti - offset[1] * cos_Ti; } From 2cd00faf598f0d93c94d4e9926ac07c3e3012c71 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 23 Jun 2022 05:17:49 -0500 Subject: [PATCH 06/18] clean up --- .../src/feature/bedlevel/ubl/ubl_motion.cpp | 18 +++++- Marlin/src/gcode/motion/G2_G3.cpp | 6 +- Marlin/src/module/planner.cpp | 56 +++++-------------- 3 files changed, 34 insertions(+), 46 deletions(-) diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp index e6eec0de63fd..9fa2257dc8a6 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp @@ -36,8 +36,18 @@ #include "../../../MarlinCore.h" #include +//#define DEBUG_UBL_MOTION +#define DEBUG_OUT ENABLED(DEBUG_UBL_MOTION) +#include "../../../core/debug_out.h" + #if !UBL_SEGMENTED + // TODO: The first and last parts of a move might result in very short segment(s) + // after getting split on the cell boundary, so moves like that should not + // get split. This will be most common for moves that start/end near the + // 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) { /** * Much of the nozzle movement will be within the same cell. So we will do as little computation @@ -176,7 +186,9 @@ dest.z += z0; planner.buffer_segment(dest, scaled_fr_mm_s, extruder); - } //else printf("FIRST MOVE PRUNED "); + } + else + DEBUG_ECHOLNPGM("[ubl] skip Y segment"); } // At the final destination? Usually not, but when on a Y Mesh Line it's completed. @@ -225,7 +237,9 @@ dest.z += z0; if (!planner.buffer_segment(dest, scaled_fr_mm_s, extruder)) break; - } //else printf("FIRST MOVE PRUNED "); + } + else + DEBUG_ECHOLNPGM("[ubl] skip Y segment"); } if (xy_pos_t(current_position) != xy_pos_t(end)) diff --git a/Marlin/src/gcode/motion/G2_G3.cpp b/Marlin/src/gcode/motion/G2_G3.cpp index e7889f391840..ade014fcea99 100644 --- a/Marlin/src/gcode/motion/G2_G3.cpp +++ b/Marlin/src/gcode/motion/G2_G3.cpp @@ -343,8 +343,10 @@ void plan_arc( #endif if (!planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, 0 - OPTARG(SCARA_FEEDRATE_SCALING, inv_duration), i > 1 ? radius : 0.0)) - break; + OPTARG(SCARA_FEEDRATE_SCALING, inv_duration) + , i > 1 ? radius : 0 + ) + ) break; } } diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 33a0edc700b7..e1f689471f0c 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -1782,7 +1782,7 @@ void Planner::synchronize() { while (busy()) idle(); } bool Planner::_buffer_steps(const xyze_long_t &target OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) - , feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters + , feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters/*=0.0*/ OPTARG(ARC_SUPPORT, const_float_t arc_radius/*=0.0*/) ) { @@ -1797,11 +1797,12 @@ bool Planner::_buffer_steps(const xyze_long_t &target // Fill the block with the specified movement if (!_populate_block(block, false, target - OPTARG(HAS_POSITION_FLOAT, target_float) - OPTARG(HAS_DIST_MM_ARG, cart_dist_mm) - , fr_mm_s, extruder, millimeters - OPTARG(ARC_SUPPORT, arc_radius) - )) { + OPTARG(HAS_POSITION_FLOAT, target_float) + OPTARG(HAS_DIST_MM_ARG, cart_dist_mm) + , fr_mm_s, extruder, millimeters + OPTARG(ARC_SUPPORT, arc_radius) + ) + ) { // Movement was not queued, probably because it was too short. // Simply accept that as movement queued and done return true; @@ -1859,36 +1860,8 @@ bool Planner::_populate_block(block_t * const block, bool split_move, ); /* <-- add a slash to enable - SERIAL_ECHOLNPGM( - " _populate_block FR:", fr_mm_s, - " A:", target.a, " (", da, " steps)" - #if HAS_Y_AXIS - " B:", target.b, " (", db, " steps)" - #endif - #if HAS_Z_AXIS - " C:", target.c, " (", dc, " steps)" - #endif - #if HAS_I_AXIS - " " STR_I ":", target.i, " (", di, " steps)" - #endif - #if HAS_J_AXIS - " " STR_J ":", target.j, " (", dj, " steps)" - #endif - #if HAS_K_AXIS - " " STR_K ":", target.k, " (", dk, " steps)" - #endif - #if HAS_U_AXIS - " " STR_U ":", target.u, " (", du, " steps)" - #endif - #if HAS_V_AXIS - " " STR_V ":", target.v, " (", dv, " steps)" - #endif - #if HAS_W_AXIS - " " STR_W ":", target.w, " (", dw, " steps)" - #if HAS_EXTRUDERS - " E:", target.e, " (", de, " steps)" - #endif - ); + #define _ALINE(A) " A:", target[_AXIS(A)], " (", int32_t(target[_AXIS(A)] - position[_AXIS(A)]), " steps)" + SERIAL_ECHOLNPGM(" _populate_block FR:", fr_mm_s, LOGICAL_AXIS_MAP(_ALINE)); //*/ #if EITHER(PREVENT_COLD_EXTRUSION, PREVENT_LENGTHY_EXTRUDE) @@ -2653,14 +2626,13 @@ bool Planner::_populate_block(block_t * const block, bool split_move, // Convert delta vector to unit vector xyze_float_t junction_unit_vec = unit_vec - prev_unit_vec; normalize_junction_vector(junction_unit_vec); + const float junction_acceleration = limit_value_by_axis_maximum(block->acceleration, junction_unit_vec); - #if ENABLED(ARC_SUPPORT) - if (arc_radius > 0.0) - vmax_junction_sqr = junction_acceleration * arc_radius; - else - #endif - { + if (TERN0(ARC_SUPPORT, arc_radius)) { + TERN_(ARC_SUPPORT, vmax_junction_sqr = junction_acceleration * arc_radius); + } + else { NOLESS(junction_cos_theta, -0.999999f); // Check for numerical round-off to avoid divide by zero. const float sin_theta_d2 = SQRT(0.5f * (1.0f - junction_cos_theta)); // Trig half angle identity. Always positive. From ce9e5e262283e72dfd2e77cd14a5ba7424225ed5 Mon Sep 17 00:00:00 2001 From: Tom Brazier Date: Sat, 25 Jun 2022 22:31:00 +0100 Subject: [PATCH 07/18] Fix recalculate_trapezoids with PAGE block Also cleaned up the code at the end so it is far more consistent name-wise with the block inside the loop above --- Marlin/src/module/planner.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index e1f689471f0c..b08918c2b50f 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -1131,7 +1131,7 @@ void Planner::recalculate_trapezoids() { // The tail may be changed by the ISR so get a local copy. uint8_t block_index = block_buffer_tail, head_block_index = block_buffer_head; - // Since there could be a sync block in the head of the queue, and the + // Since there could be a sync or page block in the head of the queue, and the // next loop must not recalculate the head block (as it needs to be // specially handled), scan backwards to the first non-SYNC block. while (head_block_index != block_index) { @@ -1143,7 +1143,7 @@ void Planner::recalculate_trapezoids() { block_t *prev = &block_buffer[prev_index]; // If not dealing with a sync block, we are done. The last block is not a SYNC block - if (!(prev->flag & BLOCK_MASK_SYNC)) break; + if (!(prev->flag & BLOCK_MASK_SYNC) && !IS_PAGE(prev)) break; // Examine the previous block. This and all following are SYNC blocks head_block_index = prev_index; @@ -1202,12 +1202,12 @@ void Planner::recalculate_trapezoids() { } // Last/newest block in buffer. Exit speed is set with MINIMUM_PLANNER_SPEED. Always recalculated. - if (next) { + if (block) { - // Mark the next(last) block as RECALCULATE, to prevent the Stepper ISR running it. + // Mark the last block as RECALCULATE, to prevent the Stepper ISR running it. // As the last block is always recalculated here, there is a chance the block isn't // marked as RECALCULATE yet. That's the reason for the following line. - SBI(next->flag, BLOCK_BIT_RECALCULATE); + SBI(block->flag, BLOCK_BIT_RECALCULATE); // But there is an inherent race condition here, as the block maybe // became BUSY, just before it was marked as RECALCULATE, so check @@ -1215,21 +1215,21 @@ void Planner::recalculate_trapezoids() { if (!stepper.is_block_busy(block)) { // Block is not BUSY, we won the race against the Stepper ISR: - const float next_nominal_speed = SQRT(next->nominal_speed_sqr), - nomr = 1.0f / next_nominal_speed; - calculate_trapezoid_for_block(next, next_entry_speed * nomr, float(MINIMUM_PLANNER_SPEED) * nomr); + const float current_nominal_speed = SQRT(block->nominal_speed_sqr), + nomr = 1.0f / current_nominal_speed; + calculate_trapezoid_for_block(block, current_entry_speed * nomr, float(MINIMUM_PLANNER_SPEED) * nomr); #if ENABLED(LIN_ADVANCE) - if (next->use_advance_lead) { - const float comp = next->e_D_ratio * extruder_advance_K[active_extruder] * settings.axis_steps_per_mm[E_AXIS]; - next->max_adv_steps = next_nominal_speed * comp; - next->final_adv_steps = (MINIMUM_PLANNER_SPEED) * comp; + if (block->use_advance_lead) { + const float comp = block->e_D_ratio * extruder_advance_K[active_extruder] * settings.axis_steps_per_mm[E_AXIS]; + block->max_adv_steps = current_nominal_speed * comp; + block->final_adv_steps = (MINIMUM_PLANNER_SPEED) * comp; } #endif } - // Reset next only to ensure its trapezoid is computed - The stepper is free to use + // Reset block to ensure its trapezoid is computed - The stepper is free to use // the block from now on. - CBI(next->flag, BLOCK_BIT_RECALCULATE); + CBI(block->flag, BLOCK_BIT_RECALCULATE); } } From 91ec035fb7b1c7e547f9ab3d817ea8f45b35c117 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 26 Jun 2022 07:14:40 -0500 Subject: [PATCH 08/18] Bit fields for block flags --- Marlin/src/gcode/temp/M106_M107.cpp | 4 +- Marlin/src/module/planner.cpp | 60 +++++++++--------- Marlin/src/module/planner.h | 97 +++++++++++++++++------------ Marlin/src/module/stepper.cpp | 21 +++---- Marlin/src/module/stepper.h | 3 +- 5 files changed, 99 insertions(+), 86 deletions(-) diff --git a/Marlin/src/gcode/temp/M106_M107.cpp b/Marlin/src/gcode/temp/M106_M107.cpp index 98e87c415de9..ae517c977b29 100644 --- a/Marlin/src/gcode/temp/M106_M107.cpp +++ b/Marlin/src/gcode/temp/M106_M107.cpp @@ -90,7 +90,7 @@ void GcodeSuite::M106() { // Set speed, with constraint thermalManager.set_fan_speed(pfan, speed); - TERN_(LASER_SYNCHRONOUS_M106_M107, planner.buffer_sync_block(BLOCK_FLAG_SYNC_FANS)); + TERN_(LASER_SYNCHRONOUS_M106_M107, planner.buffer_sync_block(BLOCK_BIT_SYNC_FANS)); if (TERN0(DUAL_X_CARRIAGE, idex_is_duplicating())) // pfan == 0 when duplicating thermalManager.set_fan_speed(1 - pfan, speed); @@ -111,7 +111,7 @@ void GcodeSuite::M107() { if (TERN0(DUAL_X_CARRIAGE, idex_is_duplicating())) // pfan == 0 when duplicating thermalManager.set_fan_speed(1 - pfan, 0); - TERN_(LASER_SYNCHRONOUS_M106_M107, planner.buffer_sync_block(BLOCK_FLAG_SYNC_FANS)); + TERN_(LASER_SYNCHRONOUS_M106_M107, planner.buffer_sync_block(BLOCK_BIT_SYNC_FANS)); } #endif // HAS_FAN diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index b08918c2b50f..93582363c474 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -739,7 +739,7 @@ block_t* Planner::get_current_block() { block_t * const block = &block_buffer[block_buffer_tail]; // No trapezoid calculated? Don't execute yet. - if (TEST(block->flag, BLOCK_BIT_RECALCULATE)) return nullptr; + if (block->flag.recalculate) return nullptr; // We can't be sure how long an active block will take, so don't count it. TERN_(HAS_WIRED_LCD, block_buffer_runtime_us -= block->segment_time_us); @@ -948,7 +948,7 @@ void Planner::reverse_pass_kernel(block_t * const current, const block_t * const // Compute maximum entry speed decelerating over the current block from its exit speed. // If not at the maximum entry speed, or the previous block entry speed changed - if (current->entry_speed_sqr != max_entry_speed_sqr || (next && TEST(next->flag, BLOCK_BIT_RECALCULATE))) { + if (current->entry_speed_sqr != max_entry_speed_sqr || (next && next->flag.recalculate)) { // If nominal length true, max junction speed is guaranteed to be reached. // If a block can de/ac-celerate from nominal speed to zero within the length of the block, then @@ -958,14 +958,14 @@ void Planner::reverse_pass_kernel(block_t * const current, const block_t * const // the reverse and forward planners, the corresponding block junction speed will always be at the // the maximum junction speed and may always be ignored for any speed reduction checks. - const float new_entry_speed_sqr = TEST(current->flag, BLOCK_BIT_NOMINAL_LENGTH) + const float new_entry_speed_sqr = current->flag.nominal_length ? max_entry_speed_sqr : _MIN(max_entry_speed_sqr, max_allowable_speed_sqr(-current->acceleration, next ? next->entry_speed_sqr : sq(float(MINIMUM_PLANNER_SPEED)), current->millimeters)); if (current->entry_speed_sqr != new_entry_speed_sqr) { // Need to recalculate the block speed - Mark it now, so the stepper // ISR does not consume the block before being recalculated - SBI(current->flag, BLOCK_BIT_RECALCULATE); + current->flag.recalculate = true; // But there is an inherent race condition here, as the block may have // become BUSY just before being marked RECALCULATE, so check for that! @@ -973,7 +973,7 @@ void Planner::reverse_pass_kernel(block_t * const current, const block_t * const // Block became busy. Clear the RECALCULATE flag (no point in // recalculating BUSY blocks). And don't set its speed, as it can't // be updated at this time. - CBI(current->flag, BLOCK_BIT_RECALCULATE); + current->flag.recalculate = false; } else { // Block is not BUSY so this is ahead of the Stepper ISR: @@ -1012,7 +1012,7 @@ void Planner::reverse_pass() { block_t *current = &block_buffer[block_index]; // Only consider non sync-and-page blocks - if (!(current->flag & BLOCK_MASK_SYNC) && !IS_PAGE(current)) { + if (current->is_move()) { reverse_pass_kernel(current, next); next = current; } @@ -1041,8 +1041,7 @@ void Planner::forward_pass_kernel(const block_t * const previous, block_t * cons // change, adjust the entry speed accordingly. Entry speeds have already been reset, // maximized, and reverse-planned. If nominal length is set, max junction speed is // guaranteed to be reached. No need to recheck. - if (!TEST(previous->flag, BLOCK_BIT_NOMINAL_LENGTH) && - previous->entry_speed_sqr < current->entry_speed_sqr) { + if (!previous->flag.nominal_length && previous->entry_speed_sqr < current->entry_speed_sqr) { // Compute the maximum allowable speed const float new_entry_speed_sqr = max_allowable_speed_sqr(-previous->acceleration, previous->entry_speed_sqr, previous->millimeters); @@ -1052,7 +1051,7 @@ void Planner::forward_pass_kernel(const block_t * const previous, block_t * cons // Mark we need to recompute the trapezoidal shape, and do it now, // so the stepper ISR does not consume the block before being recalculated - SBI(current->flag, BLOCK_BIT_RECALCULATE); + current->flag.recalculate = true; // But there is an inherent race condition here, as the block maybe // became BUSY, just before it was marked as RECALCULATE, so check @@ -1061,7 +1060,7 @@ void Planner::forward_pass_kernel(const block_t * const previous, block_t * cons // Block became busy. Clear the RECALCULATE flag (no point in // recalculating BUSY blocks and don't set its speed, as it can't // be updated at this time. - CBI(current->flag, BLOCK_BIT_RECALCULATE); + current->flag.recalculate = false; } else { // Block is not BUSY, we won the race against the Stepper ISR: @@ -1107,7 +1106,7 @@ void Planner::forward_pass() { block = &block_buffer[block_index]; // Skip SYNC and page blocks - if (!(block->flag & BLOCK_MASK_SYNC) && !IS_PAGE(block)) { + if (!block->is_move()) { // If there's no previous block or the previous block is not // BUSY (thus, modifiable) run the forward_pass_kernel. Otherwise, // the previous block became BUSY, so assume the current block's @@ -1142,8 +1141,8 @@ void Planner::recalculate_trapezoids() { // Get the pointer to the block block_t *prev = &block_buffer[prev_index]; - // If not dealing with a sync block, we are done. The last block is not a SYNC block - if (!(prev->flag & BLOCK_MASK_SYNC) && !IS_PAGE(prev)) break; + // If not dealing with a sync or page block, we are done. The last block is not a SYNC or PAGE block. + if (!prev->is_move()) break; // Examine the previous block. This and all following are SYNC blocks head_block_index = prev_index; @@ -1157,17 +1156,16 @@ void Planner::recalculate_trapezoids() { next = &block_buffer[block_index]; // Skip sync and page blocks - if (!(next->flag & BLOCK_MASK_SYNC) && !IS_PAGE(next)) { + if (!next->is_move()) { next_entry_speed = SQRT(next->entry_speed_sqr); if (block) { - // Recalculate if current block entry or exit junction speed has changed. - if (TEST(block->flag, BLOCK_BIT_RECALCULATE) || TEST(next->flag, BLOCK_BIT_RECALCULATE)) { - // Mark the current block as RECALCULATE, to protect it from the Stepper ISR running it. - // Note that due to the above condition, there's a chance the current block isn't marked as - // RECALCULATE yet, but the next one is. That's the reason for the following line. - SBI(block->flag, BLOCK_BIT_RECALCULATE); + // If the next block is marked to RECALCULATE, also mark the previously-fetched one + if (next->flag.recalculate) block->flag.recalculate = true; + + // Recalculate if current block entry or exit junction speed has changed. + if (block->flag.recalculate) { // But there is an inherent race condition here, as the block maybe // became BUSY, just before it was marked as RECALCULATE, so check @@ -1190,7 +1188,7 @@ void Planner::recalculate_trapezoids() { // Reset current only to ensure next trapezoid is computed - The // stepper is free to use the block from now on. - CBI(block->flag, BLOCK_BIT_RECALCULATE); + block->flag.recalculate = false; } } @@ -1207,7 +1205,7 @@ void Planner::recalculate_trapezoids() { // Mark the last block as RECALCULATE, to prevent the Stepper ISR running it. // As the last block is always recalculated here, there is a chance the block isn't // marked as RECALCULATE yet. That's the reason for the following line. - SBI(block->flag, BLOCK_BIT_RECALCULATE); + block->flag.recalculate = true; // But there is an inherent race condition here, as the block maybe // became BUSY, just before it was marked as RECALCULATE, so check @@ -1229,7 +1227,7 @@ void Planner::recalculate_trapezoids() { // Reset block to ensure its trapezoid is computed - The stepper is free to use // the block from now on. - CBI(block->flag, BLOCK_BIT_RECALCULATE); + block->flag.recalculate = false; } } @@ -1460,7 +1458,7 @@ void Planner::check_axes_activity() { for (uint8_t b = block_buffer_tail; b != block_buffer_head; b = next_block_index(b)) { const block_t * const block = &block_buffer[b]; if (NUM_AXIS_GANG(block->steps.x, || block->steps.y, || block->steps.z, || block->steps.i, || block->steps.j, || block->steps.k, || block->steps.u, || block->steps.v, || block->steps.w)) { - const float se = (float)block->steps.e / block->step_event_count * SQRT(block->nominal_speed_sqr); // mm/sec; + const float se = (float)block->steps.e / block->step_event_count * SQRT(block->nominal_speed_sqr); // mm/sec NOLESS(high, se); } } @@ -1954,7 +1952,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, #endif // Clear all flags, including the "busy" bit - block->flag = 0x00; + block->flag.clear(); // Set direction bits block->direction_bits = dm; @@ -2421,7 +2419,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, if (speed_factor < 1.0f) { current_speed *= speed_factor; block->nominal_rate *= speed_factor; - block->nominal_speed_sqr = block->nominal_speed_sqr * sq(speed_factor); + block->nominal_speed_sqr *= sq(speed_factor); } // Compute and limit the acceleration rate for the trapezoid generator. @@ -2866,7 +2864,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, // block nominal speed limits both the current and next maximum junction speeds. Hence, in both // the reverse and forward planners, the corresponding block junction speed will always be at the // the maximum junction speed and may always be ignored for any speed reduction checks. - block->flag |= block->nominal_speed_sqr <= v_allowable_sqr ? BLOCK_FLAG_RECALCULATE | BLOCK_FLAG_NOMINAL_LENGTH : BLOCK_FLAG_RECALCULATE; + block->flag.set_nominal(block->nominal_speed_sqr <= v_allowable_sqr); // Update previous path unit_vector and nominal speed previous_speed = current_speed; @@ -2891,9 +2889,9 @@ bool Planner::_populate_block(block_t * const block, bool split_move, * Add a block to the buffer that just updates the position, * or in case of LASER_SYNCHRONOUS_M106_M107 the fan PWM */ -void Planner::buffer_sync_block(TERN_(LASER_SYNCHRONOUS_M106_M107, uint8_t sync_flag)) { +void Planner::buffer_sync_block(TERN_(LASER_SYNCHRONOUS_M106_M107, const BlockFlagBit sync_flag)) { #if DISABLED(LASER_SYNCHRONOUS_M106_M107) - constexpr uint8_t sync_flag = BLOCK_FLAG_SYNC_POSITION; + constexpr BlockFlagBit sync_flag = BLOCK_BIT_SYNC_POSITION; #endif // Wait for the next available block @@ -2903,7 +2901,7 @@ void Planner::buffer_sync_block(TERN_(LASER_SYNCHRONOUS_M106_M107, uint8_t sync_ // Clear block memset(block, 0, sizeof(block_t)); - block->flag = sync_flag; + block->flag.apply(sync_flag); block->position = position; #if ENABLED(BACKLASH_COMPENSATION) @@ -3131,7 +3129,7 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, cons uint8_t next_buffer_head; block_t * const block = get_next_free_block(next_buffer_head); - block->flag = BLOCK_FLAG_IS_PAGE; + block->flag.only(BLOCK_BIT_PAGE); #if HAS_FAN FANS_LOOP(i) block->fan_speed[i] = thermalManager.fan_speed[i]; diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index 987bbe116445..de587f3bb0ec 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -70,9 +70,6 @@ #if ENABLED(DIRECT_STEPPING) #include "../feature/direct_stepping.h" - #define IS_PAGE(B) TEST(B->flag, BLOCK_BIT_IS_PAGE) -#else - #define IS_PAGE(B) false #endif #if ENABLED(EXTERNAL_CLOSED_LOOP_CONTROLLER) @@ -92,7 +89,31 @@ #define HAS_DIST_MM_ARG 1 #endif -enum BlockFlagBit : char { +#if ENABLED(LASER_POWER_INLINE) + + typedef struct { + bool isPlanned:1; + bool isEnabled:1; + bool dir:1; + bool Reserved:6; + } power_status_t; + + typedef struct { + power_status_t status; // See planner settings for meaning + uint8_t power; // Ditto; When in trapezoid mode this is nominal power + #if ENABLED(LASER_POWER_INLINE_TRAPEZOID) + uint8_t power_entry; // Entry power for the laser + #if DISABLED(LASER_POWER_INLINE_TRAPEZOID_CONT) + uint8_t power_exit; // Exit power for the laser + uint32_t entry_per, // Steps per power increment (to avoid floats in stepper calcs) + exit_per; // Steps per power decrement + #endif + #endif + } block_laser_t; + +#endif + +enum BlockFlagBit { // Recalculate trapezoids on entry junction. For optimization. BLOCK_BIT_RECALCULATE, @@ -109,7 +130,7 @@ enum BlockFlagBit : char { // Direct stepping page #if ENABLED(DIRECT_STEPPING) - , BLOCK_BIT_IS_PAGE + , BLOCK_BIT_PAGE #endif // Sync the fan speeds from the block @@ -118,44 +139,37 @@ enum BlockFlagBit : char { #endif }; -enum BlockFlag : char { - BLOCK_FLAG_RECALCULATE = _BV(BLOCK_BIT_RECALCULATE) - , BLOCK_FLAG_NOMINAL_LENGTH = _BV(BLOCK_BIT_NOMINAL_LENGTH) - , BLOCK_FLAG_CONTINUED = _BV(BLOCK_BIT_CONTINUED) - , BLOCK_FLAG_SYNC_POSITION = _BV(BLOCK_BIT_SYNC_POSITION) - #if ENABLED(DIRECT_STEPPING) - , BLOCK_FLAG_IS_PAGE = _BV(BLOCK_BIT_IS_PAGE) - #endif - #if ENABLED(LASER_SYNCHRONOUS_M106_M107) - , BLOCK_FLAG_SYNC_FANS = _BV(BLOCK_BIT_SYNC_FANS) - #endif -}; +typedef struct { + union { + uint8_t bits; -#define BLOCK_MASK_SYNC ( BLOCK_FLAG_SYNC_POSITION | TERN0(LASER_SYNCHRONOUS_M106_M107, BLOCK_FLAG_SYNC_FANS) ) + struct { + bool recalculate:1; -#if ENABLED(LASER_POWER_INLINE) + bool nominal_length:1; - typedef struct { - bool isPlanned:1; - bool isEnabled:1; - bool dir:1; - bool Reserved:6; - } power_status_t; + bool continued:1; - typedef struct { - power_status_t status; // See planner settings for meaning - uint8_t power; // Ditto; When in trapezoid mode this is nominal power - #if ENABLED(LASER_POWER_INLINE_TRAPEZOID) - uint8_t power_entry; // Entry power for the laser - #if DISABLED(LASER_POWER_INLINE_TRAPEZOID_CONT) - uint8_t power_exit; // Exit power for the laser - uint32_t entry_per, // Steps per power increment (to avoid floats in stepper calcs) - exit_per; // Steps per power decrement + bool sync_position:1; + + #if ENABLED(DIRECT_STEPPING) + bool page:1; #endif - #endif - } block_laser_t; -#endif + #if ENABLED(LASER_SYNCHRONOUS_M106_M107) + bool sync_fans:1; + #endif + }; + }; + + void clear() volatile { bits = 0; } + void apply(const uint8_t f) volatile { bits |= f; } + void apply(const BlockFlagBit b) volatile { SBI(bits, b); } + void only(const BlockFlagBit b) volatile { bits = _BV(b); } + void set_nominal(const bool n) volatile { recalculate = true; if (n) nominal_length = true; } + +} block_flags_t; + /** * struct block_t @@ -168,7 +182,12 @@ enum BlockFlag : char { */ typedef struct block_t { - volatile uint8_t flag; // Block flags (See BlockFlag enum above) - Modified by ISR and main thread! + volatile block_flags_t flag; // Block flags + + volatile bool is_fan_sync() { return TERN0(LASER_SYNCHRONOUS_M106_M107, flag.sync_fans); } + volatile bool is_sync() { return flag.sync_position || is_fan_sync(); } + volatile bool is_page() { return TERN0(DIRECT_STEPPING, flag.page); } + volatile bool is_move() { return !(is_sync() || is_page()); } // Fields used by the motion planner to manage acceleration float nominal_speed_sqr, // The nominal speed for this block in (mm/sec)^2 @@ -761,7 +780,7 @@ class Planner { * case of LASER_SYNCHRONOUS_M106_M107 the fan pwm */ static void buffer_sync_block( - TERN_(LASER_SYNCHRONOUS_M106_M107, uint8_t sync_flag=BLOCK_FLAG_SYNC_POSITION) + TERN_(LASER_SYNCHRONOUS_M106_M107, const BlockFlagBit flag=BLOCK_BIT_SYNC_POSITION) ); #if IS_KINEMATIC diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 40cf7d02eaae..5dd1bd24b3fe 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -1699,7 +1699,7 @@ void Stepper::pulse_phase_isr() { }while(0) // Direct Stepping page? - const bool is_page = IS_PAGE(current_block); + const bool is_page = current_block->is_page(); #if ENABLED(DIRECT_STEPPING) // Direct stepping is currently not ready for HAS_I_AXIS @@ -1977,7 +1977,7 @@ uint32_t Stepper::block_phase_isr() { count_position[_AXIS(AXIS)] += page_step_state.bd[_AXIS(AXIS)] * count_direction[_AXIS(AXIS)]; #endif - if (IS_PAGE(current_block)) { + if (current_block->is_page()) { PAGE_SEGMENT_UPDATE_POS(X); PAGE_SEGMENT_UPDATE_POS(Y); PAGE_SEGMENT_UPDATE_POS(Z); @@ -2167,16 +2167,13 @@ uint32_t Stepper::block_phase_isr() { if ((current_block = planner.get_current_block())) { // Sync block? Sync the stepper counts or fan speeds and return - while (current_block->flag & BLOCK_MASK_SYNC) { + while (current_block->is_sync()) { - #if ENABLED(LASER_SYNCHRONOUS_M106_M107) - const bool is_sync_fans = TEST(current_block->flag, BLOCK_BIT_SYNC_FANS); - if (is_sync_fans) planner.sync_fan_speeds(current_block->fan_speed); - #else - constexpr bool is_sync_fans = false; - #endif - - if (!is_sync_fans) _set_position(current_block->position); + if (current_block->is_fan_sync()) { + TERN_(LASER_SYNCHRONOUS_M106_M107, planner.sync_fan_speeds(current_block->fan_speed)); + } + else + _set_position(current_block->position); discard_current_block(); @@ -2196,7 +2193,7 @@ uint32_t Stepper::block_phase_isr() { #endif #if ENABLED(DIRECT_STEPPING) - if (IS_PAGE(current_block)) { + if (current_block->is_page()) { page_step_state.segment_steps = 0; page_step_state.segment_idx = 0; page_step_state.page = page_manager.get_page(current_block->page_idx); diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h index 3b899e93e27c..c9a83caa7edb 100644 --- a/Marlin/src/module/stepper.h +++ b/Marlin/src/module/stepper.h @@ -524,8 +524,7 @@ class Stepper { // Discard current block and free any resources FORCE_INLINE static void discard_current_block() { #if ENABLED(DIRECT_STEPPING) - if (IS_PAGE(current_block)) - page_manager.free_page(current_block->page_idx); + if (current_block->is_page()) page_manager.free_page(current_block->page_idx); #endif current_block = nullptr; axis_did_move = 0; From ca9491b9c1a07bd851072bdd58133e9e99cbe6f8 Mon Sep 17 00:00:00 2001 From: Tom Brazier Date: Sun, 26 Jun 2022 20:26:56 +0100 Subject: [PATCH 09/18] Fixed inverse logic on is_move() --- Marlin/src/module/planner.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 93582363c474..4f523b941a75 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -1106,7 +1106,7 @@ void Planner::forward_pass() { block = &block_buffer[block_index]; // Skip SYNC and page blocks - if (!block->is_move()) { + if (block->is_move()) { // If there's no previous block or the previous block is not // BUSY (thus, modifiable) run the forward_pass_kernel. Otherwise, // the previous block became BUSY, so assume the current block's @@ -1142,7 +1142,7 @@ void Planner::recalculate_trapezoids() { block_t *prev = &block_buffer[prev_index]; // If not dealing with a sync or page block, we are done. The last block is not a SYNC or PAGE block. - if (!prev->is_move()) break; + if (prev->is_move()) break; // Examine the previous block. This and all following are SYNC blocks head_block_index = prev_index; @@ -1156,7 +1156,7 @@ void Planner::recalculate_trapezoids() { next = &block_buffer[block_index]; // Skip sync and page blocks - if (!next->is_move()) { + if (next->is_move()) { next_entry_speed = SQRT(next->entry_speed_sqr); if (block) { From 30c4d34ab7d74c83074055599db31d377ea58f0b Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 26 Jun 2022 20:33:56 -0500 Subject: [PATCH 10/18] fix _ALINE --- Marlin/src/module/planner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 4f523b941a75..5ac31487e575 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -1858,7 +1858,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, ); /* <-- add a slash to enable - #define _ALINE(A) " A:", target[_AXIS(A)], " (", int32_t(target[_AXIS(A)] - position[_AXIS(A)]), " steps)" + #define _ALINE(A) " " STR_##A ":", target[_AXIS(A)], " (", int32_t(target[_AXIS(A)] - position[_AXIS(A)]), " steps)" SERIAL_ECHOLNPGM(" _populate_block FR:", fr_mm_s, LOGICAL_AXIS_MAP(_ALINE)); //*/ From 0606d50f7789f44d9a2bdb0fe8cf1a81386dae7f Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 26 Jun 2022 20:43:08 -0500 Subject: [PATCH 11/18] update comments --- Marlin/src/module/planner.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 5ac31487e575..e755ee1d785f 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -1011,7 +1011,7 @@ void Planner::reverse_pass() { // Perform the reverse pass block_t *current = &block_buffer[block_index]; - // Only consider non sync-and-page blocks + // Only process movement blocks if (current->is_move()) { reverse_pass_kernel(current, next); next = current; @@ -1105,7 +1105,7 @@ void Planner::forward_pass() { // Perform the forward pass block = &block_buffer[block_index]; - // Skip SYNC and page blocks + // Only process movement blocks if (block->is_move()) { // If there's no previous block or the previous block is not // BUSY (thus, modifiable) run the forward_pass_kernel. Otherwise, @@ -1130,9 +1130,10 @@ void Planner::recalculate_trapezoids() { // The tail may be changed by the ISR so get a local copy. uint8_t block_index = block_buffer_tail, head_block_index = block_buffer_head; - // Since there could be a sync or page block in the head of the queue, and the + + // Since there could be non-move blocks in the head of the queue, and the // next loop must not recalculate the head block (as it needs to be - // specially handled), scan backwards to the first non-SYNC block. + // specially handled), scan backwards to the first move block. while (head_block_index != block_index) { // Go back (head always point to the first free block) @@ -1141,7 +1142,7 @@ void Planner::recalculate_trapezoids() { // Get the pointer to the block block_t *prev = &block_buffer[prev_index]; - // If not dealing with a sync or page block, we are done. The last block is not a SYNC or PAGE block. + // It the block is a move, we're done with this loop if (prev->is_move()) break; // Examine the previous block. This and all following are SYNC blocks @@ -1155,7 +1156,7 @@ void Planner::recalculate_trapezoids() { next = &block_buffer[block_index]; - // Skip sync and page blocks + // Only process movement blocks if (next->is_move()) { next_entry_speed = SQRT(next->entry_speed_sqr); @@ -2889,7 +2890,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, * Add a block to the buffer that just updates the position, * or in case of LASER_SYNCHRONOUS_M106_M107 the fan PWM */ -void Planner::buffer_sync_block(TERN_(LASER_SYNCHRONOUS_M106_M107, const BlockFlagBit sync_flag)) { +void Planner::buffer_sync_block(TERN_(LASER_SYNCHRONOUS_M106_M107, const BlockFlagBit sync_flag/*=BLOCK_BIT_SYNC_POSITION*/)) { #if DISABLED(LASER_SYNCHRONOUS_M106_M107) constexpr BlockFlagBit sync_flag = BLOCK_BIT_SYNC_POSITION; #endif From f4adc98f0e18c25ccef803d6b363f1c37216b6f4 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Sun, 26 Jun 2022 21:35:23 -0500 Subject: [PATCH 12/18] comments --- Marlin/src/gcode/calibrate/G28.cpp | 4 +-- Marlin/src/gcode/motion/G6.cpp | 2 +- Marlin/src/lcd/menu/menu_advanced.cpp | 8 +++--- Marlin/src/module/planner.cpp | 39 ++++++++++++++++++++------- Marlin/src/module/planner.h | 17 +++++++----- Marlin/src/module/settings.cpp | 2 +- 6 files changed, 47 insertions(+), 25 deletions(-) diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp index 27551fb10911..01c2b13dda53 100644 --- a/Marlin/src/gcode/calibrate/G28.cpp +++ b/Marlin/src/gcode/calibrate/G28.cpp @@ -169,7 +169,7 @@ motion_state.jerk_state = planner.max_jerk; planner.max_jerk.set(0, 0 OPTARG(DELTA, 0)); #endif - planner.reset_acceleration_rates(); + planner.refresh_acceleration_rates(); return motion_state; } @@ -178,7 +178,7 @@ planner.settings.max_acceleration_mm_per_s2[Y_AXIS] = motion_state.acceleration.y; TERN_(DELTA, planner.settings.max_acceleration_mm_per_s2[Z_AXIS] = motion_state.acceleration.z); TERN_(HAS_CLASSIC_JERK, planner.max_jerk = motion_state.jerk_state); - planner.reset_acceleration_rates(); + planner.refresh_acceleration_rates(); } #endif // IMPROVE_HOMING_RELIABILITY diff --git a/Marlin/src/gcode/motion/G6.cpp b/Marlin/src/gcode/motion/G6.cpp index a57a293e06f8..fb6281707b45 100644 --- a/Marlin/src/gcode/motion/G6.cpp +++ b/Marlin/src/gcode/motion/G6.cpp @@ -50,7 +50,7 @@ void GcodeSuite::G6() { // No speed is set, can't schedule the move if (!planner.last_page_step_rate) return; - const page_idx_t page_idx = (page_idx_t) parser.value_ulong(); + const page_idx_t page_idx = (page_idx_t)parser.value_ulong(); uint16_t num_steps = DirectStepping::Config::TOTAL_STEPS; if (parser.seen('S')) num_steps = parser.value_ushort(); diff --git a/Marlin/src/lcd/menu/menu_advanced.cpp b/Marlin/src/lcd/menu/menu_advanced.cpp index a6ebb104076d..a81dfcfcd916 100644 --- a/Marlin/src/lcd/menu/menu_advanced.cpp +++ b/Marlin/src/lcd/menu/menu_advanced.cpp @@ -483,7 +483,7 @@ void menu_backlash(); // M204 T Travel Acceleration EDIT_ITEM_FAST(float5_25, MSG_A_TRAVEL, &planner.settings.travel_acceleration, 25, max_accel); - #define EDIT_AMAX(Q,L) EDIT_ITEM_FAST(long5_25, MSG_AMAX_##Q, &planner.settings.max_acceleration_mm_per_s2[_AXIS(Q)], L, max_accel_edit_scaled[_AXIS(Q)], []{ planner.reset_acceleration_rates(); }) + #define EDIT_AMAX(Q,L) EDIT_ITEM_FAST(long5_25, MSG_AMAX_##Q, &planner.settings.max_acceleration_mm_per_s2[_AXIS(Q)], L, max_accel_edit_scaled[_AXIS(Q)], []{ planner.refresh_acceleration_rates(); }) NUM_AXIS_CODE( EDIT_AMAX(A, 100), EDIT_AMAX(B, 100), EDIT_AMAX(C, 10), EDIT_AMAX(I, 10), EDIT_AMAX(J, 10), EDIT_AMAX(K, 10), @@ -491,14 +491,14 @@ void menu_backlash(); ); #if ENABLED(DISTINCT_E_FACTORS) - EDIT_ITEM_FAST(long5_25, MSG_AMAX_E, &planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(active_extruder)], 100, max_accel_edit_scaled.e, []{ planner.reset_acceleration_rates(); }); + EDIT_ITEM_FAST(long5_25, MSG_AMAX_E, &planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(active_extruder)], 100, max_accel_edit_scaled.e, []{ planner.refresh_acceleration_rates(); }); LOOP_L_N(n, E_STEPPERS) EDIT_ITEM_FAST_N(long5_25, n, MSG_AMAX_EN, &planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(n)], 100, max_accel_edit_scaled.e, []{ if (MenuItemBase::itemIndex == active_extruder) - planner.reset_acceleration_rates(); + planner.refresh_acceleration_rates(); }); #elif E_STEPPERS - EDIT_ITEM_FAST(long5_25, MSG_AMAX_E, &planner.settings.max_acceleration_mm_per_s2[E_AXIS], 100, max_accel_edit_scaled.e, []{ planner.reset_acceleration_rates(); }); + EDIT_ITEM_FAST(long5_25, MSG_AMAX_E, &planner.settings.max_acceleration_mm_per_s2[E_AXIS], 100, max_accel_edit_scaled.e, []{ planner.refresh_acceleration_rates(); }); #endif #ifdef XY_FREQUENCY_LIMIT diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index e755ee1d785f..afa3787ffae2 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -1557,7 +1557,7 @@ void Planner::check_axes_activity() { TERN_(DELTA, settings.max_acceleration_mm_per_s2[Z_AXIS] = saved_motion_state.acceleration.z); TERN_(HAS_CLASSIC_JERK, max_jerk = saved_motion_state.jerk_state); } - reset_acceleration_rates(); + refresh_acceleration_rates(); } #endif @@ -2908,7 +2908,6 @@ void Planner::buffer_sync_block(TERN_(LASER_SYNCHRONOUS_M106_M107, const BlockFl #if ENABLED(BACKLASH_COMPENSATION) LOOP_NUM_AXES(axis) block->position[axis] += backlash.get_applied_steps((AxisEnum)axis); #endif - #if BOTH(HAS_FAN, LASER_SYNCHRONOUS_M106_M107) FANS_LOOP(i) block->fan_speed[i] = thermalManager.fan_speed[i]; #endif @@ -3121,6 +3120,14 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, cons #if ENABLED(DIRECT_STEPPING) + /** + * @brief Add a direct stepping page block to the buffer + * and wake up the Stepper ISR to process it. + * + * @param page_idx Page index provided by G6 I + * @param extruder The extruder to use in the move + * @param num_steps Number of steps to process in the ISR + */ void Planner::buffer_page(const page_idx_t page_idx, const uint8_t extruder, const uint16_t num_steps) { if (!last_page_step_rate) { kill(GET_TEXT_F(MSG_BAD_PAGE_SPEED)); @@ -3130,7 +3137,7 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, cons uint8_t next_buffer_head; block_t * const block = get_next_free_block(next_buffer_head); - block->flag.only(BLOCK_BIT_PAGE); + block->flag.reset(BLOCK_BIT_PAGE); #if HAS_FAN FANS_LOOP(i) block->fan_speed[i] = thermalManager.fan_speed[i]; @@ -3218,6 +3225,12 @@ void Planner::set_machine_position_mm(const abce_pos_t &abce) { } } +/** + * @brief Set the Planner position in mm + * @details Set the Planner position from a native machine position in mm + * + * @param xyze A native (Cartesian) machine position + */ void Planner::set_position_mm(const xyze_pos_t &xyze) { xyze_pos_t machine = xyze; TERN_(HAS_POSITION_MODIFIERS, apply_modifiers(machine, true)); @@ -3253,8 +3266,14 @@ void Planner::set_position_mm(const xyze_pos_t &xyze) { #endif -// Recalculate the steps/s^2 acceleration rates, based on the mm/s^2 -void Planner::reset_acceleration_rates() { +/** + * @brief Recalculate the steps/s^2 acceleration rates, based on the mm/s^2 + * @details Update planner movement factors after a change to certain settings: + * - max_acceleration_steps_per_s2 from settings max_acceleration_mm_per_s2 * axis_steps_per_mm (M201, M92) + * - acceleration_long_cutoff based on the largest max_acceleration_steps_per_s2 (M201) + * - max_e_jerk for all extruders based on junction_deviation_mm (M205 J) + */ +void Planner::refresh_acceleration_rates() { uint32_t highest_rate = 1; LOOP_DISTINCT_AXES(i) { max_acceleration_steps_per_s2[i] = settings.max_acceleration_mm_per_s2[i] * settings.axis_steps_per_mm[i]; @@ -3266,13 +3285,13 @@ void Planner::reset_acceleration_rates() { } /** - * Recalculate 'position' and 'mm_per_step'. - * Must be called whenever settings.axis_steps_per_mm changes! + * @brief Recalculate 'position' and 'mm_per_step'. + * @details Required whenever settings.axis_steps_per_mm changes! */ void Planner::refresh_positioning() { LOOP_DISTINCT_AXES(i) mm_per_step[i] = 1.0f / settings.axis_steps_per_mm[i]; set_position_mm(current_position); - reset_acceleration_rates(); + refresh_acceleration_rates(); } // Apply limits to a variable and give a warning if the value was out of range @@ -3291,7 +3310,7 @@ inline void limit_and_warn(float &val, const AxisEnum axis, PGM_P const setting_ /** * For the specified 'axis' set the Maximum Acceleration to the given value (mm/s^2) * The value may be limited with warning feedback, if configured. - * Calls reset_acceleration_rates to precalculate planner terms in steps. + * Calls refresh_acceleration_rates to precalculate planner terms in steps. * * This hard limit is applied as a block is being added to the planner queue. */ @@ -3309,7 +3328,7 @@ void Planner::set_max_acceleration(const AxisEnum axis, float inMaxAccelMMS2) { settings.max_acceleration_mm_per_s2[axis] = inMaxAccelMMS2; // Update steps per s2 to agree with the units per s2 (since they are used in the planner) - reset_acceleration_rates(); + refresh_acceleration_rates(); } /** diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index de587f3bb0ec..1c8eaa48f046 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -113,6 +113,9 @@ #endif +/** + * Planner block flags as boolean bit fields + */ enum BlockFlagBit { // Recalculate trapezoids on entry junction. For optimization. BLOCK_BIT_RECALCULATE, @@ -139,6 +142,9 @@ enum BlockFlagBit { #endif }; +/** + * Planner block flags as boolean bit fields + */ typedef struct { union { uint8_t bits; @@ -165,17 +171,14 @@ typedef struct { void clear() volatile { bits = 0; } void apply(const uint8_t f) volatile { bits |= f; } void apply(const BlockFlagBit b) volatile { SBI(bits, b); } - void only(const BlockFlagBit b) volatile { bits = _BV(b); } + void reset(const BlockFlagBit b) volatile { bits = _BV(b); } void set_nominal(const bool n) volatile { recalculate = true; if (n) nominal_length = true; } } block_flags_t; - /** - * struct block_t - * - * A single entry in the planner buffer. - * Tracks linear movement over multiple axes. + * A single entry in the planner buffer, used to set up and + * track a coordinated linear motion for one or more axes. * * The "nominal" values are as-specified by G-code, and * may never actually be reached due to acceleration limits. @@ -511,7 +514,7 @@ class Planner { */ // Recalculate steps/s^2 accelerations based on mm/s^2 settings - static void reset_acceleration_rates(); + static void refresh_acceleration_rates(); /** * Recalculate 'position' and 'mm_per_step'. diff --git a/Marlin/src/module/settings.cpp b/Marlin/src/module/settings.cpp index 149b1b6dc1e0..7ee3a87fce39 100644 --- a/Marlin/src/module/settings.cpp +++ b/Marlin/src/module/settings.cpp @@ -592,7 +592,7 @@ void MarlinSettings::postprocess() { xyze_pos_t oldpos = current_position; // steps per s2 needs to be updated to agree with units per s2 - planner.reset_acceleration_rates(); + planner.refresh_acceleration_rates(); // Make sure delta kinematics are updated before refreshing the // planner position so the stepper counts will be set correctly. From ce1eb2ed1dcea8f654f52e22b20d073fcc52c44a Mon Sep 17 00:00:00 2001 From: Tom Brazier Date: Mon, 27 Jun 2022 07:57:34 +0100 Subject: [PATCH 13/18] When printing an arc, tell the planner a safe exit speed after the last block in the queue. This reduces queue recalculation and also allows faster print speeds. --- Marlin/src/gcode/motion/G2_G3.cpp | 17 +++++++- Marlin/src/module/planner.cpp | 67 ++++++++++++++++++------------- Marlin/src/module/planner.h | 14 +++---- 3 files changed, 61 insertions(+), 37 deletions(-) diff --git a/Marlin/src/gcode/motion/G2_G3.cpp b/Marlin/src/gcode/motion/G2_G3.cpp index ade014fcea99..b6c7624bece4 100644 --- a/Marlin/src/gcode/motion/G2_G3.cpp +++ b/Marlin/src/gcode/motion/G2_G3.cpp @@ -214,6 +214,7 @@ void plan_arc( const uint16_t segments = nominal_segment_mm > (MAX_ARC_SEGMENT_MM) ? CEIL(flat_mm / (MAX_ARC_SEGMENT_MM)) : nominal_segment_mm < (MIN_ARC_SEGMENT_MM) ? _MAX(1, FLOOR(flat_mm / (MIN_ARC_SEGMENT_MM))) : nominal_segments; + float segment_mm = flat_mm / segments; #if ENABLED(SCARA_FEEDRATE_SCALING) const float inv_duration = (scaled_fr_mm_s / flat_mm) * segments; @@ -288,6 +289,16 @@ void plan_arc( int8_t arc_recalc_count = N_ARC_CORRECTION; #endif + // An arc can always complete within limits from a speed which... + // a) is <= any configured maximum speed, + // b) does not require centripetal force greater than any configured maximum acceleration, + // c) allows the print head to stop in the remining length of the curve within all configured maximum accelerations. + // The last has to be calculated every time through the loop. + const float limiting_accel = _MIN(planner.settings.max_acceleration_mm_per_s2[axis_p], planner.settings.max_acceleration_mm_per_s2[axis_q]), + limiting_speed = _MIN(planner.settings.max_feedrate_mm_s[axis_p], planner.settings.max_acceleration_mm_per_s2[axis_q]), + limiting_speed_sqr = _MIN(sq(limiting_speed), limiting_accel * radius); + float arc_mm_remaining = flat_mm; + for (uint16_t i = 1; i < segments; i++) { // Iterate (segments-1) times thermalManager.manage_heater(); @@ -342,9 +353,13 @@ void plan_arc( planner.apply_leveling(raw); #endif + // calculate safe speed for stopping by the end of the arc + arc_mm_remaining -= segment_mm; + const float safe_exit_speed_sqr = _MIN(limiting_speed_sqr, 2 * limiting_accel * arc_mm_remaining); + if (!planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, 0 OPTARG(SCARA_FEEDRATE_SCALING, inv_duration) - , i > 1 ? radius : 0 + , i > 1 ? radius : 0, safe_exit_speed_sqr ) ) break; } diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index afa3787ffae2..ed9828f76812 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -926,19 +926,25 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t this requirement when encountered by the Planner::release_current_block() routine during a cycle. NOTE: Since the planner only computes on what's in the planner buffer, some motions with lots of short - line segments, like G2/3 arcs or complex curves, may seem to move slow. This is because there simply isn't - enough combined distance traveled in the entire buffer to accelerate up to the nominal speed and then - decelerate to a complete stop at the end of the buffer, as stated by the guidelines. If this happens and - becomes an annoyance, there are a few simple solutions: (1) Maximize the machine acceleration. The planner - will be able to compute higher velocity profiles within the same combined distance. (2) Maximize line - motion(s) distance per block to a desired tolerance. The more combined distance the planner has to use, - the faster it can go. (3) Maximize the planner buffer size. This also will increase the combined distance - for the planner to compute over. It also increases the number of computations the planner has to perform - to compute an optimal plan, so select carefully. + line segments, like complex curves, may seem to move slow. This is because there simply isn't enough + combined distance traveled in the entire buffer to accelerate up to the nominal speed and then decelerate + to a complete stop at the end of the buffer, as stated by the guidelines. If this happens and becomes an + annoyance, there are a few simple solutions: + (1) Maximize the machine acceleration. The planner will be able to compute higher velocity profiles + within the same combined distance. + (2) Maximize line motion(s) distance per block to a desired tolerance. The more combined distance the + planner has to use, the faster it can go. + (3) Maximize the planner buffer size. This also will increase the combined distance for the planner to + compute over. It also increases the number of computations the planner has to perform to compute an + optimal plan, so select carefully. + (4) Use G2/G3 arcs instead of many short segment. These now inform the planner of a safe exit speed at + the end of the last segment, which alleviates this problem. */ // The kernel called by recalculate() when scanning the plan from last to first entry. -void Planner::reverse_pass_kernel(block_t * const current, const block_t * const next) { +void Planner::reverse_pass_kernel(block_t * const current, const block_t * const next + OPTARG(ARC_SUPPORT, const_float_t safe_exit_speed_sqr) +) { if (current) { // If entry speed is already at the maximum entry speed, and there was no change of speed // in the next block, there is no need to recheck. Block is cruising and there is no need to @@ -958,9 +964,10 @@ void Planner::reverse_pass_kernel(block_t * const current, const block_t * const // the reverse and forward planners, the corresponding block junction speed will always be at the // the maximum junction speed and may always be ignored for any speed reduction checks. - const float new_entry_speed_sqr = current->flag.nominal_length - ? max_entry_speed_sqr - : _MIN(max_entry_speed_sqr, max_allowable_speed_sqr(-current->acceleration, next ? next->entry_speed_sqr : sq(float(MINIMUM_PLANNER_SPEED)), current->millimeters)); + const float next_entry_speed_sqr = next ? next->entry_speed_sqr : TERN_(ARC_SUPPORT, safe_exit_speed_sqr > 0.0 ? safe_exit_speed_sqr : ) sq(float(MINIMUM_PLANNER_SPEED)), + new_entry_speed_sqr = current->flag.nominal_length + ? max_entry_speed_sqr + : _MIN(max_entry_speed_sqr, max_allowable_speed_sqr(-current->acceleration, next_entry_speed_sqr, current->millimeters)); if (current->entry_speed_sqr != new_entry_speed_sqr) { // Need to recalculate the block speed - Mark it now, so the stepper @@ -989,7 +996,7 @@ void Planner::reverse_pass_kernel(block_t * const current, const block_t * const * recalculate() needs to go over the current plan twice. * Once in reverse and once forward. This implements the reverse pass. */ -void Planner::reverse_pass() { +void Planner::reverse_pass(TERN_(ARC_SUPPORT, const_float_t safe_exit_speed_sqr)) { // Initialize block index to the last block in the planner buffer. uint8_t block_index = prev_block_index(block_buffer_head); @@ -1013,7 +1020,7 @@ void Planner::reverse_pass() { // Only process movement blocks if (current->is_move()) { - reverse_pass_kernel(current, next); + reverse_pass_kernel(current, next OPTARG(ARC_SUPPORT, safe_exit_speed_sqr)); next = current; } @@ -1126,7 +1133,7 @@ void Planner::forward_pass() { * according to the entry_factor for each junction. Must be called by * recalculate() after updating the blocks. */ -void Planner::recalculate_trapezoids() { +void Planner::recalculate_trapezoids(TERN_(ARC_SUPPORT, const_float_t safe_exit_speed_sqr)) { // The tail may be changed by the ISR so get a local copy. uint8_t block_index = block_buffer_tail, head_block_index = block_buffer_head; @@ -1200,8 +1207,10 @@ void Planner::recalculate_trapezoids() { block_index = next_block_index(block_index); } - // Last/newest block in buffer. Exit speed is set with MINIMUM_PLANNER_SPEED. Always recalculated. + // Last/newest block in buffer. Always recalculated. if (block) { + // Exit speed is set with MINIMUM_PLANNER_SPEED unless some code higher up knows better. + next_entry_speed = TERN_(ARC_SUPPORT, safe_exit_speed_sqr > 0.0 ? SQRT(safe_exit_speed_sqr) : ) float(MINIMUM_PLANNER_SPEED); // Mark the last block as RECALCULATE, to prevent the Stepper ISR running it. // As the last block is always recalculated here, there is a chance the block isn't @@ -1216,12 +1225,12 @@ void Planner::recalculate_trapezoids() { const float current_nominal_speed = SQRT(block->nominal_speed_sqr), nomr = 1.0f / current_nominal_speed; - calculate_trapezoid_for_block(block, current_entry_speed * nomr, float(MINIMUM_PLANNER_SPEED) * nomr); + calculate_trapezoid_for_block(block, current_entry_speed * nomr, next_entry_speed * nomr); #if ENABLED(LIN_ADVANCE) if (block->use_advance_lead) { const float comp = block->e_D_ratio * extruder_advance_K[active_extruder] * settings.axis_steps_per_mm[E_AXIS]; block->max_adv_steps = current_nominal_speed * comp; - block->final_adv_steps = (MINIMUM_PLANNER_SPEED) * comp; + block->final_adv_steps = next_entry_speed * comp; } #endif } @@ -1232,15 +1241,15 @@ void Planner::recalculate_trapezoids() { } } -void Planner::recalculate() { +void Planner::recalculate(TERN_(ARC_SUPPORT, const_float_t safe_exit_speed_sqr)) { // Initialize block index to the last block in the planner buffer. const uint8_t block_index = prev_block_index(block_buffer_head); // If there is just one block, no planning can be done. Avoid it! if (block_index != block_buffer_planned) { - reverse_pass(); + reverse_pass(TERN_(ARC_SUPPORT, safe_exit_speed_sqr)); forward_pass(); } - recalculate_trapezoids(); + recalculate_trapezoids(TERN_(ARC_SUPPORT, safe_exit_speed_sqr)); } /** @@ -1782,7 +1791,7 @@ bool Planner::_buffer_steps(const xyze_long_t &target OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters/*=0.0*/ - OPTARG(ARC_SUPPORT, const_float_t arc_radius/*=0.0*/) + OPTARG(ARC_SUPPORT, const_float_t arc_radius/*=0.0*/) OPTARG(ARC_SUPPORT, const_float_t safe_exit_speed_sqr/*=0.0*/) ) { // Wait for the next available block @@ -1821,7 +1830,7 @@ bool Planner::_buffer_steps(const xyze_long_t &target block_buffer_head = next_buffer_head; // Recalculate and optimize trapezoidal speed profiles - recalculate(); + recalculate(TERN_(ARC_SUPPORT, safe_exit_speed_sqr)); // Movement successfully queued! return true; @@ -2944,7 +2953,7 @@ void Planner::buffer_sync_block(TERN_(LASER_SYNCHRONOUS_M106_M107, const BlockFl bool Planner::buffer_segment(const abce_pos_t &abce OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , const_feedRate_t fr_mm_s, const uint8_t extruder/*=active_extruder*/, const_float_t millimeters/*=0.0*/ - OPTARG(ARC_SUPPORT, const_float_t arc_radius/*=0.0*/) + OPTARG(ARC_SUPPORT, const_float_t arc_radius/*=0.0*/) OPTARG(ARC_SUPPORT, const_float_t safe_exit_speed_sqr/*=0.0*/) ) { // If we are cleaning, do not accept queuing of movements @@ -3051,7 +3060,7 @@ bool Planner::buffer_segment(const abce_pos_t &abce OPTARG(HAS_POSITION_FLOAT, target_float) OPTARG(HAS_DIST_MM_ARG, cart_dist_mm) , fr_mm_s, extruder, millimeters - OPTARG(ARC_SUPPORT, arc_radius) + OPTARG(ARC_SUPPORT, arc_radius) OPTARG(ARC_SUPPORT, safe_exit_speed_sqr) )) return false; stepper.wake_up(); @@ -3071,7 +3080,7 @@ bool Planner::buffer_segment(const abce_pos_t &abce */ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, const uint8_t extruder/*=active_extruder*/, const float millimeters/*=0.0*/ OPTARG(SCARA_FEEDRATE_SCALING, const_float_t inv_duration/*=0.0*/) - OPTARG(ARC_SUPPORT, const_float_t arc_radius/*=0.0*/) + OPTARG(ARC_SUPPORT, const_float_t arc_radius/*=0.0*/) OPTARG(ARC_SUPPORT, const_float_t safe_exit_speed_sqr/*=0.0*/) ) { xyze_pos_t machine = cart; TERN_(HAS_POSITION_MODIFIERS, apply_modifiers(machine)); @@ -3108,13 +3117,13 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, cons const feedRate_t feedrate = fr_mm_s; #endif TERN_(HAS_EXTRUDERS, delta.e = machine.e); - if (buffer_segment(delta OPTARG(HAS_DIST_MM_ARG, cart_dist_mm), feedrate, extruder, mm OPTARG(ARC_SUPPORT, arc_radius))) { + if (buffer_segment(delta OPTARG(HAS_DIST_MM_ARG, cart_dist_mm), feedrate, extruder, mm OPTARG(ARC_SUPPORT, arc_radius) OPTARG(ARC_SUPPORT, safe_exit_speed_sqr))) { position_cart = cart; return true; } return false; #else - return buffer_segment(machine, fr_mm_s, extruder, millimeters OPTARG(ARC_SUPPORT, arc_radius)); + return buffer_segment(machine, fr_mm_s, extruder, millimeters OPTARG(ARC_SUPPORT, arc_radius) OPTARG(ARC_SUPPORT, safe_exit_speed_sqr)); #endif } // buffer_line() diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index 1c8eaa48f046..b37e94796076 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -755,7 +755,7 @@ class Planner { OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters=0.0 - OPTARG(ARC_SUPPORT, const_float_t arc_radius=0.0) + OPTARG(ARC_SUPPORT, const_float_t arc_radius=0.0) OPTARG(ARC_SUPPORT, const_float_t safe_exit_speed_sqr=0.0) ); /** @@ -808,7 +808,7 @@ class Planner { static bool buffer_segment(const abce_pos_t &abce OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , const_feedRate_t fr_mm_s, const uint8_t extruder=active_extruder, const_float_t millimeters=0.0 - OPTARG(ARC_SUPPORT, const_float_t arc_radius=0.0) + OPTARG(ARC_SUPPORT, const_float_t arc_radius=0.0) OPTARG(ARC_SUPPORT, const_float_t safe_exit_speed_sqr=0.0) ); public: @@ -826,7 +826,7 @@ class Planner { */ static bool buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, const uint8_t extruder=active_extruder, const float millimeters=0.0 OPTARG(SCARA_FEEDRATE_SCALING, const_float_t inv_duration=0.0) - OPTARG(ARC_SUPPORT, const_float_t arc_radius=0.0) + OPTARG(ARC_SUPPORT, const_float_t arc_radius=0.0) OPTARG(ARC_SUPPORT, const_float_t safe_exit_speed_sqr=0.0) ); #if ENABLED(DIRECT_STEPPING) @@ -1019,15 +1019,15 @@ class Planner { static void calculate_trapezoid_for_block(block_t * const block, const_float_t entry_factor, const_float_t exit_factor); - static void reverse_pass_kernel(block_t * const current, const block_t * const next); + static void reverse_pass_kernel(block_t * const current, const block_t * const next OPTARG(ARC_SUPPORT, const_float_t safe_exit_speed_sqr)); static void forward_pass_kernel(const block_t * const previous, block_t * const current, uint8_t block_index); - static void reverse_pass(); + static void reverse_pass(TERN_(ARC_SUPPORT, const_float_t safe_exit_speed_sqr)); static void forward_pass(); - static void recalculate_trapezoids(); + static void recalculate_trapezoids(TERN_(ARC_SUPPORT, const_float_t safe_exit_speed_sqr)); - static void recalculate(); + static void recalculate(TERN_(ARC_SUPPORT, const_float_t safe_exit_speed_sqr)); #if HAS_JUNCTION_DEVIATION From e639249faa064c17d3f09b3dcb0897fe895e95d8 Mon Sep 17 00:00:00 2001 From: Tom Brazier Date: Mon, 27 Jun 2022 10:38:42 +0100 Subject: [PATCH 14/18] Cleaned up proliferation OPTARGS for the planner --- .../src/feature/bedlevel/ubl/ubl_motion.cpp | 11 +-- Marlin/src/gcode/motion/G2_G3.cpp | 6 +- Marlin/src/module/motion.cpp | 12 ++-- Marlin/src/module/planner.cpp | 67 +++++++++---------- Marlin/src/module/planner.h | 51 ++++++++++---- 5 files changed, 85 insertions(+), 62 deletions(-) diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp index 9fa2257dc8a6..d63eb1f9115e 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp @@ -392,12 +392,12 @@ if (!planner.leveling_active || !planner.leveling_active_at_z(destination.z)) { while (--segments) { raw += diff; - planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, segment_xyz_mm - OPTARG(SCARA_FEEDRATE_SCALING, inv_duration) + planner.buffer_line(raw, scaled_fr_mm_s, active_extruder + , planner_hints_t(segment_xyz_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)) ); } - planner.buffer_line(destination, scaled_fr_mm_s, active_extruder, segment_xyz_mm - OPTARG(SCARA_FEEDRATE_SCALING, inv_duration) + planner.buffer_line(destination, scaled_fr_mm_s, active_extruder + , planner_hints_t(segment_xyz_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)) ); return false; // Did not set current from destination } @@ -467,7 +467,8 @@ TERN_(ENABLE_LEVELING_FADE_HEIGHT, * fade_scaling_factor); // apply fade factor to interpolated height const float oldz = raw.z; raw.z += z_cxcy; - planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, segment_xyz_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration) ); + planner.buffer_line(raw, scaled_fr_mm_s, active_extruder + , planner_hints_t(segment_xyz_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration))); raw.z = oldz; if (segments == 0) // done with last segment diff --git a/Marlin/src/gcode/motion/G2_G3.cpp b/Marlin/src/gcode/motion/G2_G3.cpp index b6c7624bece4..f9134f2b2a28 100644 --- a/Marlin/src/gcode/motion/G2_G3.cpp +++ b/Marlin/src/gcode/motion/G2_G3.cpp @@ -357,10 +357,8 @@ void plan_arc( arc_mm_remaining -= segment_mm; const float safe_exit_speed_sqr = _MIN(limiting_speed_sqr, 2 * limiting_accel * arc_mm_remaining); - if (!planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, 0 - OPTARG(SCARA_FEEDRATE_SCALING, inv_duration) - , i > 1 ? radius : 0, safe_exit_speed_sqr - ) + if (!planner.buffer_line(raw, scaled_fr_mm_s, active_extruder + , planner_hints_t(0 OPTARG(SCARA_FEEDRATE_SCALING, inv_duration), i > 1 ? radius : 0, safe_exit_speed_sqr)) ) break; } } diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 36afdb2e485f..48c6422e4125 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -1065,11 +1065,13 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) { while (--segments) { segment_idle(next_idle_ms); raw += segment_distance; - if (!planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration))) break; + if (!planner.buffer_line(raw, scaled_fr_mm_s, active_extruder + , planner_hints_t(cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)))) break; } // Ensure last segment arrives at target location. - planner.buffer_line(destination, scaled_fr_mm_s, active_extruder, cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)); + planner.buffer_line(destination, scaled_fr_mm_s, active_extruder + , planner_hints_t(cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration))); return false; // caller will update current_position } @@ -1128,12 +1130,14 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) { while (--segments) { segment_idle(next_idle_ms); raw += segment_distance; - if (!planner.buffer_line(raw, fr_mm_s, active_extruder, cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration))) break; + if (!planner.buffer_line(raw, fr_mm_s, active_extruder + , planner_hints_t(cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)))) break; } // Since segment_distance is only approximate, // the final move must be to the exact destination. - planner.buffer_line(destination, fr_mm_s, active_extruder, cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)); + planner.buffer_line(destination, fr_mm_s, active_extruder + , planner_hints_t(cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration))); } #endif // SEGMENT_LEVELED_MOVES && !AUTO_BED_LEVELING_UBL diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index ed9828f76812..be2a4a17dea5 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -943,7 +943,7 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t // The kernel called by recalculate() when scanning the plan from last to first entry. void Planner::reverse_pass_kernel(block_t * const current, const block_t * const next - OPTARG(ARC_SUPPORT, const_float_t safe_exit_speed_sqr) + OPTARG(HINTS_SAFE_EXIT_SPEED, const_float_t safe_exit_speed_sqr) ) { if (current) { // If entry speed is already at the maximum entry speed, and there was no change of speed @@ -964,7 +964,7 @@ void Planner::reverse_pass_kernel(block_t * const current, const block_t * const // the reverse and forward planners, the corresponding block junction speed will always be at the // the maximum junction speed and may always be ignored for any speed reduction checks. - const float next_entry_speed_sqr = next ? next->entry_speed_sqr : TERN_(ARC_SUPPORT, safe_exit_speed_sqr > 0.0 ? safe_exit_speed_sqr : ) sq(float(MINIMUM_PLANNER_SPEED)), + const float next_entry_speed_sqr = next ? next->entry_speed_sqr : TERN_(HINTS_SAFE_EXIT_SPEED, safe_exit_speed_sqr > 0.0 ? safe_exit_speed_sqr : ) sq(float(MINIMUM_PLANNER_SPEED)), new_entry_speed_sqr = current->flag.nominal_length ? max_entry_speed_sqr : _MIN(max_entry_speed_sqr, max_allowable_speed_sqr(-current->acceleration, next_entry_speed_sqr, current->millimeters)); @@ -996,7 +996,7 @@ void Planner::reverse_pass_kernel(block_t * const current, const block_t * const * recalculate() needs to go over the current plan twice. * Once in reverse and once forward. This implements the reverse pass. */ -void Planner::reverse_pass(TERN_(ARC_SUPPORT, const_float_t safe_exit_speed_sqr)) { +void Planner::reverse_pass(TERN_(HINTS_SAFE_EXIT_SPEED, const_float_t safe_exit_speed_sqr)) { // Initialize block index to the last block in the planner buffer. uint8_t block_index = prev_block_index(block_buffer_head); @@ -1020,7 +1020,7 @@ void Planner::reverse_pass(TERN_(ARC_SUPPORT, const_float_t safe_exit_speed_sqr) // Only process movement blocks if (current->is_move()) { - reverse_pass_kernel(current, next OPTARG(ARC_SUPPORT, safe_exit_speed_sqr)); + reverse_pass_kernel(current, next OPTARG(HINTS_SAFE_EXIT_SPEED, safe_exit_speed_sqr)); next = current; } @@ -1133,7 +1133,7 @@ void Planner::forward_pass() { * according to the entry_factor for each junction. Must be called by * recalculate() after updating the blocks. */ -void Planner::recalculate_trapezoids(TERN_(ARC_SUPPORT, const_float_t safe_exit_speed_sqr)) { +void Planner::recalculate_trapezoids(TERN_(HINTS_SAFE_EXIT_SPEED, const_float_t safe_exit_speed_sqr)) { // The tail may be changed by the ISR so get a local copy. uint8_t block_index = block_buffer_tail, head_block_index = block_buffer_head; @@ -1210,7 +1210,7 @@ void Planner::recalculate_trapezoids(TERN_(ARC_SUPPORT, const_float_t safe_exit_ // Last/newest block in buffer. Always recalculated. if (block) { // Exit speed is set with MINIMUM_PLANNER_SPEED unless some code higher up knows better. - next_entry_speed = TERN_(ARC_SUPPORT, safe_exit_speed_sqr > 0.0 ? SQRT(safe_exit_speed_sqr) : ) float(MINIMUM_PLANNER_SPEED); + next_entry_speed = TERN_(HINTS_SAFE_EXIT_SPEED, safe_exit_speed_sqr > 0.0 ? SQRT(safe_exit_speed_sqr) : ) float(MINIMUM_PLANNER_SPEED); // Mark the last block as RECALCULATE, to prevent the Stepper ISR running it. // As the last block is always recalculated here, there is a chance the block isn't @@ -1241,15 +1241,15 @@ void Planner::recalculate_trapezoids(TERN_(ARC_SUPPORT, const_float_t safe_exit_ } } -void Planner::recalculate(TERN_(ARC_SUPPORT, const_float_t safe_exit_speed_sqr)) { +void Planner::recalculate(TERN_(HINTS_SAFE_EXIT_SPEED, const_float_t safe_exit_speed_sqr)) { // Initialize block index to the last block in the planner buffer. const uint8_t block_index = prev_block_index(block_buffer_head); // If there is just one block, no planning can be done. Avoid it! if (block_index != block_buffer_planned) { - reverse_pass(TERN_(ARC_SUPPORT, safe_exit_speed_sqr)); + reverse_pass(TERN_(HINTS_SAFE_EXIT_SPEED, safe_exit_speed_sqr)); forward_pass(); } - recalculate_trapezoids(TERN_(ARC_SUPPORT, safe_exit_speed_sqr)); + recalculate_trapezoids(TERN_(HINTS_SAFE_EXIT_SPEED, safe_exit_speed_sqr)); } /** @@ -1783,15 +1783,14 @@ void Planner::synchronize() { while (busy()) idle(); } * target_float - target position in direct (mm, degrees) units. optional * fr_mm_s - (target) speed of the move * extruder - target extruder - * millimeters - the length of the movement, if known + * hints - optional parameters to aid planner's calculations * * Returns true if movement was properly queued, false otherwise (if cleaning) */ bool Planner::_buffer_steps(const xyze_long_t &target OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) - , feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters/*=0.0*/ - OPTARG(ARC_SUPPORT, const_float_t arc_radius/*=0.0*/) OPTARG(ARC_SUPPORT, const_float_t safe_exit_speed_sqr/*=0.0*/) + , feedRate_t fr_mm_s, const uint8_t extruder, const planner_hints_t &hints ) { // Wait for the next available block @@ -1807,8 +1806,7 @@ bool Planner::_buffer_steps(const xyze_long_t &target if (!_populate_block(block, false, target OPTARG(HAS_POSITION_FLOAT, target_float) OPTARG(HAS_DIST_MM_ARG, cart_dist_mm) - , fr_mm_s, extruder, millimeters - OPTARG(ARC_SUPPORT, arc_radius) + , fr_mm_s, extruder, hints ) ) { // Movement was not queued, probably because it was too short. @@ -1830,7 +1828,7 @@ bool Planner::_buffer_steps(const xyze_long_t &target block_buffer_head = next_buffer_head; // Recalculate and optimize trapezoidal speed profiles - recalculate(TERN_(ARC_SUPPORT, safe_exit_speed_sqr)); + recalculate(TERN_(HINTS_SAFE_EXIT_SPEED, hints.safe_exit_speed_sqr)); // Movement successfully queued! return true; @@ -1844,6 +1842,7 @@ bool Planner::_buffer_steps(const xyze_long_t &target * target - target position in steps units * fr_mm_s - (target) speed of the move * extruder - target extruder + * hints - optional parameters to aid planner's calculations * * Returns true if movement is acceptable, false otherwise */ @@ -1851,8 +1850,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, const abce_long_t &target OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) - , feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters/*=0.0*/ - OPTARG(ARC_SUPPORT, const_float_t arc_radius/*=0.0*/) + , feedRate_t fr_mm_s, const uint8_t extruder, const planner_hints_t &hints ) { int32_t LOGICAL_AXIS_LIST( de = target.e - position.e, @@ -2077,8 +2075,8 @@ bool Planner::_populate_block(block_t * const block, bool split_move, block->millimeters = TERN0(HAS_EXTRUDERS, ABS(steps_dist_mm.e)); } else { - if (millimeters) - block->millimeters = millimeters; + if (hints.millimeters) + block->millimeters = hints.millimeters; else { /** * Distance for interpretation of feedrate in accordance with LinuxCNC (the successor of NIST @@ -2637,8 +2635,8 @@ bool Planner::_populate_block(block_t * const block, bool split_move, const float junction_acceleration = limit_value_by_axis_maximum(block->acceleration, junction_unit_vec); - if (TERN0(ARC_SUPPORT, arc_radius)) { - TERN_(ARC_SUPPORT, vmax_junction_sqr = junction_acceleration * arc_radius); + if (TERN0(HINTS_CURVE_RADIUS, hints.curve_radius)) { + TERN_(HINTS_CURVE_RADIUS, vmax_junction_sqr = junction_acceleration * hints.curve_radius); } else { NOLESS(junction_cos_theta, -0.999999f); // Check for numerical round-off to avoid divide by zero. @@ -2946,14 +2944,14 @@ void Planner::buffer_sync_block(TERN_(LASER_SYNCHRONOUS_M106_M107, const BlockFl * a,b,c,e - target positions in mm and/or degrees * fr_mm_s - (target) speed of the move * extruder - target extruder - * millimeters - the length of the movement, if known + * hints - optional parameters to aid planner's calculations * * Return 'false' if no segment was queued due to cleaning, cold extrusion, full queue, etc. */ bool Planner::buffer_segment(const abce_pos_t &abce OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) - , const_feedRate_t fr_mm_s, const uint8_t extruder/*=active_extruder*/, const_float_t millimeters/*=0.0*/ - OPTARG(ARC_SUPPORT, const_float_t arc_radius/*=0.0*/) OPTARG(ARC_SUPPORT, const_float_t safe_exit_speed_sqr/*=0.0*/) + , const_feedRate_t fr_mm_s, const uint8_t extruder/*=active_extruder*/ + , const planner_hints_t &hints/* = planner_hints_t()*/ ) { // If we are cleaning, do not accept queuing of movements @@ -3059,8 +3057,7 @@ bool Planner::buffer_segment(const abce_pos_t &abce if (!_buffer_steps(target OPTARG(HAS_POSITION_FLOAT, target_float) OPTARG(HAS_DIST_MM_ARG, cart_dist_mm) - , fr_mm_s, extruder, millimeters - OPTARG(ARC_SUPPORT, arc_radius) OPTARG(ARC_SUPPORT, safe_exit_speed_sqr) + , fr_mm_s, extruder, hints )) return false; stepper.wake_up(); @@ -3075,12 +3072,10 @@ bool Planner::buffer_segment(const abce_pos_t &abce * cart - target position in mm or degrees * fr_mm_s - (target) speed of the move (mm/s) * extruder - target extruder - * millimeters - the length of the movement, if known - * inv_duration - the reciprocal if the duration of the movement, if known (kinematic only if feeedrate scaling is enabled) + * hints - optional parameters to aid planner's calculations */ -bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, const uint8_t extruder/*=active_extruder*/, const float millimeters/*=0.0*/ - OPTARG(SCARA_FEEDRATE_SCALING, const_float_t inv_duration/*=0.0*/) - OPTARG(ARC_SUPPORT, const_float_t arc_radius/*=0.0*/) OPTARG(ARC_SUPPORT, const_float_t safe_exit_speed_sqr/*=0.0*/) +bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s + , const uint8_t extruder/*=active_extruder*/, const planner_hints_t &hints/*=planner_hints_t()*/ ) { xyze_pos_t machine = cart; TERN_(HAS_POSITION_MODIFIERS, apply_modifiers(machine)); @@ -3102,7 +3097,9 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, cons ); #endif - const float mm = millimeters ?: (cart_dist_mm.x || cart_dist_mm.y) ? cart_dist_mm.magnitude() : TERN0(HAS_Z_AXIS, ABS(cart_dist_mm.z)); + planner_hints_t _hints(hints); + if (!_hints.millimeters) + _hints.millimeters = (cart_dist_mm.x || cart_dist_mm.y) ? cart_dist_mm.magnitude() : TERN0(HAS_Z_AXIS, ABS(cart_dist_mm.z)); // Cartesian XYZ to kinematic ABC, stored in global 'delta' inverse_kinematics(machine); @@ -3110,20 +3107,20 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, cons #if ENABLED(SCARA_FEEDRATE_SCALING) // For SCARA scale the feed rate from mm/s to degrees/s // i.e., Complete the angular vector in the given time. - const float duration_recip = inv_duration ?: fr_mm_s / mm; + const float duration_recip = hints.inv_duration ?: fr_mm_s / _hints.millimeters; const xyz_pos_t diff = delta - position_float; const feedRate_t feedrate = diff.magnitude() * duration_recip; #else const feedRate_t feedrate = fr_mm_s; #endif TERN_(HAS_EXTRUDERS, delta.e = machine.e); - if (buffer_segment(delta OPTARG(HAS_DIST_MM_ARG, cart_dist_mm), feedrate, extruder, mm OPTARG(ARC_SUPPORT, arc_radius) OPTARG(ARC_SUPPORT, safe_exit_speed_sqr))) { + if (buffer_segment(delta OPTARG(HAS_DIST_MM_ARG, cart_dist_mm), feedrate, extruder, _hints)) { position_cart = cart; return true; } return false; #else - return buffer_segment(machine, fr_mm_s, extruder, millimeters OPTARG(ARC_SUPPORT, arc_radius) OPTARG(ARC_SUPPORT, safe_exit_speed_sqr)); + return buffer_segment(machine, fr_mm_s, extruder, hints); #endif } // buffer_line() diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index b37e94796076..71fa4fbd0757 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -344,6 +344,33 @@ typedef struct { typedef IF<(BLOCK_BUFFER_SIZE > 64), uint16_t, uint8_t>::type last_move_t; #endif +#if ENABLED(ARC_SUPPORT) + #define HINTS_CURVE_RADIUS + #define HINTS_SAFE_EXIT_SPEED +#endif + +struct planner_hints_t { + // the length of the movement, if known + float millimeters = 0.0; + // the reciprocal if the duration of the movement, if known (kinematic only if feeedrate scaling is enabled) + TERN_(SCARA_FEEDRATE_SCALING, float inv_duration = 0.0); + // the radius of curvature of the tool head path - for cornering speed calculation + TERN_(HINTS_CURVE_RADIUS, float curve_radius = 0.0); + // the square of the speed which would be "safe" at the end of this segment, i.e. <= the exit speed + // of the segment that the planner would calculate of it knew the as yet unbuffered path + TERN_(HINTS_SAFE_EXIT_SPEED, float safe_exit_speed_sqr = 0.0); + + planner_hints_t(float _millimeters = 0.0 + OPTARG(SCARA_FEEDRATE_SCALING, const_float_t _inv_duration = 0.0) + OPTARG(HINTS_CURVE_RADIUS, const_float_t _curve_radius = 0.0) + OPTARG (HINTS_SAFE_EXIT_SPEED, const_float_t _safe_exit_speed_sqr = 0.0) + ) : millimeters(_millimeters) + OPTARG(SCARA_FEEDRATE_SCALING, inv_duration(_inv_duration)) + OPTARG(HINTS_CURVE_RADIUS, curve_radius(_curve_radius)) + OPTARG (HINTS_SAFE_EXIT_SPEED, safe_exit_speed_sqr(_safe_exit_speed_sqr)) + {} +}; + class Planner { public: @@ -747,15 +774,14 @@ class Planner { * target - target position in steps units * fr_mm_s - (target) speed of the move * extruder - target extruder - * millimeters - the length of the movement, if known + * hints - optional parameters to aid planner's calculations * * Returns true if movement was buffered, false otherwise */ static bool _buffer_steps(const xyze_long_t &target OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) - , feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters=0.0 - OPTARG(ARC_SUPPORT, const_float_t arc_radius=0.0) OPTARG(ARC_SUPPORT, const_float_t safe_exit_speed_sqr=0.0) + , feedRate_t fr_mm_s, const uint8_t extruder, const planner_hints_t &hints ); /** @@ -766,15 +792,14 @@ class Planner { * target - target position in steps units * fr_mm_s - (target) speed of the move * extruder - target extruder - * millimeters - the length of the movement, if known + * hints - optional parameters to aid planner's calculations * * Returns true is movement is acceptable, false otherwise */ static bool _populate_block(block_t * const block, bool split_move, const xyze_long_t &target OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) - , feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters=0.0 - OPTARG(ARC_SUPPORT, const_float_t arc_radius=0.0) + , feedRate_t fr_mm_s, const uint8_t extruder, const planner_hints_t &hints ); /** @@ -803,12 +828,12 @@ class Planner { * a,b,c,e - target positions in mm and/or degrees * fr_mm_s - (target) speed of the move * extruder - target extruder - * millimeters - the length of the movement, if known + * hints - optional parameters to aid planner's calculations */ static bool buffer_segment(const abce_pos_t &abce OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) - , const_feedRate_t fr_mm_s, const uint8_t extruder=active_extruder, const_float_t millimeters=0.0 - OPTARG(ARC_SUPPORT, const_float_t arc_radius=0.0) OPTARG(ARC_SUPPORT, const_float_t safe_exit_speed_sqr=0.0) + , const_feedRate_t fr_mm_s, const uint8_t extruder=active_extruder + , const planner_hints_t &hints = planner_hints_t() ); public: @@ -821,12 +846,10 @@ class Planner { * cart - target position in mm or degrees * fr_mm_s - (target) speed of the move (mm/s) * extruder - target extruder - * millimeters - the length of the movement, if known - * inv_duration - the reciprocal if the duration of the movement, if known (kinematic only if feeedrate scaling is enabled) + * hints - optional parameters to aid planner's calculations */ - static bool buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, const uint8_t extruder=active_extruder, const float millimeters=0.0 - OPTARG(SCARA_FEEDRATE_SCALING, const_float_t inv_duration=0.0) - OPTARG(ARC_SUPPORT, const_float_t arc_radius=0.0) OPTARG(ARC_SUPPORT, const_float_t safe_exit_speed_sqr=0.0) + static bool buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, + const uint8_t extruder=active_extruder, const planner_hints_t &hints=planner_hints_t() ); #if ENABLED(DIRECT_STEPPING) From 4f1f87fb32475530f87c639d58f30ac9aea55313 Mon Sep 17 00:00:00 2001 From: Tom Brazier Date: Mon, 27 Jun 2022 11:55:43 +0100 Subject: [PATCH 15/18] Don't do below MINIMUM_PLANNER_SPEED --- Marlin/src/module/planner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index be2a4a17dea5..883b5e2de285 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -964,7 +964,7 @@ void Planner::reverse_pass_kernel(block_t * const current, const block_t * const // the reverse and forward planners, the corresponding block junction speed will always be at the // the maximum junction speed and may always be ignored for any speed reduction checks. - const float next_entry_speed_sqr = next ? next->entry_speed_sqr : TERN_(HINTS_SAFE_EXIT_SPEED, safe_exit_speed_sqr > 0.0 ? safe_exit_speed_sqr : ) sq(float(MINIMUM_PLANNER_SPEED)), + const float next_entry_speed_sqr = next ? next->entry_speed_sqr : _MAX(TERN0(HINTS_SAFE_EXIT_SPEED, safe_exit_speed_sqr), sq(float(MINIMUM_PLANNER_SPEED))), new_entry_speed_sqr = current->flag.nominal_length ? max_entry_speed_sqr : _MIN(max_entry_speed_sqr, max_allowable_speed_sqr(-current->acceleration, next_entry_speed_sqr, current->millimeters)); @@ -1210,7 +1210,7 @@ void Planner::recalculate_trapezoids(TERN_(HINTS_SAFE_EXIT_SPEED, const_float_t // Last/newest block in buffer. Always recalculated. if (block) { // Exit speed is set with MINIMUM_PLANNER_SPEED unless some code higher up knows better. - next_entry_speed = TERN_(HINTS_SAFE_EXIT_SPEED, safe_exit_speed_sqr > 0.0 ? SQRT(safe_exit_speed_sqr) : ) float(MINIMUM_PLANNER_SPEED); + next_entry_speed = _MAX(TERN0(HINTS_SAFE_EXIT_SPEED, SQRT(safe_exit_speed_sqr)), float(MINIMUM_PLANNER_SPEED)); // Mark the last block as RECALCULATE, to prevent the Stepper ISR running it. // As the last block is always recalculated here, there is a chance the block isn't From 9413cd8ace5db633ec3579184f98e4162332b61a Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 30 Jun 2022 22:29:07 -0500 Subject: [PATCH 16/18] better with a ClassLike name --- .../src/feature/bedlevel/ubl/ubl_motion.cpp | 6 ++-- Marlin/src/gcode/motion/G2_G3.cpp | 2 +- Marlin/src/module/motion.cpp | 8 ++--- Marlin/src/module/planner.cpp | 10 +++---- Marlin/src/module/planner.h | 30 +++++++++++-------- 5 files changed, 31 insertions(+), 25 deletions(-) diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp index d63eb1f9115e..ebd39db3aff2 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp @@ -393,11 +393,11 @@ while (--segments) { raw += diff; planner.buffer_line(raw, scaled_fr_mm_s, active_extruder - , planner_hints_t(segment_xyz_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)) + , PlannerHints(segment_xyz_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)) ); } planner.buffer_line(destination, scaled_fr_mm_s, active_extruder - , planner_hints_t(segment_xyz_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)) + , PlannerHints(segment_xyz_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)) ); return false; // Did not set current from destination } @@ -468,7 +468,7 @@ const float oldz = raw.z; raw.z += z_cxcy; planner.buffer_line(raw, scaled_fr_mm_s, active_extruder - , planner_hints_t(segment_xyz_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration))); + , PlannerHints(segment_xyz_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration))); raw.z = oldz; if (segments == 0) // done with last segment diff --git a/Marlin/src/gcode/motion/G2_G3.cpp b/Marlin/src/gcode/motion/G2_G3.cpp index f9134f2b2a28..e49be88a8a12 100644 --- a/Marlin/src/gcode/motion/G2_G3.cpp +++ b/Marlin/src/gcode/motion/G2_G3.cpp @@ -358,7 +358,7 @@ void plan_arc( const float safe_exit_speed_sqr = _MIN(limiting_speed_sqr, 2 * limiting_accel * arc_mm_remaining); if (!planner.buffer_line(raw, scaled_fr_mm_s, active_extruder - , planner_hints_t(0 OPTARG(SCARA_FEEDRATE_SCALING, inv_duration), i > 1 ? radius : 0, safe_exit_speed_sqr)) + , PlannerHints(0 OPTARG(SCARA_FEEDRATE_SCALING, inv_duration), i > 1 ? radius : 0, safe_exit_speed_sqr)) ) break; } } diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 48c6422e4125..b9e7bc696374 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -1066,12 +1066,12 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) { segment_idle(next_idle_ms); raw += segment_distance; if (!planner.buffer_line(raw, scaled_fr_mm_s, active_extruder - , planner_hints_t(cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)))) break; + , PlannerHints(cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)))) break; } // Ensure last segment arrives at target location. planner.buffer_line(destination, scaled_fr_mm_s, active_extruder - , planner_hints_t(cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration))); + , PlannerHints(cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration))); return false; // caller will update current_position } @@ -1131,13 +1131,13 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) { segment_idle(next_idle_ms); raw += segment_distance; if (!planner.buffer_line(raw, fr_mm_s, active_extruder - , planner_hints_t(cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)))) break; + , PlannerHints(cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)))) break; } // Since segment_distance is only approximate, // the final move must be to the exact destination. planner.buffer_line(destination, fr_mm_s, active_extruder - , planner_hints_t(cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration))); + , PlannerHints(cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration))); } #endif // SEGMENT_LEVELED_MOVES && !AUTO_BED_LEVELING_UBL diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 3d6dc5366b18..1d94e456e6f0 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -1790,7 +1790,7 @@ void Planner::synchronize() { while (busy()) idle(); } bool Planner::_buffer_steps(const xyze_long_t &target OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) - , feedRate_t fr_mm_s, const uint8_t extruder, const planner_hints_t &hints + , feedRate_t fr_mm_s, const uint8_t extruder, const PlannerHints &hints ) { // Wait for the next available block @@ -1850,7 +1850,7 @@ bool Planner::_populate_block(block_t * const block, bool split_move, const abce_long_t &target OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) - , feedRate_t fr_mm_s, const uint8_t extruder, const planner_hints_t &hints + , feedRate_t fr_mm_s, const uint8_t extruder, const PlannerHints &hints ) { int32_t LOGICAL_AXIS_LIST( de = target.e - position.e, @@ -2955,7 +2955,7 @@ void Planner::buffer_sync_block(TERN_(LASER_SYNCHRONOUS_M106_M107, const BlockFl bool Planner::buffer_segment(const abce_pos_t &abce OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , const_feedRate_t fr_mm_s, const uint8_t extruder/*=active_extruder*/ - , const planner_hints_t &hints/* = planner_hints_t()*/ + , const PlannerHints &hints/* = PlannerHints()*/ ) { // If we are cleaning, do not accept queuing of movements @@ -3079,7 +3079,7 @@ bool Planner::buffer_segment(const abce_pos_t &abce * hints - optional parameters to aid planner's calculations */ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s - , const uint8_t extruder/*=active_extruder*/, const planner_hints_t &hints/*=planner_hints_t()*/ + , const uint8_t extruder/*=active_extruder*/, const PlannerHints &hints/*=PlannerHints()*/ ) { xyze_pos_t machine = cart; TERN_(HAS_POSITION_MODIFIERS, apply_modifiers(machine)); @@ -3101,7 +3101,7 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s ); #endif - planner_hints_t _hints(hints); + PlannerHints _hints(hints); if (!_hints.millimeters) _hints.millimeters = (cart_dist_mm.x || cart_dist_mm.y) ? cart_dist_mm.magnitude() : TERN0(HAS_Z_AXIS, ABS(cart_dist_mm.z)); diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index abb7e52d83b2..39e269e70cb6 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -351,21 +351,27 @@ typedef struct { #define HINTS_SAFE_EXIT_SPEED #endif -struct planner_hints_t { +struct PlannerHints { // the length of the movement, if known float millimeters = 0.0; // the reciprocal if the duration of the movement, if known (kinematic only if feeedrate scaling is enabled) - TERN_(SCARA_FEEDRATE_SCALING, float inv_duration = 0.0); + #if ENABLED(SCARA_FEEDRATE_SCALING) + float inv_duration = 0.0; + #endif // the radius of curvature of the tool head path - for cornering speed calculation - TERN_(HINTS_CURVE_RADIUS, float curve_radius = 0.0); + #if ENABLED(HINTS_CURVE_RADIUS) + float curve_radius = 0.0; + #endif // the square of the speed which would be "safe" at the end of this segment, i.e. <= the exit speed // of the segment that the planner would calculate of it knew the as yet unbuffered path - TERN_(HINTS_SAFE_EXIT_SPEED, float safe_exit_speed_sqr = 0.0); + #if ENABLED(HINTS_SAFE_EXIT_SPEED) + float safe_exit_speed_sqr = 0.0; + #endif - planner_hints_t(float _millimeters = 0.0 - OPTARG(SCARA_FEEDRATE_SCALING, const_float_t _inv_duration = 0.0) - OPTARG(HINTS_CURVE_RADIUS, const_float_t _curve_radius = 0.0) - OPTARG (HINTS_SAFE_EXIT_SPEED, const_float_t _safe_exit_speed_sqr = 0.0) + PlannerHints(float _millimeters = 0.0 + OPTARG(SCARA_FEEDRATE_SCALING, const_float_t _inv_duration = 0.0) + OPTARG(HINTS_CURVE_RADIUS, const_float_t _curve_radius = 0.0) + OPTARG (HINTS_SAFE_EXIT_SPEED, const_float_t _safe_exit_speed_sqr = 0.0) ) : millimeters(_millimeters) OPTARG(SCARA_FEEDRATE_SCALING, inv_duration(_inv_duration)) OPTARG(HINTS_CURVE_RADIUS, curve_radius(_curve_radius)) @@ -783,7 +789,7 @@ class Planner { static bool _buffer_steps(const xyze_long_t &target OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) - , feedRate_t fr_mm_s, const uint8_t extruder, const planner_hints_t &hints + , feedRate_t fr_mm_s, const uint8_t extruder, const PlannerHints &hints ); /** @@ -801,7 +807,7 @@ class Planner { static bool _populate_block(block_t * const block, bool split_move, const xyze_long_t &target OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) - , feedRate_t fr_mm_s, const uint8_t extruder, const planner_hints_t &hints + , feedRate_t fr_mm_s, const uint8_t extruder, const PlannerHints &hints ); /** @@ -835,7 +841,7 @@ class Planner { static bool buffer_segment(const abce_pos_t &abce OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) , const_feedRate_t fr_mm_s, const uint8_t extruder=active_extruder - , const planner_hints_t &hints = planner_hints_t() + , const PlannerHints &hints = PlannerHints() ); public: @@ -851,7 +857,7 @@ class Planner { * hints - optional parameters to aid planner's calculations */ static bool buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, - const uint8_t extruder=active_extruder, const planner_hints_t &hints=planner_hints_t() + const uint8_t extruder=active_extruder, const PlannerHints &hints=PlannerHints() ); #if ENABLED(DIRECT_STEPPING) From 8e293f06a02fce899ddb5865dc585e0cefe03dfd Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 30 Jun 2022 23:10:16 -0500 Subject: [PATCH 17/18] adjust code style --- .../src/feature/bedlevel/ubl/ubl_motion.cpp | 19 ++++------ Marlin/src/gcode/motion/G2_G3.cpp | 18 +++++---- Marlin/src/module/motion.cpp | 38 +++++++++---------- Marlin/src/module/planner.cpp | 36 ++++++++++-------- Marlin/src/module/planner.h | 27 ++++--------- Marlin/src/module/planner_bezier.cpp | 7 +++- 6 files changed, 70 insertions(+), 75 deletions(-) diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp index ebd39db3aff2..dcd3f1b7b813 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp @@ -374,11 +374,13 @@ #endif NOLESS(segments, 1U); // Must have at least one segment - const float inv_segments = 1.0f / segments, // Reciprocal to save calculation - segment_xyz_mm = SQRT(cart_xy_mm_2 + sq(total.z)) * inv_segments; // Length of each segment + const float inv_segments = 1.0f / segments; // Reciprocal to save calculation + // Add hints to help optimize the move + PlannerHints hints; + hints.millimeters = SQRT(cart_xy_mm_2 + sq(total.z)) * inv_segments; // Length of each segment #if ENABLED(SCARA_FEEDRATE_SCALING) - const float inv_duration = scaled_fr_mm_s / segment_xyz_mm; + hints.inv_duration = scaled_fr_mm_s / hints.millimeters; #endif xyze_float_t diff = total * inv_segments; @@ -392,13 +394,9 @@ if (!planner.leveling_active || !planner.leveling_active_at_z(destination.z)) { while (--segments) { raw += diff; - planner.buffer_line(raw, scaled_fr_mm_s, active_extruder - , PlannerHints(segment_xyz_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)) - ); + planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, hints); } - planner.buffer_line(destination, scaled_fr_mm_s, active_extruder - , PlannerHints(segment_xyz_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)) - ); + planner.buffer_line(destination, scaled_fr_mm_s, active_extruder, hints); return false; // Did not set current from destination } @@ -467,8 +465,7 @@ TERN_(ENABLE_LEVELING_FADE_HEIGHT, * fade_scaling_factor); // apply fade factor to interpolated height const float oldz = raw.z; raw.z += z_cxcy; - planner.buffer_line(raw, scaled_fr_mm_s, active_extruder - , PlannerHints(segment_xyz_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration))); + planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, hints); raw.z = oldz; if (segments == 0) // done with last segment diff --git a/Marlin/src/gcode/motion/G2_G3.cpp b/Marlin/src/gcode/motion/G2_G3.cpp index e49be88a8a12..d8eff80bfbc2 100644 --- a/Marlin/src/gcode/motion/G2_G3.cpp +++ b/Marlin/src/gcode/motion/G2_G3.cpp @@ -214,10 +214,12 @@ void plan_arc( const uint16_t segments = nominal_segment_mm > (MAX_ARC_SEGMENT_MM) ? CEIL(flat_mm / (MAX_ARC_SEGMENT_MM)) : nominal_segment_mm < (MIN_ARC_SEGMENT_MM) ? _MAX(1, FLOOR(flat_mm / (MIN_ARC_SEGMENT_MM))) : nominal_segments; - float segment_mm = flat_mm / segments; + const float segment_mm = flat_mm / segments; + // Add hints to help optimize the move + PlannerHints hints; #if ENABLED(SCARA_FEEDRATE_SCALING) - const float inv_duration = (scaled_fr_mm_s / flat_mm) * segments; + hints.inv_duration = (scaled_fr_mm_s / flat_mm) * segments; #endif /** @@ -355,11 +357,12 @@ void plan_arc( // calculate safe speed for stopping by the end of the arc arc_mm_remaining -= segment_mm; - const float safe_exit_speed_sqr = _MIN(limiting_speed_sqr, 2 * limiting_accel * arc_mm_remaining); - if (!planner.buffer_line(raw, scaled_fr_mm_s, active_extruder - , PlannerHints(0 OPTARG(SCARA_FEEDRATE_SCALING, inv_duration), i > 1 ? radius : 0, safe_exit_speed_sqr)) - ) break; + hints.curve_radius = i > 1 ? radius : 0; + hints.safe_exit_speed_sqr = _MIN(limiting_speed_sqr, 2 * limiting_accel * arc_mm_remaining); + + if (!planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, hints)) + break; } } @@ -379,7 +382,8 @@ void plan_arc( planner.apply_leveling(raw); #endif - planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, 0 OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)); + hints.curve_radius = 0; + planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, hints); #if ENABLED(AUTO_BED_LEVELING_UBL) ARC_LIJKUVW_CODE( diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index b9e7bc696374..68395fc56a28 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -1041,19 +1041,19 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) { NOLESS(segments, 1U); // The approximate length of each segment - const float inv_segments = 1.0f / float(segments), - cartesian_segment_mm = cartesian_mm * inv_segments; + const float inv_segments = 1.0f / float(segments); const xyze_float_t segment_distance = diff * inv_segments; - #if ENABLED(SCARA_FEEDRATE_SCALING) - const float inv_duration = scaled_fr_mm_s / cartesian_segment_mm; - #endif + // Add hints to help optimize the move + PlannerHints hints; + hints.millimeters = cartesian_mm * inv_segments; + TERN_(SCARA_FEEDRATE_SCALING, hints.inv_duration = scaled_fr_mm_s / hints.millimeters); /* SERIAL_ECHOPGM("mm=", cartesian_mm); SERIAL_ECHOPGM(" seconds=", seconds); SERIAL_ECHOPGM(" segments=", segments); - SERIAL_ECHOPGM(" segment_mm=", cartesian_segment_mm); + SERIAL_ECHOPGM(" segment_mm=", hints.millimeters); SERIAL_EOL(); //*/ @@ -1065,13 +1065,12 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) { while (--segments) { segment_idle(next_idle_ms); raw += segment_distance; - if (!planner.buffer_line(raw, scaled_fr_mm_s, active_extruder - , PlannerHints(cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)))) break; + if (!planner.buffer_line(raw, scaled_fr_mm_s, active_extruder, hints)) + break; } // Ensure last segment arrives at target location. - planner.buffer_line(destination, scaled_fr_mm_s, active_extruder - , PlannerHints(cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration))); + planner.buffer_line(destination, scaled_fr_mm_s, active_extruder, hints); return false; // caller will update current_position } @@ -1110,17 +1109,17 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) { NOLESS(segments, 1U); // The approximate length of each segment - const float inv_segments = 1.0f / float(segments), - cartesian_segment_mm = cartesian_mm * inv_segments; + const float inv_segments = 1.0f / float(segments); const xyze_float_t segment_distance = diff * inv_segments; - #if ENABLED(SCARA_FEEDRATE_SCALING) - const float inv_duration = scaled_fr_mm_s / cartesian_segment_mm; - #endif + // Add hints to help optimize the move + PlannerHints hints; + hints.millimeters = cartesian_mm * inv_segments; + TERN_(SCARA_FEEDRATE_SCALING, hints.inv_duration = scaled_fr_mm_s / hints.millimeters); //SERIAL_ECHOPGM("mm=", cartesian_mm); //SERIAL_ECHOLNPGM(" segments=", segments); - //SERIAL_ECHOLNPGM(" segment_mm=", cartesian_segment_mm); + //SERIAL_ECHOLNPGM(" segment_mm=", hints.millimeters); // Get the raw current position as starting point xyze_pos_t raw = current_position; @@ -1130,14 +1129,13 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) { while (--segments) { segment_idle(next_idle_ms); raw += segment_distance; - if (!planner.buffer_line(raw, fr_mm_s, active_extruder - , PlannerHints(cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration)))) break; + if (!planner.buffer_line(raw, fr_mm_s, active_extruder, hints)) + break; } // Since segment_distance is only approximate, // the final move must be to the exact destination. - planner.buffer_line(destination, fr_mm_s, active_extruder - , PlannerHints(cartesian_segment_mm OPTARG(SCARA_FEEDRATE_SCALING, inv_duration))); + planner.buffer_line(destination, fr_mm_s, active_extruder, hints); } #endif // SEGMENT_LEVELED_MOVES && !AUTO_BED_LEVELING_UBL diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index 1d94e456e6f0..d72a16c72c55 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -925,20 +925,24 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t this block can never be less than block_buffer_tail and will always be pushed forward and maintain this requirement when encountered by the Planner::release_current_block() routine during a cycle. - NOTE: Since the planner only computes on what's in the planner buffer, some motions with lots of short - line segments, like complex curves, may seem to move slow. This is because there simply isn't enough - combined distance traveled in the entire buffer to accelerate up to the nominal speed and then decelerate - to a complete stop at the end of the buffer, as stated by the guidelines. If this happens and becomes an - annoyance, there are a few simple solutions: - (1) Maximize the machine acceleration. The planner will be able to compute higher velocity profiles + NOTE: Since the planner only computes on what's in the planner buffer, some motions with many short + segments (e.g., complex curves) may seem to move slowly. This is because there simply isn't + enough combined distance traveled in the entire buffer to accelerate up to the nominal speed and + then decelerate to a complete stop at the end of the buffer, as stated by the guidelines. If this + happens and becomes an annoyance, there are a few simple solutions: + + - Maximize the machine acceleration. The planner will be able to compute higher velocity profiles within the same combined distance. - (2) Maximize line motion(s) distance per block to a desired tolerance. The more combined distance the + + - Maximize line motion(s) distance per block to a desired tolerance. The more combined distance the planner has to use, the faster it can go. - (3) Maximize the planner buffer size. This also will increase the combined distance for the planner to + + - Maximize the planner buffer size. This also will increase the combined distance for the planner to compute over. It also increases the number of computations the planner has to perform to compute an optimal plan, so select carefully. - (4) Use G2/G3 arcs instead of many short segment. These now inform the planner of a safe exit speed at - the end of the last segment, which alleviates this problem. + + - Use G2/G3 arcs instead of many short segments. Arcs inform the planner of a safe exit speed at the + end of the last segment, which alleviates this problem. */ // The kernel called by recalculate() when scanning the plan from last to first entry. @@ -3101,24 +3105,24 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s ); #endif - PlannerHints _hints(hints); - if (!_hints.millimeters) - _hints.millimeters = (cart_dist_mm.x || cart_dist_mm.y) ? cart_dist_mm.magnitude() : TERN0(HAS_Z_AXIS, ABS(cart_dist_mm.z)); - // Cartesian XYZ to kinematic ABC, stored in global 'delta' inverse_kinematics(machine); + PlannerHints ph = hints; + if (!hints.millimeters) + ph.millimeters = (cart_dist_mm.x || cart_dist_mm.y) ? cart_dist_mm.magnitude() : TERN0(HAS_Z_AXIS, ABS(cart_dist_mm.z)); + #if ENABLED(SCARA_FEEDRATE_SCALING) // For SCARA scale the feed rate from mm/s to degrees/s // i.e., Complete the angular vector in the given time. - const float duration_recip = hints.inv_duration ?: fr_mm_s / _hints.millimeters; + const float duration_recip = hints.inv_duration ?: fr_mm_s / ph.millimeters; const xyz_pos_t diff = delta - position_float; const feedRate_t feedrate = diff.magnitude() * duration_recip; #else const feedRate_t feedrate = fr_mm_s; #endif TERN_(HAS_EXTRUDERS, delta.e = machine.e); - if (buffer_segment(delta OPTARG(HAS_DIST_MM_ARG, cart_dist_mm), feedrate, extruder, _hints)) { + if (buffer_segment(delta OPTARG(HAS_DIST_MM_ARG, cart_dist_mm), feedrate, extruder, ph)) { position_cart = cart; return true; } diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index 39e269e70cb6..7ee6a3d685ca 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -352,31 +352,20 @@ typedef struct { #endif struct PlannerHints { - // the length of the movement, if known - float millimeters = 0.0; - // the reciprocal if the duration of the movement, if known (kinematic only if feeedrate scaling is enabled) + float millimeters = 0.0; // Move Length, if known, else 0. #if ENABLED(SCARA_FEEDRATE_SCALING) - float inv_duration = 0.0; + float inv_duration = 0.0; // Reciprocal of the move duration, if known #endif - // the radius of curvature of the tool head path - for cornering speed calculation #if ENABLED(HINTS_CURVE_RADIUS) - float curve_radius = 0.0; + float curve_radius = 0.0; // Radius of curvature of the motion path - to calculate cornering speed + #else + static constexpr float curve_radius = 0.0; #endif - // the square of the speed which would be "safe" at the end of this segment, i.e. <= the exit speed - // of the segment that the planner would calculate of it knew the as yet unbuffered path #if ENABLED(HINTS_SAFE_EXIT_SPEED) - float safe_exit_speed_sqr = 0.0; + float safe_exit_speed_sqr = 0.0; // Square of the speed considered "safe" at the end of the segment + // i.e., at or below the exit speed of the segment that the planner + // would calculate if it knew the as-yet-unbuffered path #endif - - PlannerHints(float _millimeters = 0.0 - OPTARG(SCARA_FEEDRATE_SCALING, const_float_t _inv_duration = 0.0) - OPTARG(HINTS_CURVE_RADIUS, const_float_t _curve_radius = 0.0) - OPTARG (HINTS_SAFE_EXIT_SPEED, const_float_t _safe_exit_speed_sqr = 0.0) - ) : millimeters(_millimeters) - OPTARG(SCARA_FEEDRATE_SCALING, inv_duration(_inv_duration)) - OPTARG(HINTS_CURVE_RADIUS, curve_radius(_curve_radius)) - OPTARG (HINTS_SAFE_EXIT_SPEED, safe_exit_speed_sqr(_safe_exit_speed_sqr)) - {} }; class Planner { diff --git a/Marlin/src/module/planner_bezier.cpp b/Marlin/src/module/planner_bezier.cpp index fa7e16a387e6..5c30702f0070 100644 --- a/Marlin/src/module/planner_bezier.cpp +++ b/Marlin/src/module/planner_bezier.cpp @@ -121,6 +121,9 @@ void cubic_b_spline( millis_t next_idle_ms = millis() + 200UL; + // Hints to help optimize the move + PlannerHints hints; + for (float t = 0; t < 1;) { thermalManager.manage_heater(); @@ -177,7 +180,7 @@ void cubic_b_spline( } */ - step = new_t - t; + hints.millimeters = new_t - t; t = new_t; // Compute and send new position @@ -203,7 +206,7 @@ void cubic_b_spline( const xyze_pos_t &pos = bez_target; #endif - if (!planner.buffer_line(pos, scaled_fr_mm_s, active_extruder, step)) + if (!planner.buffer_line(pos, scaled_fr_mm_s, active_extruder, hints)) break; } } From 17f2fcfd349fcec42c54a8dc641f74f2bc59cadf Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 7 Jul 2022 11:14:17 -0500 Subject: [PATCH 18/18] misc. cleanup --- .../src/feature/bedlevel/ubl/ubl_motion.cpp | 3 +- Marlin/src/feature/joystick.cpp | 3 +- Marlin/src/module/motion.cpp | 6 +- Marlin/src/module/planner.cpp | 127 ++++++++---------- Marlin/src/module/planner.h | 26 ++-- Marlin/src/module/stepper.cpp | 27 ++-- 6 files changed, 92 insertions(+), 100 deletions(-) diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp index dcd3f1b7b813..8121a0b9b5bb 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp @@ -377,8 +377,7 @@ const float inv_segments = 1.0f / segments; // Reciprocal to save calculation // Add hints to help optimize the move - PlannerHints hints; - hints.millimeters = SQRT(cart_xy_mm_2 + sq(total.z)) * inv_segments; // Length of each segment + PlannerHints hints(SQRT(cart_xy_mm_2 + sq(total.z)) * inv_segments); // Length of each segment #if ENABLED(SCARA_FEEDRATE_SCALING) hints.inv_duration = scaled_fr_mm_s / hints.millimeters; #endif diff --git a/Marlin/src/feature/joystick.cpp b/Marlin/src/feature/joystick.cpp index daa642d32e36..acab5d7437a2 100644 --- a/Marlin/src/feature/joystick.cpp +++ b/Marlin/src/feature/joystick.cpp @@ -172,8 +172,9 @@ Joystick joystick; current_position += move_dist; apply_motion_limits(current_position); const float length = sqrt(hypot2); + PlannerHints hints(length); injecting_now = true; - planner.buffer_line(current_position, length / seg_time, active_extruder, length); + planner.buffer_line(current_position, length / seg_time, active_extruder, hints); injecting_now = false; } } diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 78848ebe0904..eaf3ab540957 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -1045,8 +1045,7 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) { const xyze_float_t segment_distance = diff * inv_segments; // Add hints to help optimize the move - PlannerHints hints; - hints.millimeters = cartesian_mm * inv_segments; + PlannerHints hints(cartesian_mm * inv_segments); TERN_(SCARA_FEEDRATE_SCALING, hints.inv_duration = scaled_fr_mm_s / hints.millimeters); /* @@ -1113,8 +1112,7 @@ FORCE_INLINE void segment_idle(millis_t &next_idle_ms) { const xyze_float_t segment_distance = diff * inv_segments; // Add hints to help optimize the move - PlannerHints hints; - hints.millimeters = cartesian_mm * inv_segments; + PlannerHints hints(cartesian_mm * inv_segments); TERN_(SCARA_FEEDRATE_SCALING, hints.inv_duration = scaled_fr_mm_s / hints.millimeters); //SERIAL_ECHOPGM("mm=", cartesian_mm); diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp index fe32d968b08f..7b00552dffa2 100644 --- a/Marlin/src/module/planner.cpp +++ b/Marlin/src/module/planner.cpp @@ -843,20 +843,22 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t /** * Laser Trapezoid Calculations * - * Approximate the trapezoid with the laser, incrementing the power every `trap_ramp_entry_incr` steps while accelerating, - * and decrementing the power every `trap_ramp_exit_decr` while decelerating, to keep power proportional to feedrate. - * Laser power trap will reduce the initial power to no less than the laser_power_floor value. Based on the number - * of calculated accel/decel steps the power is distributed over the trapezoid entry- and exit-ramp steps. + * Approximate the trapezoid with the laser, incrementing the power every `trap_ramp_entry_incr` + * steps while accelerating, and decrementing the power every `trap_ramp_exit_decr` while decelerating, + * to keep power proportional to feedrate. Laser power trap will reduce the initial power to no less + * than the laser_power_floor value. Based on the number of calculated accel/decel steps the power is + * distributed over the trapezoid entry- and exit-ramp steps. * - * trap_ramp_active_pwr - The active power is initially set at a reduced level factor of initial power / accel steps and - * will be additively incremented using a trap_ramp_entry_incr value for each accel step processed later in the stepper code. - * The trap_ramp_exit_decr value is calculated as power / decel steps and is also adjusted to no less than the power floor. + * trap_ramp_active_pwr - The active power is initially set at a reduced level factor of initial + * power / accel steps and will be additively incremented using a trap_ramp_entry_incr value for each + * accel step processed later in the stepper code. The trap_ramp_exit_decr value is calculated as + * power / decel steps and is also adjusted to no less than the power floor. * - * If the power == 0 the inline mode variables need to be set to zero to prevent stepper processing. The method allows - * for simpler non-powered moves like G0 or G28. + * If the power == 0 the inline mode variables need to be set to zero to prevent stepper processing. + * The method allows for simpler non-powered moves like G0 or G28. * - * Laser Trap Power works for all Jerk and Curve modes; however Arc-based moves will have issues since the segments are - * usually too small. + * Laser Trap Power works for all Jerk and Curve modes; however Arc-based moves will have issues since + * the segments are usually too small. */ if (cutter.cutter_mode == CUTTER_MODE_CONTINUOUS) { if (planner.laser_inline.status.isPowered && planner.laser_inline.status.isEnabled) { @@ -1790,17 +1792,16 @@ float Planner::get_axis_position_mm(const AxisEnum axis) { void Planner::synchronize() { while (busy()) idle(); } /** - * Planner::_buffer_steps + * @brief Add a new linear movement to the planner queue (in terms of steps). * - * Add a new linear movement to the planner queue (in terms of steps). - * - * target - target position in steps units - * target_float - target position in direct (mm, degrees) units. optional - * fr_mm_s - (target) speed of the move - * extruder - target extruder - * hints - optional parameters to aid planner's calculations + * @param target Target position in steps units + * @param target_float Target position in direct (mm, degrees) units. + * @param cart_dist_mm The pre-calculated move lengths for all axes, in mm + * @param fr_mm_s (target) speed of the move + * @param extruder target extruder + * @param hints parameters to aid planner calculations * - * Returns true if movement was properly queued, false otherwise (if cleaning) + * @return true if movement was properly queued, false otherwise (if cleaning) */ bool Planner::_buffer_steps(const xyze_long_t &target OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float) @@ -1861,7 +1862,7 @@ bool Planner::_buffer_steps(const xyze_long_t &target * @param cart_dist_mm The pre-calculated move lengths for all axes, in mm * @param fr_mm_s (target) speed of the move * @param extruder target extruder - * @param hints optional parameters to aid planner's calculations + * @param hints parameters to aid planner calculations * * @return true if movement is acceptable, false otherwise */ @@ -2255,15 +2256,9 @@ bool Planner::_populate_block( #if ENABLED(AUTO_POWER_CONTROL) if (NUM_AXIS_GANG( - block->steps.x, - || block->steps.y, - || block->steps.z, - || block->steps.i, - || block->steps.j, - || block->steps.k, - || block->steps.u, - || block->steps.v, - || block->steps.w + block->steps.x, || block->steps.y, || block->steps.z, + || block->steps.i, || block->steps.j, || block->steps.k, + || block->steps.u, || block->steps.v, || block->steps.w )) powerManager.power_on(); #endif @@ -2574,29 +2569,17 @@ bool Planner::_populate_block( if (block->step_event_count <= acceleration_long_cutoff) { LOGICAL_AXIS_CODE( LIMIT_ACCEL_LONG(E_AXIS, E_INDEX_N(extruder)), - LIMIT_ACCEL_LONG(A_AXIS, 0), - LIMIT_ACCEL_LONG(B_AXIS, 0), - LIMIT_ACCEL_LONG(C_AXIS, 0), - LIMIT_ACCEL_LONG(I_AXIS, 0), - LIMIT_ACCEL_LONG(J_AXIS, 0), - LIMIT_ACCEL_LONG(K_AXIS, 0), - LIMIT_ACCEL_LONG(U_AXIS, 0), - LIMIT_ACCEL_LONG(V_AXIS, 0), - LIMIT_ACCEL_LONG(W_AXIS, 0) + LIMIT_ACCEL_LONG(A_AXIS, 0), LIMIT_ACCEL_LONG(B_AXIS, 0), LIMIT_ACCEL_LONG(C_AXIS, 0), + LIMIT_ACCEL_LONG(I_AXIS, 0), LIMIT_ACCEL_LONG(J_AXIS, 0), LIMIT_ACCEL_LONG(K_AXIS, 0), + LIMIT_ACCEL_LONG(U_AXIS, 0), LIMIT_ACCEL_LONG(V_AXIS, 0), LIMIT_ACCEL_LONG(W_AXIS, 0) ); } else { LOGICAL_AXIS_CODE( LIMIT_ACCEL_FLOAT(E_AXIS, E_INDEX_N(extruder)), - LIMIT_ACCEL_FLOAT(A_AXIS, 0), - LIMIT_ACCEL_FLOAT(B_AXIS, 0), - LIMIT_ACCEL_FLOAT(C_AXIS, 0), - LIMIT_ACCEL_FLOAT(I_AXIS, 0), - LIMIT_ACCEL_FLOAT(J_AXIS, 0), - LIMIT_ACCEL_FLOAT(K_AXIS, 0), - LIMIT_ACCEL_FLOAT(U_AXIS, 0), - LIMIT_ACCEL_FLOAT(V_AXIS, 0), - LIMIT_ACCEL_FLOAT(W_AXIS, 0) + LIMIT_ACCEL_FLOAT(A_AXIS, 0), LIMIT_ACCEL_FLOAT(B_AXIS, 0), LIMIT_ACCEL_FLOAT(C_AXIS, 0), + LIMIT_ACCEL_FLOAT(I_AXIS, 0), LIMIT_ACCEL_FLOAT(J_AXIS, 0), LIMIT_ACCEL_FLOAT(K_AXIS, 0), + LIMIT_ACCEL_FLOAT(U_AXIS, 0), LIMIT_ACCEL_FLOAT(V_AXIS, 0), LIMIT_ACCEL_FLOAT(W_AXIS, 0) ); } } @@ -2661,7 +2644,10 @@ bool Planner::_populate_block( #if HAS_DIST_MM_ARG cart_dist_mm #else - LOGICAL_AXIS_ARRAY(steps_dist_mm.e, steps_dist_mm.x, steps_dist_mm.y, steps_dist_mm.z, steps_dist_mm.i, steps_dist_mm.j, steps_dist_mm.k, steps_dist_mm.u, steps_dist_mm.v, steps_dist_mm.w) + LOGICAL_AXIS_ARRAY(steps_dist_mm.e, + steps_dist_mm.x, steps_dist_mm.y, steps_dist_mm.z, + steps_dist_mm.i, steps_dist_mm.j, steps_dist_mm.k, + steps_dist_mm.u, steps_dist_mm.v, steps_dist_mm.w) #endif ; @@ -2682,7 +2668,7 @@ bool Planner::_populate_block( // NOTE: Max junction velocity is computed without sin() or acos() by trig half angle identity. float junction_cos_theta = LOGICAL_AXIS_GANG( + (-prev_unit_vec.e * unit_vec.e), - (-prev_unit_vec.x * unit_vec.x), + + (-prev_unit_vec.x * unit_vec.x), + (-prev_unit_vec.y * unit_vec.y), + (-prev_unit_vec.z * unit_vec.z), + (-prev_unit_vec.i * unit_vec.i), @@ -2962,12 +2948,11 @@ bool Planner::_populate_block( } // _populate_block() /** - * Planner::buffer_sync_block - * Add a block to the buffer that just updates the position - * @param sync_flag BLOCK_FLAG_SYNC_FANS & BLOCK_FLAG_LASER_PWR - * Supports LASER_SYNCHRONOUS_M106_M107 and LASER_POWER_SYNC power sync block buffer queueing. + * @brief Add a block to the buffer that just updates the position + * Supports LASER_SYNCHRONOUS_M106_M107 and LASER_POWER_SYNC power sync block buffer queueing. + * + * @param sync_flag The sync flag to set, determining the type of sync the block will do */ - void Planner::buffer_sync_block(const BlockFlagBit sync_flag/*=BLOCK_BIT_SYNC_POSITION*/) { // Wait for the next available block @@ -2975,7 +2960,7 @@ void Planner::buffer_sync_block(const BlockFlagBit sync_flag/*=BLOCK_BIT_SYNC_PO block_t * const block = get_next_free_block(next_buffer_head); // Clear block - memset(block, 0, sizeof(block_t)); + block->reset(); block->flag.apply(sync_flag); block->position = position; @@ -3008,23 +2993,24 @@ void Planner::buffer_sync_block(const BlockFlagBit sync_flag/*=BLOCK_BIT_SYNC_PO } // buffer_sync_block() /** - * Planner::buffer_segment - * - * Add a new linear movement to the buffer in axis units. + * @brief Add a single linear movement * - * Leveling and kinematics should be applied ahead of calling this. + * @description Add a new linear movement to the buffer in axis units. + * Leveling and kinematics should be applied before calling this. * - * a,b,c,e - target positions in mm and/or degrees - * fr_mm_s - (target) speed of the move - * extruder - target extruder - * hints - optional parameters to aid planner's calculations + * @param abce Target position in mm and/or degrees + * @param cart_dist_mm The pre-calculated move lengths for all axes, in mm + * @param fr_mm_s (target) speed of the move + * @param extruder optional target extruder (otherwise active_extruder) + * @param hints optional parameters to aid planner calculations * - * Return 'false' if no segment was queued due to cleaning, cold extrusion, full queue, etc. + * @return false if no segment was queued due to cleaning, cold extrusion, full queue, etc. */ bool Planner::buffer_segment(const abce_pos_t &abce OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) - , const_feedRate_t fr_mm_s, const uint8_t extruder/*=active_extruder*/ - , const PlannerHints &hints/* = PlannerHints()*/ + , const_feedRate_t fr_mm_s + , const uint8_t extruder/*=active_extruder*/ + , const PlannerHints &hints/*=PlannerHints()*/ ) { // If we are cleaning, do not accept queuing of movements @@ -3144,11 +3130,12 @@ bool Planner::buffer_segment(const abce_pos_t &abce * * cart - target position in mm or degrees * fr_mm_s - (target) speed of the move (mm/s) - * extruder - target extruder - * hints - optional parameters to aid planner's calculations + * extruder - optional target extruder (otherwise active_extruder) + * hints - optional parameters to aid planner calculations */ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s - , const uint8_t extruder/*=active_extruder*/, const PlannerHints &hints/*=PlannerHints()*/ + , const uint8_t extruder/*=active_extruder*/ + , const PlannerHints &hints/*=PlannerHints()*/ ) { xyze_pos_t machine = cart; TERN_(HAS_POSITION_MODIFIERS, apply_modifiers(machine)); diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h index 59bca9f10eda..5a0de47bf2f0 100644 --- a/Marlin/src/module/planner.h +++ b/Marlin/src/module/planner.h @@ -280,6 +280,8 @@ typedef struct block_t { block_laser_t laser; #endif + void reset() { memset((char*)this, 0, sizeof(*this)); } + } block_t; #if ANY(LIN_ADVANCE, SCARA_FEEDRATE_SCALING, GRADIENT_MIX, LCD_SHOW_E_TOTAL, POWER_LOSS_RECOVERY) @@ -369,6 +371,8 @@ struct PlannerHints { // i.e., at or below the exit speed of the segment that the planner // would calculate if it knew the as-yet-unbuffered path #endif + + PlannerHints(const_float_t mm=0.0f) : millimeters(mm) {} }; class Planner { @@ -774,7 +778,7 @@ class Planner { * target - target position in steps units * fr_mm_s - (target) speed of the move * extruder - target extruder - * hints - optional parameters to aid planner's calculations + * hints - parameters to aid planner calculations * * Returns true if movement was buffered, false otherwise */ @@ -796,7 +800,7 @@ class Planner { * @param cart_dist_mm The pre-calculated move lengths for all axes, in mm * @param fr_mm_s (target) speed of the move * @param extruder target extruder - * @param hints optional parameters to aid planner's calculations + * @param hints parameters to aid planner calculations * * @return true if movement is acceptable, false otherwise */ @@ -830,13 +834,14 @@ class Planner { * * a,b,c,e - target positions in mm and/or degrees * fr_mm_s - (target) speed of the move - * extruder - target extruder - * hints - optional parameters to aid planner's calculations + * extruder - optional target extruder (otherwise active_extruder) + * hints - optional parameters to aid planner calculations */ static bool buffer_segment(const abce_pos_t &abce OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm) - , const_feedRate_t fr_mm_s, const uint8_t extruder=active_extruder - , const PlannerHints &hints = PlannerHints() + , const_feedRate_t fr_mm_s + , const uint8_t extruder=active_extruder + , const PlannerHints &hints=PlannerHints() ); public: @@ -848,11 +853,12 @@ class Planner { * * cart - target position in mm or degrees * fr_mm_s - (target) speed of the move (mm/s) - * extruder - target extruder - * hints - optional parameters to aid planner's calculations + * extruder - optional target extruder (otherwise active_extruder) + * hints - optional parameters to aid planner calculations */ - static bool buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s, - const uint8_t extruder=active_extruder, const PlannerHints &hints=PlannerHints() + static bool buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s + , const uint8_t extruder=active_extruder + , const PlannerHints &hints=PlannerHints() ); #if ENABLED(DIRECT_STEPPING) diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index 4832220abd75..2bacc556060b 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -2002,14 +2002,15 @@ uint32_t Stepper::block_phase_isr() { else if (LA_steps) nextAdvanceISR = 0; #endif - /* + /** * Adjust Laser Power - Accelerating - * isPowered - True when a move is powered. - * isEnabled - laser power is active. - * Laser power variables are calulated and stored in this block by the planner code. * - * trap_ramp_active_pwr - the active power in this block across accel or decel trap steps. - * trap_ramp_entry_incr - holds the precalculated value to increase the current power per accel step. + * isPowered - True when a move is powered. + * isEnabled - laser power is active. + * + * Laser power variables are calulated and stored in this block by the planner code. + * trap_ramp_active_pwr - the active power in this block across accel or decel trap steps. + * trap_ramp_entry_incr - holds the precalculated value to increase the current power per accel step. * * Apply the starting active power and then increase power per step by the trap_ramp_entry_incr value if positive. */ @@ -2032,6 +2033,7 @@ uint32_t Stepper::block_phase_isr() { uint32_t step_rate; #if ENABLED(S_CURVE_ACCELERATION) + // If this is the 1st time we process the 2nd half of the trapezoid... if (!bezier_2nd_half) { // Initialize the Bézier speed curve @@ -2046,6 +2048,7 @@ uint32_t Stepper::block_phase_isr() { ? _eval_bezier_curve(deceleration_time) : current_block->final_rate; } + #else // Using the old trapezoidal control step_rate = STEP_MULTIPLY(deceleration_time, current_block->acceleration_rate); @@ -2055,9 +2058,8 @@ uint32_t Stepper::block_phase_isr() { } else step_rate = current_block->final_rate; - #endif - // step_rate is in steps/second + #endif // step_rate to timer interval and steps per stepper isr interval = calc_timer_interval(step_rate, &steps_per_isr); @@ -2109,10 +2111,10 @@ uint32_t Stepper::block_phase_isr() { interval = ticks_nominal; } - /* Adjust Laser Power - Cruise + /** + * Adjust Laser Power - Cruise * power - direct or floor adjusted active laser power. */ - #if ENABLED(LASER_POWER_TRAP) if (cutter.cutter_mode == CUTTER_MODE_CONTINUOUS) { if (step_events_completed + 1 == accelerate_until) { @@ -2130,7 +2132,7 @@ uint32_t Stepper::block_phase_isr() { } #if ENABLED(LASER_FEATURE) - /* + /** * CUTTER_MODE_DYNAMIC is experimental and developing. * Super-fast method to dynamically adjust the laser power OCR value based on the input feedrate in mm-per-minute. * TODO: Set up Min/Max OCR offsets to allow tuning and scaling of various lasers. @@ -2147,9 +2149,8 @@ uint32_t Stepper::block_phase_isr() { } else { // !current_block #if ENABLED(LASER_FEATURE) - if (cutter.cutter_mode == CUTTER_MODE_DYNAMIC) { + if (cutter.cutter_mode == CUTTER_MODE_DYNAMIC) cutter.apply_power(0); // No movement in dynamic mode so turn Laser off - } #endif }