diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 5effb31883..dc042ff1cb 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -2037,8 +2037,11 @@ //#define FILAMENT_MOTION_SENSOR #if ENABLED(FILAMENT_MOTION_SENSOR) - //#define FILAMENT_SWITCH_AND_MOTION + //#define FILAMENT_SWITCH_AND_MOTION // Define separate pins below to sense motion #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + + #define FILAMENT_MOTION_DISTANCE_MM 3.0 // (mm) Missing distance required to trigger runout + #define NUM_MOTION_SENSORS 1 // Number of sensors, up to one per extruder. Define a FIL_MOTION#_PIN for each. //#define FIL_MOTION1_PIN -1 @@ -2074,7 +2077,7 @@ //#define FIL_MOTION8_STATE LOW //#define FIL_MOTION8_PULLUP //#define FIL_MOTION8_PULLDOWN - #endif + #endif // FILAMENT_SWITCH_AND_MOTION #endif // FILAMENT_MOTION_SENSOR #endif // FILAMENT_RUNOUT_DISTANCE_MM #endif // FILAMENT_RUNOUT_SENSOR diff --git a/Marlin/src/feature/runout.cpp b/Marlin/src/feature/runout.cpp index cb7c6279bc..147f38ef09 100644 --- a/Marlin/src/feature/runout.cpp +++ b/Marlin/src/feature/runout.cpp @@ -33,7 +33,7 @@ FilamentMonitor runout; bool FilamentMonitorBase::enabled = true, - FilamentMonitorBase::filament_ran_out; // = false + FilamentMonitorBase::filament_ran_out; // = false #if ENABLED(HOST_ACTION_COMMANDS) bool FilamentMonitorBase::host_handling; // = false @@ -51,6 +51,11 @@ bool FilamentMonitorBase::enabled = true, #if ENABLED(FILAMENT_MOTION_SENSOR) uint8_t FilamentSensorEncoder::motion_detected; #endif + + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + bool RunoutResponseDelayed::ignore_motion = false; + constexpr float RunoutResponseDelayed::motion_distance_mm; + #endif #else int8_t RunoutResponseDebounced::runout_count[NUM_RUNOUT_SENSORS]; // = 0 #endif @@ -72,6 +77,8 @@ bool FilamentMonitorBase::enabled = true, void event_filament_runout(const uint8_t extruder) { + runout.init_for_restart(false); // Reset and disable + if (did_pause_print) return; // Action already in progress. Purge triggered repeated runout. #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE) diff --git a/Marlin/src/feature/runout.h b/Marlin/src/feature/runout.h index d7c41907ed..8047db4f41 100644 --- a/Marlin/src/feature/runout.h +++ b/Marlin/src/feature/runout.h @@ -46,8 +46,10 @@ #if ENABLED(FILAMENT_MOTION_SENSOR) #define HAS_FILAMENT_MOTION 1 -#endif -#if DISABLED(FILAMENT_MOTION_SENSOR) || ENABLED(FILAMENT_SWITCH_AND_MOTION) + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + #define HAS_FILAMENT_SWITCH 1 + #endif +#else #define HAS_FILAMENT_SWITCH 1 #endif @@ -129,6 +131,7 @@ class TFilamentMonitor : public FilamentMonitorBase { // Handle a block completion. RunoutResponseDelayed uses this to // add up the length of filament moved while the filament is out. + // Called from ISR context! static void block_completed(const block_t * const b) { if (enabled) { response.block_completed(b); @@ -171,6 +174,12 @@ class TFilamentMonitor : public FilamentMonitorBase { } } } + + // Reset after a filament runout or upon resuming a job + static void init_for_restart(const bool onoff=true) { + response.init_for_restart(onoff); + } + }; /*************************** FILAMENT PRESENCE SENSORS ***************************/ @@ -267,6 +276,7 @@ class FilamentSensorBase { } public: + // Called from ISR context to indicate a block was completed static void block_completed(const block_t * const b) { // If the sensor wheel has moved since the last call to // this method reset the runout counter for the extruder. @@ -303,6 +313,7 @@ class FilamentSensorBase { } public: + // Called from ISR context to indicate a block was completed static void block_completed(const block_t * const) {} static void run() { @@ -332,6 +343,7 @@ class FilamentSensorBase { TERN_(HAS_FILAMENT_SWITCH, static FilamentSensorSwitch switch_sensor); public: + // Called from ISR context to indicate a block was completed static void block_completed(const block_t * const b) { TERN_(HAS_FILAMENT_MOTION, encoder_sensor.block_completed(b)); TERN_(HAS_FILAMENT_SWITCH, switch_sensor.block_completed(b)); @@ -362,10 +374,17 @@ class FilamentSensorBase { class RunoutResponseDelayed { private: static countdown_t mm_countdown; + static bool ignore_motion; // Flag to ignore the encoder public: static float runout_distance_mm; + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + static constexpr float motion_distance_mm = FILAMENT_MOTION_DISTANCE_MM; + #endif + + static void set_ignore_motion(const bool ignore=true) { ignore_motion = ignore; } + static void reset() { for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) filament_present(i); #if ENABLED(FILAMENT_SWITCH_AND_MOTION) @@ -377,24 +396,27 @@ class FilamentSensorBase { #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) static millis_t t = 0; const millis_t ms = millis(); - if (ELAPSED(ms, t)) { - t = millis() + 1000UL; - for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) - SERIAL_ECHO(i ? F(", ") : F("Runout remaining mm: "), mm_countdown.runout[i]); - #if ENABLED(FILAMENT_SWITCH_AND_MOTION) - for (uint8_t i = 0; i < NUM_MOTION_SENSORS; ++i) - SERIAL_ECHO(i ? F(", ") : F("Motion remaining mm: "), mm_countdown.motion[i]); - #endif - SERIAL_EOL(); - } + if (PENDING(ms, t)) return; + t = ms + 1000UL; + for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) + SERIAL_ECHO(i ? F(", ") : F("Runout remaining mm: "), mm_countdown.runout[i]); + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + for (uint8_t i = 0; i < NUM_MOTION_SENSORS; ++i) + SERIAL_ECHO(i ? F(", ") : F("Motion remaining mm: "), mm_countdown.motion[i]); + #endif + SERIAL_EOL(); #endif } + // Get runout status for all presence sensors and motion sensors static runout_flags_t has_run_out() { runout_flags_t runout_flags{0}; + // Runout based on filament presence for (uint8_t i = 0; i < NUM_RUNOUT_SENSORS; ++i) if (mm_countdown.runout[i] < 0) runout_flags.set(i); + // Runout based on filament motion #if ENABLED(FILAMENT_SWITCH_AND_MOTION) - for (uint8_t i = 0; i < NUM_MOTION_SENSORS; ++i) if (mm_countdown.motion[i] < 0) runout_flags.set(i); + if (!ignore_motion) + for (uint8_t i = 0; i < NUM_MOTION_SENSORS; ++i) if (mm_countdown.motion[i] < 0) runout_flags.set(i); #endif return runout_flags; } @@ -419,8 +441,8 @@ class FilamentSensorBase { #if ENABLED(FILAMENT_SWITCH_AND_MOTION) static void filament_motion_present(const uint8_t extruder) { // Same logic as filament_present - if (mm_countdown.motion[extruder] < runout_distance_mm || did_pause_print) { - mm_countdown.motion[extruder] = runout_distance_mm; + if (mm_countdown.motion[extruder] < motion_distance_mm || did_pause_print) { + mm_countdown.motion[extruder] = motion_distance_mm; mm_countdown.motion_reset.clear(extruder); } else @@ -428,29 +450,42 @@ class FilamentSensorBase { } #endif + // Called from ISR context to indicate a block was completed static void block_completed(const block_t * const b) { - const int32_t esteps = b->steps.e; - if (!esteps) return; - // No calculation unless paused or printing if (!should_monitor_runout()) return; + // Only extrusion moves are examined + const int32_t esteps = b->steps.e; + if (!esteps) return; + // No need to ignore retract/unretract movement since they complement each other const uint8_t e = b->extruder; const float mm = (b->direction_bits.e ? esteps : -esteps) * planner.mm_per_step[E_AXIS_N(e)]; + // Apply E distance to runout countdown, reset if flagged if (e < NUM_RUNOUT_SENSORS) { mm_countdown.runout[e] -= mm; if (mm_countdown.runout_reset[e]) filament_present(e); // Reset pending. Try to reset. } + // Apply E distance to motion countdown, reset if flagged #if ENABLED(FILAMENT_SWITCH_AND_MOTION) - if (e < NUM_MOTION_SENSORS) { + if (!ignore_motion && e < NUM_MOTION_SENSORS) { mm_countdown.motion[e] -= mm; if (mm_countdown.motion_reset[e]) filament_motion_present(e); // Reset pending. Try to reset. } #endif } + + // Reset after a filament runout or upon resuming a job + static void init_for_restart(const bool onoff=true) { + UNUSED(onoff); + #if ENABLED(FILAMENT_SWITCH_AND_MOTION) + reset(); + set_ignore_motion(!onoff); + #endif + } }; #else // !HAS_FILAMENT_RUNOUT_DISTANCE @@ -478,11 +513,15 @@ class FilamentSensorBase { return runout_flags; } + // Called from ISR context to indicate a block was completed static void block_completed(const block_t * const) { } static void filament_present(const uint8_t extruder) { runout_count[extruder] = runout_threshold; } + + // Reset after a filament runout or upon resuming a job + static void init_for_restart(const bool=true) { reset(); } }; #endif // !HAS_FILAMENT_RUNOUT_DISTANCE