From f5f1b069ade516793995870bac4d6707cff43407 Mon Sep 17 00:00:00 2001 From: Roxy-3D Date: Tue, 16 Jan 2018 11:08:00 -0600 Subject: [PATCH] Convert UBL mesh tilting to all use the same algorithm (#9204) A number of regressions were patched also. The UBL G29 P2 and P4 Press and Hold had stopped working. It is very possible this is broken in the bugfix_v1.1.x branch also. The main purpose of the Pull Request is to get the 3-Point mesh tilting to use the LSF algorithm just like the grid based mesh tilt. This simplifies the logic and reduces the code size some what. But the real reason to do it is the 3-Point case can be solved exactly. And by feeding these numbers into the LSF algorithm it provides a way to check all that code for 'correctness'. --- .../examples/gCreate/gMax1.5+/Configuration.h | 4 +- Marlin/src/feature/Max7219_Debug_LEDs.cpp | 28 +- Marlin/src/feature/bedlevel/ubl/ubl.h | 4 +- Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp | 315 +++++++++--------- Marlin/src/gcode/bedlevel/G26.cpp | 21 +- Marlin/src/lcd/ultralcd.cpp | 13 +- Marlin/src/lcd/ultralcd.h | 2 +- 7 files changed, 193 insertions(+), 194 deletions(-) diff --git a/Marlin/src/config/examples/gCreate/gMax1.5+/Configuration.h b/Marlin/src/config/examples/gCreate/gMax1.5+/Configuration.h index 1180903c2..aba5d1bc9 100644 --- a/Marlin/src/config/examples/gCreate/gMax1.5+/Configuration.h +++ b/Marlin/src/config/examples/gCreate/gMax1.5+/Configuration.h @@ -1061,8 +1061,8 @@ #define Z_SAFE_HOMING #if ENABLED(Z_SAFE_HOMING) - #define Z_SAFE_HOMING_X_POINT ((X_BED_SIZE) / 2 - 4) // X point for Z homing when homing all axes (G28). - #define Z_SAFE_HOMING_Y_POINT ((Y_BED_SIZE) / 2 + 4) // Y point for Z homing when homing all axes (G28). + #define Z_SAFE_HOMING_X_POINT ((X_BED_SIZE) / 2 - 8) // X point for Z homing when homing all axes (G28). + #define Z_SAFE_HOMING_Y_POINT ((Y_BED_SIZE) / 2 - 4) // Y point for Z homing when homing all axes (G28). #endif // Homing speeds (mm/m) diff --git a/Marlin/src/feature/Max7219_Debug_LEDs.cpp b/Marlin/src/feature/Max7219_Debug_LEDs.cpp index 83c94ccd9..29ab81569 100644 --- a/Marlin/src/feature/Max7219_Debug_LEDs.cpp +++ b/Marlin/src/feature/Max7219_Debug_LEDs.cpp @@ -237,13 +237,13 @@ void Max7219_init() { for (x = 0; x <= 7; x++) // Do an aesthetically pleasing pattern to fully test for (y = 0; y <= 7; y++) { // the Max7219 module and LEDs. First, turn them - Max7219_LED_On(x, y); // all on. + Max7219_LED_On(y, x); // all on. delay(3); } for (x = 0; x <= 7; x++) // Now, turn them all off. for (y = 0; y <= 7; y++) { - Max7219_LED_Off(x, y); + Max7219_LED_Off(y, x); delay(3); // delay() is OK here. Max7219_init() is only called from } // setup() and nothing is running yet. @@ -251,13 +251,13 @@ void Max7219_init() { for (x = 8; x--;) // Now, do the same thing from the opposite direction for (y = 0; y <= 7; y++) { - Max7219_LED_On(x, y); + Max7219_LED_On(y, x); delay(2); } for (x = 8; x--;) for (y = 0; y <= 7; y++) { - Max7219_LED_Off(x, y); + Max7219_LED_Off(y, x); delay(2); } } @@ -295,15 +295,15 @@ void Max7219_idle_tasks() { static int16_t last_head_cnt = 0; if (last_head_cnt != head) { if (last_head_cnt < 8) - Max7219_LED_Off(last_head_cnt, MAX7219_DEBUG_STEPPER_HEAD); + Max7219_LED_Off(MAX7219_DEBUG_STEPPER_HEAD, last_head_cnt); else - Max7219_LED_Off(last_head_cnt - 8, MAX7219_DEBUG_STEPPER_HEAD + 1); + Max7219_LED_Off(MAX7219_DEBUG_STEPPER_HEAD + 1, last_head_cnt - 8); last_head_cnt = head; if (head < 8) - Max7219_LED_On(head, MAX7219_DEBUG_STEPPER_HEAD); + Max7219_LED_On(MAX7219_DEBUG_STEPPER_HEAD, head); else - Max7219_LED_On(head - 8, MAX7219_DEBUG_STEPPER_HEAD + 1); + Max7219_LED_On(MAX7219_DEBUG_STEPPER_HEAD + 1, head - 8); } #endif @@ -311,15 +311,15 @@ void Max7219_idle_tasks() { static int16_t last_tail_cnt = 0; if (last_tail_cnt != tail) { if (last_tail_cnt < 8) - Max7219_LED_Off(last_tail_cnt, MAX7219_DEBUG_STEPPER_TAIL); + Max7219_LED_Off(MAX7219_DEBUG_STEPPER_TAIL, last_tail_cnt); else - Max7219_LED_Off(last_tail_cnt - 8, MAX7219_DEBUG_STEPPER_TAIL + 1); + Max7219_LED_Off(MAX7219_DEBUG_STEPPER_TAIL + 1, last_tail_cnt - 8); last_tail_cnt = tail; if (tail < 8) - Max7219_LED_On(tail, MAX7219_DEBUG_STEPPER_TAIL); + Max7219_LED_On(MAX7219_DEBUG_STEPPER_TAIL, tail); else - Max7219_LED_On(tail - 8, MAX7219_DEBUG_STEPPER_TAIL + 1); + Max7219_LED_On(MAX7219_DEBUG_STEPPER_TAIL + 1, tail - 8); } #endif @@ -336,10 +336,10 @@ void Max7219_idle_tasks() { en = max(current_depth, last_depth); if (current_depth < last_depth) for (uint8_t i = st; i <= en; i++) // clear the highest order LEDs - Max7219_LED_Off(i / 2, MAX7219_DEBUG_STEPPER_QUEUE + (i & 1)); + Max7219_LED_Off(MAX7219_DEBUG_STEPPER_QUEUE + (i & 1), i / 2); else for (uint8_t i = st; i <= en; i++) // set the LEDs to current depth - Max7219_LED_On(i / 2, MAX7219_DEBUG_STEPPER_QUEUE + (i & 1)); + Max7219_LED_On(MAX7219_DEBUG_STEPPER_QUEUE + (i & 1), i / 2); last_depth = current_depth; } diff --git a/Marlin/src/feature/bedlevel/ubl/ubl.h b/Marlin/src/feature/bedlevel/ubl/ubl.h index 82bdbce87..b215165e7 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl.h +++ b/Marlin/src/feature/bedlevel/ubl/ubl.h @@ -59,7 +59,7 @@ extern uint8_t ubl_cnt; #if ENABLED(ULTRA_LCD) extern char lcd_status_message[]; - void lcd_quick_feedback(); + void lcd_quick_feedback(const bool clear_buttons); #endif #define MESH_X_DIST (float(MESH_MAX_X - (MESH_MIN_X)) / float(GRID_MAX_POINTS_X - 1)) @@ -85,7 +85,7 @@ class unified_bed_leveling { #if ENABLED(NEWPANEL) static void move_z_with_encoder(const float &multiplier); static float measure_point_with_encoder(); - static float measure_business_card_thickness(const float&); + static float measure_business_card_thickness(float); static void manually_probe_remaining_mesh(const float&, const float&, const float&, const float&, const bool); static void fine_tune_mesh(const float &rx, const float &ry, const bool do_ubl_mesh_map); #endif diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp index 96a827fad..910417f78 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp @@ -40,6 +40,8 @@ #include "../../../feature/bedlevel/bedlevel.h" #include "../../../libs/least_squares_fit.h" +#include "../../../feature/Max7219_Debug_LEDs.h" + #include #define UBL_G29_P31 @@ -98,8 +100,9 @@ * C Continue G29 P1 C continues the generation of a partially-constructed Mesh without invalidating * previous measurements. * - * C Constant G29 P2 C specifies a Constant and tells the Manual Probe subsystem to use the current - * location in its search for the closest unmeasured Mesh Point. + * C G29 P2 C tells the Manual Probe subsystem to not use the current nozzle + * location in its search for the closest unmeasured Mesh Point. Instead, attempt to + * start at one end of the uprobed points and Continue sequentually. * * G29 P3 C specifies the Constant for the fill. Otherwise, uses a "reasonable" value. * @@ -281,9 +284,7 @@ * * Release Notes: * You MUST do M502, M500 to initialize the storage. Failure to do this will cause all - * kinds of problems. Enabling EEPROM Storage is highly recommended. With EEPROM Storage - * of the mesh, you are limited to 3-Point and Grid Leveling. (G29 P0 T and G29 P0 G - * respectively.) + * kinds of problems. Enabling EEPROM Storage is required. * * When you do a G28 and then a G29 P1 to automatically build your first mesh, you are going to notice * the Unified Bed Leveling probes points further and further away from the starting location. (The @@ -385,36 +386,16 @@ if (parser.seen('J')) { if (g29_grid_size) { // if not 0 it is a normal n x n grid being probed save_ubl_active_state_and_disable(); - tilt_mesh_based_on_probed_grid(parser.seen('T')); + tilt_mesh_based_on_probed_grid(false /* false says to do normal grid probing */ ); restore_ubl_active_state_and_leave(); } else { // grid_size == 0 : A 3-Point leveling has been requested - float z3, z2, z1 = probe_pt(UBL_PROBE_PT_1_X, UBL_PROBE_PT_1_Y, false, g29_verbose_level); - if (!isnan(z1)) { - z2 = probe_pt(UBL_PROBE_PT_2_X, UBL_PROBE_PT_2_Y, false, g29_verbose_level); - if (!isnan(z2)) - z3 = probe_pt(UBL_PROBE_PT_3_X, UBL_PROBE_PT_3_Y, true, g29_verbose_level); - } - - if (isnan(z1) || isnan(z2) || isnan(z3)) { // probe_pt will return NAN if unreachable - SERIAL_ERROR_START(); - SERIAL_ERRORLNPGM("Attempt to probe off the bed."); - goto LEAVE; - } - - // Adjust z1, z2, z3 by the Mesh Height at these points. Just because they're non-zero - // doesn't mean the Mesh is tilted! (Compensate each probe point by what the Mesh says - // its height is.) save_ubl_active_state_and_disable(); - z1 -= get_z_correction(UBL_PROBE_PT_1_X, UBL_PROBE_PT_1_Y) /* + zprobe_zoffset */ ; - z2 -= get_z_correction(UBL_PROBE_PT_2_X, UBL_PROBE_PT_2_Y) /* + zprobe_zoffset */ ; - z3 -= get_z_correction(UBL_PROBE_PT_3_X, UBL_PROBE_PT_3_Y) /* + zprobe_zoffset */ ; - - do_blocking_move_to_xy(0.5 * (MESH_MAX_X - (MESH_MIN_X)), 0.5 * (MESH_MAX_Y - (MESH_MIN_Y))); - tilt_mesh_based_on_3pts(z1, z2, z3); + tilt_mesh_based_on_probed_grid(true /* true says to do 3-Point leveling */ ); restore_ubl_active_state_and_leave(); } + do_blocking_move_to_xy(0.5 * (MESH_MAX_X - (MESH_MIN_X)), 0.5 * (MESH_MAX_Y - (MESH_MIN_Y))); } #endif // HAS_BED_PROBE @@ -464,7 +445,7 @@ SERIAL_PROTOCOLLNPGM("Manually probing unreachable mesh locations."); do_blocking_move_to_z(Z_CLEARANCE_BETWEEN_PROBES); - if (!g29_x_flag && !g29_y_flag) { + if (parser.seen('C') && !g29_x_flag && !g29_y_flag) { /** * Use a good default location for the path. * The flipped > and < operators in these comparisons is intentional. @@ -481,13 +462,8 @@ #endif } - if (parser.seen('C')) { - g29_x_pos = current_position[X_AXIS]; - g29_y_pos = current_position[Y_AXIS]; - } - if (parser.seen('B')) { - g29_card_thickness = parser.has_value() ? parser.value_float() : measure_business_card_thickness(Z_CLEARANCE_BETWEEN_PROBES); + g29_card_thickness = parser.has_value() ? parser.value_float() : measure_business_card_thickness((float) Z_CLEARANCE_BETWEEN_PROBES); if (FABS(g29_card_thickness) > 1.5) { SERIAL_PROTOCOLLNPGM("?Error in Business Card measurement."); return; @@ -672,7 +648,7 @@ #if ENABLED(NEWPANEL) lcd_reset_alert_level(); LCD_MESSAGEPGM(""); - lcd_quick_feedback(); + lcd_quick_feedback(true); lcd_external_control = false; #endif @@ -730,12 +706,13 @@ bool click_and_hold(const clickFunc_t func=NULL) { if (is_lcd_clicked()) { - lcd_quick_feedback(); + lcd_quick_feedback(false); // Do NOT clear button status! If cleared, the code + // code can not look for a 'click and hold' const millis_t nxt = millis() + 1500UL; while (is_lcd_clicked()) { // Loop while the encoder is pressed. Uses hardware flag! idle(); // idle, of course if (ELAPSED(millis(), nxt)) { // After 1.5 seconds - lcd_quick_feedback(); + lcd_quick_feedback(true); if (func) (*func)(); wait_for_release(); safe_delay(50); // Debounce the Encoder wheel @@ -743,6 +720,7 @@ } } } + safe_delay(5); return false; } @@ -771,11 +749,12 @@ #if ENABLED(NEWPANEL) if (is_lcd_clicked()) { SERIAL_PROTOCOLLNPGM("\nMesh only partially populated.\n"); - lcd_quick_feedback(); + lcd_quick_feedback(false); STOW_PROBE(); - wait_for_release(); + while (is_lcd_clicked()) idle(); lcd_external_control = false; restore_ubl_active_state_and_leave(); + safe_delay(50); // Debounce the Encoder wheel return; } #endif @@ -804,109 +783,6 @@ ); } - void unified_bed_leveling::tilt_mesh_based_on_3pts(const float &z1, const float &z2, const float &z3) { - matrix_3x3 rotation; - vector_3 v1 = vector_3( (UBL_PROBE_PT_1_X - UBL_PROBE_PT_2_X), - (UBL_PROBE_PT_1_Y - UBL_PROBE_PT_2_Y), - (z1 - z2) ), - - v2 = vector_3( (UBL_PROBE_PT_3_X - UBL_PROBE_PT_2_X), - (UBL_PROBE_PT_3_Y - UBL_PROBE_PT_2_Y), - (z3 - z2) ), - - normal = vector_3::cross(v1, v2); - - normal = normal.get_normal(); - - /** - * This vector is normal to the tilted plane. - * However, we don't know its direction. We need it to point up. So if - * Z is negative, we need to invert the sign of all components of the vector - */ - if (normal.z < 0.0) { - normal.x = -normal.x; - normal.y = -normal.y; - normal.z = -normal.z; - } - - rotation = matrix_3x3::create_look_at(vector_3(normal.x, normal.y, 1)); - - if (g29_verbose_level > 2) { - SERIAL_ECHOPGM("bed plane normal = ["); - SERIAL_PROTOCOL_F(normal.x, 7); - SERIAL_PROTOCOLCHAR(','); - SERIAL_PROTOCOL_F(normal.y, 7); - SERIAL_PROTOCOLCHAR(','); - SERIAL_PROTOCOL_F(normal.z, 7); - SERIAL_ECHOLNPGM("]"); - rotation.debug(PSTR("rotation matrix:")); - } - - // - // All of 3 of these points should give us the same d constant - // - - float t = normal.x * (UBL_PROBE_PT_1_X) + normal.y * (UBL_PROBE_PT_1_Y), - d = t + normal.z * z1; - - if (g29_verbose_level>2) { - SERIAL_ECHOPGM("D constant: "); - SERIAL_PROTOCOL_F(d, 7); - SERIAL_ECHOLNPGM(" "); - } - - #if ENABLED(DEBUG_LEVELING_FEATURE) - if (DEBUGGING(LEVELING)) { - SERIAL_ECHOPGM("d from 1st point: "); - SERIAL_ECHO_F(d, 6); - SERIAL_EOL(); - t = normal.x * (UBL_PROBE_PT_2_X) + normal.y * (UBL_PROBE_PT_2_Y); - d = t + normal.z * z2; - SERIAL_ECHOPGM("d from 2nd point: "); - SERIAL_ECHO_F(d, 6); - SERIAL_EOL(); - t = normal.x * (UBL_PROBE_PT_3_X) + normal.y * (UBL_PROBE_PT_3_Y); - d = t + normal.z * z3; - SERIAL_ECHOPGM("d from 3rd point: "); - SERIAL_ECHO_F(d, 6); - SERIAL_EOL(); - } - #endif - - for (uint8_t i = 0; i < GRID_MAX_POINTS_X; i++) { - for (uint8_t j = 0; j < GRID_MAX_POINTS_Y; j++) { - float x_tmp = mesh_index_to_xpos(i), - y_tmp = mesh_index_to_ypos(j), - z_tmp = z_values[i][j]; - #if ENABLED(DEBUG_LEVELING_FEATURE) - if (DEBUGGING(LEVELING)) { - SERIAL_ECHOPGM("before rotation = ["); - SERIAL_PROTOCOL_F(x_tmp, 7); - SERIAL_PROTOCOLCHAR(','); - SERIAL_PROTOCOL_F(y_tmp, 7); - SERIAL_PROTOCOLCHAR(','); - SERIAL_PROTOCOL_F(z_tmp, 7); - SERIAL_ECHOPGM("] ---> "); - safe_delay(20); - } - #endif - apply_rotation_xyz(rotation, x_tmp, y_tmp, z_tmp); - #if ENABLED(DEBUG_LEVELING_FEATURE) - if (DEBUGGING(LEVELING)) { - SERIAL_ECHOPGM("after rotation = ["); - SERIAL_PROTOCOL_F(x_tmp, 7); - SERIAL_PROTOCOLCHAR(','); - SERIAL_PROTOCOL_F(y_tmp, 7); - SERIAL_PROTOCOLCHAR(','); - SERIAL_PROTOCOL_F(z_tmp, 7); - SERIAL_ECHOLNPGM("]"); - safe_delay(55); - } - #endif - z_values[i][j] += z_tmp - d; - } - } - } #endif // HAS_BED_PROBE @@ -932,7 +808,7 @@ static void echo_and_take_a_measurement() { SERIAL_PROTOCOLLNPGM(" and take a measurement."); } - float unified_bed_leveling::measure_business_card_thickness(const float &in_height) { + float unified_bed_leveling::measure_business_card_thickness(float in_height) { lcd_external_control = true; save_ubl_active_state_and_disable(); // Disable bed level correction for probing @@ -985,7 +861,7 @@ lcd_external_control = true; save_ubl_active_state_and_disable(); // we don't do bed level correction because we want the raw data when we probe - do_blocking_move_to(rx, ry, Z_CLEARANCE_BETWEEN_PROBES); + do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], z_clearance); lcd_return_to_status(); @@ -1047,7 +923,7 @@ #if ENABLED(NEWPANEL) LCD_MESSAGEPGM(MSG_UBL_DOING_G29); - lcd_quick_feedback(); + lcd_quick_feedback(true); #endif g29_constant = 0.0; @@ -1170,7 +1046,7 @@ SERIAL_ECHOLNPGM("save_ubl_active_state_and_disabled() called multiple times in a row."); #if ENABLED(NEWPANEL) LCD_MESSAGEPGM(MSG_UBL_SAVE_ERROR); - lcd_quick_feedback(); + lcd_quick_feedback(true); #endif return; } @@ -1185,7 +1061,7 @@ SERIAL_ECHOLNPGM("restore_ubl_active_state_and_leave() called too many times."); #if ENABLED(NEWPANEL) LCD_MESSAGEPGM(MSG_UBL_RESTORE_ERROR); - lcd_quick_feedback(); + lcd_quick_feedback(true); #endif return; } @@ -1217,6 +1093,8 @@ SERIAL_EOL(); #endif + find_mean_mesh_height(); + #if HAS_BED_PROBE SERIAL_PROTOCOLPGM("zprobe_zoffset: "); SERIAL_PROTOCOL_F(zprobe_zoffset, 7); @@ -1531,13 +1409,13 @@ lcd_mesh_edit_setup(new_z); - while (!is_lcd_clicked()) { + do { new_z = lcd_mesh_edit(); #if ENABLED(UBL_MESH_EDIT_MOVES_Z) do_blocking_move_to_z(h_offset + new_z); // Move the nozzle as the point is edited #endif idle(); - } + } while (!is_lcd_clicked()); if (!lcd_map_control) lcd_return_to_status(); @@ -1632,24 +1510,87 @@ #if HAS_BED_PROBE - void unified_bed_leveling::tilt_mesh_based_on_probed_grid(const bool do_ubl_mesh_map) { + void unified_bed_leveling::tilt_mesh_based_on_probed_grid(const bool do_3_pt_leveling) { constexpr int16_t x_min = max(MIN_PROBE_X, MESH_MIN_X), x_max = min(MAX_PROBE_X, MESH_MAX_X), y_min = max(MIN_PROBE_Y, MESH_MIN_Y), y_max = min(MAX_PROBE_Y, MESH_MAX_Y); + bool abort_flag=false; + + float measured_z; + const float dx = float(x_max - x_min) / (g29_grid_size - 1.0), dy = float(y_max - y_min) / (g29_grid_size - 1.0); struct linear_fit_data lsf_results; + +// float z1, z2, z3; // Needed for algorithm validation down below. + incremental_LSF_reset(&lsf_results); + if (do_3_pt_leveling) { + measured_z = probe_pt(UBL_PROBE_PT_1_X, UBL_PROBE_PT_1_Y, false, g29_verbose_level); + if (isnan(measured_z)) + abort_flag = true; + else { + measured_z -= get_z_correction(UBL_PROBE_PT_1_X, UBL_PROBE_PT_1_Y); +// z1 = measured_z; + if (g29_verbose_level>3) { + serial_spaces(16); + SERIAL_ECHOLNPAIR("Corrected_Z=", measured_z); + } + incremental_LSF(&lsf_results, UBL_PROBE_PT_1_X, UBL_PROBE_PT_1_Y, measured_z); + } + + if (!abort_flag) { + measured_z = probe_pt(UBL_PROBE_PT_2_X, UBL_PROBE_PT_2_Y, false, g29_verbose_level); +// z2 = measured_z; + if (isnan(measured_z)) + abort_flag = true; + else { + measured_z -= get_z_correction(UBL_PROBE_PT_2_X, UBL_PROBE_PT_2_Y); + if (g29_verbose_level>3) { + serial_spaces(16); + SERIAL_ECHOLNPAIR("Corrected_Z=", measured_z); + } + incremental_LSF(&lsf_results, UBL_PROBE_PT_2_X, UBL_PROBE_PT_2_Y, measured_z); + } + } + + if (!abort_flag) { + measured_z = probe_pt(UBL_PROBE_PT_3_X, UBL_PROBE_PT_3_Y, true, g29_verbose_level); +// z3 = measured_z; + if (isnan(measured_z)) + abort_flag = true; + else { + measured_z -= get_z_correction(UBL_PROBE_PT_3_X, UBL_PROBE_PT_3_Y); + if (g29_verbose_level>3) { + serial_spaces(16); + SERIAL_ECHOLNPAIR("Corrected_Z=", measured_z); + } + incremental_LSF(&lsf_results, UBL_PROBE_PT_3_X, UBL_PROBE_PT_3_Y, measured_z); + } + } + + if (abort_flag) { + SERIAL_ECHOPGM("?Error probing point. Aborting operation.\n"); + return; + } + } else { + bool zig_zag = false; for (uint8_t ix = 0; ix < g29_grid_size; ix++) { const float rx = float(x_min) + ix * dx; for (int8_t iy = 0; iy < g29_grid_size; iy++) { const float ry = float(y_min) + dy * (zig_zag ? g29_grid_size - 1 - iy : iy); - float measured_z = probe_pt(rx, ry, parser.seen('E'), g29_verbose_level); // TODO: Needs error handling + + if (!abort_flag) { + measured_z = probe_pt(rx, ry, parser.seen('E'), g29_verbose_level); // TODO: Needs error handling + + if (isnan(measured_z)) + abort_flag = true; + #if ENABLED(DEBUG_LEVELING_FEATURE) if (DEBUGGING(LEVELING)) { SERIAL_CHAR('('); @@ -1680,24 +1621,18 @@ incremental_LSF(&lsf_results, rx, ry, measured_z); } + } zig_zag ^= true; } - if (finish_incremental_LSF(&lsf_results)) { + } + + if (abort_flag || finish_incremental_LSF(&lsf_results)) { SERIAL_ECHOPGM("Could not complete LSF!"); return; } - if (g29_verbose_level > 3) { - SERIAL_ECHOPGM("LSF Results A="); - SERIAL_PROTOCOL_F(lsf_results.A, 7); - SERIAL_ECHOPGM(" B="); - SERIAL_PROTOCOL_F(lsf_results.B, 7); - SERIAL_ECHOPGM(" D="); - SERIAL_PROTOCOL_F(lsf_results.D, 7); - SERIAL_EOL(); - } vector_3 normal = vector_3(lsf_results.A, lsf_results.B, 1.0000).get_normal(); @@ -1753,7 +1688,7 @@ #if ENABLED(DEBUG_LEVELING_FEATURE) if (DEBUGGING(LEVELING)) { - rotation.debug(PSTR("rotation matrix:")); + rotation.debug(PSTR("rotation matrix:\n")); SERIAL_ECHOPGM("LSF Results A="); SERIAL_PROTOCOL_F(lsf_results.A, 7); SERIAL_ECHOPGM(" B="); @@ -1771,10 +1706,62 @@ SERIAL_PROTOCOL_F(normal.z, 7); SERIAL_ECHOPGM("]\n"); SERIAL_EOL(); + +/* + * The following code can be used to check the validity of the mesh tilting algorithm. + * When a 3-Point Mesh Tilt is done, the same algorithm is used as the grid based tilting. + * The only difference is just 3 points are used in the calculations. That fact guarantees + * each probed point should have an exact match when a get_z_correction() for that location + * is calculated. The Z error between the probed point locations and the get_z_correction() + * numbers for those locations should be 0.000 + */ +/* + float t, t1, d; + t = normal.x * (UBL_PROBE_PT_1_X) + normal.y * (UBL_PROBE_PT_1_Y); + d = t + normal.z * z1; + SERIAL_ECHOPGM("D from 1st point: "); + SERIAL_ECHO_F(d, 6); + SERIAL_ECHO(" Z error: "); + SERIAL_ECHO_F(normal.z*z1-get_z_correction(UBL_PROBE_PT_1_X, UBL_PROBE_PT_1_Y),6); + SERIAL_EOL(); + + t = normal.x * (UBL_PROBE_PT_2_X) + normal.y * (UBL_PROBE_PT_2_Y); + d = t + normal.z * z2; + SERIAL_EOL(); + SERIAL_ECHOPGM("D from 2nd point: "); + SERIAL_ECHO_F(d, 6); + SERIAL_ECHO(" Z error: "); + SERIAL_ECHO_F(normal.z*z2-get_z_correction(UBL_PROBE_PT_2_X, UBL_PROBE_PT_2_Y),6); + SERIAL_EOL(); + + t = normal.x * (UBL_PROBE_PT_3_X) + normal.y * (UBL_PROBE_PT_3_Y); + d = t + normal.z * z3; + SERIAL_ECHOPGM("D from 3rd point: "); + SERIAL_ECHO_F(d, 6); + SERIAL_ECHO(" Z error: "); + SERIAL_ECHO_F(normal.z*z3-get_z_correction(UBL_PROBE_PT_3_X, UBL_PROBE_PT_3_Y),6); + SERIAL_EOL(); + + t = normal.x * (Z_SAFE_HOMING_X_POINT) + normal.y * (Z_SAFE_HOMING_Y_POINT); + d = t + normal.z * 0.000; + SERIAL_ECHOPGM("D from home location with Z=0 : "); + SERIAL_ECHO_F(d, 6); + SERIAL_EOL(); + + t = normal.x * (Z_SAFE_HOMING_X_POINT) + normal.y * (Z_SAFE_HOMING_Y_POINT); + d = t + get_z_correction(Z_SAFE_HOMING_X_POINT, Z_SAFE_HOMING_Y_POINT); // normal.z * 0.000; + SERIAL_ECHOPGM("D from home location using mesh value for Z: "); + SERIAL_ECHO_F(d, 6); + + SERIAL_ECHOPAIR(" Z error: (", Z_SAFE_HOMING_X_POINT ); + SERIAL_ECHOPAIR(",", Z_SAFE_HOMING_Y_POINT ); + SERIAL_ECHO(") = "); + SERIAL_ECHO_F( get_z_correction(Z_SAFE_HOMING_X_POINT, Z_SAFE_HOMING_Y_POINT),6); + SERIAL_EOL(); +*/ } #endif - if (do_ubl_mesh_map) display_map(g29_map_type); } #endif // HAS_BED_PROBE diff --git a/Marlin/src/gcode/bedlevel/G26.cpp b/Marlin/src/gcode/bedlevel/G26.cpp index 053e879ff..5e2bc46c9 100644 --- a/Marlin/src/gcode/bedlevel/G26.cpp +++ b/Marlin/src/gcode/bedlevel/G26.cpp @@ -165,7 +165,7 @@ int8_t g26_prime_flag; if (!is_lcd_clicked()) return false; // Return if the button isn't pressed lcd_setstatusPGM(PSTR("Mesh Validation Stopped."), 99); #if ENABLED(ULTIPANEL) - lcd_quick_feedback(); + lcd_quick_feedback(true); #endif wait_for_release(); return true; @@ -421,7 +421,7 @@ inline bool turn_on_heaters() { #if ENABLED(ULTRA_LCD) if (g26_bed_temp > 25) { lcd_setstatusPGM(PSTR("G26 Heating Bed."), 99); - lcd_quick_feedback(); + lcd_quick_feedback(true); lcd_external_control = true; #endif thermalManager.setTargetBed(g26_bed_temp); @@ -441,7 +441,7 @@ inline bool turn_on_heaters() { #if ENABLED(ULTRA_LCD) } lcd_setstatusPGM(PSTR("G26 Heating Nozzle."), 99); - lcd_quick_feedback(); + lcd_quick_feedback(true); #endif #endif @@ -463,7 +463,7 @@ inline bool turn_on_heaters() { #if ENABLED(ULTRA_LCD) lcd_reset_status(); - lcd_quick_feedback(); + lcd_quick_feedback(true); #endif return G26_OK; @@ -509,7 +509,7 @@ inline bool prime_nozzle() { strcpy_P(lcd_status_message, PSTR("Done Priming")); // We can't do lcd_setstatusPGM() without having it continue; // So... We cheat to get a message up. lcd_setstatusPGM(PSTR("Done Priming"), 99); - lcd_quick_feedback(); + lcd_quick_feedback(true); lcd_external_control = false; } else @@ -517,7 +517,7 @@ inline bool prime_nozzle() { { #if ENABLED(ULTRA_LCD) lcd_setstatusPGM(PSTR("Fixed Length Prime."), 99); - lcd_quick_feedback(); + lcd_quick_feedback(true); #endif set_destination_from_current(); destination[E_AXIS] += g26_prime_length; @@ -680,9 +680,12 @@ void GcodeSuite::G26() { set_bed_leveling_enabled(!parser.seen('D')); if (current_position[Z_AXIS] < Z_CLEARANCE_BETWEEN_PROBES) { +SERIAL_PROTOCOLLNPGM("! move nozzle to Z_CLEARANCE_BETWEEN_PROBES height."); +SERIAL_ECHOLNPAIR(" Z at:", current_position[Z_AXIS]); do_blocking_move_to_z(Z_CLEARANCE_BETWEEN_PROBES); stepper.synchronize(); set_current_from_destination(); +SERIAL_ECHOLNPAIR(" Z now at:", current_position[Z_AXIS]); } if (turn_on_heaters() != G26_OK) goto LEAVE; @@ -708,8 +711,14 @@ void GcodeSuite::G26() { // Move nozzle to the specified height for the first layer set_destination_from_current(); +SERIAL_PROTOCOLLNPGM("! moving nozzle to 1st layer height."); +SERIAL_ECHOLNPAIR(" Z1 at:", current_position[Z_AXIS]); + destination[Z_AXIS] = g26_layer_height; move_to(destination, 0.0); + stepper.synchronize(); + set_destination_from_current(); +SERIAL_ECHOLNPAIR(" Z2 at:", current_position[Z_AXIS]); move_to(destination, g26_ooze_amount); #if ENABLED(ULTRA_LCD) diff --git a/Marlin/src/lcd/ultralcd.cpp b/Marlin/src/lcd/ultralcd.cpp index 4473ded64..b7bd1fcce 100644 --- a/Marlin/src/lcd/ultralcd.cpp +++ b/Marlin/src/lcd/ultralcd.cpp @@ -774,9 +774,12 @@ void kill_screen(const char* lcd_msg) { #endif } - void lcd_quick_feedback() { + void lcd_quick_feedback(const bool clear_buttons) { lcdDrawUpdate = LCDVIEW_CLEAR_CALL_REDRAW; - buttons = 0; + + if (clear_buttons) + buttons = 0; + next_button_update_ms = millis() + 500; // Buzz and wait. The delay is needed for buttons to settle! @@ -4672,8 +4675,8 @@ void kill_screen(const char* lcd_msg) { if (encoderDirection == -1) { // side effect which signals we are inside a menu if (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_DOWN) encoderPosition -= ENCODER_STEPS_PER_MENU_ITEM; else if (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_UP) encoderPosition += ENCODER_STEPS_PER_MENU_ITEM; - else if (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_LEFT) { menu_action_back(); lcd_quick_feedback(); } - else if (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_RIGHT) { lcd_return_to_status(); lcd_quick_feedback(); } + else if (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_LEFT) { menu_action_back(); lcd_quick_feedback(true); } + else if (buttons_reprapworld_keypad & EN_REPRAPWORLD_KEYPAD_RIGHT) { lcd_return_to_status(); lcd_quick_feedback(true); } } else { if (buttons_reprapworld_keypad & (EN_REPRAPWORLD_KEYPAD_DOWN|EN_REPRAPWORLD_KEYPAD_UP|EN_REPRAPWORLD_KEYPAD_RIGHT)) { @@ -4941,7 +4944,7 @@ void lcd_update() { wait_for_unclick = true; // Set debounce flag to ignore continous clicks lcd_clicked = !wait_for_user && !no_reentry; // Keep the click if not waiting for a user-click wait_for_user = false; // Any click clears wait for user - lcd_quick_feedback(); // Always make a click sound + lcd_quick_feedback(true); // Always make a click sound } } else wait_for_unclick = false; diff --git a/Marlin/src/lcd/ultralcd.h b/Marlin/src/lcd/ultralcd.h index 857d0344b..27103faff 100644 --- a/Marlin/src/lcd/ultralcd.h +++ b/Marlin/src/lcd/ultralcd.h @@ -116,7 +116,7 @@ extern volatile uint8_t buttons; // The last-checked buttons in a bit array. void lcd_buttons_update(); - void lcd_quick_feedback(); // Audible feedback for a button click - could also be visual + void lcd_quick_feedback(const bool clear_buttons); // Audible feedback for a button click - could also be visual void lcd_completion_feedback(const bool good=true); #if ENABLED(ADVANCED_PAUSE_FEATURE)