mirror of
https://github.com/MarlinFirmware/Marlin.git
synced 2026-01-24 22:17:25 -07:00
✨ SOFT_FEED_HOLD (#28265)
This commit is contained in:
parent
367e2219e3
commit
7c29cdb685
12 changed files with 270 additions and 36 deletions
|
|
@ -2826,8 +2826,8 @@
|
|||
*
|
||||
* Adds support for commands:
|
||||
* S000 : Report State and Position while moving.
|
||||
* P000 : Instant Pause / Hold while moving.
|
||||
* R000 : Resume from Pause / Hold.
|
||||
* P000 : Instant Pause / Hold while moving. Enable SOFT_FEED_HOLD for soft deceleration.
|
||||
* R000 : Resume from Pause / Hold. Enable SOFT_FEED_HOLD for soft acceleration.
|
||||
*
|
||||
* - During Hold all Emergency Parser commands are available, as usual.
|
||||
* - Enable NANODLP_Z_SYNC and NANODLP_ALL_AXIS for move command end-state reports.
|
||||
|
|
@ -4457,15 +4457,38 @@
|
|||
#endif
|
||||
|
||||
/**
|
||||
* Instant freeze / unfreeze functionality
|
||||
* Potentially useful for rapid stop that allows being resumed. Halts stepper movement.
|
||||
* Note this does NOT pause spindles, lasers, fans, heaters or any other auxiliary device.
|
||||
* @section interface
|
||||
* Freeze / Unfreeze
|
||||
*
|
||||
* Pause / Hold that keeps power available and does not stop the spindle can be initiated by
|
||||
* the FREEZE_PIN. Halts instantly (default) or performs a soft feed hold that decelerates and
|
||||
* halts movement at FREEZE_JERK (requires SOFT_FEED_HOLD).
|
||||
* Motion can be resumed by using the FREEZE_PIN.
|
||||
*
|
||||
* NOTE: Controls Laser PWM but does NOT pause Spindle, Fans, Heaters or other devices.
|
||||
* @section freeze
|
||||
*/
|
||||
//#define FREEZE_FEATURE
|
||||
#if ENABLED(FREEZE_FEATURE)
|
||||
//#define FREEZE_PIN 41 // Override the default (KILL) pin here
|
||||
#define FREEZE_STATE LOW // State of pin indicating freeze
|
||||
//#define FREEZE_PIN -1 // Override the default (KILL) pin here
|
||||
#define FREEZE_STATE LOW // State of pin indicating freeze
|
||||
#endif
|
||||
|
||||
#if ANY(FREEZE_FEATURE, REALTIME_REPORTING_COMMANDS)
|
||||
/**
|
||||
* Command P000 (REALTIME_REPORTING_COMMANDS and EMERGENCY_PARSER) or
|
||||
* FREEZE_PIN (FREEZE_FEATURE) initiates a soft feed hold that keeps
|
||||
* power available and does not stop the spindle.
|
||||
*
|
||||
* The soft feed hold decelerates and halts movement at FREEZE_JERK.
|
||||
* Motion can be resumed with command R000 (requires REALTIME_REPORTING_COMMANDS) or
|
||||
* by using the FREEZE_PIN (requires FREEZE_FEATURE).
|
||||
*
|
||||
* NOTE: Affects Laser PWM but DOES NOT pause Spindle, Fans, Heaters or other devices.
|
||||
*/
|
||||
//#define SOFT_FEED_HOLD
|
||||
#if ENABLED(SOFT_FEED_HOLD)
|
||||
#define FREEZE_JERK 2 // (mm/s) Completely halt when motion has decelerated below this value
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -260,6 +260,10 @@
|
|||
#include "feature/rs485.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(SOFT_FEED_HOLD)
|
||||
#include "feature/e_parser.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Spin in place here while keeping temperature processing alive
|
||||
*/
|
||||
|
|
@ -514,8 +518,14 @@ void Marlin::manage_inactivity(const bool no_stepper_sleep/*=false*/) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#if ENABLED(FREEZE_FEATURE)
|
||||
stepper.frozen = READ(FREEZE_PIN) == FREEZE_STATE;
|
||||
// Handle the FREEZE button
|
||||
#if ANY(FREEZE_FEATURE, SOFT_FEED_HOLD)
|
||||
stepper.set_frozen_triggered(
|
||||
TERN0(FREEZE_FEATURE, READ(FREEZE_PIN) == FREEZE_STATE)
|
||||
#if ALL(SOFT_FEED_HOLD, REALTIME_REPORTING_COMMANDS)
|
||||
|| realtime_ramping_pause_flag
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
|
||||
#if HAS_HOME
|
||||
|
|
@ -1221,7 +1231,7 @@ void setup() {
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if ENABLED(FREEZE_FEATURE)
|
||||
#if ENABLED(FREEZE_FEATURE) && DISABLED(NO_FREEZE_PIN)
|
||||
SETUP_LOG("FREEZE_PIN");
|
||||
#if FREEZE_STATE
|
||||
SET_INPUT_PULLDOWN(FREEZE_PIN);
|
||||
|
|
|
|||
|
|
@ -60,6 +60,10 @@ EmergencyParser emergency_parser;
|
|||
void quickresume_stepper();
|
||||
#endif
|
||||
|
||||
#if ENABLED(SOFT_FEED_HOLD)
|
||||
bool realtime_ramping_pause_flag = false;
|
||||
#endif
|
||||
|
||||
void EmergencyParser::update(EmergencyParser::State &state, const uint8_t c) {
|
||||
auto uppercase = [](char c) {
|
||||
return TERN0(GCODE_CASE_INSENSITIVE, WITHIN(c, 'a', 'z')) ? c + 'A' - 'a' : c;
|
||||
|
|
@ -223,8 +227,8 @@ void EmergencyParser::update(EmergencyParser::State &state, const uint8_t c) {
|
|||
#endif
|
||||
#if ENABLED(REALTIME_REPORTING_COMMANDS)
|
||||
case EP_GRBL_STATUS: report_current_position_moving(); break;
|
||||
case EP_GRBL_PAUSE: quickpause_stepper(); break;
|
||||
case EP_GRBL_RESUME: quickresume_stepper(); break;
|
||||
case EP_GRBL_PAUSE: TERN(SOFT_FEED_HOLD, realtime_ramping_pause_flag = true, quickpause_stepper()); break;
|
||||
case EP_GRBL_RESUME: TERN(SOFT_FEED_HOLD, realtime_ramping_pause_flag = false, quickresume_stepper()); break;
|
||||
#endif
|
||||
#if ENABLED(SOFT_RESET_VIA_SERIAL)
|
||||
case EP_KILL: hal.reboot(); break;
|
||||
|
|
|
|||
|
|
@ -93,3 +93,7 @@ private:
|
|||
};
|
||||
|
||||
extern EmergencyParser emergency_parser;
|
||||
|
||||
#if ENABLED(SOFT_FEED_HOLD)
|
||||
extern bool realtime_ramping_pause_flag;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -3047,9 +3047,10 @@
|
|||
#endif
|
||||
|
||||
// User Interface
|
||||
#if ENABLED(FREEZE_FEATURE) && !PIN_EXISTS(FREEZE) && PIN_EXISTS(KILL)
|
||||
#if ENABLED(FREEZE_FEATURE) && DISABLED(NO_FREEZE_PIN) && !PIN_EXISTS(FREEZE) && PIN_EXISTS(KILL)
|
||||
#define FREEZE_PIN KILL_PIN
|
||||
#elif PIN_EXISTS(KILL) && TERN1(FREEZE_FEATURE, KILL_PIN != FREEZE_PIN)
|
||||
#define FREEZE_STOLE_KILL_PIN_WARNING 1
|
||||
#elif PIN_EXISTS(KILL) && TERN1(HAS_FREEZE_PIN, KILL_PIN != FREEZE_PIN)
|
||||
#define HAS_KILL 1
|
||||
#endif
|
||||
#if PIN_EXISTS(HOME)
|
||||
|
|
|
|||
|
|
@ -579,8 +579,12 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L
|
|||
/**
|
||||
* Instant Freeze
|
||||
*/
|
||||
#if ENABLED(FREEZE_FEATURE) && !(PIN_EXISTS(FREEZE) && defined(FREEZE_STATE))
|
||||
#error "FREEZE_FEATURE requires both FREEZE_PIN and FREEZE_STATE."
|
||||
#if ENABLED(SOFT_FEED_HOLD) && !defined(FREEZE_JERK)
|
||||
#error "SOFT_FEED_HOLD requires FREEZE_JERK."
|
||||
#elif ENABLED(FREEZE_FEATURE) && DISABLED(NO_FREEZE_PIN) && !(defined(FREEZE_PIN) && defined(FREEZE_STATE))
|
||||
#error "FREEZE_FEATURE requires FREEZE_PIN and FREEZE_STATE."
|
||||
#elif ENABLED(NO_FREEZE_PIN) && !(defined(REALTIME_REPORTING_COMMANDS))
|
||||
#error "NO_FREEZE_PIN requires REALTIME_REPORTING_COMMANDS."
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
@ -4501,8 +4505,8 @@ static_assert(_PLUS_TEST(3), "DEFAULT_MAX_ACCELERATION values must be positive."
|
|||
#error "SMOOTH_LIN_ADVANCE is not yet available in FT_MOTION. Disable NO_STANDARD_MOTION if you require it."
|
||||
#elif ENABLED(MIXING_EXTRUDER)
|
||||
#error "MIXING_EXTRUDER is not yet available in FT_MOTION. Disable NO_STANDARD_MOTION if you require it."
|
||||
#elif ENABLED(FREEZE_FEATURE)
|
||||
#error "FREEZE_FEATURE is not yet available in FT_MOTION. Disable NO_STANDARD_MOTION if you require it."
|
||||
#elif ENABLED(SOFT_FEED_HOLD)
|
||||
#error "SOFT_FEED_HOLD is not yet available in FT_MOTION. Disable NO_STANDARD_MOTION if you require it."
|
||||
#elif ENABLED(DIRECT_STEPPING)
|
||||
#error "DIRECT_STEPPING is not yet available in FT_MOTION. Disable NO_STANDARD_MOTION if you require it."
|
||||
#elif ENABLED(DIFFERENTIAL_EXTRUDER)
|
||||
|
|
|
|||
|
|
@ -1005,3 +1005,10 @@
|
|||
#elif !RECOMMEND_REINIT_NOISY_LCD && ENABLED(REINIT_NOISY_LCD)
|
||||
#warning "REINIT_NOISY_LCD is probably not required with your LCD controller model."
|
||||
#endif
|
||||
|
||||
/**
|
||||
* FREEZE_FEATURE may override the KILL_PIN
|
||||
*/
|
||||
#if FREEZE_STOLE_KILL_PIN_WARNING
|
||||
#warning "FREEZE_FEATURE uses KILL_PIN replacing the KILL button. Define a separate FREEZE_PIN if you don't want this behavior."
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -2428,6 +2428,9 @@ bool Planner::_populate_block(
|
|||
block->acceleration_steps_per_s2 = accel;
|
||||
#if DISABLED(S_CURVE_ACCELERATION)
|
||||
block->acceleration_rate = uint32_t(accel * (float(_BV32(24)) / (STEPPER_TIMER_RATE)));
|
||||
#elif ENABLED(SOFT_FEED_HOLD)
|
||||
// No need to waste time calculating the linear acceleration rate until the freeze_pin is triggered, leave this 0
|
||||
block->acceleration_rate = 0;
|
||||
#endif
|
||||
#endif
|
||||
block->acceleration = accel / steps_per_mm;
|
||||
|
|
|
|||
|
|
@ -254,7 +254,8 @@ typedef struct PlannerBlock {
|
|||
#if ENABLED(S_CURVE_ACCELERATION)
|
||||
uint32_t acceleration_time_inverse, // Inverse of acceleration and deceleration periods, expressed as integer. Scale depends on CPU being used
|
||||
deceleration_time_inverse;
|
||||
#elif HAS_STANDARD_MOTION
|
||||
#endif
|
||||
#if ENABLED(HAS_STANDARD_MOTION) && (DISABLED(S_CURVE_ACCELERATION) || ENABLED(FREEZE_FEATURE))
|
||||
uint32_t acceleration_rate; // Acceleration rate in (2^24 steps)/timer_ticks*s
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -199,8 +199,14 @@ uint32_t Stepper::acceleration_time, Stepper::deceleration_time;
|
|||
constexpr uint8_t Stepper::oversampling_factor; // = 0
|
||||
#endif
|
||||
|
||||
#if ENABLED(FREEZE_FEATURE)
|
||||
bool Stepper::frozen; // = false
|
||||
#if ANY(SOFT_FEED_HOLD, FREEZE_FEATURE)
|
||||
frozen_state_t Stepper::frozen_state; // Frozen flags
|
||||
#endif
|
||||
#if ENABLED(SOFT_FEED_HOLD)
|
||||
uint32_t Stepper::frozen_time; // How much time has passed since frozen_state was triggered?
|
||||
#if ENABLED(LASER_FEATURE)
|
||||
uint8_t frozen_last_laser_power; // Saved laser power prior to halting motion
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Delta error variables for the Bresenham line tracer
|
||||
|
|
@ -1846,7 +1852,11 @@ void Stepper::isr() {
|
|||
if (!current_block || step_events_completed >= step_event_count) return;
|
||||
|
||||
// Skipping step processing causes motion to freeze
|
||||
if (TERN0(FREEZE_FEATURE, frozen)) return;
|
||||
#if ENABLED(SOFT_FEED_HOLD)
|
||||
if (frozen_state.triggered && frozen_state.solid) return;
|
||||
#elif ENABLED(FREEZE_FEATURE)
|
||||
if (frozen_state.state == 0) return;
|
||||
#endif
|
||||
|
||||
// Count of pending loops and events for this iteration
|
||||
const uint32_t pending_events = step_event_count - step_events_completed;
|
||||
|
|
@ -2418,6 +2428,10 @@ void Stepper::isr() {
|
|||
// If no queued movements, just wait 1ms for the next block
|
||||
hal_timer_t interval = (STEPPER_TIMER_RATE) / 1000UL;
|
||||
|
||||
// Frozen solid?? Exit and do not fetch blocks.
|
||||
if (TERN0(SOFT_FEED_HOLD, frozen_state.triggered && frozen_state.solid))
|
||||
return interval;
|
||||
|
||||
// If there is a current block
|
||||
if (current_block) {
|
||||
// If current block is finished, reset pointer and finalize state
|
||||
|
|
@ -2460,11 +2474,16 @@ void Stepper::isr() {
|
|||
|
||||
// acc_step_rate is in steps/second
|
||||
|
||||
// Modify acc_step_rate if the machine is freezing
|
||||
TERN_(SOFT_FEED_HOLD, check_frozen_time(acc_step_rate));
|
||||
|
||||
// step_rate to timer interval and steps per stepper isr
|
||||
interval = calc_multistep_timer_interval(acc_step_rate << oversampling_factor);
|
||||
acceleration_time += interval;
|
||||
deceleration_time = 0; // Reset since we're doing acceleration first.
|
||||
|
||||
TERN_(SOFT_FEED_HOLD, check_frozen_state(FREEZE_ACCELERATION, interval));
|
||||
|
||||
// Apply Nonlinear Extrusion, if enabled
|
||||
calc_nonlinear_e(acc_step_rate << oversampling_factor);
|
||||
|
||||
|
|
@ -2526,10 +2545,14 @@ void Stepper::isr() {
|
|||
|
||||
#endif
|
||||
|
||||
TERN_(SOFT_FEED_HOLD, check_frozen_time(step_rate));
|
||||
|
||||
// step_rate to timer interval and steps per stepper isr
|
||||
interval = calc_multistep_timer_interval(step_rate << oversampling_factor);
|
||||
deceleration_time += interval;
|
||||
|
||||
TERN_(SOFT_FEED_HOLD, check_frozen_state(FREEZE_DECELERATION, interval));
|
||||
|
||||
// Apply Nonlinear Extrusion, if enabled
|
||||
calc_nonlinear_e(step_rate << oversampling_factor);
|
||||
|
||||
|
|
@ -2576,21 +2599,25 @@ void Stepper::isr() {
|
|||
else { // Must be in cruise phase otherwise
|
||||
|
||||
// Calculate the ticks_nominal for this nominal speed, if not done yet
|
||||
if (ticks_nominal == 0) {
|
||||
if (ticks_nominal == 0 || TERN0(SOFT_FEED_HOLD, frozen_time)) {
|
||||
uint32_t step_rate = current_block->nominal_rate;
|
||||
|
||||
TERN_(SOFT_FEED_HOLD, check_frozen_time(step_rate));
|
||||
|
||||
// step_rate to timer interval and loops for the nominal speed
|
||||
ticks_nominal = calc_multistep_timer_interval(current_block->nominal_rate << oversampling_factor);
|
||||
ticks_nominal = calc_multistep_timer_interval(step_rate << oversampling_factor);
|
||||
deceleration_time = ticks_nominal / 2;
|
||||
|
||||
// Prepare for deceleration
|
||||
IF_DISABLED(S_CURVE_ACCELERATION, acc_step_rate = current_block->nominal_rate);
|
||||
IF_DISABLED(S_CURVE_ACCELERATION, acc_step_rate = step_rate);
|
||||
TERN_(SMOOTH_LIN_ADVANCE, curr_step_rate = current_block->nominal_rate);
|
||||
|
||||
// Apply Nonlinear Extrusion, if enabled
|
||||
calc_nonlinear_e(current_block->nominal_rate << oversampling_factor);
|
||||
calc_nonlinear_e(step_rate << oversampling_factor);
|
||||
|
||||
#if HAS_ROUGH_LIN_ADVANCE
|
||||
if (la_active)
|
||||
la_interval = calc_timer_interval(current_block->nominal_rate >> current_block->la_scaling);
|
||||
la_interval = calc_timer_interval(step_rate >> current_block->la_scaling);
|
||||
#endif
|
||||
|
||||
// Adjust Laser Power - Cruise
|
||||
|
|
@ -2610,6 +2637,8 @@ void Stepper::isr() {
|
|||
|
||||
// The timer interval is just the nominal value for the nominal speed
|
||||
interval = ticks_nominal;
|
||||
|
||||
TERN_(SOFT_FEED_HOLD, check_frozen_state(FREEZE_CRUISE, interval));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2631,9 +2660,12 @@ void Stepper::isr() {
|
|||
#endif
|
||||
}
|
||||
else { // !current_block
|
||||
TERN_(SOFT_FEED_HOLD, check_frozen_state(FREEZE_STATIONARY, interval));
|
||||
|
||||
#if ENABLED(LASER_FEATURE)
|
||||
// If no movement in dynamic mode turn Laser off
|
||||
if (cutter.cutter_mode == CUTTER_MODE_DYNAMIC)
|
||||
cutter.apply_power(0); // No movement in dynamic mode so turn Laser off
|
||||
cutter.apply_power(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -2916,13 +2948,22 @@ void Stepper::isr() {
|
|||
}
|
||||
#endif
|
||||
|
||||
uint32_t initial_rate = current_block->initial_rate;
|
||||
|
||||
#if ENABLED(SOFT_FEED_HOLD)
|
||||
if (frozen_time) check_frozen_time(initial_rate);
|
||||
#endif
|
||||
|
||||
// Calculate the initial timer interval
|
||||
interval = calc_multistep_timer_interval(current_block->initial_rate << oversampling_factor);
|
||||
interval = calc_multistep_timer_interval(initial_rate << oversampling_factor);
|
||||
|
||||
TERN_(SOFT_FEED_HOLD, check_frozen_state(FREEZE_ACCELERATION, interval));
|
||||
|
||||
// Initialize ac/deceleration time as if half the time passed.
|
||||
acceleration_time = deceleration_time = interval / 2;
|
||||
|
||||
// Apply Nonlinear Extrusion, if enabled
|
||||
calc_nonlinear_e(current_block->initial_rate << oversampling_factor);
|
||||
calc_nonlinear_e(initial_rate << oversampling_factor);
|
||||
|
||||
#if ENABLED(LIN_ADVANCE)
|
||||
#if ENABLED(SMOOTH_LIN_ADVANCE)
|
||||
|
|
@ -2930,7 +2971,7 @@ void Stepper::isr() {
|
|||
#else
|
||||
if (la_active) {
|
||||
const uint32_t la_step_rate = la_advance_steps < current_block->max_adv_steps ? current_block->la_advance_rate : 0;
|
||||
la_interval = calc_timer_interval((current_block->initial_rate + la_step_rate) >> current_block->la_scaling);
|
||||
la_interval = calc_timer_interval((initial_rate + la_step_rate) >> current_block->la_scaling);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -3876,3 +3917,105 @@ void Stepper::report_positions() {
|
|||
}
|
||||
|
||||
#endif // BABYSTEPPING
|
||||
|
||||
#if ENABLED(SOFT_FEED_HOLD)
|
||||
|
||||
void Stepper::set_frozen_solid(const bool state) {
|
||||
if (state == frozen_state.solid) return;
|
||||
|
||||
frozen_state.solid = true;
|
||||
|
||||
#if ENABLED(LASER_FEATURE)
|
||||
if (state) {
|
||||
frozen_last_laser_power = cutter.last_power_applied;
|
||||
cutter.apply_power(0); // No movement in dynamic mode so turn Laser off
|
||||
}
|
||||
else
|
||||
cutter.apply_power(frozen_last_laser_power); // Restore frozen laser power
|
||||
#endif
|
||||
|
||||
#if ENABLED(REALTIME_REPORTING_COMMANDS)
|
||||
set_and_report_grblstate(state ? M_HOLD : M_RUNNING);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Stepper::check_frozen_time(uint32_t &step_rate) {
|
||||
// If frozen_time is 0 there is no need to modify the current step_rate
|
||||
if (!frozen_time) return;
|
||||
|
||||
#if ENABLED(S_CURVE_ACCELERATION)
|
||||
// If the machine is configured to use S_CURVE_ACCELERATION standard ramp acceleration
|
||||
// rate will not have been calculated at this point
|
||||
if (!current_block->acceleration_rate)
|
||||
current_block->acceleration_rate = uint32_t(current_block->acceleration_steps_per_s2 * (float(1UL << 24) / (STEPPER_TIMER_RATE)));
|
||||
#endif
|
||||
|
||||
const uint32_t freeze_rate = STEP_MULTIPLY(frozen_time, current_block->acceleration_rate);
|
||||
const uint32_t min_step_rate = current_block->steps_per_mm * (FREEZE_JERK);
|
||||
|
||||
if (step_rate > freeze_rate)
|
||||
step_rate -= freeze_rate;
|
||||
else
|
||||
step_rate = 0;
|
||||
|
||||
if (step_rate <= min_step_rate) {
|
||||
set_frozen_solid(true);
|
||||
step_rate = min_step_rate;
|
||||
}
|
||||
}
|
||||
|
||||
void Stepper::check_frozen_state(const FreezePhase phase, const uint32_t interval) {
|
||||
switch (phase) {
|
||||
case FREEZE_STATIONARY:
|
||||
// If triggered while stationary immediately set solid flag
|
||||
if (frozen_state.triggered) {
|
||||
frozen_time = 0;
|
||||
set_frozen_solid(true);
|
||||
}
|
||||
else
|
||||
set_frozen_solid(false);
|
||||
break;
|
||||
|
||||
case FREEZE_ACCELERATION:
|
||||
// If frozen state is activated during the acceleration phase of a block we need to double our decceleration efforts
|
||||
if (frozen_state.triggered) {
|
||||
if (!frozen_state.solid) frozen_time += interval * 2;
|
||||
}
|
||||
else
|
||||
set_frozen_solid(false);
|
||||
break;
|
||||
|
||||
case FREEZE_DECELERATION:
|
||||
// If frozen state is deactivated during the deceleration phase we need to double our acceleration efforts
|
||||
if (!frozen_state.triggered) {
|
||||
if (frozen_time) {
|
||||
if (frozen_time > interval * 2)
|
||||
frozen_time -= interval * 2;
|
||||
else
|
||||
frozen_time = 0;
|
||||
}
|
||||
set_frozen_solid(false);
|
||||
}
|
||||
break;
|
||||
|
||||
case FREEZE_CRUISE:
|
||||
// During cruise stage acceleration/deceleration take place at regular rate
|
||||
if (frozen_state.triggered) {
|
||||
if (!frozen_state.solid) frozen_time += interval;
|
||||
}
|
||||
else {
|
||||
if (frozen_time) {
|
||||
if (frozen_time > interval)
|
||||
frozen_time -= interval;
|
||||
else {
|
||||
frozen_time = 0;
|
||||
ticks_nominal = 0; // Reset ticks_nominal to allow for recalculation of interval at nominal_rate
|
||||
}
|
||||
}
|
||||
set_frozen_solid(false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SOFT_FEED_HOLD
|
||||
|
|
|
|||
|
|
@ -318,6 +318,26 @@ constexpr ena_mask_t enable_overlap[] = {
|
|||
|
||||
#endif // NONLINEAR_EXTRUSION
|
||||
|
||||
#if ANY(FREEZE_FEATURE, SOFT_FEED_HOLD)
|
||||
|
||||
typedef union {
|
||||
uint8_t state;
|
||||
struct { bool triggered:1, solid:1; };
|
||||
} frozen_state_t;
|
||||
|
||||
enum FrozenState { FROZEN_TRIGGERED, FROZEN_SOLID };
|
||||
|
||||
#if ENABLED(SOFT_FEED_HOLD)
|
||||
enum FreezePhase : uint8_t {
|
||||
FREEZE_STATIONARY,
|
||||
FREEZE_ACCELERATION,
|
||||
FREEZE_DECELERATION,
|
||||
FREEZE_CRUISE
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// Stepper class definition
|
||||
//
|
||||
|
|
@ -367,8 +387,12 @@ class Stepper {
|
|||
static constexpr uint8_t last_moved_extruder = 0;
|
||||
#endif
|
||||
|
||||
#if ENABLED(FREEZE_FEATURE)
|
||||
static bool frozen; // Set this flag to instantly freeze motion
|
||||
#if ANY(FREEZE_FEATURE, SOFT_FEED_HOLD)
|
||||
static frozen_state_t frozen_state; // Frozen flags
|
||||
static void set_frozen_triggered(const bool state) { frozen_state.triggered = state; }
|
||||
#if ENABLED(SOFT_FEED_HOLD)
|
||||
static bool is_frozen_triggered() { return frozen_state.triggered; }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ENABLED(NONLINEAR_EXTRUSION)
|
||||
|
|
@ -800,6 +824,15 @@ class Stepper {
|
|||
static void ftMotion_stepper();
|
||||
#endif
|
||||
|
||||
#if ENABLED(SOFT_FEED_HOLD)
|
||||
static uint32_t frozen_time; // How much time passed since frozen_state was triggered?
|
||||
#if ENABLED(LASER_FEATURE)
|
||||
static uint8_t frozen_last_laser_power; // Saved laser power prior to halting motion
|
||||
#endif
|
||||
static void check_frozen_state(const FreezePhase type, const uint32_t interval);
|
||||
static void check_frozen_time(uint32_t &step_rate);
|
||||
static void set_frozen_solid(const bool state);
|
||||
#endif
|
||||
};
|
||||
|
||||
extern Stepper stepper;
|
||||
|
|
|
|||
|
|
@ -14,8 +14,9 @@ opt_set MOTHERBOARD BOARD_RAMPS4DUE_EFB \
|
|||
E0_AUTO_FAN_PIN 8 FANMUX0_PIN 53 EXTRUDER_AUTO_FAN_SPEED 100 \
|
||||
TEMP_SENSOR_CHAMBER 3 TEMP_CHAMBER_PIN 6 HEATER_CHAMBER_PIN 45 \
|
||||
BACKLASH_MEASUREMENT_FEEDRATE 600 \
|
||||
TRAMMING_POINT_XY '{{20,20},{20,20},{20,20},{20,20},{20,20}}' TRAMMING_POINT_NAME_5 '"Point 5"'
|
||||
opt_enable S_CURVE_ACCELERATION EEPROM_SETTINGS GCODE_MACROS GCODE_MACROS_IN_EEPROM \
|
||||
TRAMMING_POINT_XY '{{20,20},{20,20},{20,20},{20,20},{20,20}}' TRAMMING_POINT_NAME_5 '"Point 5"' \
|
||||
FREEZE_PIN 17
|
||||
opt_enable S_CURVE_ACCELERATION FREEZE_FEATURE SOFT_FEED_HOLD EEPROM_SETTINGS GCODE_MACROS GCODE_MACROS_IN_EEPROM \
|
||||
FIX_MOUNTED_PROBE Z_SAFE_HOMING CODEPENDENT_XY_HOMING \
|
||||
ASSISTED_TRAMMING REPORT_TRAMMING_MM ASSISTED_TRAMMING_WAIT_POSITION \
|
||||
EEPROM_SETTINGS SDSUPPORT BINARY_FILE_TRANSFER \
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue