Configurable Corner Leveling point order (#20733)
This commit is contained in:
		| @@ -1451,6 +1451,25 @@ | ||||
|     #define LEVEL_CORNERS_VERIFY_RAISED   // After adjustment triggers the probe, re-probe to verify | ||||
|     //#define LEVEL_CORNERS_AUDIO_FEEDBACK | ||||
|   #endif | ||||
|  | ||||
|   /** | ||||
|    * Corner Leveling Order | ||||
|    * | ||||
|    * Set 2 or 4 points. When 2 points are given, the 3rd is the center of the opposite edge. | ||||
|    * | ||||
|    *  LF  Left-Front    RF  Right-Front | ||||
|    *  LB  Left-Back     RB  Right-Back | ||||
|    * | ||||
|    * Examples: | ||||
|    * | ||||
|    *      Default        {LF,RB,LB,RF}         {LF,RF}           {LB,LF} | ||||
|    *  LB --------- RB   LB --------- RB    LB --------- RB   LB --------- RB | ||||
|    *  |  4       3  |   | 3         2 |    |     <3>     |   | 1           | | ||||
|    *  |             |   |             |    |             |   |          <3>| | ||||
|    *  |  1       2  |   | 1         4 |    | 1         2 |   | 2           | | ||||
|    *  LF --------- RF   LF --------- RF    LF --------- RF   LF --------- RF | ||||
|    */ | ||||
|   #define LEVEL_CORNERS_LEVELING_ORDER { LF, RF, RB, LB } | ||||
| #endif | ||||
|  | ||||
| /** | ||||
|   | ||||
| @@ -130,6 +130,8 @@ namespace Language_en { | ||||
|   PROGMEM Language_Str MSG_LEVEL_CORNERS                   = _UxGT("Level Corners"); | ||||
|   PROGMEM Language_Str MSG_LEVEL_CORNERS_RAISE             = _UxGT("Raise Bed Until Probe Triggered"); | ||||
|   PROGMEM Language_Str MSG_LEVEL_CORNERS_IN_RANGE          = _UxGT("All Corners Within Tolerance. Level Bed"); | ||||
|   PROGMEM Language_Str MSG_LEVEL_CORNERS_GOOD_POINTS       = _UxGT("Good Points: "); | ||||
|   PROGMEM Language_Str MSG_LEVEL_CORNERS_LAST_Z            = _UxGT("Last Z: "); | ||||
|   PROGMEM Language_Str MSG_NEXT_CORNER                     = _UxGT("Next Corner"); | ||||
|   PROGMEM Language_Str MSG_MESH_EDITOR                     = _UxGT("Mesh Editor"); | ||||
|   PROGMEM Language_Str MSG_EDIT_MESH                       = _UxGT("Edit Mesh"); | ||||
|   | ||||
| @@ -56,6 +56,13 @@ | ||||
|   float last_z; | ||||
|   int good_points; | ||||
|   bool corner_probing_done, wait_for_probe; | ||||
|  | ||||
|   #if HAS_MARLINUI_U8GLIB | ||||
|     #include "../dogm/marlinui_DOGM.h" | ||||
|   #endif | ||||
|   #define GOOD_POINTS_TO_STR(N) ui8tostr2(N) | ||||
|   #define LAST_Z_TO_STR(N) ftostr53_63(N) //ftostr42_52(N) | ||||
|  | ||||
| #endif | ||||
|  | ||||
| static_assert(LEVEL_CORNERS_Z_HOP >= 0, "LEVEL_CORNERS_Z_HOP must be >= 0. Please update your configuration."); | ||||
| @@ -66,12 +73,89 @@ extern const char G28_STR[]; | ||||
|   static bool leveling_was_active = false; | ||||
| #endif | ||||
|  | ||||
| static int8_t bed_corner; | ||||
| #ifndef LEVEL_CORNERS_LEVELING_ORDER | ||||
|   #define LEVEL_CORNERS_LEVELING_ORDER { LF, RF, LB, RB } // Default | ||||
|   //#define LEVEL_CORNERS_LEVELING_ORDER { LF, LB, RF  }  // 3 hard-coded points | ||||
|   //#define LEVEL_CORNERS_LEVELING_ORDER { LF, RF }       // 3-Point tramming - Rear | ||||
|   //#define LEVEL_CORNERS_LEVELING_ORDER { LF, LB }       // 3-Point tramming - Right | ||||
|   //#define LEVEL_CORNERS_LEVELING_ORDER { RF, RB }       // 3-Point tramming - Left | ||||
|   //#define LEVEL_CORNERS_LEVELING_ORDER { LB, RB }       // 3-Point tramming - Front | ||||
| #endif | ||||
|  | ||||
| #define LF 1 | ||||
| #define RF 2 | ||||
| #define RB 3 | ||||
| #define LB 4 | ||||
| constexpr int lco[] = LEVEL_CORNERS_LEVELING_ORDER; | ||||
| constexpr bool level_corners_3_points = COUNT(lco) == 2; | ||||
| static_assert(level_corners_3_points || COUNT(lco) == 4, "LEVEL_CORNERS_LEVELING_ORDER must have exactly 2 or 4 corners."); | ||||
|  | ||||
| constexpr int lcodiff = abs(lco[0] - lco[1]); | ||||
| static_assert(COUNT(lco) == 4 || lcodiff == 1 || lcodiff == 3, "The first two LEVEL_CORNERS_LEVELING_ORDER corners must be on the same edge."); | ||||
|  | ||||
| constexpr int nr_edge_points = level_corners_3_points ? 3 : 4; | ||||
| constexpr int available_points = nr_edge_points + ENABLED(LEVEL_CENTER_TOO); | ||||
| constexpr int center_index = TERN(LEVEL_CENTER_TOO, available_points - 1, -1); | ||||
| constexpr float inset_lfrb[4] = LEVEL_CORNERS_INSET_LFRB; | ||||
| constexpr xy_pos_t lf { (X_MIN_BED) + inset_lfrb[0], (Y_MIN_BED) + inset_lfrb[1] }, | ||||
|                    rb { (X_MAX_BED) - inset_lfrb[2], (Y_MAX_BED) - inset_lfrb[3] }; | ||||
|  | ||||
| static int8_t bed_corner; | ||||
|  | ||||
| /** | ||||
|  * Select next corner coordinates | ||||
|  */ | ||||
| static inline void _lcd_level_bed_corners_get_next_position() { | ||||
|  | ||||
|   if (level_corners_3_points) { | ||||
|     if (bed_corner >= available_points) bed_corner = 0; // Above max position -> move back to first corner | ||||
|     switch (bed_corner) { | ||||
|       case 0 ... 1: | ||||
|         // First two corners set explicitly by the configuration | ||||
|         current_position = lf;                       // Left front | ||||
|         switch (lco[bed_corner]) { | ||||
|           case RF: current_position.x = rb.x; break; // Right Front | ||||
|           case RB: current_position   = rb;   break; // Right Back | ||||
|           case LB: current_position.y = rb.y; break; // Left Back | ||||
|         } | ||||
|         break; | ||||
|  | ||||
|       case 2: | ||||
|         // Determine which edge to probe for 3rd point | ||||
|         current_position.set(lf.x + (rb.x - lf.x) / 2, lf.y + (rb.y - lf.y) / 2); | ||||
|         if ((lco[0] == LB && lco[1] == RB) || (lco[0] == RB && lco[1] == LB)) current_position.y = lf.y; // Front Center | ||||
|         if ((lco[0] == LF && lco[1] == LB) || (lco[0] == LB && lco[1] == LF)) current_position.x = rb.x; // Center Right | ||||
|         if ((lco[0] == RF && lco[1] == RB) || (lco[0] == RB && lco[1] == RF)) current_position.x = lf.x; // Left Center | ||||
|         if ((lco[0] == LF && lco[1] == RF) || (lco[0] == RF && lco[1] == LF)) current_position.y = rb.y; // Center Back | ||||
|         #if DISABLED(LEVEL_CENTER_TOO) && ENABLED(LEVEL_CORNERS_USE_PROBE) | ||||
|           bed_corner++;  // Must increment the count to ensure it resets the loop if the 3rd point is out of tolerance | ||||
|         #endif | ||||
|         break; | ||||
|  | ||||
|       #if ENABLED(LEVEL_CENTER_TOO) | ||||
|         case 3: | ||||
|           current_position.set(X_CENTER, Y_CENTER); | ||||
|           break; | ||||
|       #endif | ||||
|     } | ||||
|   } | ||||
|   else { | ||||
|     // Four-Corner Bed Tramming with optional center | ||||
|     if (TERN0(LEVEL_CENTER_TOO, bed_corner == center_index)) { | ||||
|       current_position.set(X_CENTER, Y_CENTER); | ||||
|       TERN_(LEVEL_CORNERS_USE_PROBE, good_points--); // Decrement to allow one additional probe point | ||||
|     } | ||||
|     else { | ||||
|       current_position = lf;                       // Left front | ||||
|       switch (lco[bed_corner]) { | ||||
|         case RF: current_position.x = rb.x; break; // Right front | ||||
|         case RB: current_position   = rb;   break; // Right rear | ||||
|         case LB: current_position.y = rb.y; break; // Left rear | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Level corners, starting in the front-left corner. | ||||
|  */ | ||||
| @@ -82,8 +166,37 @@ constexpr xy_pos_t lf { (X_MIN_BED) + inset_lfrb[0], (Y_MIN_BED) + inset_lfrb[1] | ||||
|   VALIDATE_POINT(lf.x, Y_CENTER, "left"); VALIDATE_POINT(X_CENTER, lf.y, "front"); | ||||
|   VALIDATE_POINT(rb.x, Y_CENTER, "right"); VALIDATE_POINT(X_CENTER, rb.y, "back"); | ||||
|  | ||||
|   #ifndef PAGE_CONTAINS | ||||
|     #define PAGE_CONTAINS(...) true | ||||
|   #endif | ||||
|  | ||||
|   void _lcd_draw_probing() { | ||||
|     if (ui.should_draw()) MenuItem_static::draw((LCD_HEIGHT - 1) / 2, GET_TEXT(MSG_PROBING_MESH)); | ||||
|     if (!ui.should_draw()) return; | ||||
|  | ||||
|     TERN_(HAS_MARLINUI_U8GLIB, ui.set_font(FONT_MENU)); // Set up the font for extra info | ||||
|  | ||||
|     MenuItem_static::draw(0, GET_TEXT(MSG_PROBING_MESH), SS_INVERT); // "Probing Mesh" heading | ||||
|  | ||||
|     uint8_t cy = LCD_HEIGHT - 1, y = LCD_ROW_Y(cy); | ||||
|  | ||||
|     // Display # of good points found vs total needed | ||||
|     if (PAGE_CONTAINS(y - (MENU_FONT_HEIGHT), y)) { | ||||
|       SETCURSOR(0, cy); | ||||
|       lcd_put_u8str_P(GET_TEXT(MSG_LEVEL_CORNERS_GOOD_POINTS)); | ||||
|       lcd_put_u8str(GOOD_POINTS_TO_STR(good_points)); | ||||
|       lcd_put_wchar('/'); | ||||
|       lcd_put_u8str(GOOD_POINTS_TO_STR(nr_edge_points)); | ||||
|     } | ||||
|  | ||||
|     --cy; | ||||
|     y -= MENU_FONT_HEIGHT; | ||||
|  | ||||
|     // Display the Last Z value | ||||
|     if (PAGE_CONTAINS(y - (MENU_FONT_HEIGHT), y)) { | ||||
|       SETCURSOR(0, cy); | ||||
|       lcd_put_u8str_P(GET_TEXT(MSG_LEVEL_CORNERS_LAST_Z)); | ||||
|       lcd_put_u8str(LAST_Z_TO_STR(last_z)); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void _lcd_draw_raise() { | ||||
| @@ -112,7 +225,7 @@ constexpr xy_pos_t lf { (X_MIN_BED) + inset_lfrb[0], (Y_MIN_BED) + inset_lfrb[1] | ||||
|   bool _lcd_level_bed_corners_probe(bool verify=false) { | ||||
|     if (verify) do_blocking_move_to_z(current_position.z + LEVEL_CORNERS_Z_HOP); // do clearance if needed | ||||
|     TERN_(BLTOUCH_SLOW_MODE, bltouch.deploy()); // Deploy in LOW SPEED MODE on every probe action | ||||
|     do_blocking_move_to_z(last_z - LEVEL_CORNERS_PROBE_TOLERANCE, manual_feedrate_mm_s.z); // Move down to lower tolerance | ||||
|     do_blocking_move_to_z(last_z - LEVEL_CORNERS_PROBE_TOLERANCE, MMM_TO_MMS(Z_PROBE_SPEED_SLOW)); // Move down to lower tolerance | ||||
|     if (TEST(endstops.trigger_state(), TERN(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN, Z_MIN, Z_MIN_PROBE))) { // check if probe triggered | ||||
|       endstops.hit_on_purpose(); | ||||
|       set_current_from_steppers_for_axis(Z_AXIS); | ||||
| @@ -149,25 +262,18 @@ constexpr xy_pos_t lf { (X_MIN_BED) + inset_lfrb[0], (Y_MIN_BED) + inset_lfrb[1] | ||||
|   } | ||||
|  | ||||
|   void _lcd_test_corners() { | ||||
|     ui.goto_screen(_lcd_draw_probing); | ||||
|     bed_corner = TERN(LEVEL_CENTER_TOO, 4, 0); | ||||
|     bed_corner = TERN(LEVEL_CENTER_TOO, center_index, 0); | ||||
|     last_z = LEVEL_CORNERS_HEIGHT; | ||||
|     endstops.enable_z_probe(true); | ||||
|     good_points = 0; | ||||
|  | ||||
|     ui.goto_screen(_lcd_draw_probing); | ||||
|     do { | ||||
|       ui.refresh(LCDVIEW_REDRAW_NOW); | ||||
|       _lcd_draw_probing();                                //update screen with # of good points | ||||
|       do_blocking_move_to_z(current_position.z + LEVEL_CORNERS_Z_HOP); // clearance | ||||
|       // Select next corner coordinates | ||||
|       xy_pos_t plf = lf - probe.offset_xy, prb = rb - probe.offset_xy; | ||||
|       switch (bed_corner) { | ||||
|         case 0: current_position   = plf;   break; // copy xy | ||||
|         case 1: current_position.x = prb.x; break; | ||||
|         case 2: current_position.y = prb.y; break; | ||||
|         case 3: current_position.x = plf.x; break; | ||||
|         #if ENABLED(LEVEL_CENTER_TOO) | ||||
|           case 4: current_position.set(X_CENTER - probe.offset_xy.x, Y_CENTER - probe.offset_xy.y); break; | ||||
|         #endif | ||||
|       } | ||||
|  | ||||
|       _lcd_level_bed_corners_get_next_position();         // Select next corner coordinates | ||||
|       current_position -= probe.offset_xy;                // Account for probe offsets | ||||
|       do_blocking_move_to_xy(current_position);           // Goto corner | ||||
|  | ||||
|       if (!_lcd_level_bed_corners_probe()) {              // Probe down to tolerance | ||||
| @@ -185,10 +291,10 @@ constexpr xy_pos_t lf { (X_MIN_BED) + inset_lfrb[0], (Y_MIN_BED) + inset_lfrb[1] | ||||
|           return; | ||||
|       } | ||||
|  | ||||
|       if (bed_corner != 4) good_points++; // ignore center | ||||
|       if (bed_corner != center_index) good_points++; // ignore center | ||||
|       if (++bed_corner > 3) bed_corner = 0; | ||||
|  | ||||
|     } while (good_points < 4); // loop until all corners whitin tolerance | ||||
|     } while (good_points < nr_edge_points); // loop until all points within tolerance | ||||
|  | ||||
|     ui.goto_screen(_lcd_draw_level_prompt); // prompt for bed leveling | ||||
|     ui.set_selection(true); | ||||
| @@ -198,18 +304,13 @@ constexpr xy_pos_t lf { (X_MIN_BED) + inset_lfrb[0], (Y_MIN_BED) + inset_lfrb[1] | ||||
|  | ||||
|   static inline void _lcd_goto_next_corner() { | ||||
|     line_to_z(LEVEL_CORNERS_Z_HOP); | ||||
|     switch (bed_corner) { | ||||
|       case 0: current_position   = lf;   break; // copy xy | ||||
|       case 1: current_position.x = rb.x; break; | ||||
|       case 2: current_position.y = rb.y; break; | ||||
|       case 3: current_position.x = lf.x; break; | ||||
|       #if ENABLED(LEVEL_CENTER_TOO) | ||||
|         case 4: current_position.set(X_CENTER, Y_CENTER); break; | ||||
|       #endif | ||||
|     } | ||||
|  | ||||
|     // Select next corner coordinates | ||||
|     _lcd_level_bed_corners_get_next_position(); | ||||
|  | ||||
|     line_to_current_position(manual_feedrate_mm_s.x); | ||||
|     line_to_z(LEVEL_CORNERS_HEIGHT); | ||||
|     if (++bed_corner > 3 + ENABLED(LEVEL_CENTER_TOO)) bed_corner = 0; | ||||
|     if (++bed_corner >= available_points) bed_corner = 0; | ||||
|   } | ||||
|  | ||||
| #endif // !LEVEL_CORNERS_USE_PROBE | ||||
|   | ||||
		Reference in New Issue
	
	Block a user