diff --git a/Marlin/UBL.h b/Marlin/UBL.h index ffb96a9f6f..51f58e235d 100644 --- a/Marlin/UBL.h +++ b/Marlin/UBL.h @@ -42,13 +42,13 @@ bool axis_unhomed_error(bool, bool, bool); void dump(char * const str, const float &f); 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 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); vector_3 tilt_mesh_based_on_3pts(const float&, const float&, 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 shift_mesh_height(); bool g29_parameter_parsing(); diff --git a/Marlin/UBL_Bed_Leveling.cpp b/Marlin/UBL_Bed_Leveling.cpp index 55f7a6d43b..83a0b2e47e 100644 --- a/Marlin/UBL_Bed_Leveling.cpp +++ b/Marlin/UBL_Bed_Leveling.cpp @@ -166,32 +166,34 @@ int8_t i, j; UNUSED(map_type); - SERIAL_PROTOCOLLNPGM("\nBed Topography Report:\n"); + if (map_type==0) { + SERIAL_PROTOCOLLNPGM("\nBed Topography Report:\n"); - SERIAL_ECHOPAIR("(", 0); - SERIAL_ECHOPAIR(", ", UBL_MESH_NUM_Y_POINTS - 1); - SERIAL_ECHOPGM(") "); + SERIAL_ECHOPAIR("(", 0); + SERIAL_ECHOPAIR(", ", UBL_MESH_NUM_Y_POINTS - 1); + SERIAL_ECHOPGM(") "); + } 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); - 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(",", UBL_MESH_NUM_Y_POINTS - 1); - SERIAL_ECHOLNPGM(")"); - - // if (map_type || 1) { + if (map_type==0) { + 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(",", UBL_MESH_NUM_Y_POINTS - 1); + SERIAL_ECHOLNPGM(")"); SERIAL_ECHOPAIR("(", UBL_MESH_MIN_X); SERIAL_ECHOPAIR(",", UBL_MESH_MAX_Y); SERIAL_CHAR(')'); + delay(15); for (i = 0; i < UBL_MESH_NUM_X_POINTS - 1; i++) { SERIAL_ECHOPGM(" "); @@ -204,75 +206,82 @@ SERIAL_ECHOPAIR("(", UBL_MESH_MAX_X); SERIAL_ECHOPAIR(",", UBL_MESH_MAX_Y); SERIAL_ECHOLNPGM(")"); - - // } + delay(15); + } for (j = UBL_MESH_NUM_Y_POINTS - 1; j >= 0; j--) { for (i = 0; i < UBL_MESH_NUM_X_POINTS; i++) { f = z_values[i][j]; // 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)) - SERIAL_PROTOCOLPGM(" . "); + if (map_type==0) { + SERIAL_PROTOCOLPGM(" . "); + } else + SERIAL_PROTOCOLPGM("NAN"); else { // 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); idle(); } + if (map_type!=0 && i0 MYSERIAL.flushTX(); #endif delay(15); - if (i == current_xi && j == current_yi) // is the nozzle here? if so, finish marking the number - SERIAL_CHAR(']'); - else - SERIAL_PROTOCOL(" "); - - SERIAL_CHAR(' '); + if (map_type==0) { + if (i == current_xi && j == current_yi) // is the nozzle here? if so, finish marking the number + SERIAL_CHAR(']'); + else + SERIAL_PROTOCOL(" "); + SERIAL_CHAR(' '); + } } 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_EOL; } } - // if (map_type) { - SERIAL_ECHOPAIR("(", int(UBL_MESH_MIN_X)); - SERIAL_ECHOPAIR(",", int(UBL_MESH_MIN_Y)); - SERIAL_ECHOPGM(") "); + if (map_type==0) { + SERIAL_ECHOPAIR("(", int(UBL_MESH_MIN_X)); + SERIAL_ECHOPAIR(",", int(UBL_MESH_MIN_Y)); + 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); + 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("(", 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() { diff --git a/Marlin/UBL_G29.cpp b/Marlin/UBL_G29.cpp index 026045a7bc..f582bc408d 100644 --- a/Marlin/UBL_G29.cpp +++ b/Marlin/UBL_G29.cpp @@ -125,7 +125,10 @@ * O Map * Display the Mesh Map Topology. * 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 - * 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 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 * + * 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. * * 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. 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 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')) { repetition_cnt = code_has_value() ? code_value_int() : 1; 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) { SERIAL_PROTOCOLLNPGM("Entire Mesh invalidated.\n"); 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')) { phase_value = code_value_int(); if (phase_value < 0 || phase_value > 7) { @@ -410,7 +427,7 @@ SERIAL_PROTOCOLLNPGM(")\n"); } 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; // // 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 (!repeat_flag) repetition_cnt = 9999; 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 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. * 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; ubl_has_control_of_lcd_panel++; @@ -721,7 +738,7 @@ 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) { const float xProbe = ubl.map_x_index_to_bed_location(location.x_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; } - 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); @@ -862,9 +879,9 @@ float last_x = -9999.99, last_y = -9999.99; mesh_index_pair location; 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 // NAN location. This is a manual probe. if (location.x_index < 0 && location.y_index < 0) continue; @@ -923,7 +940,7 @@ } } 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: restore_ubl_active_state_and_leave(); @@ -941,6 +958,7 @@ x_pos = current_position[X_AXIS]; y_pos = current_position[Y_AXIS]; x_flag = y_flag = repeat_flag = false; + map_type = 0; constant = 0.0; repetition_cnt = 1; @@ -1008,6 +1026,23 @@ 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; } @@ -1217,9 +1252,9 @@ 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]) { - int i, j; - float closest = 99999.99; + 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, k, l; + float distance, closest = far_flag ? -99999.99 : 99999.99; mesh_index_pair return_val; 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. // 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 return_val.x_index = i; // the specified type of mesh value. return_val.y_index = j; @@ -1283,9 +1330,9 @@ do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE); do_blocking_move_to_xy(lx, ly); 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 // 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. @@ -1356,7 +1403,7 @@ 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(); do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE);