✨ Laser Safety Timeout (#24189)
This commit is contained in:
parent
6f3d7d864f
commit
85c0875db2
|
@ -3668,6 +3668,16 @@
|
|||
#define LASER_TEST_PULSE_MIN 1 // Used with Laser Control Menu
|
||||
#define LASER_TEST_PULSE_MAX 999 // Caution: Menu may not show more than 3 characters
|
||||
|
||||
/**
|
||||
* Laser Safety Timeout
|
||||
*
|
||||
* The laser should be turned off when there is no movement for a period of time.
|
||||
* Consider material flammability, cut rate, and G-code order when setting this
|
||||
* value. Too low and it could turn off during a very slow move; too high and
|
||||
* the material could ignite.
|
||||
*/
|
||||
#define LASER_SAFETY_TIMEOUT_MS 1000 // (ms)
|
||||
|
||||
/**
|
||||
* Enable inline laser power to be handled in the planner / stepper routines.
|
||||
* Inline power is specified by the I (inline) flag in an M3 command (e.g., M3 S20 I)
|
||||
|
|
|
@ -423,37 +423,38 @@ inline void manage_inactivity(const bool no_stepper_sleep=false) {
|
|||
kill();
|
||||
}
|
||||
|
||||
const bool has_blocks = planner.has_blocks_queued(); // Any moves in the planner?
|
||||
if (has_blocks) gcode.reset_stepper_timeout(ms); // Reset timeout for M18/M84, M85 max 'kill', and laser.
|
||||
|
||||
// M18 / M84 : Handle steppers inactive time timeout
|
||||
if (gcode.stepper_inactive_time) {
|
||||
#if HAS_DISABLE_INACTIVE_AXIS
|
||||
if (gcode.stepper_inactive_time) {
|
||||
|
||||
static bool already_shutdown_steppers; // = false
|
||||
static bool already_shutdown_steppers; // = false
|
||||
|
||||
// Any moves in the planner? Resets both the M18/M84
|
||||
// activity timeout and the M85 max 'kill' timeout
|
||||
if (planner.has_blocks_queued())
|
||||
gcode.reset_stepper_timeout(ms);
|
||||
else if (!do_reset_timeout && gcode.stepper_inactive_timeout()) {
|
||||
if (!already_shutdown_steppers) {
|
||||
already_shutdown_steppers = true; // L6470 SPI will consume 99% of free time without this
|
||||
if (!has_blocks && !do_reset_timeout && gcode.stepper_inactive_timeout()) {
|
||||
if (!already_shutdown_steppers) {
|
||||
already_shutdown_steppers = true; // L6470 SPI will consume 99% of free time without this
|
||||
|
||||
// Individual axes will be disabled if configured
|
||||
TERN_(DISABLE_INACTIVE_X, stepper.disable_axis(X_AXIS));
|
||||
TERN_(DISABLE_INACTIVE_Y, stepper.disable_axis(Y_AXIS));
|
||||
TERN_(DISABLE_INACTIVE_Z, stepper.disable_axis(Z_AXIS));
|
||||
TERN_(DISABLE_INACTIVE_I, stepper.disable_axis(I_AXIS));
|
||||
TERN_(DISABLE_INACTIVE_J, stepper.disable_axis(J_AXIS));
|
||||
TERN_(DISABLE_INACTIVE_K, stepper.disable_axis(K_AXIS));
|
||||
TERN_(DISABLE_INACTIVE_U, stepper.disable_axis(U_AXIS));
|
||||
TERN_(DISABLE_INACTIVE_V, stepper.disable_axis(V_AXIS));
|
||||
TERN_(DISABLE_INACTIVE_W, stepper.disable_axis(W_AXIS));
|
||||
TERN_(DISABLE_INACTIVE_E, stepper.disable_e_steppers());
|
||||
// Individual axes will be disabled if configured
|
||||
TERN_(DISABLE_INACTIVE_X, stepper.disable_axis(X_AXIS));
|
||||
TERN_(DISABLE_INACTIVE_Y, stepper.disable_axis(Y_AXIS));
|
||||
TERN_(DISABLE_INACTIVE_Z, stepper.disable_axis(Z_AXIS));
|
||||
TERN_(DISABLE_INACTIVE_I, stepper.disable_axis(I_AXIS));
|
||||
TERN_(DISABLE_INACTIVE_J, stepper.disable_axis(J_AXIS));
|
||||
TERN_(DISABLE_INACTIVE_K, stepper.disable_axis(K_AXIS));
|
||||
TERN_(DISABLE_INACTIVE_U, stepper.disable_axis(U_AXIS));
|
||||
TERN_(DISABLE_INACTIVE_V, stepper.disable_axis(V_AXIS));
|
||||
TERN_(DISABLE_INACTIVE_W, stepper.disable_axis(W_AXIS));
|
||||
TERN_(DISABLE_INACTIVE_E, stepper.disable_e_steppers());
|
||||
|
||||
TERN_(AUTO_BED_LEVELING_UBL, bedlevel.steppers_were_disabled());
|
||||
TERN_(AUTO_BED_LEVELING_UBL, bedlevel.steppers_were_disabled());
|
||||
}
|
||||
}
|
||||
else
|
||||
already_shutdown_steppers = false;
|
||||
}
|
||||
else
|
||||
already_shutdown_steppers = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLED(PHOTO_GCODE) && PIN_EXISTS(CHDK)
|
||||
// Check if CHDK should be set to LOW (after M240 set it HIGH)
|
||||
|
|
|
@ -39,7 +39,8 @@
|
|||
#endif
|
||||
|
||||
SpindleLaser cutter;
|
||||
uint8_t SpindleLaser::power;
|
||||
uint8_t SpindleLaser::power,
|
||||
SpindleLaser::last_power_applied; // = 0 // Basic power state tracking
|
||||
#if ENABLED(LASER_FEATURE)
|
||||
cutter_test_pulse_t SpindleLaser::testPulse = 50; // Test fire Pulse time ms value.
|
||||
#endif
|
||||
|
@ -113,7 +114,6 @@ void SpindleLaser::init() {
|
|||
* @param opwr Power value. Range 0 to MAX. When 0 disable spindle/laser.
|
||||
*/
|
||||
void SpindleLaser::apply_power(const uint8_t opwr) {
|
||||
static uint8_t last_power_applied = 0;
|
||||
if (opwr == last_power_applied) return;
|
||||
last_power_applied = opwr;
|
||||
power = opwr;
|
||||
|
|
|
@ -89,7 +89,8 @@ public:
|
|||
#endif
|
||||
|
||||
static bool isReady; // Ready to apply power setting from the UI to OCR
|
||||
static uint8_t power;
|
||||
static uint8_t power,
|
||||
last_power_applied; // Basic power state tracking
|
||||
|
||||
#if ENABLED(MARLIN_DEV_MODE)
|
||||
static cutter_frequency_t frequency; // Set PWM frequency; range: 2K-50K
|
||||
|
|
|
@ -211,7 +211,16 @@ void try_to_disable(const stepper_flags_t to_disable) {
|
|||
void GcodeSuite::M18_M84() {
|
||||
if (parser.seenval('S')) {
|
||||
reset_stepper_timeout();
|
||||
stepper_inactive_time = parser.value_millis_from_seconds();
|
||||
#if HAS_DISABLE_INACTIVE_AXIS
|
||||
const millis_t ms = parser.value_millis_from_seconds();
|
||||
#if LASER_SAFETY_TIMEOUT_MS > 0
|
||||
if (ms && ms <= LASER_SAFETY_TIMEOUT_MS) {
|
||||
SERIAL_ECHO_MSG("M18 timeout must be > ", MS_TO_SEC(LASER_SAFETY_TIMEOUT_MS + 999), " s for laser safety.");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
stepper_inactive_time = ms;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
if (parser.seen_axis()) {
|
||||
|
|
|
@ -66,6 +66,10 @@
|
|||
* PWM duty cycle goes from 0 (off) to 255 (always on).
|
||||
*/
|
||||
void GcodeSuite::M3_M4(const bool is_M4) {
|
||||
#if LASER_SAFETY_TIMEOUT_MS > 0
|
||||
reset_stepper_timeout(); // Reset timeout to allow subsequent G-code to power the laser (imm.)
|
||||
#endif
|
||||
|
||||
#if EITHER(SPINDLE_LASER_USE_PWM, SPINDLE_SERVO)
|
||||
auto get_s_power = [] {
|
||||
if (parser.seenval('S')) {
|
||||
|
|
|
@ -29,7 +29,14 @@ void GcodeSuite::M85() {
|
|||
|
||||
if (parser.seen('S')) {
|
||||
reset_stepper_timeout();
|
||||
max_inactive_time = parser.value_millis_from_seconds();
|
||||
const millis_t ms = parser.value_millis_from_seconds();
|
||||
#if LASER_SAFETY_TIMEOUT_MS > 0
|
||||
if (ms && ms <= LASER_SAFETY_TIMEOUT_MS) {
|
||||
SERIAL_ECHO_MSG("M85 timeout must be > ", MS_TO_SEC(LASER_SAFETY_TIMEOUT_MS + 999), " s for laser safety.");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
max_inactive_time = ms;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -73,8 +73,11 @@ GcodeSuite gcode;
|
|||
|
||||
// Inactivity shutdown
|
||||
millis_t GcodeSuite::previous_move_ms = 0,
|
||||
GcodeSuite::max_inactive_time = 0,
|
||||
GcodeSuite::stepper_inactive_time = SEC_TO_MS(DEFAULT_STEPPER_DEACTIVE_TIME);
|
||||
GcodeSuite::max_inactive_time = 0;
|
||||
|
||||
#if HAS_DISABLE_INACTIVE_AXIS
|
||||
millis_t GcodeSuite::stepper_inactive_time = SEC_TO_MS(DEFAULT_STEPPER_DEACTIVE_TIME);
|
||||
#endif
|
||||
|
||||
// Relative motion mode for each logical axis
|
||||
static constexpr xyze_bool_t ar_init = AXIS_RELATIVE_MODES;
|
||||
|
|
|
@ -396,14 +396,20 @@ public:
|
|||
static bool select_coordinate_system(const int8_t _new);
|
||||
#endif
|
||||
|
||||
static millis_t previous_move_ms, max_inactive_time, stepper_inactive_time;
|
||||
FORCE_INLINE static void reset_stepper_timeout(const millis_t ms=millis()) { previous_move_ms = ms; }
|
||||
static millis_t previous_move_ms, max_inactive_time;
|
||||
FORCE_INLINE static bool stepper_max_timed_out(const millis_t ms=millis()) {
|
||||
return max_inactive_time && ELAPSED(ms, previous_move_ms + max_inactive_time);
|
||||
}
|
||||
FORCE_INLINE static bool stepper_inactive_timeout(const millis_t ms=millis()) {
|
||||
return ELAPSED(ms, previous_move_ms + stepper_inactive_time);
|
||||
}
|
||||
FORCE_INLINE static void reset_stepper_timeout(const millis_t ms=millis()) { previous_move_ms = ms; }
|
||||
|
||||
#if HAS_DISABLE_INACTIVE_AXIS
|
||||
static millis_t stepper_inactive_time;
|
||||
FORCE_INLINE static bool stepper_inactive_timeout(const millis_t ms=millis()) {
|
||||
return ELAPSED(ms, previous_move_ms + stepper_inactive_time);
|
||||
}
|
||||
#else
|
||||
static bool stepper_inactive_timeout(const millis_t) { return false; }
|
||||
#endif
|
||||
|
||||
static void report_echo_start(const bool forReplay);
|
||||
static void report_heading(const bool forReplay, FSTR_P const fstr, const bool eol=true);
|
||||
|
|
|
@ -1044,3 +1044,7 @@
|
|||
#undef CONFIGURATION_EMBEDDING
|
||||
#define CANNOT_EMBED_CONFIGURATION defined(__AVR__)
|
||||
#endif
|
||||
|
||||
#if ANY(DISABLE_INACTIVE_X, DISABLE_INACTIVE_Y, DISABLE_INACTIVE_Z, DISABLE_INACTIVE_I, DISABLE_INACTIVE_J, DISABLE_INACTIVE_K, DISABLE_INACTIVE_U, DISABLE_INACTIVE_V, DISABLE_INACTIVE_W, DISABLE_INACTIVE_E)
|
||||
#define HAS_DISABLE_INACTIVE_AXIS 1
|
||||
#endif
|
||||
|
|
|
@ -3867,6 +3867,7 @@ static_assert(_PLUS_TEST(4), "HOMING_FEEDRATE_MM_M values must be positive.");
|
|||
#error "Enabled an inline laser feature without inline laser power being enabled."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define _PIN_CONFLICT(P) (PIN_EXISTS(P) && P##_PIN == SPINDLE_LASER_PWM_PIN)
|
||||
#if BOTH(SPINDLE_FEATURE, LASER_FEATURE)
|
||||
#error "Enable only one of SPINDLE_FEATURE or LASER_FEATURE."
|
||||
|
@ -3934,6 +3935,11 @@ static_assert(_PLUS_TEST(4), "HOMING_FEEDRATE_MM_M values must be positive.");
|
|||
#endif
|
||||
#endif
|
||||
#undef _PIN_CONFLICT
|
||||
|
||||
#ifdef LASER_SAFETY_TIMEOUT_MS
|
||||
static_assert(LASER_SAFETY_TIMEOUT_MS < (DEFAULT_STEPPER_DEACTIVE_TIME) * 1000UL, "LASER_SAFETY_TIMEOUT_MS must be less than DEFAULT_STEPPER_DEACTIVE_TIME (" STRINGIFY(DEFAULT_STEPPER_DEACTIVE_TIME) " seconds)");
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if ENABLED(COOLANT_MIST) && !PIN_EXISTS(COOLANT_MIST)
|
||||
|
|
|
@ -71,6 +71,10 @@
|
|||
#include "../libs/nozzle.h"
|
||||
#endif
|
||||
|
||||
#if LASER_SAFETY_TIMEOUT_MS > 0
|
||||
#include "../feature/spindle_laser.h"
|
||||
#endif
|
||||
|
||||
// MAX TC related macros
|
||||
#define TEMP_SENSOR_IS_MAX(n, M) (ENABLED(TEMP_SENSOR_##n##_IS_MAX##M) || (ENABLED(TEMP_SENSOR_REDUNDANT_IS_MAX##M) && REDUNDANT_TEMP_MATCH(SOURCE, E##n)))
|
||||
#define TEMP_SENSOR_IS_ANY_MAX_TC(n) (ENABLED(TEMP_SENSOR_##n##_IS_MAX_TC) || (ENABLED(TEMP_SENSOR_REDUNDANT_IS_MAX_TC) && REDUNDANT_TEMP_MATCH(SOURCE, E##n)))
|
||||
|
@ -3328,6 +3332,7 @@ public:
|
|||
|
||||
/**
|
||||
* Handle various ~1kHz tasks associated with temperature
|
||||
* - Check laser safety timeout
|
||||
* - Heater PWM (~1kHz with scaler)
|
||||
* - LCD Button polling (~500Hz)
|
||||
* - Start / Read one ADC sensor
|
||||
|
@ -3337,6 +3342,14 @@ public:
|
|||
*/
|
||||
void Temperature::isr() {
|
||||
|
||||
// Shut down the laser if steppers are inactive for > LASER_SAFETY_TIMEOUT_MS ms
|
||||
#if LASER_SAFETY_TIMEOUT_MS > 0
|
||||
if (cutter.last_power_applied && ELAPSED(millis(), gcode.previous_move_ms + (LASER_SAFETY_TIMEOUT_MS))) {
|
||||
cutter.power = 0; // Prevent planner idle from re-enabling power
|
||||
cutter.apply_power(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int8_t temp_count = -1;
|
||||
static ADCSensorState adc_sensor_state = StartupDelay;
|
||||
static uint8_t pwm_count = _BV(SOFT_PWM_SCALE);
|
||||
|
|
|
@ -26,7 +26,7 @@ opt_set MOTHERBOARD BOARD_BTT_SKR_PRO_V1_1 SERIAL_PORT -1 \
|
|||
CUTTER_POWER_UNIT PERCENT \
|
||||
SPINDLE_LASER_PWM_PIN HEATER_1_PIN SPINDLE_LASER_ENA_PIN HEATER_2_PIN \
|
||||
TEMP_SENSOR_COOLER 1000 TEMP_COOLER_PIN PD13
|
||||
opt_enable LASER_FEATURE REPRAP_DISCOUNT_SMART_CONTROLLER
|
||||
opt_enable LASER_FEATURE LASER_SAFETY_TIMEOUT_MS REPRAP_DISCOUNT_SMART_CONTROLLER
|
||||
exec_test $1 $2 "BigTreeTech SKR Pro | Laser (Percent) | Cooling | LCD" "$3"
|
||||
|
||||
# clean up
|
||||
|
|
|
@ -179,8 +179,8 @@ opt_set MOTHERBOARD BOARD_RAMPS_14_EFB EXTRUDERS 0 LCD_LANGUAGE en TEMP_SENSOR_C
|
|||
DEFAULT_MAX_ACCELERATION '{ 3000, 3000, 100 }' \
|
||||
MANUAL_FEEDRATE '{ 50*60, 50*60, 4*60 }' \
|
||||
AXIS_RELATIVE_MODES '{ false, false, false }'
|
||||
opt_enable REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER SDSUPPORT EEPROM_SETTINGS EEPROM_BOOT_SILENT EEPROM_AUTO_INIT \
|
||||
LASER_FEATURE AIR_EVACUATION AIR_EVACUATION_PIN AIR_ASSIST AIR_ASSIST_PIN LASER_COOLANT_FLOW_METER MEATPACK_ON_SERIAL_PORT_1
|
||||
opt_enable REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER SDSUPPORT EEPROM_SETTINGS EEPROM_BOOT_SILENT EEPROM_AUTO_INIT MEATPACK_ON_SERIAL_PORT_1 \
|
||||
LASER_FEATURE LASER_SAFETY_TIMEOUT_MS LASER_COOLANT_FLOW_METER AIR_EVACUATION AIR_EVACUATION_PIN AIR_ASSIST AIR_ASSIST_PIN
|
||||
exec_test $1 $2 "MEGA2560 RAMPS | Laser Feature | Air Evacuation | Air Assist | Cooler | Flowmeter | 12864 LCD | meatpack | SERIAL_PORT_2 " "$3"
|
||||
|
||||
#
|
||||
|
@ -193,8 +193,8 @@ opt_set MOTHERBOARD BOARD_RAMPS_14_EFB EXTRUDERS 0 LCD_LANGUAGE en TEMP_SENSOR_C
|
|||
DEFAULT_MAX_ACCELERATION '{ 3000, 3000, 100 }' \
|
||||
MANUAL_FEEDRATE '{ 50*60, 50*60, 4*60 }' \
|
||||
AXIS_RELATIVE_MODES '{ false, false, false }'
|
||||
opt_enable REPRAP_DISCOUNT_SMART_CONTROLLER SDSUPPORT EEPROM_SETTINGS EEPROM_BOOT_SILENT EEPROM_AUTO_INIT PRINTCOUNTER \
|
||||
LASER_FEATURE AIR_EVACUATION AIR_EVACUATION_PIN AIR_ASSIST AIR_ASSIST_PIN LASER_COOLANT_FLOW_METER I2C_AMMETER
|
||||
opt_enable REPRAP_DISCOUNT_SMART_CONTROLLER SDSUPPORT EEPROM_SETTINGS EEPROM_BOOT_SILENT EEPROM_AUTO_INIT PRINTCOUNTER I2C_AMMETER \
|
||||
LASER_FEATURE LASER_SAFETY_TIMEOUT_MS LASER_COOLANT_FLOW_METER AIR_EVACUATION AIR_EVACUATION_PIN AIR_ASSIST AIR_ASSIST_PIN
|
||||
exec_test $1 $2 "MEGA2560 RAMPS | Laser Feature | Air Evacuation | Air Assist | Cooler | Flowmeter | 44780 LCD " "$3"
|
||||
|
||||
#
|
||||
|
|
Loading…
Reference in a new issue