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

menu_motion.cpp 12KB

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