Permalink
Browse files

Re-factored system states and alarm management. Serial baud support g…

…reater 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
  • Loading branch information...
1 parent e6ad15b commit 559feb97e23b783883c8aef549d3dc330f9171b9 @chamnit chamnit committed Nov 15, 2012
Showing with 465 additions and 419 deletions.
  1. +14 −2 config.h
  2. +6 −1 gcode.c
  3. +35 −18 limits.c
  4. +21 −17 main.c
  5. +28 −23 motion_control.c
  6. +2 −2 motion_control.h
  7. +1 −1 nuts_bolts.c
  8. +9 −11 nuts_bolts.h
  9. +36 −41 protocol.c
  10. +58 −48 report.c
  11. +21 −16 report.h
  12. +12 −16 serial.c
  13. +1 −1 serial.h
  14. +221 −222 settings.c
View
@@ -69,9 +69,9 @@
#define COOLANT_FLOOD_PORT PORTC
#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
// a later date if flash and memory space allows.
+// #define ENABLE_M7 // Mist coolant disabled by default. Uncomment to enable.
#ifdef ENABLE_M7
#define COOLANT_MIST_DDR DDRC
#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.
#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.
// This help in preventing overshoot and should improve repeatability. This value should be one or
// greater.
@@ -167,7 +179,7 @@
// 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
// 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:
View
@@ -84,6 +84,11 @@ static float to_millimeters(float value)
// internal functions in terms of (mm, mm/min) and absolute machine coordinates, respectively.
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;
char letter;
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,
// 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; }
}
View
@@ -41,30 +41,41 @@ void limits_init()
LIMIT_PORT |= (LIMIT_MASK); // Enable internal pull-up resistors. Normal high operation.
if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) {
- LIMIT_PCMSK |= LIMIT_MASK; // Enable specific pins of the Pin Change Interrupt
- PCICR |= (1 << LIMIT_INT); // Enable Pin Change Interrupt
+ LIMIT_PCMSK |= LIMIT_MASK; // Enable specific pins of the 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
// 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
// your e-stop switch to the Arduino reset pin, since it is the most correct way to do this.
-// 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
-// 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
-// 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)
{
- // Only enter if the system alarm is not active.
- if (bit_isfalse(sys.execute,EXEC_ALARM)) {
- // Kill all processes upon hard limit event.
- if ((LIMIT_PIN & LIMIT_MASK) ^ LIMIT_MASK) {
- mc_alarm(); // Initiate system kill.
- sys.state = STATE_LIMIT; // Set system state to indicate event.
- }
+ // 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
+ // 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
+ // we move on to new hardware or flash space becomes an issue. If it ain't broke, don't fix it.
+
+ // Ignore limit switches if already in an alarm state or in-process of executing an alarm.
+ // 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)) {
+ mc_reset(); // Initiate system kill.
+ sys.execute |= EXEC_CRIT_EVENT; // Indicate hard limit critical 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)
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
// 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,
@@ -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()
{
- // 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();
// 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
- homing_cycle(true, true, false, true, false, settings.homing_seek_rate); // Then jog the x and y axis
+ // First jog z-axis to clear workspace, 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
// Now in proximity of all limits. Carefully leave and approach switches in multiple cycles
View
38 main.c
@@ -45,22 +45,21 @@ system_t sys;
int main(void)
{
// 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
st_init(); // Setup stepper pins and interrupt timers
sei(); // Enable interrupts
memset(&sys, 0, sizeof(sys)); // Clear all system variables
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(;;) {
// Execute system reset upon a system abort, where the main program will return to this loop.
// Once here, it is safe to re-initialize the system. At startup, the system will automatically
// reset to finish the initialization process.
if (sys.abort) {
-
// Reset system.
serial_reset_read_buffer(); // Clear serial read buffer
plan_init(); // Clear block buffer and planner variables
@@ -72,28 +71,33 @@ int main(void)
st_reset(); // Clear stepper subsystem variables.
// 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
- // 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.
+ // cleared upon startup, not a reset/abort.
sys_sync_current_position();
// Reset system variables.
sys.abort = false;
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);
+ if (bit_istrue(settings.flags,BITFLAG_AUTO_START)) { sys.auto_start = true; }
+
+ // 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();
}
- if (bit_istrue(settings.flags,BITFLAG_AUTO_START)) { sys.auto_start = true; }
-
- // Execute user startup script
- protocol_execute_startup();
}
protocol_execute_runtime();
View
@@ -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)) {
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.
- // NOTE: If homing cycles are enabled, a position lost state will lock out all motions,
- // until a homing cycle has been completed. This is a safety feature to help prevent
- // the machine from crashing.
+ // If idle, indicate to the system there is now a planned block in the buffer ready to cycle
+ // start. Otherwise ignore and continue on.
if (!sys.state) { sys.state = STATE_QUEUED; }
// 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()
{
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.
- if (sys.abort) {
- sys.state = STATE_ALARM; // Homing routine did not complete.
- return;
- }
+ if (sys.abort) { return; } // Did not complete. Alarm state set by mc_alarm.
// The machine should now be homed and machine zero has been located. Upon completion,
// 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(Z_DIRECTION_BIT))) { z_dir = 1; }
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.
plan_synchronize(); // Make sure the motion completes.
// The gcode parser position was circumvented by the pull-off maneuver, so sync position vectors.
sys_sync_current_position();
- // If hard limits feature enabled, re-enable hard limits interrupt after homing cycle.
- if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) { PCICR |= (1 << LIMIT_INT); }
+ // If hard limits feature enabled, re-enable hard limits pin change register after homing cycle.
+ if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) { LIMIT_PCMSK |= LIMIT_MASK; }
// Finished!
}
-// Method to immediately kill all motion and set system alarm. Used by system abort, hard limits,
-// and upon g-code parser error (when installed).
-void mc_alarm()
+// Method to ready the system to reset by setting the runtime reset command and killing any
+// active processes in the system. This also checks if a system reset is issued while Grbl
+// 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
- // by different processes.
- if (bit_isfalse(sys.execute, EXEC_ALARM)) {
- // Set system alarm flag to have the main program check for anything wrong with shutting
- // down the system.
- sys.execute |= EXEC_ALARM;
- // Immediately force stepper, spindle, and coolant to stop.
- st_go_idle();
+ // Only this function can set the system reset. Helps prevent multiple kill calls.
+ if (bit_isfalse(sys.execute, EXEC_RESET)) {
+ sys.execute |= EXEC_RESET;
+
+ // Kill spindle and coolant.
spindle_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
@@ -43,7 +43,7 @@ void mc_dwell(float seconds);
// Perform homing cycle to locate machine zero. Requires limit switches.
void mc_go_home();
-// Kills all motion and sets system alarm
-void mc_alarm();
+// Performs system reset. If in motion state, kills all motion and sets system alarm.
+void mc_reset();
#endif
View
@@ -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()
{
plan_set_current_position(sys.position[X_AXIS],sys.position[Y_AXIS],sys.position[Z_AXIS]);
View
@@ -63,31 +63,29 @@
#define EXEC_FEED_HOLD bit(3) // bitmask 00001000
#define EXEC_RESET bit(4) // bitmask 00010000
#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 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
// critical events.
#define STATE_IDLE 0 // Must be zero.
-#define STATE_QUEUED 1 // Indicates buffered blocks, awaiting cycle start.
-#define STATE_CYCLE 2 // Cycle is running
-#define STATE_HOLD 3 // Executing feed hold
-#define STATE_HOMING 4 // Performing homing cycle
-#define STATE_JOG 5 // Jogging mode is unique like homing.
-#define STATE_ALARM 6 // In alarm state. Locks out all g-code processes and messages position lost
-#define STATE_LIMIT 7 // Used to message hard limit triggered.
+#define STATE_INIT 1 // Initial power up state.
+#define STATE_QUEUED 2 // Indicates buffered blocks, awaiting cycle start.
+#define STATE_CYCLE 3 // Cycle is running
+#define STATE_HOLD 4 // Executing feed hold
+#define STATE_HOMING 5 // Performing homing cycle
+#define STATE_ALARM 6 // In alarm state. Locks out all g-code processes. Allows settings access.
+// #define STATE_JOG 7 // Jogging mode is unique like homing.
// Define global system variables
typedef struct {
uint8_t abort; // System abort flag. Forces exit back to main loop for reset.
uint8_t state; // Tracks the current state of Grbl.
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.
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;
extern system_t sys;
Oops, something went wrong.

0 comments on commit 559feb9

Please sign in to comment.