My Marlin configs for Fabrikator Mini and CTC i3 Pro B
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

runout.h 9.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /**
  2. * Marlin 3D Printer Firmware
  3. * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
  4. *
  5. * Based on Sprinter and grbl.
  6. * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. #pragma once
  23. /**
  24. * feature/runout.h - Runout sensor support
  25. */
  26. #include "../sd/cardreader.h"
  27. #include "../module/printcounter.h"
  28. #include "../module/stepper.h"
  29. #include "../gcode/queue.h"
  30. #include "../inc/MarlinConfig.h"
  31. #if ENABLED(EXTENSIBLE_UI)
  32. #include "../lcd/extensible_ui/ui_api.h"
  33. #endif
  34. //#define FILAMENT_RUNOUT_SENSOR_DEBUG
  35. class FilamentSensorBase {
  36. public:
  37. static bool enabled;
  38. protected:
  39. static bool filament_ran_out;
  40. };
  41. template<class RESPONSE_T, class SENSOR_T>
  42. class TFilamentSensor : public FilamentSensorBase {
  43. private:
  44. typedef RESPONSE_T response_t;
  45. typedef SENSOR_T sensor_t;
  46. static response_t response;
  47. static sensor_t sensor;
  48. public:
  49. static void setup() {
  50. sensor.setup();
  51. }
  52. inline static void reset() {
  53. filament_ran_out = false;
  54. response.reset();
  55. }
  56. // The sensor calls this method when filament is present
  57. inline static void filament_present(const uint8_t extruder) {
  58. response.filament_present(extruder);
  59. }
  60. inline static void block_complete(const block_t *b) {
  61. response.block_complete(b);
  62. sensor.block_complete(b);
  63. }
  64. static void run() {
  65. if (enabled && !filament_ran_out && (IS_SD_PRINTING() || print_job_timer.isRunning())) {
  66. response.run();
  67. sensor.run();
  68. if (response.has_runout()) {
  69. filament_ran_out = true;
  70. #if ENABLED(EXTENSIBLE_UI)
  71. UI::onFilamentRunout();
  72. #endif
  73. enqueue_and_echo_commands_P(PSTR(FILAMENT_RUNOUT_SCRIPT));
  74. planner.synchronize();
  75. }
  76. }
  77. }
  78. };
  79. /*************************** FILAMENT PRESENCE SENSORS ***************************/
  80. class FilamentSensorTypeBase {
  81. protected:
  82. static void filament_present(const uint8_t extruder);
  83. public:
  84. static void setup() {
  85. #if ENABLED(FIL_RUNOUT_PULLUP)
  86. #define INIT_RUNOUT_PIN(P) SET_INPUT_PULLUP(P)
  87. #elif ENABLED(FIL_RUNOUT_PULLDOWN)
  88. #define INIT_RUNOUT_PIN(P) SET_INPUT_PULLDOWN(P)
  89. #else
  90. #define INIT_RUNOUT_PIN(P) SET_INPUT(P)
  91. #endif
  92. INIT_RUNOUT_PIN(FIL_RUNOUT_PIN);
  93. #if NUM_RUNOUT_SENSORS > 1
  94. INIT_RUNOUT_PIN(FIL_RUNOUT2_PIN);
  95. #if NUM_RUNOUT_SENSORS > 2
  96. INIT_RUNOUT_PIN(FIL_RUNOUT3_PIN);
  97. #if NUM_RUNOUT_SENSORS > 3
  98. INIT_RUNOUT_PIN(FIL_RUNOUT4_PIN);
  99. #if NUM_RUNOUT_SENSORS > 4
  100. INIT_RUNOUT_PIN(FIL_RUNOUT5_PIN);
  101. #if NUM_RUNOUT_SENSORS > 5
  102. INIT_RUNOUT_PIN(FIL_RUNOUT6_PIN);
  103. #endif
  104. #endif
  105. #endif
  106. #endif
  107. #endif
  108. }
  109. #if FIL_RUNOUT_INVERTING
  110. #define FIL_RUNOUT_INVERT_MASK (_BV(NUM_RUNOUT_SENSORS) - 1)
  111. #else
  112. #define FIL_RUNOUT_INVERT_MASK 0
  113. #endif
  114. // Return a bitmask of all runout sensor states
  115. static uint8_t poll_runout_pins() {
  116. return (
  117. (READ(FIL_RUNOUT_PIN ) ? _BV(0) : 0)
  118. #if NUM_RUNOUT_SENSORS > 1
  119. | (READ(FIL_RUNOUT2_PIN) ? _BV(1) : 0)
  120. #if NUM_RUNOUT_SENSORS > 2
  121. | (READ(FIL_RUNOUT3_PIN) ? _BV(2) : 0)
  122. #if NUM_RUNOUT_SENSORS > 3
  123. | (READ(FIL_RUNOUT4_PIN) ? _BV(3) : 0)
  124. #if NUM_RUNOUT_SENSORS > 4
  125. | (READ(FIL_RUNOUT5_PIN) ? _BV(4) : 0)
  126. #if NUM_RUNOUT_SENSORS > 5
  127. | (READ(FIL_RUNOUT6_PIN) ? _BV(5) : 0)
  128. #endif
  129. #endif
  130. #endif
  131. #endif
  132. #endif
  133. ) ^ FIL_RUNOUT_INVERT_MASK;
  134. }
  135. };
  136. /**
  137. * This sensor is a simple endstop
  138. * switch in the path of the filament. It detects
  139. * filament runout, but not stripouts or jams.
  140. */
  141. class FilamentSensorTypeSwitch : public FilamentSensorTypeBase {
  142. private:
  143. static bool poll_runout_pin(const uint8_t extruder) {
  144. const uint8_t runout_bits = poll_runout_pins();
  145. #if NUM_RUNOUT_SENSORS == 1
  146. return runout_bits; // A single sensor applying to all extruders
  147. #else
  148. #if ENABLED(DUAL_X_CARRIAGE)
  149. if (extruder_duplication_enabled)
  150. return runout_bits; // Any extruder
  151. else
  152. #endif
  153. return TEST(runout_bits, extruder); // Specific extruder
  154. #endif
  155. }
  156. public:
  157. FORCE_INLINE static void block_complete(const block_t *b) {}
  158. FORCE_INLINE static void run() {
  159. if (!poll_runout_pin(active_extruder))
  160. filament_present(active_extruder);
  161. }
  162. };
  163. // This filament sensor uses a magnetic encoder disc and a hall
  164. // effect sensor (or a slitted disc and an optical sensor). The state
  165. // will toggle between 0 and 1 with filament movement. It can detect
  166. // filament runout and stripouts or jams.
  167. class FilamentSensorTypeEncoder : public FilamentSensorTypeBase {
  168. private:
  169. static uint8_t motion_detected, old_state;
  170. static void poll_motion_sensor() {
  171. const uint8_t new_state = poll_runout_pins(),
  172. change = old_state ^ new_state;
  173. old_state = new_state;
  174. #ifdef FILAMENT_RUNOUT_SENSOR_DEBUG
  175. if (change) SERIAL_PROTOCOLLNPAIR("motion detected: ", change);
  176. #endif
  177. motion_detected |= change;
  178. }
  179. public:
  180. static void block_complete(const block_t *b) {
  181. // If the just-executed block caused the sensor wheel
  182. // to turn, reset the runout counter for that extruder.
  183. if (TEST(motion_detected, b->extruder))
  184. filament_present(b->extruder);
  185. // Clear motion triggers for next block
  186. motion_detected = 0;
  187. }
  188. FORCE_INLINE static void run() { poll_motion_sensor(); }
  189. };
  190. /********************************* RESPONSE TYPE *********************************/
  191. #if FILAMENT_RUNOUT_DISTANCE_MM > 0
  192. // The RunoutResponseDelayed will trigger an runout event only after
  193. // RUNOUT_DISTANCE_MM of filament have been fed after a runout condition.
  194. class RunoutResponseDelayed {
  195. private:
  196. static int32_t steps_since_detection[EXTRUDERS];
  197. static float get_mm_since_runout(const uint8_t extruder) {
  198. return (steps_since_detection[extruder] / planner.settings.axis_steps_per_mm[E_AXIS_N(extruder)]);
  199. }
  200. public:
  201. static float runout_distance_mm;
  202. FORCE_INLINE static bool has_runout() {
  203. return get_mm_since_runout(active_extruder) > runout_distance_mm;
  204. }
  205. static inline void filament_present(const uint8_t extruder) {
  206. steps_since_detection[extruder] = 0;
  207. }
  208. static inline void run() {
  209. #ifdef FILAMENT_RUNOUT_SENSOR_DEBUG
  210. static uint16_t r = 0;
  211. if ((r++ % 24000) == 0) {
  212. SERIAL_PROTOCOLPGM("mm since filament detection: ");
  213. LOOP_L_N(i, NUM_RUNOUT_SENSORS) {
  214. if (i > 0) SERIAL_PROTOCOLPGM(", ");
  215. SERIAL_PROTOCOL(get_mm_since_runout(i));
  216. }
  217. SERIAL_EOL();
  218. }
  219. #endif
  220. }
  221. static void reset() {
  222. LOOP_L_N(i, NUM_RUNOUT_SENSORS) steps_since_detection[i] = 0;
  223. }
  224. static inline void block_complete(const block_t *b) {
  225. steps_since_detection[b->extruder] += TEST(b->direction_bits, E_AXIS) ? -b->steps[E_AXIS] : b->steps[E_AXIS];
  226. }
  227. };
  228. #else // !FILAMENT_RUNOUT_DISTANCE_MM
  229. // The RunoutResponseDebounced will trigger an runout event after
  230. // a runout condition is detected FIL_RUNOUT_THRESHOLD times in a row.
  231. class RunoutResponseDebounced {
  232. private:
  233. static constexpr uint8_t FIL_RUNOUT_THRESHOLD = 5;
  234. static uint8_t runout_count;
  235. public:
  236. FORCE_INLINE static bool has_runout() { return runout_count > FIL_RUNOUT_THRESHOLD; }
  237. FORCE_INLINE static void block_complete(const block_t *b) {}
  238. FORCE_INLINE static void filament_present(const uint8_t extruder) { runout_count = 0; UNUSED(extruder); }
  239. FORCE_INLINE static void run() { runout_count++; }
  240. FORCE_INLINE static void reset() { runout_count = 0; }
  241. };
  242. #endif // !FILAMENT_RUNOUT_DISTANCE_MM
  243. /********************************* TEMPLATE SPECIALIZATION *********************************/
  244. typedef TFilamentSensor<
  245. #if FILAMENT_RUNOUT_DISTANCE_MM > 0
  246. #if ENABLED(FILAMENT_MOTION_SENSOR)
  247. RunoutResponseDelayed, FilamentSensorTypeEncoder
  248. #else
  249. RunoutResponseDelayed, FilamentSensorTypeSwitch
  250. #endif
  251. #else
  252. RunoutResponseDebounced, FilamentSensorTypeSwitch
  253. #endif
  254. > FilamentRunoutSensor;
  255. extern FilamentRunoutSensor runout;