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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  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.
  99. *
  100. * X<accel> : Max Acceleration for X
  101. * Y<accel> : Max Acceleration for Y
  102. * Z<accel> : Max Acceleration for Z
  103. * ... : etc
  104. * E<accel> : Max Acceleration for Extruder
  105. * T<index> : Extruder index to set
  106. *
  107. * With XY_FREQUENCY_LIMIT:
  108. * F<Hz> : Frequency limit for XY...IJKUVW
  109. * S<percent> : Speed factor percentage.
  110. */
  111. void GcodeSuite::M201() {
  112. if (!parser.seen("T" STR_AXES_LOGICAL TERN_(XY_FREQUENCY_LIMIT, "FS")))
  113. return M201_report();
  114. const int8_t target_extruder = get_target_extruder_from_command();
  115. if (target_extruder < 0) return;
  116. #ifdef XY_FREQUENCY_LIMIT
  117. if (parser.seenval('F')) planner.set_frequency_limit(parser.value_byte());
  118. if (parser.seenval('S')) planner.xy_freq_min_speed_factor = constrain(parser.value_float(), 1, 100) / 100;
  119. #endif
  120. LOOP_LOGICAL_AXES(i) {
  121. if (parser.seenval(AXIS_CHAR(i))) {
  122. const AxisEnum a = TERN(HAS_EXTRUDERS, (i == E_AXIS ? E_AXIS_N(target_extruder) : (AxisEnum)i), (AxisEnum)i);
  123. planner.set_max_acceleration(a, parser.value_axis_units(a));
  124. }
  125. }
  126. }
  127. void GcodeSuite::M201_report(const bool forReplay/*=true*/) {
  128. report_heading_etc(forReplay, F(STR_MAX_ACCELERATION));
  129. SERIAL_ECHOLNPGM_P(
  130. LIST_N(DOUBLE(NUM_AXES),
  131. PSTR(" M201 X"), LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[X_AXIS]),
  132. SP_Y_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Y_AXIS]),
  133. SP_Z_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[Z_AXIS]),
  134. SP_I_STR, I_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[I_AXIS]),
  135. SP_J_STR, J_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[J_AXIS]),
  136. SP_K_STR, K_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[K_AXIS]),
  137. SP_U_STR, U_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[U_AXIS]),
  138. SP_V_STR, V_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[V_AXIS]),
  139. SP_W_STR, W_AXIS_UNIT(planner.settings.max_acceleration_mm_per_s2[W_AXIS])
  140. )
  141. #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)
  142. , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_acceleration_mm_per_s2[E_AXIS])
  143. #endif
  144. );
  145. #if ENABLED(DISTINCT_E_FACTORS)
  146. LOOP_L_N(i, E_STEPPERS) {
  147. report_echo_start(forReplay);
  148. SERIAL_ECHOLNPGM_P(
  149. PSTR(" M201 T"), i
  150. , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(i)])
  151. );
  152. }
  153. #endif
  154. }
  155. /**
  156. * M203: Set maximum feedrate that your machine can sustain (M203 X200 Y200 Z300 E10000) in units/sec
  157. *
  158. * With multiple extruders use T to specify which one.
  159. */
  160. void GcodeSuite::M203() {
  161. if (!parser.seen("T" STR_AXES_LOGICAL))
  162. return M203_report();
  163. const int8_t target_extruder = get_target_extruder_from_command();
  164. if (target_extruder < 0) return;
  165. LOOP_LOGICAL_AXES(i)
  166. if (parser.seenval(AXIS_CHAR(i))) {
  167. const AxisEnum a = TERN(HAS_EXTRUDERS, (i == E_AXIS ? E_AXIS_N(target_extruder) : (AxisEnum)i), (AxisEnum)i);
  168. planner.set_max_feedrate(a, parser.value_axis_units(a));
  169. }
  170. }
  171. void GcodeSuite::M203_report(const bool forReplay/*=true*/) {
  172. report_heading_etc(forReplay, F(STR_MAX_FEEDRATES));
  173. SERIAL_ECHOLNPGM_P(
  174. LIST_N(DOUBLE(NUM_AXES),
  175. PSTR(" M203 X"), LINEAR_UNIT(planner.settings.max_feedrate_mm_s[X_AXIS]),
  176. SP_Y_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Y_AXIS]),
  177. SP_Z_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Z_AXIS]),
  178. SP_I_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[I_AXIS]),
  179. SP_J_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[J_AXIS]),
  180. SP_K_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[K_AXIS]),
  181. SP_U_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[U_AXIS]),
  182. SP_V_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[V_AXIS]),
  183. SP_W_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[W_AXIS])
  184. )
  185. #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)
  186. , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS])
  187. #endif
  188. );
  189. #if ENABLED(DISTINCT_E_FACTORS)
  190. LOOP_L_N(i, E_STEPPERS) {
  191. if (!forReplay) SERIAL_ECHO_START();
  192. SERIAL_ECHOLNPGM_P(
  193. PSTR(" M203 T"), i
  194. , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS_N(i)])
  195. );
  196. }
  197. #endif
  198. }
  199. /**
  200. * M204: Set Accelerations in units/sec^2 (M204 P1200 R3000 T3000)
  201. *
  202. * P = Printing moves
  203. * R = Retract only (no X, Y, Z) moves
  204. * T = Travel (non printing) moves
  205. */
  206. void GcodeSuite::M204() {
  207. if (!parser.seen("PRST"))
  208. return M204_report();
  209. else {
  210. //planner.synchronize();
  211. // 'S' for legacy compatibility. Should NOT BE USED for new development
  212. if (parser.seenval('S')) planner.settings.travel_acceleration = planner.settings.acceleration = parser.value_linear_units();
  213. if (parser.seenval('P')) planner.settings.acceleration = parser.value_linear_units();
  214. if (parser.seenval('R')) planner.settings.retract_acceleration = parser.value_linear_units();
  215. if (parser.seenval('T')) planner.settings.travel_acceleration = parser.value_linear_units();
  216. }
  217. }
  218. void GcodeSuite::M204_report(const bool forReplay/*=true*/) {
  219. report_heading_etc(forReplay, F(STR_ACCELERATION_P_R_T));
  220. SERIAL_ECHOLNPGM_P(
  221. PSTR(" M204 P"), LINEAR_UNIT(planner.settings.acceleration)
  222. , PSTR(" R"), LINEAR_UNIT(planner.settings.retract_acceleration)
  223. , SP_T_STR, LINEAR_UNIT(planner.settings.travel_acceleration)
  224. );
  225. }
  226. /**
  227. * M205: Set Advanced Settings
  228. *
  229. * B = Min Segment Time (µs)
  230. * S = Min Feed Rate (units/s)
  231. * T = Min Travel Feed Rate (units/s)
  232. * X = Max X Jerk (units/sec^2)
  233. * Y = Max Y Jerk (units/sec^2)
  234. * Z = Max Z Jerk (units/sec^2)
  235. * E = Max E Jerk (units/sec^2)
  236. * J = Junction Deviation (mm) (If not using CLASSIC_JERK)
  237. */
  238. void GcodeSuite::M205() {
  239. if (!parser.seen("BST" TERN_(HAS_JUNCTION_DEVIATION, "J") TERN_(HAS_CLASSIC_JERK, "XYZE")))
  240. return M205_report();
  241. //planner.synchronize();
  242. if (parser.seenval('B')) planner.settings.min_segment_time_us = parser.value_ulong();
  243. if (parser.seenval('S')) planner.settings.min_feedrate_mm_s = parser.value_linear_units();
  244. if (parser.seenval('T')) planner.settings.min_travel_feedrate_mm_s = parser.value_linear_units();
  245. #if HAS_JUNCTION_DEVIATION
  246. #if HAS_CLASSIC_JERK && AXIS_COLLISION('J')
  247. #error "Can't set_max_jerk for 'J' axis because 'J' is used for Junction Deviation."
  248. #endif
  249. if (parser.seenval('J')) {
  250. const float junc_dev = parser.value_linear_units();
  251. if (WITHIN(junc_dev, 0.01f, 0.3f)) {
  252. planner.junction_deviation_mm = junc_dev;
  253. TERN_(LIN_ADVANCE, planner.recalculate_max_e_jerk());
  254. }
  255. else
  256. SERIAL_ERROR_MSG("?J out of range (0.01 to 0.3)");
  257. }
  258. #endif
  259. #if HAS_CLASSIC_JERK
  260. bool seenZ = false;
  261. LOGICAL_AXIS_CODE(
  262. if (parser.seenval('E')) planner.set_max_jerk(E_AXIS, parser.value_linear_units()),
  263. if (parser.seenval('X')) planner.set_max_jerk(X_AXIS, parser.value_linear_units()),
  264. if (parser.seenval('Y')) planner.set_max_jerk(Y_AXIS, parser.value_linear_units()),
  265. if ((seenZ = parser.seenval('Z'))) planner.set_max_jerk(Z_AXIS, parser.value_linear_units()),
  266. if (parser.seenval(AXIS4_NAME)) planner.set_max_jerk(I_AXIS, parser.TERN(AXIS4_ROTATES, value_float, value_linear_units)()),
  267. if (parser.seenval(AXIS5_NAME)) planner.set_max_jerk(J_AXIS, parser.TERN(AXIS5_ROTATES, value_float, value_linear_units)()),
  268. if (parser.seenval(AXIS6_NAME)) planner.set_max_jerk(K_AXIS, parser.TERN(AXIS6_ROTATES, value_float, value_linear_units)()),
  269. if (parser.seenval(AXIS7_NAME)) planner.set_max_jerk(U_AXIS, parser.TERN(AXIS7_ROTATES, value_float, value_linear_units)()),
  270. if (parser.seenval(AXIS8_NAME)) planner.set_max_jerk(V_AXIS, parser.TERN(AXIS8_ROTATES, value_float, value_linear_units)()),
  271. if (parser.seenval(AXIS9_NAME)) planner.set_max_jerk(W_AXIS, parser.TERN(AXIS9_ROTATES, value_float, value_linear_units)())
  272. );
  273. #if HAS_MESH && DISABLED(LIMITED_JERK_EDITING)
  274. if (seenZ && planner.max_jerk.z <= 0.1f)
  275. SERIAL_ECHOLNPGM("WARNING! Low Z Jerk may lead to unwanted pauses.");
  276. #endif
  277. #endif // HAS_CLASSIC_JERK
  278. }
  279. void GcodeSuite::M205_report(const bool forReplay/*=true*/) {
  280. report_heading_etc(forReplay, F(
  281. "Advanced (B<min_segment_time_us> S<min_feedrate> T<min_travel_feedrate>"
  282. TERN_(HAS_JUNCTION_DEVIATION, " J<junc_dev>")
  283. #if HAS_CLASSIC_JERK
  284. NUM_AXIS_GANG(
  285. " X<max_jerk>", " Y<max_jerk>", " Z<max_jerk>",
  286. " " STR_I "<max_jerk>", " " STR_J "<max_jerk>", " " STR_K "<max_jerk>",
  287. " " STR_U "<max_jerk>", " " STR_V "<max_jerk>", " " STR_W "<max_jerk>"
  288. )
  289. #endif
  290. TERN_(HAS_CLASSIC_E_JERK, " E<max_jerk>")
  291. ")"
  292. ));
  293. SERIAL_ECHOLNPGM_P(
  294. PSTR(" M205 B"), LINEAR_UNIT(planner.settings.min_segment_time_us)
  295. , PSTR(" S"), LINEAR_UNIT(planner.settings.min_feedrate_mm_s)
  296. , SP_T_STR, LINEAR_UNIT(planner.settings.min_travel_feedrate_mm_s)
  297. #if HAS_JUNCTION_DEVIATION
  298. , PSTR(" J"), LINEAR_UNIT(planner.junction_deviation_mm)
  299. #endif
  300. #if HAS_CLASSIC_JERK
  301. , LIST_N(DOUBLE(NUM_AXES),
  302. SP_X_STR, LINEAR_UNIT(planner.max_jerk.x),
  303. SP_Y_STR, LINEAR_UNIT(planner.max_jerk.y),
  304. SP_Z_STR, LINEAR_UNIT(planner.max_jerk.z),
  305. SP_I_STR, I_AXIS_UNIT(planner.max_jerk.i),
  306. SP_J_STR, J_AXIS_UNIT(planner.max_jerk.j),
  307. SP_K_STR, K_AXIS_UNIT(planner.max_jerk.k),
  308. SP_U_STR, U_AXIS_UNIT(planner.max_jerk.u),
  309. SP_V_STR, V_AXIS_UNIT(planner.max_jerk.v),
  310. SP_W_STR, W_AXIS_UNIT(planner.max_jerk.w)
  311. )
  312. #if HAS_CLASSIC_E_JERK
  313. , SP_E_STR, LINEAR_UNIT(planner.max_jerk.e)
  314. #endif
  315. #endif
  316. );
  317. }