My Marlin configs for Fabrikator Mini and CTC i3 Pro B
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

planner.h 38KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061
  1. /**
  2. * Marlin 3D Printer Firmware
  3. * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
  4. *
  5. * Based on Sprinter and grbl.
  6. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. *
  21. */
  22. #pragma once
  23. /**
  24. * planner.h
  25. *
  26. * Buffer movement commands and manage the acceleration profile plan
  27. *
  28. * Derived from Grbl
  29. * Copyright (c) 2009-2011 Simen Svale Skogsrud
  30. */
  31. #include "../MarlinCore.h"
  32. #if ENABLED(JD_HANDLE_SMALL_SEGMENTS)
  33. // Enable this option for perfect accuracy but maximum
  34. // computation. Should be fine on ARM processors.
  35. //#define JD_USE_MATH_ACOS
  36. // Disable this option to save 120 bytes of PROGMEM,
  37. // but incur increased computation and a reduction
  38. // in accuracy.
  39. #define JD_USE_LOOKUP_TABLE
  40. #endif
  41. #include "motion.h"
  42. #include "../gcode/queue.h"
  43. #if ENABLED(DELTA)
  44. #include "delta.h"
  45. #elif ENABLED(POLARGRAPH)
  46. #include "polargraph.h"
  47. #endif
  48. #if ABL_PLANAR
  49. #include "../libs/vector_3.h" // for matrix_3x3
  50. #endif
  51. #if ENABLED(FWRETRACT)
  52. #include "../feature/fwretract.h"
  53. #endif
  54. #if ENABLED(MIXING_EXTRUDER)
  55. #include "../feature/mixing.h"
  56. #endif
  57. #if HAS_CUTTER
  58. #include "../feature/spindle_laser_types.h"
  59. #endif
  60. #if ENABLED(DIRECT_STEPPING)
  61. #include "../feature/direct_stepping.h"
  62. #endif
  63. #if ENABLED(EXTERNAL_CLOSED_LOOP_CONTROLLER)
  64. #include "../feature/closedloop.h"
  65. #endif
  66. // Feedrate for manual moves
  67. #ifdef MANUAL_FEEDRATE
  68. constexpr xyze_feedrate_t _mf = MANUAL_FEEDRATE,
  69. manual_feedrate_mm_s = LOGICAL_AXIS_ARRAY(_mf.e / 60.0f,
  70. _mf.x / 60.0f, _mf.y / 60.0f, _mf.z / 60.0f,
  71. _mf.i / 60.0f, _mf.j / 60.0f, _mf.k / 60.0f,
  72. _mf.u / 60.0f, _mf.v / 60.0f, _mf.w / 60.0f);
  73. #endif
  74. #if IS_KINEMATIC && HAS_JUNCTION_DEVIATION
  75. #define HAS_DIST_MM_ARG 1
  76. #endif
  77. /**
  78. * Planner block flags as boolean bit fields
  79. */
  80. enum BlockFlagBit {
  81. // Recalculate trapezoids on entry junction. For optimization.
  82. BLOCK_BIT_RECALCULATE,
  83. // Nominal speed always reached.
  84. // i.e., The segment is long enough, so the nominal speed is reachable if accelerating
  85. // from a safe speed (in consideration of jerking from zero speed).
  86. BLOCK_BIT_NOMINAL_LENGTH,
  87. // The block is segment 2+ of a longer move
  88. BLOCK_BIT_CONTINUED,
  89. // Sync the stepper counts from the block
  90. BLOCK_BIT_SYNC_POSITION
  91. // Direct stepping page
  92. OPTARG(DIRECT_STEPPING, BLOCK_BIT_PAGE)
  93. // Sync the fan speeds from the block
  94. OPTARG(LASER_SYNCHRONOUS_M106_M107, BLOCK_BIT_SYNC_FANS)
  95. // Sync laser power from a queued block
  96. OPTARG(LASER_POWER_SYNC, BLOCK_BIT_LASER_PWR)
  97. };
  98. /**
  99. * Planner block flags as boolean bit fields
  100. */
  101. typedef struct {
  102. union {
  103. uint8_t bits;
  104. struct {
  105. bool recalculate:1;
  106. bool nominal_length:1;
  107. bool continued:1;
  108. bool sync_position:1;
  109. #if ENABLED(DIRECT_STEPPING)
  110. bool page:1;
  111. #endif
  112. #if ENABLED(LASER_SYNCHRONOUS_M106_M107)
  113. bool sync_fans:1;
  114. #endif
  115. #if ENABLED(LASER_POWER_SYNC)
  116. bool sync_laser_pwr:1;
  117. #endif
  118. };
  119. };
  120. void clear() volatile { bits = 0; }
  121. void apply(const uint8_t f) volatile { bits |= f; }
  122. void apply(const BlockFlagBit b) volatile { SBI(bits, b); }
  123. void reset(const BlockFlagBit b) volatile { bits = _BV(b); }
  124. void set_nominal(const bool n) volatile { recalculate = true; if (n) nominal_length = true; }
  125. } block_flags_t;
  126. #if ENABLED(LASER_FEATURE)
  127. typedef struct {
  128. bool isEnabled:1; // Set to engage the inline laser power output.
  129. bool dir:1;
  130. bool isPowered:1; // Set on any parsed G1, G2, G3, or G5 powered move, cleared on G0 and G28.
  131. bool isSyncPower:1; // Set on a M3 sync based set laser power, used to determine active trap power
  132. bool Reserved:4;
  133. } power_status_t;
  134. typedef struct {
  135. power_status_t status; // See planner settings for meaning
  136. uint8_t power; // Ditto; When in trapezoid mode this is nominal power
  137. #if ENABLED(LASER_POWER_TRAP)
  138. float trap_ramp_active_pwr; // Laser power level during active trapezoid smoothing
  139. float trap_ramp_entry_incr; // Acceleration per step laser power increment (trap entry)
  140. float trap_ramp_exit_decr; // Deceleration per step laser power decrement (trap exit)
  141. #endif
  142. } block_laser_t;
  143. #endif
  144. /**
  145. * struct block_t
  146. *
  147. * A single entry in the planner buffer.
  148. * Tracks linear movement over multiple axes.
  149. *
  150. * The "nominal" values are as-specified by G-code, and
  151. * may never actually be reached due to acceleration limits.
  152. */
  153. typedef struct block_t {
  154. volatile block_flags_t flag; // Block flags
  155. volatile bool is_fan_sync() { return TERN0(LASER_SYNCHRONOUS_M106_M107, flag.sync_fans); }
  156. volatile bool is_pwr_sync() { return TERN0(LASER_POWER_SYNC, flag.sync_laser_pwr); }
  157. volatile bool is_sync() { return flag.sync_position || is_fan_sync() || is_pwr_sync(); }
  158. volatile bool is_page() { return TERN0(DIRECT_STEPPING, flag.page); }
  159. volatile bool is_move() { return !(is_sync() || is_page()); }
  160. // Fields used by the motion planner to manage acceleration
  161. float nominal_speed_sqr, // The nominal speed for this block in (mm/sec)^2
  162. entry_speed_sqr, // Entry speed at previous-current junction in (mm/sec)^2
  163. max_entry_speed_sqr, // Maximum allowable junction entry speed in (mm/sec)^2
  164. millimeters, // The total travel of this block in mm
  165. acceleration; // acceleration mm/sec^2
  166. union {
  167. abce_ulong_t steps; // Step count along each axis
  168. abce_long_t position; // New position to force when this sync block is executed
  169. };
  170. uint32_t step_event_count; // The number of step events required to complete this block
  171. #if HAS_MULTI_EXTRUDER
  172. uint8_t extruder; // The extruder to move (if E move)
  173. #else
  174. static constexpr uint8_t extruder = 0;
  175. #endif
  176. #if ENABLED(MIXING_EXTRUDER)
  177. mixer_comp_t b_color[MIXING_STEPPERS]; // Normalized color for the mixing steppers
  178. #endif
  179. // Settings for the trapezoid generator
  180. uint32_t accelerate_until, // The index of the step event on which to stop acceleration
  181. decelerate_after; // The index of the step event on which to start decelerating
  182. #if ENABLED(S_CURVE_ACCELERATION)
  183. uint32_t cruise_rate, // The actual cruise rate to use, between end of the acceleration phase and start of deceleration phase
  184. acceleration_time, // Acceleration time and deceleration time in STEP timer counts
  185. deceleration_time,
  186. acceleration_time_inverse, // Inverse of acceleration and deceleration periods, expressed as integer. Scale depends on CPU being used
  187. deceleration_time_inverse;
  188. #else
  189. uint32_t acceleration_rate; // The acceleration rate used for acceleration calculation
  190. #endif
  191. axis_bits_t direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h)
  192. // Advance extrusion
  193. #if ENABLED(LIN_ADVANCE)
  194. bool use_advance_lead;
  195. uint16_t advance_speed, // STEP timer value for extruder speed offset ISR
  196. max_adv_steps, // max. advance steps to get cruising speed pressure (not always nominal_speed!)
  197. final_adv_steps; // advance steps due to exit speed
  198. float e_D_ratio;
  199. #endif
  200. uint32_t nominal_rate, // The nominal step rate for this block in step_events/sec
  201. initial_rate, // The jerk-adjusted step rate at start of block
  202. final_rate, // The minimal rate at exit
  203. acceleration_steps_per_s2; // acceleration steps/sec^2
  204. #if ENABLED(DIRECT_STEPPING)
  205. page_idx_t page_idx; // Page index used for direct stepping
  206. #endif
  207. #if HAS_CUTTER
  208. cutter_power_t cutter_power; // Power level for Spindle, Laser, etc.
  209. #endif
  210. #if HAS_FAN
  211. uint8_t fan_speed[FAN_COUNT];
  212. #endif
  213. #if ENABLED(BARICUDA)
  214. uint8_t valve_pressure, e_to_p_pressure;
  215. #endif
  216. #if HAS_WIRED_LCD
  217. uint32_t segment_time_us;
  218. #endif
  219. #if ENABLED(POWER_LOSS_RECOVERY)
  220. uint32_t sdpos;
  221. xyze_pos_t start_position;
  222. #endif
  223. #if ENABLED(LASER_FEATURE)
  224. block_laser_t laser;
  225. #endif
  226. } block_t;
  227. #if ANY(LIN_ADVANCE, SCARA_FEEDRATE_SCALING, GRADIENT_MIX, LCD_SHOW_E_TOTAL, POWER_LOSS_RECOVERY)
  228. #define HAS_POSITION_FLOAT 1
  229. #endif
  230. #define BLOCK_MOD(n) ((n)&(BLOCK_BUFFER_SIZE-1))
  231. #if ENABLED(LASER_FEATURE)
  232. typedef struct {
  233. /**
  234. * Laser status flags
  235. */
  236. power_status_t status;
  237. /**
  238. * Laser power: 0 or 255 in case of PWM-less laser,
  239. * or the OCR (oscillator count register) value;
  240. * Using OCR instead of raw power, because it avoids
  241. * floating point operations during the move loop.
  242. */
  243. volatile uint8_t power;
  244. } laser_state_t;
  245. #endif
  246. typedef struct {
  247. uint32_t max_acceleration_mm_per_s2[DISTINCT_AXES], // (mm/s^2) M201 XYZE
  248. min_segment_time_us; // (µs) M205 B
  249. float axis_steps_per_mm[DISTINCT_AXES]; // (steps) M92 XYZE - Steps per millimeter
  250. feedRate_t max_feedrate_mm_s[DISTINCT_AXES]; // (mm/s) M203 XYZE - Max speeds
  251. float acceleration, // (mm/s^2) M204 S - Normal acceleration. DEFAULT ACCELERATION for all printing moves.
  252. retract_acceleration, // (mm/s^2) M204 R - Retract acceleration. Filament pull-back and push-forward while standing still in the other axes
  253. travel_acceleration; // (mm/s^2) M204 T - Travel acceleration. DEFAULT ACCELERATION for all NON printing moves.
  254. feedRate_t min_feedrate_mm_s, // (mm/s) M205 S - Minimum linear feedrate
  255. min_travel_feedrate_mm_s; // (mm/s) M205 T - Minimum travel feedrate
  256. } planner_settings_t;
  257. #if ENABLED(IMPROVE_HOMING_RELIABILITY)
  258. struct motion_state_t {
  259. TERN(DELTA, xyz_ulong_t, xy_ulong_t) acceleration;
  260. #if HAS_CLASSIC_JERK
  261. TERN(DELTA, xyz_float_t, xy_float_t) jerk_state;
  262. #endif
  263. };
  264. #endif
  265. #if DISABLED(SKEW_CORRECTION)
  266. #define XY_SKEW_FACTOR 0
  267. #define XZ_SKEW_FACTOR 0
  268. #define YZ_SKEW_FACTOR 0
  269. #endif
  270. typedef struct {
  271. #if ENABLED(SKEW_CORRECTION_GCODE)
  272. float xy;
  273. #if ENABLED(SKEW_CORRECTION_FOR_Z)
  274. float xz, yz;
  275. #else
  276. const float xz = XZ_SKEW_FACTOR, yz = YZ_SKEW_FACTOR;
  277. #endif
  278. #else
  279. const float xy = XY_SKEW_FACTOR,
  280. xz = XZ_SKEW_FACTOR, yz = YZ_SKEW_FACTOR;
  281. #endif
  282. } skew_factor_t;
  283. #if ENABLED(DISABLE_INACTIVE_EXTRUDER)
  284. typedef IF<(BLOCK_BUFFER_SIZE > 64), uint16_t, uint8_t>::type last_move_t;
  285. #endif
  286. class Planner {
  287. public:
  288. /**
  289. * The move buffer, calculated in stepper steps
  290. *
  291. * block_buffer is a ring buffer...
  292. *
  293. * head,tail : indexes for write,read
  294. * head==tail : the buffer is empty
  295. * head!=tail : blocks are in the buffer
  296. * head==(tail-1)%size : the buffer is full
  297. *
  298. * Writer of head is Planner::buffer_segment().
  299. * Reader of tail is Stepper::isr(). Always consider tail busy / read-only
  300. */
  301. static block_t block_buffer[BLOCK_BUFFER_SIZE];
  302. static volatile uint8_t block_buffer_head, // Index of the next block to be pushed
  303. block_buffer_nonbusy, // Index of the first non busy block
  304. block_buffer_planned, // Index of the optimally planned block
  305. block_buffer_tail; // Index of the busy block, if any
  306. static uint16_t cleaning_buffer_counter; // A counter to disable queuing of blocks
  307. static uint8_t delay_before_delivering; // This counter delays delivery of blocks when queue becomes empty to allow the opportunity of merging blocks
  308. #if ENABLED(DISTINCT_E_FACTORS)
  309. static uint8_t last_extruder; // Respond to extruder change
  310. #endif
  311. #if ENABLED(DIRECT_STEPPING)
  312. static uint32_t last_page_step_rate; // Last page step rate given
  313. static xyze_bool_t last_page_dir; // Last page direction given
  314. #endif
  315. #if HAS_EXTRUDERS
  316. static int16_t flow_percentage[EXTRUDERS]; // Extrusion factor for each extruder
  317. static float e_factor[EXTRUDERS]; // The flow percentage and volumetric multiplier combine to scale E movement
  318. #endif
  319. #if DISABLED(NO_VOLUMETRICS)
  320. 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
  321. volumetric_area_nominal, // Nominal cross-sectional area
  322. volumetric_multiplier[EXTRUDERS]; // Reciprocal of cross-sectional area of filament (in mm^2). Pre-calculated to reduce computation in the planner
  323. // May be auto-adjusted by a filament width sensor
  324. #endif
  325. #if ENABLED(VOLUMETRIC_EXTRUDER_LIMIT)
  326. static float volumetric_extruder_limit[EXTRUDERS], // Maximum mm^3/sec the extruder can handle
  327. volumetric_extruder_feedrate_limit[EXTRUDERS]; // Feedrate limit (mm/s) calculated from volume limit
  328. #endif
  329. static planner_settings_t settings;
  330. #if ENABLED(LASER_FEATURE)
  331. static laser_state_t laser_inline;
  332. #endif
  333. static uint32_t max_acceleration_steps_per_s2[DISTINCT_AXES]; // (steps/s^2) Derived from mm_per_s2
  334. static float mm_per_step[DISTINCT_AXES]; // Millimeters per step
  335. #if HAS_JUNCTION_DEVIATION
  336. static float junction_deviation_mm; // (mm) M205 J
  337. #if HAS_LINEAR_E_JERK
  338. static float max_e_jerk[DISTINCT_E]; // Calculated from junction_deviation_mm
  339. #endif
  340. #endif
  341. #if HAS_CLASSIC_JERK
  342. // (mm/s^2) M205 XYZ(E) - The largest speed change requiring no acceleration.
  343. static TERN(HAS_LINEAR_E_JERK, xyz_pos_t, xyze_pos_t) max_jerk;
  344. #endif
  345. #if HAS_LEVELING
  346. static bool leveling_active; // Flag that bed leveling is enabled
  347. #if ABL_PLANAR
  348. static matrix_3x3 bed_level_matrix; // Transform to compensate for bed level
  349. #endif
  350. #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
  351. static float z_fade_height, inverse_z_fade_height;
  352. #endif
  353. #else
  354. static constexpr bool leveling_active = false;
  355. #endif
  356. #if ENABLED(LIN_ADVANCE)
  357. static float extruder_advance_K[EXTRUDERS];
  358. #endif
  359. /**
  360. * The current position of the tool in absolute steps
  361. * Recalculated if any axis_steps_per_mm are changed by G-code
  362. */
  363. static xyze_long_t position;
  364. #if HAS_POSITION_FLOAT
  365. static xyze_pos_t position_float;
  366. #endif
  367. #if IS_KINEMATIC
  368. static xyze_pos_t position_cart;
  369. #endif
  370. static skew_factor_t skew_factor;
  371. #if ENABLED(SD_ABORT_ON_ENDSTOP_HIT)
  372. static bool abort_on_endstop_hit;
  373. #endif
  374. #ifdef XY_FREQUENCY_LIMIT
  375. static int8_t xy_freq_limit_hz; // Minimum XY frequency setting
  376. static float xy_freq_min_speed_factor; // Minimum speed factor setting
  377. static int32_t xy_freq_min_interval_us; // Minimum segment time based on xy_freq_limit_hz
  378. static void refresh_frequency_limit() {
  379. //xy_freq_min_interval_us = xy_freq_limit_hz ?: LROUND(1000000.0f / xy_freq_limit_hz);
  380. if (xy_freq_limit_hz)
  381. xy_freq_min_interval_us = LROUND(1000000.0f / xy_freq_limit_hz);
  382. }
  383. static void set_min_speed_factor_u8(const uint8_t v255) {
  384. xy_freq_min_speed_factor = float(ui8_to_percent(v255)) / 100;
  385. }
  386. static void set_frequency_limit(const uint8_t hz) {
  387. xy_freq_limit_hz = constrain(hz, 0, 100);
  388. refresh_frequency_limit();
  389. }
  390. #endif
  391. private:
  392. /**
  393. * Speed of previous path line segment
  394. */
  395. static xyze_float_t previous_speed;
  396. /**
  397. * Nominal speed of previous path line segment (mm/s)^2
  398. */
  399. static float previous_nominal_speed_sqr;
  400. /**
  401. * Limit where 64bit math is necessary for acceleration calculation
  402. */
  403. static uint32_t acceleration_long_cutoff;
  404. #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
  405. static float last_fade_z;
  406. #endif
  407. #if ENABLED(DISABLE_INACTIVE_EXTRUDER)
  408. // Counters to manage disabling inactive extruder steppers
  409. static last_move_t g_uc_extruder_last_move[E_STEPPERS];
  410. #endif
  411. #if HAS_WIRED_LCD
  412. volatile static uint32_t block_buffer_runtime_us; // Theoretical block buffer runtime in µs
  413. #endif
  414. public:
  415. /**
  416. * Instance Methods
  417. */
  418. Planner();
  419. void init();
  420. /**
  421. * Static (class) Methods
  422. */
  423. // Recalculate steps/s^2 accelerations based on mm/s^2 settings
  424. static void refresh_acceleration_rates();
  425. /**
  426. * Recalculate 'position' and 'mm_per_step'.
  427. * Must be called whenever settings.axis_steps_per_mm changes!
  428. */
  429. static void refresh_positioning();
  430. // For an axis set the Maximum Acceleration in mm/s^2
  431. static void set_max_acceleration(const AxisEnum axis, float inMaxAccelMMS2);
  432. // For an axis set the Maximum Feedrate in mm/s
  433. static void set_max_feedrate(const AxisEnum axis, float inMaxFeedrateMMS);
  434. // For an axis set the Maximum Jerk (instant change) in mm/s
  435. #if HAS_CLASSIC_JERK
  436. static void set_max_jerk(const AxisEnum axis, float inMaxJerkMMS);
  437. #else
  438. static void set_max_jerk(const AxisEnum, const_float_t) {}
  439. #endif
  440. #if HAS_EXTRUDERS
  441. FORCE_INLINE static void refresh_e_factor(const uint8_t e) {
  442. e_factor[e] = flow_percentage[e] * 0.01f * TERN(NO_VOLUMETRICS, 1.0f, volumetric_multiplier[e]);
  443. }
  444. static void set_flow(const uint8_t e, const int16_t flow) {
  445. flow_percentage[e] = flow;
  446. refresh_e_factor(e);
  447. }
  448. #endif
  449. // Manage fans, paste pressure, etc.
  450. static void check_axes_activity();
  451. // Apply fan speeds
  452. #if HAS_FAN
  453. static void sync_fan_speeds(uint8_t (&fan_speed)[FAN_COUNT]);
  454. #if FAN_KICKSTART_TIME
  455. static void kickstart_fan(uint8_t (&fan_speed)[FAN_COUNT], const millis_t &ms, const uint8_t f);
  456. #else
  457. FORCE_INLINE static void kickstart_fan(uint8_t (&)[FAN_COUNT], const millis_t &, const uint8_t) {}
  458. #endif
  459. #endif
  460. #if ENABLED(FILAMENT_WIDTH_SENSOR)
  461. void apply_filament_width_sensor(const int8_t encoded_ratio);
  462. static float volumetric_percent(const bool vol) {
  463. return 100.0f * (vol
  464. ? volumetric_area_nominal / volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM]
  465. : volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM]
  466. );
  467. }
  468. #endif
  469. #if ENABLED(IMPROVE_HOMING_RELIABILITY)
  470. void enable_stall_prevention(const bool onoff);
  471. #endif
  472. #if DISABLED(NO_VOLUMETRICS)
  473. // Update multipliers based on new diameter measurements
  474. static void calculate_volumetric_multipliers();
  475. #if ENABLED(VOLUMETRIC_EXTRUDER_LIMIT)
  476. // Update pre calculated extruder feedrate limits based on volumetric values
  477. static void calculate_volumetric_extruder_limit(const uint8_t e);
  478. static void calculate_volumetric_extruder_limits();
  479. #endif
  480. FORCE_INLINE static void set_filament_size(const uint8_t e, const_float_t v) {
  481. filament_size[e] = v;
  482. if (v > 0) volumetric_area_nominal = CIRCLE_AREA(v * 0.5); //TODO: should it be per extruder
  483. // make sure all extruders have some sane value for the filament size
  484. LOOP_L_N(i, COUNT(filament_size))
  485. if (!filament_size[i]) filament_size[i] = DEFAULT_NOMINAL_FILAMENT_DIA;
  486. }
  487. #endif
  488. #if ENABLED(VOLUMETRIC_EXTRUDER_LIMIT)
  489. FORCE_INLINE static void set_volumetric_extruder_limit(const uint8_t e, const_float_t v) {
  490. volumetric_extruder_limit[e] = v;
  491. calculate_volumetric_extruder_limit(e);
  492. }
  493. #endif
  494. #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
  495. /**
  496. * Get the Z leveling fade factor based on the given Z height,
  497. * re-calculating only when needed.
  498. *
  499. * Returns 1.0 if planner.z_fade_height is 0.0.
  500. * Returns 0.0 if Z is past the specified 'Fade Height'.
  501. */
  502. static float fade_scaling_factor_for_z(const_float_t rz) {
  503. static float z_fade_factor = 1;
  504. if (!z_fade_height || rz <= 0) return 1;
  505. if (rz >= z_fade_height) return 0;
  506. if (last_fade_z != rz) {
  507. last_fade_z = rz;
  508. z_fade_factor = 1 - rz * inverse_z_fade_height;
  509. }
  510. return z_fade_factor;
  511. }
  512. FORCE_INLINE static void force_fade_recalc() { last_fade_z = -999.999f; }
  513. FORCE_INLINE static void set_z_fade_height(const_float_t zfh) {
  514. z_fade_height = zfh > 0 ? zfh : 0;
  515. inverse_z_fade_height = RECIPROCAL(z_fade_height);
  516. force_fade_recalc();
  517. }
  518. FORCE_INLINE static bool leveling_active_at_z(const_float_t rz) {
  519. return !z_fade_height || rz < z_fade_height;
  520. }
  521. #else
  522. FORCE_INLINE static float fade_scaling_factor_for_z(const_float_t) { return 1; }
  523. FORCE_INLINE static bool leveling_active_at_z(const_float_t) { return true; }
  524. #endif
  525. #if ENABLED(SKEW_CORRECTION)
  526. FORCE_INLINE static void skew(float &cx, float &cy, const_float_t cz) {
  527. if (COORDINATE_OKAY(cx, X_MIN_POS + 1, X_MAX_POS) && COORDINATE_OKAY(cy, Y_MIN_POS + 1, Y_MAX_POS)) {
  528. const float sx = cx - cy * skew_factor.xy - cz * (skew_factor.xz - (skew_factor.xy * skew_factor.yz)),
  529. sy = cy - cz * skew_factor.yz;
  530. if (COORDINATE_OKAY(sx, X_MIN_POS, X_MAX_POS) && COORDINATE_OKAY(sy, Y_MIN_POS, Y_MAX_POS)) {
  531. cx = sx; cy = sy;
  532. }
  533. }
  534. }
  535. FORCE_INLINE static void skew(xyz_pos_t &raw) { skew(raw.x, raw.y, raw.z); }
  536. FORCE_INLINE static void unskew(float &cx, float &cy, const_float_t cz) {
  537. if (COORDINATE_OKAY(cx, X_MIN_POS, X_MAX_POS) && COORDINATE_OKAY(cy, Y_MIN_POS, Y_MAX_POS)) {
  538. const float sx = cx + cy * skew_factor.xy + cz * skew_factor.xz,
  539. sy = cy + cz * skew_factor.yz;
  540. if (COORDINATE_OKAY(sx, X_MIN_POS, X_MAX_POS) && COORDINATE_OKAY(sy, Y_MIN_POS, Y_MAX_POS)) {
  541. cx = sx; cy = sy;
  542. }
  543. }
  544. }
  545. FORCE_INLINE static void unskew(xyz_pos_t &raw) { unskew(raw.x, raw.y, raw.z); }
  546. #endif // SKEW_CORRECTION
  547. #if HAS_LEVELING
  548. /**
  549. * Apply leveling to transform a cartesian position
  550. * as it will be given to the planner and steppers.
  551. */
  552. static void apply_leveling(xyz_pos_t &raw);
  553. static void unapply_leveling(xyz_pos_t &raw);
  554. FORCE_INLINE static void force_unapply_leveling(xyz_pos_t &raw) {
  555. leveling_active = true;
  556. unapply_leveling(raw);
  557. leveling_active = false;
  558. }
  559. #else
  560. FORCE_INLINE static void apply_leveling(xyz_pos_t&) {}
  561. FORCE_INLINE static void unapply_leveling(xyz_pos_t&) {}
  562. #endif
  563. #if ENABLED(FWRETRACT)
  564. static void apply_retract(float &rz, float &e);
  565. FORCE_INLINE static void apply_retract(xyze_pos_t &raw) { apply_retract(raw.z, raw.e); }
  566. static void unapply_retract(float &rz, float &e);
  567. FORCE_INLINE static void unapply_retract(xyze_pos_t &raw) { unapply_retract(raw.z, raw.e); }
  568. #endif
  569. #if HAS_POSITION_MODIFIERS
  570. FORCE_INLINE static void apply_modifiers(xyze_pos_t &pos, bool leveling=ENABLED(PLANNER_LEVELING)) {
  571. TERN_(SKEW_CORRECTION, skew(pos));
  572. if (leveling) apply_leveling(pos);
  573. TERN_(FWRETRACT, apply_retract(pos));
  574. }
  575. FORCE_INLINE static void unapply_modifiers(xyze_pos_t &pos, bool leveling=ENABLED(PLANNER_LEVELING)) {
  576. TERN_(FWRETRACT, unapply_retract(pos));
  577. if (leveling) unapply_leveling(pos);
  578. TERN_(SKEW_CORRECTION, unskew(pos));
  579. }
  580. #endif // HAS_POSITION_MODIFIERS
  581. // Number of moves currently in the planner including the busy block, if any
  582. FORCE_INLINE static uint8_t movesplanned() { return BLOCK_MOD(block_buffer_head - block_buffer_tail); }
  583. // Number of nonbusy moves currently in the planner
  584. FORCE_INLINE static uint8_t nonbusy_movesplanned() { return BLOCK_MOD(block_buffer_head - block_buffer_nonbusy); }
  585. // Remove all blocks from the buffer
  586. FORCE_INLINE static void clear_block_buffer() { block_buffer_nonbusy = block_buffer_planned = block_buffer_head = block_buffer_tail = 0; }
  587. // Check if movement queue is full
  588. FORCE_INLINE static bool is_full() { return block_buffer_tail == next_block_index(block_buffer_head); }
  589. // Get count of movement slots free
  590. FORCE_INLINE static uint8_t moves_free() { return BLOCK_BUFFER_SIZE - 1 - movesplanned(); }
  591. /**
  592. * Planner::get_next_free_block
  593. *
  594. * - Get the next head indices (passed by reference)
  595. * - Wait for the number of spaces to open up in the planner
  596. * - Return the first head block
  597. */
  598. FORCE_INLINE static block_t* get_next_free_block(uint8_t &next_buffer_head, const uint8_t count=1) {
  599. // Wait until there are enough slots free
  600. while (moves_free() < count) { idle(); }
  601. // Return the first available block
  602. next_buffer_head = next_block_index(block_buffer_head);
  603. return &block_buffer[block_buffer_head];
  604. }
  605. /**
  606. * Planner::_buffer_steps
  607. *
  608. * Add a new linear movement to the buffer (in terms of steps).
  609. *
  610. * target - target position in steps units
  611. * fr_mm_s - (target) speed of the move
  612. * extruder - target extruder
  613. * millimeters - the length of the movement, if known
  614. *
  615. * Returns true if movement was buffered, false otherwise
  616. */
  617. static bool _buffer_steps(const xyze_long_t &target
  618. OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float)
  619. OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm)
  620. , feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters=0.0
  621. );
  622. /**
  623. * @brief Populate a block in preparation for insertion
  624. * @details Populate the fields of a new linear movement block
  625. * that will be added to the queue and processed soon
  626. * by the Stepper ISR.
  627. *
  628. * @param block A block to populate
  629. * @param target Target position in steps units
  630. * @param target_float Target position in native mm
  631. * @param cart_dist_mm The pre-calculated move lengths for all axes, in mm
  632. * @param fr_mm_s (target) speed of the move
  633. * @param extruder target extruder
  634. * @param millimeters A pre-calculated linear distance for the move, in mm,
  635. * or 0.0 to have the distance calculated here.
  636. *
  637. * @return true if movement is acceptable, false otherwise
  638. */
  639. static bool _populate_block(block_t * const block, const xyze_long_t &target
  640. OPTARG(HAS_POSITION_FLOAT, const xyze_pos_t &target_float)
  641. OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm)
  642. , feedRate_t fr_mm_s, const uint8_t extruder, const_float_t millimeters=0.0
  643. );
  644. /**
  645. * Planner::buffer_sync_block
  646. * Add a block to the buffer that just updates the position
  647. * @param sync_flag sets a condition bit to process additional items
  648. * such as sync fan pwm or sync M3/M4 laser power into a queued block
  649. */
  650. static void buffer_sync_block(const BlockFlagBit flag=BLOCK_BIT_SYNC_POSITION);
  651. #if IS_KINEMATIC
  652. private:
  653. // Allow do_homing_move to access internal functions, such as buffer_segment.
  654. friend void do_homing_move(const AxisEnum, const float, const feedRate_t, const bool);
  655. #endif
  656. /**
  657. * Planner::buffer_segment
  658. *
  659. * Add a new linear movement to the buffer in axis units.
  660. *
  661. * Leveling and kinematics should be applied ahead of calling this.
  662. *
  663. * a,b,c,e - target positions in mm and/or degrees
  664. * fr_mm_s - (target) speed of the move
  665. * extruder - target extruder
  666. * millimeters - the length of the movement, if known
  667. */
  668. static bool buffer_segment(const abce_pos_t &abce
  669. OPTARG(HAS_DIST_MM_ARG, const xyze_float_t &cart_dist_mm)
  670. , const_feedRate_t fr_mm_s, const uint8_t extruder=active_extruder, const_float_t millimeters=0.0
  671. );
  672. public:
  673. /**
  674. * Add a new linear movement to the buffer.
  675. * The target is cartesian. It's translated to
  676. * delta/scara if needed.
  677. *
  678. * cart - target position in mm or degrees
  679. * fr_mm_s - (target) speed of the move (mm/s)
  680. * extruder - target extruder
  681. * millimeters - the length of the movement, if known
  682. * inv_duration - the reciprocal if the duration of the movement, if known (kinematic only if feeedrate scaling is enabled)
  683. */
  684. 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
  685. OPTARG(SCARA_FEEDRATE_SCALING, const_float_t inv_duration=0.0)
  686. );
  687. #if ENABLED(DIRECT_STEPPING)
  688. static void buffer_page(const page_idx_t page_idx, const uint8_t extruder, const uint16_t num_steps);
  689. #endif
  690. /**
  691. * Set the planner.position and individual stepper positions.
  692. * Used by G92, G28, G29, and other procedures.
  693. *
  694. * The supplied position is in the cartesian coordinate space and is
  695. * translated in to machine space as needed. Modifiers such as leveling
  696. * and skew are also applied.
  697. *
  698. * Multiplies by axis_steps_per_mm[] and does necessary conversion
  699. * for COREXY / COREXZ / COREYZ to set the corresponding stepper positions.
  700. *
  701. * Clears previous speed values.
  702. */
  703. static void set_position_mm(const xyze_pos_t &xyze);
  704. #if HAS_EXTRUDERS
  705. static void set_e_position_mm(const_float_t e);
  706. #endif
  707. /**
  708. * Set the planner.position and individual stepper positions.
  709. *
  710. * The supplied position is in machine space, and no additional
  711. * conversions are applied.
  712. */
  713. static void set_machine_position_mm(const abce_pos_t &abce);
  714. /**
  715. * Get an axis position according to stepper position(s)
  716. * For CORE machines apply translation from ABC to XYZ.
  717. */
  718. static float get_axis_position_mm(const AxisEnum axis);
  719. static abce_pos_t get_axis_positions_mm() {
  720. const abce_pos_t out = LOGICAL_AXIS_ARRAY(
  721. get_axis_position_mm(E_AXIS),
  722. get_axis_position_mm(A_AXIS), get_axis_position_mm(B_AXIS), get_axis_position_mm(C_AXIS),
  723. get_axis_position_mm(I_AXIS), get_axis_position_mm(J_AXIS), get_axis_position_mm(K_AXIS),
  724. get_axis_position_mm(U_AXIS), get_axis_position_mm(V_AXIS), get_axis_position_mm(W_AXIS)
  725. );
  726. return out;
  727. }
  728. // SCARA AB axes are in degrees, not mm
  729. #if IS_SCARA
  730. FORCE_INLINE static float get_axis_position_degrees(const AxisEnum axis) { return get_axis_position_mm(axis); }
  731. #endif
  732. // Called to force a quick stop of the machine (for example, when
  733. // a Full Shutdown is required, or when endstops are hit)
  734. static void quick_stop();
  735. #if ENABLED(REALTIME_REPORTING_COMMANDS)
  736. // Force a quick pause of the machine (e.g., when a pause is required in the middle of move).
  737. // NOTE: Hard-stops will lose steps so encoders are highly recommended if using these!
  738. static void quick_pause();
  739. static void quick_resume();
  740. #endif
  741. // Called when an endstop is triggered. Causes the machine to stop immediately
  742. static void endstop_triggered(const AxisEnum axis);
  743. // Triggered position of an axis in mm (not core-savvy)
  744. static float triggered_position_mm(const AxisEnum axis);
  745. // Blocks are queued, or we're running out moves, or the closed loop controller is waiting
  746. static bool busy() {
  747. return (has_blocks_queued() || cleaning_buffer_counter
  748. || TERN0(EXTERNAL_CLOSED_LOOP_CONTROLLER, CLOSED_LOOP_WAITING())
  749. );
  750. }
  751. // Block until all buffered steps are executed / cleaned
  752. static void synchronize();
  753. // Wait for moves to finish and disable all steppers
  754. static void finish_and_disable();
  755. // Periodic handler to manage the cleaning buffer counter
  756. // Called from the Temperature ISR at ~1kHz
  757. static void isr() { if (cleaning_buffer_counter) --cleaning_buffer_counter; }
  758. /**
  759. * Does the buffer have any blocks queued?
  760. */
  761. FORCE_INLINE static bool has_blocks_queued() { return (block_buffer_head != block_buffer_tail); }
  762. /**
  763. * Get the current block for processing
  764. * and mark the block as busy.
  765. * Return nullptr if the buffer is empty
  766. * or if there is a first-block delay.
  767. *
  768. * WARNING: Called from Stepper ISR context!
  769. */
  770. static block_t* get_current_block();
  771. /**
  772. * "Release" the current block so its slot can be reused.
  773. * Called when the current block is no longer needed.
  774. */
  775. FORCE_INLINE static void release_current_block() {
  776. if (has_blocks_queued())
  777. block_buffer_tail = next_block_index(block_buffer_tail);
  778. }
  779. #if HAS_WIRED_LCD
  780. static uint16_t block_buffer_runtime();
  781. static void clear_block_buffer_runtime();
  782. #endif
  783. #if ENABLED(AUTOTEMP)
  784. static celsius_t autotemp_min, autotemp_max;
  785. static float autotemp_factor;
  786. static bool autotemp_enabled;
  787. static void autotemp_update();
  788. static void autotemp_M104_M109();
  789. static void autotemp_task();
  790. #endif
  791. #if HAS_LINEAR_E_JERK
  792. FORCE_INLINE static void recalculate_max_e_jerk() {
  793. const float prop = junction_deviation_mm * SQRT(0.5) / (1.0f - SQRT(0.5));
  794. EXTRUDER_LOOP()
  795. max_e_jerk[E_INDEX_N(e)] = SQRT(prop * settings.max_acceleration_mm_per_s2[E_INDEX_N(e)]);
  796. }
  797. #endif
  798. private:
  799. #if ENABLED(AUTOTEMP)
  800. #if ENABLED(AUTOTEMP_PROPORTIONAL)
  801. static void _autotemp_update_from_hotend();
  802. #else
  803. static void _autotemp_update_from_hotend() {}
  804. #endif
  805. #endif
  806. /**
  807. * Get the index of the next / previous block in the ring buffer
  808. */
  809. static constexpr uint8_t next_block_index(const uint8_t block_index) { return BLOCK_MOD(block_index + 1); }
  810. static constexpr uint8_t prev_block_index(const uint8_t block_index) { return BLOCK_MOD(block_index - 1); }
  811. /**
  812. * Calculate the distance (not time) it takes to accelerate
  813. * from initial_rate to target_rate using the given acceleration:
  814. */
  815. static float estimate_acceleration_distance(const_float_t initial_rate, const_float_t target_rate, const_float_t accel) {
  816. if (accel == 0) return 0; // accel was 0, set acceleration distance to 0
  817. return (sq(target_rate) - sq(initial_rate)) / (accel * 2);
  818. }
  819. /**
  820. * Return the point at which you must start braking (at the rate of -'accel') if
  821. * you start at 'initial_rate', accelerate (until reaching the point), and want to end at
  822. * 'final_rate' after traveling 'distance'.
  823. *
  824. * This is used to compute the intersection point between acceleration and deceleration
  825. * in cases where the "trapezoid" has no plateau (i.e., never reaches maximum speed)
  826. */
  827. static float intersection_distance(const_float_t initial_rate, const_float_t final_rate, const_float_t accel, const_float_t distance) {
  828. if (accel == 0) return 0; // accel was 0, set intersection distance to 0
  829. return (accel * 2 * distance - sq(initial_rate) + sq(final_rate)) / (accel * 4);
  830. }
  831. /**
  832. * Calculate the maximum allowable speed squared at this point, in order
  833. * to reach 'target_velocity_sqr' using 'acceleration' within a given
  834. * 'distance'.
  835. */
  836. static float max_allowable_speed_sqr(const_float_t accel, const_float_t target_velocity_sqr, const_float_t distance) {
  837. return target_velocity_sqr - 2 * accel * distance;
  838. }
  839. #if ENABLED(S_CURVE_ACCELERATION)
  840. /**
  841. * Calculate the speed reached given initial speed, acceleration and distance
  842. */
  843. static float final_speed(const_float_t initial_velocity, const_float_t accel, const_float_t distance) {
  844. return SQRT(sq(initial_velocity) + 2 * accel * distance);
  845. }
  846. #endif
  847. static void calculate_trapezoid_for_block(block_t * const block, const_float_t entry_factor, const_float_t exit_factor);
  848. static void reverse_pass_kernel(block_t * const current, const block_t * const next);
  849. static void forward_pass_kernel(const block_t * const previous, block_t * const current, uint8_t block_index);
  850. static void reverse_pass();
  851. static void forward_pass();
  852. static void recalculate_trapezoids();
  853. static void recalculate();
  854. #if HAS_JUNCTION_DEVIATION
  855. FORCE_INLINE static void normalize_junction_vector(xyze_float_t &vector) {
  856. float magnitude_sq = 0;
  857. LOOP_LOGICAL_AXES(idx) if (vector[idx]) magnitude_sq += sq(vector[idx]);
  858. vector *= RSQRT(magnitude_sq);
  859. }
  860. FORCE_INLINE static float limit_value_by_axis_maximum(const_float_t max_value, xyze_float_t &unit_vec) {
  861. float limit_value = max_value;
  862. LOOP_LOGICAL_AXES(idx) {
  863. if (unit_vec[idx]) {
  864. if (limit_value * ABS(unit_vec[idx]) > settings.max_acceleration_mm_per_s2[idx])
  865. limit_value = ABS(settings.max_acceleration_mm_per_s2[idx] / unit_vec[idx]);
  866. }
  867. }
  868. return limit_value;
  869. }
  870. #endif // HAS_JUNCTION_DEVIATION
  871. };
  872. #define PLANNER_XY_FEEDRATE() _MIN(planner.settings.max_feedrate_mm_s[X_AXIS], planner.settings.max_feedrate_mm_s[Y_AXIS])
  873. extern Planner planner;