ソースを参照

UBL G29 -P3.1 smart fill (#6823)

* UBL G29 -P3.1 mesh fill with distance-weighted least squares fit.

* Back to original -O0 on G29 for now.
oldmcg 7年前
コミット
48f7652143
4個のファイルの変更135行の追加27行の削除
  1. 4
    19
      Marlin/least_squares_fit.cpp
  2. 37
    4
      Marlin/least_squares_fit.h
  3. 6
    0
      Marlin/macros.h
  4. 88
    4
      Marlin/ubl_G29.cpp

+ 4
- 19
Marlin/least_squares_fit.cpp ファイルの表示

@@ -41,27 +41,12 @@
41 41
 
42 42
 #include "least_squares_fit.h"
43 43
 
44
-void incremental_LSF_reset(struct linear_fit_data *lsf) {
45
-  memset(lsf, 0, sizeof(linear_fit_data));
46
-}
44
+int finish_incremental_LSF(struct linear_fit_data *lsf) {
47 45
 
48
-void incremental_LSF(struct linear_fit_data *lsf, float x, float y, float z) {
49
-  lsf->xbar += x;
50
-  lsf->ybar += y;
51
-  lsf->zbar += z;
52
-  lsf->x2bar += sq(x);
53
-  lsf->y2bar += sq(y);
54
-  lsf->z2bar += sq(z);
55
-  lsf->xybar += x * y;
56
-  lsf->xzbar += x * z;
57
-  lsf->yzbar += y * z;
58
-  lsf->max_absx = max(fabs(x), lsf->max_absx);
59
-  lsf->max_absy = max(fabs(y), lsf->max_absy);
60
-  lsf->n++;
61
-}
46
+  const float N = lsf->N;
62 47
 
63
-int finish_incremental_LSF(struct linear_fit_data *lsf) {
64
-  const float N = (float)lsf->n;
48
+  if (N == 0.0)
49
+    return 1;
65 50
 
66 51
   lsf->xbar /= N;
67 52
   lsf->ybar /= N;

+ 37
- 4
Marlin/least_squares_fit.h ファイルの表示

@@ -41,16 +41,49 @@
41 41
 #include <math.h>
42 42
 
43 43
 struct linear_fit_data {
44
-  int n;
45 44
   float xbar, ybar, zbar,
46 45
         x2bar, y2bar, z2bar,
47 46
         xybar, xzbar, yzbar,
48 47
         max_absx, max_absy,
49
-        A, B, D;
48
+        A, B, D, N;
50 49
 };
51 50
 
52
-void incremental_LSF_reset(struct linear_fit_data *);
53
-void incremental_LSF(struct linear_fit_data *, float x, float y, float z);
51
+void inline incremental_LSF_reset(struct linear_fit_data *lsf) {
52
+  memset(lsf, 0, sizeof(linear_fit_data));
53
+}
54
+
55
+void inline incremental_WLSF(struct linear_fit_data *lsf, float x, float y, float z, float w) {
56
+  // weight each accumulator by factor w, including the "number" of samples
57
+  // (analagous to calling inc_LSF twice with same values to weight it by 2X)
58
+  lsf->xbar  += w * x;
59
+  lsf->ybar  += w * y;
60
+  lsf->zbar  += w * z;
61
+  lsf->x2bar += w * x * x;  // don't use sq(x) -- let compiler re-use w*x four times
62
+  lsf->y2bar += w * y * y;
63
+  lsf->z2bar += w * z * z;
64
+  lsf->xybar += w * x * y;
65
+  lsf->xzbar += w * x * z;
66
+  lsf->yzbar += w * y * z;
67
+  lsf->N     += w;
68
+  lsf->max_absx = max(fabs( w * x ), lsf->max_absx);
69
+  lsf->max_absy = max(fabs( w * y ), lsf->max_absy);
70
+}
71
+
72
+void inline incremental_LSF(struct linear_fit_data *lsf, float x, float y, float z) {
73
+  lsf->xbar += x;
74
+  lsf->ybar += y;
75
+  lsf->zbar += z;
76
+  lsf->x2bar += sq(x);
77
+  lsf->y2bar += sq(y);
78
+  lsf->z2bar += sq(z);
79
+  lsf->xybar += x * y;
80
+  lsf->xzbar += x * z;
81
+  lsf->yzbar += y * z;
82
+  lsf->max_absx = max(fabs(x), lsf->max_absx);
83
+  lsf->max_absy = max(fabs(y), lsf->max_absy);
84
+  lsf->N += 1.0;
85
+}
86
+
54 87
 int finish_incremental_LSF(struct linear_fit_data *);
55 88
 
56 89
 #endif

+ 6
- 0
Marlin/macros.h ファイルの表示

@@ -30,6 +30,12 @@
30 30
 
31 31
 #define FORCE_INLINE __attribute__((always_inline)) inline
32 32
 
33
+#define _O0 __attribute__((optimize("O0")))
34
+#define _Os __attribute__((optimize("Os")))
35
+#define _O1 __attribute__((optimize("O1")))
36
+#define _O2 __attribute__((optimize("O2")))
37
+#define _O3 __attribute__((optimize("O3")))
38
+
33 39
 // Bracket code that shouldn't be interrupted
34 40
 #ifndef CRITICAL_SECTION_START
35 41
   #define CRITICAL_SECTION_START  unsigned char _sreg = SREG; cli();

+ 88
- 4
Marlin/ubl_G29.cpp ファイルの表示

@@ -23,8 +23,6 @@
23 23
 #include "MarlinConfig.h"
24 24
 
25 25
 #if ENABLED(AUTO_BED_LEVELING_UBL)
26
-  //#include "vector_3.h"
27
-  //#include "qr_solve.h"
28 26
 
29 27
   #include "ubl.h"
30 28
   #include "Marlin.h"
@@ -36,6 +34,8 @@
36 34
   #include <math.h>
37 35
   #include "least_squares_fit.h"
38 36
 
37
+  #define UBL_G29_P31
38
+
39 39
   extern float destination[XYZE];
40 40
   extern float current_position[XYZE];
41 41
 
@@ -55,6 +55,7 @@
55 55
   extern float probe_pt(float x, float y, bool, int);
56 56
   extern bool set_probe_deployed(bool);
57 57
   void smart_fill_mesh();
58
+  void smart_fill_wlsf(float);
58 59
   float measure_business_card_thickness(float &in_height);
59 60
   void manually_probe_remaining_mesh(const float&, const float&, const float&, const float&, const bool);
60 61
 
@@ -312,7 +313,7 @@
312 313
   extern void lcd_setstatus(const char* message, const bool persist);
313 314
   extern void lcd_setstatuspgm(const char* message, const uint8_t level);
314 315
 
315
-  void __attribute__((optimize("O0"))) gcode_G29() {
316
+  void _O0 gcode_G29() {
316 317
 
317 318
     if (!settings.calc_num_meshes()) {
318 319
       SERIAL_PROTOCOLLNPGM("?You need to enable your EEPROM and initialize it");
@@ -529,7 +530,28 @@
529 530
               }
530 531
             }
531 532
           } else {
532
-            smart_fill_mesh(); // Do a 'Smart' fill using nearby known values
533
+            const float cvf = code_value_float();
534
+            switch( (int)truncf( cvf * 10.0 ) - 30 ) {   // 3.1 -> 1
535
+              #if ENABLED(UBL_G29_P31)
536
+                case 1: {
537
+
538
+                  // P3.1  use least squares fit to fill missing mesh values
539
+                  // P3.10 zero weighting for distance, all grid points equal, best fit tilted plane
540
+                  // P3.11 10X weighting for nearest grid points versus farthest grid points
541
+                  // P3.12 100X distance weighting
542
+                  // P3.13 1000X distance weighting, approaches simple average of nearest points
543
+
544
+                  const float weight_power  = (cvf - 3.10) * 100.0;  // 3.12345 -> 2.345
545
+                  const float weight_factor = weight_power ? pow( 10.0, weight_power ) : 0;
546
+                  smart_fill_wlsf( weight_factor );
547
+                }
548
+                break;
549
+              #endif
550
+              case 0:   // P3 or P3.0
551
+              default:  // and anything P3.x that's not P3.1
552
+                smart_fill_mesh();  // Do a 'Smart' fill using nearby known values
553
+                break;
554
+            }
533 555
           }
534 556
           break;
535 557
         }
@@ -1694,4 +1716,66 @@
1694 1716
     #endif
1695 1717
   }
1696 1718
 
1719
+  #if ENABLED(UBL_G29_P31)
1720
+
1721
+    // Note: using optimize("O2") for this routine results in smaller
1722
+    // codegen than default optimize("Os") on A2560.
1723
+
1724
+    void _O2 smart_fill_wlsf( float weight_factor ) {
1725
+
1726
+      // For each undefined mesh point, compute a distance-weighted least squares fit
1727
+      // from all the originally populated mesh points, weighted toward the point
1728
+      // being extrapolated so that nearby points will have greater influence on
1729
+      // the point being extrapolated.  Then extrapolate the mesh point from WLSF.
1730
+
1731
+      static_assert( GRID_MAX_POINTS_Y <= 16, "GRID_MAX_POINTS_Y too big" );
1732
+      uint16_t bitmap[GRID_MAX_POINTS_X] = {0};
1733
+      struct linear_fit_data lsf_results;
1734
+
1735
+      SERIAL_ECHOPGM("Extrapolating mesh...");
1736
+
1737
+      const float weight_scaled = weight_factor * max(MESH_X_DIST, MESH_Y_DIST);
1738
+
1739
+      for (uint8_t jx = 0; jx < GRID_MAX_POINTS_X; jx++) {
1740
+        for (uint8_t jy = 0; jy < GRID_MAX_POINTS_Y; jy++) {
1741
+          if ( !isnan( ubl.z_values[jx][jy] )) {
1742
+            bitmap[jx] |= (uint16_t)1 << jy;
1743
+          }
1744
+        }
1745
+      }
1746
+
1747
+      for (uint8_t ix = 0; ix < GRID_MAX_POINTS_X; ix++) {
1748
+        const float px = pgm_read_float(&(ubl.mesh_index_to_xpos[ix]));
1749
+        for (uint8_t iy = 0; iy < GRID_MAX_POINTS_Y; iy++) {
1750
+          const float py = pgm_read_float(&(ubl.mesh_index_to_ypos[iy]));
1751
+          if ( isnan( ubl.z_values[ix][iy] )) {
1752
+            // undefined mesh point at (px,py), compute weighted LSF from original valid mesh points.
1753
+            incremental_LSF_reset(&lsf_results);
1754
+            for (uint8_t jx = 0; jx < GRID_MAX_POINTS_X; jx++) {
1755
+              const float rx = pgm_read_float(&(ubl.mesh_index_to_xpos[jx]));
1756
+              for (uint8_t jy = 0; jy < GRID_MAX_POINTS_Y; jy++) {
1757
+                if ( bitmap[jx] & (uint16_t)1 << jy ) {
1758
+                  const float ry = pgm_read_float(&(ubl.mesh_index_to_ypos[jy]));
1759
+                  const float rz = ubl.z_values[jx][jy];
1760
+                  const float w  = 1.0 + weight_scaled / HYPOT((rx - px),(ry - py));
1761
+                  incremental_WLSF(&lsf_results, rx, ry, rz, w);
1762
+                }
1763
+              }
1764
+            }
1765
+            if (finish_incremental_LSF(&lsf_results)) {
1766
+              SERIAL_ECHOLNPGM("Insufficient data");
1767
+              return;
1768
+            }
1769
+            const float ez = -lsf_results.D - lsf_results.A * px - lsf_results.B * py;
1770
+            ubl.z_values[ix][iy] = ez;
1771
+            idle();   // housekeeping
1772
+          }
1773
+        }
1774
+      }
1775
+
1776
+      SERIAL_ECHOLNPGM("done");
1777
+    }
1778
+  #endif // UBL_G29_P31
1779
+
1780
+
1697 1781
 #endif // AUTO_BED_LEVELING_UBL

読み込み中…
キャンセル
保存