My Marlin configs for Fabrikator Mini and CTC i3 Pro B
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

menu_motion.cpp 12KB

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