diff --git a/.travis.yml b/.travis.yml index 652ddbebb..93a365a72 100644 --- a/.travis.yml +++ b/.travis.yml @@ -96,13 +96,18 @@ script: - opt_set_adv FANMUX0_PIN 53 - build_marlin # - # Test a simple build of AUTO_BED_LEVELING_UBL + # Test a probeless build of AUTO_BED_LEVELING_UBL # - restore_configs - - opt_enable AUTO_BED_LEVELING_UBL UBL_G26_MESH_EDITING ENABLE_LEVELING_FADE_HEIGHT FIX_MOUNTED_PROBE EEPROM_SETTINGS G3D_PANEL + - opt_enable AUTO_BED_LEVELING_UBL UBL_G26_MESH_EDITING ENABLE_LEVELING_FADE_HEIGHT EEPROM_SETTINGS G3D_PANEL - opt_enable_adv CUSTOM_USER_MENUS I2C_POSITION_ENCODERS BABYSTEPPING - build_marlin # + # And with a probe... + # + - opt_enable FIX_MOUNTED_PROBE + - build_marlin + # # Test a Sled Z Probe # ...with AUTO_BED_LEVELING_LINEAR, DEBUG_LEVELING_FEATURE, EEPROM_SETTINGS, and EEPROM_CHITCHAT # diff --git a/Marlin/G26_Mesh_Validation_Tool.cpp b/Marlin/G26_Mesh_Validation_Tool.cpp index ffcad389f..92c86b7ff 100644 --- a/Marlin/G26_Mesh_Validation_Tool.cpp +++ b/Marlin/G26_Mesh_Validation_Tool.cpp @@ -136,13 +136,8 @@ extern float destination[XYZE]; void set_destination_to_current(); void prepare_move_to_destination(); - #if AVR_AT90USB1286_FAMILY // Teensyduino & Printrboard IDE extensions have compile errors without this - inline void sync_plan_position_e() { planner.set_e_position_mm(current_position[E_AXIS]); } - inline void set_current_to_destination() { COPY(current_position, destination); } - #else - void sync_plan_position_e(); - void set_current_to_destination(); - #endif + inline void sync_plan_position_e() { planner.set_e_position_mm(current_position[E_AXIS]); } + inline void set_current_to_destination() { COPY(current_position, destination); } #if ENABLED(NEWPANEL) void lcd_setstatusPGM(const char* const message, const int8_t level); void chirp_at_user(); diff --git a/Marlin/SanityCheck.h b/Marlin/SanityCheck.h index 6362f2d73..5a5cc3d09 100644 --- a/Marlin/SanityCheck.h +++ b/Marlin/SanityCheck.h @@ -647,9 +647,7 @@ static_assert(1 >= 0 /** * Require some kind of probe for bed leveling and probe testing */ - #if ENABLED(AUTO_BED_LEVELING_UBL) - #error "Unified Bed Leveling requires a probe: FIX_MOUNTED_PROBE, BLTOUCH, SOLENOID_PROBE, Z_PROBE_ALLEN_KEY, Z_PROBE_SLED, or Z Servo." - #elif HAS_ABL + #if HAS_ABL && DISABLED(AUTO_BED_LEVELING_UBL) #error "Auto Bed Leveling requires one of these: PROBE_MANUALLY, FIX_MOUNTED_PROBE, BLTOUCH, SOLENOID_PROBE, Z_PROBE_ALLEN_KEY, Z_PROBE_SLED, or a Z Servo." #endif diff --git a/Marlin/ubl.h b/Marlin/ubl.h index b1d3bed78..e11c743b4 100644 --- a/Marlin/ubl.h +++ b/Marlin/ubl.h @@ -91,13 +91,16 @@ g29_phase_value, g29_repetition_cnt, g29_storage_slot, - g29_map_type, - g29_grid_size; + g29_map_type; static bool g29_c_flag, g29_x_flag, g29_y_flag; static float g29_x_pos, g29_y_pos, g29_card_thickness, g29_constant; + #if HAS_BED_PROBE + static int g29_grid_size; + #endif + #if ENABLED(UBL_G26_MESH_VALIDATION) static float g26_extrusion_multiplier, g26_retraction_multiplier, diff --git a/Marlin/ubl_G29.cpp b/Marlin/ubl_G29.cpp index 06c51aef4..3ec507a68 100644 --- a/Marlin/ubl_G29.cpp +++ b/Marlin/ubl_G29.cpp @@ -64,8 +64,7 @@ unified_bed_leveling::g29_phase_value, unified_bed_leveling::g29_repetition_cnt, unified_bed_leveling::g29_storage_slot = 0, - unified_bed_leveling::g29_map_type, - unified_bed_leveling::g29_grid_size; + unified_bed_leveling::g29_map_type; bool unified_bed_leveling::g29_c_flag, unified_bed_leveling::g29_x_flag, unified_bed_leveling::g29_y_flag; @@ -74,6 +73,10 @@ unified_bed_leveling::g29_card_thickness = 0.0, unified_bed_leveling::g29_constant = 0.0; + #if HAS_BED_PROBE + int unified_bed_leveling::g29_grid_size; + #endif + /** * G29: Unified Bed Leveling by Roxy * @@ -309,6 +312,8 @@ return; } + if (g29_parameter_parsing()) return; // abort if parsing the simple parameters causes a problem, + // Check for commands that require the printer to be homed if (axis_unhomed_error()) { const int8_t p_val = parser.intval('P', -1); @@ -316,8 +321,6 @@ home_all_axes(); } - if (g29_parameter_parsing()) return; // abort if parsing the simple parameters causes a problem, - // Invalidate Mesh Points. This command is a little bit asymmetrical because // it directly specifies the repetition count and does not use the 'R' parameter. if (parser.seen('I')) { @@ -380,40 +383,44 @@ } } - 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')); - restore_ubl_active_state_and_leave(); - } - else { // grid_size == 0 : A 3-Point leveling has been requested - float z3, z2, z1 = probe_pt(LOGICAL_X_POSITION(UBL_PROBE_PT_1_X), LOGICAL_Y_POSITION(UBL_PROBE_PT_1_Y), false, g29_verbose_level); - if (!isnan(z1)) { - z2 = probe_pt(LOGICAL_X_POSITION(UBL_PROBE_PT_2_X), LOGICAL_Y_POSITION(UBL_PROBE_PT_2_Y), false, g29_verbose_level); - if (!isnan(z2)) - z3 = probe_pt(LOGICAL_X_POSITION(UBL_PROBE_PT_3_X), LOGICAL_Y_POSITION(UBL_PROBE_PT_3_Y), true, g29_verbose_level); - } + #if HAS_BED_PROBE - 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; + 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')); + restore_ubl_active_state_and_leave(); } + else { // grid_size == 0 : A 3-Point leveling has been requested + float z3, z2, z1 = probe_pt(LOGICAL_X_POSITION(UBL_PROBE_PT_1_X), LOGICAL_Y_POSITION(UBL_PROBE_PT_1_Y), false, g29_verbose_level); + if (!isnan(z1)) { + z2 = probe_pt(LOGICAL_X_POSITION(UBL_PROBE_PT_2_X), LOGICAL_Y_POSITION(UBL_PROBE_PT_2_Y), false, g29_verbose_level); + if (!isnan(z2)) + z3 = probe_pt(LOGICAL_X_POSITION(UBL_PROBE_PT_3_X), LOGICAL_Y_POSITION(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.) + // 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(LOGICAL_X_POSITION(UBL_PROBE_PT_1_X), LOGICAL_Y_POSITION(UBL_PROBE_PT_1_Y)) /* + zprobe_zoffset */ ; - z2 -= get_z_correction(LOGICAL_X_POSITION(UBL_PROBE_PT_2_X), LOGICAL_Y_POSITION(UBL_PROBE_PT_2_Y)) /* + zprobe_zoffset */ ; - z3 -= get_z_correction(LOGICAL_X_POSITION(UBL_PROBE_PT_3_X), LOGICAL_Y_POSITION(UBL_PROBE_PT_3_Y)) /* + zprobe_zoffset */ ; + save_ubl_active_state_and_disable(); + z1 -= get_z_correction(LOGICAL_X_POSITION(UBL_PROBE_PT_1_X), LOGICAL_Y_POSITION(UBL_PROBE_PT_1_Y)) /* + zprobe_zoffset */ ; + z2 -= get_z_correction(LOGICAL_X_POSITION(UBL_PROBE_PT_2_X), LOGICAL_Y_POSITION(UBL_PROBE_PT_2_Y)) /* + zprobe_zoffset */ ; + z3 -= get_z_correction(LOGICAL_X_POSITION(UBL_PROBE_PT_3_X), LOGICAL_Y_POSITION(UBL_PROBE_PT_3_Y)) /* + zprobe_zoffset */ ; - do_blocking_move_to_xy(0.5 * (UBL_MESH_MAX_X - (UBL_MESH_MIN_X)), 0.5 * (UBL_MESH_MAX_Y - (UBL_MESH_MIN_Y))); - tilt_mesh_based_on_3pts(z1, z2, z3); - restore_ubl_active_state_and_leave(); + do_blocking_move_to_xy(0.5 * (UBL_MESH_MAX_X - (UBL_MESH_MIN_X)), 0.5 * (UBL_MESH_MAX_Y - (UBL_MESH_MIN_Y))); + tilt_mesh_based_on_3pts(z1, z2, z3); + restore_ubl_active_state_and_leave(); + } } - } + + #endif // HAS_BED_PROBE if (parser.seen('P')) { if (WITHIN(g29_phase_value, 0, 1) && state.storage_slot == -1) { @@ -430,23 +437,27 @@ SERIAL_PROTOCOLLNPGM("Mesh zeroed."); break; - case 1: - // - // Invalidate Entire Mesh and Automatically Probe Mesh in areas that can be reached by the probe - // - if (!parser.seen('C')) { - invalidate(); - SERIAL_PROTOCOLLNPGM("Mesh invalidated. Probing mesh."); - } - if (g29_verbose_level > 1) { - SERIAL_PROTOCOLPAIR("Probing Mesh Points Closest to (", g29_x_pos); - SERIAL_PROTOCOLCHAR(','); - SERIAL_PROTOCOL(g29_y_pos); - SERIAL_PROTOCOLLNPGM(").\n"); - } - probe_entire_mesh(g29_x_pos + X_PROBE_OFFSET_FROM_EXTRUDER, g29_y_pos + Y_PROBE_OFFSET_FROM_EXTRUDER, - parser.seen('T'), parser.seen('E'), parser.seen('U')); - break; + #if HAS_BED_PROBE + + case 1: + // + // Invalidate Entire Mesh and Automatically Probe Mesh in areas that can be reached by the probe + // + if (!parser.seen('C')) { + invalidate(); + SERIAL_PROTOCOLLNPGM("Mesh invalidated. Probing mesh."); + } + if (g29_verbose_level > 1) { + SERIAL_PROTOCOLPAIR("Probing Mesh Points Closest to (", g29_x_pos); + SERIAL_PROTOCOLCHAR(','); + SERIAL_PROTOCOL(g29_y_pos); + SERIAL_PROTOCOLLNPGM(").\n"); + } + probe_entire_mesh(g29_x_pos + X_PROBE_OFFSET_FROM_EXTRUDER, g29_y_pos + Y_PROBE_OFFSET_FROM_EXTRUDER, + parser.seen('T'), parser.seen('E'), parser.seen('U')); + break; + + #endif // HAS_BED_PROBE case 2: { #if ENABLED(NEWPANEL) @@ -775,159 +786,161 @@ z_values[x][y] += g29_constant; } - /** - * 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 unified_bed_leveling::probe_entire_mesh(const float &lx, const float &ly, const bool do_ubl_mesh_map, const bool stow_probe, bool close_or_far) { - mesh_index_pair location; - - has_control_of_lcd_panel = true; - save_ubl_active_state_and_disable(); // we don't do bed level correction because we want the raw data when we probe - DEPLOY_PROBE(); - - uint16_t max_iterations = GRID_MAX_POINTS; - - do { - #if ENABLED(NEWPANEL) - if (ubl_lcd_clicked()) { - SERIAL_PROTOCOLLNPGM("\nMesh only partially populated.\n"); - lcd_quick_feedback(); - STOW_PROBE(); - while (ubl_lcd_clicked()) idle(); - has_control_of_lcd_panel = false; - restore_ubl_active_state_and_leave(); - safe_delay(50); // Debounce the Encoder wheel - return; - } - #endif - - location = find_closest_mesh_point_of_type(INVALID, lx, ly, USE_PROBE_AS_REFERENCE, NULL, close_or_far); - - if (location.x_index >= 0) { // mesh point found and is reachable by probe - const float rawx = mesh_index_to_xpos(location.x_index), - rawy = mesh_index_to_ypos(location.y_index); + #if HAS_BED_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. + */ + void unified_bed_leveling::probe_entire_mesh(const float &lx, const float &ly, const bool do_ubl_mesh_map, const bool stow_probe, bool close_or_far) { + mesh_index_pair location; - const float measured_z = probe_pt(LOGICAL_X_POSITION(rawx), LOGICAL_Y_POSITION(rawy), stow_probe, g29_verbose_level); // TODO: Needs error handling - z_values[location.x_index][location.y_index] = measured_z; - } + has_control_of_lcd_panel = true; + save_ubl_active_state_and_disable(); // we don't do bed level correction because we want the raw data when we probe + DEPLOY_PROBE(); - if (do_ubl_mesh_map) display_map(g29_map_type); + uint16_t max_iterations = GRID_MAX_POINTS; - } while (location.x_index >= 0 && --max_iterations); + do { + #if ENABLED(NEWPANEL) + if (ubl_lcd_clicked()) { + SERIAL_PROTOCOLLNPGM("\nMesh only partially populated.\n"); + lcd_quick_feedback(); + STOW_PROBE(); + while (ubl_lcd_clicked()) idle(); + has_control_of_lcd_panel = false; + restore_ubl_active_state_and_leave(); + safe_delay(50); // Debounce the Encoder wheel + return; + } + #endif - STOW_PROBE(); - restore_ubl_active_state_and_leave(); + location = find_closest_mesh_point_of_type(INVALID, lx, ly, USE_PROBE_AS_REFERENCE, NULL, close_or_far); - do_blocking_move_to_xy( - constrain(lx - (X_PROBE_OFFSET_FROM_EXTRUDER), UBL_MESH_MIN_X, UBL_MESH_MAX_X), - constrain(ly - (Y_PROBE_OFFSET_FROM_EXTRUDER), UBL_MESH_MIN_Y, UBL_MESH_MAX_Y) - ); - } + if (location.x_index >= 0) { // mesh point found and is reachable by probe + const float rawx = mesh_index_to_xpos(location.x_index), + rawy = mesh_index_to_ypos(location.y_index); - 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) ), + const float measured_z = probe_pt(LOGICAL_X_POSITION(rawx), LOGICAL_Y_POSITION(rawy), stow_probe, g29_verbose_level); // TODO: Needs error handling + z_values[location.x_index][location.y_index] = measured_z; + } - 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) ), + if (do_ubl_mesh_map) display_map(g29_map_type); - normal = vector_3::cross(v1, v2); + } while (location.x_index >= 0 && --max_iterations); - normal = normal.get_normal(); + STOW_PROBE(); + restore_ubl_active_state_and_leave(); - /** - * 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; + do_blocking_move_to_xy( + constrain(lx - (X_PROBE_OFFSET_FROM_EXTRUDER), UBL_MESH_MIN_X, UBL_MESH_MAX_X), + constrain(ly - (Y_PROBE_OFFSET_FROM_EXTRUDER), UBL_MESH_MIN_Y, UBL_MESH_MAX_Y) + ); } - 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:")); - } + 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; + } - // - // All of 3 of these points should give us the same d constant - // + rotation = matrix_3x3::create_look_at(vector_3(normal.x, normal.y, 1)); - 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("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:")); + } - if (g29_verbose_level>2) { - SERIAL_ECHOPGM("D constant: "); - SERIAL_PROTOCOL_F(d, 7); - SERIAL_ECHOLNPGM(" "); - } + // + // All of 3 of these points should give us the same d constant + // - #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(); + 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(" "); } - #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; + #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 #if ENABLED(NEWPANEL) float unified_bed_leveling::measure_point_with_encoder() { @@ -1079,7 +1092,7 @@ do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE); do_blocking_move_to_xy(lx, ly); } - #endif + #endif // NEWPANEL bool unified_bed_leveling::g29_parameter_parsing() { bool err_flag = false; @@ -1113,19 +1126,34 @@ } if (parser.seen('P')) { - g29_phase_value = parser.value_int(); - if (!WITHIN(g29_phase_value, 0, 6)) { - SERIAL_PROTOCOLLNPGM("?(P)hase value invalid (0-6).\n"); - err_flag = true; - } + const int pv = parser.value_int(); + #if !HAS_BED_PROBE + if (pv == 1) { + SERIAL_PROTOCOLLNPGM("G29 P1 requires a probe.\n"); + err_flag = true; + } + else + #endif + { + g29_phase_value = pv; + if (!WITHIN(g29_phase_value, 0, 6)) { + SERIAL_PROTOCOLLNPGM("?(P)hase value invalid (0-6).\n"); + err_flag = true; + } + } } if (parser.seen('J')) { - g29_grid_size = parser.has_value() ? parser.value_int() : 0; - if (g29_grid_size && !WITHIN(g29_grid_size, 2, 9)) { - SERIAL_PROTOCOLLNPGM("?Invalid grid size (J) specified (2-9).\n"); + #if HAS_BED_PROBE + g29_grid_size = parser.has_value() ? parser.value_int() : 0; + if (g29_grid_size && !WITHIN(g29_grid_size, 2, 9)) { + SERIAL_PROTOCOLLNPGM("?Invalid grid size (J) specified (2-9).\n"); + err_flag = true; + } + #else + SERIAL_PROTOCOLLNPGM("G29 J action requires a probe.\n"); err_flag = true; - } + #endif } if (g29_x_flag != g29_y_flag) { @@ -1625,128 +1653,66 @@ } } - void unified_bed_leveling::tilt_mesh_based_on_probed_grid(const bool do_ubl_mesh_map) { - constexpr int16_t x_min = max(MIN_PROBE_X, UBL_MESH_MIN_X), - x_max = min(MAX_PROBE_X, UBL_MESH_MAX_X), - y_min = max(MIN_PROBE_Y, UBL_MESH_MIN_Y), - y_max = min(MAX_PROBE_Y, UBL_MESH_MAX_Y); - - 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; - incremental_LSF_reset(&lsf_results); - - bool zig_zag = false; - for (uint8_t ix = 0; ix < g29_grid_size; ix++) { - const float x = float(x_min) + ix * dx; - for (int8_t iy = 0; iy < g29_grid_size; iy++) { - const float y = float(y_min) + dy * (zig_zag ? g29_grid_size - 1 - iy : iy); - float measured_z = probe_pt(LOGICAL_X_POSITION(x), LOGICAL_Y_POSITION(y), parser.seen('E'), g29_verbose_level); // TODO: Needs error handling - #if ENABLED(DEBUG_LEVELING_FEATURE) - if (DEBUGGING(LEVELING)) { - SERIAL_CHAR('('); - SERIAL_PROTOCOL_F(x, 7); - SERIAL_CHAR(','); - SERIAL_PROTOCOL_F(y, 7); - SERIAL_ECHOPGM(") logical: "); - SERIAL_CHAR('('); - SERIAL_PROTOCOL_F(LOGICAL_X_POSITION(x), 7); - SERIAL_CHAR(','); - SERIAL_PROTOCOL_F(LOGICAL_X_POSITION(y), 7); - SERIAL_ECHOPGM(") measured: "); - SERIAL_PROTOCOL_F(measured_z, 7); - SERIAL_ECHOPGM(" correction: "); - SERIAL_PROTOCOL_F(get_z_correction(LOGICAL_X_POSITION(x), LOGICAL_Y_POSITION(y)), 7); - } - #endif + #if HAS_BED_PROBE - measured_z -= get_z_correction(LOGICAL_X_POSITION(x), LOGICAL_Y_POSITION(y)) /* + 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, x, y, measured_z); - } - - zig_zag ^= true; - } - - if (finish_incremental_LSF(&lsf_results)) { - SERIAL_ECHOPGM("Could not complete LSF!"); - return; - } + void unified_bed_leveling::tilt_mesh_based_on_probed_grid(const bool do_ubl_mesh_map) { + constexpr int16_t x_min = max(MIN_PROBE_X, UBL_MESH_MIN_X), + x_max = min(MAX_PROBE_X, UBL_MESH_MAX_X), + y_min = max(MIN_PROBE_Y, UBL_MESH_MIN_Y), + y_max = min(MAX_PROBE_Y, UBL_MESH_MAX_Y); - 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(); - } + const float dx = float(x_max - x_min) / (g29_grid_size - 1.0), + dy = float(y_max - y_min) / (g29_grid_size - 1.0); - vector_3 normal = vector_3(lsf_results.A, lsf_results.B, 1.0000).get_normal(); + struct linear_fit_data lsf_results; + incremental_LSF_reset(&lsf_results); + + bool zig_zag = false; + for (uint8_t ix = 0; ix < g29_grid_size; ix++) { + const float x = float(x_min) + ix * dx; + for (int8_t iy = 0; iy < g29_grid_size; iy++) { + const float y = float(y_min) + dy * (zig_zag ? g29_grid_size - 1 - iy : iy); + float measured_z = probe_pt(LOGICAL_X_POSITION(x), LOGICAL_Y_POSITION(y), parser.seen('E'), g29_verbose_level); // TODO: Needs error handling + #if ENABLED(DEBUG_LEVELING_FEATURE) + if (DEBUGGING(LEVELING)) { + SERIAL_CHAR('('); + SERIAL_PROTOCOL_F(x, 7); + SERIAL_CHAR(','); + SERIAL_PROTOCOL_F(y, 7); + SERIAL_ECHOPGM(") logical: "); + SERIAL_CHAR('('); + SERIAL_PROTOCOL_F(LOGICAL_X_POSITION(x), 7); + SERIAL_CHAR(','); + SERIAL_PROTOCOL_F(LOGICAL_X_POSITION(y), 7); + SERIAL_ECHOPGM(") measured: "); + SERIAL_PROTOCOL_F(measured_z, 7); + SERIAL_ECHOPGM(" correction: "); + SERIAL_PROTOCOL_F(get_z_correction(LOGICAL_X_POSITION(x), LOGICAL_Y_POSITION(y)), 7); + } + #endif - 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("]"); - } + measured_z -= get_z_correction(LOGICAL_X_POSITION(x), LOGICAL_Y_POSITION(y)) /* + zprobe_zoffset */ ; - matrix_3x3 rotation = matrix_3x3::create_look_at(vector_3(lsf_results.A, lsf_results.B, 1)); + #if ENABLED(DEBUG_LEVELING_FEATURE) + if (DEBUGGING(LEVELING)) { + SERIAL_ECHOPGM(" final >>>---> "); + SERIAL_PROTOCOL_F(measured_z, 7); + 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 + incremental_LSF(&lsf_results, x, y, measured_z); + } - 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 + zig_zag ^= true; + } - z_values[i][j] += z_tmp - lsf_results.D; + if (finish_incremental_LSF(&lsf_results)) { + SERIAL_ECHOPGM("Could not complete LSF!"); + return; } - } - #if ENABLED(DEBUG_LEVELING_FEATURE) - if (DEBUGGING(LEVELING)) { - rotation.debug(PSTR("rotation matrix:")); + if (g29_verbose_level > 3) { SERIAL_ECHOPGM("LSF Results A="); SERIAL_PROTOCOL_F(lsf_results.A, 7); SERIAL_ECHOPGM(" B="); @@ -1754,21 +1720,87 @@ SERIAL_ECHOPGM(" D="); SERIAL_PROTOCOL_F(lsf_results.D, 7); SERIAL_EOL(); - safe_delay(55); + } + vector_3 normal = vector_3(lsf_results.A, lsf_results.B, 1.0000).get_normal(); + + 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_ECHOPGM("]\n"); - SERIAL_EOL(); + SERIAL_ECHOLNPGM("]"); } - #endif - if (do_ubl_mesh_map) display_map(g29_map_type); - } + matrix_3x3 rotation = matrix_3x3::create_look_at(vector_3(lsf_results.A, lsf_results.B, 1)); + + 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 - lsf_results.D; + } + } + + #if ENABLED(DEBUG_LEVELING_FEATURE) + if (DEBUGGING(LEVELING)) { + rotation.debug(PSTR("rotation matrix:")); + 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(); + safe_delay(55); + + 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_ECHOPGM("]\n"); + SERIAL_EOL(); + } + #endif + + if (do_ubl_mesh_map) display_map(g29_map_type); + } + + #endif // HAS_BED_PROBE #if ENABLED(UBL_G29_P31) void unified_bed_leveling::smart_fill_wlsf(const float &weight_factor) {