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 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  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];
  41. extern xyz_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 abc_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;
  67. #if ENABLED(DELTA)
  68. v = homing_feedrate_mm_m.z;
  69. #else
  70. switch (a) {
  71. case X_AXIS: v = homing_feedrate_mm_m.x; break;
  72. case Y_AXIS: v = homing_feedrate_mm_m.y; break;
  73. case Z_AXIS:
  74. default: v = homing_feedrate_mm_m.z;
  75. }
  76. #endif
  77. return MMM_TO_MMS(v);
  78. }
  79. feedRate_t get_homing_bump_feedrate(const AxisEnum axis);
  80. /**
  81. * The default feedrate for many moves, set by the most recent move
  82. */
  83. extern feedRate_t feedrate_mm_s;
  84. /**
  85. * Feedrate scaling is applied to all G0/G1, G2/G3, and G5 moves
  86. */
  87. extern int16_t feedrate_percentage;
  88. #define MMS_SCALED(V) ((V) * 0.01f * feedrate_percentage)
  89. // The active extruder (tool). Set with T<extruder> command.
  90. #if HAS_MULTI_EXTRUDER
  91. extern uint8_t active_extruder;
  92. #else
  93. constexpr uint8_t active_extruder = 0;
  94. #endif
  95. #if ENABLED(LCD_SHOW_E_TOTAL)
  96. extern float e_move_accumulator;
  97. #endif
  98. #ifdef __IMXRT1062__
  99. #define DEFS_PROGMEM
  100. #else
  101. #define DEFS_PROGMEM PROGMEM
  102. #endif
  103. inline float pgm_read_any(const float *p) { return TERN(__IMXRT1062__, *p, pgm_read_float(p)); }
  104. inline int8_t pgm_read_any(const int8_t *p) { return TERN(__IMXRT1062__, *p, pgm_read_byte(p)); }
  105. #define XYZ_DEFS(T, NAME, OPT) \
  106. inline T NAME(const AxisEnum axis) { \
  107. static const XYZval<T> NAME##_P DEFS_PROGMEM = { X_##OPT, Y_##OPT, Z_##OPT }; \
  108. return pgm_read_any(&NAME##_P[axis]); \
  109. }
  110. XYZ_DEFS(float, base_min_pos, MIN_POS);
  111. XYZ_DEFS(float, base_max_pos, MAX_POS);
  112. XYZ_DEFS(float, base_home_pos, HOME_POS);
  113. XYZ_DEFS(float, max_length, MAX_LENGTH);
  114. XYZ_DEFS(int8_t, home_dir, HOME_DIR);
  115. inline float home_bump_mm(const AxisEnum axis) {
  116. static const xyz_pos_t home_bump_mm_P DEFS_PROGMEM = HOMING_BUMP_MM;
  117. return pgm_read_any(&home_bump_mm_P[axis]);
  118. }
  119. #if HAS_WORKSPACE_OFFSET
  120. void update_workspace_offset(const AxisEnum axis);
  121. #else
  122. inline void update_workspace_offset(const AxisEnum) {}
  123. #endif
  124. #if HAS_HOTEND_OFFSET
  125. extern xyz_pos_t hotend_offset[HOTENDS];
  126. void reset_hotend_offsets();
  127. #elif HOTENDS
  128. constexpr xyz_pos_t hotend_offset[HOTENDS] = { { 0 } };
  129. #else
  130. constexpr xyz_pos_t hotend_offset[1] = { { 0 } };
  131. #endif
  132. #if HAS_SOFTWARE_ENDSTOPS
  133. typedef struct {
  134. bool _enabled, _loose;
  135. bool enabled() { return _enabled && !_loose; }
  136. xyz_pos_t min, max;
  137. void get_manual_axis_limits(const AxisEnum axis, float &amin, float &amax) {
  138. amin = -100000; amax = 100000; // "No limits"
  139. #if HAS_SOFTWARE_ENDSTOPS
  140. if (enabled()) switch (axis) {
  141. case X_AXIS:
  142. TERN_(MIN_SOFTWARE_ENDSTOP_X, amin = min.x);
  143. TERN_(MAX_SOFTWARE_ENDSTOP_X, amax = max.x);
  144. break;
  145. case Y_AXIS:
  146. TERN_(MIN_SOFTWARE_ENDSTOP_Y, amin = min.y);
  147. TERN_(MAX_SOFTWARE_ENDSTOP_Y, amax = max.y);
  148. break;
  149. case Z_AXIS:
  150. TERN_(MIN_SOFTWARE_ENDSTOP_Z, amin = min.z);
  151. TERN_(MAX_SOFTWARE_ENDSTOP_Z, amax = max.z);
  152. default: break;
  153. }
  154. #endif
  155. }
  156. } soft_endstops_t;
  157. extern soft_endstops_t soft_endstop;
  158. void apply_motion_limits(xyz_pos_t &target);
  159. void update_software_endstops(const AxisEnum axis
  160. #if HAS_HOTEND_OFFSET
  161. , const uint8_t old_tool_index=0, const uint8_t new_tool_index=0
  162. #endif
  163. );
  164. #define SET_SOFT_ENDSTOP_LOOSE(loose) (soft_endstop._loose = loose)
  165. #else // !HAS_SOFTWARE_ENDSTOPS
  166. typedef struct {
  167. bool enabled() { return false; }
  168. void get_manual_axis_limits(const AxisEnum axis, float &amin, float &amax) {
  169. // No limits
  170. amin = current_position[axis] - 1000;
  171. amax = current_position[axis] + 1000;
  172. }
  173. } soft_endstops_t;
  174. extern soft_endstops_t soft_endstop;
  175. #define apply_motion_limits(V) NOOP
  176. #define update_software_endstops(...) NOOP
  177. #define SET_SOFT_ENDSTOP_LOOSE(V) NOOP
  178. #endif // !HAS_SOFTWARE_ENDSTOPS
  179. void report_real_position();
  180. void report_current_position();
  181. void report_current_position_projected();
  182. #if EITHER(FULL_REPORT_TO_HOST_FEATURE, REALTIME_REPORTING_COMMANDS)
  183. #define HAS_GRBL_STATE 1
  184. /**
  185. * Machine states for GRBL or TinyG
  186. */
  187. enum M_StateEnum : uint8_t {
  188. M_INIT = 0, // 0 machine is initializing
  189. M_RESET, // 1 machine is ready for use
  190. M_ALARM, // 2 machine is in alarm state (soft shut down)
  191. M_IDLE, // 3 program stop or no more blocks (M0, M1, M60)
  192. M_END, // 4 program end via M2, M30
  193. M_RUNNING, // 5 motion is running
  194. M_HOLD, // 6 motion is holding
  195. M_PROBE, // 7 probe cycle active
  196. M_CYCLING, // 8 machine is running (cycling)
  197. M_HOMING, // 9 machine is homing
  198. M_JOGGING, // 10 machine is jogging
  199. M_ERROR // 11 machine is in hard alarm state (shut down)
  200. };
  201. extern M_StateEnum M_State_grbl;
  202. M_StateEnum grbl_state_for_marlin_state();
  203. void report_current_grblstate_moving();
  204. void report_current_position_moving();
  205. #if ENABLED(FULL_REPORT_TO_HOST_FEATURE)
  206. inline void set_and_report_grblstate(const M_StateEnum state) {
  207. M_State_grbl = state;
  208. report_current_grblstate_moving();
  209. }
  210. #endif
  211. #if ENABLED(REALTIME_REPORTING_COMMANDS)
  212. void quickpause_stepper();
  213. void quickresume_stepper();
  214. #endif
  215. #endif
  216. void get_cartesian_from_steppers();
  217. void set_current_from_steppers_for_axis(const AxisEnum axis);
  218. void quickstop_stepper();
  219. /**
  220. * Set the planner/stepper positions directly from current_position with
  221. * no kinematic translation. Used for homing axes and cartesian/core syncing.
  222. */
  223. void sync_plan_position();
  224. void sync_plan_position_e();
  225. /**
  226. * Move the planner to the current position from wherever it last moved
  227. * (or from wherever it has been told it is located).
  228. */
  229. void line_to_current_position(const_feedRate_t fr_mm_s=feedrate_mm_s);
  230. #if EXTRUDERS
  231. void unscaled_e_move(const_float_t length, const_feedRate_t fr_mm_s);
  232. #endif
  233. void prepare_line_to_destination();
  234. void _internal_move_to_destination(const_feedRate_t fr_mm_s=0.0f
  235. #if IS_KINEMATIC
  236. , const bool is_fast=false
  237. #endif
  238. );
  239. inline void prepare_internal_move_to_destination(const_feedRate_t fr_mm_s=0.0f) {
  240. _internal_move_to_destination(fr_mm_s);
  241. }
  242. #if IS_KINEMATIC
  243. void prepare_fast_move_to_destination(const_feedRate_t scaled_fr_mm_s=MMS_SCALED(feedrate_mm_s));
  244. inline void prepare_internal_fast_move_to_destination(const_feedRate_t fr_mm_s=0.0f) {
  245. _internal_move_to_destination(fr_mm_s, true);
  246. }
  247. #endif
  248. /**
  249. * Blocking movement and shorthand functions
  250. */
  251. void do_blocking_move_to(const float rx, const float ry, const float rz, const_feedRate_t fr_mm_s=0.0f);
  252. void do_blocking_move_to(const xy_pos_t &raw, const_feedRate_t fr_mm_s=0.0f);
  253. void do_blocking_move_to(const xyz_pos_t &raw, const_feedRate_t fr_mm_s=0.0f);
  254. void do_blocking_move_to(const xyze_pos_t &raw, const_feedRate_t fr_mm_s=0.0f);
  255. void do_blocking_move_to_x(const_float_t rx, const_feedRate_t fr_mm_s=0.0f);
  256. void do_blocking_move_to_y(const_float_t ry, const_feedRate_t fr_mm_s=0.0f);
  257. void do_blocking_move_to_z(const_float_t rz, const_feedRate_t fr_mm_s=0.0f);
  258. void do_blocking_move_to_xy(const_float_t rx, const_float_t ry, const_feedRate_t fr_mm_s=0.0f);
  259. void do_blocking_move_to_xy(const xy_pos_t &raw, const_feedRate_t fr_mm_s=0.0f);
  260. 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); }
  261. 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); }
  262. void do_blocking_move_to_xy_z(const xy_pos_t &raw, const_float_t z, const_feedRate_t fr_mm_s=0.0f);
  263. 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); }
  264. 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); }
  265. void remember_feedrate_and_scaling();
  266. void remember_feedrate_scaling_off();
  267. void restore_feedrate_and_scaling();
  268. void do_z_clearance(const_float_t zclear, const bool lower_allowed=false);
  269. /**
  270. * Homing and Trusted Axes
  271. */
  272. constexpr uint8_t xyz_bits = _BV(X_AXIS) | _BV(Y_AXIS) | _BV(Z_AXIS);
  273. void set_axis_is_at_home(const AxisEnum axis);
  274. #if HAS_ENDSTOPS
  275. /**
  276. * axis_homed
  277. * Flags that each linear axis was homed.
  278. * XYZ on cartesian, ABC on delta, ABZ on SCARA.
  279. *
  280. * axis_trusted
  281. * Flags that the position is trusted in each linear axis. Set when homed.
  282. * Cleared whenever a stepper powers off, potentially losing its position.
  283. */
  284. extern uint8_t axis_homed, axis_trusted;
  285. void homeaxis(const AxisEnum axis);
  286. void set_axis_never_homed(const AxisEnum axis);
  287. uint8_t axes_should_home(uint8_t axis_bits=0x07);
  288. bool homing_needed_error(uint8_t axis_bits=0x07);
  289. FORCE_INLINE void set_axis_unhomed(const AxisEnum axis) { CBI(axis_homed, axis); }
  290. FORCE_INLINE void set_axis_untrusted(const AxisEnum axis) { CBI(axis_trusted, axis); }
  291. FORCE_INLINE void set_all_unhomed() { axis_homed = axis_trusted = 0; }
  292. FORCE_INLINE void set_axis_homed(const AxisEnum axis) { SBI(axis_homed, axis); }
  293. FORCE_INLINE void set_axis_trusted(const AxisEnum axis) { SBI(axis_trusted, axis); }
  294. FORCE_INLINE void set_all_homed() { axis_homed = axis_trusted = xyz_bits; }
  295. #else
  296. constexpr uint8_t axis_homed = xyz_bits, axis_trusted = xyz_bits; // Zero-endstop machines are always homed and trusted
  297. FORCE_INLINE void homeaxis(const AxisEnum axis) {}
  298. FORCE_INLINE void set_axis_never_homed(const AxisEnum) {}
  299. FORCE_INLINE uint8_t axes_should_home(uint8_t=0x07) { return false; }
  300. FORCE_INLINE bool homing_needed_error(uint8_t=0x07) { return false; }
  301. FORCE_INLINE void set_axis_unhomed(const AxisEnum axis) {}
  302. FORCE_INLINE void set_axis_untrusted(const AxisEnum axis) {}
  303. FORCE_INLINE void set_all_unhomed() {}
  304. FORCE_INLINE void set_axis_homed(const AxisEnum axis) {}
  305. FORCE_INLINE void set_axis_trusted(const AxisEnum axis) {}
  306. FORCE_INLINE void set_all_homed() {}
  307. #endif
  308. FORCE_INLINE bool axis_was_homed(const AxisEnum axis) { return TEST(axis_homed, axis); }
  309. FORCE_INLINE bool axis_is_trusted(const AxisEnum axis) { return TEST(axis_trusted, axis); }
  310. FORCE_INLINE bool axis_should_home(const AxisEnum axis) { return (axes_should_home() & _BV(axis)) != 0; }
  311. FORCE_INLINE bool no_axes_homed() { return !axis_homed; }
  312. FORCE_INLINE bool all_axes_homed() { return xyz_bits == (axis_homed & xyz_bits); }
  313. FORCE_INLINE bool homing_needed() { return !all_axes_homed(); }
  314. FORCE_INLINE bool all_axes_trusted() { return xyz_bits == (axis_trusted & xyz_bits); }
  315. #if ENABLED(NO_MOTION_BEFORE_HOMING)
  316. #define MOTION_CONDITIONS (IsRunning() && !homing_needed_error())
  317. #else
  318. #define MOTION_CONDITIONS IsRunning()
  319. #endif
  320. #define BABYSTEP_ALLOWED() ((ENABLED(BABYSTEP_WITHOUT_HOMING) || all_axes_trusted()) && (ENABLED(BABYSTEP_ALWAYS_AVAILABLE) || printer_busy()))
  321. /**
  322. * Workspace offsets
  323. */
  324. #if HAS_HOME_OFFSET || HAS_POSITION_SHIFT
  325. #if HAS_HOME_OFFSET
  326. extern xyz_pos_t home_offset;
  327. #endif
  328. #if HAS_POSITION_SHIFT
  329. extern xyz_pos_t position_shift;
  330. #endif
  331. #if HAS_HOME_OFFSET && HAS_POSITION_SHIFT
  332. extern xyz_pos_t workspace_offset;
  333. #define _WS workspace_offset
  334. #elif HAS_HOME_OFFSET
  335. #define _WS home_offset
  336. #else
  337. #define _WS position_shift
  338. #endif
  339. #define NATIVE_TO_LOGICAL(POS, AXIS) ((POS) + _WS[AXIS])
  340. #define LOGICAL_TO_NATIVE(POS, AXIS) ((POS) - _WS[AXIS])
  341. FORCE_INLINE void toLogical(xy_pos_t &raw) { raw += _WS; }
  342. FORCE_INLINE void toLogical(xyz_pos_t &raw) { raw += _WS; }
  343. FORCE_INLINE void toLogical(xyze_pos_t &raw) { raw += _WS; }
  344. FORCE_INLINE void toNative(xy_pos_t &raw) { raw -= _WS; }
  345. FORCE_INLINE void toNative(xyz_pos_t &raw) { raw -= _WS; }
  346. FORCE_INLINE void toNative(xyze_pos_t &raw) { raw -= _WS; }
  347. #else
  348. #define NATIVE_TO_LOGICAL(POS, AXIS) (POS)
  349. #define LOGICAL_TO_NATIVE(POS, AXIS) (POS)
  350. FORCE_INLINE void toLogical(xy_pos_t&) {}
  351. FORCE_INLINE void toLogical(xyz_pos_t&) {}
  352. FORCE_INLINE void toLogical(xyze_pos_t&) {}
  353. FORCE_INLINE void toNative(xy_pos_t&) {}
  354. FORCE_INLINE void toNative(xyz_pos_t&) {}
  355. FORCE_INLINE void toNative(xyze_pos_t&) {}
  356. #endif
  357. #define LOGICAL_X_POSITION(POS) NATIVE_TO_LOGICAL(POS, X_AXIS)
  358. #define LOGICAL_Y_POSITION(POS) NATIVE_TO_LOGICAL(POS, Y_AXIS)
  359. #define LOGICAL_Z_POSITION(POS) NATIVE_TO_LOGICAL(POS, Z_AXIS)
  360. #define RAW_X_POSITION(POS) LOGICAL_TO_NATIVE(POS, X_AXIS)
  361. #define RAW_Y_POSITION(POS) LOGICAL_TO_NATIVE(POS, Y_AXIS)
  362. #define RAW_Z_POSITION(POS) LOGICAL_TO_NATIVE(POS, Z_AXIS)
  363. /**
  364. * position_is_reachable family of functions
  365. */
  366. #if IS_KINEMATIC // (DELTA or SCARA)
  367. #if HAS_SCARA_OFFSET
  368. extern abc_pos_t scara_home_offset; // A and B angular offsets, Z mm offset
  369. #endif
  370. // Return true if the given point is within the printable area
  371. inline bool position_is_reachable(const_float_t rx, const_float_t ry, const float inset=0) {
  372. #if ENABLED(DELTA)
  373. return HYPOT2(rx, ry) <= sq(DELTA_PRINTABLE_RADIUS - inset + fslop);
  374. #elif ENABLED(AXEL_TPARA)
  375. const float R2 = HYPOT2(rx - TPARA_OFFSET_X, ry - TPARA_OFFSET_Y);
  376. return (
  377. R2 <= sq(L1 + L2) - inset
  378. #if MIDDLE_DEAD_ZONE_R > 0
  379. && R2 >= sq(float(MIDDLE_DEAD_ZONE_R))
  380. #endif
  381. );
  382. #elif IS_SCARA
  383. const float R2 = HYPOT2(rx - SCARA_OFFSET_X, ry - SCARA_OFFSET_Y);
  384. return (
  385. R2 <= sq(L1 + L2) - inset
  386. #if MIDDLE_DEAD_ZONE_R > 0
  387. && R2 >= sq(float(MIDDLE_DEAD_ZONE_R))
  388. #endif
  389. );
  390. #endif
  391. }
  392. inline bool position_is_reachable(const xy_pos_t &pos, const float inset=0) {
  393. return position_is_reachable(pos.x, pos.y, inset);
  394. }
  395. #else // CARTESIAN
  396. // Return true if the given position is within the machine bounds.
  397. inline bool position_is_reachable(const_float_t rx, const_float_t ry) {
  398. if (!COORDINATE_OKAY(ry, Y_MIN_POS - fslop, Y_MAX_POS + fslop)) return false;
  399. #if ENABLED(DUAL_X_CARRIAGE)
  400. if (active_extruder)
  401. return COORDINATE_OKAY(rx, X2_MIN_POS - fslop, X2_MAX_POS + fslop);
  402. else
  403. return COORDINATE_OKAY(rx, X1_MIN_POS - fslop, X1_MAX_POS + fslop);
  404. #else
  405. return COORDINATE_OKAY(rx, X_MIN_POS - fslop, X_MAX_POS + fslop);
  406. #endif
  407. }
  408. inline bool position_is_reachable(const xy_pos_t &pos) { return position_is_reachable(pos.x, pos.y); }
  409. #endif // CARTESIAN
  410. /**
  411. * Duplication mode
  412. */
  413. #if HAS_DUPLICATION_MODE
  414. extern bool extruder_duplication_enabled; // Used in Dual X mode 2
  415. #endif
  416. /**
  417. * Dual X Carriage
  418. */
  419. #if ENABLED(DUAL_X_CARRIAGE)
  420. enum DualXMode : char {
  421. DXC_FULL_CONTROL_MODE,
  422. DXC_AUTO_PARK_MODE,
  423. DXC_DUPLICATION_MODE,
  424. DXC_MIRRORED_MODE
  425. };
  426. extern DualXMode dual_x_carriage_mode;
  427. extern float inactive_extruder_x, // Used in mode 0 & 1
  428. duplicate_extruder_x_offset; // Used in mode 2 & 3
  429. extern xyz_pos_t raised_parked_position; // Used in mode 1
  430. extern bool active_extruder_parked; // Used in mode 1, 2 & 3
  431. extern millis_t delayed_move_time; // Used in mode 1
  432. extern celsius_t duplicate_extruder_temp_offset; // Used in mode 2 & 3
  433. extern bool idex_mirrored_mode; // Used in mode 3
  434. FORCE_INLINE bool idex_is_duplicating() { return dual_x_carriage_mode >= DXC_DUPLICATION_MODE; }
  435. float x_home_pos(const uint8_t extruder);
  436. FORCE_INLINE int x_home_dir(const uint8_t extruder) { return extruder ? X2_HOME_DIR : X_HOME_DIR; }
  437. void set_duplication_enabled(const bool dupe, const int8_t tool_index=-1);
  438. void idex_set_mirrored_mode(const bool mirr);
  439. void idex_set_parked(const bool park=true);
  440. #else
  441. #if ENABLED(MULTI_NOZZLE_DUPLICATION)
  442. extern uint8_t duplication_e_mask;
  443. enum DualXMode : char { DXC_DUPLICATION_MODE = 2 };
  444. FORCE_INLINE void set_duplication_enabled(const bool dupe) { extruder_duplication_enabled = dupe; }
  445. #endif
  446. FORCE_INLINE int x_home_dir(const uint8_t) { return X_HOME_DIR; }
  447. #endif
  448. #if HAS_M206_COMMAND
  449. void set_home_offset(const AxisEnum axis, const float v);
  450. #endif
  451. #if USE_SENSORLESS
  452. struct sensorless_t;
  453. sensorless_t start_sensorless_homing_per_axis(const AxisEnum axis);
  454. void end_sensorless_homing_per_axis(const AxisEnum axis, sensorless_t enable_stealth);
  455. #endif