Skip to content

Commit 1a785e5

Browse files
mh-dmEvilGremlin
authored andcommitted
⚡️ Fix motion smoothness (MarlinFirmware#27013)
1 parent 7188442 commit 1a785e5

File tree

4 files changed

+56
-47
lines changed

4 files changed

+56
-47
lines changed

Marlin/src/module/planner.cpp

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -796,22 +796,27 @@ block_t* Planner::get_current_block() {
796796
*/
797797
void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t entry_factor, const_float_t exit_factor) {
798798

799-
uint32_t initial_rate = CEIL(block->nominal_rate * entry_factor),
800-
final_rate = CEIL(block->nominal_rate * exit_factor); // (steps per second)
801-
802-
// Limit minimal step rate (Otherwise the timer will overflow.)
803-
NOLESS(initial_rate, uint32_t(MINIMAL_STEP_RATE));
799+
uint32_t initial_rate = LROUND(block->nominal_rate * entry_factor),
800+
final_rate = LROUND(block->nominal_rate * exit_factor); // (steps per second)
801+
802+
// Legacy check against supposed timer overflow. However Stepper::calc_timer_interval() already
803+
// should protect against it. But removing this code produces judder in direction-switching
804+
// moves. This is because the current discrete stepping math diverges from physical motion under
805+
// constant acceleration when acceleration_steps_per_s2 is large compared to initial/final_rate.
806+
NOLESS(initial_rate, uint32_t(MINIMAL_STEP_RATE)); // Enforce the minimum speed
804807
NOLESS(final_rate, uint32_t(MINIMAL_STEP_RATE));
808+
NOMORE(initial_rate, block->nominal_rate); // NOTE: The nominal rate may be less than MINIMAL_STEP_RATE!
809+
NOMORE(final_rate, block->nominal_rate);
805810

806811
#if ANY(S_CURVE_ACCELERATION, LIN_ADVANCE)
807812
// If we have some plateau time, the cruise rate will be the nominal rate
808813
uint32_t cruise_rate = block->nominal_rate;
809814
#endif
810815

811816
// Steps for acceleration, plateau and deceleration
812-
int32_t plateau_steps = block->step_event_count;
813-
uint32_t accelerate_steps = 0,
814-
decelerate_steps = 0;
817+
int32_t plateau_steps = block->step_event_count,
818+
accelerate_steps = 0,
819+
decelerate_steps = 0;
815820

816821
const int32_t accel = block->acceleration_steps_per_s2;
817822
float inverse_accel = 0.0f;
@@ -820,10 +825,11 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t
820825
const float half_inverse_accel = 0.5f * inverse_accel,
821826
nominal_rate_sq = FLOAT_SQ(block->nominal_rate),
822827
// Steps required for acceleration, deceleration to/from nominal rate
823-
decelerate_steps_float = half_inverse_accel * (nominal_rate_sq - FLOAT_SQ(final_rate));
824-
float accelerate_steps_float = half_inverse_accel * (nominal_rate_sq - FLOAT_SQ(initial_rate));
828+
decelerate_steps_float = half_inverse_accel * (nominal_rate_sq - FLOAT_SQ(final_rate)),
829+
accelerate_steps_float = half_inverse_accel * (nominal_rate_sq - FLOAT_SQ(initial_rate));
830+
// Aims to fully reach nominal and final rates
825831
accelerate_steps = CEIL(accelerate_steps_float);
826-
decelerate_steps = FLOOR(decelerate_steps_float);
832+
decelerate_steps = CEIL(decelerate_steps_float);
827833

828834
// Steps between acceleration and deceleration, if any
829835
plateau_steps -= accelerate_steps + decelerate_steps;
@@ -833,13 +839,13 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t
833839
// Calculate accel / braking time in order to reach the final_rate exactly
834840
// at the end of this block.
835841
if (plateau_steps < 0) {
836-
accelerate_steps_float = CEIL((block->step_event_count + accelerate_steps_float - decelerate_steps_float) * 0.5f);
837-
accelerate_steps = _MIN(uint32_t(_MAX(accelerate_steps_float, 0)), block->step_event_count);
842+
accelerate_steps = LROUND((block->step_event_count + accelerate_steps_float - decelerate_steps_float) * 0.5f);
843+
LIMIT(accelerate_steps, 0, int32_t(block->step_event_count));
838844
decelerate_steps = block->step_event_count - accelerate_steps;
839845

840846
#if ANY(S_CURVE_ACCELERATION, LIN_ADVANCE)
841847
// We won't reach the cruising rate. Let's calculate the speed we will reach
842-
cruise_rate = final_speed(initial_rate, accel, accelerate_steps);
848+
NOMORE(cruise_rate, final_speed(initial_rate, accel, accelerate_steps));
843849
#endif
844850
}
845851
}
@@ -855,8 +861,8 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t
855861
#endif
856862

857863
// Store new block parameters
858-
block->accelerate_until = accelerate_steps;
859-
block->decelerate_after = block->step_event_count - decelerate_steps;
864+
block->accelerate_before = accelerate_steps;
865+
block->decelerate_start = block->step_event_count - decelerate_steps;
860866
block->initial_rate = initial_rate;
861867
#if ENABLED(S_CURVE_ACCELERATION)
862868
block->acceleration_time = acceleration_time;
@@ -3158,8 +3164,8 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s
31583164
block->step_event_count = num_steps;
31593165
block->initial_rate = block->final_rate = block->nominal_rate = last_page_step_rate; // steps/s
31603166

3161-
block->accelerate_until = 0;
3162-
block->decelerate_after = block->step_event_count;
3167+
block->accelerate_before = 0;
3168+
block->decelerate_start = block->step_event_count;
31633169

31643170
// Will be set to last direction later if directional format.
31653171
block->direction_bits.reset();

Marlin/src/module/planner.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,8 @@ typedef struct PlannerBlock {
238238
#endif
239239

240240
// Settings for the trapezoid generator
241-
uint32_t accelerate_until, // The index of the step event on which to stop acceleration
242-
decelerate_after; // The index of the step event on which to start decelerating
241+
uint32_t accelerate_before, // The index of the step event where cruising starts
242+
decelerate_start; // The index of the step event on which to start decelerating
243243

244244
#if ENABLED(S_CURVE_ACCELERATION)
245245
uint32_t cruise_rate, // The actual cruise rate to use, between end of the acceleration phase and start of deceleration phase

Marlin/src/module/stepper.cpp

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,16 @@
5858
*
5959
* time ----->
6060
*
61-
* The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates
62-
* first block->accelerate_until step_events_completed, then keeps going at constant speed until
63-
* step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset.
64-
* The slope of acceleration is calculated using v = u + at where t is the accumulated timer values of the steps so far.
61+
* The speed over time graph forms a TRAPEZOID. The slope of acceleration is calculated by
62+
* v = u + t
63+
* where 't' is the accumulated timer values of the steps so far.
64+
*
65+
* The Stepper ISR dynamically executes acceleration, deceleration, and cruising according to the block parameters.
66+
* - Start at block->initial_rate.
67+
* - Accelerate while step_events_completed < block->accelerate_before.
68+
* - Cruise while step_events_completed < block->decelerate_start.
69+
* - Decelerate after that, until all steps are completed.
70+
* - Reset the trapezoid generator.
6571
*/
6672

6773
/**
@@ -193,6 +199,7 @@ bool Stepper::abort_current_block;
193199
;
194200
#endif
195201

202+
// In timer_ticks
196203
uint32_t Stepper::acceleration_time, Stepper::deceleration_time;
197204

198205
#if MULTISTEPPING_LIMIT > 1
@@ -224,8 +231,8 @@ xyze_long_t Stepper::delta_error{0};
224231
xyze_long_t Stepper::advance_dividend{0};
225232
uint32_t Stepper::advance_divisor = 0,
226233
Stepper::step_events_completed = 0, // The number of step events executed in the current block
227-
Stepper::accelerate_until, // The count at which to stop accelerating
228-
Stepper::decelerate_after, // The count at which to start decelerating
234+
Stepper::accelerate_before, // The count at which to start cruising
235+
Stepper::decelerate_start, // The count at which to start decelerating
229236
Stepper::step_event_count; // The total event count for the current block
230237

231238
#if ANY(HAS_MULTI_EXTRUDER, MIXING_EXTRUDER)
@@ -2403,7 +2410,7 @@ hal_timer_t Stepper::block_phase_isr() {
24032410
// Step events not completed yet...
24042411

24052412
// Are we in acceleration phase ?
2406-
if (step_events_completed <= accelerate_until) { // Calculate new timer value
2413+
if (step_events_completed < accelerate_before) { // Calculate new timer value
24072414

24082415
#if ENABLED(S_CURVE_ACCELERATION)
24092416
// Get the next speed to use (Jerk limited!)
@@ -2420,6 +2427,7 @@ hal_timer_t Stepper::block_phase_isr() {
24202427
// step_rate to timer interval and steps per stepper isr
24212428
interval = calc_multistep_timer_interval(acc_step_rate << oversampling_factor);
24222429
acceleration_time += interval;
2430+
deceleration_time = 0; // Reset since we're doing acceleration first.
24232431

24242432
#if ENABLED(NONLINEAR_EXTRUSION)
24252433
calc_nonlinear_e(acc_step_rate << oversampling_factor);
@@ -2456,30 +2464,24 @@ hal_timer_t Stepper::block_phase_isr() {
24562464
#endif
24572465
}
24582466
// Are we in Deceleration phase ?
2459-
else if (step_events_completed > decelerate_after) {
2467+
else if (step_events_completed >= decelerate_start) {
24602468
uint32_t step_rate;
24612469

24622470
#if ENABLED(S_CURVE_ACCELERATION)
2463-
24642471
// If this is the 1st time we process the 2nd half of the trapezoid...
24652472
if (!bezier_2nd_half) {
24662473
// Initialize the Bézier speed curve
24672474
_calc_bezier_curve_coeffs(current_block->cruise_rate, current_block->final_rate, current_block->deceleration_time_inverse);
24682475
bezier_2nd_half = true;
2469-
// The first point starts at cruise rate. Just save evaluation of the Bézier curve
2470-
step_rate = current_block->cruise_rate;
2471-
}
2472-
else {
2473-
// Calculate the next speed to use
2474-
step_rate = deceleration_time < current_block->deceleration_time
2475-
? _eval_bezier_curve(deceleration_time)
2476-
: current_block->final_rate;
24772476
}
2478-
2477+
// Calculate the next speed to use
2478+
step_rate = deceleration_time < current_block->deceleration_time
2479+
? _eval_bezier_curve(deceleration_time)
2480+
: current_block->final_rate;
24792481
#else
24802482
// Using the old trapezoidal control
24812483
step_rate = STEP_MULTIPLY(deceleration_time, current_block->acceleration_rate);
2482-
if (step_rate < acc_step_rate) { // Still decelerating?
2484+
if (step_rate < acc_step_rate) {
24832485
step_rate = acc_step_rate - step_rate;
24842486
NOLESS(step_rate, current_block->final_rate);
24852487
}
@@ -2542,6 +2544,9 @@ hal_timer_t Stepper::block_phase_isr() {
25422544
if (ticks_nominal == 0) {
25432545
// step_rate to timer interval and loops for the nominal speed
25442546
ticks_nominal = calc_multistep_timer_interval(current_block->nominal_rate << oversampling_factor);
2547+
// Prepare for deceleration
2548+
IF_DISABLED(S_CURVE_ACCELERATION, acc_step_rate = current_block->nominal_rate);
2549+
deceleration_time = ticks_nominal / 2;
25452550

25462551
#if ENABLED(NONLINEAR_EXTRUSION)
25472552
calc_nonlinear_e(current_block->nominal_rate << oversampling_factor);
@@ -2664,9 +2669,6 @@ hal_timer_t Stepper::block_phase_isr() {
26642669
// Set flags for all moving axes, accounting for kinematics
26652670
set_axis_moved_for_current_block();
26662671

2667-
// No acceleration / deceleration time elapsed so far
2668-
acceleration_time = deceleration_time = 0;
2669-
26702672
#if ENABLED(ADAPTIVE_STEP_SMOOTHING)
26712673
// Nonlinear Extrusion needs at least 2x oversampling to permit increase of E step rate
26722674
// Otherwise assume no axis smoothing (via oversampling)
@@ -2720,8 +2722,8 @@ hal_timer_t Stepper::block_phase_isr() {
27202722
step_events_completed = 0;
27212723

27222724
// Compute the acceleration and deceleration points
2723-
accelerate_until = current_block->accelerate_until << oversampling_factor;
2724-
decelerate_after = current_block->decelerate_after << oversampling_factor;
2725+
accelerate_before = current_block->accelerate_before << oversampling_factor;
2726+
decelerate_start = current_block->decelerate_start << oversampling_factor;
27252727

27262728
TERN_(MIXING_EXTRUDER, mixer.stepper_setup(current_block->b_color));
27272729

@@ -2807,7 +2809,8 @@ hal_timer_t Stepper::block_phase_isr() {
28072809

28082810
// Calculate the initial timer interval
28092811
interval = calc_multistep_timer_interval(current_block->initial_rate << oversampling_factor);
2810-
acceleration_time += interval;
2812+
// Initialize ac/deceleration time as if half the time passed.
2813+
acceleration_time = deceleration_time = interval / 2;
28112814

28122815
#if ENABLED(NONLINEAR_EXTRUSION)
28132816
calc_nonlinear_e(current_block->initial_rate << oversampling_factor);

Marlin/src/module/stepper.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,8 +391,8 @@ class Stepper {
391391
static xyze_long_t advance_dividend;
392392
static uint32_t advance_divisor,
393393
step_events_completed, // The number of step events executed in the current block
394-
accelerate_until, // The point from where we need to stop acceleration
395-
decelerate_after, // The point from where we need to start decelerating
394+
accelerate_before, // The count at which to start cruising
395+
decelerate_start, // The count at which to start decelerating
396396
step_event_count; // The total event count for the current block
397397

398398
#if ANY(HAS_MULTI_EXTRUDER, MIXING_EXTRUDER)

0 commit comments

Comments
 (0)