|
@@ -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
|