2016-03-25 01:19:46 -05:00
/**
2016-03-24 13:01:20 -05:00
* Marlin 3 D Printer Firmware
2020-02-03 08:00:57 -06:00
* Copyright ( c ) 2020 MarlinFirmware [ https : //github.com/MarlinFirmware/Marlin]
2016-03-24 13:01:20 -05:00
*
* Based on Sprinter and grbl .
2019-06-27 23:57:50 -05:00
* Copyright ( c ) 2011 Camiel Gubbels / Erik van der Zalm
2016-03-24 13:01:20 -05:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2020-07-22 22:20:14 -05:00
* along with this program . If not , see < https : //www.gnu.org/licenses/>.
2016-03-24 13:01:20 -05:00
*
*/
2018-10-10 09:45:20 -05:00
# pragma once
2016-03-24 13:01:20 -05:00
2016-03-25 01:19:46 -05:00
/**
2016-05-03 19:00:28 -05:00
* planner . h
*
* Buffer movement commands and manage the acceleration profile plan
*
* Derived from Grbl
* Copyright ( c ) 2009 - 2011 Simen Svale Skogsrud
*/
2011-11-15 15:50:43 -06:00
2020-01-02 19:01:38 -06:00
# include "../MarlinCore.h"
2011-11-15 15:50:43 -06:00
2020-06-15 18:54:00 -05:00
# if ENABLED(JD_HANDLE_SMALL_SEGMENTS)
2020-05-02 23:59:09 -05:00
// Enable this option for perfect accuracy but maximum
// computation. Should be fine on ARM processors.
//#define JD_USE_MATH_ACOS
// Disable this option to save 120 bytes of PROGMEM,
// but incur increased computation and a reduction
// in accuracy.
# define JD_USE_LOOKUP_TABLE
# endif
2017-09-08 15:35:25 -05:00
# include "motion.h"
2018-05-09 00:17:53 -05:00
# include "../gcode/queue.h"
2017-09-08 15:35:25 -05:00
# if ENABLED(DELTA)
# include "delta.h"
# endif
2018-05-01 07:05:18 -05:00
# if ABL_PLANAR
2019-09-29 04:25:39 -05:00
# include "../libs/vector_3.h" // for matrix_3x3
2016-04-27 20:06:32 -05:00
# endif
2018-09-16 21:24:15 -05:00
# if ENABLED(FWRETRACT)
# include "../feature/fwretract.h"
# endif
2018-10-16 03:38:57 -05:00
# if ENABLED(MIXING_EXTRUDER)
# include "../feature/mixing.h"
# endif
2019-10-15 16:10:20 -05:00
# if HAS_CUTTER
2020-04-02 19:31:08 -05:00
# include "../feature/spindle_laser_types.h"
2019-10-15 16:10:20 -05:00
# endif
2020-05-11 19:22:41 -05:00
# 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
2019-09-29 04:25:39 -05:00
// Feedrate for manual moves
# ifdef MANUAL_FEEDRATE
2020-02-03 00:00:35 -06:00
constexpr xyze_feedrate_t _mf = MANUAL_FEEDRATE ,
2021-06-05 02:18:47 -05:00
manual_feedrate_mm_s = LOGICAL_AXIS_ARRAY ( _mf . e / 60.0f ,
_mf . x / 60.0f , _mf . y / 60.0f , _mf . z / 60.0f ,
_mf . i / 60.0f , _mf . j / 60.0f , _mf . k / 60.0f ) ;
2019-09-29 04:25:39 -05:00
# endif
2020-04-23 20:49:11 -05:00
# if IS_KINEMATIC && HAS_JUNCTION_DEVIATION
2020-03-25 17:55:36 -05:00
# define HAS_DIST_MM_ARG 1
# endif
2018-03-06 22:35:22 -06:00
enum BlockFlagBit : char {
2016-10-30 16:05:14 -05:00
// Recalculate trapezoids on entry junction. For optimization.
BLOCK_BIT_RECALCULATE ,
// Nominal speed always reached.
// i.e., The segment is long enough, so the nominal speed is reachable if accelerating
// from a safe speed (in consideration of jerking from zero speed).
BLOCK_BIT_NOMINAL_LENGTH ,
2017-12-07 23:03:36 -06:00
// The block is segment 2+ of a longer move
2018-05-03 17:45:13 -05:00
BLOCK_BIT_CONTINUED ,
// Sync the stepper counts from the block
BLOCK_BIT_SYNC_POSITION
2020-05-11 19:22:41 -05:00
// Direct stepping page
# if ENABLED(DIRECT_STEPPING)
, BLOCK_BIT_IS_PAGE
# endif
2021-03-24 12:21:11 -05:00
// Sync the fan speeds from the block
# if ENABLED(LASER_SYNCHRONOUS_M106_M107)
, BLOCK_BIT_SYNC_FANS
# endif
2016-10-30 16:05:14 -05:00
} ;
2016-10-10 23:17:49 -05:00
2018-03-06 22:35:22 -06:00
enum BlockFlag : char {
2020-05-11 19:22:41 -05:00
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
2021-03-24 12:21:11 -05:00
# if ENABLED(LASER_SYNCHRONOUS_M106_M107)
, BLOCK_FLAG_SYNC_FANS = _BV ( BLOCK_BIT_SYNC_FANS )
# endif
2016-10-10 23:17:49 -05:00
} ;
2021-03-24 12:21:11 -05:00
# define BLOCK_MASK_SYNC ( BLOCK_FLAG_SYNC_POSITION | TERN0(LASER_SYNCHRONOUS_M106_M107, BLOCK_FLAG_SYNC_FANS) )
2020-04-02 19:31:08 -05:00
# if ENABLED(LASER_POWER_INLINE)
typedef struct {
2020-06-08 00:47:31 -05:00
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
2020-04-02 19:31:08 -05:00
# 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
2016-04-27 20:06:32 -05:00
/**
* struct block_t
*
* A single entry in the planner buffer .
* Tracks linear movement over multiple axes .
*
* The " nominal " values are as - specified by gcode , and
* may never actually be reached due to acceleration limits .
*/
2018-10-16 07:28:52 -05:00
typedef struct block_t {
2016-04-27 20:06:32 -05:00
2018-06-27 18:11:16 -05:00
volatile uint8_t flag ; // Block flags (See BlockFlag enum above) - Modified by ISR and main thread!
2016-10-30 16:08:46 -05:00
2018-05-09 00:17:53 -05:00
// Fields used by the motion planner to manage acceleration
float nominal_speed_sqr , // The nominal speed for this block in (mm/sec)^2
entry_speed_sqr , // Entry speed at previous-current junction in (mm/sec)^2
max_entry_speed_sqr , // Maximum allowable junction entry speed in (mm/sec)^2
millimeters , // The total travel of this block in mm
acceleration ; // acceleration mm/sec^2
2016-04-27 20:06:32 -05:00
2018-05-09 00:17:53 -05:00
union {
2019-09-29 04:25:39 -05:00
abce_ulong_t steps ; // Step count along each axis
abce_long_t position ; // New position to force when this sync block is executed
2018-05-09 00:17:53 -05:00
} ;
2016-10-30 16:08:46 -05:00
uint32_t step_event_count ; // The number of step events required to complete this block
2016-04-27 20:06:32 -05:00
2020-09-20 18:29:08 -05:00
# if HAS_MULTI_EXTRUDER
2018-10-16 03:38:57 -05:00
uint8_t extruder ; // The extruder to move (if E move)
2018-10-16 07:28:52 -05:00
# else
static constexpr uint8_t extruder = 0 ;
2018-09-10 23:09:26 -05:00
# endif
2018-05-09 00:17:53 -05:00
2021-03-24 05:40:28 -05:00
# if ENABLED(MIXING_EXTRUDER)
mixer_comp_t b_color [ MIXING_STEPPERS ] ; // Normalized color for the mixing steppers
# endif
2016-06-28 17:06:56 -05:00
2018-04-06 20:48:06 -05:00
// Settings for the trapezoid generator
2018-05-09 00:17:53 -05:00
uint32_t accelerate_until , // The index of the step event on which to stop acceleration
decelerate_after ; // The index of the step event on which to start decelerating
2018-04-06 20:48:06 -05:00
2018-05-26 02:02:39 -05:00
# if ENABLED(S_CURVE_ACCELERATION)
2018-06-10 18:02:54 -05:00
uint32_t cruise_rate , // The actual cruise rate to use, between end of the acceleration phase and start of deceleration phase
acceleration_time , // Acceleration time and deceleration time in STEP timer counts
deceleration_time ,
acceleration_time_inverse , // Inverse of acceleration and deceleration periods, expressed as integer. Scale depends on CPU being used
2018-04-11 18:13:42 -05:00
deceleration_time_inverse ;
2018-04-06 20:48:06 -05:00
# else
2018-05-09 00:17:53 -05:00
uint32_t acceleration_rate ; // The acceleration rate used for acceleration calculation
2018-04-06 20:48:06 -05:00
# endif
2016-04-27 20:06:32 -05:00
2016-10-30 16:08:46 -05:00
uint8_t direction_bits ; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h)
2016-04-27 20:06:32 -05:00
2016-05-04 14:10:42 -05:00
// Advance extrusion
# if ENABLED(LIN_ADVANCE)
bool use_advance_lead ;
2018-06-02 22:59:21 -05:00
uint16_t advance_speed , // STEP timer value for extruder speed offset ISR
2018-02-23 00:53:29 -06:00
max_adv_steps , // max. advance steps to get cruising speed pressure (not always nominal_speed!)
final_adv_steps ; // advance steps due to exit speed
float e_D_ratio ;
2011-11-15 15:50:43 -06:00
# endif
2016-10-30 16:08:46 -05:00
uint32_t nominal_rate , // The nominal step rate for this block in step_events/sec
initial_rate , // The jerk-adjusted step rate at start of block
final_rate , // The minimal rate at exit
acceleration_steps_per_s2 ; // acceleration steps/sec^2
2016-03-05 20:27:45 -06:00
2020-05-11 19:22:41 -05:00
# if ENABLED(DIRECT_STEPPING)
page_idx_t page_idx ; // Page index used for direct stepping
# endif
2019-10-15 16:10:20 -05:00
# if HAS_CUTTER
cutter_power_t cutter_power ; // Power level for Spindle, Laser, etc.
# endif
2020-04-27 04:41:18 -05:00
# if HAS_FAN
2018-10-07 15:34:41 -05:00
uint8_t fan_speed [ FAN_COUNT ] ;
2016-03-05 20:27:45 -06:00
# endif
2015-07-31 00:30:29 -05:00
# if ENABLED(BARICUDA)
2017-07-17 22:01:20 -05:00
uint8_t valve_pressure , e_to_p_pressure ;
2013-06-06 17:49:25 -05:00
# endif
2016-12-15 09:21:32 -06:00
2020-09-28 01:13:27 -05:00
# if HAS_WIRED_LCD
2019-08-16 21:17:10 -05:00
uint32_t segment_time_us ;
# endif
2016-03-05 20:27:45 -06:00
2019-09-10 18:52:41 -05:00
# if ENABLED(POWER_LOSS_RECOVERY)
uint32_t sdpos ;
# endif
2020-04-02 19:31:08 -05:00
# if ENABLED(LASER_POWER_INLINE)
block_laser_t laser ;
# endif
2011-11-15 15:50:43 -06:00
} block_t ;
2020-04-22 16:35:03 -05:00
# if ANY(LIN_ADVANCE, SCARA_FEEDRATE_SCALING, GRADIENT_MIX, LCD_SHOW_E_TOTAL)
# define HAS_POSITION_FLOAT 1
# endif
2018-04-05 15:47:56 -05:00
2015-03-20 22:42:49 -05:00
# define BLOCK_MOD(n) ((n)&(BLOCK_BUFFER_SIZE-1))
2013-09-29 11:20:06 -05:00
2020-04-02 19:31:08 -05:00
# if ENABLED(LASER_POWER_INLINE)
typedef struct {
/**
2020-06-08 00:47:31 -05:00
* Laser status flags
2020-04-02 19:31:08 -05:00
*/
2020-06-08 00:47:31 -05:00
power_status_t status ;
2020-04-02 19:31:08 -05:00
/**
* Laser power : 0 or 255 in case of PWM - less laser ,
2020-06-08 00:47:31 -05:00
* or the OCR ( oscillator count register ) value ;
2020-04-02 19:31:08 -05:00
*
2020-06-08 00:47:31 -05:00
* Using OCR instead of raw power , because it avoids
* floating point operations during the move loop .
2020-04-02 19:31:08 -05:00
*/
uint8_t power ;
2020-05-12 00:09:18 -05:00
} laser_state_t ;
2020-04-02 19:31:08 -05:00
# endif
2018-10-10 09:45:20 -05:00
typedef struct {
2021-05-18 22:51:19 -05:00
uint32_t max_acceleration_mm_per_s2 [ DISTINCT_AXES ] , // (mm/s^2) M201 XYZE
2019-09-26 01:28:09 -05:00
min_segment_time_us ; // (µs) M205 B
2021-05-18 22:51:19 -05:00
float axis_steps_per_mm [ DISTINCT_AXES ] ; // (steps) M92 XYZE - Steps per millimeter
feedRate_t max_feedrate_mm_s [ DISTINCT_AXES ] ; // (mm/s) M203 XYZE - Max speeds
2019-09-26 01:28:09 -05:00
float acceleration , // (mm/s^2) M204 S - Normal acceleration. DEFAULT ACCELERATION for all printing moves.
retract_acceleration , // (mm/s^2) M204 R - Retract acceleration. Filament pull-back and push-forward while standing still in the other axes
travel_acceleration ; // (mm/s^2) M204 T - Travel acceleration. DEFAULT ACCELERATION for all NON printing moves.
feedRate_t min_feedrate_mm_s , // (mm/s) M205 S - Minimum linear feedrate
min_travel_feedrate_mm_s ; // (mm/s) M205 T - Minimum travel feedrate
2018-10-10 09:45:20 -05:00
} planner_settings_t ;
2018-11-29 11:39:31 -06:00
# if DISABLED(SKEW_CORRECTION)
2018-10-10 09:45:20 -05:00
# define XY_SKEW_FACTOR 0
# define XZ_SKEW_FACTOR 0
# define YZ_SKEW_FACTOR 0
# endif
typedef struct {
# if ENABLED(SKEW_CORRECTION_GCODE)
float xy ;
# if ENABLED(SKEW_CORRECTION_FOR_Z)
float xz , yz ;
# else
const float xz = XZ_SKEW_FACTOR , yz = YZ_SKEW_FACTOR ;
# endif
# else
const float xy = XY_SKEW_FACTOR ,
xz = XZ_SKEW_FACTOR , yz = YZ_SKEW_FACTOR ;
# endif
} skew_factor_t ;
2020-11-16 14:56:05 -06:00
# if ENABLED(DISABLE_INACTIVE_EXTRUDER)
typedef IF < ( BLOCK_BUFFER_SIZE > 64 ) , uint16_t , uint8_t > : : type last_move_t ;
# endif
2016-04-27 20:06:32 -05:00
class Planner {
public :
2013-09-29 11:20:06 -05:00
2016-04-27 20:06:32 -05:00
/**
2017-12-08 21:38:45 -06:00
* The move buffer , calculated in stepper steps
*
* block_buffer is a ring buffer . . .
*
* head , tail : indexes for write , read
* head = = tail : the buffer is empty
* head ! = tail : blocks are in the buffer
* head = = ( tail - 1 ) % size : the buffer is full
*
2017-12-09 07:41:19 -06:00
* Writer of head is Planner : : buffer_segment ( ) .
2017-12-08 21:38:45 -06:00
* Reader of tail is Stepper : : isr ( ) . Always consider tail busy / read - only
2016-04-27 20:06:32 -05:00
*/
2016-05-26 13:22:51 -05:00
static block_t block_buffer [ BLOCK_BUFFER_SIZE ] ;
2017-12-08 21:38:45 -06:00
static volatile uint8_t block_buffer_head , // Index of the next block to be pushed
2018-06-27 18:11:16 -05:00
block_buffer_nonbusy , // Index of the first non busy block
block_buffer_planned , // Index of the optimally planned block
2017-12-08 21:38:45 -06:00
block_buffer_tail ; // Index of the busy block, if any
2018-05-12 22:49:54 -05:00
static uint16_t cleaning_buffer_counter ; // A counter to disable queuing of blocks
2018-06-27 18:11:16 -05:00
static uint8_t delay_before_delivering ; // This counter delays delivery of blocks when queue becomes empty to allow the opportunity of merging blocks
2016-05-26 13:22:51 -05:00
2016-12-03 22:02:27 -06:00
# if ENABLED(DISTINCT_E_FACTORS)
2017-12-08 21:38:45 -06:00
static uint8_t last_extruder ; // Respond to extruder change
2016-12-03 22:02:27 -06:00
# endif
2020-05-11 19:22:41 -05:00
# if ENABLED(DIRECT_STEPPING)
static uint32_t last_page_step_rate ; // Last page step rate given
static xyze_bool_t last_page_dir ; // Last page direction given
# endif
2021-05-21 08:23:09 -05:00
# if HAS_EXTRUDERS
2019-09-10 02:20:49 -05:00
static int16_t flow_percentage [ EXTRUDERS ] ; // Extrusion factor for each extruder
static float e_factor [ EXTRUDERS ] ; // The flow percentage and volumetric multiplier combine to scale E movement
# endif
2017-12-19 19:44:11 -06:00
# if DISABLED(NO_VOLUMETRICS)
static float filament_size [ EXTRUDERS ] , // diameter of filament (in millimeters), typically around 1.75 or 2.85, 0 disables the volumetric calculations for the extruder
volumetric_area_nominal , // Nominal cross-sectional area
volumetric_multiplier [ EXTRUDERS ] ; // Reciprocal of cross-sectional area of filament (in mm^2). Pre-calculated to reduce computation in the planner
// May be auto-adjusted by a filament width sensor
# endif
2017-09-18 05:51:45 -05:00
2020-06-08 03:24:46 -05:00
# if ENABLED(VOLUMETRIC_EXTRUDER_LIMIT)
static float volumetric_extruder_limit [ EXTRUDERS ] , // Maximum mm^3/sec the extruder can handle
volumetric_extruder_feedrate_limit [ EXTRUDERS ] ; // Feedrate limit (mm/s) calculated from volume limit
# endif
2018-10-10 09:45:20 -05:00
static planner_settings_t settings ;
2020-05-12 00:09:18 -05:00
# if ENABLED(LASER_POWER_INLINE)
2020-06-08 00:47:31 -05:00
static laser_state_t laser_inline ;
2020-05-12 00:09:18 -05:00
# endif
2021-05-18 22:51:19 -05:00
static uint32_t max_acceleration_steps_per_s2 [ DISTINCT_AXES ] ; // (steps/s^2) Derived from mm_per_s2
static float steps_to_mm [ DISTINCT_AXES ] ; // Millimeters per step
2016-04-27 20:06:32 -05:00
2020-04-23 20:49:11 -05:00
# if HAS_JUNCTION_DEVIATION
2021-05-18 22:51:19 -05:00
static float junction_deviation_mm ; // (mm) M205 J
2020-05-05 00:28:39 -05:00
# if HAS_LINEAR_E_JERK
2021-05-18 22:51:19 -05:00
static float max_e_jerk [ DISTINCT_E ] ; // Calculated from junction_deviation_mm
2018-09-16 21:24:15 -05:00
# endif
# endif
# if HAS_CLASSIC_JERK
2020-04-24 17:41:20 -05:00
// (mm/s^2) M205 XYZ(E) - The largest speed change requiring no acceleration.
static TERN ( HAS_LINEAR_E_JERK , xyz_pos_t , xyze_pos_t ) max_jerk ;
2018-06-10 18:02:54 -05:00
# endif
2017-10-13 17:21:25 -05:00
# if HAS_LEVELING
2017-11-30 15:55:08 -06:00
static bool leveling_active ; // Flag that bed leveling is enabled
2017-05-20 19:23:39 -05:00
# if ABL_PLANAR
static matrix_3x3 bed_level_matrix ; // Transform to compensate for bed level
# endif
2017-10-13 17:21:25 -05:00
# if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
static float z_fade_height , inverse_z_fade_height ;
# endif
2017-12-05 18:41:56 -06:00
# else
static constexpr bool leveling_active = false ;
2016-11-25 23:32:47 -06:00
# endif
2017-04-21 22:30:36 -05:00
# if ENABLED(LIN_ADVANCE)
2018-09-10 22:37:32 -05:00
static float extruder_advance_K [ EXTRUDERS ] ;
2018-04-05 15:47:56 -05:00
# endif
2020-03-02 21:52:53 -06:00
/**
* The current position of the tool in absolute steps
* Recalculated if any axis_steps_per_mm are changed by gcode
*/
static xyze_long_t position ;
2018-04-05 15:47:56 -05:00
# if HAS_POSITION_FLOAT
2019-09-29 04:25:39 -05:00
static xyze_pos_t position_float ;
2017-04-21 22:30:36 -05:00
# endif
2018-09-16 21:24:15 -05:00
# if IS_KINEMATIC
2019-09-29 04:25:39 -05:00
static xyze_pos_t position_cart ;
2018-09-16 21:24:15 -05:00
# endif
2018-10-10 09:45:20 -05:00
static skew_factor_t skew_factor ;
2017-12-01 16:42:23 -06:00
2019-06-10 17:25:43 -05:00
# if ENABLED(SD_ABORT_ON_ENDSTOP_HIT)
2018-05-09 00:17:53 -05:00
static bool abort_on_endstop_hit ;
# endif
2020-04-27 05:59:52 -05:00
# ifdef XY_FREQUENCY_LIMIT
static int8_t xy_freq_limit_hz ; // Minimum XY frequency setting
static float xy_freq_min_speed_factor ; // Minimum speed factor setting
static int32_t xy_freq_min_interval_us ; // Minimum segment time based on xy_freq_limit_hz
static inline void refresh_frequency_limit ( ) {
//xy_freq_min_interval_us = xy_freq_limit_hz ?: LROUND(1000000.0f / xy_freq_limit_hz);
if ( xy_freq_limit_hz )
xy_freq_min_interval_us = LROUND ( 1000000.0f / xy_freq_limit_hz ) ;
}
static inline void set_min_speed_factor_u8 ( const uint8_t v255 ) {
xy_freq_min_speed_factor = float ( ui8_to_percent ( v255 ) ) / 100 ;
}
static inline void set_frequency_limit ( const uint8_t hz ) {
xy_freq_limit_hz = constrain ( hz , 0 , 100 ) ;
refresh_frequency_limit ( ) ;
}
# endif
2018-05-09 00:17:53 -05:00
2016-04-27 20:06:32 -05:00
private :
2013-09-29 11:20:06 -05:00
2016-04-27 20:06:32 -05:00
/**
* Speed of previous path line segment
*/
2019-09-29 04:25:39 -05:00
static xyze_float_t previous_speed ;
2016-04-27 20:06:32 -05:00
/**
2018-05-09 00:17:53 -05:00
* Nominal speed of previous path line segment ( mm / s ) ^ 2
2016-04-27 20:06:32 -05:00
*/
2018-05-09 00:17:53 -05:00
static float previous_nominal_speed_sqr ;
2016-12-15 09:21:32 -06:00
2016-11-25 23:32:47 -06:00
/**
* Limit where 64 bit math is necessary for acceleration calculation
*/
2021-04-13 23:22:57 -05:00
static uint32_t acceleration_long_cutoff ;
2016-04-27 20:06:32 -05:00
2017-10-13 11:07:09 -05:00
# if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
2017-11-02 23:59:42 -05:00
static float last_fade_z ;
2017-10-13 11:07:09 -05:00
# endif
2016-04-27 20:06:32 -05:00
# if ENABLED(DISABLE_INACTIVE_EXTRUDER)
2021-06-04 20:02:37 -05:00
// Counters to manage disabling inactive extruder steppers
static last_move_t g_uc_extruder_last_move [ E_STEPPERS ] ;
2016-10-31 10:17:30 -05:00
# endif
2016-04-27 20:06:32 -05:00
2020-09-28 01:13:27 -05:00
# if HAS_WIRED_LCD
2020-04-27 05:59:52 -05:00
volatile static uint32_t block_buffer_runtime_us ; // Theoretical block buffer runtime in µs
2016-11-21 10:49:16 -06:00
# endif
2016-04-27 20:06:32 -05:00
public :
2016-05-26 13:22:51 -05:00
/**
* Instance Methods
*/
2016-04-27 20:06:32 -05:00
Planner ( ) ;
void init ( ) ;
2016-05-26 13:22:51 -05:00
/**
* Static ( class ) Methods
*/
2021-03-16 15:12:28 -05:00
// Recalculate steps/s^2 accelerations based on mm/s^2 settings
2016-05-26 13:22:51 -05:00
static void reset_acceleration_rates ( ) ;
2021-03-16 15:12:28 -05:00
/**
* Recalculate ' position ' and ' steps_to_mm ' .
* Must be called whenever settings . axis_steps_per_mm changes !
*/
2016-07-23 21:36:26 -05:00
static void refresh_positioning ( ) ;
2019-10-01 19:59:48 -05:00
2021-03-16 15:12:28 -05:00
// For an axis set the Maximum Acceleration in mm/s^2
2021-03-18 00:11:06 -05:00
static void set_max_acceleration ( const uint8_t axis , float inMaxAccelMMS2 ) ;
2021-03-16 15:12:28 -05:00
// For an axis set the Maximum Feedrate in mm/s
2021-03-18 00:11:06 -05:00
static void set_max_feedrate ( const uint8_t axis , float inMaxFeedrateMMS ) ;
2021-03-16 15:12:28 -05:00
// For an axis set the Maximum Jerk (instant change) in mm/s
# if HAS_CLASSIC_JERK
2021-03-18 00:11:06 -05:00
static void set_max_jerk ( const AxisEnum axis , float inMaxJerkMMS ) ;
2021-03-16 15:12:28 -05:00
# else
2021-05-22 21:12:53 -05:00
static inline void set_max_jerk ( const AxisEnum , const_float_t ) { }
2021-03-16 15:12:28 -05:00
# endif
2016-04-27 20:06:32 -05:00
2021-05-21 08:23:09 -05:00
# if HAS_EXTRUDERS
2019-09-10 02:20:49 -05:00
FORCE_INLINE static void refresh_e_factor ( const uint8_t e ) {
2020-04-22 21:03:28 -05:00
e_factor [ e ] = flow_percentage [ e ] * 0.01f * TERN ( NO_VOLUMETRICS , 1.0f , volumetric_multiplier [ e ] ) ;
2019-09-10 02:20:49 -05:00
}
2020-04-22 21:03:28 -05:00
static inline void set_flow ( const uint8_t e , const int16_t flow ) {
flow_percentage [ e ] = flow ;
refresh_e_factor ( e ) ;
}
2019-09-10 02:20:49 -05:00
# endif
2017-11-10 02:26:49 -06:00
2016-04-27 20:06:32 -05:00
// Manage fans, paste pressure, etc.
2016-05-26 13:22:51 -05:00
static void check_axes_activity ( ) ;
2015-03-28 22:33:21 -05:00
2021-03-24 12:21:11 -05:00
// Apply fan speeds
# if HAS_FAN
static void sync_fan_speeds ( uint8_t ( & fan_speed ) [ FAN_COUNT ] ) ;
# if FAN_KICKSTART_TIME
static void kickstart_fan ( uint8_t ( & fan_speed ) [ FAN_COUNT ] , const millis_t & ms , const uint8_t f ) ;
# else
FORCE_INLINE static void kickstart_fan ( uint8_t ( & ) [ FAN_COUNT ] , const millis_t & , const uint8_t ) { }
# endif
# endif
2017-12-13 02:32:34 -06:00
# if ENABLED(FILAMENT_WIDTH_SENSOR)
2019-09-10 18:48:58 -05:00
void apply_filament_width_sensor ( const int8_t encoded_ratio ) ;
static inline float volumetric_percent ( const bool vol ) {
return 100.0f * ( vol
? volumetric_area_nominal / volumetric_multiplier [ FILAMENT_SENSOR_EXTRUDER_NUM ]
: volumetric_multiplier [ FILAMENT_SENSOR_EXTRUDER_NUM ]
) ;
}
2017-12-13 02:32:34 -06:00
# endif
2017-12-19 19:44:11 -06:00
# if DISABLED(NO_VOLUMETRICS)
2020-06-08 03:24:46 -05:00
// Update multipliers based on new diameter measurements
static void calculate_volumetric_multipliers ( ) ;
2020-06-15 18:11:19 -05:00
2020-06-08 03:24:46 -05:00
# if ENABLED(VOLUMETRIC_EXTRUDER_LIMIT)
// Update pre calculated extruder feedrate limits based on volumetric values
static void calculate_volumetric_extruder_limit ( const uint8_t e ) ;
static void calculate_volumetric_extruder_limits ( ) ;
# endif
2021-04-01 17:59:57 -05:00
FORCE_INLINE static void set_filament_size ( const uint8_t e , const_float_t v ) {
2017-12-19 19:44:11 -06:00
filament_size [ e ] = v ;
2020-06-08 03:24:46 -05:00
if ( v > 0 ) volumetric_area_nominal = CIRCLE_AREA ( v * 0.5 ) ; //TODO: should it be per extruder
2017-12-19 19:44:11 -06:00
// make sure all extruders have some sane value for the filament size
2020-03-13 23:18:16 -05:00
LOOP_L_N ( i , COUNT ( filament_size ) )
2017-12-19 19:44:11 -06:00
if ( ! filament_size [ i ] ) filament_size [ i ] = DEFAULT_NOMINAL_FILAMENT_DIA ;
}
# endif
2017-09-18 05:51:45 -05:00
2020-06-08 03:24:46 -05:00
# if ENABLED(VOLUMETRIC_EXTRUDER_LIMIT)
2021-04-01 17:59:57 -05:00
FORCE_INLINE static void set_volumetric_extruder_limit ( const uint8_t e , const_float_t v ) {
2020-06-08 03:24:46 -05:00
volumetric_extruder_limit [ e ] = v ;
calculate_volumetric_extruder_limit ( e ) ;
}
# endif
2017-10-13 10:39:11 -05:00
# if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
/**
* Get the Z leveling fade factor based on the given Z height ,
* re - calculating only when needed .
*
* Returns 1.0 if planner . z_fade_height is 0.0 .
* Returns 0.0 if Z is past the specified ' Fade Height ' .
*/
2021-04-01 17:59:57 -05:00
static inline float fade_scaling_factor_for_z ( const_float_t rz ) {
2018-07-01 15:20:28 -05:00
static float z_fade_factor = 1 ;
2019-09-26 01:15:35 -05:00
if ( ! z_fade_height ) return 1 ;
if ( rz > = z_fade_height ) return 0 ;
if ( last_fade_z ! = rz ) {
last_fade_z = rz ;
z_fade_factor = 1 - rz * inverse_z_fade_height ;
2017-10-13 10:39:11 -05:00
}
2019-09-26 01:15:35 -05:00
return z_fade_factor ;
2017-10-13 10:39:11 -05:00
}
2018-07-01 15:20:28 -05:00
FORCE_INLINE static void force_fade_recalc ( ) { last_fade_z = - 999.999f ; }
2017-10-13 11:07:09 -05:00
2021-04-01 17:59:57 -05:00
FORCE_INLINE static void set_z_fade_height ( const_float_t zfh ) {
2017-10-13 17:21:25 -05:00
z_fade_height = zfh > 0 ? zfh : 0 ;
inverse_z_fade_height = RECIPROCAL ( z_fade_height ) ;
force_fade_recalc ( ) ;
}
2021-04-01 17:59:57 -05:00
FORCE_INLINE static bool leveling_active_at_z ( const_float_t rz ) {
2017-11-02 23:59:42 -05:00
return ! z_fade_height | | rz < z_fade_height ;
2017-10-13 17:21:25 -05:00
}
2017-10-13 10:39:11 -05:00
# else
2021-05-22 21:12:53 -05:00
FORCE_INLINE static float fade_scaling_factor_for_z ( const_float_t ) { return 1 ; }
2017-10-13 10:39:11 -05:00
2021-05-22 21:12:53 -05:00
FORCE_INLINE static bool leveling_active_at_z ( const_float_t ) { return true ; }
2017-10-13 17:21:25 -05:00
2017-10-13 10:39:11 -05:00
# endif
2017-12-09 07:50:55 -06:00
# if ENABLED(SKEW_CORRECTION)
2021-04-01 17:59:57 -05:00
FORCE_INLINE static void skew ( float & cx , float & cy , const_float_t cz ) {
2021-02-25 04:49:34 -06:00
if ( COORDINATE_OKAY ( cx , X_MIN_POS + 1 , X_MAX_POS ) & & COORDINATE_OKAY ( cy , Y_MIN_POS + 1 , Y_MAX_POS ) ) {
2018-10-10 09:45:20 -05:00
const float sx = cx - cy * skew_factor . xy - cz * ( skew_factor . xz - ( skew_factor . xy * skew_factor . yz ) ) ,
sy = cy - cz * skew_factor . yz ;
2021-02-25 04:49:34 -06:00
if ( COORDINATE_OKAY ( sx , X_MIN_POS , X_MAX_POS ) & & COORDINATE_OKAY ( sy , Y_MIN_POS , Y_MAX_POS ) ) {
2017-12-09 07:50:55 -06:00
cx = sx ; cy = sy ;
}
}
}
2019-09-29 04:25:39 -05:00
FORCE_INLINE static void skew ( xyz_pos_t & raw ) { skew ( raw . x , raw . y , raw . z ) ; }
2017-12-09 07:50:55 -06:00
2021-04-01 17:59:57 -05:00
FORCE_INLINE static void unskew ( float & cx , float & cy , const_float_t cz ) {
2021-02-25 04:49:34 -06:00
if ( COORDINATE_OKAY ( cx , X_MIN_POS , X_MAX_POS ) & & COORDINATE_OKAY ( cy , Y_MIN_POS , Y_MAX_POS ) ) {
2018-10-10 09:45:20 -05:00
const float sx = cx + cy * skew_factor . xy + cz * skew_factor . xz ,
sy = cy + cz * skew_factor . yz ;
2021-02-25 04:49:34 -06:00
if ( COORDINATE_OKAY ( sx , X_MIN_POS , X_MAX_POS ) & & COORDINATE_OKAY ( sy , Y_MIN_POS , Y_MAX_POS ) ) {
2017-12-09 07:50:55 -06:00
cx = sx ; cy = sy ;
}
}
}
2019-09-29 04:25:39 -05:00
FORCE_INLINE static void unskew ( xyz_pos_t & raw ) { unskew ( raw . x , raw . y , raw . z ) ; }
2017-12-09 07:50:55 -06:00
# endif // SKEW_CORRECTION
2018-09-16 21:24:15 -05:00
# if HAS_LEVELING
2016-04-27 20:06:32 -05:00
/**
2016-09-11 21:40:44 -05:00
* Apply leveling to transform a cartesian position
* as it will be given to the planner and steppers .
2016-04-27 20:06:32 -05:00
*/
2019-09-29 04:25:39 -05:00
static void apply_leveling ( xyz_pos_t & raw ) ;
static void unapply_leveling ( xyz_pos_t & raw ) ;
FORCE_INLINE static void force_unapply_leveling ( xyz_pos_t & raw ) {
leveling_active = true ;
unapply_leveling ( raw ) ;
leveling_active = false ;
}
2020-05-05 03:09:40 -05:00
# else
FORCE_INLINE static void apply_leveling ( xyz_pos_t & ) { }
FORCE_INLINE static void unapply_leveling ( xyz_pos_t & ) { }
2016-09-11 21:40:44 -05:00
# endif
2016-12-15 09:21:32 -06:00
2018-09-16 21:24:15 -05:00
# if ENABLED(FWRETRACT)
static void apply_retract ( float & rz , float & e ) ;
2019-09-29 04:25:39 -05:00
FORCE_INLINE static void apply_retract ( xyze_pos_t & raw ) { apply_retract ( raw . z , raw . e ) ; }
2018-09-16 21:24:15 -05:00
static void unapply_retract ( float & rz , float & e ) ;
2019-09-29 04:25:39 -05:00
FORCE_INLINE static void unapply_retract ( xyze_pos_t & raw ) { unapply_retract ( raw . z , raw . e ) ; }
2018-09-16 21:24:15 -05:00
# endif
# if HAS_POSITION_MODIFIERS
2020-05-05 03:09:40 -05:00
FORCE_INLINE static void apply_modifiers ( xyze_pos_t & pos , bool leveling = ENABLED ( PLANNER_LEVELING ) ) {
2020-04-22 16:35:03 -05:00
TERN_ ( SKEW_CORRECTION , skew ( pos ) ) ;
2020-05-05 03:09:40 -05:00
if ( leveling ) apply_leveling ( pos ) ;
2020-04-22 16:35:03 -05:00
TERN_ ( FWRETRACT , apply_retract ( pos ) ) ;
2018-09-16 21:24:15 -05:00
}
2020-05-05 03:09:40 -05:00
FORCE_INLINE static void unapply_modifiers ( xyze_pos_t & pos , bool leveling = ENABLED ( PLANNER_LEVELING ) ) {
2020-04-22 16:35:03 -05:00
TERN_ ( FWRETRACT , unapply_retract ( pos ) ) ;
2020-05-05 03:09:40 -05:00
if ( leveling ) unapply_leveling ( pos ) ;
2020-04-22 16:35:03 -05:00
TERN_ ( SKEW_CORRECTION , unskew ( pos ) ) ;
2018-09-16 21:24:15 -05:00
}
# endif // HAS_POSITION_MODIFIERS
2018-06-27 18:11:16 -05:00
// Number of moves currently in the planner including the busy block, if any
2018-05-09 00:17:53 -05:00
FORCE_INLINE static uint8_t movesplanned ( ) { return BLOCK_MOD ( block_buffer_head - block_buffer_tail ) ; }
2018-06-27 18:11:16 -05:00
// Number of nonbusy moves currently in the planner
FORCE_INLINE static uint8_t nonbusy_movesplanned ( ) { return BLOCK_MOD ( block_buffer_head - block_buffer_nonbusy ) ; }
2018-05-09 00:17:53 -05:00
// Remove all blocks from the buffer
2018-06-27 18:11:16 -05:00
FORCE_INLINE static void clear_block_buffer ( ) { block_buffer_nonbusy = block_buffer_planned = block_buffer_head = block_buffer_tail = 0 ; }
2018-05-09 00:17:53 -05:00
// Check if movement queue is full
FORCE_INLINE static bool is_full ( ) { return block_buffer_tail = = next_block_index ( block_buffer_head ) ; }
// Get count of movement slots free
FORCE_INLINE static uint8_t moves_free ( ) { return BLOCK_BUFFER_SIZE - 1 - movesplanned ( ) ; }
2018-05-03 17:45:13 -05:00
/**
* Planner : : get_next_free_block
*
2018-05-09 00:17:53 -05:00
* - Get the next head indices ( passed by reference )
* - Wait for the number of spaces to open up in the planner
* - Return the first head block
2018-05-03 17:45:13 -05:00
*/
2018-05-20 22:20:11 -05:00
FORCE_INLINE static block_t * get_next_free_block ( uint8_t & next_buffer_head , const uint8_t count = 1 ) {
2018-05-09 00:17:53 -05:00
// Wait until there are enough slots free
while ( moves_free ( ) < count ) { idle ( ) ; }
// Return the first available block
2018-05-03 17:45:13 -05:00
next_buffer_head = next_block_index ( block_buffer_head ) ;
return & block_buffer [ block_buffer_head ] ;
}
2017-11-30 16:40:42 -06:00
/**
* Planner : : _buffer_steps
*
* Add a new linear movement to the buffer ( in terms of steps ) .
*
* target - target position in steps units
* fr_mm_s - ( target ) speed of the move
* extruder - target extruder
2018-02-04 00:26:05 -06:00
* millimeters - the length of the movement , if known
2018-05-09 00:17:53 -05:00
*
* Returns true if movement was buffered , false otherwise
2017-11-30 16:40:42 -06:00
*/
2019-09-29 04:25:39 -05:00
static bool _buffer_steps ( const xyze_long_t & target
2021-05-23 21:33:22 -05:00
OPTARG ( HAS_POSITION_FLOAT , const xyze_pos_t & target_float )
OPTARG ( HAS_DIST_MM_ARG , const xyze_float_t & cart_dist_mm )
2021-04-01 17:59:57 -05:00
, feedRate_t fr_mm_s , const uint8_t extruder , const_float_t millimeters = 0.0
2018-05-09 00:17:53 -05:00
) ;
/**
* Planner : : _populate_block
*
* Fills a new linear movement in the block ( in terms of steps ) .
*
* 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
*
* Returns true is movement is acceptable , false otherwise
*/
2021-05-23 21:33:22 -05:00
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 )
2021-04-01 17:59:57 -05:00
, feedRate_t fr_mm_s , const uint8_t extruder , const_float_t millimeters = 0.0
2018-02-23 00:53:29 -06:00
) ;
2017-11-30 16:40:42 -06:00
2018-05-03 17:45:13 -05:00
/**
* Planner : : buffer_sync_block
2021-03-24 12:21:11 -05:00
* Add a block to the buffer that just updates the position or in
* case of LASER_SYNCHRONOUS_M106_M107 the fan pwm
2018-05-03 17:45:13 -05:00
*/
2021-03-24 12:21:11 -05:00
static void buffer_sync_block (
TERN_ ( LASER_SYNCHRONOUS_M106_M107 , uint8_t sync_flag = BLOCK_FLAG_SYNC_POSITION )
) ;
2018-05-03 17:45:13 -05:00
2018-09-16 21:24:15 -05:00
# if IS_KINEMATIC
private :
// Allow do_homing_move to access internal functions, such as buffer_segment.
2021-01-04 20:32:52 -06:00
friend void do_homing_move ( const AxisEnum , const float , const feedRate_t , const bool ) ;
2018-09-16 21:24:15 -05:00
# endif
2016-09-11 21:40:44 -05:00
/**
2017-12-09 07:41:19 -06:00
* Planner : : buffer_segment
2016-10-06 03:56:05 -05:00
*
2017-11-30 15:55:08 -06:00
* Add a new linear movement to the buffer in axis units .
2016-10-09 13:25:25 -05:00
*
2017-11-30 15:55:08 -06:00
* Leveling and kinematics should be applied ahead of calling this .
2016-10-06 03:56:05 -05:00
*
2018-02-04 00:26:05 -06:00
* 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
2016-10-06 03:56:05 -05:00
*/
2021-06-05 02:18:47 -05:00
static bool buffer_segment ( const abce_pos_t & abce
2021-05-23 21:33:22 -05:00
OPTARG ( HAS_DIST_MM_ARG , const xyze_float_t & cart_dist_mm )
2021-06-05 02:18:47 -05:00
, const_feedRate_t fr_mm_s , const uint8_t extruder = active_extruder , const_float_t millimeters = 0.0
2018-09-16 21:24:15 -05:00
) ;
2016-10-06 03:56:05 -05:00
2018-09-16 21:24:15 -05:00
public :
2016-10-06 03:56:05 -05:00
/**
* Add a new linear movement to the buffer .
2019-09-26 01:28:09 -05:00
* The target is cartesian . It ' s translated to
* delta / scara if needed .
2018-09-16 21:24:15 -05:00
*
2021-06-05 02:18:47 -05:00
* cart - target position in mm or degrees
2018-02-04 00:26:05 -06:00
* fr_mm_s - ( target ) speed of the move ( mm / s )
* extruder - target extruder
* millimeters - the length of the movement , if known
2018-09-17 17:30:04 -05:00
* inv_duration - the reciprocal if the duration of the movement , if known ( kinematic only if feeedrate scaling is enabled )
2016-10-06 03:56:05 -05:00
*/
2021-06-05 02:18:47 -05:00
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
2021-05-23 21:33:22 -05:00
OPTARG ( SCARA_FEEDRATE_SCALING , const_float_t inv_duration = 0.0 )
2018-09-16 21:24:15 -05:00
) ;
2020-05-11 19:22:41 -05:00
# if ENABLED(DIRECT_STEPPING)
static void buffer_page ( const page_idx_t page_idx , const uint8_t extruder , const uint16_t num_steps ) ;
# endif
2016-09-11 21:40:44 -05:00
/**
* Set the planner . position and individual stepper positions .
* Used by G92 , G28 , G29 , and other procedures .
2018-09-17 17:30:04 -05:00
*
2018-09-16 21:24:15 -05:00
* The supplied position is in the cartesian coordinate space and is
* translated in to machine space as needed . Modifiers such as leveling
* and skew are also applied .
2016-09-11 21:40:44 -05:00
*
* Multiplies by axis_steps_per_mm [ ] and does necessary conversion
* for COREXY / COREXZ / COREYZ to set the corresponding stepper positions .
*
* Clears previous speed values .
*/
2021-06-05 02:18:47 -05:00
static void set_position_mm ( const xyze_pos_t & xyze ) ;
2021-05-24 16:38:57 -05:00
# if HAS_EXTRUDERS
static void set_e_position_mm ( const_float_t e ) ;
# endif
2018-09-16 21:24:15 -05:00
/**
* Set the planner . position and individual stepper positions .
2018-09-17 17:30:04 -05:00
*
2018-09-16 21:24:15 -05:00
* The supplied position is in machine space , and no additional
* conversions are applied .
*/
2021-06-05 02:18:47 -05:00
static void set_machine_position_mm ( const abce_pos_t & abce ) ;
2016-04-27 20:06:32 -05:00
2018-05-12 09:59:11 -05:00
/**
* Get an axis position according to stepper position ( s )
* For CORE machines apply translation from ABC to XYZ .
*/
static float get_axis_position_mm ( const AxisEnum axis ) ;
2020-03-02 21:52:53 -06:00
static inline abce_pos_t get_axis_positions_mm ( ) {
2021-05-24 16:38:57 -05:00
const abce_pos_t out = LOGICAL_AXIS_ARRAY (
get_axis_position_mm ( E_AXIS ) ,
2021-06-05 02:18:47 -05:00
get_axis_position_mm ( A_AXIS ) , get_axis_position_mm ( B_AXIS ) , get_axis_position_mm ( C_AXIS ) ,
get_axis_position_mm ( I_AXIS ) , get_axis_position_mm ( J_AXIS ) , get_axis_position_mm ( K_AXIS )
2021-05-24 16:38:57 -05:00
) ;
2020-03-02 21:52:53 -06:00
return out ;
}
2018-05-12 09:59:11 -05:00
// SCARA AB axes are in degrees, not mm
# if IS_SCARA
FORCE_INLINE static float get_axis_position_degrees ( const AxisEnum axis ) { return get_axis_position_mm ( axis ) ; }
# endif
2019-08-28 00:51:01 -05:00
// Called to force a quick stop of the machine (for example, when
// a Full Shutdown is required, or when endstops are hit)
2018-05-09 00:17:53 -05:00
static void quick_stop ( ) ;
2021-04-16 01:59:28 -05:00
# if ENABLED(REALTIME_REPORTING_COMMANDS)
// Force a quick pause of the machine (e.g., when a pause is required in the middle of move).
// NOTE: Hard-stops will lose steps so encoders are highly recommended if using these!
static void quick_pause ( ) ;
static void quick_resume ( ) ;
# endif
2018-05-09 00:17:53 -05:00
// Called when an endstop is triggered. Causes the machine to stop inmediately
static void endstop_triggered ( const AxisEnum axis ) ;
2016-04-27 20:06:32 -05:00
2018-05-09 00:17:53 -05:00
// Triggered position of an axis in mm (not core-savvy)
static float triggered_position_mm ( const AxisEnum axis ) ;
// Block until all buffered steps are executed / cleaned
2018-05-12 01:38:02 -05:00
static void synchronize ( ) ;
2018-05-09 00:17:53 -05:00
// Wait for moves to finish and disable all steppers
static void finish_and_disable ( ) ;
2021-04-08 15:43:16 -05:00
// Periodic handler to manage the cleaning buffer counter
2018-05-09 00:17:53 -05:00
// Called from the Temperature ISR at ~1kHz
2021-04-08 15:43:16 -05:00
static void isr ( ) { if ( cleaning_buffer_counter ) - - cleaning_buffer_counter ; }
2016-04-27 20:06:32 -05:00
2017-12-07 23:03:36 -06:00
/**
2018-05-09 00:17:53 -05:00
* Does the buffer have any blocks queued ?
2017-12-07 23:03:36 -06:00
*/
2018-05-09 00:17:53 -05:00
FORCE_INLINE static bool has_blocks_queued ( ) { return ( block_buffer_head ! = block_buffer_tail ) ; }
2017-12-07 23:03:36 -06:00
2016-04-27 20:06:32 -05:00
/**
2020-02-14 05:14:37 -06:00
* Get the current block for processing
* and mark the block as busy .
* Return nullptr if the buffer is empty
* or if there is a first - block delay .
*
2017-12-02 20:17:51 -06:00
* WARNING : Called from Stepper ISR context !
2016-04-27 20:06:32 -05:00
*/
2020-02-14 05:14:37 -06:00
static block_t * get_current_block ( ) ;
2016-04-27 20:06:32 -05:00
2018-05-09 00:17:53 -05:00
/**
2020-05-11 19:22:41 -05:00
* " Release " the current block so its slot can be reused .
2018-05-09 00:17:53 -05:00
* Called when the current block is no longer needed .
*/
2020-05-11 19:22:41 -05:00
FORCE_INLINE static void release_current_block ( ) {
2018-06-27 18:11:16 -05:00
if ( has_blocks_queued ( ) )
block_buffer_tail = next_block_index ( block_buffer_tail ) ;
2018-05-09 00:17:53 -05:00
}
2020-09-28 01:13:27 -05:00
# if HAS_WIRED_LCD
2020-02-14 05:14:37 -06:00
static uint16_t block_buffer_runtime ( ) ;
static void clear_block_buffer_runtime ( ) ;
2016-11-11 11:15:39 -06:00
# endif
2016-05-03 19:00:28 -05:00
# if ENABLED(AUTOTEMP)
2021-03-24 04:11:43 -05:00
static celsius_t autotemp_min , autotemp_max ;
static float autotemp_factor ;
2016-05-26 13:22:51 -05:00
static bool autotemp_enabled ;
2020-04-28 00:21:23 -05:00
static void autotemp_update ( ) ;
2021-03-16 15:12:28 -05:00
static void autotemp_M104_M109 ( ) ;
2021-04-05 21:27:05 -05:00
static void autotemp_task ( ) ;
2016-05-03 19:00:28 -05:00
# endif
2019-10-08 19:42:18 -05:00
# if HAS_LINEAR_E_JERK
2018-06-26 21:38:31 -05:00
FORCE_INLINE static void recalculate_max_e_jerk ( ) {
2020-05-04 23:07:54 -05:00
const float prop = junction_deviation_mm * SQRT ( 0.5 ) / ( 1.0f - SQRT ( 0.5 ) ) ;
LOOP_L_N ( i , EXTRUDERS )
2020-05-05 00:28:39 -05:00
max_e_jerk [ E_INDEX_N ( i ) ] = SQRT ( prop * settings . max_acceleration_mm_per_s2 [ E_INDEX_N ( i ) ] ) ;
2018-06-11 18:49:08 -05:00
}
# endif
2016-05-03 19:00:28 -05:00
private :
2021-03-16 15:12:28 -05:00
# if ENABLED(AUTOTEMP)
# if ENABLED(AUTOTEMP_PROPORTIONAL)
static void _autotemp_update_from_hotend ( ) ;
# else
static inline void _autotemp_update_from_hotend ( ) { }
# endif
# endif
2016-04-27 20:06:32 -05:00
/**
* Get the index of the next / previous block in the ring buffer
*/
2018-05-18 02:04:01 -05:00
static constexpr uint8_t next_block_index ( const uint8_t block_index ) { return BLOCK_MOD ( block_index + 1 ) ; }
static constexpr uint8_t prev_block_index ( const uint8_t block_index ) { return BLOCK_MOD ( block_index - 1 ) ; }
2016-04-27 20:06:32 -05:00
/**
* Calculate the distance ( not time ) it takes to accelerate
* from initial_rate to target_rate using the given acceleration :
*/
2021-04-01 17:59:57 -05:00
static float estimate_acceleration_distance ( const_float_t initial_rate , const_float_t target_rate , const_float_t accel ) {
2016-06-07 17:38:45 -05:00
if ( accel = = 0 ) return 0 ; // accel was 0, set acceleration distance to 0
2016-07-15 20:50:25 -05:00
return ( sq ( target_rate ) - sq ( initial_rate ) ) / ( accel * 2 ) ;
2016-04-27 20:06:32 -05:00
}
/**
2017-12-02 20:17:51 -06:00
* Return the point at which you must start braking ( at the rate of - ' accel ' ) if
2016-04-27 20:06:32 -05:00
* you start at ' initial_rate ' , accelerate ( until reaching the point ) , and want to end at
* ' final_rate ' after traveling ' distance ' .
*
* This is used to compute the intersection point between acceleration and deceleration
* in cases where the " trapezoid " has no plateau ( i . e . , never reaches maximum speed )
*/
2021-04-01 17:59:57 -05:00
static float intersection_distance ( const_float_t initial_rate , const_float_t final_rate , const_float_t accel , const_float_t distance ) {
2016-06-07 17:38:45 -05:00
if ( accel = = 0 ) return 0 ; // accel was 0, set intersection distance to 0
2016-07-15 20:50:25 -05:00
return ( accel * 2 * distance - sq ( initial_rate ) + sq ( final_rate ) ) / ( accel * 4 ) ;
2016-04-27 20:06:32 -05:00
}
/**
2018-05-09 00:17:53 -05:00
* Calculate the maximum allowable speed squared at this point , in order
* to reach ' target_velocity_sqr ' using ' acceleration ' within a given
2016-04-27 20:06:32 -05:00
* ' distance ' .
*/
2021-04-01 17:59:57 -05:00
static float max_allowable_speed_sqr ( const_float_t accel , const_float_t target_velocity_sqr , const_float_t distance ) {
2018-05-09 00:17:53 -05:00
return target_velocity_sqr - 2 * accel * distance ;
2016-04-27 20:06:32 -05:00
}
2018-05-26 02:02:39 -05:00
# if ENABLED(S_CURVE_ACCELERATION)
2018-04-06 20:48:06 -05:00
/**
* Calculate the speed reached given initial speed , acceleration and distance
*/
2021-04-01 17:59:57 -05:00
static float final_speed ( const_float_t initial_velocity , const_float_t accel , const_float_t distance ) {
2018-04-06 20:48:06 -05:00
return SQRT ( sq ( initial_velocity ) + 2 * accel * distance ) ;
}
# endif
2021-04-01 17:59:57 -05:00
static void calculate_trapezoid_for_block ( block_t * const block , const_float_t entry_factor , const_float_t exit_factor ) ;
2016-04-27 20:06:32 -05:00
2021-03-29 20:36:37 -05:00
static void reverse_pass_kernel ( block_t * const current , const block_t * const next ) ;
static void forward_pass_kernel ( const block_t * const previous , block_t * const current , uint8_t block_index ) ;
2016-04-27 20:06:32 -05:00
2016-05-26 13:22:51 -05:00
static void reverse_pass ( ) ;
static void forward_pass ( ) ;
2016-04-27 20:06:32 -05:00
2016-05-26 13:22:51 -05:00
static void recalculate_trapezoids ( ) ;
2016-04-27 20:06:32 -05:00
2016-05-26 13:22:51 -05:00
static void recalculate ( ) ;
2011-11-19 08:37:10 -06:00
2020-04-23 20:49:11 -05:00
# if HAS_JUNCTION_DEVIATION
2018-05-31 20:09:53 -05:00
2019-09-29 04:25:39 -05:00
FORCE_INLINE static void normalize_junction_vector ( xyze_float_t & vector ) {
2018-07-01 15:20:28 -05:00
float magnitude_sq = 0 ;
2021-05-18 22:51:19 -05:00
LOOP_LOGICAL_AXES ( idx ) if ( vector [ idx ] ) magnitude_sq + = sq ( vector [ idx ] ) ;
2019-09-29 04:25:39 -05:00
vector * = RSQRT ( magnitude_sq ) ;
2018-05-31 20:09:53 -05:00
}
2021-04-01 17:59:57 -05:00
FORCE_INLINE static float limit_value_by_axis_maximum ( const_float_t max_value , xyze_float_t & unit_vec ) {
2018-05-31 20:09:53 -05:00
float limit_value = max_value ;
2021-05-18 22:51:19 -05:00
LOOP_LOGICAL_AXES ( idx ) {
2020-05-10 21:23:51 -05:00
if ( unit_vec [ idx ] ) {
if ( limit_value * ABS ( unit_vec [ idx ] ) > settings . max_acceleration_mm_per_s2 [ idx ] )
limit_value = ABS ( settings . max_acceleration_mm_per_s2 [ idx ] / unit_vec [ idx ] ) ;
}
}
2018-05-31 20:09:53 -05:00
return limit_value ;
}
2019-10-08 19:42:18 -05:00
# endif // !CLASSIC_JERK
2016-04-27 20:06:32 -05:00
} ;
2015-03-20 22:42:49 -05:00
2020-12-16 22:18:40 -06:00
# define PLANNER_XY_FEEDRATE() _MIN(planner.settings.max_feedrate_mm_s[X_AXIS], planner.settings.max_feedrate_mm_s[Y_AXIS])
2017-05-01 15:17:40 -05:00
2016-10-10 15:34:35 -05:00
extern Planner planner ;