My Marlin configs for Fabrikator Mini and CTC i3 Pro B
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

motion.h 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  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. * motion.h
  25. *
  26. * High-level motion commands to feed the planner
  27. * Some of these methods may migrate to the planner class.
  28. */
  29. #include "../inc/MarlinConfig.h"
  30. #if IS_SCARA
  31. #include "scara.h"
  32. #endif
  33. // Error margin to work around float imprecision
  34. constexpr float fslop = 0.0001;
  35. extern bool relative_mode;
  36. extern xyze_pos_t current_position, // High-level current tool position
  37. destination; // Destination for a move
  38. // G60/G61 Position Save and Return
  39. #if SAVED_POSITIONS
  40. extern uint8_t saved_slots[(SAVED_POSITIONS + 7) >> 3]; // TODO: Add support for HAS_I_AXIS
  41. extern xyze_pos_t stored_position[SAVED_POSITIONS];
  42. #endif
  43. // Scratch space for a cartesian result
  44. extern xyz_pos_t cartes;
  45. // Until kinematics.cpp is created, declare this here
  46. #if IS_KINEMATIC
  47. extern abce_pos_t delta;
  48. #endif
  49. #if HAS_ABL_NOT_UBL
  50. extern feedRate_t xy_probe_feedrate_mm_s;
  51. #define XY_PROBE_FEEDRATE_MM_S xy_probe_feedrate_mm_s
  52. #elif defined(XY_PROBE_FEEDRATE)
  53. #define XY_PROBE_FEEDRATE_MM_S MMM_TO_MMS(XY_PROBE_FEEDRATE)
  54. #else
  55. #define XY_PROBE_FEEDRATE_MM_S PLANNER_XY_FEEDRATE()
  56. #endif
  57. #if HAS_BED_PROBE
  58. constexpr feedRate_t z_probe_fast_mm_s = MMM_TO_MMS(Z_PROBE_FEEDRATE_FAST);
  59. #endif
  60. /**
  61. * Feed rates are often configured with mm/m
  62. * but the planner and stepper like mm/s units.
  63. */
  64. constexpr xyz_feedrate_t homing_feedrate_mm_m = HOMING_FEEDRATE_MM_M;
  65. FORCE_INLINE feedRate_t homing_feedrate(const AxisEnum a) {
  66. float v = TERN0(HAS_Z_AXIS, homing_feedrate_mm_m.z);
  67. #if DISABLED(DELTA)
  68. NUM_AXIS_CODE(
  69. if (a == X_AXIS) v = homing_feedrate_mm_m.x,
  70. else if (a == Y_AXIS) v = homing_feedrate_mm_m.y,
  71. else if (a == Z_AXIS) v = homing_feedrate_mm_m.z,
  72. else if (a == I_AXIS) v = homing_feedrate_mm_m.i,
  73. else if (a == J_AXIS) v = homing_feedrate_mm_m.j,
  74. else if (a == K_AXIS) v = homing_feedrate_mm_m.k,
  75. else if (a == U_AXIS) v = homing_feedrate_mm_m.u,
  76. else if (a == V_AXIS) v = homing_feedrate_mm_m.v,
  77. else if (a == W_AXIS) v = homing_feedrate_mm_m.w
  78. );
  79. #endif
  80. return MMM_TO_MMS(v);
  81. }
  82. feedRate_t get_homing_bump_feedrate(const AxisEnum axis);
  83. /**
  84. * The default feedrate for many moves, set by the most recent move
  85. */
  86. extern feedRate_t feedrate_mm_s;
  87. /**
  88. * Feedrate scaling is applied to all G0/G1, G2/G3, and G5 moves
  89. */
  90. extern int16_t feedrate_percentage;
  91. #define MMS_SCALED(V) ((V) * 0.01f * feedrate_percentage)
  92. // The active extruder (tool). Set with T<extruder> command.
  93. #if HAS_MULTI_EXTRUDER
  94. extern uint8_t active_extruder;
  95. #else
  96. constexpr uint8_t active_extruder = 0;
  97. #endif
  98. #if ENABLED(LCD_SHOW_E_TOTAL)
  99. extern float e_move_accumulator;
  100. #endif
  101. #ifdef __IMXRT1062__
  102. #define DEFS_PROGMEM
  103. #else
  104. #define DEFS_PROGMEM PROGMEM
  105. #endif
  106. inline float pgm_read_any(const float *p) { return TERN(__IMXRT1062__, *p, pgm_read_float(p)); }
  107. inline int8_t pgm_read_any(const int8_t *p) { return TERN(__IMXRT1062__, *p, pgm_read_byte(p)); }
  108. #define XYZ_DEFS(T, NAME, OPT) \
  109. inline T NAME(const AxisEnum axis) { \
  110. static const XYZval<T> NAME##_P DEFS_PROGMEM = NUM_AXIS_ARRAY(X_##OPT, Y_##OPT, Z_##OPT, I_##OPT, J_##OPT, K_##OPT, U_##OPT, V_##OPT, W_##OPT); \
  111. return pgm_read_any(&NAME##_P[axis]); \
  112. }
  113. XYZ_DEFS(float, base_min_pos, MIN_POS);
  114. XYZ_DEFS(float, base_max_pos, MAX_POS);
  115. XYZ_DEFS(float, base_home_pos, HOME_POS);
  116. XYZ_DEFS(float, max_length, MAX_LENGTH);
  117. XYZ_DEFS(int8_t, home_dir, HOME_DIR);
  118. inline float home_bump_mm(const AxisEnum axis) {
  119. static const xyz_pos_t home_bump_mm_P DEFS_PROGMEM = HOMING_BUMP_MM;
  120. return pgm_read_any(&home_bump_mm_P[axis]);
  121. }
  122. #if HAS_WORKSPACE_OFFSET
  123. void update_workspace_offset(const AxisEnum axis);
  124. #else
  125. inline void update_workspace_offset(const AxisEnum) {}
  126. #endif
  127. #if HAS_HOTEND_OFFSET
  128. extern xyz_pos_t hotend_offset[HOTENDS];
  129. void reset_hotend_offsets();
  130. #elif HOTENDS
  131. constexpr xyz_pos_t hotend_offset[HOTENDS] = { { 0 } };
  132. #else
  133. constexpr xyz_pos_t hotend_offset[1] = { { 0 } };
  134. #endif
  135. #if HAS_SOFTWARE_ENDSTOPS
  136. typedef struct {
  137. bool _enabled, _loose;
  138. bool enabled() { return _enabled && !_loose; }
  139. xyz_pos_t min, max;
  140. void get_manual_axis_limits(const AxisEnum axis, float &amin, float &amax) {
  141. amin = -100000; amax = 100000; // "No limits"
  142. #if HAS_SOFTWARE_ENDSTOPS
  143. if (enabled()) switch (axis) {
  144. case X_AXIS:
  145. TERN_(MIN_SOFTWARE_ENDSTOP_X, amin = min.x);
  146. TERN_(MAX_SOFTWARE_ENDSTOP_X, amax = max.x);
  147. break;
  148. #if HAS_Y_AXIS
  149. case Y_AXIS:
  150. TERN_(MIN_SOFTWARE_ENDSTOP_Y, amin = min.y);
  151. TERN_(MAX_SOFTWARE_ENDSTOP_Y, amax = max.y);
  152. break;
  153. #endif
  154. #if HAS_Z_AXIS
  155. case Z_AXIS:
  156. TERN_(MIN_SOFTWARE_ENDSTOP_Z, amin = min.z);
  157. TERN_(MAX_SOFTWARE_ENDSTOP_Z, amax = max.z);
  158. break;
  159. #endif
  160. #if HAS_I_AXIS
  161. case I_AXIS:
  162. TERN_(MIN_SOFTWARE_ENDSTOP_I, amin = min.i);
  163. TERN_(MIN_SOFTWARE_ENDSTOP_I, amax = max.i);
  164. break;
  165. #endif
  166. #if HAS_J_AXIS
  167. case J_AXIS:
  168. TERN_(MIN_SOFTWARE_ENDSTOP_J, amin = min.j);
  169. TERN_(MIN_SOFTWARE_ENDSTOP_J, amax = max.j);
  170. break;
  171. #endif
  172. #if HAS_K_AXIS
  173. case K_AXIS:
  174. TERN_(MIN_SOFTWARE_ENDSTOP_K, amin = min.k);
  175. TERN_(MIN_SOFTWARE_ENDSTOP_K, amax = max.k);
  176. break;
  177. #endif
  178. #if HAS_U_AXIS
  179. case U_AXIS:
  180. TERN_(MIN_SOFTWARE_ENDSTOP_U, amin = min.u);
  181. TERN_(MIN_SOFTWARE_ENDSTOP_U, amax = max.u);
  182. break;
  183. #endif
  184. #if HAS_V_AXIS
  185. case V_AXIS:
  186. TERN_(MIN_SOFTWARE_ENDSTOP_V, amin = min.v);
  187. TERN_(MIN_SOFTWARE_ENDSTOP_V, amax = max.v);
  188. break;
  189. #endif
  190. #if HAS_W_AXIS
  191. case W_AXIS:
  192. TERN_(MIN_SOFTWARE_ENDSTOP_W, amin = min.w);
  193. TERN_(MIN_SOFTWARE_ENDSTOP_W, amax = max.w);
  194. break;
  195. #endif
  196. default: break;
  197. }
  198. #endif
  199. }
  200. } soft_endstops_t;
  201. extern soft_endstops_t soft_endstop;
  202. void apply_motion_limits(xyz_pos_t &target);
  203. void update_software_endstops(const AxisEnum axis
  204. #if HAS_HOTEND_OFFSET
  205. , const uint8_t old_tool_index=0, const uint8_t new_tool_index=0
  206. #endif
  207. );
  208. #define SET_SOFT_ENDSTOP_LOOSE(loose) (soft_endstop._loose = loose)
  209. #else // !HAS_SOFTWARE_ENDSTOPS
  210. typedef struct {
  211. bool enabled() { return false; }
  212. void get_manual_axis_limits(const AxisEnum axis, float &amin, float &amax) {
  213. // No limits
  214. amin = current_position[axis] - 1000;
  215. amax = current_position[axis] + 1000;
  216. }
  217. } soft_endstops_t;
  218. extern soft_endstops_t soft_endstop;
  219. #define apply_motion_limits(V) NOOP
  220. #define update_software_endstops(...) NOOP
  221. #define SET_SOFT_ENDSTOP_LOOSE(V) NOOP
  222. #endif // !HAS_SOFTWARE_ENDSTOPS
  223. void report_real_position();
  224. void report_current_position();
  225. void report_current_position_projected();
  226. #if ENABLED(AUTO_REPORT_POSITION)
  227. #include "../libs/autoreport.h"
  228. struct PositionReport { static void report() { report_current_position_projected(); } };
  229. extern AutoReporter<PositionReport> position_auto_reporter;
  230. #endif
  231. #if EITHER(FULL_REPORT_TO_HOST_FEATURE, REALTIME_REPORTING_COMMANDS)
  232. #define HAS_GRBL_STATE 1
  233. /**
  234. * Machine states for GRBL or TinyG
  235. */
  236. enum M_StateEnum : uint8_t {
  237. M_INIT = 0, // 0 machine is initializing
  238. M_RESET, // 1 machine is ready for use
  239. M_ALARM, // 2 machine is in alarm state (soft shut down)
  240. M_IDLE, // 3 program stop or no more blocks (M0, M1, M60)
  241. M_END, // 4 program end via M2, M30
  242. M_RUNNING, // 5 motion is running
  243. M_HOLD, // 6 motion is holding
  244. M_PROBE, // 7 probe cycle active
  245. M_CYCLING, // 8 machine is running (cycling)
  246. M_HOMING, // 9 machine is homing
  247. M_JOGGING, // 10 machine is jogging
  248. M_ERROR // 11 machine is in hard alarm state (shut down)
  249. };
  250. extern M_StateEnum M_State_grbl;
  251. M_StateEnum grbl_state_for_marlin_state();
  252. void report_current_grblstate_moving();
  253. void report_current_position_moving();
  254. #if ENABLED(FULL_REPORT_TO_HOST_FEATURE)
  255. inline void set_and_report_grblstate(const M_StateEnum state, const bool force=true) {
  256. if (force || M_State_grbl != state) {
  257. M_State_grbl = state;
  258. report_current_grblstate_moving();
  259. }
  260. }
  261. #endif
  262. #if ENABLED(REALTIME_REPORTING_COMMANDS)
  263. void quickpause_stepper();
  264. void quickresume_stepper();
  265. #endif
  266. #endif
  267. void get_cartesian_from_steppers();
  268. void set_current_from_steppers_for_axis(const AxisEnum axis);
  269. void quickstop_stepper();
  270. /**
  271. * Set the planner/stepper positions directly from current_position with
  272. * no kinematic translation. Used for homing axes and cartesian/core syncing.
  273. */
  274. void sync_plan_position();
  275. #if HAS_EXTRUDERS
  276. void sync_plan_position_e();
  277. #endif
  278. /**
  279. * Move the planner to the current position from wherever it last moved
  280. * (or from wherever it has been told it is located).
  281. */
  282. void line_to_current_position(const_feedRate_t fr_mm_s=feedrate_mm_s);
  283. #if HAS_EXTRUDERS
  284. void unscaled_e_move(const_float_t length, const_feedRate_t fr_mm_s);
  285. #endif
  286. void prepare_line_to_destination();
  287. void _internal_move_to_destination(const_feedRate_t fr_mm_s=0.0f OPTARG(IS_KINEMATIC, const bool is_fast=false));
  288. inline void prepare_internal_move_to_destination(const_feedRate_t fr_mm_s=0.0f) {
  289. _internal_move_to_destination(fr_mm_s);
  290. }
  291. #if IS_KINEMATIC
  292. void prepare_fast_move_to_destination(const_feedRate_t scaled_fr_mm_s=MMS_SCALED(feedrate_mm_s));
  293. inline void prepare_internal_fast_move_to_destination(const_feedRate_t fr_mm_s=0.0f) {
  294. _internal_move_to_destination(fr_mm_s, true);
  295. }
  296. #endif
  297. /**
  298. * Blocking movement and shorthand functions
  299. */
  300. void do_blocking_move_to(NUM_AXIS_ARGS(const float), const_feedRate_t fr_mm_s=0.0f);
  301. void do_blocking_move_to(const xy_pos_t &raw, const_feedRate_t fr_mm_s=0.0f);
  302. void do_blocking_move_to(const xyz_pos_t &raw, const_feedRate_t fr_mm_s=0.0f);
  303. void do_blocking_move_to(const xyze_pos_t &raw, const_feedRate_t fr_mm_s=0.0f);
  304. void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s=0.0f);
  305. #if HAS_Y_AXIS
  306. void do_blocking_move_to_y(const_float_t ry, const_feedRate_t fr_mm_s=0.0f);
  307. #endif
  308. #if HAS_Z_AXIS
  309. void do_blocking_move_to_z(const_float_t rz, const_feedRate_t fr_mm_s=0.0f);
  310. #endif
  311. #if HAS_I_AXIS
  312. void do_blocking_move_to_i(const_float_t ri, const_feedRate_t fr_mm_s=0.0f);
  313. void do_blocking_move_to_xyz_i(const xyze_pos_t &raw, const_float_t i, const_feedRate_t fr_mm_s=0.0f);
  314. #endif
  315. #if HAS_J_AXIS
  316. void do_blocking_move_to_j(const_float_t rj, const_feedRate_t fr_mm_s=0.0f);
  317. void do_blocking_move_to_xyzi_j(const xyze_pos_t &raw, const_float_t j, const_feedRate_t fr_mm_s=0.0f);
  318. #endif
  319. #if HAS_K_AXIS
  320. void do_blocking_move_to_k(const_float_t rk, const_feedRate_t fr_mm_s=0.0f);
  321. void do_blocking_move_to_xyzij_k(const xyze_pos_t &raw, const_float_t k, const_feedRate_t fr_mm_s=0.0f);
  322. #endif
  323. #if HAS_U_AXIS
  324. void do_blocking_move_to_u(const_float_t ru, const_feedRate_t fr_mm_s=0.0f);
  325. void do_blocking_move_to_xyzijk_u(const xyze_pos_t &raw, const_float_t u, const_feedRate_t fr_mm_s=0.0f);
  326. #endif
  327. #if HAS_V_AXIS
  328. void do_blocking_move_to_v(const_float_t rv, const_feedRate_t fr_mm_s=0.0f);
  329. void do_blocking_move_to_xyzijku_v(const xyze_pos_t &raw, const_float_t v, const_feedRate_t fr_mm_s=0.0f);
  330. #endif
  331. #if HAS_W_AXIS
  332. void do_blocking_move_to_w(const float rw, const feedRate_t &fr_mm_s=0.0f);
  333. void do_blocking_move_to_xyzijkuv_w(const xyze_pos_t &raw, const float w, const feedRate_t &fr_mm_s=0.0f);
  334. #endif
  335. #if HAS_Y_AXIS
  336. void do_blocking_move_to_xy(const_float_t rx, const_float_t ry, const_feedRate_t fr_mm_s=0.0f);
  337. void do_blocking_move_to_xy(const xy_pos_t &raw, const_feedRate_t fr_mm_s=0.0f);
  338. FORCE_INLINE void do_blocking_move_to_xy(const xyz_pos_t &raw, const_feedRate_t fr_mm_s=0.0f) { do_blocking_move_to_xy(xy_pos_t(raw), fr_mm_s); }
  339. FORCE_INLINE void do_blocking_move_to_xy(const xyze_pos_t &raw, const_feedRate_t fr_mm_s=0.0f) { do_blocking_move_to_xy(xy_pos_t(raw), fr_mm_s); }
  340. #endif
  341. #if HAS_Z_AXIS
  342. void do_blocking_move_to_xy_z(const xy_pos_t &raw, const_float_t z, const_feedRate_t fr_mm_s=0.0f);
  343. FORCE_INLINE void do_blocking_move_to_xy_z(const xyz_pos_t &raw, const_float_t z, const_feedRate_t fr_mm_s=0.0f) { do_blocking_move_to_xy_z(xy_pos_t(raw), z, fr_mm_s); }
  344. FORCE_INLINE void do_blocking_move_to_xy_z(const xyze_pos_t &raw, const_float_t z, const_feedRate_t fr_mm_s=0.0f) { do_blocking_move_to_xy_z(xy_pos_t(raw), z, fr_mm_s); }
  345. #endif
  346. void remember_feedrate_and_scaling();
  347. void remember_feedrate_scaling_off();
  348. void restore_feedrate_and_scaling();
  349. #if HAS_Z_AXIS
  350. void do_z_clearance(const_float_t zclear, const bool lower_allowed=false);
  351. #else
  352. inline void do_z_clearance(float, bool=false) {}
  353. #endif
  354. /**
  355. * Homing and Trusted Axes
  356. */
  357. typedef IF<(NUM_AXES > 8), uint16_t, uint8_t>::type linear_axis_bits_t;
  358. constexpr linear_axis_bits_t linear_bits = _BV(NUM_AXES) - 1;
  359. void set_axis_is_at_home(const AxisEnum axis);
  360. #if HAS_ENDSTOPS
  361. /**
  362. * axis_homed
  363. * Flags that each linear axis was homed.
  364. * XYZ on cartesian, ABC on delta, ABZ on SCARA.
  365. *
  366. * axis_trusted
  367. * Flags that the position is trusted in each linear axis. Set when homed.
  368. * Cleared whenever a stepper powers off, potentially losing its position.
  369. */
  370. extern linear_axis_bits_t axis_homed, axis_trusted;
  371. void homeaxis(const AxisEnum axis);
  372. void set_axis_never_homed(const AxisEnum axis);
  373. linear_axis_bits_t axes_should_home(linear_axis_bits_t axis_bits=linear_bits);
  374. bool homing_needed_error(linear_axis_bits_t axis_bits=linear_bits);
  375. inline void set_axis_unhomed(const AxisEnum axis) { CBI(axis_homed, axis); }
  376. inline void set_axis_untrusted(const AxisEnum axis) { CBI(axis_trusted, axis); }
  377. inline void set_all_unhomed() { axis_homed = axis_trusted = 0; }
  378. inline void set_axis_homed(const AxisEnum axis) { SBI(axis_homed, axis); }
  379. inline void set_axis_trusted(const AxisEnum axis) { SBI(axis_trusted, axis); }
  380. inline void set_all_homed() { axis_homed = axis_trusted = linear_bits; }
  381. #else
  382. constexpr linear_axis_bits_t axis_homed = linear_bits, axis_trusted = linear_bits; // Zero-endstop machines are always homed and trusted
  383. inline void homeaxis(const AxisEnum axis) {}
  384. inline void set_axis_never_homed(const AxisEnum) {}
  385. inline linear_axis_bits_t axes_should_home(linear_axis_bits_t=linear_bits) { return 0; }
  386. inline bool homing_needed_error(linear_axis_bits_t=linear_bits) { return false; }
  387. inline void set_axis_unhomed(const AxisEnum axis) {}
  388. inline void set_axis_untrusted(const AxisEnum axis) {}
  389. inline void set_all_unhomed() {}
  390. inline void set_axis_homed(const AxisEnum axis) {}
  391. inline void set_axis_trusted(const AxisEnum axis) {}
  392. inline void set_all_homed() {}
  393. #endif
  394. inline bool axis_was_homed(const AxisEnum axis) { return TEST(axis_homed, axis); }
  395. inline bool axis_is_trusted(const AxisEnum axis) { return TEST(axis_trusted, axis); }
  396. inline bool axis_should_home(const AxisEnum axis) { return (axes_should_home() & _BV(axis)) != 0; }
  397. inline bool no_axes_homed() { return !axis_homed; }
  398. inline bool all_axes_homed() { return linear_bits == (axis_homed & linear_bits); }
  399. inline bool homing_needed() { return !all_axes_homed(); }
  400. inline bool all_axes_trusted() { return linear_bits == (axis_trusted & linear_bits); }
  401. void home_if_needed(const bool keeplev=false);
  402. #if ENABLED(NO_MOTION_BEFORE_HOMING)
  403. #define MOTION_CONDITIONS (IsRunning() && !homing_needed_error())
  404. #else
  405. #define MOTION_CONDITIONS IsRunning()
  406. #endif
  407. #define BABYSTEP_ALLOWED() ((ENABLED(BABYSTEP_WITHOUT_HOMING) || all_axes_trusted()) && (ENABLED(BABYSTEP_ALWAYS_AVAILABLE) || printer_busy()))
  408. /**
  409. * Workspace offsets
  410. */
  411. #if HAS_HOME_OFFSET || HAS_POSITION_SHIFT
  412. #if HAS_HOME_OFFSET
  413. extern xyz_pos_t home_offset;
  414. #endif
  415. #if HAS_POSITION_SHIFT
  416. extern xyz_pos_t position_shift;
  417. #endif
  418. #if HAS_HOME_OFFSET && HAS_POSITION_SHIFT
  419. extern xyz_pos_t workspace_offset;
  420. #define _WS workspace_offset
  421. #elif HAS_HOME_OFFSET
  422. #define _WS home_offset
  423. #else
  424. #define _WS position_shift
  425. #endif
  426. #define NATIVE_TO_LOGICAL(POS, AXIS) ((POS) + _WS[AXIS])
  427. #define LOGICAL_TO_NATIVE(POS, AXIS) ((POS) - _WS[AXIS])
  428. FORCE_INLINE void toLogical(xy_pos_t &raw) { raw += _WS; }
  429. FORCE_INLINE void toLogical(xyz_pos_t &raw) { raw += _WS; }
  430. FORCE_INLINE void toLogical(xyze_pos_t &raw) { raw += _WS; }
  431. FORCE_INLINE void toNative(xy_pos_t &raw) { raw -= _WS; }
  432. FORCE_INLINE void toNative(xyz_pos_t &raw) { raw -= _WS; }
  433. FORCE_INLINE void toNative(xyze_pos_t &raw) { raw -= _WS; }
  434. #else
  435. #define NATIVE_TO_LOGICAL(POS, AXIS) (POS)
  436. #define LOGICAL_TO_NATIVE(POS, AXIS) (POS)
  437. FORCE_INLINE void toLogical(xy_pos_t&) {}
  438. FORCE_INLINE void toLogical(xyz_pos_t&) {}
  439. FORCE_INLINE void toLogical(xyze_pos_t&) {}
  440. FORCE_INLINE void toNative(xy_pos_t&) {}
  441. FORCE_INLINE void toNative(xyz_pos_t&) {}
  442. FORCE_INLINE void toNative(xyze_pos_t&) {}
  443. #endif
  444. #define LOGICAL_X_POSITION(POS) NATIVE_TO_LOGICAL(POS, X_AXIS)
  445. #define RAW_X_POSITION(POS) LOGICAL_TO_NATIVE(POS, X_AXIS)
  446. #if HAS_Y_AXIS
  447. #define LOGICAL_Y_POSITION(POS) NATIVE_TO_LOGICAL(POS, Y_AXIS)
  448. #define RAW_Y_POSITION(POS) LOGICAL_TO_NATIVE(POS, Y_AXIS)
  449. #endif
  450. #if HAS_Z_AXIS
  451. #define LOGICAL_Z_POSITION(POS) NATIVE_TO_LOGICAL(POS, Z_AXIS)
  452. #define RAW_Z_POSITION(POS) LOGICAL_TO_NATIVE(POS, Z_AXIS)
  453. #endif
  454. #if HAS_I_AXIS
  455. #define LOGICAL_I_POSITION(POS) NATIVE_TO_LOGICAL(POS, I_AXIS)
  456. #define RAW_I_POSITION(POS) LOGICAL_TO_NATIVE(POS, I_AXIS)
  457. #endif
  458. #if HAS_J_AXIS
  459. #define LOGICAL_J_POSITION(POS) NATIVE_TO_LOGICAL(POS, J_AXIS)
  460. #define RAW_J_POSITION(POS) LOGICAL_TO_NATIVE(POS, J_AXIS)
  461. #endif
  462. #if HAS_K_AXIS
  463. #define LOGICAL_K_POSITION(POS) NATIVE_TO_LOGICAL(POS, K_AXIS)
  464. #define RAW_K_POSITION(POS) LOGICAL_TO_NATIVE(POS, K_AXIS)
  465. #endif
  466. #if HAS_U_AXIS
  467. #define LOGICAL_U_POSITION(POS) NATIVE_TO_LOGICAL(POS, U_AXIS)
  468. #define RAW_U_POSITION(POS) LOGICAL_TO_NATIVE(POS, U_AXIS)
  469. #endif
  470. #if HAS_V_AXIS
  471. #define LOGICAL_V_POSITION(POS) NATIVE_TO_LOGICAL(POS, V_AXIS)
  472. #define RAW_V_POSITION(POS) LOGICAL_TO_NATIVE(POS, V_AXIS)
  473. #endif
  474. #if HAS_W_AXIS
  475. #define LOGICAL_W_POSITION(POS) NATIVE_TO_LOGICAL(POS, W_AXIS)
  476. #define RAW_W_POSITION(POS) LOGICAL_TO_NATIVE(POS, W_AXIS)
  477. #endif
  478. /**
  479. * position_is_reachable family of functions
  480. */
  481. #if IS_KINEMATIC // (DELTA or SCARA)
  482. #if HAS_SCARA_OFFSET
  483. extern abc_pos_t scara_home_offset; // A and B angular offsets, Z mm offset
  484. #endif
  485. // Return true if the given point is within the printable area
  486. inline bool position_is_reachable(const_float_t rx, const_float_t ry, const float inset=0) {
  487. #if ENABLED(DELTA)
  488. return HYPOT2(rx, ry) <= sq(DELTA_PRINTABLE_RADIUS - inset + fslop);
  489. #elif ENABLED(POLARGRAPH)
  490. const float x1 = rx - (X_MIN_POS), x2 = (X_MAX_POS) - rx, y = ry - (Y_MAX_POS),
  491. a = HYPOT(x1, y), b = HYPOT(x2, y);
  492. return a < (POLARGRAPH_MAX_BELT_LEN) + 1
  493. && b < (POLARGRAPH_MAX_BELT_LEN) + 1
  494. && (a + b) > _MIN(X_BED_SIZE, Y_BED_SIZE);
  495. #elif ENABLED(AXEL_TPARA)
  496. const float R2 = HYPOT2(rx - TPARA_OFFSET_X, ry - TPARA_OFFSET_Y);
  497. return (
  498. R2 <= sq(L1 + L2) - inset
  499. #if MIDDLE_DEAD_ZONE_R > 0
  500. && R2 >= sq(float(MIDDLE_DEAD_ZONE_R))
  501. #endif
  502. );
  503. #elif IS_SCARA
  504. const float R2 = HYPOT2(rx - SCARA_OFFSET_X, ry - SCARA_OFFSET_Y);
  505. return (
  506. R2 <= sq(L1 + L2) - inset
  507. #if MIDDLE_DEAD_ZONE_R > 0
  508. && R2 >= sq(float(MIDDLE_DEAD_ZONE_R))
  509. #endif
  510. );
  511. #endif
  512. }
  513. inline bool position_is_reachable(const xy_pos_t &pos, const float inset=0) {
  514. return position_is_reachable(pos.x, pos.y, inset);
  515. }
  516. #else // CARTESIAN
  517. // Return true if the given position is within the machine bounds.
  518. inline bool position_is_reachable(const_float_t rx, const_float_t ry) {
  519. if (!COORDINATE_OKAY(ry, Y_MIN_POS - fslop, Y_MAX_POS + fslop)) return false;
  520. #if ENABLED(DUAL_X_CARRIAGE)
  521. if (active_extruder)
  522. return COORDINATE_OKAY(rx, X2_MIN_POS - fslop, X2_MAX_POS + fslop);
  523. else
  524. return COORDINATE_OKAY(rx, X1_MIN_POS - fslop, X1_MAX_POS + fslop);
  525. #else
  526. return COORDINATE_OKAY(rx, X_MIN_POS - fslop, X_MAX_POS + fslop);
  527. #endif
  528. }
  529. inline bool position_is_reachable(const xy_pos_t &pos) { return position_is_reachable(pos.x, pos.y); }
  530. #endif // CARTESIAN
  531. /**
  532. * Duplication mode
  533. */
  534. #if HAS_DUPLICATION_MODE
  535. extern bool extruder_duplication_enabled; // Used in Dual X mode 2
  536. #endif
  537. /**
  538. * Dual X Carriage
  539. */
  540. #if ENABLED(DUAL_X_CARRIAGE)
  541. enum DualXMode : char {
  542. DXC_FULL_CONTROL_MODE,
  543. DXC_AUTO_PARK_MODE,
  544. DXC_DUPLICATION_MODE,
  545. DXC_MIRRORED_MODE
  546. };
  547. extern DualXMode dual_x_carriage_mode;
  548. extern float inactive_extruder_x, // Used in mode 0 & 1
  549. duplicate_extruder_x_offset; // Used in mode 2 & 3
  550. extern xyz_pos_t raised_parked_position; // Used in mode 1
  551. extern bool active_extruder_parked; // Used in mode 1, 2 & 3
  552. extern millis_t delayed_move_time; // Used in mode 1
  553. extern celsius_t duplicate_extruder_temp_offset; // Used in mode 2 & 3
  554. extern bool idex_mirrored_mode; // Used in mode 3
  555. FORCE_INLINE bool idex_is_duplicating() { return dual_x_carriage_mode >= DXC_DUPLICATION_MODE; }
  556. float x_home_pos(const uint8_t extruder);
  557. #define TOOL_X_HOME_DIR(T) ((T) ? X2_HOME_DIR : X_HOME_DIR)
  558. void set_duplication_enabled(const bool dupe, const int8_t tool_index=-1);
  559. void idex_set_mirrored_mode(const bool mirr);
  560. void idex_set_parked(const bool park=true);
  561. #else
  562. #if ENABLED(MULTI_NOZZLE_DUPLICATION)
  563. extern uint8_t duplication_e_mask;
  564. enum DualXMode : char { DXC_DUPLICATION_MODE = 2 };
  565. FORCE_INLINE void set_duplication_enabled(const bool dupe) { extruder_duplication_enabled = dupe; }
  566. #endif
  567. #define TOOL_X_HOME_DIR(T) X_HOME_DIR
  568. #endif
  569. #if HAS_M206_COMMAND
  570. void set_home_offset(const AxisEnum axis, const float v);
  571. #endif
  572. #if USE_SENSORLESS
  573. struct sensorless_t;
  574. sensorless_t start_sensorless_homing_per_axis(const AxisEnum axis);
  575. void end_sensorless_homing_per_axis(const AxisEnum axis, sensorless_t enable_stealth);
  576. #endif