diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index d7d815fe97..ce773728e2 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -96,7 +96,7 @@ // // Marlin now allow you to have a vendor boot image to be displayed on machine // start. When SHOW_CUSTOM_BOOTSCREEN is defined Marlin will first show your -// custom boot image and them the default Marlin boot image is shown. +// custom boot image and then the default Marlin boot image is shown. // // We suggest for you to take advantage of this new feature and keep the Marlin // boot image unmodified. For an example have a look at the bq Hephestos 2 @@ -1000,6 +1000,9 @@ // |________|_________|_________| // T1 T2 T3 // +// P2: This starts a circular pattern with circle with middle in +// NOZZLE_CLEAN_CIRCLE_MIDDLE radius of R and stroke count of S. +// Before starting the circle nozzle goes to NOZZLE_CLEAN_START_POINT. // // Caveats: End point Z should use the same value as Start point Z. // @@ -1011,7 +1014,7 @@ #if ENABLED(NOZZLE_CLEAN_FEATURE) // Default number of pattern repetitions #define NOZZLE_CLEAN_STROKES 12 - + // Default number of triangles #define NOZZLE_CLEAN_TRIANGLES 3 @@ -1019,6 +1022,13 @@ #define NOZZLE_CLEAN_START_POINT { 30, 30, (Z_MIN_POS + 1)} #define NOZZLE_CLEAN_END_POINT {100, 60, (Z_MIN_POS + 1)} + // Circular pattern radius + #define NOZZLE_CLEAN_CIRCLE_RADIUS 6.5 + // Circular pattern circle fragments number + #define NOZZLE_CLEAN_CIRCLE_FN 10 + // Middle point of circle + #define NOZZLE_CLEAN_CIRCLE_MIDDLE NOZZLE_CLEAN_START_POINT + // Moves the nozzle to the initial position #define NOZZLE_CLEAN_GOBACK #endif diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 2d1ef53f04..eb96e892e6 100755 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -3164,8 +3164,9 @@ inline void gcode_G4() { const uint8_t pattern = code_seen('P') ? code_value_ushort() : 0, strokes = code_seen('S') ? code_value_ushort() : NOZZLE_CLEAN_STROKES, objects = code_seen('T') ? code_value_ushort() : NOZZLE_CLEAN_TRIANGLES; + const float radius = code_seen('R') ? code_value_float() : NOZZLE_CLEAN_CIRCLE_RADIUS; - Nozzle::clean(pattern, strokes, objects); + Nozzle::clean(pattern, strokes, radius, objects); } #endif diff --git a/Marlin/nozzle.cpp b/Marlin/nozzle.cpp new file mode 100644 index 0000000000..f890cca935 --- /dev/null +++ b/Marlin/nozzle.cpp @@ -0,0 +1,236 @@ +#include "nozzle.h" + +#include "Marlin.h" +#include "point_t.h" + +/** + * @brief Stroke clean pattern + * @details Wipes the nozzle back and forth in a linear movement + * + * @param start point_t defining the starting point + * @param end point_t defining the ending point + * @param strokes number of strokes to execute + */ +void Nozzle::stroke( + __attribute__((unused)) point_t const &start, + __attribute__((unused)) point_t const &end, + __attribute__((unused)) uint8_t const &strokes +) { + #if ENABLED(NOZZLE_CLEAN_FEATURE) + + #if ENABLED(NOZZLE_CLEAN_GOBACK) + // Store the current coords + point_t const initial = { + current_position[X_AXIS], + current_position[Y_AXIS], + current_position[Z_AXIS], + current_position[E_AXIS] + }; + #endif // NOZZLE_CLEAN_GOBACK + + // Move to the starting point + do_blocking_move_to_xy(start.x, start.y); + do_blocking_move_to_z(start.z); + + // Start the stroke pattern + for (uint8_t i = 0; i < (strokes >>1); i++) { + do_blocking_move_to_xy(end.x, end.y); + do_blocking_move_to_xy(start.x, start.y); + } + + #if ENABLED(NOZZLE_CLEAN_GOBACK) + // Move the nozzle to the initial point + do_blocking_move_to(initial.x, initial.y, initial.z); + #endif // NOZZLE_CLEAN_GOBACK + + #endif // NOZZLE_CLEAN_FEATURE +} + +/** + * @brief Zig-zag clean pattern + * @details Apply a zig-zag cleanning pattern + * + * @param start point_t defining the starting point + * @param end point_t defining the ending point + * @param strokes number of strokes to execute + * @param objects number of objects to create + */ +void Nozzle::zigzag( + __attribute__((unused)) point_t const &start, + __attribute__((unused)) point_t const &end, + __attribute__((unused)) uint8_t const &strokes, + __attribute__((unused)) uint8_t const &objects +) { + #if ENABLED(NOZZLE_CLEAN_FEATURE) + float A = fabs(end.y - start.y); // [twice the] Amplitude + float P = fabs(end.x - start.x) / (objects << 1); // Period + + // Don't allow impossible triangles + if (A <= 0.0f || P <= 0.0f ) return; + + #if ENABLED(NOZZLE_CLEAN_GOBACK) + // Store the current coords + point_t const initial = { + current_position[X_AXIS], + current_position[Y_AXIS], + current_position[Z_AXIS], + current_position[E_AXIS] + }; + #endif // NOZZLE_CLEAN_GOBACK + + for (uint8_t j = 0; j < strokes; j++) { + for (uint8_t i = 0; i < (objects << 1); i++) { + float const x = start.x + i * P; + float const y = start.y + (A/P) * (P - fabs(fmod((i*P), (2*P)) - P)); + + do_blocking_move_to_xy(x, y); + if (i == 0) do_blocking_move_to_z(start.z); + } + + for (int i = (objects << 1); i > -1; i--) { + float const x = start.x + i * P; + float const y = start.y + (A/P) * (P - fabs(fmod((i*P), (2*P)) - P)); + + do_blocking_move_to_xy(x, y); + } + } + + #if ENABLED(NOZZLE_CLEAN_GOBACK) + // Move the nozzle to the initial point + do_blocking_move_to_z(initial.z); + do_blocking_move_to_xy(initial.x, initial.y); + #endif // NOZZLE_CLEAN_GOBACK + + #endif // NOZZLE_CLEAN_FEATURE +} + + +/** + * @brief Circular clean pattern + * @details Apply a circular cleaning pattern + * + * @param start point_t defining the middle of circle + * @param strokes number of strokes to execute + * @param radius radius of circle + */ +void Nozzle::circle( + __attribute__((unused)) point_t const &start, + __attribute__((unused)) point_t const &middle, + __attribute__((unused)) uint8_t const &strokes, + __attribute__((unused)) float const &radius +) { + #if ENABLED(NOZZLE_CLEAN_FEATURE) + if (strokes == 0) return; + + #if ENABLED(NOZZLE_CLEAN_GOBACK) + // Store the current coords + point_t const initial = { + current_position[X_AXIS], + current_position[Y_AXIS], + current_position[Z_AXIS], + current_position[E_AXIS] + }; + #endif // NOZZLE_CLEAN_GOBACK + + if (start.z <= current_position[Z_AXIS]) { + // Order of movement is pretty darn important here + do_blocking_move_to_xy(start.x, start.y); + do_blocking_move_to_z(start.z); + } else { + do_blocking_move_to_z(start.z); + do_blocking_move_to_xy(start.x, start.y); + } + + float x, y; + for (uint8_t s = 0; s < strokes; s++) { + for (uint8_t i = 0; i < NOZZLE_CLEAN_CIRCLE_FN; i++) { + x = middle.x + sin((M_2_PI / NOZZLE_CLEAN_CIRCLE_FN) * i) * radius; + y = middle.y + cos((M_2_PI / NOZZLE_CLEAN_CIRCLE_FN) * i) * radius; + + do_blocking_move_to_xy(x, y); + } + } + + // Let's be safe + do_blocking_move_to_xy(start.x, start.y); + + #if ENABLED(NOZZLE_CLEAN_GOBACK) + // Move the nozzle to the initial point + if (start.z <= initial.z) { + // As above order is important + do_blocking_move_to_z(initial.z); + do_blocking_move_to_xy(initial.x, initial.y); + } else { + do_blocking_move_to_xy(initial.x, initial.y); + do_blocking_move_to_z(initial.z); + } + #endif // NOZZLE_CLEAN_GOBACK + + #endif // NOZZLE_CLEAN_FEATURE +} + +/** + * @brief Clean the nozzle + * @details Starts the selected clean procedure pattern + * + * @param pattern one of the available patterns + * @param argument depends on the cleaning pattern + */ +void Nozzle::clean( + __attribute__((unused)) uint8_t const &pattern, + __attribute__((unused)) uint8_t const &strokes, + __attribute__((unused)) float const &radius, + __attribute__((unused)) uint8_t const &objects +) { + #if ENABLED(NOZZLE_CLEAN_FEATURE) + #if ENABLED(DELTA) + if (current_position[Z_AXIS] > delta_clip_start_height) + do_blocking_move_to_z(delta_clip_start_height); + #endif + switch (pattern) { + case 1: + Nozzle::zigzag( + NOZZLE_CLEAN_START_POINT, + NOZZLE_CLEAN_END_POINT, strokes, objects); + break; + + case 2: + Nozzle::circle( + NOZZLE_CLEAN_START_POINT, + NOZZLE_CLEAN_CIRCLE_MIDDLE, strokes, radius); + break; + + default: + Nozzle::stroke( + NOZZLE_CLEAN_START_POINT, + NOZZLE_CLEAN_END_POINT, strokes); + } + #endif // NOZZLE_CLEAN_FEATURE +} + +void Nozzle::park( + __attribute__((unused)) uint8_t const &z_action +) { + #if ENABLED(NOZZLE_PARK_FEATURE) + float const z = current_position[Z_AXIS]; + point_t const park = NOZZLE_PARK_POINT; + + switch(z_action) { + case 1: // force Z-park height + do_blocking_move_to_z(park.z); + break; + + case 2: // Raise by Z-park height + do_blocking_move_to_z( + (z + park.z > Z_MAX_POS) ? Z_MAX_POS : z + park.z); + break; + + default: // Raise to Z-park height if lower + if (current_position[Z_AXIS] < park.z) + do_blocking_move_to_z(park.z); + } + + do_blocking_move_to_xy(park.x, park.y); + + #endif // NOZZLE_PARK_FEATURE +} diff --git a/Marlin/nozzle.h b/Marlin/nozzle.h index 14423adfbd..f98bc40dba 100644 --- a/Marlin/nozzle.h +++ b/Marlin/nozzle.h @@ -53,40 +53,11 @@ class Nozzle { __attribute__((unused)) point_t const &start, __attribute__((unused)) point_t const &end, __attribute__((unused)) uint8_t const &strokes - ) __attribute__((optimize ("Os"))) { - #if ENABLED(NOZZLE_CLEAN_FEATURE) - - #if ENABLED(NOZZLE_CLEAN_GOBACK) - // Store the current coords - point_t const initial = { - current_position[X_AXIS], - current_position[Y_AXIS], - current_position[Z_AXIS], - current_position[E_AXIS] - }; - #endif // NOZZLE_CLEAN_GOBACK - - // Move to the starting point - do_blocking_move_to_xy(start.x, start.y); - do_blocking_move_to_z(start.z); - - // Start the stroke pattern - for (uint8_t i = 0; i < (strokes >>1); i++) { - do_blocking_move_to_xy(end.x, end.y); - do_blocking_move_to_xy(start.x, start.y); - } - - #if ENABLED(NOZZLE_CLEAN_GOBACK) - // Move the nozzle to the initial point - do_blocking_move_to(initial.x, initial.y, initial.z); - #endif // NOZZLE_CLEAN_GOBACK - - #endif // NOZZLE_CLEAN_FEATURE - } + ) __attribute__((optimize ("Os"))); /** * @brief Zig-zag clean pattern - * @details Apply a zig-zag cleanning pattern + * @details Apply a zig-zag cleaning pattern * * @param start point_t defining the starting point * @param end point_t defining the ending point @@ -98,49 +69,22 @@ class Nozzle { __attribute__((unused)) point_t const &end, __attribute__((unused)) uint8_t const &strokes, __attribute__((unused)) uint8_t const &objects - ) __attribute__((optimize ("Os"))) { - #if ENABLED(NOZZLE_CLEAN_FEATURE) - float A = nozzle_clean_horizontal ? nozzle_clean_height : nozzle_clean_length; // [twice the] Amplitude - float P = ( nozzle_clean_horizontal ? nozzle_clean_length : nozzle_clean_height ) / (objects << 1); // Period + ) __attribute__((optimize ("Os"))); - // Don't allow impossible triangles - if (A <= 0.0f || P <= 0.0f ) return; - - #if ENABLED(NOZZLE_CLEAN_GOBACK) - // Store the current coords - point_t const initial = { - current_position[X_AXIS], - current_position[Y_AXIS], - current_position[Z_AXIS], - current_position[E_AXIS] - }; - #endif // NOZZLE_CLEAN_GOBACK - - for (uint8_t j = 0; j < strokes; j++) { - for (uint8_t i = 0; i < (objects << 1); i++) { - float const x = start.x + ( nozzle_clean_horizontal ? i * P : (A/P) * (P - fabs(fmod((i*P), (2*P)) - P)) ); - float const y = start.y + (!nozzle_clean_horizontal ? i * P : (A/P) * (P - fabs(fmod((i*P), (2*P)) - P)) ); - - do_blocking_move_to_xy(x, y); - if (i == 0) do_blocking_move_to_z(start.z); - } - - for (int i = (objects << 1); i > -1; i--) { - float const x = start.x + ( nozzle_clean_horizontal ? i * P : (A/P) * (P - fabs(fmod((i*P), (2*P)) - P)) ); - float const y = start.y + (!nozzle_clean_horizontal ? i * P : (A/P) * (P - fabs(fmod((i*P), (2*P)) - P)) ); - - do_blocking_move_to_xy(x, y); - } - } - - #if ENABLED(NOZZLE_CLEAN_GOBACK) - // Move the nozzle to the initial point - do_blocking_move_to_z(initial.z); - do_blocking_move_to_xy(initial.x, initial.y); - #endif // NOZZLE_CLEAN_GOBACK - - #endif // NOZZLE_CLEAN_FEATURE - } + /** + * @brief Circular clean pattern + * @details Apply a circular cleaning pattern + * + * @param start point_t defining the middle of circle + * @param strokes number of strokes to execute + * @param radius radius of circle + */ + static void circle( + __attribute__((unused)) point_t const &start, + __attribute__((unused)) point_t const &middle, + __attribute__((unused)) uint8_t const &strokes, + __attribute__((unused)) float const &radius + ) __attribute__((optimize ("Os"))); public: /** @@ -153,54 +97,13 @@ class Nozzle { static void clean( __attribute__((unused)) uint8_t const &pattern, __attribute__((unused)) uint8_t const &strokes, + __attribute__((unused)) float const &radius, __attribute__((unused)) uint8_t const &objects = 0 - ) __attribute__((optimize ("Os"))) { - #if ENABLED(NOZZLE_CLEAN_FEATURE) - #if ENABLED(DELTA) - if (current_position[Z_AXIS] > delta_clip_start_height) - do_blocking_move_to_z(delta_clip_start_height); - #endif - switch (pattern) { - case 1: - Nozzle::zigzag( - NOZZLE_CLEAN_START_POINT, - NOZZLE_CLEAN_END_POINT, strokes, objects); - break; - - default: - Nozzle::stroke( - NOZZLE_CLEAN_START_POINT, - NOZZLE_CLEAN_END_POINT, strokes); - } - #endif // NOZZLE_CLEAN_FEATURE - } + ) __attribute__((optimize ("Os"))); static void park( __attribute__((unused)) uint8_t const &z_action - ) __attribute__((optimize ("Os"))) { - #if ENABLED(NOZZLE_PARK_FEATURE) - float const z = current_position[Z_AXIS]; - point_t const park = NOZZLE_PARK_POINT; - - switch(z_action) { - case 1: // force Z-park height - do_blocking_move_to_z(park.z); - break; - - case 2: // Raise by Z-park height - do_blocking_move_to_z( - (z + park.z > Z_MAX_POS) ? Z_MAX_POS : z + park.z); - break; - - default: // Raise to Z-park height if lower - if (current_position[Z_AXIS] < park.z) - do_blocking_move_to_z(park.z); - } - - do_blocking_move_to_xy(park.x, park.y); - - #endif // NOZZLE_PARK_FEATURE - } + ) __attribute__((optimize ("Os"))); }; #endif