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.

M200-M205.cpp 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  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. #include "../gcode.h"
  23. #include "../../MarlinCore.h"
  24. #include "../../module/planner.h"
  25. #if DISABLED(NO_VOLUMETRICS)
  26. /**
  27. * M200: Set filament diameter and set E axis units to cubic units
  28. *
  29. * T<extruder> - Optional extruder number. Current extruder if omitted.
  30. * D<linear> - Set filament diameter and enable. D0 disables volumetric.
  31. * S<bool> - Turn volumetric ON or OFF.
  32. *
  33. * With VOLUMETRIC_EXTRUDER_LIMIT:
  34. *
  35. * L<float> - Volumetric extruder limit (in mm^3/sec). L0 disables the limit.
  36. */
  37. void GcodeSuite::M200() {
  38. if (!parser.seen("DST" TERN_(VOLUMETRIC_EXTRUDER_LIMIT, "L")))
  39. return M200_report();
  40. const int8_t target_extruder = get_target_extruder_from_command();
  41. if (target_extruder < 0) return;
  42. bool vol_enable = parser.volumetric_enabled,
  43. can_enable = true;
  44. if (parser.seenval('D')) {
  45. const float dval = parser.value_linear_units();
  46. if (dval) { // Set filament size for volumetric calculation
  47. planner.set_filament_size(target_extruder, dval);
  48. vol_enable = true; // Dn = enable for compatibility
  49. }
  50. else
  51. can_enable = false; // D0 = disable for compatibility
  52. }
  53. // Enable or disable with S1 / S0
  54. parser.volumetric_enabled = can_enable && parser.boolval('S', vol_enable);
  55. #if ENABLED(VOLUMETRIC_EXTRUDER_LIMIT)
  56. if (parser.seenval('L')) {
  57. // Set volumetric limit (in mm^3/sec)
  58. const float lval = parser.value_float();
  59. if (WITHIN(lval, 0, 20))
  60. planner.set_volumetric_extruder_limit(target_extruder, lval);
  61. else
  62. SERIAL_ECHOLNPGM("?L value out of range (0-20).");
  63. }
  64. #endif
  65. planner.calculate_volumetric_multipliers();
  66. }
  67. void GcodeSuite::M200_report(const bool forReplay/*=true*/) {
  68. if (!forReplay) {
  69. report_heading(forReplay, F(STR_FILAMENT_SETTINGS), false);
  70. if (!parser.volumetric_enabled) SERIAL_ECHOPGM(" (Disabled):");
  71. SERIAL_EOL();
  72. report_echo_start(forReplay);
  73. }
  74. #if EXTRUDERS == 1
  75. {
  76. SERIAL_ECHOLNPGM(
  77. " M200 S", parser.volumetric_enabled, " D", LINEAR_UNIT(planner.filament_size[0])
  78. #if ENABLED(VOLUMETRIC_EXTRUDER_LIMIT)
  79. , " L", LINEAR_UNIT(planner.volumetric_extruder_limit[0])
  80. #endif
  81. );
  82. }
  83. #else
  84. SERIAL_ECHOLNPGM(" M200 S", parser.volumetric_enabled);
  85. EXTRUDER_LOOP() {
  86. report_echo_start(forReplay);
  87. SERIAL_ECHOLNPGM(
  88. " M200 T", e, " D", LINEAR_UNIT(planner.filament_size[e])
  89. #if ENABLED(VOLUMETRIC_EXTRUDER_LIMIT)
  90. , " L", LINEAR_UNIT(planner.volumetric_extruder_limit[e])
  91. #endif
  92. );
  93. }
  94. #endif
  95. }
  96. #endif // !NO_VOLUMETRICS
  97. /**
  98. * M201: Set max acceleration in units/s^2 for print moves (M201 X1000 Y1000)
  99. *
  100. * With multiple extruders use T to specify which one.
  101. */
  102. void GcodeSuite::M201() {
  103. if (!parser.seen("T" LOGICAL_AXES_STRING))
  104. return M201_report();
  105. const int8_t target_extruder = get_target_extruder_from_command();
  106. if (target_extruder < 0) return;
  107. #ifdef XY_FREQUENCY_LIMIT
  108. if (parser.seenval('F')) planner.set_frequency_limit(parser.value_byte());
  109. if (parser.seenval('G')) planner.xy_freq_min_speed_factor = constrain(parser.value_float(), 1, 100) / 100;
  110. #endif
  111. LOOP_LOGICAL_AXES(i) {
  112. if (parser.seenval(axis_codes[i])) {
  113. const uint8_t a = TERN(HAS_EXTRUDERS, (i == E_AXIS ? uint8_t(E_AXIS_N(target_extruder)) : i), i);
  114. planner.set_max_acceleration(a, parser.value_axis_units((AxisEnum)a));
  115. }
  116. }
  117. }
  118. void GcodeSuite::M201_report(const bool forReplay/*=true*/) {
  119. report_heading_etc(forReplay, F(STR_MAX_ACCELERATION));
  120. SERIAL_ECHOLNPGM_P(
  121. LIST_N(DOUBLE(NUM_AXES),
  122. PSTR(" M201 X"), LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[X_AXIS]),
  123. SP_Y_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Y_AXIS]),
  124. SP_Z_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Z_AXIS]),
  125. SP_I_STR, I_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[I_AXIS]),
  126. SP_J_STR, J_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[J_AXIS]),
  127. SP_K_STR, K_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[K_AXIS]),
  128. SP_U_STR, U_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[U_AXIS]),
  129. SP_V_STR, V_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[V_AXIS]),
  130. SP_W_STR, W_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[W_AXIS])
  131. )
  132. #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)
  133. , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_acceleration_mm_per_s2[E_AXIS])
  134. #endif
  135. );
  136. #if ENABLED(DISTINCT_E_FACTORS)
  137. LOOP_L_N(i, E_STEPPERS) {
  138. report_echo_start(forReplay);
  139. SERIAL_ECHOLNPGM_P(
  140. PSTR(" M201 T"), i
  141. , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(i)])
  142. );
  143. }
  144. #endif
  145. }
  146. /**
  147. * M203: Set maximum feedrate that your machine can sustain (M203 X200 Y200 Z300 E10000) in units/sec
  148. *
  149. * With multiple extruders use T to specify which one.
  150. */
  151. void GcodeSuite::M203() {
  152. if (!parser.seen("T" LOGICAL_AXES_STRING))
  153. return M203_report();
  154. const int8_t target_extruder = get_target_extruder_from_command();
  155. if (target_extruder < 0) return;
  156. LOOP_LOGICAL_AXES(i)
  157. if (parser.seenval(axis_codes[i])) {
  158. const uint8_t a = TERN(HAS_EXTRUDERS, (i == E_AXIS ? uint8_t(E_AXIS_N(target_extruder)) : i), i);
  159. planner.set_max_feedrate(a, parser.value_axis_units((AxisEnum)a));
  160. }
  161. }
  162. void GcodeSuite::M203_report(const bool forReplay/*=true*/) {
  163. report_heading_etc(forReplay, F(STR_MAX_FEEDRATES));
  164. SERIAL_ECHOLNPGM_P(
  165. LIST_N(DOUBLE(NUM_AXES),
  166. PSTR(" M203 X"), LINEAR_UNIT(planner.settings.max_feedrate_mm_s[X_AXIS]),
  167. SP_Y_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Y_AXIS]),
  168. SP_Z_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Z_AXIS]),
  169. SP_I_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[I_AXIS]),
  170. SP_J_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[J_AXIS]),
  171. SP_K_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[K_AXIS]),
  172. SP_U_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[U_AXIS]),
  173. SP_V_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[V_AXIS]),
  174. SP_W_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[W_AXIS])
  175. )
  176. #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)
  177. , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS])
  178. #endif
  179. );
  180. #if ENABLED(DISTINCT_E_FACTORS)
  181. LOOP_L_N(i, E_STEPPERS) {
  182. SERIAL_ECHO_START();
  183. SERIAL_ECHOLNPGM_P(
  184. PSTR(" M203 T"), i
  185. , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS_N(i)])
  186. );
  187. }
  188. #endif
  189. }
  190. /**
  191. * M204: Set Accelerations in units/sec^2 (M204 P1200 R3000 T3000)
  192. *
  193. * P = Printing moves
  194. * R = Retract only (no X, Y, Z) moves
  195. * T = Travel (non printing) moves
  196. */
  197. void GcodeSuite::M204() {
  198. if (!parser.seen("PRST"))
  199. return M204_report();
  200. else {
  201. //planner.synchronize();
  202. // 'S' for legacy compatibility. Should NOT BE USED for new development
  203. if (parser.seenval('S')) planner.settings.travel_acceleration = planner.settings.acceleration = parser.value_linear_units();
  204. if (parser.seenval('P')) planner.settings.acceleration = parser.value_linear_units();
  205. if (parser.seenval('R')) planner.settings.retract_acceleration = parser.value_linear_units();
  206. if (parser.seenval('T')) planner.settings.travel_acceleration = parser.value_linear_units();
  207. }
  208. }
  209. void GcodeSuite::M204_report(const bool forReplay/*=true*/) {
  210. report_heading_etc(forReplay, F(STR_ACCELERATION_P_R_T));
  211. SERIAL_ECHOLNPGM_P(
  212. PSTR(" M204 P"), LINEAR_UNIT(planner.settings.acceleration)
  213. , PSTR(" R"), LINEAR_UNIT(planner.settings.retract_acceleration)
  214. , SP_T_STR, LINEAR_UNIT(planner.settings.travel_acceleration)
  215. );
  216. }
  217. /**
  218. * M205: Set Advanced Settings
  219. *
  220. * B = Min Segment Time (µs)
  221. * S = Min Feed Rate (units/s)
  222. * T = Min Travel Feed Rate (units/s)
  223. * X = Max X Jerk (units/sec^2)
  224. * Y = Max Y Jerk (units/sec^2)
  225. * Z = Max Z Jerk (units/sec^2)
  226. * E = Max E Jerk (units/sec^2)
  227. * J = Junction Deviation (mm) (If not using CLASSIC_JERK)
  228. */
  229. void GcodeSuite::M205() {
  230. if (!parser.seen("BST" TERN_(HAS_JUNCTION_DEVIATION, "J") TERN_(HAS_CLASSIC_JERK, "XYZE")))
  231. return M205_report();
  232. //planner.synchronize();
  233. if (parser.seenval('B')) planner.settings.min_segment_time_us = parser.value_ulong();
  234. if (parser.seenval('S')) planner.settings.min_feedrate_mm_s = parser.value_linear_units();
  235. if (parser.seenval('T')) planner.settings.min_travel_feedrate_mm_s = parser.value_linear_units();
  236. #if HAS_JUNCTION_DEVIATION
  237. #if HAS_CLASSIC_JERK && AXIS_COLLISION('J')
  238. #error "Can't set_max_jerk for 'J' axis because 'J' is used for Junction Deviation."
  239. #endif
  240. if (parser.seenval('J')) {
  241. const float junc_dev = parser.value_linear_units();
  242. if (WITHIN(junc_dev, 0.01f, 0.3f)) {
  243. planner.junction_deviation_mm = junc_dev;
  244. TERN_(LIN_ADVANCE, planner.recalculate_max_e_jerk());
  245. }
  246. else
  247. SERIAL_ERROR_MSG("?J out of range (0.01 to 0.3)");
  248. }
  249. #endif
  250. #if HAS_CLASSIC_JERK
  251. bool seenZ = false;
  252. LOGICAL_AXIS_CODE(
  253. if (parser.seenval('E')) planner.set_max_jerk(E_AXIS, parser.value_linear_units()),
  254. if (parser.seenval('X')) planner.set_max_jerk(X_AXIS, parser.value_linear_units()),
  255. if (parser.seenval('Y')) planner.set_max_jerk(Y_AXIS, parser.value_linear_units()),
  256. if ((seenZ = parser.seenval('Z'))) planner.set_max_jerk(Z_AXIS, parser.value_linear_units()),
  257. if (parser.seenval(AXIS4_NAME)) planner.set_max_jerk(I_AXIS, parser.TERN(AXIS4_ROTATES, value_float, value_linear_units)()),
  258. if (parser.seenval(AXIS5_NAME)) planner.set_max_jerk(J_AXIS, parser.TERN(AXIS5_ROTATES, value_float, value_linear_units)()),
  259. if (parser.seenval(AXIS6_NAME)) planner.set_max_jerk(K_AXIS, parser.TERN(AXIS6_ROTATES, value_float, value_linear_units)()),
  260. if (parser.seenval(AXIS7_NAME)) planner.set_max_jerk(U_AXIS, parser.TERN(AXIS7_ROTATES, value_float, value_linear_units)()),
  261. if (parser.seenval(AXIS8_NAME)) planner.set_max_jerk(V_AXIS, parser.TERN(AXIS8_ROTATES, value_float, value_linear_units)()),
  262. if (parser.seenval(AXIS9_NAME)) planner.set_max_jerk(W_AXIS, parser.TERN(AXIS9_ROTATES, value_float, value_linear_units)())
  263. );
  264. #if HAS_MESH && DISABLED(LIMITED_JERK_EDITING)
  265. if (seenZ && planner.max_jerk.z <= 0.1f)
  266. SERIAL_ECHOLNPGM("WARNING! Low Z Jerk may lead to unwanted pauses.");
  267. #endif
  268. #endif // HAS_CLASSIC_JERK
  269. }
  270. void GcodeSuite::M205_report(const bool forReplay/*=true*/) {
  271. report_heading_etc(forReplay, F(
  272. "Advanced (B<min_segment_time_us> S<min_feedrate> T<min_travel_feedrate>"
  273. TERN_(HAS_JUNCTION_DEVIATION, " J<junc_dev>")
  274. #if HAS_CLASSIC_JERK
  275. NUM_AXIS_GANG(
  276. " X<max_jerk>", " Y<max_jerk>", " Z<max_jerk>",
  277. " " STR_I "<max_jerk>", " " STR_J "<max_jerk>", " " STR_K "<max_jerk>",
  278. " " STR_U "<max_jerk>", " " STR_V "<max_jerk>", " " STR_W "<max_jerk>"
  279. )
  280. #endif
  281. TERN_(HAS_CLASSIC_E_JERK, " E<max_jerk>")
  282. ")"
  283. ));
  284. SERIAL_ECHOLNPGM_P(
  285. PSTR(" M205 B"), LINEAR_UNIT(planner.settings.min_segment_time_us)
  286. , PSTR(" S"), LINEAR_UNIT(planner.settings.min_feedrate_mm_s)
  287. , SP_T_STR, LINEAR_UNIT(planner.settings.min_travel_feedrate_mm_s)
  288. #if HAS_JUNCTION_DEVIATION
  289. , PSTR(" J"), LINEAR_UNIT(planner.junction_deviation_mm)
  290. #endif
  291. #if HAS_CLASSIC_JERK
  292. , LIST_N(DOUBLE(NUM_AXES),
  293. SP_X_STR, LINEAR_UNIT(planner.max_jerk.x),
  294. SP_Y_STR, LINEAR_UNIT(planner.max_jerk.y),
  295. SP_Z_STR, LINEAR_UNIT(planner.max_jerk.z),
  296. SP_I_STR, I_AXIS_UNIT(planner.max_jerk.i),
  297. SP_J_STR, J_AXIS_UNIT(planner.max_jerk.j),
  298. SP_K_STR, K_AXIS_UNIT(planner.max_jerk.k),
  299. SP_U_STR, U_AXIS_UNIT(planner.max_jerk.u),
  300. SP_V_STR, V_AXIS_UNIT(planner.max_jerk.v),
  301. SP_W_STR, W_AXIS_UNIT(planner.max_jerk.w)
  302. )
  303. #if HAS_CLASSIC_E_JERK
  304. , SP_E_STR, LINEAR_UNIT(planner.max_jerk.e)
  305. #endif
  306. #endif
  307. );
  308. }