Map clean up of UBL

UBL's maps are cleaner.   And with a 1 value, G29 O 1  will generate a
map suitable to be Cut & Pasted into Excel so a Suface Map can be
generated.
This commit is contained in:
Roxy-3D 2017-03-25 18:37:54 -05:00 committed by Roxy-3D
parent 9a1949a91e
commit 9d3ac66f73
3 changed files with 137 additions and 81 deletions

View file

@ -42,13 +42,13 @@
bool axis_unhomed_error(bool, bool, bool); bool axis_unhomed_error(bool, bool, bool);
void dump(char * const str, const float &f); void dump(char * const str, const float &f);
bool ubl_lcd_clicked(); bool ubl_lcd_clicked();
void probe_entire_mesh(const float&, const float&, const bool, const bool); void probe_entire_mesh(const float&, const float&, const bool, const bool, const bool);
void debug_current_and_destination(char *title); void debug_current_and_destination(char *title);
void ubl_line_to_destination(const float&, const float&, const float&, const float&, const float&, uint8_t); void ubl_line_to_destination(const float&, const float&, const float&, const float&, const float&, uint8_t);
void manually_probe_remaining_mesh(const float&, const float&, const float&, const float&, const bool); void manually_probe_remaining_mesh(const float&, const float&, const float&, const float&, const bool);
vector_3 tilt_mesh_based_on_3pts(const float&, const float&, const float&); vector_3 tilt_mesh_based_on_3pts(const float&, const float&, const float&);
float measure_business_card_thickness(const float&); float measure_business_card_thickness(const float&);
mesh_index_pair find_closest_mesh_point_of_type(const MeshPointType, const float&, const float&, const bool, unsigned int[16]); mesh_index_pair find_closest_mesh_point_of_type(const MeshPointType, const float&, const float&, const bool, unsigned int[16], bool);
void find_mean_mesh_height(); void find_mean_mesh_height();
void shift_mesh_height(); void shift_mesh_height();
bool g29_parameter_parsing(); bool g29_parameter_parsing();

View file

@ -166,32 +166,34 @@
int8_t i, j; int8_t i, j;
UNUSED(map_type); UNUSED(map_type);
SERIAL_PROTOCOLLNPGM("\nBed Topography Report:\n"); if (map_type==0) {
SERIAL_PROTOCOLLNPGM("\nBed Topography Report:\n");
SERIAL_ECHOPAIR("(", 0); SERIAL_ECHOPAIR("(", 0);
SERIAL_ECHOPAIR(", ", UBL_MESH_NUM_Y_POINTS - 1); SERIAL_ECHOPAIR(", ", UBL_MESH_NUM_Y_POINTS - 1);
SERIAL_ECHOPGM(") "); SERIAL_ECHOPGM(") ");
}
current_xi = ubl.get_cell_index_x(current_position[X_AXIS] + (MESH_X_DIST) / 2.0); current_xi = ubl.get_cell_index_x(current_position[X_AXIS] + (MESH_X_DIST) / 2.0);
current_yi = ubl.get_cell_index_y(current_position[Y_AXIS] + (MESH_Y_DIST) / 2.0); current_yi = ubl.get_cell_index_y(current_position[Y_AXIS] + (MESH_Y_DIST) / 2.0);
for (i = 0; i < UBL_MESH_NUM_X_POINTS - 1; i++) { if (map_type==0) {
SERIAL_ECHOPGM(" "); for (i = 0; i < UBL_MESH_NUM_X_POINTS - 1; i++) {
#if TX_BUFFER_SIZE>0 SERIAL_ECHOPGM(" ");
MYSERIAL.flushTX(); #if TX_BUFFER_SIZE>0
#endif MYSERIAL.flushTX();
delay(15); #endif
} delay(15);
}
SERIAL_ECHOPAIR("(", UBL_MESH_NUM_X_POINTS - 1);
SERIAL_ECHOPAIR(",", UBL_MESH_NUM_Y_POINTS - 1); SERIAL_ECHOPAIR("(", UBL_MESH_NUM_X_POINTS - 1);
SERIAL_ECHOLNPGM(")"); SERIAL_ECHOPAIR(",", UBL_MESH_NUM_Y_POINTS - 1);
SERIAL_ECHOLNPGM(")");
// if (map_type || 1) {
SERIAL_ECHOPAIR("(", UBL_MESH_MIN_X); SERIAL_ECHOPAIR("(", UBL_MESH_MIN_X);
SERIAL_ECHOPAIR(",", UBL_MESH_MAX_Y); SERIAL_ECHOPAIR(",", UBL_MESH_MAX_Y);
SERIAL_CHAR(')'); SERIAL_CHAR(')');
delay(15);
for (i = 0; i < UBL_MESH_NUM_X_POINTS - 1; i++) { for (i = 0; i < UBL_MESH_NUM_X_POINTS - 1; i++) {
SERIAL_ECHOPGM(" "); SERIAL_ECHOPGM(" ");
@ -204,75 +206,82 @@
SERIAL_ECHOPAIR("(", UBL_MESH_MAX_X); SERIAL_ECHOPAIR("(", UBL_MESH_MAX_X);
SERIAL_ECHOPAIR(",", UBL_MESH_MAX_Y); SERIAL_ECHOPAIR(",", UBL_MESH_MAX_Y);
SERIAL_ECHOLNPGM(")"); SERIAL_ECHOLNPGM(")");
delay(15);
// } }
for (j = UBL_MESH_NUM_Y_POINTS - 1; j >= 0; j--) { for (j = UBL_MESH_NUM_Y_POINTS - 1; j >= 0; j--) {
for (i = 0; i < UBL_MESH_NUM_X_POINTS; i++) { for (i = 0; i < UBL_MESH_NUM_X_POINTS; i++) {
f = z_values[i][j]; f = z_values[i][j];
// is the nozzle here? if so, mark the number // is the nozzle here? if so, mark the number
SERIAL_CHAR(i == current_xi && j == current_yi ? '[' : ' '); if (map_type==0)
SERIAL_CHAR(i == current_xi && j == current_yi ? '[' : ' ');
if (isnan(f)) if (isnan(f))
SERIAL_PROTOCOLPGM(" . "); if (map_type==0) {
SERIAL_PROTOCOLPGM(" . ");
} else
SERIAL_PROTOCOLPGM("NAN");
else { else {
// if we don't do this, the columns won't line up nicely // if we don't do this, the columns won't line up nicely
if (f >= 0.0) SERIAL_CHAR(' '); if (f>=0.0 && map_type==0) SERIAL_CHAR(' ');
SERIAL_PROTOCOL_F(f, 3); SERIAL_PROTOCOL_F(f, 3);
idle(); idle();
} }
if (map_type!=0 && i<UBL_MESH_NUM_X_POINTS-1)
SERIAL_PROTOCOLPGM(",");
#if TX_BUFFER_SIZE>0 #if TX_BUFFER_SIZE>0
MYSERIAL.flushTX(); MYSERIAL.flushTX();
#endif #endif
delay(15); delay(15);
if (i == current_xi && j == current_yi) // is the nozzle here? if so, finish marking the number if (map_type==0) {
SERIAL_CHAR(']'); if (i == current_xi && j == current_yi) // is the nozzle here? if so, finish marking the number
else SERIAL_CHAR(']');
SERIAL_PROTOCOL(" "); else
SERIAL_PROTOCOL(" ");
SERIAL_CHAR(' '); SERIAL_CHAR(' ');
}
} }
SERIAL_EOL; SERIAL_EOL;
if (j) { // we want the (0,0) up tight against the block of numbers if (j && map_type==0) { // we want the (0,0) up tight against the block of numbers
SERIAL_CHAR(' '); SERIAL_CHAR(' ');
SERIAL_EOL; SERIAL_EOL;
} }
} }
// if (map_type) { if (map_type==0) {
SERIAL_ECHOPAIR("(", int(UBL_MESH_MIN_X)); SERIAL_ECHOPAIR("(", int(UBL_MESH_MIN_X));
SERIAL_ECHOPAIR(",", int(UBL_MESH_MIN_Y)); SERIAL_ECHOPAIR(",", int(UBL_MESH_MIN_Y));
SERIAL_ECHOPGM(") "); SERIAL_ECHOPGM(") ");
for (i = 0; i < UBL_MESH_NUM_X_POINTS - 1; i++) { for (i = 0; i < UBL_MESH_NUM_X_POINTS - 1; i++) {
SERIAL_ECHOPGM(" "); SERIAL_ECHOPGM(" ");
#if TX_BUFFER_SIZE>0 #if TX_BUFFER_SIZE>0
MYSERIAL.flushTX(); MYSERIAL.flushTX();
#endif #endif
delay(15); delay(15);
}
SERIAL_ECHOPAIR("(", int(UBL_MESH_MAX_X));
SERIAL_ECHOPAIR(",", int(UBL_MESH_MIN_Y));
SERIAL_CHAR(')');
SERIAL_EOL;
SERIAL_ECHOPAIR("(", 0);
SERIAL_ECHOPAIR(",", 0);
SERIAL_ECHOPGM(") ");
for (i = 0; i < UBL_MESH_NUM_X_POINTS - 1; i++) {
SERIAL_ECHOPGM(" ");
#if TX_BUFFER_SIZE>0
MYSERIAL.flushTX();
#endif
delay(15);
}
SERIAL_ECHOPAIR("(", UBL_MESH_NUM_X_POINTS-1);
SERIAL_ECHOPAIR(",", 0);
SERIAL_ECHOLNPGM(")");
} }
SERIAL_ECHOPAIR("(", int(UBL_MESH_MAX_X));
SERIAL_ECHOPAIR(",", int(UBL_MESH_MIN_Y));
SERIAL_CHAR(')');
SERIAL_EOL;
SERIAL_ECHOPAIR("(", 0);
SERIAL_ECHOPAIR(",", 0);
SERIAL_ECHOPGM(") ");
for (i = 0; i < UBL_MESH_NUM_X_POINTS - 1; i++) {
SERIAL_ECHOPGM(" ");
#if TX_BUFFER_SIZE>0
MYSERIAL.flushTX();
#endif
delay(15);
}
SERIAL_ECHOPAIR("(", UBL_MESH_NUM_X_POINTS-1);
SERIAL_ECHOPAIR(",", 0);
SERIAL_ECHOLNPGM(")");
} }
bool unified_bed_leveling::sanity_check() { bool unified_bed_leveling::sanity_check() {

View file

@ -125,7 +125,10 @@
* O Map * Display the Mesh Map Topology. * O Map * Display the Mesh Map Topology.
* The parameter can be specified alone (ie. G29 O) or in combination with many of the * The parameter can be specified alone (ie. G29 O) or in combination with many of the
* other commands. The Mesh Map option works with all of the Phase * other commands. The Mesh Map option works with all of the Phase
* commands (ie. G29 P4 R 5 X 50 Y100 C -.1 O) * commands (ie. G29 P4 R 5 X 50 Y100 C -.1 O) The Map parameter can also of a Map Type
* specified. A map type of 0 is the default is user readable. A map type of 1 can
* be specified and is suitable to Cut & Paste into Excel to allow graphing of the user's
* mesh.
* *
* N No Home G29 normally insists that a G28 has been performed. You can over rule this with an * N No Home G29 normally insists that a G28 has been performed. You can over rule this with an
* N option. In general, you should not do this. This can only be done safely with * N option. In general, you should not do this. This can only be done safely with
@ -250,6 +253,10 @@
* *
* T 3-Point Perform a 3 Point Bed Leveling on the current Mesh * T 3-Point Perform a 3 Point Bed Leveling on the current Mesh
* *
* U Unlevel Perform a probe of the outer perimeter to assist in physically leveling unlevel beds.
* Only used for G29 P1 O U It will speed up the probing of the edge of the bed. This
* is useful when the entire bed does not need to be probed because it will be adjusted.
*
* W What? Display valuable data the Unified Bed Leveling System knows. * W What? Display valuable data the Unified Bed Leveling System knows.
* *
* X # * * X Location for this line of commands * X # * * X Location for this line of commands
@ -297,7 +304,7 @@
// The simple parameter flags and values are 'static' so parameter parsing can be in a support routine. // The simple parameter flags and values are 'static' so parameter parsing can be in a support routine.
static int g29_verbose_level = 0, phase_value = -1, repetition_cnt = 1, static int g29_verbose_level = 0, phase_value = -1, repetition_cnt = 1,
storage_slot = 0, test_pattern = 0; storage_slot = 0, map_type = 0, test_pattern = 0, unlevel_value = -1;
static bool repeat_flag = UBL_OK, c_flag = false, x_flag = UBL_OK, y_flag = UBL_OK, statistics_flag = UBL_OK, business_card_mode = false; static bool repeat_flag = UBL_OK, c_flag = false, x_flag = UBL_OK, y_flag = UBL_OK, statistics_flag = UBL_OK, business_card_mode = false;
static float x_pos = 0.0, y_pos = 0.0, height_value = 5.0, measured_z, card_thickness = 0.0, constant = 0.0; static float x_pos = 0.0, y_pos = 0.0, height_value = 5.0, measured_z, card_thickness = 0.0, constant = 0.0;
@ -331,7 +338,7 @@
if (code_seen('I')) { if (code_seen('I')) {
repetition_cnt = code_has_value() ? code_value_int() : 1; repetition_cnt = code_has_value() ? code_value_int() : 1;
while (repetition_cnt--) { while (repetition_cnt--) {
const mesh_index_pair location = find_closest_mesh_point_of_type(REAL, x_pos, y_pos, 0, NULL); // The '0' says we want to use the nozzle's position const mesh_index_pair location = find_closest_mesh_point_of_type(REAL, x_pos, y_pos, 0, NULL, false); // The '0' says we want to use the nozzle's position
if (location.x_index < 0) { if (location.x_index < 0) {
SERIAL_PROTOCOLLNPGM("Entire Mesh invalidated.\n"); SERIAL_PROTOCOLLNPGM("Entire Mesh invalidated.\n");
break; // No more invalid Mesh Points to populate break; // No more invalid Mesh Points to populate
@ -381,6 +388,16 @@
} }
} }
/*
if (code_seen('U')) {
unlevel_value = code_value_int();
// if (unlevel_value < 0 || unlevel_value > 7) {
// SERIAL_PROTOCOLLNPGM("Invalid Unlevel value. (0-4)\n");
// return;
// }
}
*/
if (code_seen('P')) { if (code_seen('P')) {
phase_value = code_value_int(); phase_value = code_value_int();
if (phase_value < 0 || phase_value > 7) { if (phase_value < 0 || phase_value > 7) {
@ -410,7 +427,7 @@
SERIAL_PROTOCOLLNPGM(")\n"); SERIAL_PROTOCOLLNPGM(")\n");
} }
probe_entire_mesh(x_pos + X_PROBE_OFFSET_FROM_EXTRUDER, y_pos + Y_PROBE_OFFSET_FROM_EXTRUDER, probe_entire_mesh(x_pos + X_PROBE_OFFSET_FROM_EXTRUDER, y_pos + Y_PROBE_OFFSET_FROM_EXTRUDER,
code_seen('O') || code_seen('M'), code_seen('E')); code_seen('O') || code_seen('M'), code_seen('E'), code_seen('U'));
break; break;
// //
// Manually Probe Mesh in areas that can not be reached by the probe // Manually Probe Mesh in areas that can not be reached by the probe
@ -455,7 +472,7 @@
// If no repetition is specified, do the whole Mesh // If no repetition is specified, do the whole Mesh
if (!repeat_flag) repetition_cnt = 9999; if (!repeat_flag) repetition_cnt = 9999;
while (repetition_cnt--) { while (repetition_cnt--) {
const mesh_index_pair location = find_closest_mesh_point_of_type(INVALID, x_pos, y_pos, 0, NULL); // The '0' says we want to use the nozzle's position const mesh_index_pair location = find_closest_mesh_point_of_type(INVALID, x_pos, y_pos, 0, NULL, false); // The '0' says we want to use the nozzle's position
if (location.x_index < 0) break; // No more invalid Mesh Points to populate if (location.x_index < 0) break; // No more invalid Mesh Points to populate
z_values[location.x_index][location.y_index] = height_value; z_values[location.x_index][location.y_index] = height_value;
} }
@ -700,7 +717,7 @@
* Probe all invalidated locations of the mesh that can be reached by the probe. * Probe all invalidated locations of the mesh that can be reached by the probe.
* This attempts to fill in locations closest to the nozzle's start location first. * This attempts to fill in locations closest to the nozzle's start location first.
*/ */
void probe_entire_mesh(const float &lx, const float &ly, const bool do_ubl_mesh_map, const bool stow_probe) { void probe_entire_mesh(const float &lx, const float &ly, const bool do_ubl_mesh_map, const bool stow_probe, bool do_furthest) {
mesh_index_pair location; mesh_index_pair location;
ubl_has_control_of_lcd_panel++; ubl_has_control_of_lcd_panel++;
@ -721,7 +738,7 @@
return; return;
} }
location = find_closest_mesh_point_of_type(INVALID, lx, ly, 1, NULL); // the '1' says we want the location to be relative to the probe location = find_closest_mesh_point_of_type(INVALID, lx, ly, 1, NULL, do_furthest ); // the '1' says we want the location to be relative to the probe
if (location.x_index >= 0 && location.y_index >= 0) { if (location.x_index >= 0 && location.y_index >= 0) {
const float xProbe = ubl.map_x_index_to_bed_location(location.x_index), const float xProbe = ubl.map_x_index_to_bed_location(location.x_index),
yProbe = ubl.map_y_index_to_bed_location(location.y_index); yProbe = ubl.map_y_index_to_bed_location(location.y_index);
@ -734,7 +751,7 @@
z_values[location.x_index][location.y_index] = measured_z + Z_PROBE_OFFSET_FROM_EXTRUDER; z_values[location.x_index][location.y_index] = measured_z + Z_PROBE_OFFSET_FROM_EXTRUDER;
} }
if (do_ubl_mesh_map) ubl.display_map(1); if (do_ubl_mesh_map) ubl.display_map(map_type);
} while (location.x_index >= 0 && location.y_index >= 0); } while (location.x_index >= 0 && location.y_index >= 0);
@ -862,9 +879,9 @@
float last_x = -9999.99, last_y = -9999.99; float last_x = -9999.99, last_y = -9999.99;
mesh_index_pair location; mesh_index_pair location;
do { do {
if (do_ubl_mesh_map) ubl.display_map(1); if (do_ubl_mesh_map) ubl.display_map(map_type);
location = find_closest_mesh_point_of_type(INVALID, lx, ly, 0, NULL); // The '0' says we want to use the nozzle's position location = find_closest_mesh_point_of_type(INVALID, lx, ly, 0, NULL, false); // The '0' says we want to use the nozzle's position
// It doesn't matter if the probe can not reach the // It doesn't matter if the probe can not reach the
// NAN location. This is a manual probe. // NAN location. This is a manual probe.
if (location.x_index < 0 && location.y_index < 0) continue; if (location.x_index < 0 && location.y_index < 0) continue;
@ -923,7 +940,7 @@
} }
} while (location.x_index >= 0 && location.y_index >= 0); } while (location.x_index >= 0 && location.y_index >= 0);
if (do_ubl_mesh_map) ubl.display_map(1); if (do_ubl_mesh_map) ubl.display_map(map_type);
LEAVE: LEAVE:
restore_ubl_active_state_and_leave(); restore_ubl_active_state_and_leave();
@ -941,6 +958,7 @@
x_pos = current_position[X_AXIS]; x_pos = current_position[X_AXIS];
y_pos = current_position[Y_AXIS]; y_pos = current_position[Y_AXIS];
x_flag = y_flag = repeat_flag = false; x_flag = y_flag = repeat_flag = false;
map_type = 0;
constant = 0.0; constant = 0.0;
repetition_cnt = 1; repetition_cnt = 1;
@ -1008,6 +1026,23 @@
return UBL_ERR; return UBL_ERR;
} }
} }
if (code_seen('O')) { // Check if a map type was specified
map_type = code_value_int() ? code_has_value() : 0;
if ( map_type<0 || map_type>1) {
SERIAL_PROTOCOLLNPGM("Invalid map type.\n");
return UBL_ERR;
}
}
if (code_seen('M')) { // Check if a map type was specified
map_type = code_value_int() ? code_has_value() : 0;
if ( map_type<0 || map_type>1) {
SERIAL_PROTOCOLLNPGM("Invalid map type.\n");
return UBL_ERR;
}
}
return UBL_OK; return UBL_OK;
} }
@ -1217,9 +1252,9 @@
z_values[x][y] = z_values[x][y] - tmp_z_values[x][y]; z_values[x][y] = z_values[x][y] - tmp_z_values[x][y];
} }
mesh_index_pair find_closest_mesh_point_of_type(const MeshPointType type, const float &lx, const float &ly, const bool probe_as_reference, unsigned int bits[16]) { mesh_index_pair find_closest_mesh_point_of_type(const MeshPointType type, const float &lx, const float &ly, const bool probe_as_reference, unsigned int bits[16], bool far_flag) {
int i, j; int i, j, k, l;
float closest = 99999.99; float distance, closest = far_flag ? -99999.99 : 99999.99;
mesh_index_pair return_val; mesh_index_pair return_val;
return_val.x_index = return_val.y_index = -1; return_val.x_index = return_val.y_index = -1;
@ -1254,9 +1289,21 @@
// We can get to it. Let's see if it is the closest location to the nozzle. // We can get to it. Let's see if it is the closest location to the nozzle.
// Add in a weighting factor that considers the current location of the nozzle. // Add in a weighting factor that considers the current location of the nozzle.
const float distance = HYPOT(px - mx, py - my) + HYPOT(current_x - mx, current_y - my) * 0.01;
if (distance < closest) { distance = HYPOT(px - mx, py - my) + HYPOT(current_x - mx, current_y - my) * 0.1;
if (far_flag) { // If doing the far_flag action, we want to be as far as possible
for (k = 0; k < UBL_MESH_NUM_X_POINTS; k++) { // from the starting point and from any other probed points. We
for (l = 0; j < UBL_MESH_NUM_Y_POINTS; l++) { // want the next point spread out and filling in any blank spaces
if ( !isnan(z_values[k][l])) { // in the mesh. So we add in some of the distance to every probed
distance += (i-k)*(i-k)*MESH_X_DIST*.05; // point we can find.
distance += (j-l)*(j-l)*MESH_Y_DIST*.05;
}
}
}
}
if ( (!far_flag&&(distance < closest)) || (far_flag&&(distance > closest)) ) { // if far_flag, look for furthest away point
closest = distance; // We found a closer location with closest = distance; // We found a closer location with
return_val.x_index = i; // the specified type of mesh value. return_val.x_index = i; // the specified type of mesh value.
return_val.y_index = j; return_val.y_index = j;
@ -1283,9 +1330,9 @@
do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE); do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE);
do_blocking_move_to_xy(lx, ly); do_blocking_move_to_xy(lx, ly);
do { do {
if (do_ubl_mesh_map) ubl.display_map(1); if (do_ubl_mesh_map) ubl.display_map(map_type);
location = find_closest_mesh_point_of_type( SET_IN_BITMAP, lx, ly, 0, not_done); // The '0' says we want to use the nozzle's position location = find_closest_mesh_point_of_type( SET_IN_BITMAP, lx, ly, 0, not_done, false); // The '0' says we want to use the nozzle's position
// It doesn't matter if the probe can not reach this // It doesn't matter if the probe can not reach this
// location. This is a manual edit of the Mesh Point. // location. This is a manual edit of the Mesh Point.
if (location.x_index < 0 && location.y_index < 0) continue; // abort if we can't find any more points. if (location.x_index < 0 && location.y_index < 0) continue; // abort if we can't find any more points.
@ -1356,7 +1403,7 @@
ubl_has_control_of_lcd_panel = false; ubl_has_control_of_lcd_panel = false;
if (do_ubl_mesh_map) ubl.display_map(1); if (do_ubl_mesh_map) ubl.display_map(map_type);
restore_ubl_active_state_and_leave(); restore_ubl_active_state_and_leave();
do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE); do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE);