Implements a nozzle parking command (G27)
This commit is contained in:
		| @@ -787,6 +787,30 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l | ||||
| #define PREHEAT_2_TEMP_BED    110 | ||||
| #define PREHEAT_2_FAN_SPEED     0 // Value from 0 to 255 | ||||
|  | ||||
| // | ||||
| // Nozzle Park -- EXPERIMENTAL | ||||
| // | ||||
| // When enabled allows the user to define a special XYZ position, inside the | ||||
| // machine's topology, to park the nozzle when idle or when receiving the G27 | ||||
| // command. | ||||
| // | ||||
| // The "P" paramenter controls what is the action applied to the Z axis: | ||||
| //    P0: (Default) If current Z-pos is lower than Z-park then the nozzle will | ||||
| //        be raised to reach Z-park height. | ||||
| // | ||||
| //    P1: No matter the current Z-pos, the nozzle will be raised/lowered to | ||||
| //        reach Z-park height. | ||||
| // | ||||
| //    P2: The nozzle height will be raised by Z-park amount but never going over | ||||
| //        the machine's limit of Z_MAX_POS. | ||||
| // | ||||
| //#define NOZZLE_PARK_FEATURE | ||||
|  | ||||
| #if ENABLED(NOZZLE_PARK_FEATURE) | ||||
|   // Specify a park position as { X, Y, Z } | ||||
|   #define NOZZLE_PARK_POINT { (X_MIN_POS + 10), (Y_MAX_POS - 10), 20 } | ||||
| #endif | ||||
|  | ||||
| // | ||||
| // Clean Nozzle Feature -- EXPERIMENTAL | ||||
| // | ||||
|   | ||||
| @@ -2736,9 +2736,12 @@ inline void gcode_G4() { | ||||
|  | ||||
| #endif //FWRETRACT | ||||
|  | ||||
| #if ENABLED(NOZZLE_CLEAN_FEATURE) && ENABLED(AUTO_BED_LEVELING_FEATURE) | ||||
| #if ENABLED(NOZZLE_CLEAN_FEATURE) && HAS_BED_PROBE | ||||
|   #include "nozzle.h" | ||||
|  | ||||
|   /** | ||||
|    * G12: Clean the nozzle | ||||
|    */ | ||||
|   inline void gcode_G12() { | ||||
|     // Don't allow nozzle cleaning without homing first | ||||
|     if (axis_unhomed_error(true, true, true)) { return; } | ||||
| @@ -2795,6 +2798,20 @@ inline void gcode_G4() { | ||||
|  | ||||
| #endif // QUICK_HOME | ||||
|  | ||||
| #if ENABLED(NOZZLE_PARK_FEATURE) | ||||
|   #include "nozzle.h" | ||||
|  | ||||
|   /** | ||||
|    * G27: Park the nozzle | ||||
|    */ | ||||
|   inline void gcode_G27() { | ||||
|     // Don't allow nozzle parking without homing first | ||||
|     if (axis_unhomed_error(true, true, true)) { return; } | ||||
|     uint8_t const z_action = code_seen('P') ? code_value_ushort() : 0; | ||||
|     Nozzle::park(z_action); | ||||
|   } | ||||
| #endif // NOZZLE_PARK_FEATURE | ||||
|  | ||||
| /** | ||||
|  * G28: Home all axes according to settings | ||||
|  * | ||||
| @@ -6884,7 +6901,7 @@ void process_next_command() { | ||||
|  | ||||
|       #if ENABLED(NOZZLE_CLEAN_FEATURE) && HAS_BED_PROBE | ||||
|         case 12: | ||||
|           gcode_G12(); // G12: Clean Nozzle | ||||
|           gcode_G12(); // G12: Nozzle Clean | ||||
|           break; | ||||
|       #endif // NOZZLE_CLEAN_FEATURE | ||||
|  | ||||
| @@ -6898,6 +6915,12 @@ void process_next_command() { | ||||
|           break; | ||||
|       #endif // INCH_MODE_SUPPORT | ||||
|  | ||||
|       #if ENABLED(NOZZLE_PARK_FEATURE) | ||||
|         case 27: // G27: Nozzle Park | ||||
|           gcode_G27(); | ||||
|           break; | ||||
|       #endif // NOZZLE_PARK_FEATURE | ||||
|  | ||||
|       case 28: // G28: Home all axes, one at a time | ||||
|         gcode_G28(); | ||||
|         break; | ||||
|   | ||||
							
								
								
									
										189
									
								
								Marlin/nozzle.h
									
									
									
									
									
								
							
							
						
						
									
										189
									
								
								Marlin/nozzle.h
									
									
									
									
									
								
							| @@ -30,8 +30,6 @@ | ||||
|  * @brief Nozzle class | ||||
|  * | ||||
|  * @todo: Do not ignore the end.z value and allow XYZ movements | ||||
|  * @todo: Currently this feature needs HAS_BED_PROBE to be active | ||||
|  *  due to the do_blocking_move_to*() functions. | ||||
|  */ | ||||
| class Nozzle { | ||||
|   private: | ||||
| @@ -43,34 +41,40 @@ class Nozzle { | ||||
|      * @param end point_t defining the ending point | ||||
|      * @param strokes number of strokes to execute | ||||
|      */ | ||||
|     static void stroke(point_t const &start, point_t const &end, uint8_t const &strokes) | ||||
|     __attribute__ ((optimize ("Os"))) { | ||||
|     static void stroke( | ||||
|       __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_PARK) | ||||
|         // 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 | ||||
|         #if ENABLED(NOZZLE_CLEAN_PARK) | ||||
|           // 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_PARK | ||||
|  | ||||
|       // 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); | ||||
|         // Move to the starting point | ||||
|         do_blocking_move_to_xy(start.x, start.y); | ||||
|       } | ||||
|         do_blocking_move_to_z(start.z); | ||||
|  | ||||
|       #if ENABLED(NOZZLE_CLEAN_PARK) | ||||
|         // Move the nozzle to the initial point | ||||
|         do_blocking_move_to_z(initial.z); | ||||
|         do_blocking_move_to_xy(initial.x, initial.y); | ||||
|       #endif | ||||
|         // 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_PARK) | ||||
|           // 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_PARK | ||||
|  | ||||
|       #endif // NOZZLE_CLEAN_FEATURE | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -82,47 +86,53 @@ class Nozzle { | ||||
|      * @param strokes number of strokes to execute | ||||
|      * @param objects number of objects to create | ||||
|      */ | ||||
|     static void zigzag(point_t const &start, | ||||
|       point_t const &end, uint8_t const &strokes, uint8_t const &objects) | ||||
|     __attribute__ ((optimize ("Os"))) { | ||||
|       float A = fabs(end.y - start.y); // [twice the] Amplitude | ||||
|       float P = fabs(end.x - start.x) / (objects << 1); // Period | ||||
|     static void 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 | ||||
|     ) __attribute__((optimize ("Os"))) { | ||||
|       #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; | ||||
|         // Don't allow impossible triangles | ||||
|         if (A <= 0.0f || P <= 0.0f ) return; | ||||
|  | ||||
|       #if ENABLED(NOZZLE_CLEAN_PARK) | ||||
|         // 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 | ||||
|         #if ENABLED(NOZZLE_CLEAN_PARK) | ||||
|           // 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_PARK | ||||
|  | ||||
|       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)); | ||||
|         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); | ||||
|             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); | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         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)); | ||||
|         #if ENABLED(NOZZLE_CLEAN_PARK) | ||||
|           // 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_PARK | ||||
|  | ||||
|           do_blocking_move_to_xy(x, y); | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       #if ENABLED(NOZZLE_CLEAN_PARK) | ||||
|         // Move the nozzle to the initial point | ||||
|         do_blocking_move_to_z(initial.z); | ||||
|         do_blocking_move_to_xy(initial.x, initial.y); | ||||
|       #endif | ||||
|       #endif // NOZZLE_CLEAN_FEATURE | ||||
|     } | ||||
|  | ||||
|   public: | ||||
| @@ -133,21 +143,52 @@ class Nozzle { | ||||
|      * @param pattern one of the available patterns | ||||
|      * @param argument depends on the cleaning pattern | ||||
|      */ | ||||
|     static void clean(uint8_t const &pattern, | ||||
|       uint8_t const &strokes, uint8_t const &objects = 0) | ||||
|     __attribute__ ((optimize ("Os"))) { | ||||
|       switch (pattern) { | ||||
|         case 1: | ||||
|           Nozzle::zigzag( | ||||
|             NOZZLE_CLEAN_START_PT, | ||||
|             NOZZLE_CLEAN_END_PT, strokes, objects); | ||||
|           break; | ||||
|     static void clean( | ||||
|       __attribute__((unused)) uint8_t const &pattern, | ||||
|       __attribute__((unused)) uint8_t const &strokes, | ||||
|       __attribute__((unused)) uint8_t const &objects = 0 | ||||
|     ) __attribute__((optimize ("Os"))) { | ||||
|       #if ENABLED(NOZZLE_CLEAN_FEATURE) | ||||
|         switch (pattern) { | ||||
|           case 1: | ||||
|             Nozzle::zigzag( | ||||
|               NOZZLE_CLEAN_START_PT, | ||||
|               NOZZLE_CLEAN_END_PT, strokes, objects); | ||||
|             break; | ||||
|  | ||||
|         default: | ||||
|           Nozzle::stroke( | ||||
|             NOZZLE_CLEAN_START_PT, | ||||
|             NOZZLE_CLEAN_END_PT, strokes); | ||||
|       } | ||||
|           default: | ||||
|             Nozzle::stroke( | ||||
|               NOZZLE_CLEAN_START_PT, | ||||
|               NOZZLE_CLEAN_END_PT, strokes); | ||||
|         } | ||||
|       #endif // NOZZLE_CLEAN_FEATURE | ||||
|     } | ||||
|  | ||||
|     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 | ||||
|     } | ||||
| }; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user