Permalink
Browse files

Hard limits, homing direction, pull-off limits after homing, status r…

…eports in mm or inches, system alarm, and more.

- Thank you statement added for Alden Hart of Synthetos.

- Hard limits option added, which also works with homing by pulling off
the switches to help prevent unintended triggering. Hard limits use a
interrupt to sense a falling edge pin change and immediately go into
alarm mode, which stops everything and forces the user to issue a reset
(Ctrl-x) or reboot.

- Auto cycle start now a configuration option.

- Alarm mode: A new method to kill all Grbl processes in the event of
something catastrophic or potentially catastropic. Just works with hard
limits for now, but will be expanded to include g-code errors (most
likely) and other events.

- Updated status reports to be configurable in inches or mm mode. Much
more to do here, but this is the first step.

- New settings: auto cycle start, hard limit enable, homing direction
mask (which works the same as the stepper mask), homing pulloff
distance (or distance traveled from homed machine zero to prevent
accidental limit trip).

- Minor memory liberation and calculation speed ups.
  • Loading branch information...
1 parent 34f6d2e commit df5bb70b2515b8bc05ca7c90abf1b221f63aeafe @chamnit chamnit committed Oct 17, 2012
Showing with 192 additions and 82 deletions.
  1. +3 −5 config.h
  2. +3 −2 gcode.c
  3. +27 −10 limits.c
  4. +9 −3 main.c
  5. +22 −1 motion_control.c
  6. +17 −2 nuts_bolts.h
  7. +38 −23 protocol.c
  8. +5 −1 serial.c
  9. +59 −29 settings.c
  10. +7 −4 settings.h
  11. +2 −2 stepper.c
View
@@ -46,9 +46,9 @@
#define X_LIMIT_BIT 1 // Uno Digital Pin 9
#define Y_LIMIT_BIT 2 // Uno Digital Pin 10
#define Z_LIMIT_BIT 3 // Uno Digital Pin 11
-// #define LIMIT_INT PCIE0 // Pin change interrupt settings
-// #define LIMIT_INT_vect PCINT0_vect
-// #define LIMIT_PCMSK PCMSK0
+#define LIMIT_INT PCIE0 // Pin change interrupt settings
+#define LIMIT_INT_vect PCINT0_vect
+#define LIMIT_PCMSK PCMSK0
#define SPINDLE_ENABLE_DDR DDRB
#define SPINDLE_ENABLE_PORT PORTB
@@ -159,9 +159,7 @@
// TODO: The following options are set as compile-time options for now, until the next EEPROM
// settings version has solidified. This is to prevent having to support dozens of different
// incremental settings versions.
-#define CYCLE_AUTO_START 1 // Cycle auto-start boolean flag for the planner.
#define BLOCK_DELETE_ENABLE 0 // Block delete enable/disable flag during g-code parsing
-#define REPORT_INCH_MODE 0 // Status reporting unit mode (1 = inch, 0 = mm)
// This parameter sets the delay time before disabling the steppers after the final block of movement.
// A short delay ensures the steppers come to a complete stop and the residual inertial force in the
View
@@ -108,7 +108,8 @@ void gc_init()
// protocol_status_message(settings_execute_startup());
}
-// Sets g-code parser position in mm. Input in steps. Called by the system abort routine.
+// Sets g-code parser position in mm. Input in steps. Called by the system abort and hard
+// limit pull-off routines.
void gc_set_current_position(int32_t x, int32_t y, int32_t z)
{
gc.position[X_AXIS] = x/settings.steps_per_mm[X_AXIS];
@@ -183,7 +184,7 @@ uint8_t gc_execute_line(char *line)
case 21: gc.inches_mode = false; break;
case 28: case 30:
// NOTE: G28.1, G30.1 sets home position parameters. Not currently supported.
- if (bit_istrue(settings.flags,FLAG_BIT_HOMING_ENABLE)) {
+ if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) {
non_modal_action = NON_MODAL_GO_HOME;
} else {
FAIL(STATUS_SETTING_DISABLED);
View
@@ -38,8 +38,31 @@ void limits_init()
{
LIMIT_DDR &= ~(LIMIT_MASK); // Set as input pins
LIMIT_PORT |= (LIMIT_MASK); // Enable internal pull-up resistors. Normal high operation.
+
+ if bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE) {
+ MCUCR = (1<<ISC01) | (0<<ISC00); //1 0 triggers at a falling edge.
+ LIMIT_PCMSK |= LIMIT_MASK; // Enable specific pins of the Pin Change Interrupt
+ PCICR |= (1 << LIMIT_INT); // Enable Pin Change Interrupt
+ }
+}
+
+// This is the Limit Pin Change Interrupt, which handles the hard limit feature. This is
+// called when Grbl detects a falling edge on a limit pin.
+// 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.
+ISR(LIMIT_INT_vect)
+{
+ // Kill all processes upon hard limit event.
+ st_go_idle(); // Immediately stop stepper motion
+ spindle_stop(); // Stop spindle
+ sys.auto_start = false; // Disable auto cycle start.
+ sys.execute |= EXEC_ALARM;
+ // TODO: When Grbl system status is installed, update here to indicate loss of position.
}
+
// Moves all specified axes in same specified direction (positive=true, negative=false)
// and at the homing rate. Homing is a special motion case, where there is only an
// acceleration followed by abrupt asynchronous stops by each axes reaching their limit
@@ -85,6 +108,7 @@ static void homing_cycle(bool x_axis, bool y_axis, bool z_axis, int8_t pos_dir,
// Set default out_bits.
uint8_t out_bits0 = settings.invert_mask;
+ out_bits0 ^= (settings.homing_dir_mask & DIRECTION_MASK); // Apply homing direction settings
if (!pos_dir) { out_bits0 ^= DIRECTION_MASK; } // Invert bits, if negative dir.
// Initialize stepping variables
@@ -160,11 +184,8 @@ static void homing_cycle(bool x_axis, bool y_axis, bool z_axis, int8_t pos_dir,
void limits_go_home()
-{
- plan_synchronize(); // Empty all motions in buffer.
-
- // Enable steppers by resetting the stepper disable port
- STEPPERS_DISABLE_PORT &= ~(1<<STEPPERS_DISABLE_BIT);
+{
+ STEPPERS_DISABLE_PORT &= ~(1<<STEPPERS_DISABLE_BIT); // Enable steppers, but not the cycle.
// 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
@@ -186,9 +207,5 @@ void limits_go_home()
}
}
- delay_ms(settings.stepper_idle_lock_time);
- // Disable steppers by setting stepper disable
- if (settings.stepper_idle_lock_time != 0xff) {
- STEPPERS_DISABLE_PORT |= (1<<STEPPERS_DISABLE_BIT);
- }
+ st_go_idle(); // Call main stepper shutdown routine.
}
View
@@ -19,6 +19,10 @@
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
+/* A big thanks to Alden Hart of Synthetos, supplier of grblshield and TinyG, who has
+ been integral throughout the development of the higher level details of Grbl, as well
+ as being a consistent sounding board for the future of accessible and free CNC. */
+
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "config.h"
@@ -46,7 +50,9 @@ int main(void)
memset(&sys, 0, sizeof(sys)); // Clear all system variables
sys.abort = true; // Set abort to complete initialization
-
+
+ // TODO: When Grbl system status is installed, need to set position lost state upon startup.
+
for(;;) {
// Execute system reset upon a system abort, where the main program will return to this loop.
@@ -87,9 +93,9 @@ int main(void)
// Set system runtime defaults
// TODO: Eventual move to EEPROM from config.h when all of the new settings are worked out.
// Mainly to avoid having to maintain several different versions.
- #ifdef CYCLE_AUTO_START
+ if (bit_istrue(settings.flags,BITFLAG_AUTO_START)) {
sys.auto_start = true;
- #endif
+ }
// TODO: Install G20/G21 unit default into settings and load appropriate settings.
}
View
@@ -196,9 +196,30 @@ void mc_dwell(float seconds)
// Execute homing cycle to locate and set machine zero.
void mc_go_home()
{
- limits_go_home();
+ plan_synchronize(); // Empty all motions in buffer before homing.
+ PCICR &= ~(1 << LIMIT_INT); // Disable hard limits pin change interrupt
+
+ limits_go_home(); // Perform homing routine.
+
// Upon completion, reset all internal position vectors (g-code parser, planner, system)
gc_clear_position();
plan_clear_position();
clear_vector_float(sys.position);
+
+ // If hard limits enabled, move all axes off limit switches before enabling the hard limit
+ // pin change interrupt. This should help prevent the switches from falsely tripping.
+ // NOTE: G-code parser was circumvented so its position needs to be updated explicitly.
+ if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) {
+ int8_t x_dir, y_dir, z_dir;
+ x_dir = y_dir = z_dir = 1;
+ if (bit_istrue(settings.homing_dir_mask,bit(X_DIRECTION_BIT))) { x_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; }
+ mc_line(x_dir*settings.homing_pulloff, y_dir*settings.homing_pulloff,
+ z_dir*settings.homing_pulloff, settings.homing_feed_rate, false);
+ st_cycle_start(); // Nothing should be in the buffer except this motion.
+ plan_synchronize(); // Make sure the motion completes.
+ gc_set_current_position(sys.position[X_AXIS],sys.position[Y_AXIS],sys.position[Z_AXIS]);
+ PCICR |= (1 << LIMIT_INT); // Re-enable hard limits.
+ }
}
View
@@ -35,6 +35,7 @@
#define Z_AXIS 2
#define MM_PER_INCH (25.4)
+#define INCH_PER_MM (0.03937)
// Useful macros
#define clear_vector(a) memset(a, 0, sizeof(a))
@@ -60,16 +61,29 @@
#define EXEC_CYCLE_STOP bit(2) // bitmask 00000100
#define EXEC_FEED_HOLD bit(3) // bitmask 00001000
#define EXEC_RESET bit(4) // bitmask 00010000
-// #define bit(5) // bitmask 00100000
+#define EXEC_ALARM bit(5) // bitmask 00100000
// #define bit(6) // bitmask 01000000
// #define bit(7) // bitmask 10000000
+// Define bit flag masks for sys.switches. (8 flag limit)
+#define BITFLAG_BLOCK_DELETE bit(0)
+#define BITFLAG_SINGLE_BLOCK bit(1)
+#define BITFLAG_OPT_STOP bit(2)
+// #define bit(3)
+// #define bit(4)
+// #define bit(5)
+// #define bit(6)
+// #define bit(7)
+
// Define global system variables
typedef struct {
uint8_t abort; // System abort flag. Forces exit back to main loop for reset.
uint8_t feed_hold; // Feed hold flag. Held true during feed hold. Released when ready to resume.
uint8_t auto_start; // Planner auto-start flag. Toggled off during feed hold. Defaulted by settings.
-
+ uint8_t alarm; // Alarm mode. Causes all functions to immediately cease until a system abort
+ // is issued by the user.
+// uint8_t switches; // Switches state bitflag variable. For settings not governed by g-code.
+
int32_t position[3]; // Real-time machine (aka home) position vector in steps.
// NOTE: This may need to be a volatile variable, if problems arise.
@@ -82,6 +96,7 @@ typedef struct {
volatile uint8_t cycle_start; // Cycle start flag. Set by stepper subsystem or main program.
volatile uint8_t execute; // Global system runtime executor bitflag variable. See EXEC bitmasks.
+
} system_t;
extern system_t sys;
View
@@ -73,7 +73,7 @@ void protocol_status_report()
// may be distance to go on block, processed block id, and feed rate. A secondary, non-critical
// status report may include g-code state, i.e. inch mode, plane mode, absolute mode, etc.
// The report generated must be as short as possible, yet still provide the user easily readable
- // information, i.e. 'x0.23,y120.4,z2.4'. This is necessary as it minimizes the computational
+ // information, i.e. '[0.23,120.4,2.4]'. This is necessary as it minimizes the computational
// overhead and allows grbl to keep running smoothly, especially with g-code programs with fast,
// short line segments and interface setups that require real-time status reports (5-20Hz).
@@ -85,24 +85,33 @@ void protocol_status_report()
// home position by the user (likely through '$' setting interface).
// Successfully tested at a query rate of 10-20Hz while running a gauntlet of programs at various
// speeds.
- int32_t print_position[3];
- memcpy(print_position,sys.position,sizeof(sys.position));
- #if REPORT_INCH_MODE
- printString("MPos:["); printFloat(print_position[X_AXIS]/(settings.steps_per_mm[X_AXIS]*MM_PER_INCH));
- printString(","); printFloat(print_position[Y_AXIS]/(settings.steps_per_mm[Y_AXIS]*MM_PER_INCH));
- printString(","); printFloat(print_position[Z_AXIS]/(settings.steps_per_mm[Z_AXIS]*MM_PER_INCH));
- printString("],WPos:["); printFloat((print_position[X_AXIS]/settings.steps_per_mm[X_AXIS]-sys.coord_system[sys.coord_select][X_AXIS]-sys.coord_offset[X_AXIS])/MM_PER_INCH);
- printString(","); printFloat((print_position[Y_AXIS]/settings.steps_per_mm[Y_AXIS]-sys.coord_system[sys.coord_select][Y_AXIS]-sys.coord_offset[Y_AXIS])/MM_PER_INCH);
- printString(","); printFloat((print_position[Z_AXIS]/settings.steps_per_mm[Z_AXIS]-sys.coord_system[sys.coord_select][Z_AXIS]-sys.coord_offset[Z_AXIS])/MM_PER_INCH);
- #else
- printString("MPos:["); printFloat(print_position[X_AXIS]/(settings.steps_per_mm[X_AXIS]));
- printString(","); printFloat(print_position[Y_AXIS]/(settings.steps_per_mm[Y_AXIS]));
- printString(","); printFloat(print_position[Z_AXIS]/(settings.steps_per_mm[Z_AXIS]));
- printString("],WPos:["); printFloat(print_position[X_AXIS]/settings.steps_per_mm[X_AXIS]-sys.coord_system[sys.coord_select][X_AXIS]-sys.coord_offset[X_AXIS]);
- printString(","); printFloat(print_position[Y_AXIS]/settings.steps_per_mm[Y_AXIS]-sys.coord_system[sys.coord_select][Y_AXIS]-sys.coord_offset[Y_AXIS]);
- printString(","); printFloat(print_position[Z_AXIS]/settings.steps_per_mm[Z_AXIS]-sys.coord_system[sys.coord_select][Z_AXIS]-sys.coord_offset[Z_AXIS]);
- #endif
- printString("]\r\n");
+ uint8_t i;
+ int32_t current_position[3]; // Copy current state of the system position variable
+ memcpy(current_position,sys.position,sizeof(sys.position));
+ float print_position[3];
+
+ // Report machine position
+ printPgmString(PSTR("MPos:["));
+ for (i=0; i<= 2; i++) {
+ print_position[i] = current_position[i]/settings.steps_per_mm[i];
+ if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) { print_position[i] *= INCH_PER_MM; }
+ printFloat(print_position[i]);
+ if (i < 2) { printPgmString(PSTR(",")); }
+ }
+
+ // Report work position
+ printPgmString(PSTR("],WPos:["));
+ for (i=0; i<= 2; i++) {
+ if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) {
+ print_position[i] -= (sys.coord_system[sys.coord_select][i]+sys.coord_offset[i])*INCH_PER_MM;
+ } else {
+ print_position[i] -= sys.coord_system[sys.coord_select][i]+sys.coord_offset[i];
+ }
+ printFloat(print_position[i]);
+ if (i < 2) { printPgmString(PSTR(",")); }
+ }
+
+ printPgmString(PSTR("]\r\n"));
}
@@ -129,6 +138,12 @@ void protocol_execute_runtime()
{
if (sys.execute) { // Enter only if any bit flag is true
uint8_t rt_exec = sys.execute; // Avoid calling volatile multiple times
+
+ // System alarm. Something has gone wrong. Disable everything until system reset.
+ if (rt_exec & EXEC_ALARM) {
+ while (bit_isfalse(sys.execute,EXEC_RESET)) { sleep_mode(); }
+ bit_false(sys.execute,EXEC_ALARM);
+ }
// System abort. Steppers have already been force stopped.
if (rt_exec & EXEC_RESET) {
@@ -157,12 +172,12 @@ void protocol_execute_runtime()
if (rt_exec & EXEC_CYCLE_START) {
st_cycle_start(); // Issue cycle start command to stepper subsystem
- #ifdef CYCLE_AUTO_START
+ if (bit_istrue(settings.flags,BITFLAG_AUTO_START)) {
sys.auto_start = true; // Re-enable auto start after feed hold.
- #endif
+ }
bit_false(sys.execute,EXEC_CYCLE_START);
- }
- }
+ }
+ }
}
View
@@ -165,7 +165,11 @@ ISR(USART_RX_vect)
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_FEED_HOLD: sys.execute |= EXEC_FEED_HOLD; break; // Set as true
- case CMD_RESET:
+ case CMD_RESET:
+ sys.alarm |= EXEC_ALARM; // Set alarm to allow subsystem disable for certain settings.
+
+ // TODO: When Grbl system status is installed, set position lost state if the cycle is active.
+
// Immediately force stepper and spindle subsystem idle at an interrupt level.
if (!(sys.execute & EXEC_RESET)) { // Force stop only first time.
st_go_idle();
Oops, something went wrong.

0 comments on commit df5bb70

Please sign in to comment.