@@ -153,9 +153,7 @@ float Planner::mm_per_step[DISTINCT_AXES]; // (mm) Millimeters per step
153
153
#if HAS_LINEAR_E_JERK
154
154
float Planner::max_e_jerk[DISTINCT_E]; // Calculated from junction_deviation_mm
155
155
#endif
156
- #endif
157
-
158
- #if ENABLED(CLASSIC_JERK)
156
+ #else // CLASSIC_JERK
159
157
TERN (HAS_LINEAR_E_JERK, xyz_pos_t , xyze_pos_t ) Planner::max_jerk;
160
158
#endif
161
159
@@ -2374,42 +2372,42 @@ bool Planner::_populate_block(
2374
2372
2375
2373
// Limit speed on extruders, if any
2376
2374
#if HAS_EXTRUDERS
2377
- {
2378
- current_speed.e = dist_mm.e * inverse_secs;
2379
- #if HAS_MIXER_SYNC_CHANNEL
2380
- // Move all mixing extruders at the specified rate
2381
- if (mixer.get_current_vtool () == MIXER_AUTORETRACT_TOOL)
2382
- current_speed.e *= MIXING_STEPPERS;
2383
- #endif
2384
-
2385
- const feedRate_t cs = ABS (current_speed.e ),
2386
- max_fr = settings.max_feedrate_mm_s [E_AXIS_N (extruder)]
2387
- * TERN (HAS_MIXER_SYNC_CHANNEL, MIXING_STEPPERS, 1 );
2388
-
2389
- if (cs > max_fr) NOMORE (speed_factor, max_fr / cs); // respect max feedrate on any movement (doesn't matter if E axes only or not)
2390
-
2391
- #if ENABLED(VOLUMETRIC_EXTRUDER_LIMIT)
2392
- const feedRate_t max_vfr = volumetric_extruder_feedrate_limit[extruder]
2393
- * TERN (HAS_MIXER_SYNC_CHANNEL, MIXING_STEPPERS, 1 );
2375
+ {
2376
+ current_speed.e = dist_mm.e * inverse_secs;
2377
+ #if HAS_MIXER_SYNC_CHANNEL
2378
+ // Move all mixing extruders at the specified rate
2379
+ if (mixer.get_current_vtool () == MIXER_AUTORETRACT_TOOL)
2380
+ current_speed.e *= MIXING_STEPPERS;
2381
+ #endif
2394
2382
2395
- // TODO: Doesn't work properly for joined segments. Set MIN_STEPS_PER_SEGMENT 1 as workaround.
2383
+ const feedRate_t cs = ABS (current_speed.e ),
2384
+ max_fr = settings.max_feedrate_mm_s [E_AXIS_N (extruder)]
2385
+ * TERN (HAS_MIXER_SYNC_CHANNEL, MIXING_STEPPERS, 1 );
2396
2386
2397
- if (block-> steps . a || block-> steps . b || block-> steps . c ) {
2387
+ if (cs > max_fr) NOMORE (speed_factor, max_fr / cs); // respect max feedrate on any movement (doesn't matter if E axes only or not)
2398
2388
2399
- if (max_vfr > 0 && cs > max_vfr) {
2400
- NOMORE (speed_factor, max_vfr / cs); // respect volumetric extruder limit (if any)
2401
- /* <-- add a slash to enable
2402
- SERIAL_ECHOPGM("volumetric extruder limit enforced: ", (cs * CIRCLE_AREA(filament_size[extruder] * 0.5f)));
2403
- SERIAL_ECHOPGM(" mm^3/s (", cs);
2404
- SERIAL_ECHOPGM(" mm/s) limited to ", (max_vfr * CIRCLE_AREA(filament_size[extruder] * 0.5f)));
2405
- SERIAL_ECHOPGM(" mm^3/s (", max_vfr);
2406
- SERIAL_ECHOLNPGM(" mm/s)");
2407
- //*/
2408
- }
2389
+ #if ENABLED(VOLUMETRIC_EXTRUDER_LIMIT)
2390
+ const feedRate_t max_vfr = volumetric_extruder_feedrate_limit[extruder]
2391
+ * TERN (HAS_MIXER_SYNC_CHANNEL, MIXING_STEPPERS, 1 );
2392
+
2393
+ // TODO: Doesn't work properly for joined segments. Set MIN_STEPS_PER_SEGMENT 1 as workaround.
2394
+
2395
+ if (block->steps .a || block->steps .b || block->steps .c ) {
2396
+
2397
+ if (max_vfr > 0 && cs > max_vfr) {
2398
+ NOMORE (speed_factor, max_vfr / cs); // respect volumetric extruder limit (if any)
2399
+ /* <-- add a slash to enable
2400
+ SERIAL_ECHOPGM("volumetric extruder limit enforced: ", (cs * CIRCLE_AREA(filament_size[extruder] * 0.5f)));
2401
+ SERIAL_ECHOPGM(" mm^3/s (", cs);
2402
+ SERIAL_ECHOPGM(" mm/s) limited to ", (max_vfr * CIRCLE_AREA(filament_size[extruder] * 0.5f)));
2403
+ SERIAL_ECHOPGM(" mm^3/s (", max_vfr);
2404
+ SERIAL_ECHOLNPGM(" mm/s)");
2405
+ //*/
2409
2406
}
2410
- #endif
2411
- }
2412
- #endif
2407
+ }
2408
+ #endif
2409
+ }
2410
+ #endif // HAS_EXTRUDERS
2413
2411
2414
2412
#ifdef XY_FREQUENCY_LIMIT
2415
2413
@@ -2492,7 +2490,7 @@ bool Planner::_populate_block(
2492
2490
*
2493
2491
* extruder_advance_K[extruder] : There is an advance factor set for this extruder.
2494
2492
*
2495
- * dist.e > 0 : Extruder is running forward (e.g., for "Wipe while retracting" (Slic3r) or "Combing" (Cura) moves)
2493
+ * dist.e > 0 : Extruder is running forward (e.g., for "Wipe while retracting" (Slic3r) or "Combing" (Cura) moves)
2496
2494
*/
2497
2495
use_advance_lead = esteps && extruder_advance_K[E_INDEX_N (extruder)] && dist.e > 0 ;
2498
2496
@@ -2511,9 +2509,10 @@ bool Planner::_populate_block(
2511
2509
else {
2512
2510
// Scale E acceleration so that it will be possible to jump to the advance speed.
2513
2511
const uint32_t max_accel_steps_per_s2 = MAX_E_JERK (extruder) / (extruder_advance_K[E_INDEX_N (extruder)] * e_D_ratio) * steps_per_mm;
2514
- if (TERN0 (LA_DEBUG, accel > max_accel_steps_per_s2))
2515
- SERIAL_ECHOLNPGM (" Acceleration limited." );
2516
- NOMORE (accel, max_accel_steps_per_s2);
2512
+ if (accel > max_accel_steps_per_s2) {
2513
+ accel = max_accel_steps_per_s2;
2514
+ if (ENABLED (LA_DEBUG)) SERIAL_ECHOLNPGM (" Acceleration limited." );
2515
+ }
2517
2516
}
2518
2517
}
2519
2518
#endif
@@ -2764,104 +2763,59 @@ bool Planner::_populate_block(
2764
2763
2765
2764
prev_unit_vec = unit_vec;
2766
2765
2767
- #endif
2768
-
2769
- #if ENABLED(CLASSIC_JERK)
2766
+ #else // CLASSIC_JERK
2770
2767
2771
2768
/* *
2772
- * Adapted from Průša MKS firmware
2769
+ * Heavily modified. Originally adapted from Průša firmware.
2773
2770
* https://github.com/prusa3d/Prusa-Firmware
2774
2771
*/
2775
- // Exit speed limited by a jerk to full halt of a previous last segment
2776
- static float previous_safe_speed;
2777
-
2778
- // Start with a safe speed (from which the machine may halt to stop immediately).
2779
- float safe_speed = block->nominal_speed ;
2780
-
2781
2772
#ifndef TRAVEL_EXTRA_XYJERK
2782
- #define TRAVEL_EXTRA_XYJERK 0
2773
+ #define TRAVEL_EXTRA_XYJERK 0 . 0f
2783
2774
#endif
2784
- const float extra_xyjerk = TERN0 (HAS_EXTRUDERS, dist.e <= 0 ) ? TRAVEL_EXTRA_XYJERK : 0 ;
2785
-
2786
- uint8_t limited = 0 ;
2787
- TERN (HAS_LINEAR_E_JERK, LOOP_NUM_AXES, LOOP_LOGICAL_AXES)(i) {
2788
- const float jerk = ABS (current_speed[i]), // cs : Starting from zero, change in speed for this axis
2789
- maxj = (max_jerk[i] + (i == X_AXIS || i == Y_AXIS ? extra_xyjerk : 0 .0f )); // mj : The max jerk setting for this axis
2790
- if (jerk > maxj) { // cs > mj : New current speed too fast?
2791
- if (limited) { // limited already?
2792
- const float mjerk = block->nominal_speed * maxj; // ns*mj
2793
- if (jerk * safe_speed > mjerk) safe_speed = mjerk / jerk; // ns*mj/cs
2794
- }
2795
- else {
2796
- safe_speed *= maxj / jerk; // Initial limit: ns*mj/cs
2797
- ++limited; // Initially limited
2798
- }
2799
- }
2800
- }
2775
+ const float extra_xyjerk = TERN0 (HAS_EXTRUDERS, dist.e <= 0 ) ? TRAVEL_EXTRA_XYJERK : 0 .0f ;
2801
2776
2802
- float vmax_junction;
2803
- if (moves_queued && !UNEAR_ZERO (previous_nominal_speed)) {
2804
- // Estimate a maximum velocity allowed at a joint of two successive segments.
2805
- // If this maximum velocity allowed is lower than the minimum of the entry / exit safe velocities,
2806
- // then the machine is not coasting anymore and the safe entry / exit velocities shall be used.
2777
+ if (!moves_queued || UNEAR_ZERO (previous_nominal_speed)) {
2778
+ // Compute "safe" speed, limited by a jerk to/from full halt.
2807
2779
2808
- // Factor to multiply the previous / current nominal velocities to get componentwise limited velocities.
2809
- float v_factor = 1 ;
2810
- limited = 0 ;
2780
+ float v_factor = 1 .0f ;
2781
+ LOOP_LOGICAL_AXES (i) {
2782
+ const float jerk = ABS (current_speed[i]), // Starting from zero, change in speed for this axis
2783
+ maxj = max_jerk[i] + (i == X_AXIS || i == Y_AXIS ? extra_xyjerk : 0 .0f ); // The max jerk setting for this axis
2784
+ if (jerk * v_factor > maxj) v_factor = maxj / jerk;
2785
+ }
2786
+ vmax_junction_sqr = sq (block->nominal_speed * v_factor);
2787
+ NOLESS (minimum_planner_speed_sqr, vmax_junction_sqr);
2788
+ }
2789
+ else {
2790
+ // Compute the maximum velocity allowed at a joint of two successive segments.
2811
2791
2812
2792
// The junction velocity will be shared between successive segments. Limit the junction velocity to their minimum.
2813
- // Pick the smaller of the nominal speeds. Higher speed shall not be achieved at the junction during coasting.
2814
- float smaller_speed_factor = 1 .0f ;
2793
+ float vmax_junction, previous_speed_factor, current_speed_factor;
2815
2794
if (block->nominal_speed < previous_nominal_speed) {
2816
2795
vmax_junction = block->nominal_speed ;
2817
- smaller_speed_factor = vmax_junction / previous_nominal_speed;
2796
+ previous_speed_factor = vmax_junction / previous_nominal_speed;
2797
+ current_speed_factor = 1 .0f ;
2818
2798
}
2819
- else
2799
+ else {
2820
2800
vmax_junction = previous_nominal_speed;
2801
+ previous_speed_factor = 1 .0f ;
2802
+ current_speed_factor = vmax_junction / block->nominal_speed ;
2803
+ }
2821
2804
2822
2805
// Now limit the jerk in all axes.
2823
- TERN (HAS_LINEAR_E_JERK, LOOP_NUM_AXES, LOOP_LOGICAL_AXES)(axis) {
2824
- // Limit an axis. We have to differentiate: coasting, reversal of an axis, full stop.
2825
- float v_exit = previous_speed[axis] * smaller_speed_factor,
2826
- v_entry = current_speed[axis];
2827
- if (limited) {
2828
- v_exit *= v_factor;
2829
- v_entry *= v_factor;
2830
- }
2831
-
2832
- // Calculate jerk depending on whether the axis is coasting in the same direction or reversing.
2833
- const float jerk = (v_exit > v_entry)
2834
- ? // coasting axis reversal
2835
- ( (v_entry > 0 || v_exit < 0 ) ? (v_exit - v_entry) : _MAX (v_exit, -v_entry) )
2836
- : // v_exit <= v_entry coasting axis reversal
2837
- ( (v_entry < 0 || v_exit > 0 ) ? (v_entry - v_exit) : _MAX (-v_exit, v_entry) );
2838
-
2839
- const float maxj = (max_jerk[axis] + (axis == X_AXIS || axis == Y_AXIS ? extra_xyjerk : 0 .0f ));
2840
-
2841
- if (jerk > maxj) {
2842
- v_factor *= maxj / jerk;
2843
- ++limited;
2844
- }
2806
+ float v_factor = 1 .0f ;
2807
+ LOOP_LOGICAL_AXES (i) {
2808
+ // Scale per-axis velocities for the same vmax_junction.
2809
+ const float v_exit = previous_speed[i] * previous_speed_factor,
2810
+ v_entry = current_speed[i] * current_speed_factor;
2811
+
2812
+ // Jerk is the per-axis velocity difference.
2813
+ const float jerk = ABS (v_exit - v_entry),
2814
+ maxj = max_jerk[i] + (i == X_AXIS || i == Y_AXIS ? extra_xyjerk : 0 .0f );
2815
+ if (jerk * v_factor > maxj) v_factor = maxj / jerk;
2845
2816
}
2846
- if (limited) vmax_junction *= v_factor;
2847
- // Now the transition velocity is known, which maximizes the shared exit / entry velocity while
2848
- // respecting the jerk factors, it may be possible, that applying separate safe exit / entry velocities will achieve faster prints.
2849
- const float vmax_junction_threshold = vmax_junction * 0 .99f ;
2850
- if (previous_safe_speed > vmax_junction_threshold && safe_speed > vmax_junction_threshold)
2851
- vmax_junction = safe_speed;
2817
+ vmax_junction_sqr = sq (vmax_junction * v_factor);
2852
2818
}
2853
- else
2854
- vmax_junction = safe_speed;
2855
-
2856
- previous_safe_speed = safe_speed;
2857
-
2858
- NOLESS (minimum_planner_speed_sqr, sq (safe_speed));
2859
-
2860
- #if HAS_JUNCTION_DEVIATION
2861
- NOMORE (vmax_junction_sqr, sq (vmax_junction)); // Throttle down to max speed
2862
- #else
2863
- vmax_junction_sqr = sq (vmax_junction); // Go up or down to the new speed
2864
- #endif
2865
2819
2866
2820
#endif // CLASSIC_JERK
2867
2821
0 commit comments