瀏覽代碼

Optional homing in LCD Repeatability Test (#19104)

Giuliano Zaro 4 年之前
父節點
當前提交
6b549e1971
沒有連結到貢獻者的電子郵件帳戶。

+ 90
- 85
Marlin/src/gcode/calibrate/M48.cpp 查看文件

@@ -27,13 +27,10 @@
27 27
 #include "../gcode.h"
28 28
 #include "../../module/motion.h"
29 29
 #include "../../module/probe.h"
30
+#include "../../lcd/ultralcd.h"
30 31
 
31 32
 #include "../../feature/bedlevel/bedlevel.h"
32 33
 
33
-#if HAS_SPI_LCD
34
-  #include "../../lcd/ultralcd.h"
35
-#endif
36
-
37 34
 #if HAS_LEVELING
38 35
   #include "../../module/planner.h"
39 36
 #endif
@@ -77,61 +74,85 @@ void GcodeSuite::M48() {
77 74
 
78 75
   const ProbePtRaise raise_after = parser.boolval('E') ? PROBE_PT_STOW : PROBE_PT_RAISE;
79 76
 
80
-  xy_float_t next_pos = current_position;
81
-
82
-  const xy_pos_t probe_pos = {
83
-    parser.linearval('X', next_pos.x + probe.offset_xy.x),  // If no X use the probe's current X position
84
-    parser.linearval('Y', next_pos.y + probe.offset_xy.y)   // If no Y, ditto
77
+  // Test at the current position by default, overridden by X and Y
78
+  const xy_pos_t test_position = {
79
+    parser.linearval('X', current_position.x + probe.offset_xy.x),  // If no X use the probe's current X position
80
+    parser.linearval('Y', current_position.y + probe.offset_xy.y)   // If no Y, ditto
85 81
   };
86 82
 
87
-  if (!probe.can_reach(probe_pos)) {
83
+  if (!probe.can_reach(test_position)) {
84
+    ui.set_status_P(GET_TEXT(MSG_M48_OUT_OF_BOUNDS), 99);
88 85
     SERIAL_ECHOLNPGM("? (X,Y) out of bounds.");
89 86
     return;
90 87
   }
91 88
 
89
+  // Get the number of leg moves per test-point
92 90
   bool seen_L = parser.seen('L');
93 91
   uint8_t n_legs = seen_L ? parser.value_byte() : 0;
94 92
   if (n_legs > 15) {
95
-    SERIAL_ECHOLNPGM("?Number of legs in movement not plausible (0-15).");
93
+    SERIAL_ECHOLNPGM("?Legs of movement implausible (0-15).");
96 94
     return;
97 95
   }
98 96
   if (n_legs == 1) n_legs = 2;
99 97
 
98
+  // Schizoid motion as an optional stress-test
100 99
   const bool schizoid_flag = parser.boolval('S');
101 100
   if (schizoid_flag && !seen_L) n_legs = 7;
102 101
 
103
-  /**
104
-   * Now get everything to the specified probe point So we can safely do a
105
-   * probe to get us close to the bed.  If the Z-Axis is far from the bed,
106
-   * we don't want to use that as a starting point for each probe.
107
-   */
108 102
   if (verbose_level > 2)
109 103
     SERIAL_ECHOLNPGM("Positioning the probe...");
110 104
 
111
-  // Disable bed level correction in M48 because we want the raw data when we probe
105
+  // Always disable Bed Level correction before probing...
112 106
 
113 107
   #if HAS_LEVELING
114 108
     const bool was_enabled = planner.leveling_active;
115 109
     set_bed_leveling_enabled(false);
116 110
   #endif
117 111
 
112
+  // Work with reasonable feedrates
118 113
   remember_feedrate_scaling_off();
119 114
 
120
-  float mean = 0.0, sigma = 0.0, min = 99999.9, max = -99999.9, sample_set[n_samples];
115
+  // Working variables
116
+  float mean = 0.0,     // The average of all points so far, used to calculate deviation
117
+        sigma = 0.0,    // Standard deviation of all points so far
118
+        min = 99999.9,  // Smallest value sampled so far
119
+        max = -99999.9, // Largest value sampled so far
120
+        sample_set[n_samples];  // Storage for sampled values
121
+
122
+  auto dev_report = [](const bool verbose, const float &mean, const float &sigma, const float &min, const float &max, const bool final=false) {
123
+    if (verbose) {
124
+      SERIAL_ECHOPAIR_F("Mean: ", mean, 6);
125
+      if (!final) SERIAL_ECHOPAIR_F(" Sigma: ", sigma, 6);
126
+      SERIAL_ECHOPAIR_F(" Min: ", min, 3);
127
+      SERIAL_ECHOPAIR_F(" Max: ", max, 3);
128
+      SERIAL_ECHOPAIR_F(" Range: ", max-min, 3);
129
+      if (final) SERIAL_EOL();
130
+    }
131
+    if (final) {
132
+      SERIAL_ECHOLNPAIR_F("Standard Deviation: ", sigma, 6);
133
+      SERIAL_EOL();
134
+    }
135
+  };
121 136
 
122 137
   // Move to the first point, deploy, and probe
123
-  const float t = probe.probe_at_point(probe_pos, raise_after, verbose_level);
138
+  const float t = probe.probe_at_point(test_position, raise_after, verbose_level);
124 139
   bool probing_good = !isnan(t);
125 140
 
126 141
   if (probing_good) {
127 142
     randomSeed(millis());
128 143
 
144
+    float sample_sum = 0.0;
145
+
129 146
     LOOP_L_N(n, n_samples) {
130 147
       #if HAS_SPI_LCD
131 148
         // Display M48 progress in the status bar
132 149
         ui.status_printf_P(0, PSTR(S_FMT ": %d/%d"), GET_TEXT(MSG_M48_POINT), int(n + 1), int(n_samples));
133 150
       #endif
151
+
152
+      // When there are "legs" of movement move around the point before probing
134 153
       if (n_legs) {
154
+
155
+        // Pick a random direction, starting angle, and radius
135 156
         const int dir = (random(0, 10) > 5.0) ? -1 : 1;  // clockwise or counter clockwise
136 157
         float angle = random(0, 360);
137 158
         const float radius = random(
@@ -142,48 +163,51 @@ void GcodeSuite::M48() {
142 163
             int(5), int(0.125 * _MIN(X_BED_SIZE, Y_BED_SIZE))
143 164
           #endif
144 165
         );
145
-
146 166
         if (verbose_level > 3) {
147 167
           SERIAL_ECHOPAIR("Start radius:", radius, " angle:", angle, " dir:");
148 168
           if (dir > 0) SERIAL_CHAR('C');
149 169
           SERIAL_ECHOLNPGM("CW");
150 170
         }
151 171
 
172
+        // Move from leg to leg in rapid succession
152 173
         LOOP_L_N(l, n_legs - 1) {
153
-          float delta_angle;
154 174
 
175
+          // Move some distance around the perimeter
176
+          float delta_angle;
155 177
           if (schizoid_flag) {
156
-            // The points of a 5 point star are 72 degrees apart.  We need to
157
-            // skip a point and go to the next one on the star.
178
+            // The points of a 5 point star are 72 degrees apart.
179
+            // Skip a point and go to the next one on the star.
158 180
             delta_angle = dir * 2.0 * 72.0;
159 181
           }
160 182
           else {
161
-            // If we do this line, we are just trying to move further
162
-            // around the circle.
163
-            delta_angle = dir * (float) random(25, 45);
183
+            // Just move further along the perimeter.
184
+            delta_angle = dir * (float)random(25, 45);
164 185
           }
165
-
166 186
           angle += delta_angle;
167
-          while (angle > 360.0) angle -= 360.0; // We probably do not need to keep the angle between 0 and 2*PI, but the
168
-                                                // Arduino documentation says the trig functions should not be given values
169
-          while (angle < 0.0) angle += 360.0;   // outside of this range.   It looks like they behave correctly with
170
-                                                // numbers outside of the range, but just to be safe we clamp them.
171 187
 
172
-          const xy_pos_t noz_pos = probe_pos - probe.offset_xy;
173
-          next_pos.set(noz_pos.x + cos(RADIANS(angle)) * radius,
174
-                       noz_pos.y + sin(RADIANS(angle)) * radius);
188
+          // Trig functions work without clamping, but just to be safe...
189
+          while (angle > 360.0) angle -= 360.0;
190
+          while (angle < 0.0) angle += 360.0;
175 191
 
176
-          #if DISABLED(DELTA)
177
-            LIMIT(next_pos.x, X_MIN_POS, X_MAX_POS);
178
-            LIMIT(next_pos.y, Y_MIN_POS, Y_MAX_POS);
179
-          #else
180
-            // If we have gone out too far, we can do a simple fix and scale the numbers
181
-            // back in closer to the origin.
192
+          // Choose the next position as an offset to chosen test position
193
+          const xy_pos_t noz_pos = test_position - probe.offset_xy;
194
+          xy_pos_t next_pos = {
195
+            noz_pos.x + cos(RADIANS(angle)) * radius,
196
+            noz_pos.y + sin(RADIANS(angle)) * radius
197
+          };
198
+
199
+          #if ENABLED(DELTA)
200
+            // If the probe can't reach the point on a round bed...
201
+            // Simply scale the numbers to bring them closer to origin.
182 202
             while (!probe.can_reach(next_pos)) {
183 203
               next_pos *= 0.8f;
184 204
               if (verbose_level > 3)
185 205
                 SERIAL_ECHOLNPAIR_P(PSTR("Moving inward: X"), next_pos.x, SP_Y_STR, next_pos.y);
186 206
             }
207
+          #else
208
+            // For a rectangular bed just keep the probe in bounds
209
+            LIMIT(next_pos.x, X_MIN_POS, X_MAX_POS);
210
+            LIMIT(next_pos.y, Y_MIN_POS, Y_MAX_POS);
187 211
           #endif
188 212
 
189 213
           if (verbose_level > 3)
@@ -194,45 +218,35 @@ void GcodeSuite::M48() {
194 218
       } // n_legs
195 219
 
196 220
       // Probe a single point
197
-      sample_set[n] = probe.probe_at_point(probe_pos, raise_after, 0);
221
+      const float pz = probe.probe_at_point(test_position, raise_after, 0);
198 222
 
199 223
       // Break the loop if the probe fails
200
-      probing_good = !isnan(sample_set[n]);
224
+      probing_good = !isnan(pz);
201 225
       if (!probing_good) break;
202 226
 
203
-      /**
204
-       * Get the current mean for the data points we have so far
205
-       */
206
-      float sum = 0.0;
207
-      LOOP_LE_N(j, n) sum += sample_set[j];
208
-      mean = sum / (n + 1);
209
-
210
-      NOMORE(min, sample_set[n]);
211
-      NOLESS(max, sample_set[n]);
212
-
213
-      /**
214
-       * Now, use that mean to calculate the standard deviation for the
215
-       * data points we have so far
216
-       */
217
-      sum = 0.0;
218
-      LOOP_LE_N(j, n)
219
-        sum += sq(sample_set[j] - mean);
220
-
221
-      sigma = SQRT(sum / (n + 1));
222
-      if (verbose_level > 0) {
223
-        if (verbose_level > 1) {
224
-          SERIAL_ECHO(n + 1);
225
-          SERIAL_ECHOPAIR(" of ", int(n_samples));
226
-          SERIAL_ECHOPAIR_F(": z: ", sample_set[n], 3);
227
-          if (verbose_level > 2) {
228
-            SERIAL_ECHOPAIR_F(" mean: ", mean, 4);
229
-            SERIAL_ECHOPAIR_F(" sigma: ", sigma, 6);
230
-            SERIAL_ECHOPAIR_F(" min: ", min, 3);
231
-            SERIAL_ECHOPAIR_F(" max: ", max, 3);
232
-            SERIAL_ECHOPAIR_F(" range: ", max-min, 3);
233
-          }
234
-          SERIAL_EOL();
235
-        }
227
+      // Store the new sample
228
+      sample_set[n] = pz;
229
+
230
+      // Keep track of the largest and smallest samples
231
+      NOMORE(min, pz);
232
+      NOLESS(max, pz);
233
+
234
+      // Get the mean value of all samples thus far
235
+      sample_sum += pz;
236
+      mean = sample_sum / (n + 1);
237
+
238
+      // Calculate the standard deviation so far.
239
+      // The value after the last sample will be the final output.
240
+      float dev_sum = 0.0;
241
+      LOOP_LE_N(j, n) dev_sum += sq(sample_set[j] - mean);
242
+      sigma = SQRT(dev_sum / (n + 1));
243
+
244
+      if (verbose_level > 1) {
245
+        SERIAL_ECHO(n + 1);
246
+        SERIAL_ECHOPAIR(" of ", int(n_samples));
247
+        SERIAL_ECHOPAIR_F(": z: ", pz, 3);
248
+        dev_report(verbose_level > 2, mean, sigma, min, max);
249
+        SERIAL_EOL();
236 250
       }
237 251
 
238 252
     } // n_samples loop
@@ -242,16 +256,7 @@ void GcodeSuite::M48() {
242 256
 
243 257
   if (probing_good) {
244 258
     SERIAL_ECHOLNPGM("Finished!");
245
-
246
-    if (verbose_level > 0) {
247
-      SERIAL_ECHOPAIR_F("Mean: ", mean, 6);
248
-      SERIAL_ECHOPAIR_F(" Min: ", min, 3);
249
-      SERIAL_ECHOPAIR_F(" Max: ", max, 3);
250
-      SERIAL_ECHOLNPAIR_F(" Range: ", max-min, 3);
251
-    }
252
-
253
-    SERIAL_ECHOLNPAIR_F("Standard Deviation: ", sigma, 6);
254
-    SERIAL_EOL();
259
+    dev_report(verbose_level > 0, mean, sigma, min, max, true);
255 260
 
256 261
     #if HAS_SPI_LCD
257 262
       // Display M48 results in the status bar

+ 1
- 0
Marlin/src/lcd/language/language_en.h 查看文件

@@ -124,6 +124,7 @@ namespace Language_en {
124 124
   PROGMEM Language_Str MSG_USER_MENU                       = _UxGT("Custom Commands");
125 125
   PROGMEM Language_Str MSG_M48_TEST                        = _UxGT("M48 Probe Test");
126 126
   PROGMEM Language_Str MSG_M48_POINT                       = _UxGT("M48 Point");
127
+  PROGMEM Language_Str MSG_M48_OUT_OF_BOUNDS               = _UxGT("Probe out of bounds");
127 128
   PROGMEM Language_Str MSG_M48_DEVIATION                   = _UxGT("Deviation");
128 129
   PROGMEM Language_Str MSG_IDEX_MENU                       = _UxGT("IDEX Mode");
129 130
   PROGMEM Language_Str MSG_OFFSETS_MENU                    = _UxGT("Tool Offsets");

+ 1
- 0
Marlin/src/lcd/language/language_it.h 查看文件

@@ -122,6 +122,7 @@ namespace Language_it {
122 122
   PROGMEM Language_Str MSG_LCD_TILTING_MESH                = _UxGT("Punto inclinaz.");
123 123
   PROGMEM Language_Str MSG_M48_TEST                        = _UxGT("Test sonda M48");
124 124
   PROGMEM Language_Str MSG_M48_POINT                       = _UxGT("Punto M48");
125
+  PROGMEM Language_Str MSG_M48_OUT_OF_BOUNDS               = _UxGT("Sonda oltre i limiti");
125 126
   PROGMEM Language_Str MSG_M48_DEVIATION                   = _UxGT("Deviazione");
126 127
   PROGMEM Language_Str MSG_IDEX_MENU                       = _UxGT("Modo IDEX");
127 128
   PROGMEM Language_Str MSG_OFFSETS_MENU                    = _UxGT("Strumenti Offsets");

+ 1
- 1
Marlin/src/lcd/menu/menu_motion.cpp 查看文件

@@ -386,7 +386,7 @@ void menu_motion() {
386 386
   #endif
387 387
 
388 388
   #if ENABLED(Z_MIN_PROBE_REPEATABILITY_TEST)
389
-    GCODES_ITEM(MSG_M48_TEST, PSTR("G28\nM48 P10"));
389
+    GCODES_ITEM(MSG_M48_TEST, PSTR("G28 O\nM48 P10"));
390 390
   #endif
391 391
 
392 392
   //

Loading…
取消
儲存