Browse Source

Implemented a least squares fit of the bed equation for auto bed leveling.

The code for the LSQ solver (qr_solve) is copyrighted by John Burkardt and released under LGPL here:
http://people.sc.fsu.edu/~%20jburkardt/c_src/qr_solve/qr_solve.html
(see qr_solve.cpp for further copyright information)
fsantini 11 years ago
parent
commit
cc2925b705
4 changed files with 2075 additions and 2 deletions
  1. 9
    0
      Marlin/Configuration.h
  2. 112
    2
      Marlin/Marlin_main.cpp
  3. 1932
    0
      Marlin/qr_solve.cpp
  4. 22
    0
      Marlin/qr_solve.h

+ 9
- 0
Marlin/Configuration.h View File

@@ -366,6 +366,15 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of
366 366
     
367 367
   #endif
368 368
   
369
+  // with accurate bed leveling, the bed is sampled in a ACCURATE_BED_LEVELING_POINTSxACCURATE_BED_LEVELING_POINTS grid and least squares solution is calculated
370
+  // Note: this feature occupies 10'206 byte
371
+  #define ACCURATE_BED_LEVELING
372
+  
373
+  #ifdef ACCURATE_BED_LEVELING
374
+     // I wouldn't see a reason to go above 3 (=9 probing points on the bed)
375
+    #define ACCURATE_BED_LEVELING_POINTS 2
376
+  #endif
377
+  
369 378
 #endif
370 379
 
371 380
 

+ 112
- 2
Marlin/Marlin_main.cpp View File

@@ -31,6 +31,9 @@
31 31
 
32 32
 #ifdef ENABLE_AUTO_BED_LEVELING
33 33
 #include "vector_3.h"
34
+  #ifdef ACCURATE_BED_LEVELING
35
+    #include "qr_solve.h"
36
+  #endif
34 37
 #endif // ENABLE_AUTO_BED_LEVELING
35 38
 
36 39
 #include "ultralcd.h"
@@ -798,6 +801,35 @@ static void axis_is_at_home(int axis) {
798 801
 }
799 802
 
800 803
 #ifdef ENABLE_AUTO_BED_LEVELING
804
+#ifdef ACCURATE_BED_LEVELING
805
+static void set_bed_level_equation_lsq(double *plane_equation_coefficients)
806
+{
807
+    vector_3 planeNormal = vector_3(-plane_equation_coefficients[0], -plane_equation_coefficients[1], 1);
808
+    planeNormal.debug("planeNormal");
809
+    plan_bed_level_matrix = matrix_3x3::create_look_at(planeNormal);
810
+    //bedLevel.debug("bedLevel");
811
+
812
+    plan_bed_level_matrix.debug("bed level before");
813
+    //vector_3 uncorrected_position = plan_get_position_mm();
814
+    //uncorrected_position.debug("position before");
815
+
816
+    // and set our bed level equation to do the right thing
817
+//    plan_bed_level_matrix = matrix_3x3::create_inverse(bedLevel);
818
+//    plan_bed_level_matrix.debug("bed level after");
819
+
820
+    vector_3 corrected_position = plan_get_position();
821
+//    corrected_position.debug("position after");
822
+    current_position[X_AXIS] = corrected_position.x;
823
+    current_position[Y_AXIS] = corrected_position.y;
824
+    current_position[Z_AXIS] = corrected_position.z;
825
+
826
+    // but the bed at 0 so we don't go below it.
827
+    current_position[Z_AXIS] = -Z_PROBE_OFFSET_FROM_EXTRUDER; // in the lsq we reach here after raising the extruder due to the loop structure
828
+
829
+    plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
830
+}
831
+
832
+#else
801 833
 static void set_bed_level_equation(float z_at_xLeft_yFront, float z_at_xRight_yFront, float z_at_xLeft_yBack) {
802 834
     plan_bed_level_matrix.set_to_identity();
803 835
 
@@ -832,6 +864,7 @@ static void set_bed_level_equation(float z_at_xLeft_yFront, float z_at_xRight_yF
832 864
 
833 865
     plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
834 866
 }
867
+#endif // ACCURATE_BED_LEVELING
835 868
 
836 869
 static void run_z_probe() {
837 870
     plan_bed_level_matrix.set_to_identity();
@@ -1320,7 +1353,82 @@ void process_commands()
1320 1353
             setup_for_endstop_move();
1321 1354
 
1322 1355
             feedrate = homing_feedrate[Z_AXIS];
1323
-
1356
+#ifdef ACCURATE_BED_LEVELING
1357
+            
1358
+            int xGridSpacing = (RIGHT_PROBE_BED_POSITION - LEFT_PROBE_BED_POSITION) / (ACCURATE_BED_LEVELING_POINTS-1);
1359
+            int yGridSpacing = (BACK_PROBE_BED_POSITION - FRONT_PROBE_BED_POSITION) / (ACCURATE_BED_LEVELING_POINTS-1);
1360
+            
1361
+            
1362
+            // solve the plane equation ax + by + d = z
1363
+            // A is the matrix with rows [x y 1] for all the probed points
1364
+            // B is the vector of the Z positions
1365
+            // the normal vector to the plane is formed by the coefficients of the plane equation in the standard form, which is Vx*x+Vy*y+Vz*z+d = 0
1366
+            // so Vx = -a Vy = -b Vz = 1 (we want the vector facing towards positive Z
1367
+            
1368
+            // "A" matrix of the linear system of equations
1369
+            double eqnAMatrix[ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS*3];
1370
+            // "B" vector of Z points
1371
+            double eqnBVector[ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS];
1372
+            
1373
+            
1374
+            int probePointCounter = 0;
1375
+            
1376
+            for (int xProbe=LEFT_PROBE_BED_POSITION; xProbe <= RIGHT_PROBE_BED_POSITION; xProbe += xGridSpacing)
1377
+            {
1378
+              for (int yProbe=FRONT_PROBE_BED_POSITION; yProbe <= BACK_PROBE_BED_POSITION; yProbe += yGridSpacing)
1379
+              {
1380
+                if (probePointCounter == 0)
1381
+                {
1382
+                  // raise before probing
1383
+                  do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], Z_RAISE_BEFORE_PROBING);
1384
+                } else
1385
+                {               
1386
+                  // raise extruder
1387
+                  do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS);
1388
+                }
1389
+                
1390
+                
1391
+                do_blocking_move_to(xProbe - X_PROBE_OFFSET_FROM_EXTRUDER, yProbe - Y_PROBE_OFFSET_FROM_EXTRUDER, current_position[Z_AXIS]);
1392
+    
1393
+                engage_z_probe();   // Engage Z Servo endstop if available
1394
+                run_z_probe();
1395
+                eqnBVector[probePointCounter] = current_position[Z_AXIS];
1396
+                retract_z_probe();
1397
+    
1398
+                SERIAL_PROTOCOLPGM("Bed x: ");
1399
+                SERIAL_PROTOCOL(xProbe);
1400
+                SERIAL_PROTOCOLPGM(" y: ");
1401
+                SERIAL_PROTOCOL(yProbe);
1402
+                SERIAL_PROTOCOLPGM(" z: ");
1403
+                SERIAL_PROTOCOL(current_position[Z_AXIS]);
1404
+                SERIAL_PROTOCOLPGM("\n");
1405
+                
1406
+                eqnAMatrix[probePointCounter + 0*ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS] = xProbe;
1407
+                eqnAMatrix[probePointCounter + 1*ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS] = yProbe;
1408
+                eqnAMatrix[probePointCounter + 2*ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS] = 1;
1409
+                probePointCounter++;
1410
+              }
1411
+            }
1412
+            clean_up_after_endstop_move();
1413
+            
1414
+            // solve lsq problem
1415
+            double *plane_equation_coefficients = qr_solve(ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS, 3, eqnAMatrix, eqnBVector);
1416
+            
1417
+            SERIAL_PROTOCOLPGM("Eqn coefficients: a: ");
1418
+            SERIAL_PROTOCOL(plane_equation_coefficients[0]);
1419
+            SERIAL_PROTOCOLPGM(" b: ");
1420
+            SERIAL_PROTOCOL(plane_equation_coefficients[1]);
1421
+            SERIAL_PROTOCOLPGM(" d: ");
1422
+            SERIAL_PROTOCOLLN(plane_equation_coefficients[2]);
1423
+            
1424
+            
1425
+            set_bed_level_equation_lsq(plane_equation_coefficients);
1426
+            
1427
+            free(plane_equation_coefficients);
1428
+            
1429
+#else // ACCURATE_BED_LEVELING not defined
1430
+            
1431
+            
1324 1432
             // prob 1
1325 1433
             do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], Z_RAISE_BEFORE_PROBING);
1326 1434
             do_blocking_move_to(LEFT_PROBE_BED_POSITION - X_PROBE_OFFSET_FROM_EXTRUDER, BACK_PROBE_BED_POSITION - Y_PROBE_OFFSET_FROM_EXTRUDER, current_position[Z_AXIS]);
@@ -1376,7 +1484,9 @@ void process_commands()
1376 1484
             clean_up_after_endstop_move();
1377 1485
 
1378 1486
             set_bed_level_equation(z_at_xLeft_yFront, z_at_xRight_yFront, z_at_xLeft_yBack);
1379
-
1487
+         
1488
+            
1489
+#endif // ACCURATE_BED_LEVELING
1380 1490
             st_synchronize();            
1381 1491
 
1382 1492
             // The following code correct the Z height difference from z-probe position and hotend tip position.

+ 1932
- 0
Marlin/qr_solve.cpp
File diff suppressed because it is too large
View File


+ 22
- 0
Marlin/qr_solve.h View File

@@ -0,0 +1,22 @@
1
+#include "Configuration.h"
2
+
3
+#ifdef ACCURATE_BED_LEVELING
4
+
5
+void daxpy ( int n, double da, double dx[], int incx, double dy[], int incy );
6
+double ddot ( int n, double dx[], int incx, double dy[], int incy );
7
+double dnrm2 ( int n, double x[], int incx );
8
+void dqrank ( double a[], int lda, int m, int n, double tol, int *kr, 
9
+  int jpvt[], double qraux[] );
10
+void dqrdc ( double a[], int lda, int n, int p, double qraux[], int jpvt[], 
11
+  double work[], int job );
12
+int dqrls ( double a[], int lda, int m, int n, double tol, int *kr, double b[], 
13
+  double x[], double rsd[], int jpvt[], double qraux[], int itask );
14
+void dqrlss ( double a[], int lda, int m, int n, int kr, double b[], double x[], 
15
+  double rsd[], int jpvt[], double qraux[] );
16
+int dqrsl ( double a[], int lda, int n, int k, double qraux[], double y[], 
17
+  double qy[], double qty[], double b[], double rsd[], double ab[], int job );
18
+void dscal ( int n, double sa, double x[], int incx );
19
+void dswap ( int n, double x[], int incx, double y[], int incy );
20
+double *qr_solve ( int m, int n, double a[], double b[] );
21
+
22
+#endif

Loading…
Cancel
Save