diff --git a/Marlin/ubl.h b/Marlin/ubl.h index b5ddb05ad..8689c6a1b 100644 --- a/Marlin/ubl.h +++ b/Marlin/ubl.h @@ -91,7 +91,7 @@ #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 in_height); static void manually_probe_remaining_mesh(const float&, const float&, const float&, const float&, const bool) _O0; static void fine_tune_mesh(const float &rx, const float &ry, const bool do_ubl_mesh_map) _O0; #endif diff --git a/Marlin/ubl_G29.cpp b/Marlin/ubl_G29.cpp index 99eadc5cd..8893c233b 100644 --- a/Marlin/ubl_G29.cpp +++ b/Marlin/ubl_G29.cpp @@ -24,6 +24,8 @@ #if ENABLED(AUTO_BED_LEVELING_UBL) + //#define UBL_DEVEL_DEBUGGING + #include "ubl.h" #include "Marlin.h" #include "hex_print_routines.h" @@ -90,8 +92,8 @@ * previous measurements. * * 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. + * location in its search for the closest unmeasured Mesh Point. Instead, attempt to + * start at one end of the uprobed points and Continue sequentially. * * G29 P3 C specifies the Constant for the fill. Otherwise, uses a "reasonable" value. * @@ -273,9 +275,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 @@ -377,34 +377,13 @@ 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))); @@ -474,9 +453,8 @@ #endif } - 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; @@ -788,6 +766,7 @@ MYSERIAL.flush(); // G29 P2's take a long time to complete. PronterFace can // over run the serial character buffer with M105's without // this fix + } while (location.x_index >= 0 && --max_iterations); STOW_PROBE(); @@ -799,109 +778,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 @@ -1158,12 +1034,12 @@ static uint8_t ubl_state_at_invocation = 0; - #if ENABLED(UBL_DEVEL_DEBUGGING) + #ifdef UBL_DEVEL_DEBUGGING static uint8_t ubl_state_recursion_chk = 0; #endif void unified_bed_leveling::save_ubl_active_state_and_disable() { - #if ENABLED(UBL_DEVEL_DEBUGGING) + #ifdef UBL_DEVEL_DEBUGGING ubl_state_recursion_chk++; if (ubl_state_recursion_chk != 1) { SERIAL_ECHOLNPGM("save_ubl_active_state_and_disabled() called multiple times in a row."); @@ -1179,7 +1055,7 @@ } void unified_bed_leveling::restore_ubl_active_state_and_leave() { - #if ENABLED(UBL_DEVEL_DEBUGGING) + #ifdef UBL_DEVEL_DEBUGGING if (--ubl_state_recursion_chk) { SERIAL_ECHOLNPGM("restore_ubl_active_state_and_leave() called too many times."); #if ENABLED(NEWPANEL) @@ -1263,7 +1139,7 @@ SERIAL_EOL(); safe_delay(50); - #if ENABLED(UBL_DEVEL_DEBUGGING) + #ifdef UBL_DEVEL_DEBUGGING SERIAL_PROTOCOLLNPAIR("ubl_state_at_invocation :", ubl_state_at_invocation); SERIAL_EOL(); SERIAL_PROTOCOLLNPAIR("ubl_state_recursion_chk :", ubl_state_recursion_chk); @@ -1377,22 +1253,22 @@ found_a_NAN = true; - int8_t closest_x=-1, closest_y=-1; + int8_t closest_x = -1, closest_y = -1; float d1, d2 = 99999.9; for (int8_t k = 0; k < GRID_MAX_POINTS_X; k++) { for (int8_t l = 0; l < GRID_MAX_POINTS_Y; l++) { if (!isnan(z_values[k][l])) { found_a_real = true; - // Add in a random weighting factor that scrambles the probing of the - // last half of the mesh (when every unprobed mesh point is one index - // from a probed location). + // Add in a random weighting factor that scrambles the probing of the + // last half of the mesh (when every unprobed mesh point is one index + // from a probed location). d1 = HYPOT(i - k, j - l) + (1.0 / ((millis() % 47) + 13)); if (d1 < d2) { // found a closer distance from invalid mesh point at (i,j) to defined mesh point at (k,l) - d2 = d1; // found a closer location with - closest_x = i; // an assigned mesh point value + d2 = d1; // found a closer location with + closest_x = i; // an assigned mesh point value closest_y = j; } } @@ -1400,7 +1276,7 @@ } // - // at this point d2 should have the closest defined mesh point to invalid mesh point (i,j) + // At this point d2 should have the closest defined mesh point to invalid mesh point (i,j) // if (found_a_real && (closest_x >= 0) && (d2 > out_mesh.distance)) { @@ -1542,7 +1418,7 @@ do_blocking_move_to_z(h_offset + new_z); // Move the nozzle as the point is edited #endif idle(); - MYSERIAL.flush(); // G29 P2's take a long time to complete. PronterFace can + MYSERIAL.flush(); // G29 P2's take a long time to complete. PronterFace can // over run the serial character buffer with M105's without // this fix } while (!is_lcd_clicked()); @@ -1597,10 +1473,10 @@ y1 = y + ydir, y2 = y1 + ydir; // A NAN next to a pair of real values? if (isnan(z_values[x][y]) && !isnan(z_values[x1][y1]) && !isnan(z_values[x2][y2])) { - if (z_values[x1][y1] < z_values[x2][y2]) // Angled downward? - z_values[x][y] = z_values[x1][y1]; // Use nearest (maybe a little too high.) + if (z_values[x1][y1] < z_values[x2][y2]) // Angled downward? + z_values[x][y] = z_values[x1][y1]; // Use nearest (maybe a little too high.) else - z_values[x][y] = 2.0 * z_values[x1][y1] - z_values[x2][y2]; // Angled upward... + z_values[x][y] = 2.0 * z_values[x1][y1] - z_values[x2][y2]; // Angled upward... return true; } return false; @@ -1637,73 +1513,129 @@ #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); - 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 ENABLED(DEBUG_LEVELING_FEATURE) - if (DEBUGGING(LEVELING)) { - SERIAL_CHAR('('); - SERIAL_PROTOCOL_F(rx, 7); - SERIAL_CHAR(','); - SERIAL_PROTOCOL_F(ry, 7); - SERIAL_ECHOPGM(") logical: "); - SERIAL_CHAR('('); - SERIAL_PROTOCOL_F(LOGICAL_X_POSITION(rx), 7); - SERIAL_CHAR(','); - SERIAL_PROTOCOL_F(LOGICAL_Y_POSITION(ry), 7); - SERIAL_ECHOPGM(") measured: "); - SERIAL_PROTOCOL_F(measured_z, 7); - SERIAL_ECHOPGM(" correction: "); - SERIAL_PROTOCOL_F(get_z_correction(rx, ry), 7); - } - #endif - - measured_z -= get_z_correction(rx, ry) /* + zprobe_zoffset */ ; - - #if ENABLED(DEBUG_LEVELING_FEATURE) - if (DEBUGGING(LEVELING)) { - SERIAL_ECHOPGM(" final >>>---> "); - SERIAL_PROTOCOL_F(measured_z, 7); - SERIAL_EOL(); - } - #endif - - incremental_LSF(&lsf_results, rx, ry, measured_z); + 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 { // !do_3_pt_leveling + + 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); + + if (!abort_flag) { + measured_z = probe_pt(rx, ry, parser.seen('E'), g29_verbose_level); // TODO: Needs error handling + + abort_flag = isnan(measured_z); + + #if ENABLED(DEBUG_LEVELING_FEATURE) + if (DEBUGGING(LEVELING)) { + SERIAL_CHAR('('); + SERIAL_PROTOCOL_F(rx, 7); + SERIAL_CHAR(','); + SERIAL_PROTOCOL_F(ry, 7); + SERIAL_ECHOPGM(") logical: "); + SERIAL_CHAR('('); + SERIAL_PROTOCOL_F(LOGICAL_X_POSITION(rx), 7); + SERIAL_CHAR(','); + SERIAL_PROTOCOL_F(LOGICAL_Y_POSITION(ry), 7); + SERIAL_ECHOPGM(") measured: "); + SERIAL_PROTOCOL_F(measured_z, 7); + SERIAL_ECHOPGM(" correction: "); + SERIAL_PROTOCOL_F(get_z_correction(rx, ry), 7); + } + #endif + + measured_z -= get_z_correction(rx, ry) /* + zprobe_zoffset */ ; + + #if ENABLED(DEBUG_LEVELING_FEATURE) + if (DEBUGGING(LEVELING)) { + SERIAL_ECHOPGM(" final >>>---> "); + SERIAL_PROTOCOL_F(measured_z, 7); + SERIAL_EOL(); + } + #endif + + incremental_LSF(&lsf_results, rx, ry, measured_z); + } + } + + zig_zag ^= true; } - 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(); if (g29_verbose_level > 2) { @@ -1776,7 +1708,60 @@ 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 + */ + #if 0 + 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_ECHOPGM(" 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_ECHOPGM(" 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_ECHOPGM(" 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_ECHOPGM(") = "); + SERIAL_ECHO_F(get_z_correction(Z_SAFE_HOMING_X_POINT, Z_SAFE_HOMING_Y_POINT), 6); + SERIAL_EOL(); + #endif + } // DEBUGGING(LEVELING) #endif } diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 70547df58..775de8b60 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -768,8 +768,7 @@ void kill_screen(const char* lcd_msg) { void lcd_quick_feedback(const bool clear_buttons) { lcdDrawUpdate = LCDVIEW_CLEAR_CALL_REDRAW; - if (clear_buttons) - buttons = 0; + if (clear_buttons) buttons = 0; next_button_update_ms = millis() + 500; // Buzz and wait. The delay is needed for buttons to settle!