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.

M48.cpp 8.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /**
  2. * Marlin 3D Printer Firmware
  3. * Copyright (c) 2019 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. #include "../../inc/MarlinConfig.h"
  23. #if ENABLED(Z_MIN_PROBE_REPEATABILITY_TEST)
  24. #include "../gcode.h"
  25. #include "../../module/motion.h"
  26. #include "../../module/probe.h"
  27. #include "../../feature/bedlevel/bedlevel.h"
  28. #if HAS_LEVELING
  29. #include "../../module/planner.h"
  30. #endif
  31. /**
  32. * M48: Z probe repeatability measurement function.
  33. *
  34. * Usage:
  35. * M48 <P#> <X#> <Y#> <V#> <E> <L#> <S>
  36. * P = Number of sampled points (4-50, default 10)
  37. * X = Sample X position
  38. * Y = Sample Y position
  39. * V = Verbose level (0-4, default=1)
  40. * E = Engage Z probe for each reading
  41. * L = Number of legs of movement before probe
  42. * S = Schizoid (Or Star if you prefer)
  43. *
  44. * This function requires the machine to be homed before invocation.
  45. */
  46. void GcodeSuite::M48() {
  47. if (axis_unhomed_error()) return;
  48. const int8_t verbose_level = parser.byteval('V', 1);
  49. if (!WITHIN(verbose_level, 0, 4)) {
  50. SERIAL_ECHOLNPGM("?(V)erbose level is implausible (0-4).");
  51. return;
  52. }
  53. if (verbose_level > 0)
  54. SERIAL_ECHOLNPGM("M48 Z-Probe Repeatability Test");
  55. const int8_t n_samples = parser.byteval('P', 10);
  56. if (!WITHIN(n_samples, 4, 50)) {
  57. SERIAL_ECHOLNPGM("?Sample size not plausible (4-50).");
  58. return;
  59. }
  60. const ProbePtRaise raise_after = parser.boolval('E') ? PROBE_PT_STOW : PROBE_PT_RAISE;
  61. float X_current = current_position[X_AXIS],
  62. Y_current = current_position[Y_AXIS];
  63. const float X_probe_location = parser.linearval('X', X_current + X_PROBE_OFFSET_FROM_EXTRUDER),
  64. Y_probe_location = parser.linearval('Y', Y_current + Y_PROBE_OFFSET_FROM_EXTRUDER);
  65. if (!position_is_reachable_by_probe(X_probe_location, Y_probe_location)) {
  66. SERIAL_ECHOLNPGM("? (X,Y) out of bounds.");
  67. return;
  68. }
  69. bool seen_L = parser.seen('L');
  70. uint8_t n_legs = seen_L ? parser.value_byte() : 0;
  71. if (n_legs > 15) {
  72. SERIAL_ECHOLNPGM("?Number of legs in movement not plausible (0-15).");
  73. return;
  74. }
  75. if (n_legs == 1) n_legs = 2;
  76. const bool schizoid_flag = parser.boolval('S');
  77. if (schizoid_flag && !seen_L) n_legs = 7;
  78. /**
  79. * Now get everything to the specified probe point So we can safely do a
  80. * probe to get us close to the bed. If the Z-Axis is far from the bed,
  81. * we don't want to use that as a starting point for each probe.
  82. */
  83. if (verbose_level > 2)
  84. SERIAL_ECHOLNPGM("Positioning the probe...");
  85. // Disable bed level correction in M48 because we want the raw data when we probe
  86. #if HAS_LEVELING
  87. const bool was_enabled = planner.leveling_active;
  88. set_bed_leveling_enabled(false);
  89. #endif
  90. setup_for_endstop_or_probe_move();
  91. float mean = 0.0, sigma = 0.0, min = 99999.9, max = -99999.9, sample_set[n_samples];
  92. // Move to the first point, deploy, and probe
  93. const float t = probe_pt(X_probe_location, Y_probe_location, raise_after, verbose_level);
  94. bool probing_good = !isnan(t);
  95. if (probing_good) {
  96. randomSeed(millis());
  97. for (uint8_t n = 0; n < n_samples; n++) {
  98. if (n_legs) {
  99. const int dir = (random(0, 10) > 5.0) ? -1 : 1; // clockwise or counter clockwise
  100. float angle = random(0, 360);
  101. const float radius = random(
  102. #if ENABLED(DELTA)
  103. (int) (0.1250000000 * (DELTA_PRINTABLE_RADIUS)),
  104. (int) (0.3333333333 * (DELTA_PRINTABLE_RADIUS))
  105. #else
  106. (int) 5.0, (int) (0.125 * MIN(X_BED_SIZE, Y_BED_SIZE))
  107. #endif
  108. );
  109. if (verbose_level > 3) {
  110. SERIAL_ECHOPAIR("Starting radius: ", radius);
  111. SERIAL_ECHOPAIR(" angle: ", angle);
  112. SERIAL_ECHOPGM(" Direction: ");
  113. if (dir > 0) SERIAL_ECHOPGM("Counter-");
  114. SERIAL_ECHOLNPGM("Clockwise");
  115. }
  116. for (uint8_t l = 0; l < n_legs - 1; l++) {
  117. float delta_angle;
  118. if (schizoid_flag)
  119. // The points of a 5 point star are 72 degrees apart. We need to
  120. // skip a point and go to the next one on the star.
  121. delta_angle = dir * 2.0 * 72.0;
  122. else
  123. // If we do this line, we are just trying to move further
  124. // around the circle.
  125. delta_angle = dir * (float) random(25, 45);
  126. angle += delta_angle;
  127. while (angle > 360.0) // We probably do not need to keep the angle between 0 and 2*PI, but the
  128. angle -= 360.0; // Arduino documentation says the trig functions should not be given values
  129. while (angle < 0.0) // outside of this range. It looks like they behave correctly with
  130. angle += 360.0; // numbers outside of the range, but just to be safe we clamp them.
  131. X_current = X_probe_location - (X_PROBE_OFFSET_FROM_EXTRUDER) + cos(RADIANS(angle)) * radius;
  132. Y_current = Y_probe_location - (Y_PROBE_OFFSET_FROM_EXTRUDER) + sin(RADIANS(angle)) * radius;
  133. #if DISABLED(DELTA)
  134. X_current = constrain(X_current, X_MIN_POS, X_MAX_POS);
  135. Y_current = constrain(Y_current, Y_MIN_POS, Y_MAX_POS);
  136. #else
  137. // If we have gone out too far, we can do a simple fix and scale the numbers
  138. // back in closer to the origin.
  139. while (!position_is_reachable_by_probe(X_current, Y_current)) {
  140. X_current *= 0.8;
  141. Y_current *= 0.8;
  142. if (verbose_level > 3) {
  143. SERIAL_ECHOPAIR("Pulling point towards center:", X_current);
  144. SERIAL_ECHOLNPAIR(", ", Y_current);
  145. }
  146. }
  147. #endif
  148. if (verbose_level > 3) {
  149. SERIAL_ECHOPGM("Going to:");
  150. SERIAL_ECHOPAIR(" X", X_current);
  151. SERIAL_ECHOPAIR(" Y", Y_current);
  152. SERIAL_ECHOLNPAIR(" Z", current_position[Z_AXIS]);
  153. }
  154. do_blocking_move_to_xy(X_current, Y_current);
  155. } // n_legs loop
  156. } // n_legs
  157. // Probe a single point
  158. sample_set[n] = probe_pt(X_probe_location, Y_probe_location, raise_after, 0);
  159. // Break the loop if the probe fails
  160. probing_good = !isnan(sample_set[n]);
  161. if (!probing_good) break;
  162. /**
  163. * Get the current mean for the data points we have so far
  164. */
  165. float sum = 0.0;
  166. for (uint8_t j = 0; j <= n; j++) sum += sample_set[j];
  167. mean = sum / (n + 1);
  168. NOMORE(min, sample_set[n]);
  169. NOLESS(max, sample_set[n]);
  170. /**
  171. * Now, use that mean to calculate the standard deviation for the
  172. * data points we have so far
  173. */
  174. sum = 0.0;
  175. for (uint8_t j = 0; j <= n; j++)
  176. sum += sq(sample_set[j] - mean);
  177. sigma = SQRT(sum / (n + 1));
  178. if (verbose_level > 0) {
  179. if (verbose_level > 1) {
  180. SERIAL_ECHO(n + 1);
  181. SERIAL_ECHOPAIR(" of ", (int)n_samples);
  182. SERIAL_ECHOPAIR_F(": z: ", sample_set[n], 3);
  183. if (verbose_level > 2) {
  184. SERIAL_ECHOPAIR_F(" mean: ", mean, 4);
  185. SERIAL_ECHOPAIR_F(" sigma: ", sigma, 6);
  186. SERIAL_ECHOPAIR_F(" min: ", min, 3);
  187. SERIAL_ECHOPAIR_F(" max: ", max, 3);
  188. SERIAL_ECHOPAIR_F(" range: ", max-min, 3);
  189. }
  190. SERIAL_EOL();
  191. }
  192. }
  193. } // n_samples loop
  194. }
  195. STOW_PROBE();
  196. if (probing_good) {
  197. SERIAL_ECHOLNPGM("Finished!");
  198. if (verbose_level > 0) {
  199. SERIAL_ECHOPAIR_F("Mean: ", mean, 6);
  200. SERIAL_ECHOPAIR_F(" Min: ", min, 3);
  201. SERIAL_ECHOPAIR_F(" Max: ", max, 3);
  202. SERIAL_ECHOLNPAIR_F(" Range: ", max-min, 3);
  203. }
  204. SERIAL_ECHOLNPAIR_F("Standard Deviation: ", sigma, 6);
  205. SERIAL_EOL();
  206. }
  207. clean_up_after_endstop_or_probe_move();
  208. // Re-enable bed level correction if it had been on
  209. #if HAS_LEVELING
  210. set_bed_leveling_enabled(was_enabled);
  211. #endif
  212. report_current_position();
  213. }
  214. #endif // Z_MIN_PROBE_REPEATABILITY_TEST