ソースを参照

Implement the "manual" option for ABL

Scott Lahteine 7年前
コミット
fcadc7bb1a
4個のファイルの変更543行の追加231行の削除
  1. 10
    11
      .travis.yml
  2. 525
    202
      Marlin/Marlin_main.cpp
  3. 0
    10
      Marlin/enum.h
  4. 8
    8
      Marlin/ultralcd.cpp

+ 10
- 11
.travis.yml ファイルの表示

@@ -124,24 +124,17 @@ script:
124 124
   - build_marlin
125 125
   #
126 126
   # Test a Sled Z Probe
127
-  #
128
-  - restore_configs
129
-  - opt_enable Z_PROBE_SLED
130
-  - build_marlin
131
-  #
132 127
   # ...with AUTO_BED_LEVELING_LINEAR, DEBUG_LEVELING_FEATURE, EEPROM_SETTINGS, and EEPROM_CHITCHAT
133 128
   #
134
-  - opt_enable AUTO_BED_LEVELING_LINEAR DEBUG_LEVELING_FEATURE EEPROM_SETTINGS EEPROM_CHITCHAT
129
+  - restore_configs
130
+  - opt_enable Z_PROBE_SLED AUTO_BED_LEVELING_LINEAR DEBUG_LEVELING_FEATURE EEPROM_SETTINGS EEPROM_CHITCHAT
135 131
   - build_marlin
136 132
   #
137 133
   # Test a Servo Probe
134
+  # ...with AUTO_BED_LEVELING_3POINT, DEBUG_LEVELING_FEATURE, EEPROM_SETTINGS, EEPROM_CHITCHAT, EXTENDED_CAPABILITIES_REPORT, and AUTO_REPORT_TEMPERATURES
138 135
   #
139 136
   - restore_configs
140 137
   - opt_enable NUM_SERVOS Z_ENDSTOP_SERVO_NR Z_SERVO_ANGLES DEACTIVATE_SERVOS_AFTER_MOVE
141
-  - build_marlin
142
-  #
143
-  # ...with AUTO_BED_LEVELING_3POINT, DEBUG_LEVELING_FEATURE, EEPROM_SETTINGS, EEPROM_CHITCHAT, EXTENDED_CAPABILITIES_REPORT, and AUTO_REPORT_TEMPERATURES
144
-  #
145 138
   - opt_enable AUTO_BED_LEVELING_3POINT DEBUG_LEVELING_FEATURE EEPROM_SETTINGS EEPROM_CHITCHAT
146 139
   - opt_enable_adv EXTENDED_CAPABILITIES_REPORT AUTO_REPORT_TEMPERATURES
147 140
   - build_marlin
@@ -149,7 +142,13 @@ script:
149 142
   # Test MESH_BED_LEVELING feature, with LCD
150 143
   #
151 144
   - restore_configs
152
-  - opt_enable MESH_BED_LEVELING MESH_G28_REST_ORIGIN MANUAL_BED_LEVELING ULTIMAKERCONTROLLER
145
+  - opt_enable MESH_BED_LEVELING MESH_G28_REST_ORIGIN LCD_BED_LEVELING ULTIMAKERCONTROLLER
146
+  - build_marlin
147
+  #
148
+  # Test PROBE_MANUALLY feature
149
+  #
150
+  - restore_configs
151
+  - opt_enable PROBE_MANUALLY AUTO_BED_LEVELING_BILINEAR
153 152
   - build_marlin
154 153
   #
155 154
   # Test EEPROM_SETTINGS, EEPROM_CHITCHAT, M100_FREE_MEMORY_WATCHER,

+ 525
- 202
Marlin/Marlin_main.cpp ファイルの表示

@@ -353,10 +353,10 @@ static long gcode_N, gcode_LastN, Stopped_gcode_LastN = 0;
353 353
  * the main loop. The process_next_command function parses the next
354 354
  * command and hands off execution to individual handler functions.
355 355
  */
356
-static char command_queue[BUFSIZE][MAX_CMD_SIZE];
356
+uint8_t commands_in_queue = 0; // Count of commands in the queue
357 357
 static uint8_t cmd_queue_index_r = 0, // Ring buffer read position
358
-               cmd_queue_index_w = 0, // Ring buffer write position
359
-               commands_in_queue = 0; // Count of commands in the queue
358
+               cmd_queue_index_w = 0; // Ring buffer write position
359
+static char command_queue[BUFSIZE][MAX_CMD_SIZE];
360 360
 
361 361
 /**
362 362
  * Current GCode Command
@@ -3502,6 +3502,12 @@ inline void gcode_G4() {
3502 3502
 
3503 3503
 #endif // Z_SAFE_HOMING
3504 3504
 
3505
+#if ENABLED(PROBE_MANUALLY)
3506
+  static bool g29_in_progress = false;
3507
+#else
3508
+  constexpr bool g29_in_progress = false;
3509
+#endif
3510
+
3505 3511
 /**
3506 3512
  * G28: Home all axes according to settings
3507 3513
  *
@@ -3529,6 +3535,11 @@ inline void gcode_G28() {
3529 3535
   // Wait for planner moves to finish!
3530 3536
   stepper.synchronize();
3531 3537
 
3538
+  // Cancel the active G29 session
3539
+  #if ENABLED(PROBE_MANUALLY)
3540
+    g29_in_progress = false;
3541
+  #endif
3542
+
3532 3543
   // Disable the leveling matrix before homing
3533 3544
   #if PLANNER_LEVELING
3534 3545
     #if ENABLED(AUTO_BED_LEVELING_UBL)
@@ -3719,9 +3730,9 @@ inline void gcode_G28() {
3719 3730
 
3720 3731
 #endif
3721 3732
 
3722
-#if ENABLED(MESH_BED_LEVELING)
3733
+#if ENABLED(MESH_BED_LEVELING) || ENABLED(PROBE_MANUALLY)
3723 3734
 
3724
-  inline void _mbl_goto_xy(const float &x, const float &y) {
3735
+  inline void _manual_goto_xy(const float &x, const float &y) {
3725 3736
     const float old_feedrate_mm_s = feedrate_mm_s;
3726 3737
 
3727 3738
     #if MANUAL_PROBE_HEIGHT > 0
@@ -3745,6 +3756,10 @@ inline void gcode_G28() {
3745 3756
     stepper.synchronize();
3746 3757
   }
3747 3758
 
3759
+#endif
3760
+
3761
+#if ENABLED(MESH_BED_LEVELING)
3762
+
3748 3763
   // Save 130 bytes with non-duplication of PSTR
3749 3764
   void say_not_entered() { SERIAL_PROTOCOLLNPGM(" not entered."); }
3750 3765
 
@@ -3835,7 +3850,7 @@ inline void gcode_G28() {
3835 3850
         // If there's another point to sample, move there with optional lift.
3836 3851
         if (mbl_probe_index < (MESH_NUM_X_POINTS) * (MESH_NUM_Y_POINTS)) {
3837 3852
           mbl.zigzag(mbl_probe_index, px, py);
3838
-          _mbl_goto_xy(mbl.index_to_xpos[px], mbl.index_to_ypos[py]);
3853
+          _manual_goto_xy(mbl.index_to_xpos[px], mbl.index_to_ypos[py]);
3839 3854
 
3840 3855
           #if HAS_SOFTWARE_ENDSTOPS
3841 3856
             // Disable software endstops to allow manual adjustment
@@ -3917,50 +3932,86 @@ inline void gcode_G28() {
3917 3932
 
3918 3933
 #elif HAS_ABL && DISABLED(AUTO_BED_LEVELING_UBL)
3919 3934
 
3935
+  #if ABL_GRID
3936
+    #if ENABLED(PROBE_Y_FIRST)
3937
+      #define PR_OUTER_VAR xCount
3938
+      #define PR_OUTER_END abl_grid_points_x
3939
+      #define PR_INNER_VAR yCount
3940
+      #define PR_INNER_END abl_grid_points_y
3941
+    #else
3942
+      #define PR_OUTER_VAR yCount
3943
+      #define PR_OUTER_END abl_grid_points_y
3944
+      #define PR_INNER_VAR xCount
3945
+      #define PR_INNER_END abl_grid_points_x
3946
+    #endif
3947
+  #endif
3948
+
3920 3949
   /**
3921 3950
    * G29: Detailed Z probe, probes the bed at 3 or more points.
3922 3951
    *      Will fail if the printer has not been homed with G28.
3923 3952
    *
3924 3953
    * Enhanced G29 Auto Bed Leveling Probe Routine
3925 3954
    *
3926
-   * Parameters With LINEAR and BILINEAR:
3955
+   *  D  Dry-Run mode. Just evaluate the bed Topology - Don't apply
3956
+   *     or alter the bed level data. Useful to check the topology
3957
+   *     after a first run of G29.
3958
+   *
3959
+   *  J  Jettison current bed leveling data
3960
+   *
3961
+   *  V  Set the verbose level (0-4). Example: "G29 V3"
3962
+   *
3963
+   * Parameters With LINEAR leveling only:
3927 3964
    *
3928 3965
    *  P  Set the size of the grid that will be probed (P x P points).
3929
-   *     Not supported by non-linear delta printer bed leveling.
3930 3966
    *     Example: "G29 P4"
3931 3967
    *
3932
-   *  S  Set the XY travel speed between probe points (in units/min)
3968
+   *  X  Set the X size of the grid that will be probed (X x Y points).
3969
+   *     Example: "G29 X7 Y5"
3933 3970
    *
3934
-   *  D  Dry-Run mode. Just evaluate the bed Topology - Don't apply
3935
-   *     or clean the rotation Matrix. Useful to check the topology
3936
-   *     after a first run of G29.
3937
-   *
3938
-   *  V  Set the verbose level (0-4). Example: "G29 V3"
3971
+   *  Y  Set the Y size of the grid that will be probed (X x Y points).
3939 3972
    *
3940 3973
    *  T  Generate a Bed Topology Report. Example: "G29 P5 T" for a detailed report.
3941 3974
    *     This is useful for manual bed leveling and finding flaws in the bed (to
3942 3975
    *     assist with part placement).
3943 3976
    *     Not supported by non-linear delta printer bed leveling.
3944 3977
    *
3978
+   * Parameters With LINEAR and BILINEAR leveling only:
3979
+   *
3980
+   *  S  Set the XY travel speed between probe points (in units/min)
3981
+   *
3945 3982
    *  F  Set the Front limit of the probing grid
3946 3983
    *  B  Set the Back limit of the probing grid
3947 3984
    *  L  Set the Left limit of the probing grid
3948 3985
    *  R  Set the Right limit of the probing grid
3949 3986
    *
3950
-   * Parameters with BILINEAR only:
3987
+   * Parameters with BILINEAR leveling only:
3951 3988
    *
3952 3989
    *  Z  Supply an additional Z probe offset
3953 3990
    *
3954
-   * Global Parameters:
3991
+   * Extra parameters with PROBE_MANUALLY:
3992
+   *
3993
+   *  To do manual probing simply repeat G29 until the procedure is complete.
3994
+   *  The first G29 accepts parameters. 'G29 Q' for status, 'G29 A' to abort.
3995
+   *
3996
+   *  Q  Query leveling and G29 state
3997
+   *
3998
+   *  A  Abort current leveling procedure
3999
+   *
4000
+   *  W  Write a mesh point. (Ignored during leveling.)
4001
+   *  X  Required X for mesh point
4002
+   *  Y  Required Y for mesh point
4003
+   *  Z  Required Z for mesh point
3955 4004
    *
3956
-   * E/e By default G29 will engage the Z probe, test the bed, then disengage.
4005
+   * Without PROBE_MANUALLY:
4006
+   *
4007
+   *  E  By default G29 will engage the Z probe, test the bed, then disengage.
3957 4008
    *     Include "E" to engage/disengage the Z probe for each sample.
3958 4009
    *     There's no extra effect if you have a fixed Z probe.
3959
-   *     Usage: "G29 E" or "G29 e"
3960 4010
    *
3961 4011
    */
3962 4012
   inline void gcode_G29() {
3963 4013
 
4014
+    // G29 Q is also available if debugging
3964 4015
     #if ENABLED(DEBUG_LEVELING_FEATURE)
3965 4016
       const bool query = code_seen('Q');
3966 4017
       const uint8_t old_debug_flags = marlin_debug_flags;
@@ -3970,37 +4021,148 @@ inline void gcode_G28() {
3970 4021
         log_machine_info();
3971 4022
       }
3972 4023
       marlin_debug_flags = old_debug_flags;
3973
-      if (query) return;
4024
+      #if DISABLED(PROBE_MANUALLY)
4025
+        if (query) return;
4026
+      #endif
3974 4027
     #endif
3975 4028
 
3976 4029
     // Don't allow auto-leveling without homing first
3977 4030
     if (axis_unhomed_error(true, true, true)) return;
3978 4031
 
3979
-    const int verbose_level = code_seen('V') ? code_value_int() : 1;
3980
-    if (verbose_level < 0 || verbose_level > 4) {
3981
-      SERIAL_PROTOCOLLNPGM("?(V)erbose Level is implausible (0-4).");
3982
-      return;
3983
-    }
4032
+    // Define local vars 'static' for manual probing, 'auto' otherwise
4033
+    #if ENABLED(PROBE_MANUALLY)
4034
+      #define ABL_VAR static
4035
+    #else
4036
+      #define ABL_VAR
4037
+    #endif
3984 4038
 
3985
-    bool dryrun = code_seen('D'),
3986
-         stow_probe_after_each = code_seen('E');
4039
+    ABL_VAR int verbose_level, abl_probe_index;
4040
+    ABL_VAR float xProbe, yProbe, measured_z;
4041
+    ABL_VAR bool dryrun, abl_should_enable;
4042
+
4043
+    #if HAS_SOFTWARE_ENDSTOPS
4044
+      ABL_VAR bool enable_soft_endstops = true;
4045
+    #endif
3987 4046
 
3988 4047
     #if ABL_GRID
4048
+      ABL_VAR uint8_t PR_OUTER_VAR;
4049
+      ABL_VAR  int8_t PR_INNER_VAR;
4050
+      ABL_VAR int left_probe_bed_position, right_probe_bed_position, front_probe_bed_position, back_probe_bed_position;
4051
+      ABL_VAR float xGridSpacing, yGridSpacing;
3989 4052
 
3990
-      if (verbose_level > 0) {
3991
-        SERIAL_PROTOCOLLNPGM("G29 Auto Bed Leveling");
3992
-        if (dryrun) SERIAL_PROTOCOLLNPGM("Running in DRY-RUN mode");
3993
-      }
4053
+      #define ABL_GRID_MAX (ABL_GRID_MAX_POINTS_X) * (ABL_GRID_MAX_POINTS_Y)
3994 4054
 
3995 4055
       #if ABL_PLANAR
4056
+        ABL_VAR uint8_t abl_grid_points_x = ABL_GRID_MAX_POINTS_X,
4057
+                        abl_grid_points_y = ABL_GRID_MAX_POINTS_Y;
4058
+        ABL_VAR int abl2;
4059
+        ABL_VAR bool do_topography_map;
4060
+      #else // 3-point
4061
+        uint8_t constexpr abl_grid_points_x = ABL_GRID_MAX_POINTS_X,
4062
+                          abl_grid_points_y = ABL_GRID_MAX_POINTS_Y;
4063
+
4064
+        int constexpr abl2 = ABL_GRID_MAX;
4065
+      #endif
4066
+
4067
+      #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
4068
+
4069
+        ABL_VAR float zoffset;
4070
+
4071
+      #elif ENABLED(AUTO_BED_LEVELING_LINEAR)
4072
+
4073
+        ABL_VAR int indexIntoAB[ABL_GRID_MAX_POINTS_X][ABL_GRID_MAX_POINTS_Y];
4074
+
4075
+        ABL_VAR float eqnAMatrix[ABL_GRID_MAX * 3], // "A" matrix of the linear system of equations
4076
+                     eqnBVector[ABL_GRID_MAX],     // "B" vector of Z points
4077
+                     mean;
4078
+      #endif
4079
+
4080
+    #elif ENABLED(AUTO_BED_LEVELING_3POINT)
4081
+
4082
+      // Probe at 3 arbitrary points
4083
+      ABL_VAR vector_3 points[3] = {
4084
+        vector_3(ABL_PROBE_PT_1_X, ABL_PROBE_PT_1_Y, 0),
4085
+        vector_3(ABL_PROBE_PT_2_X, ABL_PROBE_PT_2_Y, 0),
4086
+        vector_3(ABL_PROBE_PT_3_X, ABL_PROBE_PT_3_Y, 0)
4087
+      };
4088
+
4089
+    #endif // AUTO_BED_LEVELING_3POINT
3996 4090
 
3997
-        bool do_topography_map = verbose_level > 2 || code_seen('T');
4091
+    /**
4092
+     * On the initial G29 fetch command parameters.
4093
+     */
4094
+    if (!g29_in_progress) {
4095
+
4096
+      abl_probe_index = 0;
4097
+      abl_should_enable = planner.abl_enabled;
4098
+
4099
+      #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
4100
+
4101
+        if (code_seen('W')) {
4102
+          if (!bilinear_grid_spacing[X_AXIS]) {
4103
+            SERIAL_ERROR_START;
4104
+            SERIAL_ERRORLNPGM("No bilinear grid");
4105
+            return;
4106
+          }
4107
+
4108
+          const float z = code_seen('Z') && code_has_value() ? code_value_float() : 99999;
4109
+          if (!WITHIN(z, -10, 10)) {
4110
+            SERIAL_ERROR_START;
4111
+            SERIAL_ERRORLNPGM("Bad Z value");
4112
+            return;
4113
+          }
4114
+
4115
+          const float x = code_seen('X') && code_has_value() ? code_value_float() : 99999,
4116
+                      y = code_seen('Y') && code_has_value() ? code_value_float() : 99999;
4117
+          int8_t i = code_seen('I') && code_has_value() ? code_value_byte() : -1,
4118
+                 j = code_seen('J') && code_has_value() ? code_value_byte() : -1;
4119
+
4120
+          if (x < 99998 && y < 99998) {
4121
+            // Get nearest i / j from x / y
4122
+            i = (x - LOGICAL_X_POSITION(bilinear_start[X_AXIS]) + 0.5 * xGridSpacing) / xGridSpacing;
4123
+            j = (y - LOGICAL_Y_POSITION(bilinear_start[Y_AXIS]) + 0.5 * yGridSpacing) / yGridSpacing;
4124
+            i = constrain(i, 0, ABL_GRID_MAX_POINTS_X - 1);
4125
+            j = constrain(j, 0, ABL_GRID_MAX_POINTS_Y - 1);
4126
+          }
4127
+          if (WITHIN(i, 0, ABL_GRID_MAX_POINTS_X - 1) && WITHIN(j, 0, ABL_GRID_MAX_POINTS_Y)) {
4128
+            set_bed_leveling_enabled(false);
4129
+            bed_level_grid[i][j] = z;
4130
+            #if ENABLED(ABL_BILINEAR_SUBDIVISION)
4131
+              bed_level_virt_interpolate();
4132
+            #endif
4133
+            set_bed_leveling_enabled(abl_should_enable);
4134
+          }
4135
+          return;
4136
+        } // code_seen('W')
4137
+
4138
+      #endif
4139
+
4140
+      #if PLANNER_LEVELING
4141
+
4142
+        // Jettison bed leveling data
4143
+        if (code_seen('J')) {
4144
+          reset_bed_level();
4145
+          return;
4146
+        }
4147
+
4148
+      #endif
4149
+
4150
+      verbose_level = code_seen('V') && code_has_value() ? code_value_int() : 0;
4151
+      if (!WITHIN(verbose_level, 0, 4)) {
4152
+        SERIAL_PROTOCOLLNPGM("?(V)erbose Level is implausible (0-4).");
4153
+        return;
4154
+      }
4155
+
4156
+      dryrun = code_seen('D') ? code_value_bool() : false;
4157
+
4158
+      #if ENABLED(AUTO_BED_LEVELING_LINEAR)
4159
+
4160
+        do_topography_map = verbose_level > 2 || code_seen('T');
3998 4161
 
3999 4162
         // X and Y specify points in each direction, overriding the default
4000 4163
         // These values may be saved with the completed mesh
4001
-        int abl_grid_points_x = code_seen('X') ? code_value_int() : ABL_GRID_MAX_POINTS_X,
4002
-            abl_grid_points_y = code_seen('Y') ? code_value_int() : ABL_GRID_MAX_POINTS_Y;
4003
-
4164
+        abl_grid_points_x = code_seen('X') ? code_value_int() : ABL_GRID_MAX_POINTS_X;
4165
+        abl_grid_points_y = code_seen('Y') ? code_value_int() : ABL_GRID_MAX_POINTS_Y;
4004 4166
         if (code_seen('P')) abl_grid_points_x = abl_grid_points_y = code_value_int();
4005 4167
 
4006 4168
         if (abl_grid_points_x < 2 || abl_grid_points_y < 2) {
@@ -4008,91 +4170,98 @@ inline void gcode_G28() {
4008 4170
           return;
4009 4171
         }
4010 4172
 
4011
-      #else
4173
+        abl2 = abl_grid_points_x * abl_grid_points_y;
4012 4174
 
4013
-         const uint8_t abl_grid_points_x = ABL_GRID_MAX_POINTS_X, abl_grid_points_y = ABL_GRID_MAX_POINTS_Y;
4175
+      #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
4176
+
4177
+        zoffset = code_seen('Z') ? code_value_axis_units(Z_AXIS) : 0;
4178
+        #if HAS_BED_PROBE
4179
+          zoffset += zprobe_zoffset;
4180
+        #endif
4014 4181
 
4015 4182
       #endif
4016 4183
 
4017
-      xy_probe_feedrate_mm_s = MMM_TO_MMS(code_seen('S') ? code_value_linear_units() : XY_PROBE_SPEED);
4184
+      #if ABL_GRID
4018 4185
 
4019
-      int left_probe_bed_position = code_seen('L') ? (int)code_value_axis_units(X_AXIS) : LOGICAL_X_POSITION(LEFT_PROBE_BED_POSITION),
4020
-          right_probe_bed_position = code_seen('R') ? (int)code_value_axis_units(X_AXIS) : LOGICAL_X_POSITION(RIGHT_PROBE_BED_POSITION),
4021
-          front_probe_bed_position = code_seen('F') ? (int)code_value_axis_units(Y_AXIS) : LOGICAL_Y_POSITION(FRONT_PROBE_BED_POSITION),
4022
-          back_probe_bed_position = code_seen('B') ? (int)code_value_axis_units(Y_AXIS) : LOGICAL_Y_POSITION(BACK_PROBE_BED_POSITION);
4186
+        xy_probe_feedrate_mm_s = MMM_TO_MMS(code_seen('S') ? code_value_linear_units() : XY_PROBE_SPEED);
4023 4187
 
4024
-      const bool left_out_l = left_probe_bed_position < LOGICAL_X_POSITION(MIN_PROBE_X),
4025
-                 left_out = left_out_l || left_probe_bed_position > right_probe_bed_position - (MIN_PROBE_EDGE),
4026
-                 right_out_r = right_probe_bed_position > LOGICAL_X_POSITION(MAX_PROBE_X),
4027
-                 right_out = right_out_r || right_probe_bed_position < left_probe_bed_position + MIN_PROBE_EDGE,
4028
-                 front_out_f = front_probe_bed_position < LOGICAL_Y_POSITION(MIN_PROBE_Y),
4029
-                 front_out = front_out_f || front_probe_bed_position > back_probe_bed_position - (MIN_PROBE_EDGE),
4030
-                 back_out_b = back_probe_bed_position > LOGICAL_Y_POSITION(MAX_PROBE_Y),
4031
-                 back_out = back_out_b || back_probe_bed_position < front_probe_bed_position + MIN_PROBE_EDGE;
4188
+        left_probe_bed_position = code_seen('L') ? (int)code_value_axis_units(X_AXIS) : LOGICAL_X_POSITION(LEFT_PROBE_BED_POSITION);
4189
+        right_probe_bed_position = code_seen('R') ? (int)code_value_axis_units(X_AXIS) : LOGICAL_X_POSITION(RIGHT_PROBE_BED_POSITION);
4190
+        front_probe_bed_position = code_seen('F') ? (int)code_value_axis_units(Y_AXIS) : LOGICAL_Y_POSITION(FRONT_PROBE_BED_POSITION);
4191
+        back_probe_bed_position = code_seen('B') ? (int)code_value_axis_units(Y_AXIS) : LOGICAL_Y_POSITION(BACK_PROBE_BED_POSITION);
4032 4192
 
4033
-      if (left_out || right_out || front_out || back_out) {
4034
-        if (left_out) {
4035
-          out_of_range_error(PSTR("(L)eft"));
4036
-          left_probe_bed_position = left_out_l ? LOGICAL_X_POSITION(MIN_PROBE_X) : right_probe_bed_position - (MIN_PROBE_EDGE);
4037
-        }
4038
-        if (right_out) {
4039
-          out_of_range_error(PSTR("(R)ight"));
4040
-          right_probe_bed_position = right_out_r ? LOGICAL_Y_POSITION(MAX_PROBE_X) : left_probe_bed_position + MIN_PROBE_EDGE;
4041
-        }
4042
-        if (front_out) {
4043
-          out_of_range_error(PSTR("(F)ront"));
4044
-          front_probe_bed_position = front_out_f ? LOGICAL_Y_POSITION(MIN_PROBE_Y) : back_probe_bed_position - (MIN_PROBE_EDGE);
4045
-        }
4046
-        if (back_out) {
4047
-          out_of_range_error(PSTR("(B)ack"));
4048
-          back_probe_bed_position = back_out_b ? LOGICAL_Y_POSITION(MAX_PROBE_Y) : front_probe_bed_position + MIN_PROBE_EDGE;
4049
-        }
4050
-        return;
4051
-      }
4193
+        const bool left_out_l = left_probe_bed_position < LOGICAL_X_POSITION(MIN_PROBE_X),
4194
+                   left_out = left_out_l || left_probe_bed_position > right_probe_bed_position - (MIN_PROBE_EDGE),
4195
+                   right_out_r = right_probe_bed_position > LOGICAL_X_POSITION(MAX_PROBE_X),
4196
+                   right_out = right_out_r || right_probe_bed_position < left_probe_bed_position + MIN_PROBE_EDGE,
4197
+                   front_out_f = front_probe_bed_position < LOGICAL_Y_POSITION(MIN_PROBE_Y),
4198
+                   front_out = front_out_f || front_probe_bed_position > back_probe_bed_position - (MIN_PROBE_EDGE),
4199
+                   back_out_b = back_probe_bed_position > LOGICAL_Y_POSITION(MAX_PROBE_Y),
4200
+                   back_out = back_out_b || back_probe_bed_position < front_probe_bed_position + MIN_PROBE_EDGE;
4052 4201
 
4053
-    #endif // ABL_GRID
4202
+        if (left_out || right_out || front_out || back_out) {
4203
+          if (left_out) {
4204
+            out_of_range_error(PSTR("(L)eft"));
4205
+            left_probe_bed_position = left_out_l ? LOGICAL_X_POSITION(MIN_PROBE_X) : right_probe_bed_position - (MIN_PROBE_EDGE);
4206
+          }
4207
+          if (right_out) {
4208
+            out_of_range_error(PSTR("(R)ight"));
4209
+            right_probe_bed_position = right_out_r ? LOGICAL_Y_POSITION(MAX_PROBE_X) : left_probe_bed_position + MIN_PROBE_EDGE;
4210
+          }
4211
+          if (front_out) {
4212
+            out_of_range_error(PSTR("(F)ront"));
4213
+            front_probe_bed_position = front_out_f ? LOGICAL_Y_POSITION(MIN_PROBE_Y) : back_probe_bed_position - (MIN_PROBE_EDGE);
4214
+          }
4215
+          if (back_out) {
4216
+            out_of_range_error(PSTR("(B)ack"));
4217
+            back_probe_bed_position = back_out_b ? LOGICAL_Y_POSITION(MAX_PROBE_Y) : front_probe_bed_position + MIN_PROBE_EDGE;
4218
+          }
4219
+          return;
4220
+        }
4054 4221
 
4055
-    stepper.synchronize();
4222
+        // probe at the points of a lattice grid
4223
+        xGridSpacing = (right_probe_bed_position - left_probe_bed_position) / (abl_grid_points_x - 1);
4224
+        yGridSpacing = (back_probe_bed_position - front_probe_bed_position) / (abl_grid_points_y - 1);
4056 4225
 
4057
-    // Disable auto bed leveling during G29
4058
-    bool abl_should_enable = planner.abl_enabled;
4226
+      #endif // ABL_GRID
4059 4227
 
4060
-    planner.abl_enabled = false;
4228
+      if (verbose_level > 0) {
4229
+        SERIAL_PROTOCOLLNPGM("G29 Auto Bed Leveling");
4230
+        if (dryrun) SERIAL_PROTOCOLLNPGM("Running in DRY-RUN mode");
4231
+      }
4061 4232
 
4062
-    if (!dryrun) {
4063
-      // Re-orient the current position without leveling
4064
-      // based on where the steppers are positioned.
4065
-      set_current_from_steppers_for_axis(ALL_AXES);
4233
+      stepper.synchronize();
4066 4234
 
4067
-      // Sync the planner to where the steppers stopped
4068
-      SYNC_PLAN_POSITION_KINEMATIC();
4069
-    }
4235
+      // Disable auto bed leveling during G29
4236
+      planner.abl_enabled = false;
4070 4237
 
4071
-    setup_for_endstop_or_probe_move();
4238
+      if (!dryrun) {
4239
+        // Re-orient the current position without leveling
4240
+        // based on where the steppers are positioned.
4241
+        set_current_from_steppers_for_axis(ALL_AXES);
4072 4242
 
4073
-    // Deploy the probe. Probe will raise if needed.
4074
-    if (DEPLOY_PROBE()) {
4075
-      planner.abl_enabled = abl_should_enable;
4076
-      return;
4077
-    }
4243
+        // Sync the planner to where the steppers stopped
4244
+        SYNC_PLAN_POSITION_KINEMATIC();
4245
+      }
4078 4246
 
4079
-    float xProbe = 0, yProbe = 0, measured_z = 0;
4247
+      setup_for_endstop_or_probe_move();
4080 4248
 
4081
-    #if ABL_GRID
4249
+      //xProbe = yProbe = measured_z = 0;
4082 4250
 
4083
-      // probe at the points of a lattice grid
4084
-      const float xGridSpacing = (right_probe_bed_position - left_probe_bed_position) / (abl_grid_points_x - 1),
4085
-                  yGridSpacing = (back_probe_bed_position - front_probe_bed_position) / (abl_grid_points_y - 1);
4251
+      #if HAS_BED_PROBE
4252
+        // Deploy the probe. Probe will raise if needed.
4253
+        if (DEPLOY_PROBE()) {
4254
+          planner.abl_enabled = abl_should_enable;
4255
+          return;
4256
+        }
4257
+      #endif
4086 4258
 
4087 4259
       #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
4088 4260
 
4089
-        float zoffset = zprobe_zoffset;
4090
-        if (code_seen('Z')) zoffset += code_value_axis_units(Z_AXIS);
4091
-
4092 4261
         if ( xGridSpacing != bilinear_grid_spacing[X_AXIS]
4093 4262
           || yGridSpacing != bilinear_grid_spacing[Y_AXIS]
4094
-          || left_probe_bed_position != bilinear_start[X_AXIS]
4095
-          || front_probe_bed_position != bilinear_start[Y_AXIS]
4263
+          || left_probe_bed_position != LOGICAL_X_POSITION(bilinear_start[X_AXIS])
4264
+          || front_probe_bed_position != LOGICAL_Y_POSITION(bilinear_start[Y_AXIS])
4096 4265
         ) {
4097 4266
           if (dryrun) {
4098 4267
             // Before reset bed level, re-enable to correct the position
@@ -4101,164 +4270,311 @@ inline void gcode_G28() {
4101 4270
           // Reset grid to 0.0 or "not probed". (Also disables ABL)
4102 4271
           reset_bed_level();
4103 4272
 
4104
-          #if ENABLED(ABL_BILINEAR_SUBDIVISION)
4105
-            bilinear_grid_spacing_virt[X_AXIS] = xGridSpacing / (BILINEAR_SUBDIVISIONS);
4106
-            bilinear_grid_spacing_virt[Y_AXIS] = yGridSpacing / (BILINEAR_SUBDIVISIONS);
4107
-          #endif
4273
+          // Initialize a grid with the given dimensions
4108 4274
           bilinear_grid_spacing[X_AXIS] = xGridSpacing;
4109 4275
           bilinear_grid_spacing[Y_AXIS] = yGridSpacing;
4110 4276
           bilinear_start[X_AXIS] = RAW_X_POSITION(left_probe_bed_position);
4111 4277
           bilinear_start[Y_AXIS] = RAW_Y_POSITION(front_probe_bed_position);
4112 4278
 
4279
+          #if ENABLED(ABL_BILINEAR_SUBDIVISION)
4280
+            bilinear_grid_spacing_virt[X_AXIS] = xGridSpacing / (BILINEAR_SUBDIVISIONS);
4281
+            bilinear_grid_spacing_virt[Y_AXIS] = yGridSpacing / (BILINEAR_SUBDIVISIONS);
4282
+          #endif
4283
+
4113 4284
           // Can't re-enable (on error) until the new grid is written
4114 4285
           abl_should_enable = false;
4115 4286
         }
4116 4287
 
4117 4288
       #elif ENABLED(AUTO_BED_LEVELING_LINEAR)
4118 4289
 
4119
-        /**
4120
-         * solve the plane equation ax + by + d = z
4121
-         * A is the matrix with rows [x y 1] for all the probed points
4122
-         * B is the vector of the Z positions
4123
-         * the normal vector to the plane is formed by the coefficients of the
4124
-         * plane equation in the standard form, which is Vx*x+Vy*y+Vz*z+d = 0
4125
-         * so Vx = -a Vy = -b Vz = 1 (we want the vector facing towards positive Z
4126
-         */
4290
+        mean = 0.0;
4127 4291
 
4128
-        const int abl2 = abl_grid_points_x * abl_grid_points_y;
4292
+      #endif // AUTO_BED_LEVELING_LINEAR
4129 4293
 
4130
-        int indexIntoAB[abl_grid_points_x][abl_grid_points_y],
4131
-            probe_index = -1;
4294
+      #if ENABLED(AUTO_BED_LEVELING_3POINT)
4132 4295
 
4133
-        float eqnAMatrix[abl2 * 3], // "A" matrix of the linear system of equations
4134
-              eqnBVector[abl2],     // "B" vector of Z points
4135
-              mean = 0.0;
4296
+        #if ENABLED(DEBUG_LEVELING_FEATURE)
4297
+          if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("> 3-point Leveling");
4298
+        #endif
4136 4299
 
4137
-      #endif // AUTO_BED_LEVELING_LINEAR
4300
+        // Probe at 3 arbitrary points
4301
+        points[0].z = points[1].z = points[2].z = 0;
4138 4302
 
4139
-      #if ENABLED(PROBE_Y_FIRST)
4140
-        #define PR_OUTER_VAR xCount
4141
-        #define PR_OUTER_NUM abl_grid_points_x
4142
-        #define PR_INNER_VAR yCount
4143
-        #define PR_INNER_NUM abl_grid_points_y
4144
-      #else
4145
-        #define PR_OUTER_VAR yCount
4146
-        #define PR_OUTER_NUM abl_grid_points_y
4147
-        #define PR_INNER_VAR xCount
4148
-        #define PR_INNER_NUM abl_grid_points_x
4149
-      #endif
4303
+      #endif // AUTO_BED_LEVELING_3POINT
4150 4304
 
4151
-      bool zig = PR_OUTER_NUM & 1;  // Always end at RIGHT and BACK_PROBE_BED_POSITION
4305
+    } // !g29_in_progress
4152 4306
 
4153
-      // Outer loop is Y with PROBE_Y_FIRST disabled
4154
-      for (uint8_t PR_OUTER_VAR = 0; PR_OUTER_VAR < PR_OUTER_NUM; PR_OUTER_VAR++) {
4307
+    #if ENABLED(PROBE_MANUALLY)
4155 4308
 
4156
-        int8_t inStart, inStop, inInc;
4309
+      // Abort current G29 procedure, go back to ABLStart
4310
+      if (code_seen('A') && g29_in_progress) {
4311
+        SERIAL_PROTOCOLLNPGM("Manual G29 aborted");
4312
+        #if HAS_SOFTWARE_ENDSTOPS
4313
+          soft_endstops_enabled = enable_soft_endstops;
4314
+        #endif
4315
+        planner.abl_enabled = abl_should_enable;
4316
+        g29_in_progress = false;
4317
+      }
4157 4318
 
4158
-        if (zig) { // away from origin
4159
-          inStart = 0;
4160
-          inStop = PR_INNER_NUM;
4161
-          inInc = 1;
4162
-        }
4163
-        else {     // towards origin
4164
-          inStart = PR_INNER_NUM - 1;
4165
-          inStop = -1;
4166
-          inInc = -1;
4319
+      // Query G29 status
4320
+      if (code_seen('Q')) {
4321
+        if (!g29_in_progress)
4322
+          SERIAL_PROTOCOLLNPGM("Manual G29 idle");
4323
+        else {
4324
+          SERIAL_PROTOCOLPAIR("Manual G29 point ", abl_probe_index + 1);
4325
+          SERIAL_PROTOCOLLNPAIR(" of ", abl2);
4167 4326
         }
4327
+      }
4328
+
4329
+      if (code_seen('A') || code_seen('Q')) return;
4168 4330
 
4169
-        zig = !zig; // zag
4331
+      // Fall through to probe the first point
4332
+      g29_in_progress = true;
4333
+
4334
+      if (abl_probe_index == 0) {
4335
+        // For the initial G29 S2 save software endstop state
4336
+        #if HAS_SOFTWARE_ENDSTOPS
4337
+          enable_soft_endstops = soft_endstops_enabled;
4338
+        #endif
4339
+      }
4340
+      else {
4341
+        // For G29 after adjusting Z.
4342
+        // Save the previous Z before going to the next point
4343
+        measured_z = current_position[Z_AXIS];
4344
+
4345
+        #if ENABLED(AUTO_BED_LEVELING_LINEAR)
4346
+
4347
+          mean += measured_z;
4348
+          eqnBVector[abl_probe_index] = measured_z;
4349
+          eqnAMatrix[abl_probe_index + 0 * abl2] = xProbe;
4350
+          eqnAMatrix[abl_probe_index + 1 * abl2] = yProbe;
4351
+          eqnAMatrix[abl_probe_index + 2 * abl2] = 1;
4352
+
4353
+        #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
4170 4354
 
4171
-        // Inner loop is Y with PROBE_Y_FIRST enabled
4172
-        for (int8_t PR_INNER_VAR = inStart; PR_INNER_VAR != inStop; PR_INNER_VAR += inInc) {
4355
+          bed_level_grid[xCount][yCount] = measured_z + zoffset;
4173 4356
 
4174
-          float xBase = left_probe_bed_position + xGridSpacing * xCount,
4175
-                yBase = front_probe_bed_position + yGridSpacing * yCount;
4357
+        #elif ENABLED(AUTO_BED_LEVELING_3POINT)
4358
+
4359
+          points[i].z = measured_z;
4360
+
4361
+        #endif
4362
+      }
4363
+
4364
+      //
4365
+      // If there's another point to sample, move there with optional lift.
4366
+      //
4367
+
4368
+      #if ABL_GRID
4369
+
4370
+        // Find a next point to probe
4371
+        // On the first G29 this will be the first probe point
4372
+        while (abl_probe_index < abl2) {
4373
+
4374
+          // Set xCount, yCount based on abl_probe_index, with zig-zag
4375
+          PR_OUTER_VAR = abl_probe_index / PR_INNER_END;
4376
+          PR_INNER_VAR = abl_probe_index - (PR_OUTER_VAR * PR_INNER_END);
4377
+
4378
+          bool zig = (PR_OUTER_VAR & 1) != ((PR_OUTER_END) & 1);
4379
+
4380
+          if (zig) PR_INNER_VAR = (PR_INNER_END - 1) - PR_INNER_VAR;
4381
+
4382
+          const float xBase = left_probe_bed_position + xGridSpacing * xCount,
4383
+                      yBase = front_probe_bed_position + yGridSpacing * yCount;
4176 4384
 
4177 4385
           xProbe = floor(xBase + (xBase < 0 ? 0 : 0.5));
4178 4386
           yProbe = floor(yBase + (yBase < 0 ? 0 : 0.5));
4179 4387
 
4180 4388
           #if ENABLED(AUTO_BED_LEVELING_LINEAR)
4181
-            indexIntoAB[xCount][yCount] = ++probe_index;
4389
+            indexIntoAB[xCount][yCount] = abl_probe_index;
4390
+          #endif
4391
+
4392
+          float pos[XYZ] = { xProbe, yProbe, 0 };
4393
+          if (position_is_reachable(pos)) break;
4394
+          ++abl_probe_index;
4395
+        }
4396
+
4397
+        // Is there a next point to move to?
4398
+        if (abl_probe_index < abl2) {
4399
+          _manual_goto_xy(xProbe, yProbe); // Can be used here too!
4400
+          ++abl_probe_index;
4401
+          #if HAS_SOFTWARE_ENDSTOPS
4402
+            // Disable software endstops to allow manual adjustment
4403
+            // If G29 is not completed, they will not be re-enabled
4404
+            soft_endstops_enabled = false;
4182 4405
           #endif
4406
+          return;
4407
+        }
4408
+        else {
4409
+          // Then leveling is done!
4410
+          // G29 finishing code goes here
4183 4411
 
4184
-          #if IS_KINEMATIC
4185
-            // Avoid probing outside the round or hexagonal area
4186
-            float pos[XYZ] = { xProbe, yProbe, 0 };
4187
-            if (!position_is_reachable(pos, true)) continue;
4412
+          // After recording the last point, activate abl
4413
+          SERIAL_PROTOCOLLNPGM("Grid probing done.");
4414
+          g29_in_progress = false;
4415
+
4416
+          // Re-enable software endstops, if needed
4417
+          #if HAS_SOFTWARE_ENDSTOPS
4418
+            soft_endstops_enabled = enable_soft_endstops;
4188 4419
           #endif
4420
+        }
4189 4421
 
4190
-          measured_z = probe_pt(xProbe, yProbe, stow_probe_after_each, verbose_level);
4422
+      #elif ENABLED(AUTO_BED_LEVELING_3POINT)
4191 4423
 
4192
-          if (measured_z == NAN) {
4193
-            planner.abl_enabled = abl_should_enable;
4194
-            return;
4424
+        // Probe at 3 arbitrary points
4425
+        if (abl_probe_index < 3) {
4426
+          xProbe = LOGICAL_X_POSITION(points[i].x);
4427
+          yProbe = LOGICAL_Y_POSITION(points[i].y);
4428
+          ++abl_probe_index;
4429
+          #if HAS_SOFTWARE_ENDSTOPS
4430
+            // Disable software endstops to allow manual adjustment
4431
+            // If G29 is not completed, they will not be re-enabled
4432
+            soft_endstops_enabled = false;
4433
+          #endif
4434
+          return;
4435
+        }
4436
+        else {
4437
+
4438
+          SERIAL_PROTOCOLLNPGM("3-point probing done.");
4439
+          g29_in_progress = false;
4440
+
4441
+          // Re-enable software endstops, if needed
4442
+          #if HAS_SOFTWARE_ENDSTOPS
4443
+            soft_endstops_enabled = enable_soft_endstops;
4444
+          #endif
4445
+
4446
+          if (!dryrun) {
4447
+            vector_3 planeNormal = vector_3::cross(points[0] - points[1], points[2] - points[1]).get_normal();
4448
+            if (planeNormal.z < 0) {
4449
+              planeNormal.x *= -1;
4450
+              planeNormal.y *= -1;
4451
+              planeNormal.z *= -1;
4452
+            }
4453
+            planner.bed_level_matrix = matrix_3x3::create_look_at(planeNormal);
4454
+
4455
+            // Can't re-enable (on error) until the new grid is written
4456
+            abl_should_enable = false;
4195 4457
           }
4196 4458
 
4197
-          #if ENABLED(AUTO_BED_LEVELING_LINEAR)
4459
+        }
4198 4460
 
4199
-            mean += measured_z;
4200
-            eqnBVector[probe_index] = measured_z;
4201
-            eqnAMatrix[probe_index + 0 * abl2] = xProbe;
4202
-            eqnAMatrix[probe_index + 1 * abl2] = yProbe;
4203
-            eqnAMatrix[probe_index + 2 * abl2] = 1;
4461
+      #endif // AUTO_BED_LEVELING_3POINT
4204 4462
 
4205
-          #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
4206 4463
 
4207
-            bed_level_grid[xCount][yCount] = measured_z + zoffset;
4464
+    #else // !PROBE_MANUALLY
4208 4465
 
4209
-          #endif
4210 4466
 
4211
-          idle();
4467
+      bool stow_probe_after_each = code_seen('E');
4212 4468
 
4213
-        } // inner
4214
-      } // outer
4469
+      #if ABL_GRID
4215 4470
 
4216
-    #elif ENABLED(AUTO_BED_LEVELING_3POINT)
4471
+        bool zig = PR_OUTER_END & 1;  // Always end at RIGHT and BACK_PROBE_BED_POSITION
4217 4472
 
4218
-      #if ENABLED(DEBUG_LEVELING_FEATURE)
4219
-        if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("> 3-point Leveling");
4220
-      #endif
4473
+        // Outer loop is Y with PROBE_Y_FIRST disabled
4474
+        for (uint8_t PR_OUTER_VAR = 0; PR_OUTER_VAR < PR_OUTER_END; PR_OUTER_VAR++) {
4221 4475
 
4222
-      // Probe at 3 arbitrary points
4223
-      vector_3 points[3] = {
4224
-        vector_3(ABL_PROBE_PT_1_X, ABL_PROBE_PT_1_Y, 0),
4225
-        vector_3(ABL_PROBE_PT_2_X, ABL_PROBE_PT_2_Y, 0),
4226
-        vector_3(ABL_PROBE_PT_3_X, ABL_PROBE_PT_3_Y, 0)
4227
-      };
4476
+          int8_t inStart, inStop, inInc;
4228 4477
 
4229
-      for (uint8_t i = 0; i < 3; ++i) {
4230
-        // Retain the last probe position
4231
-        xProbe = LOGICAL_X_POSITION(points[i].x);
4232
-        yProbe = LOGICAL_Y_POSITION(points[i].y);
4233
-        measured_z = points[i].z = probe_pt(xProbe, yProbe, stow_probe_after_each, verbose_level);
4234
-      }
4478
+          if (zig) { // away from origin
4479
+            inStart = 0;
4480
+            inStop = PR_INNER_END;
4481
+            inInc = 1;
4482
+          }
4483
+          else {     // towards origin
4484
+            inStart = PR_INNER_END - 1;
4485
+            inStop = -1;
4486
+            inInc = -1;
4487
+          }
4235 4488
 
4236
-      if (measured_z == NAN) {
4237
-        planner.abl_enabled = abl_should_enable;
4238
-        return;
4239
-      }
4489
+          zig = !zig; // zag
4240 4490
 
4241
-      if (!dryrun) {
4242
-        vector_3 planeNormal = vector_3::cross(points[0] - points[1], points[2] - points[1]).get_normal();
4243
-        if (planeNormal.z < 0) {
4244
-          planeNormal.x *= -1;
4245
-          planeNormal.y *= -1;
4246
-          planeNormal.z *= -1;
4491
+          // Inner loop is Y with PROBE_Y_FIRST enabled
4492
+          for (int8_t PR_INNER_VAR = inStart; PR_INNER_VAR != inStop; PR_INNER_VAR += inInc) {
4493
+
4494
+            float xBase = left_probe_bed_position + xGridSpacing * xCount,
4495
+                  yBase = front_probe_bed_position + yGridSpacing * yCount;
4496
+
4497
+            xProbe = floor(xBase + (xBase < 0 ? 0 : 0.5));
4498
+            yProbe = floor(yBase + (yBase < 0 ? 0 : 0.5));
4499
+
4500
+            #if ENABLED(AUTO_BED_LEVELING_LINEAR)
4501
+              indexIntoAB[xCount][yCount] = ++abl_probe_index;
4502
+            #endif
4503
+
4504
+            #if IS_KINEMATIC
4505
+              // Avoid probing outside the round or hexagonal area
4506
+              float pos[XYZ] = { xProbe, yProbe, 0 };
4507
+              if (!position_is_reachable(pos, true)) continue;
4508
+            #endif
4509
+
4510
+            measured_z = probe_pt(xProbe, yProbe, stow_probe_after_each, verbose_level);
4511
+
4512
+            if (measured_z == NAN) {
4513
+              planner.abl_enabled = abl_should_enable;
4514
+              return;
4515
+            }
4516
+
4517
+            #if ENABLED(AUTO_BED_LEVELING_LINEAR)
4518
+
4519
+              mean += measured_z;
4520
+              eqnBVector[abl_probe_index] = measured_z;
4521
+              eqnAMatrix[abl_probe_index + 0 * abl2] = xProbe;
4522
+              eqnAMatrix[abl_probe_index + 1 * abl2] = yProbe;
4523
+              eqnAMatrix[abl_probe_index + 2 * abl2] = 1;
4524
+
4525
+            #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
4526
+
4527
+              bed_level_grid[xCount][yCount] = measured_z + zoffset;
4528
+
4529
+            #endif
4530
+
4531
+            abl_should_enable = false;
4532
+            idle();
4533
+
4534
+          } // inner
4535
+        } // outer
4536
+
4537
+      #elif ENABLED(AUTO_BED_LEVELING_3POINT)
4538
+
4539
+        // Probe at 3 arbitrary points
4540
+
4541
+        for (uint8_t i = 0; i < 3; ++i) {
4542
+          // Retain the last probe position
4543
+          xProbe = LOGICAL_X_POSITION(points[i].x);
4544
+          yProbe = LOGICAL_Y_POSITION(points[i].y);
4545
+          measured_z = points[i].z = probe_pt(xProbe, yProbe, stow_probe_after_each, verbose_level);
4247 4546
         }
4248
-        planner.bed_level_matrix = matrix_3x3::create_look_at(planeNormal);
4249 4547
 
4250
-        // Can't re-enable (on error) until the new grid is written
4251
-        abl_should_enable = false;
4252
-      }
4548
+        if (measured_z == NAN) {
4549
+          planner.abl_enabled = abl_should_enable;
4550
+          return;
4551
+        }
4253 4552
 
4254
-    #endif // AUTO_BED_LEVELING_3POINT
4553
+        if (!dryrun) {
4554
+          vector_3 planeNormal = vector_3::cross(points[0] - points[1], points[2] - points[1]).get_normal();
4555
+          if (planeNormal.z < 0) {
4556
+            planeNormal.x *= -1;
4557
+            planeNormal.y *= -1;
4558
+            planeNormal.z *= -1;
4559
+          }
4560
+          planner.bed_level_matrix = matrix_3x3::create_look_at(planeNormal);
4255 4561
 
4256
-    // Raise to _Z_CLEARANCE_DEPLOY_PROBE. Stow the probe.
4257
-    if (STOW_PROBE()) {
4258
-      planner.abl_enabled = abl_should_enable;
4259
-      return;
4260
-    }
4562
+          // Can't re-enable (on error) until the new grid is written
4563
+          abl_should_enable = false;
4564
+        }
4565
+
4566
+      #endif // AUTO_BED_LEVELING_3POINT
4261 4567
 
4568
+      // Raise to _Z_CLEARANCE_DEPLOY_PROBE. Stow the probe.
4569
+      if (STOW_PROBE()) {
4570
+        planner.abl_enabled = abl_should_enable;
4571
+        return;
4572
+      }
4573
+
4574
+    #endif // !PROBE_MANUALLY
4575
+
4576
+    //
4577
+    // G29 Finishing Code
4262 4578
     //
4263 4579
     // Unless this is a dry run, auto bed leveling will
4264 4580
     // definitely be enabled after this point
@@ -4286,7 +4602,14 @@ inline void gcode_G28() {
4286 4602
 
4287 4603
       // For LINEAR leveling calculate matrix, print reports, correct the position
4288 4604
 
4289
-      // solve lsq problem
4605
+      /**
4606
+       * solve the plane equation ax + by + d = z
4607
+       * A is the matrix with rows [x y 1] for all the probed points
4608
+       * B is the vector of the Z positions
4609
+       * the normal vector to the plane is formed by the coefficients of the
4610
+       * plane equation in the standard form, which is Vx*x+Vy*y+Vz*z+d = 0
4611
+       * so Vx = -a Vy = -b Vz = 1 (we want the vector facing towards positive Z
4612
+       */
4290 4613
       float plane_equation_coefficients[3];
4291 4614
       qr_solve(plane_equation_coefficients, abl2, 3, eqnAMatrix, eqnBVector);
4292 4615
 

+ 0
- 10
Marlin/enum.h ファイルの表示

@@ -165,16 +165,6 @@ enum TempState {
165 165
   };
166 166
 #endif
167 167
 
168
-#if ENABLED(PROBE_MANUALLY)
169
-  enum ABLState {
170
-    ABLReport,
171
-    ABLStart,
172
-    ABLNext,
173
-    ABLSet,
174
-    ABLReset
175
-  };
176
-#endif
177
-
178 168
 /**
179 169
  * SD Card
180 170
  */

+ 8
- 8
Marlin/ultralcd.cpp ファイルの表示

@@ -181,7 +181,7 @@ uint16_t max_display_update_time = 0;
181 181
     void lcd_delta_calibrate_menu();
182 182
   #endif
183 183
 
184
-  #if ENABLED(MANUAL_BED_LEVELING)
184
+  #if ENABLED(MESH_BED_LEVELING) && ENABLED(LCD_BED_LEVELING)
185 185
     #include "mesh_bed_leveling.h"
186 186
   #endif
187 187
 
@@ -982,7 +982,7 @@ void kill_screen(const char* lcd_msg) {
982 982
     MENU_ITEM_EDIT(int3, MSG_SPEED, &feedrate_percentage, 10, 999);
983 983
 
984 984
     // Manual bed leveling, Bed Z:
985
-    #if ENABLED(MANUAL_BED_LEVELING)
985
+    #if ENABLED(LCD_BED_LEVELING)
986 986
       MENU_ITEM_EDIT(float43, MSG_BED_Z, &mbl.z_offset, -1, 1);
987 987
     #endif
988 988
 
@@ -1321,7 +1321,7 @@ void kill_screen(const char* lcd_msg) {
1321 1321
 
1322 1322
   #endif
1323 1323
 
1324
-  #if ENABLED(MANUAL_BED_LEVELING)
1324
+  #if ENABLED(LCD_BED_LEVELING)
1325 1325
 
1326 1326
     /**
1327 1327
      *
@@ -1367,8 +1367,8 @@ void kill_screen(const char* lcd_msg) {
1367 1367
       if (encoderPosition) {
1368 1368
         refresh_cmd_timeout();
1369 1369
         current_position[Z_AXIS] += float((int32_t)encoderPosition) * (MBL_Z_STEP);
1370
-        NOLESS(current_position[Z_AXIS], -(MANUAL_PROBE_Z_RANGE) * 0.5);
1371
-        NOMORE(current_position[Z_AXIS], (MANUAL_PROBE_Z_RANGE) * 0.5);
1370
+        NOLESS(current_position[Z_AXIS], -(LCD_PROBE_Z_RANGE) * 0.5);
1371
+        NOMORE(current_position[Z_AXIS], (LCD_PROBE_Z_RANGE) * 0.5);
1372 1372
         line_to_current(Z_AXIS);
1373 1373
         lcdDrawUpdate = LCDVIEW_KEEP_REDRAWING;
1374 1374
         encoderPosition = 0;
@@ -1483,7 +1483,7 @@ KeepDrawing:
1483 1483
       END_MENU();
1484 1484
     }
1485 1485
 
1486
-  #endif  // MANUAL_BED_LEVELING
1486
+  #endif  // LCD_BED_LEVELING
1487 1487
 
1488 1488
   /**
1489 1489
    *
@@ -1524,7 +1524,7 @@ KeepDrawing:
1524 1524
       MENU_ITEM(gcode, MSG_LEVEL_BED,
1525 1525
         axis_homed[X_AXIS] && axis_homed[Y_AXIS] ? PSTR("G29") : PSTR("G28\nG29")
1526 1526
       );
1527
-    #elif ENABLED(MANUAL_BED_LEVELING)
1527
+    #elif ENABLED(LCD_BED_LEVELING)
1528 1528
       MENU_ITEM(submenu, MSG_LEVEL_BED, lcd_level_bed);
1529 1529
     #endif
1530 1530
 
@@ -2253,7 +2253,7 @@ KeepDrawing:
2253 2253
       MENU_ITEM_EDIT(float32, MSG_ZPROBE_ZOFFSET, &zprobe_zoffset, Z_PROBE_OFFSET_RANGE_MIN, Z_PROBE_OFFSET_RANGE_MAX);
2254 2254
     #endif
2255 2255
     // Manual bed leveling, Bed Z:
2256
-    #if ENABLED(MANUAL_BED_LEVELING)
2256
+    #if ENABLED(LCD_BED_LEVELING)
2257 2257
       MENU_ITEM_EDIT(float43, MSG_BED_Z, &mbl.z_offset, -1, 1);
2258 2258
     #endif
2259 2259
     MENU_ITEM_EDIT(float5, MSG_ACC, &planner.acceleration, 10, 99000);

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