From df5bb70b2515b8bc05ca7c90abf1b221f63aeafe Mon Sep 17 00:00:00 2001 From: Sonny Jeon Date: Tue, 16 Oct 2012 21:29:45 -0600 Subject: [PATCH] Hard limits, homing direction, pull-off limits after homing, status reports 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. --- config.h | 8 ++--- gcode.c | 5 +-- limits.c | 37 ++++++++++++++------ main.c | 12 +++++-- motion_control.c | 23 ++++++++++++- nuts_bolts.h | 19 ++++++++-- protocol.c | 61 +++++++++++++++++++------------- serial.c | 6 +++- settings.c | 90 ++++++++++++++++++++++++++++++++---------------- settings.h | 11 +++--- stepper.c | 4 +-- 11 files changed, 193 insertions(+), 83 deletions(-) diff --git a/config.h b/config.h index fc5605e..73c4533 100755 --- a/config.h +++ b/config.h @@ -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 diff --git a/gcode.c b/gcode.c index c59bac7..8437405 100755 --- a/gcode.c +++ b/gcode.c @@ -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); diff --git a/limits.c b/limits.c index da36409..0785fa5 100755 --- a/limits.c +++ b/limits.c @@ -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<. */ +/* 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 #include #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. } diff --git a/motion_control.c b/motion_control.c index 26f16bc..76d8092 100755 --- a/motion_control.c +++ b/motion_control.c @@ -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. + } } diff --git a/nuts_bolts.h b/nuts_bolts.h index 8e9b58b..d4ecb2d 100755 --- a/nuts_bolts.h +++ b/nuts_bolts.h @@ -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; diff --git a/protocol.c b/protocol.c index 78e42bf..234ad45 100755 --- a/protocol.c +++ b/protocol.c @@ -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); - } - } + } + } } diff --git a/serial.c b/serial.c index aa35237..a346cd3 100755 --- a/serial.c +++ b/serial.c @@ -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(); diff --git a/settings.c b/settings.c index e012c5c..d4e723c 100755 --- a/settings.c +++ b/settings.c @@ -69,14 +69,16 @@ typedef struct { #define DEFAULT_STEPPING_INVERT_MASK ((1<