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 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  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, PSTR(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. LOOP_L_N(i, EXTRUDERS) {
  86. report_echo_start(forReplay);
  87. SERIAL_ECHOLNPGM(
  88. " M200 T", i, " D", LINEAR_UNIT(planner.filament_size[i])
  89. #if ENABLED(VOLUMETRIC_EXTRUDER_LIMIT)
  90. , " L", LINEAR_UNIT(planner.volumetric_extruder_limit[i])
  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, PSTR(STR_MAX_ACCELERATION));
  120. SERIAL_ECHOLNPGM_P(
  121. LIST_N(DOUBLE(LINEAR_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, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[I_AXIS]),
  126. SP_J_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[J_AXIS]),
  127. SP_K_STR, LINEAR_UNIT(planner.settings.max_acceleration_mm_per_s2[K_AXIS])
  128. )
  129. #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)
  130. , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_acceleration_mm_per_s2[E_AXIS])
  131. #endif
  132. );
  133. #if ENABLED(DISTINCT_E_FACTORS)
  134. LOOP_L_N(i, E_STEPPERS) {
  135. report_echo_start(forReplay);
  136. SERIAL_ECHOLNPGM_P(
  137. PSTR(" M201 T"), i
  138. , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(i)])
  139. );
  140. }
  141. #endif
  142. }
  143. /**
  144. * M203: Set maximum feedrate that your machine can sustain (M203 X200 Y200 Z300 E10000) in units/sec
  145. *
  146. * With multiple extruders use T to specify which one.
  147. */
  148. void GcodeSuite::M203() {
  149. if (!parser.seen("T" LOGICAL_AXES_STRING))
  150. return M203_report();
  151. const int8_t target_extruder = get_target_extruder_from_command();
  152. if (target_extruder < 0) return;
  153. LOOP_LOGICAL_AXES(i)
  154. if (parser.seenval(axis_codes[i])) {
  155. const uint8_t a = TERN(HAS_EXTRUDERS, (i == E_AXIS ? uint8_t(E_AXIS_N(target_extruder)) : i), i);
  156. planner.set_max_feedrate(a, parser.value_axis_units((AxisEnum)a));
  157. }
  158. }
  159. void GcodeSuite::M203_report(const bool forReplay/*=true*/) {
  160. report_heading_etc(forReplay, PSTR(STR_MAX_FEEDRATES));
  161. SERIAL_ECHOLNPGM_P(
  162. LIST_N(DOUBLE(LINEAR_AXES),
  163. PSTR(" M203 X"), LINEAR_UNIT(planner.settings.max_feedrate_mm_s[X_AXIS]),
  164. SP_Y_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Y_AXIS]),
  165. SP_Z_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[Z_AXIS]),
  166. SP_I_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[I_AXIS]),
  167. SP_J_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[J_AXIS]),
  168. SP_K_STR, LINEAR_UNIT(planner.settings.max_feedrate_mm_s[K_AXIS])
  169. )
  170. #if HAS_EXTRUDERS && DISABLED(DISTINCT_E_FACTORS)
  171. , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS])
  172. #endif
  173. );
  174. #if ENABLED(DISTINCT_E_FACTORS)
  175. LOOP_L_N(i, E_STEPPERS) {
  176. SERIAL_ECHO_START();
  177. SERIAL_ECHOLNPGM_P(
  178. PSTR(" M203 T"), i
  179. , SP_E_STR, VOLUMETRIC_UNIT(planner.settings.max_feedrate_mm_s[E_AXIS_N(i)])
  180. );
  181. }
  182. #endif
  183. }
  184. /**
  185. * M204: Set Accelerations in units/sec^2 (M204 P1200 R3000 T3000)
  186. *
  187. * P = Printing moves
  188. * R = Retract only (no X, Y, Z) moves
  189. * T = Travel (non printing) moves
  190. */
  191. void GcodeSuite::M204() {
  192. if (!parser.seen("PRST"))
  193. return M204_report();
  194. else {
  195. //planner.synchronize();
  196. // 'S' for legacy compatibility. Should NOT BE USED for new development
  197. if (parser.seenval('S')) planner.settings.travel_acceleration = planner.settings.acceleration = parser.value_linear_units();
  198. if (parser.seenval('P')) planner.settings.acceleration = parser.value_linear_units();
  199. if (parser.seenval('R')) planner.settings.retract_acceleration = parser.value_linear_units();
  200. if (parser.seenval('T')) planner.settings.travel_acceleration = parser.value_linear_units();
  201. }
  202. }
  203. void GcodeSuite::M204_report(const bool forReplay/*=true*/) {
  204. report_heading_etc(forReplay, PSTR(STR_ACCELERATION_P_R_T));
  205. SERIAL_ECHOLNPGM_P(
  206. PSTR(" M204 P"), LINEAR_UNIT(planner.settings.acceleration)
  207. , PSTR(" R"), LINEAR_UNIT(planner.settings.retract_acceleration)
  208. , SP_T_STR, LINEAR_UNIT(planner.settings.travel_acceleration)
  209. );
  210. }
  211. /**
  212. * M205: Set Advanced Settings
  213. *
  214. * B = Min Segment Time (µs)
  215. * S = Min Feed Rate (units/s)
  216. * T = Min Travel Feed Rate (units/s)
  217. * X = Max X Jerk (units/sec^2)
  218. * Y = Max Y Jerk (units/sec^2)
  219. * Z = Max Z Jerk (units/sec^2)
  220. * E = Max E Jerk (units/sec^2)
  221. * J = Junction Deviation (mm) (If not using CLASSIC_JERK)
  222. */
  223. void GcodeSuite::M205() {
  224. if (!parser.seen("BST" TERN_(HAS_JUNCTION_DEVIATION, "J") TERN_(HAS_CLASSIC_JERK, "XYZE")))
  225. return M205_report();
  226. //planner.synchronize();
  227. if (parser.seenval('B')) planner.settings.min_segment_time_us = parser.value_ulong();
  228. if (parser.seenval('S')) planner.settings.min_feedrate_mm_s = parser.value_linear_units();
  229. if (parser.seenval('T')) planner.settings.min_travel_feedrate_mm_s = parser.value_linear_units();
  230. #if HAS_JUNCTION_DEVIATION
  231. #if HAS_CLASSIC_JERK && (AXIS4_NAME == 'J' || AXIS5_NAME == 'J' || AXIS6_NAME == 'J')
  232. #error "Can't set_max_jerk for 'J' axis because 'J' is used for Junction Deviation."
  233. #endif
  234. if (parser.seenval('J')) {
  235. const float junc_dev = parser.value_linear_units();
  236. if (WITHIN(junc_dev, 0.01f, 0.3f)) {
  237. planner.junction_deviation_mm = junc_dev;
  238. TERN_(LIN_ADVANCE, planner.recalculate_max_e_jerk());
  239. }
  240. else
  241. SERIAL_ERROR_MSG("?J out of range (0.01 to 0.3)");
  242. }
  243. #endif
  244. #if HAS_CLASSIC_JERK
  245. bool seenZ = false;
  246. LOGICAL_AXIS_CODE(
  247. if (parser.seenval('E')) planner.set_max_jerk(E_AXIS, parser.value_linear_units()),
  248. if (parser.seenval('X')) planner.set_max_jerk(X_AXIS, parser.value_linear_units()),
  249. if (parser.seenval('Y')) planner.set_max_jerk(Y_AXIS, parser.value_linear_units()),
  250. if ((seenZ = parser.seenval('Z'))) planner.set_max_jerk(Z_AXIS, parser.value_linear_units()),
  251. if (parser.seenval(AXIS4_NAME)) planner.set_max_jerk(I_AXIS, parser.value_linear_units()),
  252. if (parser.seenval(AXIS5_NAME)) planner.set_max_jerk(J_AXIS, parser.value_linear_units()),
  253. if (parser.seenval(AXIS6_NAME)) planner.set_max_jerk(K_AXIS, parser.value_linear_units())
  254. );
  255. #if HAS_MESH && DISABLED(LIMITED_JERK_EDITING)
  256. if (seenZ && planner.max_jerk.z <= 0.1f)
  257. SERIAL_ECHOLNPGM("WARNING! Low Z Jerk may lead to unwanted pauses.");
  258. #endif
  259. #endif // HAS_CLASSIC_JERK
  260. }
  261. void GcodeSuite::M205_report(const bool forReplay/*=true*/) {
  262. report_heading_etc(forReplay, PSTR(
  263. "Advanced (B<min_segment_time_us> S<min_feedrate> T<min_travel_feedrate>"
  264. TERN_(HAS_JUNCTION_DEVIATION, " J<junc_dev>")
  265. TERN_(HAS_CLASSIC_JERK, " X<max_x_jerk> Y<max_y_jerk> Z<max_z_jerk>")
  266. TERN_(HAS_CLASSIC_E_JERK, " E<max_e_jerk>")
  267. ")"
  268. ));
  269. SERIAL_ECHOLNPGM_P(
  270. PSTR(" M205 B"), LINEAR_UNIT(planner.settings.min_segment_time_us)
  271. , PSTR(" S"), LINEAR_UNIT(planner.settings.min_feedrate_mm_s)
  272. , SP_T_STR, LINEAR_UNIT(planner.settings.min_travel_feedrate_mm_s)
  273. #if HAS_JUNCTION_DEVIATION
  274. , PSTR(" J"), LINEAR_UNIT(planner.junction_deviation_mm)
  275. #endif
  276. #if HAS_CLASSIC_JERK
  277. , LIST_N(DOUBLE(LINEAR_AXES),
  278. SP_X_STR, LINEAR_UNIT(planner.max_jerk.x),
  279. SP_Y_STR, LINEAR_UNIT(planner.max_jerk.y),
  280. SP_Z_STR, LINEAR_UNIT(planner.max_jerk.z),
  281. SP_I_STR, LINEAR_UNIT(planner.max_jerk.i),
  282. SP_J_STR, LINEAR_UNIT(planner.max_jerk.j),
  283. SP_K_STR, LINEAR_UNIT(planner.max_jerk.k)
  284. )
  285. #if HAS_CLASSIC_E_JERK
  286. , SP_E_STR, LINEAR_UNIT(planner.max_jerk.e)
  287. #endif
  288. #endif
  289. );
  290. }