Explorar el Código

Bed Auto Leveling feature

Check the Readme for instruction how to enable and configure the feature
Alex Borro hace 10 años
padre
commit
253dfc4bc1
Se han modificado 12 ficheros con 806 adiciones y 4 borrados
  1. 37
    0
      Marlin/Configuration.h
  2. 52
    0
      Marlin/Marlin.ino
  3. 302
    1
      Marlin/Marlin_main.cpp
  4. 3
    0
      Marlin/Servo.cpp
  5. 3
    0
      Marlin/Servo.h
  6. 39
    0
      Marlin/planner.cpp
  7. 22
    0
      Marlin/planner.h
  8. 8
    0
      Marlin/stepper.cpp
  9. 8
    3
      Marlin/stepper.h
  10. 202
    0
      Marlin/vector_3.cpp
  11. 62
    0
      Marlin/vector_3.h
  12. 68
    0
      README.md

+ 37
- 0
Marlin/Configuration.h Ver fichero

@@ -292,13 +292,50 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of
292 292
 
293 293
 #define min_software_endstops true // If true, axis won't move to coordinates less than HOME_POS.
294 294
 #define max_software_endstops true  // If true, axis won't move to coordinates greater than the defined lengths below.
295
+
296
+//============================= Bed Auto Leveling ===========================
297
+
298
+//#define ENABLE_AUTO_BED_LEVELING // Delete the comment to enable (remove // at the start of the line)
299
+
300
+#ifdef ENABLE_AUTO_BED_LEVELING
301
+
302
+  // these are the positions on the bed to do the probing
303
+  #define LEFT_PROBE_BED_POSITION 15
304
+  #define RIGHT_PROBE_BED_POSITION 170
305
+  #define BACK_PROBE_BED_POSITION 180
306
+  #define FRONT_PROBE_BED_POSITION 20
307
+
308
+  // these are the offsets to the prob relative to the extruder tip (Hotend - Probe)
309
+  #define X_PROBE_OFFSET_FROM_EXTRUDER -25
310
+  #define Y_PROBE_OFFSET_FROM_EXTRUDER -29
311
+  #define Z_PROBE_OFFSET_FROM_EXTRUDER -12.35
312
+  
313
+  #define XY_TRAVEL_SPEED 8000         // X and Y axis travel speed between probes, in mm/min
314
+  
315
+  #define Z_RAISE_BEFORE_PROBING 15    //How much the extruder will be raised before traveling to the first probing point.
316
+  #define Z_RAISE_BETWEEN_PROBINGS 5  //How much the extruder will be raised when traveling from between next probing points
317
+
318
+
319
+  //If defined, the Probe servo will be turned on only during movement and then turned off to avoid jerk
320
+  //The value is the delay to turn the servo off after powered on - depends on the servo speed; 300ms is good value, but you can try lower it.
321
+  // You MUST HAVE the SERVO_ENDSTOPS defined to use here a value higher than zero otherwise your code will not compile.
322
+
323
+//  #define PROBE_SERVO_DEACTIVATION_DELAY 300  
324
+  
325
+#endif
326
+
295 327
 // Travel limits after homing
296 328
 #define X_MAX_POS 205
297 329
 #define X_MIN_POS 0
298 330
 #define Y_MAX_POS 205
299 331
 #define Y_MIN_POS 0
300 332
 #define Z_MAX_POS 200
333
+
334
+#ifndef ENABLE_AUTO_BED_LEVELING
301 335
 #define Z_MIN_POS 0
336
+#else
337
+#define Z_MIN_POS (-1*Z_PROBE_OFFSET_FROM_EXTRUDER)  //With Auto Bed Leveling, the Z_MIN MUST have the same distance as Z_PROBE
338
+#endif
302 339
 
303 340
 #define X_MAX_LENGTH (X_MAX_POS - X_MIN_POS)
304 341
 #define Y_MAX_LENGTH (Y_MAX_POS - Y_MIN_POS)

+ 52
- 0
Marlin/Marlin.ino Ver fichero

@@ -0,0 +1,52 @@
1
+/* -*- c++ -*- */
2
+
3
+/*
4
+    Reprap firmware based on Sprinter and grbl.
5
+ Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
6
+ 
7
+ This program is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+ 
12
+ This program is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
+ GNU General Public License for more details.
16
+ 
17
+ You should have received a copy of the GNU General Public License
18
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
+ */
20
+
21
+/*
22
+ This firmware is a mashup between Sprinter and grbl.
23
+  (https://github.com/kliment/Sprinter)
24
+  (https://github.com/simen/grbl/tree)
25
+ 
26
+ It has preliminary support for Matthew Roberts advance algorithm 
27
+    http://reprap.org/pipermail/reprap-dev/2011-May/003323.html
28
+ */
29
+
30
+/* All the implementation is done in *.cpp files to get better compatibility with avr-gcc without the Arduino IDE */
31
+/* Use this file to help the Arduino IDE find which Arduino libraries are needed and to keep documentation on GCode */
32
+
33
+#include "Configuration.h"
34
+#include "pins.h"
35
+
36
+#ifdef ULTRA_LCD
37
+  #if defined(LCD_I2C_TYPE_PCF8575)
38
+    #include <Wire.h>
39
+    #include <LiquidCrystal_I2C.h>
40
+  #elif defined(LCD_I2C_TYPE_MCP23017) || defined(LCD_I2C_TYPE_MCP23008)
41
+    #include <Wire.h>
42
+    #include <LiquidTWI2.h>
43
+  #elif defined(DOGLCD)
44
+    #include <U8glib.h> // library for graphics LCD by Oli Kraus (https://code.google.com/p/u8glib/)
45
+  #else
46
+    #include <LiquidCrystal.h> // library for character LCD
47
+  #endif
48
+#endif
49
+
50
+#if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1
51
+#include <SPI.h>
52
+#endif

+ 302
- 1
Marlin/Marlin_main.cpp Ver fichero

@@ -29,6 +29,10 @@
29 29
 
30 30
 #include "Marlin.h"
31 31
 
32
+#ifdef ENABLE_AUTO_BED_LEVELING
33
+#include "vector_3.h"
34
+#endif // ENABLE_AUTO_BED_LEVELING
35
+
32 36
 #include "ultralcd.h"
33 37
 #include "planner.h"
34 38
 #include "stepper.h"
@@ -63,6 +67,8 @@
63 67
 // G10 - retract filament according to settings of M207
64 68
 // G11 - retract recover filament according to settings of M208
65 69
 // G28 - Home all Axis
70
+// G29 - Detailed Z-Probe, probes the bed at 3 points.  You must de at the home position for this to work correctly.
71
+// G30 - Single Z Probe, probes bed at current XY location.
66 72
 // G90 - Use Absolute Coordinates
67 73
 // G91 - Use Relative Coordinates
68 74
 // G92 - Set current position to cordinates given
@@ -133,6 +139,8 @@
133 139
 // M303 - PID relay autotune S<temperature> sets the target temperature. (default target temperature = 150C)
134 140
 // M304 - Set bed PID parameters P I and D
135 141
 // M400 - Finish all moves
142
+// M401 - Lower z-probe if present
143
+// M402 - Raise z-probe if present
136 144
 // M500 - stores paramters in EEPROM
137 145
 // M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily).
138 146
 // M502 - reverts to the default "factory settings".  You still need to store them in EEPROM afterwards if you want to.
@@ -388,6 +396,11 @@ void servo_init()
388 396
     }
389 397
   }
390 398
   #endif
399
+
400
+  #if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0)
401
+  delay(PROBE_SERVO_DEACTIVATION_DELAY);
402
+  servos[servo_endstops[Z_AXIS]].detach();  
403
+  #endif
391 404
 }
392 405
 
393 406
 void setup()
@@ -756,6 +769,143 @@ static void axis_is_at_home(int axis) {
756 769
   max_pos[axis] =          base_max_pos(axis) + add_homeing[axis];
757 770
 }
758 771
 
772
+#ifdef ENABLE_AUTO_BED_LEVELING
773
+static void set_bed_level_equation(float z_at_xLeft_yFront, float z_at_xRight_yFront, float z_at_xLeft_yBack) {
774
+    plan_bed_level_matrix.set_to_identity();
775
+
776
+    vector_3 xLeftyFront = vector_3(LEFT_PROBE_BED_POSITION, FRONT_PROBE_BED_POSITION, z_at_xLeft_yFront);
777
+    vector_3 xLeftyBack = vector_3(LEFT_PROBE_BED_POSITION, BACK_PROBE_BED_POSITION, z_at_xLeft_yBack);
778
+    vector_3 xRightyFront = vector_3(RIGHT_PROBE_BED_POSITION, FRONT_PROBE_BED_POSITION, z_at_xRight_yFront);
779
+
780
+    vector_3 xPositive = (xRightyFront - xLeftyFront).get_normal();
781
+    vector_3 yPositive = (xLeftyBack - xLeftyFront).get_normal();
782
+    vector_3 planeNormal = vector_3::cross(yPositive, xPositive).get_normal();
783
+
784
+    //planeNormal.debug("planeNormal");
785
+    //yPositive.debug("yPositive");
786
+    matrix_3x3 bedLevel = matrix_3x3::create_look_at(planeNormal, yPositive);
787
+    //bedLevel.debug("bedLevel");
788
+
789
+    //plan_bed_level_matrix.debug("bed level before");
790
+    //vector_3 uncorrected_position = plan_get_position_mm();
791
+    //uncorrected_position.debug("position before");
792
+
793
+    // and set our bed level equation to do the right thing
794
+    plan_bed_level_matrix = matrix_3x3::create_inverse(bedLevel);
795
+    //plan_bed_level_matrix.debug("bed level after");
796
+
797
+    vector_3 corrected_position = plan_get_position();
798
+    //corrected_position.debug("position after");
799
+    current_position[X_AXIS] = corrected_position.x;
800
+    current_position[Y_AXIS] = corrected_position.y;
801
+    current_position[Z_AXIS] = corrected_position.z;
802
+
803
+    // but the bed at 0 so we don't go below it.
804
+    current_position[Z_AXIS] = -Z_PROBE_OFFSET_FROM_EXTRUDER;
805
+
806
+    plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
807
+}
808
+
809
+static void run_z_probe() {
810
+    plan_bed_level_matrix.set_to_identity();
811
+    feedrate = homing_feedrate[Z_AXIS];
812
+
813
+    // move down until you find the bed
814
+    float zPosition = -10;
815
+    plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], zPosition, current_position[E_AXIS], feedrate/60, active_extruder);
816
+    st_synchronize();
817
+
818
+        // we have to let the planner know where we are right now as it is not where we said to go.
819
+    zPosition = st_get_position_mm(Z_AXIS);
820
+    plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], zPosition, current_position[E_AXIS]);
821
+
822
+    // move up the retract distance
823
+    zPosition += home_retract_mm(Z_AXIS);
824
+    plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], zPosition, current_position[E_AXIS], feedrate/60, active_extruder);
825
+    st_synchronize();
826
+
827
+    // move back down slowly to find bed
828
+    feedrate = homing_feedrate[Z_AXIS]/4; 
829
+    zPosition -= home_retract_mm(Z_AXIS) * 2;
830
+    plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], zPosition, current_position[E_AXIS], feedrate/60, active_extruder);
831
+    st_synchronize();
832
+
833
+    current_position[Z_AXIS] = st_get_position_mm(Z_AXIS);
834
+    // make sure the planner knows where we are as it may be a bit different than we last said to move to
835
+    plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
836
+}
837
+
838
+static void do_blocking_move_to(float x, float y, float z) {
839
+    float oldFeedRate = feedrate;
840
+
841
+    feedrate = XY_TRAVEL_SPEED;
842
+
843
+    current_position[X_AXIS] = x;
844
+    current_position[Y_AXIS] = y;
845
+    current_position[Z_AXIS] = z;
846
+    plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], feedrate/60, active_extruder);
847
+    st_synchronize();
848
+
849
+    feedrate = oldFeedRate;
850
+}
851
+
852
+static void do_blocking_move_relative(float offset_x, float offset_y, float offset_z) {
853
+    do_blocking_move_to(current_position[X_AXIS] + offset_x, current_position[Y_AXIS] + offset_y, current_position[Z_AXIS] + offset_z);
854
+}
855
+
856
+static void setup_for_endstop_move() {
857
+    saved_feedrate = feedrate;
858
+    saved_feedmultiply = feedmultiply;
859
+    feedmultiply = 100;
860
+    previous_millis_cmd = millis();
861
+
862
+    enable_endstops(true);
863
+}
864
+
865
+static void clean_up_after_endstop_move() {
866
+#ifdef ENDSTOPS_ONLY_FOR_HOMING
867
+    enable_endstops(false);
868
+#endif
869
+
870
+    feedrate = saved_feedrate;
871
+    feedmultiply = saved_feedmultiply;
872
+    previous_millis_cmd = millis();
873
+}
874
+
875
+static void engage_z_probe() {
876
+    // Engage Z Servo endstop if enabled
877
+    #ifdef SERVO_ENDSTOPS
878
+    if (servo_endstops[Z_AXIS] > -1) {
879
+#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0)
880
+        servos[servo_endstops[Z_AXIS]].attach(0);
881
+#endif
882
+        servos[servo_endstops[Z_AXIS]].write(servo_endstop_angles[Z_AXIS * 2]);
883
+#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0)
884
+        delay(PROBE_SERVO_DEACTIVATION_DELAY);
885
+        servos[servo_endstops[Z_AXIS]].detach();
886
+#endif
887
+    }
888
+    #endif
889
+}
890
+
891
+static void retract_z_probe() {
892
+    // Retract Z Servo endstop if enabled
893
+    #ifdef SERVO_ENDSTOPS
894
+    if (servo_endstops[Z_AXIS] > -1) {
895
+#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0)
896
+        servos[servo_endstops[Z_AXIS]].attach(0);
897
+#endif
898
+        servos[servo_endstops[Z_AXIS]].write(servo_endstop_angles[Z_AXIS * 2 + 1]);
899
+#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0)
900
+        delay(PROBE_SERVO_DEACTIVATION_DELAY);
901
+        servos[servo_endstops[Z_AXIS]].detach();
902
+#endif
903
+    }
904
+    #endif
905
+}
906
+
907
+#endif // #ifdef ENABLE_AUTO_BED_LEVELING
908
+
759 909
 static void homeaxis(int axis) {
760 910
 #define HOMEAXIS_DO(LETTER) \
761 911
   ((LETTER##_MIN_PIN > -1 && LETTER##_HOME_DIR==-1) || (LETTER##_MAX_PIN > -1 && LETTER##_HOME_DIR==1))
@@ -772,6 +922,10 @@ static void homeaxis(int axis) {
772 922
 
773 923
     // Engage Servo endstop if enabled
774 924
     #ifdef SERVO_ENDSTOPS
925
+#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0)
926
+    if (axis==Z_AXIS) engage_z_probe();
927
+	else
928
+#endif
775 929
       if (servo_endstops[axis] > -1) {
776 930
         servos[servo_endstops[axis]].write(servo_endstop_angles[axis * 2]);
777 931
       }
@@ -818,6 +972,10 @@ static void homeaxis(int axis) {
818 972
         servos[servo_endstops[axis]].write(servo_endstop_angles[axis * 2 + 1]);
819 973
       }
820 974
     #endif
975
+#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0)
976
+    if (axis==Z_AXIS) retract_z_probe();
977
+#endif
978
+    
821 979
   }
822 980
 }
823 981
 #define HOMEAXIS(LETTER) homeaxis(LETTER##_AXIS)
@@ -826,7 +984,9 @@ void process_commands()
826 984
 {
827 985
   unsigned long codenum; //throw away variable
828 986
   char *starpos = NULL;
829
-
987
+#ifdef ENABLE_AUTO_BED_LEVELING
988
+  float x_tmp, y_tmp, z_tmp, real_z;
989
+#endif
830 990
   if(code_seen('G'))
831 991
   {
832 992
     switch((int)code_value())
@@ -898,6 +1058,11 @@ void process_commands()
898 1058
       break;
899 1059
       #endif //FWRETRACT
900 1060
     case 28: //G28 Home all Axis one at a time
1061
+#ifdef ENABLE_AUTO_BED_LEVELING
1062
+      plan_bed_level_matrix.set_to_identity();  //Reset the plane ("erase" all leveling data)
1063
+#endif //ENABLE_AUTO_BED_LEVELING
1064
+
1065
+
901 1066
       saved_feedrate = feedrate;
902 1067
       saved_feedmultiply = feedmultiply;
903 1068
       feedmultiply = 100;
@@ -1045,6 +1210,122 @@ void process_commands()
1045 1210
       previous_millis_cmd = millis();
1046 1211
       endstops_hit_on_purpose();
1047 1212
       break;
1213
+
1214
+#ifdef ENABLE_AUTO_BED_LEVELING
1215
+    case 29: // G29 Detailed Z-Probe, probes the bed at 3 points.
1216
+        {
1217
+            #if Z_MIN_PIN == -1
1218
+            #error "You must have a Z_MIN endstop in order to enable Auto Bed Leveling feature!!! Z_MIN_PIN must point to a valid hardware pin."
1219
+            #endif
1220
+
1221
+            st_synchronize();
1222
+            // make sure the bed_level_rotation_matrix is identity or the planner will get it incorectly
1223
+            //vector_3 corrected_position = plan_get_position_mm();
1224
+            //corrected_position.debug("position before G29");
1225
+            plan_bed_level_matrix.set_to_identity();
1226
+            vector_3 uncorrected_position = plan_get_position();
1227
+            //uncorrected_position.debug("position durring G29");
1228
+            current_position[X_AXIS] = uncorrected_position.x;
1229
+            current_position[Y_AXIS] = uncorrected_position.y;
1230
+            current_position[Z_AXIS] = uncorrected_position.z;
1231
+            plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
1232
+            setup_for_endstop_move();
1233
+
1234
+            feedrate = homing_feedrate[Z_AXIS];
1235
+
1236
+            // prob 1
1237
+            do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], Z_RAISE_BEFORE_PROBING);
1238
+            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]);
1239
+
1240
+            engage_z_probe();   // Engage Z Servo endstop if available
1241
+            
1242
+            run_z_probe();
1243
+            float z_at_xLeft_yBack = current_position[Z_AXIS];
1244
+
1245
+            SERIAL_PROTOCOLPGM("Bed x: ");
1246
+            SERIAL_PROTOCOL(LEFT_PROBE_BED_POSITION);
1247
+            SERIAL_PROTOCOLPGM(" y: ");
1248
+            SERIAL_PROTOCOL(BACK_PROBE_BED_POSITION);
1249
+            SERIAL_PROTOCOLPGM(" z: ");
1250
+            SERIAL_PROTOCOL(current_position[Z_AXIS]);
1251
+            SERIAL_PROTOCOLPGM("\n");
1252
+
1253
+            // prob 2
1254
+            do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS);
1255
+            do_blocking_move_to(LEFT_PROBE_BED_POSITION - X_PROBE_OFFSET_FROM_EXTRUDER, FRONT_PROBE_BED_POSITION - Y_PROBE_OFFSET_FROM_EXTRUDER, current_position[Z_AXIS]);
1256
+            run_z_probe();
1257
+            float z_at_xLeft_yFront = current_position[Z_AXIS];
1258
+
1259
+            SERIAL_PROTOCOLPGM("Bed x: ");
1260
+            SERIAL_PROTOCOL(LEFT_PROBE_BED_POSITION);
1261
+            SERIAL_PROTOCOLPGM(" y: ");
1262
+            SERIAL_PROTOCOL(FRONT_PROBE_BED_POSITION);
1263
+            SERIAL_PROTOCOLPGM(" z: ");
1264
+            SERIAL_PROTOCOL(current_position[Z_AXIS]);
1265
+            SERIAL_PROTOCOLPGM("\n");
1266
+
1267
+            // prob 3
1268
+            do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS);
1269
+            // the current position will be updated by the blocking move so the head will not lower on this next call.
1270
+            do_blocking_move_to(RIGHT_PROBE_BED_POSITION - X_PROBE_OFFSET_FROM_EXTRUDER, FRONT_PROBE_BED_POSITION - Y_PROBE_OFFSET_FROM_EXTRUDER, current_position[Z_AXIS]);
1271
+            run_z_probe();
1272
+            float z_at_xRight_yFront = current_position[Z_AXIS];
1273
+
1274
+            SERIAL_PROTOCOLPGM("Bed x: ");
1275
+            SERIAL_PROTOCOL(RIGHT_PROBE_BED_POSITION);
1276
+            SERIAL_PROTOCOLPGM(" y: ");
1277
+            SERIAL_PROTOCOL(FRONT_PROBE_BED_POSITION);
1278
+            SERIAL_PROTOCOLPGM(" z: ");
1279
+            SERIAL_PROTOCOL(current_position[Z_AXIS]);
1280
+            SERIAL_PROTOCOLPGM("\n");
1281
+
1282
+            clean_up_after_endstop_move();
1283
+
1284
+            set_bed_level_equation(z_at_xLeft_yFront, z_at_xRight_yFront, z_at_xLeft_yBack);
1285
+
1286
+            retract_z_probe(); // Retract Z Servo endstop if available
1287
+            
1288
+            st_synchronize();            
1289
+
1290
+            // The following code correct the Z height difference from z-probe position and hotend tip position.
1291
+            // The Z height on homing is measured by Z-Probe, but the probe is quite far from the hotend. 
1292
+            // When the bed is uneven, this height must be corrected.
1293
+            real_z = float(st_get_position(Z_AXIS))/axis_steps_per_unit[Z_AXIS];  //get the real Z (since the auto bed leveling is already correcting the plane)
1294
+            x_tmp = current_position[X_AXIS] + X_PROBE_OFFSET_FROM_EXTRUDER;
1295
+            y_tmp = current_position[Y_AXIS] + Y_PROBE_OFFSET_FROM_EXTRUDER;
1296
+            z_tmp = current_position[Z_AXIS];
1297
+
1298
+            apply_rotation_xyz(plan_bed_level_matrix, x_tmp, y_tmp, z_tmp);         //Apply the correction sending the probe offset
1299
+            current_position[Z_AXIS] = z_tmp - real_z + current_position[Z_AXIS];   //The difference is added to current position and sent to planner.
1300
+            plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
1301
+        }
1302
+        break;
1303
+        
1304
+    case 30: // G30 Single Z Probe
1305
+        {
1306
+            engage_z_probe(); // Engage Z Servo endstop if available
1307
+            
1308
+            st_synchronize();
1309
+            // TODO: make sure the bed_level_rotation_matrix is identity or the planner will get set incorectly
1310
+            setup_for_endstop_move();
1311
+
1312
+            feedrate = homing_feedrate[Z_AXIS];
1313
+
1314
+            run_z_probe();
1315
+            SERIAL_PROTOCOLPGM("Bed Position X: ");
1316
+            SERIAL_PROTOCOL(current_position[X_AXIS]);
1317
+            SERIAL_PROTOCOLPGM(" Y: ");
1318
+            SERIAL_PROTOCOL(current_position[Y_AXIS]);
1319
+            SERIAL_PROTOCOLPGM(" Z: ");
1320
+            SERIAL_PROTOCOL(current_position[Z_AXIS]);
1321
+            SERIAL_PROTOCOLPGM("\n");
1322
+
1323
+            clean_up_after_endstop_move();
1324
+
1325
+            retract_z_probe(); // Retract Z Servo endstop if available
1326
+        }
1327
+        break;
1328
+#endif // ENABLE_AUTO_BED_LEVELING
1048 1329
     case 90: // G90
1049 1330
       relative_mode = false;
1050 1331
       break;
@@ -1787,7 +2068,14 @@ void process_commands()
1787 2068
         if (code_seen('S')) {
1788 2069
           servo_position = code_value();
1789 2070
           if ((servo_index >= 0) && (servo_index < NUM_SERVOS)) {
2071
+#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0)
2072
+		      servos[servo_index].attach(0);
2073
+#endif
1790 2074
             servos[servo_index].write(servo_position);
2075
+#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0)
2076
+              delay(PROBE_SERVO_DEACTIVATION_DELAY);
2077
+              servos[servo_index].detach();
2078
+#endif
1791 2079
           }
1792 2080
           else {
1793 2081
             SERIAL_ECHO_START;
@@ -1938,6 +2226,19 @@ void process_commands()
1938 2226
       st_synchronize();
1939 2227
     }
1940 2228
     break;
2229
+#if defined(ENABLE_AUTO_BED_LEVELING) && defined(SERVO_ENDSTOPS)
2230
+    case 401:
2231
+    {
2232
+        engage_z_probe();    // Engage Z Servo endstop if available
2233
+    }
2234
+    break;
2235
+    
2236
+    case 402:
2237
+    {
2238
+        retract_z_probe();    // Retract Z Servo endstop if enabled
2239
+    }
2240
+    break;
2241
+#endif    
1941 2242
     case 500: // M500 Store settings in EEPROM
1942 2243
     {
1943 2244
         Config_StoreSettings();

+ 3
- 0
Marlin/Servo.cpp Ver fichero

@@ -262,6 +262,9 @@ uint8_t Servo::attach(int pin)
262 262
 uint8_t Servo::attach(int pin, int min, int max)
263 263
 {
264 264
   if(this->servoIndex < MAX_SERVOS ) {
265
+#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0)
266
+    if (pin > 0) this->pin = pin; else pin = this->pin;
267
+#endif
265 268
     pinMode( pin, OUTPUT) ;                                   // set servo pin to output
266 269
     servos[this->servoIndex].Pin.nbr = pin;
267 270
     // todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128

+ 3
- 0
Marlin/Servo.h Ver fichero

@@ -123,6 +123,9 @@ public:
123 123
   int read();                        // returns current pulse width as an angle between 0 and 180 degrees
124 124
   int readMicroseconds();            // returns current pulse width in microseconds for this servo (was read_us() in first release)
125 125
   bool attached();                   // return true if this servo is attached, otherwise false
126
+#if defined (ENABLE_AUTO_BED_LEVELING) && (PROBE_SERVO_DEACTIVATION_DELAY > 0)
127
+  int pin;                           // store the hw pin of the servo
128
+#endif
126 129
 private:
127 130
    uint8_t servoIndex;               // index into the channel data for this servo
128 131
    int8_t min;                       // minimum is this value times 4 added to MIN_PULSE_WIDTH

+ 39
- 0
Marlin/planner.cpp Ver fichero

@@ -75,6 +75,15 @@ float max_e_jerk;
75 75
 float mintravelfeedrate;
76 76
 unsigned long axis_steps_per_sqr_second[NUM_AXIS];
77 77
 
78
+#ifdef ENABLE_AUTO_BED_LEVELING
79
+// this holds the required transform to compensate for bed level
80
+matrix_3x3 plan_bed_level_matrix = {
81
+	1.0, 0.0, 0.0,
82
+	0.0, 1.0, 0.0,
83
+	0.0, 0.0, 1.0,
84
+};
85
+#endif // #ifdef ENABLE_AUTO_BED_LEVELING
86
+
78 87
 // The current position of the tool in absolute steps
79 88
 long position[4];   //rescaled from extern when axis_steps_per_unit are changed by gcode
80 89
 static float previous_speed[4]; // Speed of previous path line segment
@@ -513,7 +522,11 @@ float junction_deviation = 0.1;
513 522
 // Add a new linear movement to the buffer. steps_x, _y and _z is the absolute position in 
514 523
 // mm. Microseconds specify how many microseconds the move should take to perform. To aid acceleration
515 524
 // calculation the caller must also provide the physical length of the line in millimeters.
525
+#ifdef ENABLE_AUTO_BED_LEVELING
526
+void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate, const uint8_t &extruder)
527
+#else
516 528
 void plan_buffer_line(const float &x, const float &y, const float &z, const float &e, float feed_rate, const uint8_t &extruder)
529
+#endif  //ENABLE_AUTO_BED_LEVELING
517 530
 {
518 531
   // Calculate the buffer head after we push this byte
519 532
   int next_buffer_head = next_block_index(block_buffer_head);
@@ -527,6 +540,10 @@ void plan_buffer_line(const float &x, const float &y, const float &z, const floa
527 540
     lcd_update();
528 541
   }
529 542
 
543
+#ifdef ENABLE_AUTO_BED_LEVELING
544
+  apply_rotation_xyz(plan_bed_level_matrix, x, y, z);
545
+#endif // ENABLE_AUTO_BED_LEVELING
546
+
530 547
   // The target position of the tool in absolute steps
531 548
   // Calculate target position in absolute steps
532 549
   //this should be done after the wait, because otherwise a M92 code within the gcode disrupts this calculation somehow
@@ -919,8 +936,30 @@ block->steps_y = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-positi
919 936
   st_wake_up();
920 937
 }
921 938
 
939
+#ifdef ENABLE_AUTO_BED_LEVELING
940
+vector_3 plan_get_position() {
941
+	vector_3 position = vector_3(st_get_position_mm(X_AXIS), st_get_position_mm(Y_AXIS), st_get_position_mm(Z_AXIS));
942
+
943
+	//position.debug("in plan_get position");
944
+	//plan_bed_level_matrix.debug("in plan_get bed_level");
945
+	matrix_3x3 inverse = matrix_3x3::create_inverse(plan_bed_level_matrix);
946
+	//inverse.debug("in plan_get inverse");
947
+	position.apply_rotation(inverse);
948
+	//position.debug("after rotation");
949
+
950
+	return position;
951
+}
952
+#endif // ENABLE_AUTO_BED_LEVELING
953
+
954
+#ifdef ENABLE_AUTO_BED_LEVELING
955
+void plan_set_position(float x, float y, float z, const float &e)
956
+{
957
+  apply_rotation_xyz(plan_bed_level_matrix, x, y, z);
958
+#else
922 959
 void plan_set_position(const float &x, const float &y, const float &z, const float &e)
923 960
 {
961
+#endif // ENABLE_AUTO_BED_LEVELING
962
+
924 963
   position[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]);
925 964
   position[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]);
926 965
   position[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]);     

+ 22
- 0
Marlin/planner.h Ver fichero

@@ -26,6 +26,10 @@
26 26
 
27 27
 #include "Marlin.h"
28 28
 
29
+#ifdef ENABLE_AUTO_BED_LEVELING
30
+#include "vector_3.h"
31
+#endif // ENABLE_AUTO_BED_LEVELING
32
+
29 33
 // This struct is used when buffering the setup for each linear movement "nominal" values are as specified in 
30 34
 // the source g-code and may never actually be reached if acceleration management is active.
31 35
 typedef struct {
@@ -67,15 +71,33 @@ typedef struct {
67 71
   volatile char busy;
68 72
 } block_t;
69 73
 
74
+#ifdef ENABLE_AUTO_BED_LEVELING
75
+// this holds the required transform to compensate for bed level
76
+extern matrix_3x3 plan_bed_level_matrix;
77
+#endif // #ifdef ENABLE_AUTO_BED_LEVELING
78
+
70 79
 // Initialize the motion plan subsystem      
71 80
 void plan_init();
72 81
 
73 82
 // Add a new linear movement to the buffer. x, y and z is the signed, absolute target position in 
74 83
 // millimaters. Feed rate specifies the speed of the motion.
84
+
85
+#ifdef ENABLE_AUTO_BED_LEVELING
86
+void plan_buffer_line(float x, float y, float z, const float &e, float feed_rate, const uint8_t &extruder);
87
+
88
+// Get the position applying the bed level matrix if enabled
89
+vector_3 plan_get_position();
90
+#else
75 91
 void plan_buffer_line(const float &x, const float &y, const float &z, const float &e, float feed_rate, const uint8_t &extruder);
92
+#endif // ENABLE_AUTO_BED_LEVELING
76 93
 
77 94
 // Set position. Used for G92 instructions.
95
+#ifdef ENABLE_AUTO_BED_LEVELING
96
+void plan_set_position(float x, float y, float z, const float &e);
97
+#else
78 98
 void plan_set_position(const float &x, const float &y, const float &z, const float &e);
99
+#endif // ENABLE_AUTO_BED_LEVELING
100
+
79 101
 void plan_set_e_position(const float &e);
80 102
 
81 103
 

+ 8
- 0
Marlin/stepper.cpp Ver fichero

@@ -969,6 +969,14 @@ long st_get_position(uint8_t axis)
969 969
   return count_pos;
970 970
 }
971 971
 
972
+#ifdef ENABLE_AUTO_BED_LEVELING
973
+float st_get_position_mm(uint8_t axis)
974
+{
975
+  float steper_position_in_steps = st_get_position(axis);
976
+  return steper_position_in_steps / axis_steps_per_unit[axis];
977
+}
978
+#endif  // ENABLE_AUTO_BED_LEVELING
979
+
972 980
 void finishAndDisableSteppers()
973 981
 {
974 982
   st_synchronize();

+ 8
- 3
Marlin/stepper.h Ver fichero

@@ -44,9 +44,9 @@
44 44
   #define REV_E_DIR() WRITE(E0_DIR_PIN, INVERT_E0_DIR)
45 45
 #endif
46 46
 
47
-#ifdef ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED
48
-extern bool abort_on_endstop_hit;
49
-#endif
47
+#ifdef ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED
48
+extern bool abort_on_endstop_hit;
49
+#endif
50 50
 
51 51
 // Initialize and start the stepper motor subsystem
52 52
 void st_init();
@@ -61,6 +61,11 @@ void st_set_e_position(const long &e);
61 61
 // Get current position in steps
62 62
 long st_get_position(uint8_t axis);
63 63
 
64
+#ifdef ENABLE_AUTO_BED_LEVELING
65
+// Get current position in mm
66
+float st_get_position_mm(uint8_t axis);
67
+#endif  //ENABLE_AUTO_BED_LEVELING
68
+
64 69
 // The stepper subsystem goes to sleep when it runs out of things to execute. Call this
65 70
 // to notify the subsystem that it is time to go to work.
66 71
 void st_wake_up();

+ 202
- 0
Marlin/vector_3.cpp Ver fichero

@@ -0,0 +1,202 @@
1
+/*
2
+  vector_3.cpp - Vector library for bed leveling
3
+  Copyright (c) 2012 Lars Brubaker.  All right reserved.
4
+
5
+  This library is free software; you can redistribute it and/or
6
+  modify it under the terms of the GNU Lesser General Public
7
+  License as published by the Free Software Foundation; either
8
+  version 2.1 of the License, or (at your option) any later version.
9
+
10
+  This library is distributed in the hope that it will be useful,
11
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
+  Lesser General Public License for more details.
14
+
15
+  You should have received a copy of the GNU Lesser General Public
16
+  License along with this library; if not, write to the Free Software
17
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
+*/
19
+#include <math.h>
20
+#include "Marlin.h"
21
+
22
+#ifdef ENABLE_AUTO_BED_LEVELING
23
+#include "vector_3.h"
24
+
25
+vector_3::vector_3()
26
+{
27
+  this->x = 0;
28
+  this->y = 0;
29
+  this->z = 0;
30
+}
31
+
32
+vector_3::vector_3(float x, float y, float z)
33
+{
34
+	this->x = x;
35
+	this->y = y;
36
+	this->z = z;
37
+}
38
+
39
+vector_3 vector_3::cross(vector_3 left, vector_3 right)
40
+{
41
+	return vector_3(left.y * right.z - left.z * right.y,
42
+		left.z * right.x - left.x * right.z,
43
+		left.x * right.y - left.y * right.x);
44
+}
45
+
46
+vector_3 vector_3::operator+(vector_3 v) 
47
+{
48
+	return vector_3((x + v.x), (y + v.y), (z + v.z));
49
+}
50
+
51
+vector_3 vector_3::operator-(vector_3 v) 
52
+{
53
+	return vector_3((x - v.x), (y - v.y), (z - v.z));
54
+}
55
+
56
+vector_3 vector_3::get_normal() 
57
+{
58
+	vector_3 normalized = vector_3(x, y, z);
59
+	normalized.normalize();
60
+	return normalized;
61
+}
62
+
63
+float vector_3::get_length() 
64
+{
65
+        float length = sqrt((x * x) + (y * y) + (z * z));
66
+	return length;
67
+}
68
+ 
69
+void vector_3::normalize()
70
+{
71
+	float length = get_length();
72
+	x /= length;
73
+	y /= length;
74
+	z /= length;
75
+}
76
+
77
+void vector_3::apply_rotation(matrix_3x3 matrix)
78
+{
79
+	float resultX = x * matrix.matrix[3*0+0] + y * matrix.matrix[3*1+0] + z * matrix.matrix[3*2+0];
80
+	float resultY = x * matrix.matrix[3*0+1] + y * matrix.matrix[3*1+1] + z * matrix.matrix[3*2+1];
81
+	float resultZ = x * matrix.matrix[3*0+2] + y * matrix.matrix[3*1+2] + z * matrix.matrix[3*2+2];
82
+
83
+	x = resultX;
84
+	y = resultY;
85
+	z = resultZ;
86
+}
87
+
88
+void vector_3::debug(char* title)
89
+{
90
+	SERIAL_PROTOCOL(title);
91
+	SERIAL_PROTOCOLPGM(" x: ");
92
+	SERIAL_PROTOCOL(x);
93
+	SERIAL_PROTOCOLPGM(" y: ");
94
+	SERIAL_PROTOCOL(y);
95
+	SERIAL_PROTOCOLPGM(" z: ");
96
+	SERIAL_PROTOCOL(z);
97
+	SERIAL_PROTOCOLPGM("\n");
98
+}
99
+
100
+void apply_rotation_xyz(matrix_3x3 matrix, float &x, float& y, float& z)
101
+{
102
+	vector_3 vector = vector_3(x, y, z);
103
+	vector.apply_rotation(matrix);
104
+	x = vector.x;
105
+	y = vector.y;
106
+	z = vector.z;
107
+}
108
+
109
+matrix_3x3 matrix_3x3::create_from_rows(vector_3 row_0, vector_3 row_1, vector_3 row_2)
110
+{
111
+        //row_0.debug("row_0");
112
+        //row_1.debug("row_1");
113
+        //row_2.debug("row_2");
114
+	matrix_3x3 new_matrix;
115
+	new_matrix.matrix[0] = row_0.x; new_matrix.matrix[1] = row_0.y; new_matrix.matrix[2] = row_0.z; 
116
+	new_matrix.matrix[3] = row_1.x; new_matrix.matrix[4] = row_1.y; new_matrix.matrix[5] = row_1.z; 
117
+	new_matrix.matrix[6] = row_2.x; new_matrix.matrix[7] = row_2.y; new_matrix.matrix[8] = row_2.z; 
118
+        //new_matrix.debug("new_matrix");
119
+        
120
+	return new_matrix;
121
+}
122
+
123
+void matrix_3x3::set_to_identity()
124
+{
125
+	matrix[0] = 1; matrix[1] = 0; matrix[2] = 0;
126
+	matrix[3] = 0; matrix[4] = 1; matrix[5] = 0;
127
+	matrix[6] = 0; matrix[7] = 0; matrix[8] = 1;
128
+}
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");
147
+    return rot;
148
+}
149
+
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;
181
+}
182
+
183
+void matrix_3x3::debug(char* title)
184
+{
185
+	SERIAL_PROTOCOL(title);
186
+	SERIAL_PROTOCOL("\n");
187
+	int count = 0;
188
+	for(int i=0; i<3; i++)
189
+	{
190
+		for(int j=0; j<3; j++)
191
+		{
192
+			SERIAL_PROTOCOL(matrix[count]);
193
+			SERIAL_PROTOCOLPGM(" ");
194
+		        count++;
195
+		}
196
+
197
+		SERIAL_PROTOCOLPGM("\n");
198
+	}
199
+}
200
+
201
+#endif // #ifdef ENABLE_AUTO_BED_LEVELING
202
+

+ 62
- 0
Marlin/vector_3.h Ver fichero

@@ -0,0 +1,62 @@
1
+/*
2
+  vector_3.cpp - Vector library for bed leveling
3
+  Copyright (c) 2012 Lars Brubaker.  All right reserved.
4
+
5
+  This library is free software; you can redistribute it and/or
6
+  modify it under the terms of the GNU Lesser General Public
7
+  License as published by the Free Software Foundation; either
8
+  version 2.1 of the License, or (at your option) any later version.
9
+
10
+  This library is distributed in the hope that it will be useful,
11
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
+  Lesser General Public License for more details.
14
+
15
+  You should have received a copy of the GNU Lesser General Public
16
+  License along with this library; if not, write to the Free Software
17
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
+*/
19
+#ifndef VECTOR_3_H
20
+#define VECTOR_3_H
21
+
22
+#ifdef ENABLE_AUTO_BED_LEVELING
23
+class matrix_3x3;
24
+
25
+struct vector_3
26
+{
27
+	float x, y, z;
28
+
29
+        vector_3();
30
+	vector_3(float x, float y, float z);
31
+
32
+	static vector_3 cross(vector_3 a, vector_3 b);
33
+
34
+	vector_3 operator+(vector_3 v);
35
+	vector_3 operator-(vector_3 v);
36
+	void normalize();
37
+	float get_length();
38
+	vector_3 get_normal();
39
+
40
+	void debug(char* title);
41
+	
42
+	void apply_rotation(matrix_3x3 matrix);
43
+};
44
+
45
+struct matrix_3x3
46
+{
47
+	float matrix[9];
48
+
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);
52
+
53
+	void set_to_identity();
54
+
55
+	void debug(char* title);
56
+};
57
+
58
+
59
+void apply_rotation_xyz(matrix_3x3 rotationMatrix, float &x, float& y, float& z);
60
+#endif // ENABLE_AUTO_BED_LEVELING
61
+
62
+#endif // VECTOR_3_H

+ 68
- 0
README.md Ver fichero

@@ -48,6 +48,7 @@ Features:
48 48
 *   Configurable serial port to support connection of wireless adaptors.
49 49
 *   Automatic operation of extruder/cold-end cooling fans based on nozzle temperature
50 50
 *   RC Servo Support, specify angle or duration for continuous rotation servos.
51
+*   Bed Auto Leveling.
51 52
 
52 53
 The default baudrate is 250000. This baudrate has less jitter and hence errors than the usual 115200 baud, but is less supported by drivers and host-environments.
53 54
 
@@ -142,6 +143,8 @@ Implemented G Codes:
142 143
 *  G10 - retract filament according to settings of M207
143 144
 *  G11 - retract recover filament according to settings of M208
144 145
 *  G28 - Home all Axis
146
+*  G29 - Detailed Z-Probe, probes the bed at 3 points.  You must de at the home position for this to work correctly.
147
+*  G30 - Single Z Probe, probes bed at current XY location.
145 148
 *  G90 - Use Absolute Coordinates
146 149
 *  G91 - Use Relative Coordinates
147 150
 *  G92 - Set current position to cordinates given
@@ -210,6 +213,8 @@ M Codes
210 213
 *  M303 - PID relay autotune S<temperature> sets the target temperature. (default target temperature = 150C)
211 214
 *  M304 - Set bed PID parameters P I and D
212 215
 *  M400 - Finish all moves
216
+*  M401 - Lower z-probe if present
217
+*  M402 - Raise z-probe if present
213 218
 *  M500 - stores paramters in EEPROM
214 219
 *  M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily).
215 220
 *  M502 - reverts to the default "factory settings".  You still need to store them in EEPROM afterwards if you want to.
@@ -249,6 +254,69 @@ If all goes well the firmware is uploading
249 254
 
250 255
 That's ok.  Enjoy Silky Smooth Printing.
251 256
 
257
+===============================================
258
+Instructions for configuring Bed Auto Leveling
259
+===============================================
260
+Uncomment the "ENABLE_AUTO_BED_LEVELING" define (commented by default)
261
+
262
+You will probably need a swivel Z-MIN endstop in the extruder. A rc servo do a great job.
263
+Check the system working here: http://www.youtube.com/watch?v=3IKMeOYz-1Q (Enable English subtitles)
264
+Teasing ;-) video: http://www.youtube.com/watch?v=x8eqSQNAyro
265
+
266
+In order to get the servo working, you need to enable:
267
+
268
+* \#define NUM_SERVOS 1 // Servo index starts with 0 for M280 command
269
+
270
+* \#define SERVO_ENDSTOPS {-1, -1, 0} // Servo index for X, Y, Z. Disable with -1
271
+
272
+* \#define SERVO_ENDSTOP_ANGLES {0,0, 0,0, 165,60} // X,Y,Z Axis Extend and Retract angles
273
+
274
+
275
+The first define tells firmware how many servos you have.
276
+The second tells what axis this servo will be attached to. In the example above, we have a servo in Z axis.
277
+The third one tells the angle in 2 situations: Probing (165º) and resting (60º). Check this with command M280 P0 S{angle}
278
+
279
+Next you need to define the Z endstop (probe) offset from hotend.
280
+My preferred method:
281
+
282
+* a) Make a small mark in the bed with a marker/felt-tip pen.
283
+* b) Place the hotend tip as *exactly* as possible on the mark, touching the bed. Raise the hotend 0.1mm (a regular paper thickness) and zero all axis (G92 X0 Y0 Z0);
284
+* d) Raise the hotend 10mm (or more) for probe clearance, lower the Z probe (Z-Endstop) with M401 and place it just on that mark by moving X, Y and Z;
285
+* e) Lower the Z in 0.1mm steps, with the probe always touching the mark (it may be necessary to adjust X and Y as well) until you hear the "click" meaning the mechanical endstop was trigged. You can confirm with M119;
286
+* f) Now you have the probe in the same place as your hotend tip was before. Perform a M114 and write down the values, for example: X:24.3 Y:-31.4 Z:5.1;
287
+* g) You can raise the z probe with M402 command;
288
+* h) Fill the defines bellow multiplying the values by "-1" (just change the signal)
289
+
290
+
291
+* \#define X_PROBE_OFFSET_FROM_EXTRUDER -24.3
292
+* \#define Y_PROBE_OFFSET_FROM_EXTRUDER 31.4
293
+* \#define Z_PROBE_OFFSET_FROM_EXTRUDER -5.1
294
+
295
+
296
+The following options define the probing positions. These are good starting values.
297
+I recommend to keep a better clearance from borders in the first run and then make the probes as close as possible to borders:
298
+
299
+* \#define LEFT_PROBE_BED_POSITION 30
300
+* \#define RIGHT_PROBE_BED_POSITION 140
301
+* \#define BACK_PROBE_BED_POSITION 140
302
+* \#define FRONT_PROBE_BED_POSITION 30
303
+
304
+A few more options:
305
+
306
+* \#define XY_TRAVEL_SPEED 6000
307
+
308
+X and Y axis travel speed between probes, in mm/min.
309
+Bear in mind that really fast moves may render step skipping. 6000 mm/min (100mm/s) is a good value.
310
+
311
+* \#define Z_RAISE_BEFORE_PROBING 10
312
+* \#define Z_RAISE_BETWEEN_PROBINGS 10
313
+
314
+The Z axis is lifted when traveling to the first probe point by Z_RAISE_BEFORE_PROBING value
315
+and then lifted when traveling from first to second and second to third point by Z_RAISE_BETWEEN_PROBINGS.
316
+All values are in mm as usual. 
317
+
318
+That's it.. enjoy never having to calibrate your Z endstop neither leveling your bed by hand anymore ;-)
319
+
252 320
 
253 321
 
254 322
 

Loading…
Cancelar
Guardar