26-day-old buried patch to U.B.L.

This commit is contained in:
Scott Lahteine 2018-02-11 05:24:56 -06:00
parent 0acaaf536d
commit 7e17a2cfd0
3 changed files with 184 additions and 200 deletions

View File

@ -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

View File

@ -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
}

View File

@ -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!