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.

menu_motion.cpp 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  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 <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. //
  23. // Motion Menu
  24. //
  25. #include "../../inc/MarlinConfigPre.h"
  26. #if HAS_LCD_MENU
  27. #include "menu.h"
  28. #include "menu_addon.h"
  29. #include "../../module/motion.h"
  30. #if ENABLED(DELTA)
  31. #include "../../module/delta.h"
  32. #endif
  33. #if ENABLED(PREVENT_COLD_EXTRUSION)
  34. #include "../../module/temperature.h"
  35. #endif
  36. #if HAS_LEVELING
  37. #include "../../module/planner.h"
  38. #include "../../feature/bedlevel/bedlevel.h"
  39. #endif
  40. extern millis_t manual_move_start_time;
  41. extern int8_t manual_move_axis;
  42. #if ENABLED(MANUAL_E_MOVES_RELATIVE)
  43. float manual_move_e_origin = 0;
  44. #endif
  45. #if IS_KINEMATIC
  46. extern float manual_move_offset;
  47. #endif
  48. //
  49. // Tell ui.update() to start a move to current_position" after a short delay.
  50. //
  51. inline void manual_move_to_current(AxisEnum axis
  52. #if E_MANUAL > 1
  53. , const int8_t eindex=-1
  54. #endif
  55. ) {
  56. #if E_MANUAL > 1
  57. if (axis == E_AXIS) ui.manual_move_e_index = eindex >= 0 ? eindex : active_extruder;
  58. #endif
  59. manual_move_start_time = millis() + (move_menu_scale < 0.99f ? 0UL : 250UL); // delay for bigger moves
  60. manual_move_axis = (int8_t)axis;
  61. }
  62. //
  63. // "Motion" > "Move Axis" submenu
  64. //
  65. static void _lcd_move_xyz(PGM_P const name, const AxisEnum axis) {
  66. if (ui.use_click()) return ui.goto_previous_screen_no_defer();
  67. if (ui.encoderPosition && !ui.processing_manual_move) {
  68. // Start with no limits to movement
  69. float min = current_position[axis] - 1000,
  70. max = current_position[axis] + 1000;
  71. // Limit to software endstops, if enabled
  72. #if HAS_SOFTWARE_ENDSTOPS
  73. if (soft_endstops_enabled) switch (axis) {
  74. case X_AXIS:
  75. #if ENABLED(MIN_SOFTWARE_ENDSTOP_X)
  76. min = soft_endstop.min.x;
  77. #endif
  78. #if ENABLED(MAX_SOFTWARE_ENDSTOP_X)
  79. max = soft_endstop.max.x;
  80. #endif
  81. break;
  82. case Y_AXIS:
  83. #if ENABLED(MIN_SOFTWARE_ENDSTOP_Y)
  84. min = soft_endstop.min.y;
  85. #endif
  86. #if ENABLED(MAX_SOFTWARE_ENDSTOP_Y)
  87. max = soft_endstop.max.y;
  88. #endif
  89. break;
  90. case Z_AXIS:
  91. #if ENABLED(MIN_SOFTWARE_ENDSTOP_Z)
  92. min = soft_endstop.min.z;
  93. #endif
  94. #if ENABLED(MAX_SOFTWARE_ENDSTOP_Z)
  95. max = soft_endstop.max.z;
  96. #endif
  97. default: break;
  98. }
  99. #endif // HAS_SOFTWARE_ENDSTOPS
  100. // Delta limits XY based on the current offset from center
  101. // This assumes the center is 0,0
  102. #if ENABLED(DELTA)
  103. if (axis != Z_AXIS) {
  104. max = SQRT(sq((float)(DELTA_PRINTABLE_RADIUS)) - sq(current_position[Y_AXIS - axis])); // (Y_AXIS - axis) == the other axis
  105. min = -max;
  106. }
  107. #endif
  108. // Get the new position
  109. const float diff = float(int32_t(ui.encoderPosition)) * move_menu_scale;
  110. #if IS_KINEMATIC
  111. manual_move_offset += diff;
  112. if (int32_t(ui.encoderPosition) < 0)
  113. NOLESS(manual_move_offset, min - current_position[axis]);
  114. else
  115. NOMORE(manual_move_offset, max - current_position[axis]);
  116. #else
  117. current_position[axis] += diff;
  118. if (int32_t(ui.encoderPosition) < 0)
  119. NOLESS(current_position[axis], min);
  120. else
  121. NOMORE(current_position[axis], max);
  122. #endif
  123. manual_move_to_current(axis);
  124. ui.refresh(LCDVIEW_REDRAW_NOW);
  125. }
  126. ui.encoderPosition = 0;
  127. if (ui.should_draw()) {
  128. const float pos = NATIVE_TO_LOGICAL(ui.processing_manual_move ? destination[axis] : current_position[axis]
  129. #if IS_KINEMATIC
  130. + manual_move_offset
  131. #endif
  132. , axis);
  133. MenuEditItemBase::draw_edit_screen(name, move_menu_scale >= 0.1f ? ftostr41sign(pos) : ftostr43sign(pos));
  134. }
  135. }
  136. void lcd_move_x() { _lcd_move_xyz(GET_TEXT(MSG_MOVE_X), X_AXIS); }
  137. void lcd_move_y() { _lcd_move_xyz(GET_TEXT(MSG_MOVE_Y), Y_AXIS); }
  138. void lcd_move_z() { _lcd_move_xyz(GET_TEXT(MSG_MOVE_Z), Z_AXIS); }
  139. #if E_MANUAL
  140. static void lcd_move_e(
  141. #if E_MANUAL > 1
  142. const int8_t eindex=-1
  143. #endif
  144. ) {
  145. if (ui.use_click()) return ui.goto_previous_screen_no_defer();
  146. if (ui.encoderPosition) {
  147. if (!ui.processing_manual_move) {
  148. const float diff = float(int32_t(ui.encoderPosition)) * move_menu_scale;
  149. #if IS_KINEMATIC
  150. manual_move_offset += diff;
  151. #else
  152. current_position.e += diff;
  153. #endif
  154. manual_move_to_current(E_AXIS
  155. #if E_MANUAL > 1
  156. , eindex
  157. #endif
  158. );
  159. ui.refresh(LCDVIEW_REDRAW_NOW);
  160. }
  161. ui.encoderPosition = 0;
  162. }
  163. if (ui.should_draw()) {
  164. #if E_MANUAL > 1
  165. MenuItemBase::init(eindex);
  166. #endif
  167. MenuEditItemBase::draw_edit_screen(
  168. GET_TEXT(
  169. #if E_MANUAL > 1
  170. MSG_MOVE_EN
  171. #else
  172. MSG_MOVE_E
  173. #endif
  174. ),
  175. ftostr41sign(current_position.e
  176. #if IS_KINEMATIC
  177. + manual_move_offset
  178. #endif
  179. #if ENABLED(MANUAL_E_MOVES_RELATIVE)
  180. - manual_move_e_origin
  181. #endif
  182. )
  183. );
  184. } // should_draw
  185. }
  186. #endif // E_MANUAL
  187. //
  188. // "Motion" > "Move Xmm" > "Move XYZ" submenu
  189. //
  190. #ifndef SHORT_MANUAL_Z_MOVE
  191. #define SHORT_MANUAL_Z_MOVE 0.025
  192. #endif
  193. screenFunc_t _manual_move_func_ptr;
  194. void _goto_manual_move(const float scale) {
  195. ui.defer_status_screen();
  196. move_menu_scale = scale;
  197. ui.goto_screen(_manual_move_func_ptr);
  198. }
  199. void _menu_move_distance(const AxisEnum axis, const screenFunc_t func, const int8_t eindex=-1) {
  200. _manual_move_func_ptr = func;
  201. START_MENU();
  202. if (LCD_HEIGHT >= 4) {
  203. switch (axis) {
  204. case X_AXIS: STATIC_ITEM(MSG_MOVE_X, SS_CENTER|SS_INVERT); break;
  205. case Y_AXIS: STATIC_ITEM(MSG_MOVE_Y, SS_CENTER|SS_INVERT); break;
  206. case Z_AXIS: STATIC_ITEM(MSG_MOVE_Z, SS_CENTER|SS_INVERT); break;
  207. default:
  208. #if ENABLED(MANUAL_E_MOVES_RELATIVE)
  209. manual_move_e_origin = current_position.e;
  210. #endif
  211. STATIC_ITEM(MSG_MOVE_E, SS_CENTER|SS_INVERT);
  212. break;
  213. }
  214. }
  215. #if ENABLED(PREVENT_COLD_EXTRUSION)
  216. if (axis == E_AXIS && thermalManager.tooColdToExtrude(eindex >= 0 ? eindex : active_extruder))
  217. BACK_ITEM(MSG_HOTEND_TOO_COLD);
  218. else
  219. #endif
  220. {
  221. BACK_ITEM(MSG_MOVE_AXIS);
  222. SUBMENU(MSG_MOVE_10MM, []{ _goto_manual_move(10); });
  223. SUBMENU(MSG_MOVE_1MM, []{ _goto_manual_move( 1); });
  224. SUBMENU(MSG_MOVE_01MM, []{ _goto_manual_move( 0.1f); });
  225. if (axis == Z_AXIS && (SHORT_MANUAL_Z_MOVE) > 0.0f && (SHORT_MANUAL_Z_MOVE) < 0.1f) {
  226. extern const char NUL_STR[];
  227. SUBMENU_P(NUL_STR, []{ _goto_manual_move(float(SHORT_MANUAL_Z_MOVE)); });
  228. MENU_ITEM_ADDON_START(0
  229. #if HAS_CHARACTER_LCD
  230. + 1
  231. #endif
  232. );
  233. char tmp[20], numstr[10];
  234. // Determine digits needed right of decimal
  235. const uint8_t digs = !UNEAR_ZERO((SHORT_MANUAL_Z_MOVE) * 1000 - int((SHORT_MANUAL_Z_MOVE) * 1000)) ? 4 :
  236. !UNEAR_ZERO((SHORT_MANUAL_Z_MOVE) * 100 - int((SHORT_MANUAL_Z_MOVE) * 100)) ? 3 : 2;
  237. sprintf_P(tmp, GET_TEXT(MSG_MOVE_Z_DIST), dtostrf(SHORT_MANUAL_Z_MOVE, 1, digs, numstr));
  238. lcd_put_u8str(tmp);
  239. MENU_ITEM_ADDON_END();
  240. }
  241. }
  242. END_MENU();
  243. }
  244. void menu_move() {
  245. START_MENU();
  246. BACK_ITEM(MSG_MOTION);
  247. #if HAS_SOFTWARE_ENDSTOPS && ENABLED(SOFT_ENDSTOPS_MENU_ITEM)
  248. EDIT_ITEM(bool, MSG_LCD_SOFT_ENDSTOPS, &soft_endstops_enabled);
  249. #endif
  250. if (
  251. #if IS_KINEMATIC || ENABLED(NO_MOTION_BEFORE_HOMING)
  252. all_axes_homed()
  253. #else
  254. true
  255. #endif
  256. ) {
  257. if (
  258. #if ENABLED(DELTA)
  259. current_position.z <= delta_clip_start_height
  260. #else
  261. true
  262. #endif
  263. ) {
  264. SUBMENU(MSG_MOVE_X, []{ _menu_move_distance(X_AXIS, lcd_move_x); });
  265. SUBMENU(MSG_MOVE_Y, []{ _menu_move_distance(Y_AXIS, lcd_move_y); });
  266. }
  267. #if ENABLED(DELTA)
  268. else
  269. ACTION_ITEM(MSG_FREE_XY, []{ line_to_z(delta_clip_start_height); ui.synchronize(); });
  270. #endif
  271. SUBMENU(MSG_MOVE_Z, []{ _menu_move_distance(Z_AXIS, lcd_move_z); });
  272. }
  273. else
  274. GCODES_ITEM(MSG_AUTO_HOME, G28_STR);
  275. #if ANY(SWITCHING_EXTRUDER, SWITCHING_NOZZLE, MAGNETIC_SWITCHING_TOOLHEAD)
  276. #if EXTRUDERS >= 4
  277. switch (active_extruder) {
  278. case 0: GCODES_ITEM_N(1, MSG_SELECT_E, PSTR("T1")); break;
  279. case 1: GCODES_ITEM_N(0, MSG_SELECT_E, PSTR("T0")); break;
  280. case 2: GCODES_ITEM_N(3, MSG_SELECT_E, PSTR("T3")); break;
  281. case 3: GCODES_ITEM_N(2, MSG_SELECT_E, PSTR("T2")); break;
  282. #if EXTRUDERS == 6
  283. case 4: GCODES_ITEM_N(5, MSG_SELECT_E, PSTR("T5")); break;
  284. case 5: GCODES_ITEM_N(4, MSG_SELECT_E, PSTR("T4")); break;
  285. #endif
  286. }
  287. #elif EXTRUDERS == 3
  288. if (active_extruder < 2) {
  289. if (active_extruder)
  290. GCODES_ITEM_N(0, MSG_SELECT_E, PSTR("T0"));
  291. else
  292. GCODES_ITEM_N(1, MSG_SELECT_E, PSTR("T1"));
  293. }
  294. #else
  295. if (active_extruder)
  296. GCODES_ITEM_N(0, MSG_SELECT_E, PSTR("T0"));
  297. else
  298. GCODES_ITEM_N(1, MSG_SELECT_E, PSTR("T1"));
  299. #endif
  300. #elif ENABLED(DUAL_X_CARRIAGE)
  301. if (active_extruder)
  302. GCODES_ITEM_N(0, MSG_SELECT_E, PSTR("T0"));
  303. else
  304. GCODES_ITEM_N(1, MSG_SELECT_E, PSTR("T1"));
  305. #endif
  306. #if E_MANUAL
  307. // The current extruder
  308. SUBMENU(MSG_MOVE_E, []{ _menu_move_distance(E_AXIS, []{ lcd_move_e(); }, -1); });
  309. #define SUBMENU_MOVE_E(N) SUBMENU_N(N, MSG_MOVE_EN, []{ _menu_move_distance(E_AXIS, []{ lcd_move_e(MenuItemBase::itemIndex); }, MenuItemBase::itemIndex); });
  310. #if EITHER(SWITCHING_EXTRUDER, SWITCHING_NOZZLE)
  311. // ...and the non-switching
  312. #if E_MANUAL == 5
  313. SUBMENU_MOVE_E(4);
  314. #elif E_MANUAL == 3
  315. SUBMENU_MOVE_E(2);
  316. #endif
  317. #elif E_MANUAL > 1
  318. // Independent extruders with one E-stepper per hotend
  319. for (uint8_t n = 0; n < E_MANUAL; n++) SUBMENU_MOVE_E(n);
  320. #endif
  321. #endif // E_MANUAL
  322. END_MENU();
  323. }
  324. #if ENABLED(AUTO_BED_LEVELING_UBL)
  325. void _lcd_ubl_level_bed();
  326. #elif ENABLED(LCD_BED_LEVELING)
  327. void menu_bed_leveling();
  328. #endif
  329. void menu_motion() {
  330. START_MENU();
  331. //
  332. // ^ Main
  333. //
  334. BACK_ITEM(MSG_MAIN);
  335. //
  336. // Move Axis
  337. //
  338. #if ENABLED(DELTA)
  339. if (all_axes_homed())
  340. #endif
  341. SUBMENU(MSG_MOVE_AXIS, menu_move);
  342. //
  343. // Auto Home
  344. //
  345. GCODES_ITEM(MSG_AUTO_HOME, G28_STR);
  346. #if ENABLED(INDIVIDUAL_AXIS_HOMING_MENU)
  347. GCODES_ITEM(MSG_AUTO_HOME_X, PSTR("G28X"));
  348. GCODES_ITEM(MSG_AUTO_HOME_Y, PSTR("G28Y"));
  349. GCODES_ITEM(MSG_AUTO_HOME_Z, PSTR("G28Z"));
  350. #endif
  351. //
  352. // Auto Z-Align
  353. //
  354. #if ENABLED(Z_STEPPER_AUTO_ALIGN)
  355. GCODES_ITEM(MSG_AUTO_Z_ALIGN, PSTR("G34"));
  356. #endif
  357. //
  358. // Level Bed
  359. //
  360. #if ENABLED(AUTO_BED_LEVELING_UBL)
  361. SUBMENU(MSG_UBL_LEVEL_BED, _lcd_ubl_level_bed);
  362. #elif ENABLED(LCD_BED_LEVELING)
  363. if (!g29_in_progress) SUBMENU(MSG_BED_LEVELING, menu_bed_leveling);
  364. #elif HAS_LEVELING && DISABLED(SLIM_LCD_MENUS)
  365. #if DISABLED(PROBE_MANUALLY)
  366. GCODES_ITEM(MSG_LEVEL_BED, PSTR("G28\nG29"));
  367. #endif
  368. if (all_axes_homed() && leveling_is_valid()) {
  369. bool show_state = planner.leveling_active;
  370. EDIT_ITEM(bool, MSG_BED_LEVELING, &show_state, _lcd_toggle_bed_leveling);
  371. }
  372. #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
  373. editable.decimal = planner.z_fade_height;
  374. EDIT_ITEM_FAST(float3, MSG_Z_FADE_HEIGHT, &editable.decimal, 0, 100, []{ set_z_fade_height(editable.decimal); });
  375. #endif
  376. #endif
  377. #if ENABLED(LEVEL_BED_CORNERS) && DISABLED(LCD_BED_LEVELING)
  378. ACTION_ITEM(MSG_LEVEL_CORNERS, _lcd_level_bed_corners);
  379. #endif
  380. #if ENABLED(Z_MIN_PROBE_REPEATABILITY_TEST)
  381. GCODES_ITEM(MSG_M48_TEST, PSTR("G28\nM48 P10"));
  382. #endif
  383. //
  384. // Disable Steppers
  385. //
  386. GCODES_ITEM(MSG_DISABLE_STEPPERS, PSTR("M84"));
  387. END_MENU();
  388. }
  389. #endif // HAS_LCD_MENU