@ -788,7 +788,7 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t
NOLESS ( initial_rate , uint32_t ( MINIMAL_STEP_RATE ) ) ;
NOLESS ( initial_rate , uint32_t ( MINIMAL_STEP_RATE ) ) ;
NOLESS ( final_rate , uint32_t ( MINIMAL_STEP_RATE ) ) ;
NOLESS ( final_rate , uint32_t ( MINIMAL_STEP_RATE ) ) ;
# if ENABLED(S_CURVE_ACCELERATION )
# if EITHER(S_CURVE_ACCELERATION, LIN_ADVANCE )
// If we have some plateau time, the cruise rate will be the nominal rate
// If we have some plateau time, the cruise rate will be the nominal rate
uint32_t cruise_rate = block - > nominal_rate ;
uint32_t cruise_rate = block - > nominal_rate ;
# endif
# endif
@ -820,7 +820,7 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t
accelerate_steps = _MIN ( uint32_t ( _MAX ( accelerate_steps_float , 0 ) ) , block - > step_event_count ) ;
accelerate_steps = _MIN ( uint32_t ( _MAX ( accelerate_steps_float , 0 ) ) , block - > step_event_count ) ;
decelerate_steps = block - > step_event_count - accelerate_steps ;
decelerate_steps = block - > step_event_count - accelerate_steps ;
# if ENABLED(S_CURVE_ACCELERATION )
# if EITHER(S_CURVE_ACCELERATION, LIN_ADVANCE )
// We won't reach the cruising rate. Let's calculate the speed we will reach
// We won't reach the cruising rate. Let's calculate the speed we will reach
cruise_rate = final_speed ( initial_rate , accel , accelerate_steps ) ;
cruise_rate = final_speed ( initial_rate , accel , accelerate_steps ) ;
# endif
# endif
@ -849,6 +849,14 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t
# endif
# endif
block - > final_rate = final_rate ;
block - > final_rate = final_rate ;
# if ENABLED(LIN_ADVANCE)
if ( block - > la_advance_rate ) {
const float comp = extruder_advance_K [ block - > extruder ] * block - > steps . e / block - > step_event_count ;
block - > max_adv_steps = cruise_rate * comp ;
block - > final_adv_steps = final_rate * comp ;
}
# endif
# if ENABLED(LASER_POWER_TRAP)
# if ENABLED(LASER_POWER_TRAP)
/**
/**
* Laser Trapezoid Calculations
* Laser Trapezoid Calculations
@ -899,74 +907,75 @@ void Planner::calculate_trapezoid_for_block(block_t * const block, const_float_t
# endif // LASER_POWER_TRAP
# endif // LASER_POWER_TRAP
}
}
/* PLANNER SPEED DEFINITION
/**
+ - - - - - - - - + < - current - > nominal_speed
* PLANNER SPEED DEFINITION
/ \
* + - - - - - - - - + < - current - > nominal_speed
current - > entry_speed - > + \
* / \
| + < - next - > entry_speed ( aka exit speed )
* current - > entry_speed - > + \
+ - - - - - - - - - - - - - +
* | + < - next - > entry_speed ( aka exit speed )
time - - >
* + - - - - - - - - - - - - - +
* time - - >
Recalculates the motion plan according to the following basic guidelines :
*
* Recalculates the motion plan according to the following basic guidelines :
1. Go over every feasible block sequentially in reverse order and calculate the junction speeds
*
( i . e . current - > entry_speed ) such that :
* 1. Go over every feasible block sequentially in reverse order and calculate the junction speeds
a . No junction speed exceeds the pre - computed maximum junction speed limit or nominal speeds of
* ( i . e . current - > entry_speed ) such that :
neighboring blocks .
* a . No junction speed exceeds the pre - computed maximum junction speed limit or nominal speeds of
b . A block entry speed cannot exceed one reverse - computed from its exit speed ( next - > entry_speed )
* neighboring blocks .
with a maximum allowable deceleration over the block travel distance .
* b . A block entry speed cannot exceed one reverse - computed from its exit speed ( next - > entry_speed )
c . The last ( or newest appended ) block is planned from a complete stop ( an exit speed of zero ) .
* with a maximum allowable deceleration over the block travel distance .
2. Go over every block in chronological ( forward ) order and dial down junction speed values if
* c . The last ( or newest appended ) block is planned from a complete stop ( an exit speed of zero ) .
a . The exit speed exceeds the one forward - computed from its entry speed with the maximum allowable
* 2. Go over every block in chronological ( forward ) order and dial down junction speed values if
acceleration over the block travel distance .
* a . The exit speed exceeds the one forward - computed from its entry speed with the maximum allowable
* acceleration over the block travel distance .
When these stages are complete , the planner will have maximized the velocity profiles throughout the all
*
of the planner blocks , where every block is operating at its maximum allowable acceleration limits . In
* When these stages are complete , the planner will have maximized the velocity profiles throughout the all
other words , for all of the blocks in the planner , the plan is optimal and no further speed improvements
* of the planner blocks , where every block is operating at its maximum allowable acceleration limits . In
are possible . If a new block is added to the buffer , the plan is recomputed according to the said
* other words , for all of the blocks in the planner , the plan is optimal and no further speed improvements
guidelines for a new optimal plan .
* are possible . If a new block is added to the buffer , the plan is recomputed according to the said
* guidelines for a new optimal plan .
To increase computational efficiency of these guidelines , a set of planner block pointers have been
*
created to indicate stop - compute points for when the planner guidelines cannot logically make any further
* To increase computational efficiency of these guidelines , a set of planner block pointers have been
changes or improvements to the plan when in normal operation and new blocks are streamed and added to the
* created to indicate stop - compute points for when the planner guidelines cannot logically make any further
planner buffer . For example , if a subset of sequential blocks in the planner have been planned and are
* changes or improvements to the plan when in normal operation and new blocks are streamed and added to the
bracketed by junction velocities at their maximums ( or by the first planner block as well ) , no new block
* planner buffer . For example , if a subset of sequential blocks in the planner have been planned and are
added to the planner buffer will alter the velocity profiles within them . So we no longer have to compute
* bracketed by junction velocities at their maximums ( or by the first planner block as well ) , no new block
them . Or , if a set of sequential blocks from the first block in the planner ( or a optimal stop - compute
* added to the planner buffer will alter the velocity profiles within them . So we no longer have to compute
point ) are all accelerating , they are all optimal and can not be altered by a new block added to the
* them . Or , if a set of sequential blocks from the first block in the planner ( or a optimal stop - compute
planner buffer , as this will only further increase the plan speed to chronological blocks until a maximum
* point ) are all accelerating , they are all optimal and can not be altered by a new block added to the
junction velocity is reached . However , if the operational conditions of the plan changes from infrequently
* planner buffer , as this will only further increase the plan speed to chronological blocks until a maximum
used feed holds or feedrate overrides , the stop - compute pointers will be reset and the entire plan is
* junction velocity is reached . However , if the operational conditions of the plan changes from infrequently
recomputed as stated in the general guidelines .
* used feed holds or feedrate overrides , the stop - compute pointers will be reset and the entire plan is
* recomputed as stated in the general guidelines .
Planner buffer index mapping :
*
- block_buffer_tail : Points to the beginning of the planner buffer . First to be executed or being executed .
* Planner buffer index mapping :
- block_buffer_head : Points to the buffer block after the last block in the buffer . Used to indicate whether
* - block_buffer_tail : Points to the beginning of the planner buffer . First to be executed or being executed .
the buffer is full or empty . As described for standard ring buffers , this block is always empty .
* - block_buffer_head : Points to the buffer block after the last block in the buffer . Used to indicate whether
- block_buffer_planned : Points to the first buffer block after the last optimally planned block for normal
* the buffer is full or empty . As described for standard ring buffers , this block is always empty .
streaming operating conditions . Use for planning optimizations by avoiding recomputing parts of the
* - block_buffer_planned : Points to the first buffer block after the last optimally planned block for normal
planner buffer that don ' t change with the addition of a new block , as describe above . In addition ,
* streaming operating conditions . Use for planning optimizations by avoiding recomputing parts of the
this block can never be less than block_buffer_tail and will always be pushed forward and maintain
* planner buffer that don ' t change with the addition of a new block , as describe above . In addition ,
this requirement when encountered by the Planner : : release_current_block ( ) routine during a cycle .
* 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 many short
*
segments ( e . g . , complex curves ) may seem to move slowly . This is because there simply isn ' t
* NOTE : Since the planner only computes on what ' s in the planner buffer , some motions with many short
enough combined distance traveled in the entire buffer to accelerate up to the nominal speed and
* segments ( e . g . , complex curves ) may seem to move slowly . This is because there simply isn ' t
then decelerate to a complete stop at the end of the buffer , as stated by the guidelines . If this
* enough combined distance traveled in the entire buffer to accelerate up to the nominal speed and
happens and becomes an annoyance , there are a few simple solutions :
* 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 .
* - Maximize the machine acceleration . The planner will be able to compute higher velocity profiles
* within the same combined distance .
- 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 .
* - 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 .
- 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
* - Maximize the planner buffer size . This also will increase the combined distance for the planner to
optimal plan , so select carefully .
* compute over . It also increases the number of computations the planner has to perform to compute an
* optimal plan , so select carefully .
- 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 .
* - 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.
// The kernel called by recalculate() when scanning the plan from last to first entry.
@ -1211,13 +1220,6 @@ void Planner::recalculate_trapezoids(TERN_(HINTS_SAFE_EXIT_SPEED, const_float_t
// NOTE: Entry and exit factors always > 0 by all previous logic operations.
// NOTE: Entry and exit factors always > 0 by all previous logic operations.
const float nomr = 1.0f / block - > nominal_speed ;
const float nomr = 1.0f / block - > nominal_speed ;
calculate_trapezoid_for_block ( block , current_entry_speed * nomr , next_entry_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 = block - > nominal_speed * comp ;
block - > final_adv_steps = next_entry_speed * comp ;
}
# endif
}
}
// Reset current only to ensure next trapezoid is computed - The
// Reset current only to ensure next trapezoid is computed - The
@ -1251,13 +1253,6 @@ void Planner::recalculate_trapezoids(TERN_(HINTS_SAFE_EXIT_SPEED, const_float_t
const float nomr = 1.0f / block - > nominal_speed ;
const float nomr = 1.0f / block - > nominal_speed ;
calculate_trapezoid_for_block ( block , current_entry_speed * nomr , next_entry_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 = block - > nominal_speed * comp ;
block - > final_adv_steps = next_entry_speed * comp ;
}
# endif
}
}
// Reset block 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
@ -2502,13 +2497,15 @@ bool Planner::_populate_block(
// Compute and limit the acceleration rate for the trapezoid generator.
// Compute and limit the acceleration rate for the trapezoid generator.
const float steps_per_mm = block - > step_event_count * inverse_millimeters ;
const float steps_per_mm = block - > step_event_count * inverse_millimeters ;
uint32_t accel ;
uint32_t accel ;
# if ENABLED(LIN_ADVANCE)
bool use_advance_lead = false ;
# endif
if ( NUM_AXIS_GANG (
if ( NUM_AXIS_GANG (
! block - > steps . a , & & ! block - > steps . b , & & ! block - > steps . c ,
! block - > steps . a , & & ! block - > steps . b , & & ! block - > steps . c ,
& & ! block - > steps . i , & & ! block - > steps . j , & & ! block - > steps . k ,
& & ! block - > steps . i , & & ! block - > steps . j , & & ! block - > steps . k ,
& & ! block - > steps . u , & & ! block - > steps . v , & & ! block - > steps . w )
& & ! block - > steps . u , & & ! block - > steps . v , & & ! block - > steps . w )
) { // Is this a retract / recover move?
) { // Is this a retract / recover move?
accel = CEIL ( settings . retract_acceleration * steps_per_mm ) ; // Convert to: acceleration steps/sec^2
accel = CEIL ( settings . retract_acceleration * steps_per_mm ) ; // Convert to: acceleration steps/sec^2
TERN_ ( LIN_ADVANCE , block - > use_advance_lead = false ) ; // No linear advance for simple retract/recover
}
}
else {
else {
# define LIMIT_ACCEL_LONG(AXIS,INDX) do{ \
# define LIMIT_ACCEL_LONG(AXIS,INDX) do{ \
@ -2537,31 +2534,27 @@ bool Planner::_populate_block(
*
*
* esteps : This is a print move , because we checked for A , B , C steps before .
* esteps : This is a print move , because we checked for A , B , C steps before .
*
*
* extruder_advance_K [ active_ extruder] : There is an advance factor set for this extruder .
* extruder_advance_K [ extruder ] : There is an advance factor set for this extruder .
*
*
* de > 0 : Extruder is running forward ( e . g . , for " Wipe while retracting " ( Slic3r ) or " Combing " ( Cura ) moves )
* de > 0 : Extruder is running forward ( e . g . , for " Wipe while retracting " ( Slic3r ) or " Combing " ( Cura ) moves )
*/
*/
block - > use_advance_lead = esteps
use_advance_lead = esteps & & extruder_advance_K [ extruder ] & & de > 0 ;
& & extruder_advance_K [ active_extruder ]
& & de > 0 ;
if ( block - > use_advance_lead ) {
if ( use_advance_lead ) {
block - > e_D_ratio = ( target_float . e - position_float . e ) /
float e_D_ratio = ( target_float . e - position_float . e ) /
# if IS_KINEMATIC
TERN ( IS_KINEMATIC , block - > millimeters ,
block - > millimeters
# else
SQRT ( sq ( target_float . x - position_float . x )
SQRT ( sq ( target_float . x - position_float . x )
+ sq ( target_float . y - position_float . y )
+ sq ( target_float . y - position_float . y )
+ sq ( target_float . z - position_float . z ) )
+ sq ( target_float . z - position_float . z ) )
# endif
) ;
;
// Check for unusual high e_D ratio to detect if a retract move was combined with the last print move due to min. steps per segment. Never execute this with advance!
// Check for unusual high e_D ratio to detect if a retract move was combined with the last print move due to min. steps per segment. Never execute this with advance!
// This assumes no one will use a retract length of 0mm < retr_length < ~0.2mm and no one will print 100mm wide lines using 3mm filament or 35mm wide lines using 1.75mm filament.
// This assumes no one will use a retract length of 0mm < retr_length < ~0.2mm and no one will print 100mm wide lines using 3mm filament or 35mm wide lines using 1.75mm filament.
if ( block - > e_D_ratio > 3.0f )
if ( e_D_ratio > 3.0f )
block - > use_advance_lead = false ;
use_advance_lead = false ;
else {
else {
const uint32_t max_accel_steps_per_s2 = MAX_E_JERK ( extruder ) / ( extruder_advance_K [ active_extruder ] * block - > e_D_ratio ) * steps_per_mm ;
// Scale E acceleration so that it will be possible to jump to the advance speed.
const uint32_t max_accel_steps_per_s2 = MAX_E_JERK ( extruder ) / ( extruder_advance_K [ extruder ] * e_D_ratio ) * steps_per_mm ;
if ( TERN0 ( LA_DEBUG , accel > max_accel_steps_per_s2 ) )
if ( TERN0 ( LA_DEBUG , accel > max_accel_steps_per_s2 ) )
SERIAL_ECHOLNPGM ( " Acceleration limited. " ) ;
SERIAL_ECHOLNPGM ( " Acceleration limited. " ) ;
NOMORE ( accel , max_accel_steps_per_s2 ) ;
NOMORE ( accel , max_accel_steps_per_s2 ) ;
@ -2593,13 +2586,21 @@ bool Planner::_populate_block(
block - > acceleration_rate = ( uint32_t ) ( accel * ( float ( 1UL < < 24 ) / ( STEPPER_TIMER_RATE ) ) ) ;
block - > acceleration_rate = ( uint32_t ) ( accel * ( float ( 1UL < < 24 ) / ( STEPPER_TIMER_RATE ) ) ) ;
# endif
# endif
# if ENABLED(LIN_ADVANCE)
# if ENABLED(LIN_ADVANCE)
if ( block - > use_advance_lead ) {
block - > la_advance_rate = 0 ;
block - > advance_speed = ( STEPPER_TIMER_RATE ) / ( extruder_advance_K [ active_extruder ] * block - > e_D_ratio * block - > acceleration * settings . axis_steps_per_mm [ E_AXIS_N ( extruder ) ] ) ;
block - > la_scaling = 0 ;
if ( use_advance_lead ) {
// the Bresenham algorithm will convert this step rate into extruder steps
block - > la_advance_rate = extruder_advance_K [ extruder ] * block - > acceleration_steps_per_s2 ;
// reduce LA ISR frequency by calling it only often enough to ensure that there will
// never be more than four extruder steps per call
for ( uint32_t dividend = block - > steps . e < < 1 ; dividend < = ( block - > step_event_count > > 2 ) ; dividend < < = 1 )
block - > la_scaling + + ;
# if ENABLED(LA_DEBUG)
# if ENABLED(LA_DEBUG)
if ( extruder_advance_K [ active_extruder ] * block - > e_D_ratio * block - > acceleration * 2 < block - > nominal_speed * block - > e_D_ratio )
if ( block - > la_advance_rate > > block - > la_scaling > 10000 )
SERIAL_ECHOLNPGM ( " More than 2 steps per eISR loop executed. " ) ;
SERIAL_ECHOLNPGM ( " eISR running at > 10kHz: " , block - > la_advance_rate ) ;
if ( block - > advance_speed < 200 )
SERIAL_ECHOLNPGM ( " eISR running at > 10kHz. " ) ;
# endif
# endif
}
}
# endif
# endif