Re-factored system states and alarm management. Serial baud support greater than 57600.

- Refactored system states to be more clear and concise. Alarm locks
processes when position is unknown to indicate to user something has
gone wrong.

- Changed mc_alarm to mc_reset, which now manages the system reset
function. Centralizes it.

- Renamed '$X' kill homing lock to kill alarm lock.

- Created an alarm error reporting method to clear up what is an alarm:
message vs a status error: message. For GUIs mainly. Alarm codes are
negative. Status codes are positive.

- Serial baud support upto 115200. Previous baudrate calc was unstable
for 57600 and above.

- Alarm state locks out all g-code blocks, including startup scripts,
but allows user to access settings and internal commands. For example,
to disable hard limits, if they are problematic.

- Hard limits do not respond in an alarm state.

- Fixed a problem with the hard limit interrupt during the homing
cycle. The interrupt register is still active during the homing cycle
and still signal the interrupt to trigger when re-enabled. Instead,
just disabled the register.

- Homing rate adjusted. All axes move at homing seek rate, regardless
of how many axes move at the same time. This is unlike how the stepper
module does it as a point to point rate.

- New config.h settings to disable the homing rate adjustment and the
force homing upon powerup.

- Reduced the number of startup lines back down to 2 from 3. This
discourages users from placing motion block in there, which can be very
dangerous.

- Startup blocks now run only after an alarm-free reset or after a
homing cycle. Does not run when $X kill is called. For satefy reasons
This commit is contained in:
Sonny Jeon 2012-11-14 17:36:29 -07:00
parent e6ad15b548
commit 559feb97e2
14 changed files with 466 additions and 420 deletions

View File

@ -69,9 +69,9 @@
#define COOLANT_FLOOD_PORT PORTC #define COOLANT_FLOOD_PORT PORTC
#define COOLANT_FLOOD_BIT 3 // Uno Analog Pin 3 #define COOLANT_FLOOD_BIT 3 // Uno Analog Pin 3
// #define ENABLE_M7 // Mist coolant disabled by default. Uncomment to enable.
// NOTE: Uno analog pins 4 and 5 are reserved for an i2c interface, and may be installed at // NOTE: Uno analog pins 4 and 5 are reserved for an i2c interface, and may be installed at
// a later date if flash and memory space allows. // a later date if flash and memory space allows.
// #define ENABLE_M7 // Mist coolant disabled by default. Uncomment to enable.
#ifdef ENABLE_M7 #ifdef ENABLE_M7
#define COOLANT_MIST_DDR DDRC #define COOLANT_MIST_DDR DDRC
#define COOLANT_MIST_PORT PORTC #define COOLANT_MIST_PORT PORTC
@ -158,6 +158,18 @@
// time step. Also, keep in mind that the Arduino delay timer is not very accurate for long delays. // time step. Also, keep in mind that the Arduino delay timer is not very accurate for long delays.
#define DWELL_TIME_STEP 50 // Integer (1-255) (milliseconds) #define DWELL_TIME_STEP 50 // Integer (1-255) (milliseconds)
// If homing is enabled, homing init lock sets Grbl into an alarm state upon power up. This forces
// the user to perform the homing cycle (or override the locks) before doing anything else. This is
// mainly a safety feature to remind the user to home, since position is unknown to Grbl.
#define HOMING_INIT_LOCK // Comment to disable
// The homing cycle seek and feed rates will adjust so all axes independently move at the homing
// seek and feed rates regardless of how many axes are in motion simultaneously. If disabled, rates
// are point-to-point rates, as done in normal operation. For example in an XY diagonal motion, the
// diagonal motion moves at the intended rate, but the individual axes move at 70% speed. This option
// just moves them all at 100% speed.
#define HOMING_RATE_ADJUST // Comment to disable
// Number of homing cycles performed after when the machine initially jogs to limit switches. // Number of homing cycles performed after when the machine initially jogs to limit switches.
// This help in preventing overshoot and should improve repeatability. This value should be one or // This help in preventing overshoot and should improve repeatability. This value should be one or
// greater. // greater.
@ -167,7 +179,7 @@
// and addresses are defined in settings.h. With the current settings, up to 5 startup blocks may // and addresses are defined in settings.h. With the current settings, up to 5 startup blocks may
// be stored and executed in order. These startup blocks would typically be used to set the g-code // be stored and executed in order. These startup blocks would typically be used to set the g-code
// parser state depending on user preferences. // parser state depending on user preferences.
#define N_STARTUP_LINE 3 // Integer (1-5) #define N_STARTUP_LINE 2 // Integer (1-5)
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
// FOR ADVANCED USERS ONLY: // FOR ADVANCED USERS ONLY:

View File

@ -84,6 +84,11 @@ static float to_millimeters(float value)
// internal functions in terms of (mm, mm/min) and absolute machine coordinates, respectively. // internal functions in terms of (mm, mm/min) and absolute machine coordinates, respectively.
uint8_t gc_execute_line(char *line) uint8_t gc_execute_line(char *line)
{ {
// If in alarm state, don't process. Immediately return with error.
// NOTE: Might not be right place for this, but also prevents $N storing during alarm.
if (sys.state == STATE_ALARM) { return(STATUS_ALARM_LOCK); }
uint8_t char_counter = 0; uint8_t char_counter = 0;
char letter; char letter;
float value; float value;
@ -545,7 +550,7 @@ uint8_t gc_execute_line(char *line)
// If complete, reset to reload defaults (G92.2,G54,G17,G90,G94,M48,G40,M5,M9). Otherwise, // If complete, reset to reload defaults (G92.2,G54,G17,G90,G94,M48,G40,M5,M9). Otherwise,
// re-enable program flow after pause complete, where cycle start will resume the program. // re-enable program flow after pause complete, where cycle start will resume the program.
if (gc.program_flow == PROGRAM_FLOW_COMPLETED) { sys.execute |= EXEC_RESET; } if (gc.program_flow == PROGRAM_FLOW_COMPLETED) { mc_reset(); }
else { gc.program_flow = PROGRAM_FLOW_RUNNING; } else { gc.program_flow = PROGRAM_FLOW_RUNNING; }
} }

View File

@ -43,27 +43,38 @@ void limits_init()
if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) { if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) {
LIMIT_PCMSK |= LIMIT_MASK; // Enable specific pins of the Pin Change Interrupt LIMIT_PCMSK |= LIMIT_MASK; // Enable specific pins of the Pin Change Interrupt
PCICR |= (1 << LIMIT_INT); // Enable Pin Change Interrupt PCICR |= (1 << LIMIT_INT); // Enable Pin Change Interrupt
} else {
LIMIT_PCMSK &= ~LIMIT_MASK; // Disable
PCICR &= ~(1 << LIMIT_INT);
} }
} }
// This is the Limit Pin Change Interrupt, which handles the hard limit feature. // This is the Limit Pin Change Interrupt, which handles the hard limit feature. A bouncing
// limit switch can cause a lot of problems, like false readings and multiple interrupt calls.
// If a switch is triggered at all, something bad has happened and treat it as such, regardless
// if a limit switch is being disengaged. It's impossible to reliably tell the state of a
// bouncing pin without a debouncing method.
// NOTE: Do not attach an e-stop to the limit pins, because this interrupt is disabled during // NOTE: Do not attach an e-stop to the limit pins, because this interrupt is disabled during
// homing cycles and will not respond correctly. Upon user request or need, there may be a // homing cycles and will not respond correctly. Upon user request or need, there may be a
// special pinout for an e-stop, but it is generally recommended to just directly connect // special pinout for an e-stop, but it is generally recommended to just directly connect
// your e-stop switch to the Arduino reset pin, since it is the most correct way to do this. // your e-stop switch to the Arduino reset pin, since it is the most correct way to do this.
ISR(LIMIT_INT_vect)
{
// TODO: This interrupt may be used to manage the homing cycle directly with the main stepper // TODO: This interrupt may be used to manage the homing cycle directly with the main stepper
// interrupt without adding too much to it. All it would need is some way to stop one axis // interrupt without adding too much to it. All it would need is some way to stop one axis
// when its limit is triggered and continue the others. This may reduce some of the code, but // when its limit is triggered and continue the others. This may reduce some of the code, but
// would make Grbl a little harder to read and understand down road. Holding off on this until // would make Grbl a little harder to read and understand down road. Holding off on this until
// we move on to new hardware or flash space becomes an issue. If it ain't broke, don't fix it. // we move on to new hardware or flash space becomes an issue. If it ain't broke, don't fix it.
ISR(LIMIT_INT_vect)
{ // Ignore limit switches if already in an alarm state or in-process of executing an alarm.
// Only enter if the system alarm is not active. // When in the alarm state, Grbl should have been reset or will force a reset, so any pending
// moves in the planner and serial buffers are all cleared and newly sent blocks will be
// locked out until a homing cycle or a kill lock command. Allows the user to disable the hard
// limit setting if their limits are constantly triggering after a reset and move their axes.
if (sys.state != STATE_ALARM) {
if (bit_isfalse(sys.execute,EXEC_ALARM)) { if (bit_isfalse(sys.execute,EXEC_ALARM)) {
// Kill all processes upon hard limit event. mc_reset(); // Initiate system kill.
if ((LIMIT_PIN & LIMIT_MASK) ^ LIMIT_MASK) { sys.execute |= EXEC_CRIT_EVENT; // Indicate hard limit critical event
mc_alarm(); // Initiate system kill.
sys.state = STATE_LIMIT; // Set system state to indicate event.
} }
} }
} }
@ -104,6 +115,11 @@ static void homing_cycle(bool x_axis, bool y_axis, bool z_axis, int8_t pos_dir,
// Compute the adjusted step rate change with each acceleration tick. (in step/min/acceleration_tick) // Compute the adjusted step rate change with each acceleration tick. (in step/min/acceleration_tick)
uint32_t delta_rate = ceil( ds*settings.acceleration/(60*ACCELERATION_TICKS_PER_SECOND)); uint32_t delta_rate = ceil( ds*settings.acceleration/(60*ACCELERATION_TICKS_PER_SECOND));
#ifdef HOMING_RATE_ADJUST
// Adjust homing rate so a multiple axes moves all at the homing rate independently.
homing_rate *= sqrt(x_axis+y_axis+z_axis);
#endif
// Nominal and initial time increment per step. Nominal should always be greater then 3 // Nominal and initial time increment per step. Nominal should always be greater then 3
// usec, since they are based on the same parameters as the main stepper routine. Initial // usec, since they are based on the same parameters as the main stepper routine. Initial
// is based on the MINIMUM_STEPS_PER_MINUTE config. Since homing feed can be very slow, // is based on the MINIMUM_STEPS_PER_MINUTE config. Since homing feed can be very slow,
@ -191,12 +207,13 @@ static void homing_cycle(bool x_axis, bool y_axis, bool z_axis, int8_t pos_dir,
void limits_go_home() void limits_go_home()
{ {
// Enable only the steppers, not the cycle. Cycle should be complete. // Enable only the steppers, not the cycle. Cycle should be inactive/complete.
st_wake_up(); st_wake_up();
// Jog all axes toward home to engage their limit switches at faster homing seek rate. // Jog all axes toward home to engage their limit switches at faster homing seek rate.
homing_cycle(false, false, true, true, false, settings.homing_seek_rate); // First jog the z axis // First jog z-axis to clear workspace, then jog the x and y axis.
homing_cycle(true, true, false, true, false, settings.homing_seek_rate); // Then jog the x and y axis homing_cycle(false, false, true, true, false, settings.homing_seek_rate); // z-axis
homing_cycle(true, true, false, true, false, settings.homing_seek_rate); // xy-axes
delay_ms(settings.homing_debounce_delay); // Delay to debounce signal delay_ms(settings.homing_debounce_delay); // Delay to debounce signal
// Now in proximity of all limits. Carefully leave and approach switches in multiple cycles // Now in proximity of all limits. Carefully leave and approach switches in multiple cycles

38
main.c
View File

@ -45,14 +45,14 @@ system_t sys;
int main(void) int main(void)
{ {
// Initialize system // Initialize system
serial_init(BAUD_RATE); // Setup serial baud rate and interrupts serial_init(); // Setup serial baud rate and interrupts
settings_init(); // Load grbl settings from EEPROM settings_init(); // Load grbl settings from EEPROM
st_init(); // Setup stepper pins and interrupt timers st_init(); // Setup stepper pins and interrupt timers
sei(); // Enable interrupts sei(); // Enable interrupts
memset(&sys, 0, sizeof(sys)); // Clear all system variables memset(&sys, 0, sizeof(sys)); // Clear all system variables
sys.abort = true; // Set abort to complete initialization sys.abort = true; // Set abort to complete initialization
sys.state = STATE_ALARM; // Set alarm state to indicate unknown initial position sys.state = STATE_INIT; // Set alarm state to indicate unknown initial position
for(;;) { for(;;) {
@ -60,7 +60,6 @@ int main(void)
// Once here, it is safe to re-initialize the system. At startup, the system will automatically // Once here, it is safe to re-initialize the system. At startup, the system will automatically
// reset to finish the initialization process. // reset to finish the initialization process.
if (sys.abort) { if (sys.abort) {
// Reset system. // Reset system.
serial_reset_read_buffer(); // Clear serial read buffer serial_reset_read_buffer(); // Clear serial read buffer
plan_init(); // Clear block buffer and planner variables plan_init(); // Clear block buffer and planner variables
@ -72,29 +71,34 @@ int main(void)
st_reset(); // Clear stepper subsystem variables. st_reset(); // Clear stepper subsystem variables.
// Sync cleared gcode and planner positions to current system position, which is only // Sync cleared gcode and planner positions to current system position, which is only
// cleared upon startup, not a reset/abort. If Grbl does not know or can ensure its // cleared upon startup, not a reset/abort.
// position, a feedback message will be sent back to the user to let them know. Also,
// if position is lost and homing is enabled, the axes motions will be locked, and
// user must either perform the homing cycle '$H' or purge the system locks '$P' to
// resume.
sys_sync_current_position(); sys_sync_current_position();
// Reset system variables. // Reset system variables.
sys.abort = false; sys.abort = false;
sys.execute = 0; sys.execute = 0;
if (sys.state == STATE_ALARM && bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) {
// Position has either been lost from a critical event or a power cycle reboot. If
// homing is enabled, force user to home to get machine position. Otherwise, let the
// user manage position on their own.
report_feedback_message(MESSAGE_HOMING_ALARM);
} else {
sys.state = STATE_IDLE;
}
if (bit_istrue(settings.flags,BITFLAG_AUTO_START)) { sys.auto_start = true; } if (bit_istrue(settings.flags,BITFLAG_AUTO_START)) { sys.auto_start = true; }
// Execute user startup script // Check for power-up and set system alarm if homing is enabled to force homing cycle
// by setting Grbl's alarm state. Alarm locks out all g-code commands, including the
// startup scripts, but allows access to settings and internal commands. Only a homing
// cycle '$H' or kill alarm locks '$X' will disable the alarm.
// NOTE: The startup script will run after successful completion of the homing cycle, but
// not after disabling the alarm locks. Prevents motion startup blocks from crashing into
// things uncontrollably. Very bad.
#ifdef HOMING_INIT_LOCK
if (sys.state == STATE_INIT && bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) { sys.state = STATE_ALARM; }
#endif
// Check for and report alarm state after a reset, error, or an initial power up.
if (sys.state == STATE_ALARM) {
report_feedback_message(MESSAGE_ALARM_LOCK);
} else {
// All systems go. Set system to ready and execute startup script.
sys.state = STATE_IDLE;
protocol_execute_startup(); protocol_execute_startup();
} }
}
protocol_execute_runtime(); protocol_execute_runtime();
protocol_process(); // ... process the serial protocol protocol_process(); // ... process the serial protocol

View File

@ -67,10 +67,8 @@ void mc_line(float x, float y, float z, float feed_rate, uint8_t invert_feed_rat
if (bit_isfalse(gc.switches,BITFLAG_CHECK_GCODE)) { if (bit_isfalse(gc.switches,BITFLAG_CHECK_GCODE)) {
plan_buffer_line(x, y, z, feed_rate, invert_feed_rate); plan_buffer_line(x, y, z, feed_rate, invert_feed_rate);
// Indicate to the system there is now a planned block in the buffer ready to cycle start. // If idle, indicate to the system there is now a planned block in the buffer ready to cycle
// NOTE: If homing cycles are enabled, a position lost state will lock out all motions, // start. Otherwise ignore and continue on.
// until a homing cycle has been completed. This is a safety feature to help prevent
// the machine from crashing.
if (!sys.state) { sys.state = STATE_QUEUED; } if (!sys.state) { sys.state = STATE_QUEUED; }
// Auto-cycle start immediately after planner finishes. Enabled/disabled by grbl settings. During // Auto-cycle start immediately after planner finishes. Enabled/disabled by grbl settings. During
@ -214,13 +212,10 @@ void mc_dwell(float seconds)
void mc_go_home() void mc_go_home()
{ {
sys.state = STATE_HOMING; // Set system state variable sys.state = STATE_HOMING; // Set system state variable
PCICR &= ~(1 << LIMIT_INT); // Disable hard limits pin change interrupt LIMIT_PCMSK &= ~LIMIT_MASK; // Disable hard limits pin change register for cycle duration
limits_go_home(); // Perform homing routine. limits_go_home(); // Perform homing routine.
if (sys.abort) { if (sys.abort) { return; } // Did not complete. Alarm state set by mc_alarm.
sys.state = STATE_ALARM; // Homing routine did not complete.
return;
}
// The machine should now be homed and machine zero has been located. Upon completion, // The machine should now be homed and machine zero has been located. Upon completion,
// reset system position and sync internal position vectors. // reset system position and sync internal position vectors.
@ -237,32 +232,42 @@ void mc_go_home()
if (bit_istrue(settings.homing_dir_mask,bit(Y_DIRECTION_BIT))) { y_dir = 1; } if (bit_istrue(settings.homing_dir_mask,bit(Y_DIRECTION_BIT))) { y_dir = 1; }
if (bit_istrue(settings.homing_dir_mask,bit(Z_DIRECTION_BIT))) { z_dir = 1; } if (bit_istrue(settings.homing_dir_mask,bit(Z_DIRECTION_BIT))) { z_dir = 1; }
mc_line(x_dir*settings.homing_pulloff, y_dir*settings.homing_pulloff, mc_line(x_dir*settings.homing_pulloff, y_dir*settings.homing_pulloff,
z_dir*settings.homing_pulloff, settings.homing_feed_rate, false); z_dir*settings.homing_pulloff, settings.homing_seek_rate, false);
st_cycle_start(); // Move it. Nothing should be in the buffer except this motion. st_cycle_start(); // Move it. Nothing should be in the buffer except this motion.
plan_synchronize(); // Make sure the motion completes. plan_synchronize(); // Make sure the motion completes.
// The gcode parser position was circumvented by the pull-off maneuver, so sync position vectors. // The gcode parser position was circumvented by the pull-off maneuver, so sync position vectors.
sys_sync_current_position(); sys_sync_current_position();
// If hard limits feature enabled, re-enable hard limits interrupt after homing cycle. // If hard limits feature enabled, re-enable hard limits pin change register after homing cycle.
if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) { PCICR |= (1 << LIMIT_INT); } if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) { LIMIT_PCMSK |= LIMIT_MASK; }
// Finished! // Finished!
} }
// Method to immediately kill all motion and set system alarm. Used by system abort, hard limits, // Method to ready the system to reset by setting the runtime reset command and killing any
// and upon g-code parser error (when installed). // active processes in the system. This also checks if a system reset is issued while Grbl
void mc_alarm() // is in a motion state. If so, kills the steppers and sets the system alarm to flag position
// lost, since there was an abrupt uncontrolled deceleration. Called at an interrupt level by
// runtime abort command and hard limits. So, keep to a minimum.
void mc_reset()
{ {
// Only this function can set the system alarm. This is done to prevent multiple kill calls // Only this function can set the system reset. Helps prevent multiple kill calls.
// by different processes. if (bit_isfalse(sys.execute, EXEC_RESET)) {
if (bit_isfalse(sys.execute, EXEC_ALARM)) { sys.execute |= EXEC_RESET;
// Set system alarm flag to have the main program check for anything wrong with shutting
// down the system. // Kill spindle and coolant.
sys.execute |= EXEC_ALARM;
// Immediately force stepper, spindle, and coolant to stop.
st_go_idle();
spindle_stop(); spindle_stop();
coolant_stop(); coolant_stop();
// Kill steppers only if in any motion state, i.e. cycle, feed hold, homing, or jogging
// NOTE: If steppers are kept enabled via the step idle delay setting, this also keeps
// the steppers enabled by avoiding the go_idle call altogether, unless the motion state is
// violated, by which, all bets are off.
switch (sys.state) {
case STATE_CYCLE: case STATE_HOLD: case STATE_HOMING: // case STATE_JOG:
sys.execute |= EXEC_ALARM; // Execute alarm state.
st_go_idle(); // Execute alarm force kills steppers. Position likely lost.
}
} }
} }

View File

@ -43,7 +43,7 @@ void mc_dwell(float seconds);
// Perform homing cycle to locate machine zero. Requires limit switches. // Perform homing cycle to locate machine zero. Requires limit switches.
void mc_go_home(); void mc_go_home();
// Kills all motion and sets system alarm // Performs system reset. If in motion state, kills all motion and sets system alarm.
void mc_alarm(); void mc_reset();
#endif #endif

View File

@ -140,7 +140,7 @@ void delay_us(uint32_t us)
} }
} }
// Syncs all internal position vectors to the current system position.
void sys_sync_current_position() void sys_sync_current_position()
{ {
plan_set_current_position(sys.position[X_AXIS],sys.position[Y_AXIS],sys.position[Z_AXIS]); plan_set_current_position(sys.position[X_AXIS],sys.position[Y_AXIS],sys.position[Z_AXIS]);

View File

@ -63,31 +63,29 @@
#define EXEC_FEED_HOLD bit(3) // bitmask 00001000 #define EXEC_FEED_HOLD bit(3) // bitmask 00001000
#define EXEC_RESET bit(4) // bitmask 00010000 #define EXEC_RESET bit(4) // bitmask 00010000
#define EXEC_ALARM bit(5) // bitmask 00100000 #define EXEC_ALARM bit(5) // bitmask 00100000
// #define bit(6) // bitmask 01000000 #define EXEC_CRIT_EVENT bit(6) // bitmask 01000000
// #define bit(7) // bitmask 10000000 // #define bit(7) // bitmask 10000000
// Define system state bit map. The state variable primarily tracks the individual functions // Define system state bit map. The state variable primarily tracks the individual functions
// of Grbl to manage each without overlapping. It is also used as a messaging flag for // of Grbl to manage each without overlapping. It is also used as a messaging flag for
// critical events. // critical events.
#define STATE_IDLE 0 // Must be zero. #define STATE_IDLE 0 // Must be zero.
#define STATE_QUEUED 1 // Indicates buffered blocks, awaiting cycle start. #define STATE_INIT 1 // Initial power up state.
#define STATE_CYCLE 2 // Cycle is running #define STATE_QUEUED 2 // Indicates buffered blocks, awaiting cycle start.
#define STATE_HOLD 3 // Executing feed hold #define STATE_CYCLE 3 // Cycle is running
#define STATE_HOMING 4 // Performing homing cycle #define STATE_HOLD 4 // Executing feed hold
#define STATE_JOG 5 // Jogging mode is unique like homing. #define STATE_HOMING 5 // Performing homing cycle
#define STATE_ALARM 6 // In alarm state. Locks out all g-code processes and messages position lost #define STATE_ALARM 6 // In alarm state. Locks out all g-code processes. Allows settings access.
#define STATE_LIMIT 7 // Used to message hard limit triggered. // #define STATE_JOG 7 // Jogging mode is unique like homing.
// Define global system variables // Define global system variables
typedef struct { typedef struct {
uint8_t abort; // System abort flag. Forces exit back to main loop for reset. uint8_t abort; // System abort flag. Forces exit back to main loop for reset.
uint8_t state; // Tracks the current state of Grbl. uint8_t state; // Tracks the current state of Grbl.
volatile uint8_t execute; // Global system runtime executor bitflag variable. See EXEC bitmasks. volatile uint8_t execute; // Global system runtime executor bitflag variable. See EXEC bitmasks.
int32_t position[3]; // Real-time machine (aka home) position vector in steps. int32_t position[N_AXIS]; // Real-time machine (aka home) position vector in steps.
// NOTE: This may need to be a volatile variable, if problems arise. // NOTE: This may need to be a volatile variable, if problems arise.
uint8_t auto_start; // Planner auto-start flag. Toggled off during feed hold. Defaulted by settings. uint8_t auto_start; // Planner auto-start flag. Toggled off during feed hold. Defaulted by settings.
// uint8_t feed_hold; // Feed hold flag. Held true during feed hold. Released when ready to resume.
// volatile uint8_t cycle_start; // Cycle start flag. Set by stepper subsystem or main program.
} system_t; } system_t;
extern system_t sys; extern system_t sys;

View File

@ -74,8 +74,7 @@ ISR(PINOUT_INT_vect)
// Enter only if any pinout pin is actively low. // Enter only if any pinout pin is actively low.
if ((PINOUT_PIN & PINOUT_MASK) ^ PINOUT_MASK) { if ((PINOUT_PIN & PINOUT_MASK) ^ PINOUT_MASK) {
if (bit_isfalse(PINOUT_PIN,bit(PIN_RESET))) { if (bit_isfalse(PINOUT_PIN,bit(PIN_RESET))) {
mc_alarm(); mc_reset();
sys.execute |= EXEC_RESET; // Set as true
} else if (bit_isfalse(PINOUT_PIN,bit(PIN_FEED_HOLD))) { } else if (bit_isfalse(PINOUT_PIN,bit(PIN_FEED_HOLD))) {
sys.execute |= EXEC_FEED_HOLD; sys.execute |= EXEC_FEED_HOLD;
} else if (bit_isfalse(PINOUT_PIN,bit(PIN_CYCLE_START))) { } else if (bit_isfalse(PINOUT_PIN,bit(PIN_CYCLE_START))) {
@ -93,36 +92,41 @@ ISR(PINOUT_INT_vect)
// define more computationally-expensive volatile variables. This also provides a controlled way to // define more computationally-expensive volatile variables. This also provides a controlled way to
// execute certain tasks without having two or more instances of the same task, such as the planner // execute certain tasks without having two or more instances of the same task, such as the planner
// recalculating the buffer upon a feedhold or override. // recalculating the buffer upon a feedhold or override.
// NOTE: The sys.execute variable flags are set by the serial read subprogram, except where noted, // NOTE: The sys.execute variable flags are set by any process, step or serial interrupts, pinouts,
// but may be set by any process, such as a switch pin change interrupt when pinouts are installed. // limit switches, or the main program.
void protocol_execute_runtime() void protocol_execute_runtime()
{ {
if (sys.execute) { // Enter only if any bit flag is true if (sys.execute) { // Enter only if any bit flag is true
uint8_t rt_exec = sys.execute; // Avoid calling volatile multiple times uint8_t rt_exec = sys.execute; // Avoid calling volatile multiple times
// System alarm. Everything has shutdown by either something that has gone wrong or issuing // System alarm. Everything has shutdown by something that has gone severely wrong. Report
// the Grbl soft-reset/abort. Check the system states to report any critical error found. // the source of the error to the user. If critical, Grbl disables by entering an infinite
// If critical, disable Grbl by entering an infinite loop until system reset/abort. // loop until system reset/abort.
// NOTE: The system alarm state is also used to set if (rt_exec & (EXEC_ALARM | EXEC_CRIT_EVENT)) {
if (rt_exec & EXEC_ALARM) { sys.state = STATE_ALARM; // Set system alarm state
// Limit switch critical event. Lock out Grbl until reset.
if (sys.state == STATE_LIMIT) { // Critical event. Only hard limit qualifies. Update this as new critical events surface.
report_status_message(STATUS_HARD_LIMIT); if (rt_exec & EXEC_CRIT_EVENT) {
sys.state = STATE_ALARM; report_alarm_message(ALARM_HARD_LIMIT);
report_feedback_message(MESSAGE_CRITICAL_EVENT); report_feedback_message(MESSAGE_CRITICAL_EVENT);
while (bit_isfalse(sys.execute,EXEC_RESET)) { sleep_mode(); } bit_false(sys.execute,EXEC_RESET); // Disable any existing reset
do {
// Nothing. Block EVERYTHING until user issues reset or power cycles. Hard limits
// typically occur while unattended or not paying attention. Gives the user time
// to do what is needed before resetting, like killing the incoming stream.
} while (bit_isfalse(sys.execute,EXEC_RESET));
// Standard alarm event. Only abort during motion qualifies.
} else {
// Runtime abort command issued during a cycle, feed hold, or homing cycle. Message the
// user that position may have been lost and set alarm state to enable the alarm lockout
// to indicate the possible severity of the problem.
report_alarm_message(ALARM_ABORT_CYCLE);
}
bit_false(sys.execute,(EXEC_ALARM | EXEC_CRIT_EVENT));
} }
// Check if a runtime abort command was issued during a cycle. If so, message the user // Execute system abort.
// that position may have been lost and set alarm state to force re-homing, if enabled.
if (sys.state == STATE_CYCLE) {
report_status_message(STATUS_ABORT_CYCLE);
sys.state = STATE_ALARM;
}
bit_false(sys.execute,EXEC_ALARM);
}
// System abort. Steppers have already been force stopped.
if (rt_exec & EXEC_RESET) { if (rt_exec & EXEC_RESET) {
sys.abort = true; // Only place this is set true. sys.abort = true; // Only place this is set true.
return; // Nothing else to do but exit. return; // Nothing else to do but exit.
@ -194,8 +198,10 @@ uint8_t protocol_execute_line(char *line)
case 'H' : // Perform homing cycle case 'H' : // Perform homing cycle
if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) { if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) {
// Only perform homing if Grbl is idle or lost. // Only perform homing if Grbl is idle or lost.
if ( sys.state==STATE_IDLE || sys.state==STATE_ALARM ) { mc_go_home(); } if ( sys.state==STATE_IDLE || sys.state==STATE_ALARM ) {
else { return(STATUS_IDLE_ERROR); } mc_go_home();
if (!sys.abort) { protocol_execute_startup(); } // Execute startup scripts after successful homing.
} else { return(STATUS_IDLE_ERROR); }
} else { return(STATUS_SETTING_DISABLED); } } else { return(STATUS_SETTING_DISABLED); }
break; break;
// case 'J' : break; // Jogging methods // case 'J' : break; // Jogging methods
@ -224,20 +230,19 @@ uint8_t protocol_execute_line(char *line)
// Perform reset when toggling off. Check g-code mode should only work if Grbl // Perform reset when toggling off. Check g-code mode should only work if Grbl
// is idle and ready, regardless of homing locks. This is mainly to keep things // is idle and ready, regardless of homing locks. This is mainly to keep things
// simple and consistent. // simple and consistent.
if ( bit_istrue(gc.switches,helper_var) ) { sys.execute |= EXEC_RESET; } if ( bit_istrue(gc.switches,helper_var) ) { mc_reset(); }
else if (sys.state) { return(STATUS_IDLE_ERROR); } else if (sys.state) { return(STATUS_IDLE_ERROR); }
} }
gc.switches ^= helper_var; gc.switches ^= helper_var;
if (bit_istrue(gc.switches,helper_var)) { report_feedback_message(MESSAGE_ENABLED); } if (bit_istrue(gc.switches,helper_var)) { report_feedback_message(MESSAGE_ENABLED); }
else { report_feedback_message(MESSAGE_DISABLED); } else { report_feedback_message(MESSAGE_DISABLED); }
break; break;
case 'X' : // Disable homing lock case 'X' : // Disable alarm lock
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
if (sys.state == STATE_ALARM) { if (sys.state == STATE_ALARM) {
report_feedback_message(MESSAGE_HOMING_UNLOCK); report_feedback_message(MESSAGE_ALARM_UNLOCK);
sys.state = STATE_IDLE; sys.state = STATE_IDLE;
} else { // Don't run startup script. Prevents stored moves in startup from causing accidents.
return(STATUS_SETTING_DISABLED);
} }
break; break;
case 'N' : // Startup lines. case 'N' : // Startup lines.
@ -279,17 +284,7 @@ uint8_t protocol_execute_line(char *line)
return(STATUS_OK); // If '$' command makes it to here, then everything's ok. return(STATUS_OK); // If '$' command makes it to here, then everything's ok.
} else { } else {
// If homing is enabled and position is lost, lock out all g-code commands.
if (sys.state != STATE_ALARM) {
return(gc_execute_line(line)); // Everything else is gcode return(gc_execute_line(line)); // Everything else is gcode
// TODO: Install option to set system alarm upon any error code received back from the
// the g-code parser. This is a common safety feature on CNCs to help prevent crashes
// if the g-code doesn't perform as intended.
} else {
return(STATUS_HOMING_LOCK);
}
} }
} }

View File

@ -62,8 +62,6 @@ void report_status_message(uint8_t status_code)
printPgmString(PSTR("Modal group violation")); break; printPgmString(PSTR("Modal group violation")); break;
case STATUS_INVALID_STATEMENT: case STATUS_INVALID_STATEMENT:
printPgmString(PSTR("Invalid statement")); break; printPgmString(PSTR("Invalid statement")); break;
case STATUS_HARD_LIMIT:
printPgmString(PSTR("Hard limit. MPos lost?")); break;
case STATUS_SETTING_DISABLED: case STATUS_SETTING_DISABLED:
printPgmString(PSTR("Setting disabled")); break; printPgmString(PSTR("Setting disabled")); break;
case STATUS_SETTING_VALUE_NEG: case STATUS_SETTING_VALUE_NEG:
@ -73,37 +71,47 @@ void report_status_message(uint8_t status_code)
case STATUS_SETTING_READ_FAIL: case STATUS_SETTING_READ_FAIL:
printPgmString(PSTR("EEPROM read fail. Using defaults")); break; printPgmString(PSTR("EEPROM read fail. Using defaults")); break;
case STATUS_IDLE_ERROR: case STATUS_IDLE_ERROR:
printPgmString(PSTR("Busy or locked")); break; printPgmString(PSTR("Busy or queued")); break;
case STATUS_ABORT_CYCLE: case STATUS_ALARM_LOCK:
printPgmString(PSTR("Abort during cycle. MPos lost?")); break; printPgmString(PSTR("Alarm lock")); break;
case STATUS_HOMING_LOCK:
printPgmString(PSTR("Locked until homed")); break;
} }
printPgmString(PSTR("\r\n")); printPgmString(PSTR("\r\n"));
} }
} }
// Prints alarm messages.
void report_alarm_message(int8_t alarm_code)
{
printPgmString(PSTR("ALARM: "));
switch (alarm_code) {
case ALARM_HARD_LIMIT:
printPgmString(PSTR("Hard limit")); break;
case ALARM_ABORT_CYCLE:
printPgmString(PSTR("Abort during cycle")); break;
}
printPgmString(PSTR(". MPos?\r\n"));
}
// Prints feedback messages. This serves as a centralized method to provide additional // Prints feedback messages. This serves as a centralized method to provide additional
// user feedback for things that are not of the status message response protocol. These // user feedback for things that are not of the status/alarm message protocol. These are
// are messages such as setup warnings and how to exit alarms. // messages such as setup warnings, switch toggling, and how to exit alarms.
// NOTE: For interfaces, messages are always placed within brackets. And if silent mode // NOTE: For interfaces, messages are always placed within brackets. And if silent mode
// is installed, the message number codes are less than zero. // is installed, the message number codes are less than zero.
// TODO: Install silence feedback messages option in settings // TODO: Install silence feedback messages option in settings
void report_feedback_message(int8_t message_code) void report_feedback_message(uint8_t message_code)
{ {
printPgmString(PSTR("[")); printPgmString(PSTR("["));
switch(message_code) { switch(message_code) {
case MESSAGE_CRITICAL_EVENT: case MESSAGE_CRITICAL_EVENT:
printPgmString(PSTR("ALARM: Check and reset")); break; printPgmString(PSTR("Reset to continue")); break;
case MESSAGE_HOMING_ALARM: case MESSAGE_ALARM_LOCK:
printPgmString(PSTR("'$H' to home and unlock")); break; printPgmString(PSTR("'$H'|'$X' to unlock")); break;
case MESSAGE_ALARM_UNLOCK:
printPgmString(PSTR("Caution: Unlocked")); break;
case MESSAGE_ENABLED: case MESSAGE_ENABLED:
printPgmString(PSTR("Enabled")); break; printPgmString(PSTR("Enabled")); break;
case MESSAGE_DISABLED: case MESSAGE_DISABLED:
printPgmString(PSTR("Disabled")); break; printPgmString(PSTR("Disabled")); break;
case MESSAGE_HOMING_UNLOCK:
printPgmString(PSTR("Unlocked. MPos lost?")); break;
} }
printPgmString(PSTR("]\r\n")); printPgmString(PSTR("]\r\n"));
} }
@ -127,7 +135,7 @@ void report_grbl_help() {
"$S1 (toggle blk del)\r\n" "$S1 (toggle blk del)\r\n"
"$S2 (toggle single blk)\r\n" "$S2 (toggle single blk)\r\n"
"$S3 (toggle opt stop)\r\n" "$S3 (toggle opt stop)\r\n"
"$X (kill homing lock)\r\n" "$X (kill alarm lock)\r\n"
"$H (run homing cycle)\r\n" "$H (run homing cycle)\r\n"
"~ (cycle start)\r\n" "~ (cycle start)\r\n"
"! (feed hold)\r\n" "! (feed hold)\r\n"
@ -296,6 +304,8 @@ void report_realtime_status()
memcpy(current_position,sys.position,sizeof(sys.position)); memcpy(current_position,sys.position,sizeof(sys.position));
float print_position[3]; float print_position[3];
// TODO: Add Grbl state feedback, i.e. IDLE, RUN, HOLD, HOME, etc.
// Report machine position // Report machine position
printPgmString(PSTR("MPos:[")); printPgmString(PSTR("MPos:["));
for (i=0; i<= 2; i++) { for (i=0; i<= 2; i++) {

View File

@ -29,27 +29,32 @@
#define STATUS_ARC_RADIUS_ERROR 4 #define STATUS_ARC_RADIUS_ERROR 4
#define STATUS_MODAL_GROUP_VIOLATION 5 #define STATUS_MODAL_GROUP_VIOLATION 5
#define STATUS_INVALID_STATEMENT 6 #define STATUS_INVALID_STATEMENT 6
#define STATUS_HARD_LIMIT 7 #define STATUS_SETTING_DISABLED 7
#define STATUS_SETTING_DISABLED 8 #define STATUS_SETTING_VALUE_NEG 8
#define STATUS_SETTING_VALUE_NEG 9 #define STATUS_SETTING_STEP_PULSE_MIN 9
#define STATUS_SETTING_STEP_PULSE_MIN 10 #define STATUS_SETTING_READ_FAIL 10
#define STATUS_SETTING_READ_FAIL 11 #define STATUS_IDLE_ERROR 11
#define STATUS_IDLE_ERROR 12 #define STATUS_ALARM_LOCK 12
#define STATUS_ABORT_CYCLE 13
#define STATUS_HOMING_LOCK 14
// Define Grbl feedback message codes. Less than zero to distinguish message from error. // Define Grbl alarm codes. Less than zero to distinguish alarm error from status error.
#define MESSAGE_CRITICAL_EVENT -1 #define ALARM_HARD_LIMIT -1
#define MESSAGE_HOMING_ALARM -2 #define ALARM_ABORT_CYCLE -2
#define MESSAGE_ENABLED -3
#define MESSAGE_DISABLED -4 // Define Grbl feedback message codes.
#define MESSAGE_HOMING_UNLOCK -5 #define MESSAGE_CRITICAL_EVENT 1
#define MESSAGE_ALARM_LOCK 2
#define MESSAGE_ALARM_UNLOCK 3
#define MESSAGE_ENABLED 4
#define MESSAGE_DISABLED 5
// Prints system status messages. // Prints system status messages.
void report_status_message(uint8_t status_code); void report_status_message(uint8_t status_code);
// Prints system alarm messages.
void report_alarm_message(int8_t alarm_code);
// Prints miscellaneous feedback messages. // Prints miscellaneous feedback messages.
void report_feedback_message(int8_t message_code); void report_feedback_message(uint8_t message_code);
// Prints welcome message // Prints welcome message
void report_init_message(); void report_init_message();

View File

@ -49,18 +49,18 @@ volatile uint8_t tx_buffer_tail = 0;
} }
#endif #endif
static void set_baud_rate(long baud) { void serial_init()
uint16_t UBRR0_value = ((F_CPU / 16 + baud / 2) / baud - 1); {
// Set baud rate
#if BAUD_RATE < 57600
uint16_t UBRR0_value = ((F_CPU / (8L * BAUD_RATE)) - 1)/2 ;
UCSR0A &= ~(1 << U2X0); // baud doubler off - Only needed on Uno XXX
#else
uint16_t UBRR0_value = ((F_CPU / (4L * BAUD_RATE)) - 1)/2;
UCSR0A |= (1 << U2X0); // baud doubler on for high baud rates, i.e. 115200
#endif
UBRR0H = UBRR0_value >> 8; UBRR0H = UBRR0_value >> 8;
UBRR0L = UBRR0_value; UBRR0L = UBRR0_value;
}
void serial_init(long baud)
{
set_baud_rate(baud);
/* baud doubler off - Only needed on Uno XXX */
UCSR0A &= ~(1 << U2X0);
// enable rx and tx // enable rx and tx
UCSR0B |= 1<<RXEN0; UCSR0B |= 1<<RXEN0;
@ -159,11 +159,7 @@ ISR(USART_RX_vect)
case CMD_STATUS_REPORT: sys.execute |= EXEC_STATUS_REPORT; break; // Set as true case CMD_STATUS_REPORT: sys.execute |= EXEC_STATUS_REPORT; break; // Set as true
case CMD_CYCLE_START: sys.execute |= EXEC_CYCLE_START; break; // Set as true case CMD_CYCLE_START: sys.execute |= EXEC_CYCLE_START; break; // Set as true
case CMD_FEED_HOLD: sys.execute |= EXEC_FEED_HOLD; break; // Set as true case CMD_FEED_HOLD: sys.execute |= EXEC_FEED_HOLD; break; // Set as true
case CMD_RESET: case CMD_RESET: mc_reset(); break; // Call motion control reset routine.
// Immediately force stepper and spindle subsystem idle at an interrupt level.
mc_alarm();
sys.execute |= EXEC_RESET; // Set as true
break;
default: // Write character to buffer default: // Write character to buffer
next_head = rx_buffer_head + 1; next_head = rx_buffer_head + 1;
if (next_head == RX_BUFFER_SIZE) { next_head = 0; } if (next_head == RX_BUFFER_SIZE) { next_head = 0; }

View File

@ -47,7 +47,7 @@
#define XON_CHAR 0x11 #define XON_CHAR 0x11
#endif #endif
void serial_init(long baud); void serial_init();
void serial_write(uint8_t data); void serial_write(uint8_t data);

View File

@ -26,6 +26,7 @@
#include "nuts_bolts.h" #include "nuts_bolts.h"
#include "settings.h" #include "settings.h"
#include "eeprom.h" #include "eeprom.h"
#include "limits.h"
settings_t settings; settings_t settings;
@ -172,24 +173,22 @@ uint8_t settings_store_global_setting(int parameter, float value) {
if (value) { settings.flags |= BITFLAG_REPORT_INCHES; } if (value) { settings.flags |= BITFLAG_REPORT_INCHES; }
else { settings.flags &= ~BITFLAG_REPORT_INCHES; } else { settings.flags &= ~BITFLAG_REPORT_INCHES; }
break; break;
case 14: // Reboot to ensure change case 14: // Reset to ensure change. Immediate re-init may cause problems.
if (value) { settings.flags |= BITFLAG_AUTO_START; } if (value) { settings.flags |= BITFLAG_AUTO_START; }
else { settings.flags &= ~BITFLAG_AUTO_START; } else { settings.flags &= ~BITFLAG_AUTO_START; }
break; break;
case 15: // Reboot to ensure change case 15: // Reset to ensure change. Immediate re-init may cause problems.
if (value) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; } if (value) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; }
else { settings.flags &= ~BITFLAG_INVERT_ST_ENABLE; } else { settings.flags &= ~BITFLAG_INVERT_ST_ENABLE; }
break; break;
case 16: // Reboot to ensure change case 16:
if (value) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; } if (value) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; }
else { settings.flags &= ~BITFLAG_HARD_LIMIT_ENABLE; } else { settings.flags &= ~BITFLAG_HARD_LIMIT_ENABLE; }
limits_init(); // Re-init to immediately change. NOTE: Nice to have but could be problematic later.
break; break;
case 17: case 17:
if (value) { if (value) { settings.flags |= BITFLAG_HOMING_ENABLE; }
settings.flags |= BITFLAG_HOMING_ENABLE; else { settings.flags &= ~BITFLAG_HOMING_ENABLE; }
sys.state = STATE_ALARM;
report_feedback_message(MESSAGE_HOMING_ALARM);
} else { settings.flags &= ~BITFLAG_HOMING_ENABLE; }
break; break;
case 18: settings.homing_dir_mask = trunc(value); break; case 18: settings.homing_dir_mask = trunc(value); break;
case 19: settings.homing_feed_rate = value; break; case 19: settings.homing_feed_rate = value; break;