From e6cdc438fdcca72f232883d765536f4a8a7a3999 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Fri, 2 Feb 2018 05:14:38 -0600 Subject: [PATCH] Change G26 circle angles To prevent the nozzle from colliding with the printed pattern. --- Marlin/src/gcode/bedlevel/G26.cpp | 105 +++++++++++++----------------- 1 file changed, 45 insertions(+), 60 deletions(-) diff --git a/Marlin/src/gcode/bedlevel/G26.cpp b/Marlin/src/gcode/bedlevel/G26.cpp index 570d3bbac..ce9531009 100644 --- a/Marlin/src/gcode/bedlevel/G26.cpp +++ b/Marlin/src/gcode/bedlevel/G26.cpp @@ -46,11 +46,11 @@ #define PRIME_LENGTH 10.0 #define OOZE_AMOUNT 0.3 -#define SIZE_OF_INTERSECTION_CIRCLES 5 -#define SIZE_OF_CROSSHAIRS 3 +#define INTERSECTION_CIRCLE_RADIUS 5 +#define CROSSHAIRS_SIZE 3 -#if SIZE_OF_CROSSHAIRS >= SIZE_OF_INTERSECTION_CIRCLES - #error "SIZE_OF_CROSSHAIRS must be less than SIZE_OF_INTERSECTION_CIRCLES." +#if CROSSHAIRS_SIZE >= INTERSECTION_CIRCLE_RADIUS + #error "CROSSHAIRS_SIZE must be less than INTERSECTION_CIRCLE_RADIUS." #endif #define G26_OK false @@ -305,7 +305,7 @@ void print_line_from_here_to_there(const float &sx, const float &sy, const float // If the end point of the line is closer to the nozzle, flip the direction, // moving from the end to the start. On very small lines the optimization isn't worth it. - if (dist_end < dist_start && (SIZE_OF_INTERSECTION_CIRCLES) < FABS(line_length)) + if (dist_end < dist_start && (INTERSECTION_CIRCLE_RADIUS) < FABS(line_length)) return print_line_from_here_to_there(ex, ey, ez, sx, sy, sz); // Decide whether to retract & bump @@ -345,8 +345,8 @@ inline bool look_for_lines_to_connect() { // We found two circles that need a horizontal line to connect them // Print it! // - sx = _GET_MESH_X( i ) + (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // right edge - ex = _GET_MESH_X(i + 1) - (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // left edge + sx = _GET_MESH_X( i ) + (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)); // right edge + ex = _GET_MESH_X(i + 1) - (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)); // left edge sx = constrain(sx, X_MIN_POS + 1, X_MAX_POS - 1); sy = ey = constrain(_GET_MESH_Y(j), Y_MIN_POS + 1, Y_MAX_POS - 1); @@ -378,8 +378,8 @@ inline bool look_for_lines_to_connect() { // We found two circles that need a vertical line to connect them // Print it! // - sy = _GET_MESH_Y( j ) + (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // top edge - ey = _GET_MESH_Y(j + 1) - (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // bottom edge + sy = _GET_MESH_Y( j ) + (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)); // top edge + ey = _GET_MESH_Y(j + 1) - (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)); // bottom edge sx = ex = constrain(_GET_MESH_X(i), X_MIN_POS + 1, X_MAX_POS - 1); sy = constrain(sy, Y_MIN_POS + 1, Y_MAX_POS - 1); @@ -551,9 +551,6 @@ float valid_trig_angle(float d) { */ void GcodeSuite::G26() { SERIAL_ECHOLNPGM("G26 command started. Waiting for heater(s)."); - float tmp, start_angle, end_angle; - int i, xi, yi; - mesh_index_pair location; // Don't allow Mesh Validation without homing first, // or if the parameter parsing did not go OK, abort @@ -726,17 +723,18 @@ void GcodeSuite::G26() { //debug_current_and_destination(PSTR("Starting G26 Mesh Validation Pattern.")); /** - * Declare and generate a sin() & cos() table to be used during the circle drawing. This will lighten - * the CPU load and make the arc drawing faster and more smooth + * Pre-generate radius offset values at 30 degree intervals to reduce CPU load. + * All angles are offset by 15 degrees to allow for a smaller table. */ - float sin_table[360 / 30 + 1], cos_table[360 / 30 + 1]; - for (i = 0; i <= 360 / 30; i++) { - cos_table[i] = SIZE_OF_INTERSECTION_CIRCLES * cos(RADIANS(valid_trig_angle(i * 30.0))); - sin_table[i] = SIZE_OF_INTERSECTION_CIRCLES * sin(RADIANS(valid_trig_angle(i * 30.0))); - } + #define A_CNT ((360 / 30) / 2) + #define _COS(A) (trig_table[((N + A_CNT * 8) % A_CNT)] * (A >= A_CNT ? -1 : 1)) + #define _SIN(A) (-_COS((A + A_CNT / 2) % (A_CNT * 2))) + float trig_table[A_CNT]; + for (uint8_t i = 0; i < A_CNT; i++) + trig_table[i] = INTERSECTION_CIRCLE_RADIUS * cos(RADIANS(i * 30 + 15)); do { - location = g26_continue_with_closest + const mesh_index_pair location = g26_continue_with_closest ? find_closest_circle_to_print(current_position[X_AXIS], current_position[Y_AXIS]) : find_closest_circle_to_print(g26_x_pos, g26_y_pos); // Find the closest Mesh Intersection to where we are now. @@ -745,12 +743,29 @@ void GcodeSuite::G26() { circle_y = _GET_MESH_Y(location.y_index); // If this mesh location is outside the printable_radius, skip it. - if (!position_is_reachable(circle_x, circle_y)) continue; - xi = location.x_index; // Just to shrink the next few lines and make them easier to understand - yi = location.y_index; - + // Determine where to start and end the circle, + // which is always drawn counter-clockwise. + const uint8_t xi = location.x_index, yi = location.y_index; + const bool f = yi == 0, r = xi == GRID_MAX_POINTS_X - 1, b = yi == GRID_MAX_POINTS_Y - 1; + int8_t start_ind = -2, end_ind = 10; // Assume a full circle (from 4:30 to 4:30) + if (xi == 0) { // Left edge? Just right half. + start_ind = f ? 0 : -3; // 05:30 (02:30 for front-left) + end_ind = b ? -1 : 2; // 12:30 (03:30 for back-left) + } + else if (r) { // Right edge? Just left half. + start_ind = f ? 5 : 3; // 11:30 (09:30 for front-right) + end_ind = b ? 6 : 8; // 06:30 (08:30 for back-right) + } + else if (f) { // Front edge? Just back half. + start_ind = 0; // 02:30 + end_ind = 5; // 09:30 + } + else if (b) { // Back edge? Just front half. + start_ind = 6; // 08:30 + end_ind = 11; // 03:30 + } if (g26_debug_flag) { SERIAL_ECHOPAIR(" Doing circle at: (xi=", xi); SERIAL_ECHOPAIR(", yi=", yi); @@ -758,47 +773,17 @@ void GcodeSuite::G26() { SERIAL_EOL(); } - start_angle = 0.0; // assume it is going to be a full circle - end_angle = 360.0; - if (xi == 0) { // Check for bottom edge - start_angle = -90.0; - end_angle = 90.0; - if (yi == 0) // it is an edge, check for the two left corners - start_angle = 0.0; - else if (yi == GRID_MAX_POINTS_Y - 1) - end_angle = 0.0; - } - else if (xi == GRID_MAX_POINTS_X - 1) { // Check for top edge - start_angle = 90.0; - end_angle = 270.0; - if (yi == 0) // it is an edge, check for the two right corners - end_angle = 180.0; - else if (yi == GRID_MAX_POINTS_Y - 1) - start_angle = 180.0; - } - else if (yi == 0) { - start_angle = 0.0; // only do the top side of the cirlce - end_angle = 180.0; - } - else if (yi == GRID_MAX_POINTS_Y - 1) { - start_angle = 180.0; // only do the bottom side of the cirlce - end_angle = 360.0; - } - - for (tmp = start_angle; tmp < end_angle - 0.1; tmp += 30.0) { + for (int8_t ind = start_ind; ind < end_ind; ind++) { #if ENABLED(NEWPANEL) - if (user_canceled()) goto LEAVE; // Check if the user wants to stop the Mesh Validation + if (user_canceled()) goto LEAVE; // Check if the user wants to stop the Mesh Validation #endif - int tmp_div_30 = tmp / 30.0; - if (tmp_div_30 < 0) tmp_div_30 += 360 / 30; - if (tmp_div_30 > 11) tmp_div_30 -= 360 / 30; + float rx = circle_x + _COS(ind), // For speed, these are now a lookup table entry + ry = circle_y + _SIN(ind), + xe = circle_x + _COS(ind + 1), + ye = circle_y + _SIN(ind + 1); - float rx = circle_x + cos_table[tmp_div_30], // for speed, these are now a lookup table entry - ry = circle_y + sin_table[tmp_div_30], - xe = circle_x + cos_table[tmp_div_30 + 1], - ye = circle_y + sin_table[tmp_div_30 + 1]; #if IS_KINEMATIC // Check to make sure this segment is entirely on the bed, skip if not. if (!position_is_reachable(rx, ry) || !position_is_reachable(xe, ye)) continue;