Spindle speed overrides behavior tweak. New experimental laser dynamic power mode.
- Spindle speed overrides now update immediately if they are changed while in a HOLD state. Previously, they would update after exiting the HOLD, which isn’t correct. - New experimental dynamic laser power mode that adjusts laser power based on current machine speed. Enabled by uncommenting LASER_CONSTANT_POWER_PER_RATE in config.h - It assumes the programmed rate is the intended power/rate for the motion. - Feed rate overrides (FRO) do not effect the power/rate. Meaning that spindle PWM will automatically lower with lower FRO and increase with higher FRO to keep it the same. - Spindle speed overrides (SSO) will directly increase and decrease the power/rate. So 150% SSO will increase the PWM output by 150% for the same speed. - The combination of FRO and SSO behaviors should allow for subtle and highly flexible tuning of how the laser cutter is operating in real-time and during the job. - Re-factored planner block rapid rate handling for the dynamic laser power feature. Should have had no effect on how Grbl operates.
This commit is contained in:
parent
cb916a996a
commit
e8b717604b
@ -1,3 +1,19 @@
|
||||
----------------
|
||||
Date: 2016-10-26
|
||||
Author: Sonny Jeon
|
||||
Subject: Add high-frequency spindle output option. Minor parking motion re-factoring.
|
||||
|
||||
- Some laser controllers were reported to need a very high PWM
|
||||
frequency. Added a line to enable this in cpu_map.h, if needed.
|
||||
|
||||
- Cleaned up some of the parking code. Mostly just editing the comments.
|
||||
|
||||
- Moved the accessory state resetting after the initial parking
|
||||
retract. Should ensure the accessory state is properly handled upon an
|
||||
aborted parking restore. Not certain if this was a problem before
|
||||
though. Just to be sure.
|
||||
|
||||
|
||||
----------------
|
||||
Date: 2016-10-25
|
||||
Author: chamnit
|
||||
|
@ -570,6 +570,11 @@
|
||||
#define PARKING_PULLOUT_INCREMENT 5.0 // Spindle pull-out and plunge distance in mm. Incremental distance.
|
||||
// Must be positive value or equal to zero.
|
||||
|
||||
// Experimental feature that adjusts laser power (PWM output) based on current running speed of the
|
||||
// machine. When laser mode is enabled, Grbl will turn off the spindle PWM pin whenever it is not
|
||||
// moving, which may be confusing to some users to why their laser is not on. This behavior may change
|
||||
// in future iterations of this feature, where it will turn on to the minimum rpm value when active.
|
||||
// #define LASER_CONSTANT_POWER_PER_RATE
|
||||
|
||||
/* ---------------------------------------------------------------------------------------
|
||||
OEM Single File Configuration Option
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
// Grbl versioning system
|
||||
#define GRBL_VERSION "1.1d"
|
||||
#define GRBL_VERSION_BUILD "20161026"
|
||||
#define GRBL_VERSION_BUILD "20161027"
|
||||
|
||||
// Define standard libraries used by Grbl.
|
||||
#include <avr/io.h>
|
||||
|
@ -258,12 +258,9 @@ uint8_t plan_check_full_buffer()
|
||||
// NOTE: All system motion commands, such as homing/parking, are not subject to overrides.
|
||||
float plan_compute_profile_nominal_speed(plan_block_t *block)
|
||||
{
|
||||
float nominal_speed;
|
||||
if (block->condition & PL_COND_FLAG_RAPID_MOTION) {
|
||||
nominal_speed = block->rapid_rate;
|
||||
nominal_speed *= (0.01*sys.r_override);
|
||||
} else {
|
||||
nominal_speed = block->programmed_rate;
|
||||
float nominal_speed = block->programmed_rate;
|
||||
if (block->condition & PL_COND_FLAG_RAPID_MOTION) { nominal_speed *= (0.01*sys.r_override); }
|
||||
else {
|
||||
if (!(block->condition & PL_COND_FLAG_NO_FEED_OVERRIDE)) { nominal_speed *= (0.01*sys.f_override); }
|
||||
if (nominal_speed > block->rapid_rate) { nominal_speed = block->rapid_rate; }
|
||||
}
|
||||
@ -385,8 +382,11 @@ uint8_t plan_buffer_line(float *target, plan_line_data_t *pl_data)
|
||||
block->rapid_rate = limit_value_by_axis_maximum(settings.max_rate, unit_vec);
|
||||
|
||||
// Store programmed rate.
|
||||
block->programmed_rate = pl_data->feed_rate;
|
||||
if (block->condition & PL_COND_FLAG_INVERSE_TIME) { block->programmed_rate *= block->millimeters; }
|
||||
if (block->condition & PL_COND_FLAG_RAPID_MOTION) { block->programmed_rate = block->rapid_rate; }
|
||||
else {
|
||||
block->programmed_rate = pl_data->feed_rate;
|
||||
if (block->condition & PL_COND_FLAG_INVERSE_TIME) { block->programmed_rate *= block->millimeters; }
|
||||
}
|
||||
|
||||
// TODO: Need to check this method handling zero junction speeds when starting from rest.
|
||||
if ((block_buffer_head == block_buffer_tail) || (block->condition & PL_COND_FLAG_SYSTEM_MOTION)) {
|
||||
|
@ -45,6 +45,7 @@
|
||||
#define PL_COND_FLAG_SPINDLE_CCW bit(5)
|
||||
#define PL_COND_FLAG_COOLANT_FLOOD bit(6)
|
||||
#define PL_COND_FLAG_COOLANT_MIST bit(7)
|
||||
#define PL_COND_MOTION_MASK (PL_COND_FLAG_RAPID_MOTION|PL_COND_FLAG_SYSTEM_MOTION|PL_COND_FLAG_NO_FEED_OVERRIDE)
|
||||
#define PL_COND_ACCESSORY_MASK (PL_COND_FLAG_SPINDLE_CW|PL_COND_FLAG_SPINDLE_CCW|PL_COND_FLAG_COOLANT_FLOOD|PL_COND_FLAG_COOLANT_MIST)
|
||||
|
||||
|
||||
|
@ -698,32 +698,39 @@ static void protocol_exec_rt_suspend()
|
||||
|
||||
// Feed hold manager. Controls spindle stop override states.
|
||||
// NOTE: Hold ensured as completed by condition check at the beginning of suspend routine.
|
||||
if (sys.spindle_stop_ovr & SPINDLE_STOP_OVR_INITIATE) { // Handles beginning of spindle stop
|
||||
|
||||
if (gc_state.modal.spindle != SPINDLE_DISABLE) {
|
||||
spindle_set_state(SPINDLE_DISABLE,0.0); // De-energize
|
||||
sys.spindle_stop_ovr = SPINDLE_STOP_OVR_ENABLED; // Set stop override state to enabled, if de-energized.
|
||||
} else {
|
||||
if (sys.spindle_stop_ovr) {
|
||||
// Handles beginning of spindle stop
|
||||
if (sys.spindle_stop_ovr & SPINDLE_STOP_OVR_INITIATE) {
|
||||
if (gc_state.modal.spindle != SPINDLE_DISABLE) {
|
||||
spindle_set_state(SPINDLE_DISABLE,0.0); // De-energize
|
||||
sys.spindle_stop_ovr = SPINDLE_STOP_OVR_ENABLED; // Set stop override state to enabled, if de-energized.
|
||||
} else {
|
||||
sys.spindle_stop_ovr = SPINDLE_STOP_OVR_DISABLED; // Clear stop override state
|
||||
}
|
||||
// Handles restoring of spindle state
|
||||
} else if (sys.spindle_stop_ovr & (SPINDLE_STOP_OVR_RESTORE | SPINDLE_STOP_OVR_RESTORE_CYCLE)) {
|
||||
if (gc_state.modal.spindle != SPINDLE_DISABLE) {
|
||||
report_feedback_message(MESSAGE_SPINDLE_RESTORE);
|
||||
if (bit_istrue(settings.flags,BITFLAG_LASER_MODE)) {
|
||||
// When in laser mode, ignore spindle spin-up delay. Set to turn on laser when cycle starts.
|
||||
bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM);
|
||||
} else {
|
||||
spindle_set_state((restore_condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)), restore_spindle_speed);
|
||||
delay_sec(SAFETY_DOOR_SPINDLE_DELAY, DELAY_MODE_SYS_SUSPEND);
|
||||
}
|
||||
}
|
||||
if (sys.spindle_stop_ovr & SPINDLE_STOP_OVR_RESTORE_CYCLE) {
|
||||
system_set_exec_state_flag(EXEC_CYCLE_START); // Set to resume program.
|
||||
}
|
||||
sys.spindle_stop_ovr = SPINDLE_STOP_OVR_DISABLED; // Clear stop override state
|
||||
}
|
||||
|
||||
} else if (sys.spindle_stop_ovr & (SPINDLE_STOP_OVR_RESTORE | SPINDLE_STOP_OVR_RESTORE_CYCLE)) { // Handles restoring of spindle state
|
||||
|
||||
if (gc_state.modal.spindle != SPINDLE_DISABLE) {
|
||||
report_feedback_message(MESSAGE_SPINDLE_RESTORE);
|
||||
if (bit_istrue(settings.flags,BITFLAG_LASER_MODE)) {
|
||||
// When in laser mode, ignore spindle spin-up delay. Set to turn on laser when cycle starts.
|
||||
bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM);
|
||||
} else {
|
||||
spindle_set_state((restore_condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)), restore_spindle_speed);
|
||||
delay_sec(SAFETY_DOOR_SPINDLE_DELAY, DELAY_MODE_SYS_SUSPEND);
|
||||
}
|
||||
} else {
|
||||
// Handles spindle state during hold. NOTE: Spindle speed overrides may be altered during hold state.
|
||||
// NOTE: STEP_CONTROL_UPDATE_SPINDLE_PWM is automatically reset upon resume in step generator.
|
||||
if (bit_istrue(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM)) {
|
||||
spindle_set_state((restore_condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)), restore_spindle_speed);
|
||||
bit_false(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM);
|
||||
}
|
||||
if (sys.spindle_stop_ovr & SPINDLE_STOP_OVR_RESTORE_CYCLE) {
|
||||
system_set_exec_state_flag(EXEC_CYCLE_START); // Set to resume program.
|
||||
}
|
||||
sys.spindle_stop_ovr = SPINDLE_STOP_OVR_DISABLED; // Clear stop override state
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -154,7 +154,7 @@ void spindle_stop()
|
||||
// Compute intermediate PWM value with linear spindle speed model.
|
||||
// NOTE: A nonlinear model could be installed here, if required, but keep it light-weight.
|
||||
sys.spindle_speed = rpm;
|
||||
pwm_value = floor( (rpm-settings.rpm_min)*pwm_gradient + (SPINDLE_PWM_MIN_VALUE+0.5));
|
||||
pwm_value = floor( (rpm-settings.rpm_min)*pwm_gradient + (SPINDLE_PWM_MIN_VALUE+0.5) );
|
||||
}
|
||||
return(pwm_value);
|
||||
}
|
||||
@ -189,6 +189,10 @@ void spindle_stop()
|
||||
#endif
|
||||
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
#ifdef LASER_CONSTANT_POWER_PER_RATE
|
||||
// NOTE: Assumes all calls to this function is when Grbl is not moving or must remain off.
|
||||
if (settings.flags & BITFLAG_LASER_MODE) { rpm = 0.0; } // TODO: May need to be rpm_min*(100/MAX_SPINDLE_SPEED_OVERRIDE);
|
||||
#endif
|
||||
spindle_set_speed(spindle_compute_pwm_value(rpm));
|
||||
#else
|
||||
// NOTE: Without variable spindle, the enable bit should just turn on or off, regardless
|
||||
|
@ -151,6 +151,10 @@ typedef struct {
|
||||
float exit_speed; // Exit speed of executing block (mm/min)
|
||||
float accelerate_until; // Acceleration ramp end measured from end of block (mm)
|
||||
float decelerate_after; // Deceleration ramp start measured from end of block (mm)
|
||||
|
||||
#ifdef LASER_CONSTANT_POWER_PER_RATE
|
||||
float inv_rate; // Used by PWM laser mode
|
||||
#endif
|
||||
} st_prep_t;
|
||||
static st_prep_t prep;
|
||||
|
||||
@ -644,6 +648,11 @@ void st_prep_buffer()
|
||||
} else {
|
||||
prep.current_speed = sqrt(pl_block->entry_speed_sqr);
|
||||
}
|
||||
|
||||
#ifdef LASER_CONSTANT_POWER_PER_RATE
|
||||
// Pre-compute inverse programmed rate to speed up PWM updating per step segment.
|
||||
prep.inv_rate = 1.0/pl_block->programmed_rate;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------
|
||||
@ -742,19 +751,6 @@ void st_prep_buffer()
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
if (sys.step_control & STEP_CONTROL_UPDATE_SPINDLE_PWM) {
|
||||
// Configure correct spindle PWM state for block. Updates with planner changes and spindle speed overrides.
|
||||
if (pl_block->condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)) {
|
||||
st_prep_block->spindle_pwm = spindle_compute_pwm_value(pl_block->spindle_speed);
|
||||
} else {
|
||||
sys.spindle_speed = 0.0;
|
||||
st_prep_block->spindle_pwm = SPINDLE_PWM_OFF_VALUE;
|
||||
}
|
||||
bit_false(sys.step_control,STEP_CONTROL_UPDATE_SPINDLE_PWM);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Initialize new segment
|
||||
segment_t *prep_segment = &segment_buffer[segment_buffer_head];
|
||||
|
||||
@ -860,6 +856,35 @@ void st_prep_buffer()
|
||||
}
|
||||
} while (mm_remaining > prep.mm_complete); // **Complete** Exit loop. Profile complete.
|
||||
|
||||
/* -----------------------------------------------------------------------------------
|
||||
Compute spindle speed PWM output for step segment
|
||||
*/
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
|
||||
#ifdef LASER_CONSTANT_POWER_PER_RATE
|
||||
if ((settings.flags & BITFLAG_LASER_MODE) || (sys.step_control & STEP_CONTROL_UPDATE_SPINDLE_PWM)) {
|
||||
#else
|
||||
if (sys.step_control & STEP_CONTROL_UPDATE_SPINDLE_PWM) {
|
||||
#endif
|
||||
if (pl_block->condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)) {
|
||||
float rpm = pl_block->spindle_speed;
|
||||
#ifdef LASER_CONSTANT_POWER_PER_RATE
|
||||
// NOTE: Feed and rapid overrides are independent of PWM value and do not alter laser power/rate.
|
||||
if (settings.flags & BITFLAG_LASER_MODE) {
|
||||
// If current_speed is zero, then may need to be rpm_min*(100/MAX_SPINDLE_SPEED_OVERRIDE)
|
||||
// but this would be instantaneous only and during a motion. May not matter at all.
|
||||
rpm *= (prep.current_speed * prep.inv_rate);
|
||||
}
|
||||
#endif
|
||||
st_prep_block->spindle_pwm = spindle_compute_pwm_value(rpm);
|
||||
} else {
|
||||
sys.spindle_speed = 0.0;
|
||||
st_prep_block->spindle_pwm = SPINDLE_PWM_OFF_VALUE;
|
||||
}
|
||||
bit_false(sys.step_control,STEP_CONTROL_UPDATE_SPINDLE_PWM);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* -----------------------------------------------------------------------------------
|
||||
Compute segment step rate, steps to execute, and apply necessary rate corrections.
|
||||
@ -976,8 +1001,8 @@ void st_prep_buffer()
|
||||
// divided by the ACCELERATION TICKS PER SECOND in seconds.
|
||||
float st_get_realtime_rate()
|
||||
{
|
||||
if (sys.state & (STATE_CYCLE | STATE_HOMING | STATE_HOLD | STATE_JOG | STATE_SAFETY_DOOR)){
|
||||
return prep.current_speed;
|
||||
}
|
||||
if (sys.state & (STATE_CYCLE | STATE_HOMING | STATE_HOLD | STATE_JOG | STATE_SAFETY_DOOR)){
|
||||
return prep.current_speed;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user