Browse Source

Merge pull request #673 from fsantini/ErikZalm

Improvements to the auto bed leveling feature
alexborro 11 years ago
parent
commit
89a304fd98
7 changed files with 2116 additions and 56 deletions
  1. 9
    0
      Marlin/Configuration.h
  2. 127
    5
      Marlin/Marlin_main.cpp
  3. 1
    1
      Marlin/planner.cpp
  4. 1932
    0
      Marlin/qr_solve.cpp
  5. 22
    0
      Marlin/qr_solve.h
  6. 23
    48
      Marlin/vector_3.cpp
  7. 2
    2
      Marlin/vector_3.h

+ 9
- 0
Marlin/Configuration.h View File

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

+ 127
- 5
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"
@@ -802,6 +805,31 @@ static void axis_is_at_home(int axis) {
802 805
 }
803 806
 
804 807
 #ifdef ENABLE_AUTO_BED_LEVELING
808
+#ifdef ACCURATE_BED_LEVELING
809
+static void set_bed_level_equation_lsq(double *plane_equation_coefficients)
810
+{
811
+    vector_3 planeNormal = vector_3(-plane_equation_coefficients[0], -plane_equation_coefficients[1], 1);
812
+    planeNormal.debug("planeNormal");
813
+    plan_bed_level_matrix = matrix_3x3::create_look_at(planeNormal);
814
+    //bedLevel.debug("bedLevel");
815
+
816
+    //plan_bed_level_matrix.debug("bed level before");
817
+    //vector_3 uncorrected_position = plan_get_position_mm();
818
+    //uncorrected_position.debug("position before");
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;
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
805 833
 static void set_bed_level_equation(float z_at_xLeft_yFront, float z_at_xRight_yFront, float z_at_xLeft_yBack) {
806 834
     plan_bed_level_matrix.set_to_identity();
807 835
 
@@ -811,11 +839,11 @@ static void set_bed_level_equation(float z_at_xLeft_yFront, float z_at_xRight_yF
811 839
 
812 840
     vector_3 xPositive = (xRightyFront - xLeftyFront).get_normal();
813 841
     vector_3 yPositive = (xLeftyBack - xLeftyFront).get_normal();
814
-    vector_3 planeNormal = vector_3::cross(yPositive, xPositive).get_normal();
842
+    vector_3 planeNormal = vector_3::cross(xPositive, yPositive).get_normal();
815 843
 
816 844
     //planeNormal.debug("planeNormal");
817 845
     //yPositive.debug("yPositive");
818
-    matrix_3x3 bedLevel = matrix_3x3::create_look_at(planeNormal, yPositive);
846
+    plan_bed_level_matrix = matrix_3x3::create_look_at(planeNormal);
819 847
     //bedLevel.debug("bedLevel");
820 848
 
821 849
     //plan_bed_level_matrix.debug("bed level before");
@@ -823,7 +851,6 @@ static void set_bed_level_equation(float z_at_xLeft_yFront, float z_at_xRight_yF
823 851
     //uncorrected_position.debug("position before");
824 852
 
825 853
     // and set our bed level equation to do the right thing
826
-    plan_bed_level_matrix = matrix_3x3::create_inverse(bedLevel);
827 854
     //plan_bed_level_matrix.debug("bed level after");
828 855
 
829 856
     vector_3 corrected_position = plan_get_position();
@@ -837,6 +864,7 @@ static void set_bed_level_equation(float z_at_xLeft_yFront, float z_at_xRight_yF
837 864
 
838 865
     plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
839 866
 }
867
+#endif // ACCURATE_BED_LEVELING
840 868
 
841 869
 static void run_z_probe() {
842 870
     plan_bed_level_matrix.set_to_identity();
@@ -1325,7 +1353,99 @@ void process_commands()
1325 1353
             setup_for_endstop_move();
1326 1354
 
1327 1355
             feedrate = homing_feedrate[Z_AXIS];
1328
-
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
+            bool zig = true;
1376
+            
1377
+            for (int yProbe=FRONT_PROBE_BED_POSITION; yProbe <= BACK_PROBE_BED_POSITION; yProbe += yGridSpacing)
1378
+            {
1379
+              int xProbe, xInc;
1380
+              if (zig)
1381
+              {
1382
+                xProbe = LEFT_PROBE_BED_POSITION;
1383
+                //xEnd = RIGHT_PROBE_BED_POSITION;
1384
+                xInc = xGridSpacing;
1385
+                zig = false;
1386
+              } else // zag
1387
+              {
1388
+                xProbe = RIGHT_PROBE_BED_POSITION;
1389
+                //xEnd = LEFT_PROBE_BED_POSITION;
1390
+                xInc = -xGridSpacing;
1391
+                zig = true;
1392
+              }
1393
+              
1394
+              for (int xCount=0; xCount < ACCURATE_BED_LEVELING_POINTS; xCount++)
1395
+              {
1396
+                if (probePointCounter == 0)
1397
+                {
1398
+                  // raise before probing
1399
+                  do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], Z_RAISE_BEFORE_PROBING);
1400
+                } else
1401
+                {               
1402
+                  // raise extruder
1403
+                  do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS);
1404
+                }
1405
+                
1406
+                
1407
+                do_blocking_move_to(xProbe - X_PROBE_OFFSET_FROM_EXTRUDER, yProbe - Y_PROBE_OFFSET_FROM_EXTRUDER, current_position[Z_AXIS]);
1408
+    
1409
+                engage_z_probe();   // Engage Z Servo endstop if available
1410
+                run_z_probe();
1411
+                eqnBVector[probePointCounter] = current_position[Z_AXIS];
1412
+                retract_z_probe();
1413
+    
1414
+                SERIAL_PROTOCOLPGM("Bed x: ");
1415
+                SERIAL_PROTOCOL(xProbe);
1416
+                SERIAL_PROTOCOLPGM(" y: ");
1417
+                SERIAL_PROTOCOL(yProbe);
1418
+                SERIAL_PROTOCOLPGM(" z: ");
1419
+                SERIAL_PROTOCOL(current_position[Z_AXIS]);
1420
+                SERIAL_PROTOCOLPGM("\n");
1421
+                
1422
+                eqnAMatrix[probePointCounter + 0*ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS] = xProbe;
1423
+                eqnAMatrix[probePointCounter + 1*ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS] = yProbe;
1424
+                eqnAMatrix[probePointCounter + 2*ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS] = 1;
1425
+                probePointCounter++;
1426
+                xProbe += xInc;
1427
+              }
1428
+            }
1429
+            clean_up_after_endstop_move();
1430
+            
1431
+            // solve lsq problem
1432
+            double *plane_equation_coefficients = qr_solve(ACCURATE_BED_LEVELING_POINTS*ACCURATE_BED_LEVELING_POINTS, 3, eqnAMatrix, eqnBVector);
1433
+            
1434
+            SERIAL_PROTOCOLPGM("Eqn coefficients: a: ");
1435
+            SERIAL_PROTOCOL(plane_equation_coefficients[0]);
1436
+            SERIAL_PROTOCOLPGM(" b: ");
1437
+            SERIAL_PROTOCOL(plane_equation_coefficients[1]);
1438
+            SERIAL_PROTOCOLPGM(" d: ");
1439
+            SERIAL_PROTOCOLLN(plane_equation_coefficients[2]);
1440
+            
1441
+            
1442
+            set_bed_level_equation_lsq(plane_equation_coefficients);
1443
+            
1444
+            free(plane_equation_coefficients);
1445
+            
1446
+#else // ACCURATE_BED_LEVELING not defined
1447
+            
1448
+            
1329 1449
             // prob 1
1330 1450
             do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], Z_RAISE_BEFORE_PROBING);
1331 1451
             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]);
@@ -1381,7 +1501,9 @@ void process_commands()
1381 1501
             clean_up_after_endstop_move();
1382 1502
 
1383 1503
             set_bed_level_equation(z_at_xLeft_yFront, z_at_xRight_yFront, z_at_xLeft_yBack);
1384
-
1504
+         
1505
+            
1506
+#endif // ACCURATE_BED_LEVELING
1385 1507
             st_synchronize();
1386 1508
 
1387 1509
             // The following code correct the Z height difference from z-probe position and hotend tip position.

+ 1
- 1
Marlin/planner.cpp View File

@@ -942,7 +942,7 @@ vector_3 plan_get_position() {
942 942
 
943 943
 	//position.debug("in plan_get position");
944 944
 	//plan_bed_level_matrix.debug("in plan_get bed_level");
945
-	matrix_3x3 inverse = matrix_3x3::create_inverse(plan_bed_level_matrix);
945
+	matrix_3x3 inverse = matrix_3x3::transpose(plan_bed_level_matrix);
946 946
 	//inverse.debug("in plan_get inverse");
947 947
 	position.apply_rotation(inverse);
948 948
 	//position.debug("after rotation");

+ 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

+ 23
- 48
Marlin/vector_3.cpp View File

@@ -127,57 +127,32 @@ void matrix_3x3::set_to_identity()
127 127
 	matrix[6] = 0; matrix[7] = 0; matrix[8] = 1;
128 128
 }
129 129
 
130
-matrix_3x3 matrix_3x3::create_look_at(vector_3 target, vector_3 up)
131
-{
132
-    // There are lots of examples of look at code on the internet that don't do all these noramize and also find the position
133
-    // through several dot products.  The problem with them is that they have a bit of error in that all the vectors arn't normal and need to be.
134
-    vector_3 z_row = vector_3(-target.x, -target.y, -target.z).get_normal();
135
-    vector_3 x_row = vector_3::cross(up, z_row).get_normal();
136
-    vector_3 y_row = vector_3::cross(z_row, x_row).get_normal();
137
-
138
-    //x_row.debug("x_row");
139
-    //y_row.debug("y_row");
140
-    //z_row.debug("z_row");
141
-    
142
-    matrix_3x3 rot = matrix_3x3::create_from_rows(vector_3(x_row.x, y_row.x, z_row.x),
143
-                                vector_3(x_row.y, y_row.y, z_row.y),
144
-                                vector_3(x_row.z, y_row.z, z_row.z));
145
-
146
-    //rot.debug("rot");
130
+matrix_3x3 matrix_3x3::create_look_at(vector_3 target)
131
+{
132
+    vector_3 z_row = target.get_normal();
133
+    vector_3 x_row = vector_3(1, 0, -target.x/target.z).get_normal();
134
+    vector_3 y_row = vector_3(0, 1, -target.y/target.z).get_normal();
135
+
136
+   // x_row.debug("x_row");
137
+   // y_row.debug("y_row");
138
+   // z_row.debug("z_row");
139
+
140
+ 
141
+     // create the matrix already correctly transposed
142
+    matrix_3x3 rot = matrix_3x3::create_from_rows(x_row, y_row, z_row);
143
+
144
+ //   rot.debug("rot");
147 145
     return rot;
148 146
 }
149 147
 
150
-matrix_3x3 matrix_3x3::create_inverse(matrix_3x3 original)
151
-{
152
-	//original.debug("original");
153
-	float* A = original.matrix;
154
-	float determinant = 
155
-		+ A[0 * 3 + 0] * (A[1 * 3 + 1] * A[2 * 3 + 2] - A[2 * 3 + 1] * A[1 * 3 + 2])
156
-		- A[0 * 3 + 1] * (A[1 * 3 + 0] * A[2 * 3 + 2] - A[1 * 3 + 2] * A[2 * 3 + 0])
157
-		+ A[0 * 3 + 2] * (A[1 * 3 + 0] * A[2 * 3 + 1] - A[1 * 3 + 1] * A[2 * 3 + 0]);
158
-	matrix_3x3 inverse;
159
-	inverse.matrix[0 * 3 + 0] = +(A[1 * 3 + 1] * A[2 * 3 + 2] - A[2 * 3 + 1] * A[1 * 3 + 2]) / determinant;
160
-	inverse.matrix[0 * 3 + 1] = -(A[0 * 3 + 1] * A[2 * 3 + 2] - A[0 * 3 + 2] * A[2 * 3 + 1]) / determinant;
161
-	inverse.matrix[0 * 3 + 2] = +(A[0 * 3 + 1] * A[1 * 3 + 2] - A[0 * 3 + 2] * A[1 * 3 + 1]) / determinant;
162
-	inverse.matrix[1 * 3 + 0] = -(A[1 * 3 + 0] * A[2 * 3 + 2] - A[1 * 3 + 2] * A[2 * 3 + 0]) / determinant;
163
-	inverse.matrix[1 * 3 + 1] = +(A[0 * 3 + 0] * A[2 * 3 + 2] - A[0 * 3 + 2] * A[2 * 3 + 0]) / determinant;
164
-	inverse.matrix[1 * 3 + 2] = -(A[0 * 3 + 0] * A[1 * 3 + 2] - A[1 * 3 + 0] * A[0 * 3 + 2]) / determinant;
165
-	inverse.matrix[2 * 3 + 0] = +(A[1 * 3 + 0] * A[2 * 3 + 1] - A[2 * 3 + 0] * A[1 * 3 + 1]) / determinant;
166
-	inverse.matrix[2 * 3 + 1] = -(A[0 * 3 + 0] * A[2 * 3 + 1] - A[2 * 3 + 0] * A[0 * 3 + 1]) / determinant;
167
-	inverse.matrix[2 * 3 + 2] = +(A[0 * 3 + 0] * A[1 * 3 + 1] - A[1 * 3 + 0] * A[0 * 3 + 1]) / determinant;
168
-
169
-	vector_3 row0 = vector_3(inverse.matrix[0 * 3 + 0], inverse.matrix[0 * 3 + 1], inverse.matrix[0 * 3 + 2]);
170
-	vector_3 row1 = vector_3(inverse.matrix[1 * 3 + 0], inverse.matrix[1 * 3 + 1], inverse.matrix[1 * 3 + 2]);
171
-	vector_3 row2 = vector_3(inverse.matrix[2 * 3 + 0], inverse.matrix[2 * 3 + 1], inverse.matrix[2 * 3 + 2]);
172
-
173
-    row0.normalize();
174
-    row1.normalize();
175
-    row2.normalize();
176
-
177
-	inverse = matrix_3x3::create_from_rows(row0, row1, row2);
178
-
179
-	//inverse.debug("inverse");
180
-	return inverse;
148
+
149
+matrix_3x3 matrix_3x3::transpose(matrix_3x3 original)
150
+{
151
+  matrix_3x3 new_matrix;
152
+  new_matrix.matrix[0] = original.matrix[0]; new_matrix.matrix[1] = original.matrix[3]; new_matrix.matrix[2] = original.matrix[6]; 
153
+  new_matrix.matrix[3] = original.matrix[1]; new_matrix.matrix[4] = original.matrix[4]; new_matrix.matrix[5] = original.matrix[7]; 
154
+  new_matrix.matrix[6] = original.matrix[2]; new_matrix.matrix[7] = original.matrix[5]; new_matrix.matrix[8] = original.matrix[8];
155
+  return new_matrix;
181 156
 }
182 157
 
183 158
 void matrix_3x3::debug(char* title)

+ 2
- 2
Marlin/vector_3.h View File

@@ -47,8 +47,8 @@ struct matrix_3x3
47 47
 	float matrix[9];
48 48
 
49 49
 	static matrix_3x3 create_from_rows(vector_3 row_0, vector_3 row_1, vector_3 row_2);
50
-	static matrix_3x3 create_look_at(vector_3 target, vector_3 up);
51
-	static matrix_3x3 create_inverse(matrix_3x3 original);
50
+	static matrix_3x3 create_look_at(vector_3 target);
51
+	static matrix_3x3 transpose(matrix_3x3 original);
52 52
 
53 53
 	void set_to_identity();
54 54
 

Loading…
Cancel
Save