New startup script setting. New dry run, check gcode switches. New system state variable. Lots of reorganizing.

(All v0.8 features installed. Still likely buggy, but now thourough
testing will need to start to squash them all. As soon as we're done,
this will be pushed to master and v0.9 development will be started.
Please report ANY issues to us so we can get this rolled out ASAP.)

- User startup script! A user can now save one (up to 5 as compile-time
option) block of g-code in EEPROM memory. This will be run everytime
Grbl resets. Mainly to be used as a way to set your preferences, like
G21, G54, etc.

- New dry run and check g-code switches. Dry run moves ALL motions at
rapids rate ignoring spindle, coolant, and dwell commands. For rapid
physical proofing of your code. The check g-code switch ignores all
motion and provides the user a way to check if there are any errors in
their program that Grbl may not like.

- Program restart! (sort of). Program restart is typically an advanced
feature that allows users to restart a program mid-stream. The check
g-code switch can perform this feature by enabling the switch at the
start of the program, and disabling it at the desired point with some
minimal changes.

- New system state variable. This state variable tracks all of the
different state processes that Grbl performs, i.e. cycle start, feed
hold, homing, etc. This is mainly for making managing of these task
easier and more clear.

- Position lost state variable. Only when homing is enabled, Grbl will
refuse to move until homing is completed and position is known. This is
mainly for safety. Otherwise, it will let users fend for themselves.

- Moved the default settings defines into config.h. The plan is to
eventually create a set of config.h's for particular as-built machines
to help users from doing it themselves.

- Moved around misc defines into .h files. And lots of other little
things.
This commit is contained in:
Sonny Jeon 2012-11-03 11:32:23 -06:00
parent 303cf59f52
commit 4c711a4af7
25 changed files with 453 additions and 370 deletions

View File

@ -69,6 +69,33 @@
#define COOLANT_MIST_BIT 1 // Uno Analog Pin 1
#endif
// Default settings (used when resetting eeprom-settings)
// TODO: Begin to fill these out for various as-built machines, i.e. config_sherline5400.h
#define MICROSTEPS 4
#define DEFAULT_X_STEPS_PER_MM (94.488188976378*MICROSTEPS)
#define DEFAULT_Y_STEPS_PER_MM (94.488188976378*MICROSTEPS)
#define DEFAULT_Z_STEPS_PER_MM (94.488188976378*MICROSTEPS)
#define DEFAULT_STEP_PULSE_MICROSECONDS 10
#define DEFAULT_MM_PER_ARC_SEGMENT 0.1
#define DEFAULT_RAPID_FEEDRATE 500.0 // mm/min
#define DEFAULT_FEEDRATE 250.0
#define DEFAULT_ACCELERATION (DEFAULT_FEEDRATE*60*60/10.0) // mm/min^2
#define DEFAULT_JUNCTION_DEVIATION 0.05 // mm
#define DEFAULT_STEPPING_INVERT_MASK ((1<<X_STEP_BIT)|(1<<Y_STEP_BIT)|(1<<Z_STEP_BIT))
#define DEFAULT_REPORT_INCHES 0 // false
#define DEFAULT_AUTO_START 1 // true
#define DEFAULT_INVERT_ST_ENABLE 0 // false
#define DEFAULT_HARD_LIMIT_ENABLE 0 // false
#define DEFAULT_HOMING_ENABLE 0 // false
#define DEFAULT_HOMING_DIR_MASK 0 // move positive dir
#define DEFAULT_HOMING_RAPID_FEEDRATE 250.0 // mm/min
#define DEFAULT_HOMING_FEEDRATE 50 // mm/min
#define DEFAULT_HOMING_DEBOUNCE_DELAY 100 // msec (0-65k)
#define DEFAULT_HOMING_PULLOFF 1 // mm
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-255)
#define DEFAULT_DECIMAL_PLACES 3
#define DEFAULT_N_ARC_CORRECTION 25
// Define runtime command special characters. These characters are 'picked-off' directly from the
// serial read data stream and are not passed to the grbl line execution parser. Select characters
// that do not and must not exist in the streamed g-code program. ASCII control characters may be
@ -114,6 +141,12 @@
// greater.
#define N_HOMING_CYCLE 2 // Integer (1-128)
// Number of blocks Grbl executes upon startup. These blocks are stored in EEPROM, where the size
// 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 1 // Integer (1-5)
// ---------------------------------------------------------------------------------------
// FOR ADVANCED USERS ONLY:
@ -146,32 +179,6 @@
// ---------------------------------------------------------------------------------------
// 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.
// -> NOW CODED INTO SETTINGS #define BLOCK_DELETE_ENABLE 0 // Block delete enable/disable flag during g-code parsing
// 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
// CNC axes don't cause the axes to drift off position. This is particularly important when manually
// entering g-code into grbl, i.e. locating part zero or simple manual machining. If the axes drift,
// grbl has no way to know this has happened, since stepper motors are open-loop control. Depending
// on the machine, this parameter may need to be larger or smaller than the default time.
// NOTE: If set to zero, no lock will occur. If set to max 255, the lock will never release, in other
// words, the steppers never disable for users that require this.
// -> NOW INSTALLED IN SETTINGS #define STEPPER_IDLE_LOCK_TIME 25 // (milliseconds) - Integer > 0
// Number of arc generation iterations by small angle approximation before exact arc trajectory
// correction. This parameter maybe decreased if there are issues with the accuracy of the arc
// generations. In general, the default value is more than enough for the intended CNC applications
// of grbl, and should be on the order or greater than the size of the buffer to help with the
// computational efficiency of generating arcs.
// -> NOW INSTALLED IN SETTINGS #define N_ARC_CORRECTION 25 // Integer (1-255)
// Specifies the number of work coordinate systems grbl will support (G54 - G59).
// This parameter must be one or greater, currently supporting up to a value of 6.
// -> NOW CODED INTO SETTINGS.C #define N_COORDINATE_SYSTEM 6
// TODO: Install compile-time option to send numeric status codes rather than strings.
#endif

14
gcode.c
View File

@ -177,7 +177,7 @@ uint8_t gc_execute_line(char *line)
switch(int_value) {
case 0: gc.program_flow = PROGRAM_FLOW_PAUSED; break; // Program pause
case 1: // Program pause with optional stop on, otherwise do nothing.
if (bit_istrue(sys.switches,BITFLAG_OPT_STOP)) {
if (bit_istrue(gc.switches,BITFLAG_OPT_STOP)) {
gc.program_flow = PROGRAM_FLOW_PAUSED;
}
break;
@ -253,13 +253,20 @@ uint8_t gc_execute_line(char *line)
NOTE: Independent non-motion/settings parameters are set out of this order for code efficiency
and simplicity purposes, but this should not affect proper g-code execution. */
// ([F]: Set feed rate. Already performed, but enforce rapids for dry runs.)
if (bit_istrue(gc.switches,BITFLAG_DRY_RUN)) { gc.feed_rate = settings.default_seek_rate; }
// ([M6]: Tool change should be executed here.)
// [M3,M4,M5]: Update spindle state
if (!(gc.switches & (BITFLAG_DRY_RUN | BITFLAG_CHECK_GCODE))) {
spindle_run(gc.spindle_direction); //, gc.spindle_speed);
}
// [*M7,M8,M9]: Update coolant state
if (!(gc.switches & (BITFLAG_DRY_RUN | BITFLAG_CHECK_GCODE))) {
coolant_run(gc.coolant_mode);
}
// [G54,G55,...,G59]: Coordinate system selection
if ( bit_istrue(modal_group_words,bit(MODAL_GROUP_12)) ) { // Check if called in block
@ -276,8 +283,11 @@ uint8_t gc_execute_line(char *line)
if (p < 0) { // Time cannot be negative.
FAIL(STATUS_INVALID_STATEMENT);
} else {
// Ignore dwell in dry run and check gcode modes
if (!(gc.switches & (BITFLAG_DRY_RUN | BITFLAG_CHECK_GCODE))) {
mc_dwell(p);
}
}
break;
case NON_MODAL_SET_COORDINATE_DATA:
int_value = trunc(p); // Convert p value to int.
@ -537,7 +547,7 @@ uint8_t gc_execute_line(char *line)
// M0,M1,M2,M30: Perform non-running program flow actions. During a program pause, the buffer may
// refill and can only be resumed by the cycle start run-time command.
if (gc.program_flow || bit_istrue(sys.switches,BITFLAG_SINGLE_BLOCK)) {
if (gc.program_flow || bit_istrue(gc.switches,BITFLAG_SINGLE_BLOCK)) {
plan_synchronize(); // Finish all remaining buffered motions. Program paused when complete.
sys.auto_start = false; // Disable auto cycle start. Forces pause until cycle start issued.

11
gcode.h
View File

@ -62,8 +62,19 @@
#define NON_MODAL_SET_COORDINATE_OFFSET 7 // G92
#define NON_MODAL_RESET_COORDINATE_OFFSET 8 //G92.1
// Define bit flag masks for gc.switches. (8 flag limit)
#define BITFLAG_CHECK_GCODE bit(0)
#define BITFLAG_DRY_RUN bit(1)
#define BITFLAG_BLOCK_DELETE bit(2)
#define BITFLAG_SINGLE_BLOCK bit(3)
#define BITFLAG_OPT_STOP bit(4)
// #define bit(5)
// #define bit(6)
// #define bit(7)
typedef struct {
uint8_t status_code; // Parser status for current block
uint8_t switches; // Handles non-gcode switches modes. Set externally by protocol. Default off
uint8_t motion_mode; // {G0, G1, G2, G3, G80}
uint8_t inverse_feed_rate_mode; // {G93, G94}
uint8_t inches_mode; // 0 = millimeter mode, 1 = inches mode {G20, G21}

View File

@ -33,7 +33,6 @@
#include "limits.h"
#include "report.h"
#define MICROSECONDS_PER_ACCELERATION_TICK (1000000/ACCELERATION_TICKS_PER_SECOND)
void limits_init()
{
@ -63,7 +62,7 @@ ISR(LIMIT_INT_vect)
// Kill all processes upon hard limit event.
if ((LIMIT_PIN & LIMIT_MASK) ^ LIMIT_MASK) {
mc_alarm(); // Initiate system kill.
report_status_message(STATUS_HARD_LIMIT); // Print ok in interrupt since system killed.
sys.state = STATE_LIMIT; // Set system state to indicate event.
}
}
}

View File

@ -22,6 +22,7 @@
#define limits_h
#define LIMIT_MASK ((1<<X_LIMIT_BIT)|(1<<Y_LIMIT_BIT)|(1<<Z_LIMIT_BIT)) // All limit bits
#define MICROSECONDS_PER_ACCELERATION_TICK (1000000/ACCELERATION_TICKS_PER_SECOND)
// initialize the limits module
void limits_init();

48
main.c
View File

@ -51,8 +51,7 @@ 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.
sys.state = STATE_LOST; // Set state to indicate unknown initial position
for(;;) {
@ -60,44 +59,41 @@ int main(void)
// 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) {
// Retain last known machine position and work coordinate offset(s). If the system abort
// occurred while in motion, machine position is not guaranteed, since a hard stop can cause
// the steppers to lose steps. Always perform a feedhold before an abort, if maintaining
// accurate machine position is required.
// TODO: Report last position and coordinate offset to users to help relocate origins. Future
// releases will auto-reset the machine position back to [0,0,0] if an abort is used while
// grbl is moving the machine.
int32_t last_position[3];
memcpy(last_position, sys.position, sizeof(sys.position)); // last_position[] = sys.position[]
// TODO: Last coordinate system method.
// If a critical event has occurred, set the position lost system state. For example, a
// hard limit event can cause the stepper to lose steps and position due to an immediate
// stop, not with a controlled deceleration. Or, if an abort was issued while a cycle
// was active, the immediate stop can also cause lost steps.
if (sys.state == STATE_ALARM) { sys.state = STATE_LOST; }
// Reset system.
memset(&sys, 0, sizeof(sys)); // Clear all system variables
serial_reset_read_buffer(); // Clear serial read buffer
settings_init(); // Load grbl settings from EEPROM
protocol_init(); // Clear incoming line data
plan_init(); // Clear block buffer and planner variables
gc_init(); // Set g-code parser to default state
protocol_init(); // Clear incoming line data and execute startup lines
spindle_init();
coolant_init();
limits_init();
st_reset(); // Clear stepper subsystem variables.
// Reload last known machine position and work systems. G92 coordinate offsets are reset.
memcpy(sys.position, last_position, sizeof(last_position)); // sys.position[] = last_position[]
gc_set_current_position(last_position[X_AXIS],last_position[Y_AXIS],last_position[Z_AXIS]);
plan_set_current_position(last_position[X_AXIS],last_position[Y_AXIS],last_position[Z_AXIS]);
// Set 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 ensure its position,
// a feedback message will be sent back to the user to let them know.
gc_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]);
// 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.
if (bit_istrue(settings.flags,BITFLAG_AUTO_START)) {
sys.auto_start = true;
// Reset system variables
sys.abort = false;
sys.execute = 0;
if (sys.state == STATE_LOST && bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) {
report_feedback_message(MESSAGE_POSITION_LOST);
} else {
sys.state = STATE_IDLE;
}
// TODO: Install G20/G21 unit default into settings and load appropriate settings.
if (bit_istrue(settings.flags,BITFLAG_AUTO_START)) { sys.auto_start = true; }
report_init_message();
// Execute user startup script
protocol_execute_startup();
}
protocol_execute_runtime();

View File

@ -21,15 +21,15 @@
*/
#include <avr/io.h>
#include <util/delay.h>
#include <math.h>
#include <stdlib.h>
#include "settings.h"
#include "config.h"
#include "gcode.h"
#include "motion_control.h"
#include "spindle_control.h"
#include "coolant_control.h"
#include <util/delay.h>
#include <math.h>
#include <stdlib.h>
#include "nuts_bolts.h"
#include "stepper.h"
#include "planner.h"
@ -62,8 +62,17 @@ void mc_line(float x, float y, float z, float feed_rate, uint8_t invert_feed_rat
protocol_execute_runtime(); // Check for any run-time commands
if (sys.abort) { return; } // Bail, if system abort.
} while ( plan_check_full_buffer() );
// If in check gcode mode, prevent motion by blocking planner.
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 (!sys.state) { sys.state = STATE_QUEUED; }
// Auto-cycle start immediately after planner finishes. Enabled/disabled by grbl settings. During
// a feed hold, auto-start is disabled momentarily until the cycle is resumed by the cycle-start
// runtime command.
@ -73,6 +82,7 @@ void mc_line(float x, float y, float z, float feed_rate, uint8_t invert_feed_rat
// command sent during manual operation; or if a system is prone to buffer starvation, auto-start
// helps make sure it minimizes any dwelling/motion hiccups and keeps the cycle going.
if (sys.auto_start) { st_cycle_start(); }
}
}
@ -195,14 +205,19 @@ void mc_dwell(float seconds)
}
// Execute homing cycle to locate and set machine zero.
// Perform homing cycle to locate and set machine zero. Only '$H' executes this command.
// NOTE: There should be no motions in the buffer and Grbl must be in an idle state before
// executing the homing cycle. This prevents incorrect buffered plans after homing.
void mc_go_home()
{
plan_synchronize(); // Empty all motions in buffer before homing.
sys.state = STATE_HOMING; // Set system state variable
PCICR &= ~(1 << LIMIT_INT); // Disable hard limits pin change interrupt
plan_clear_position();
limits_go_home(); // Perform homing routine.
if (sys.abort) {
sys.state = STATE_LOST; // Homing routine did not complete.
return;
}
// The machine should now be homed and machine zero has been located. Upon completion,
// reset planner and system internal position vectors, but not gcode parser position yet.
@ -227,6 +242,7 @@ void mc_go_home()
// 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); }
sys.state = STATE_IDLE; // Finished!
}

View File

@ -40,7 +40,7 @@ void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8
// Dwell for a specific number of seconds
void mc_dwell(float seconds);
// Send the tool home (not implemented)
// Perform homing cycle to locate machine zero. Requires limit switches.
void mc_go_home();
// Kills all motion and sets system alarm

View File

@ -20,8 +20,6 @@
*/
#include "nuts_bolts.h"
#include <stdint.h>
#include <stdlib.h>
#include <util/delay.h>
#define MAX_INT_DIGITS 8 // Maximum number of digits in int32 (and float)

View File

@ -66,36 +66,29 @@
// #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 Grbl system states for sys.state
// Define position lost in states?
// 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 but reset
#define STATE_LOST 7 // Used to message position may be lost upon startup or event
#define STATE_LIMIT 8 // Used to message hard limit triggered.
// 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 switches; // Switches state bitflag variable. For features not governed by g-code.
// uint8_t state; // Tracks the current state of Grbl.
// TODO: This may replace the functionality of the feed_hold and cycle_start variables. Need to
// make sure that overall processes don't change.
volatile uint8_t cycle_start; // Cycle start flag. Set by stepper subsystem or main program.
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.
// 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;

View File

@ -23,9 +23,7 @@
/* The ring buffer implementation gleaned from the wiring_serial library by David A. Mellis. */
#include <inttypes.h>
#include <math.h>
#include <stdlib.h>
#include "planner.h"
#include "nuts_bolts.h"
#include "stepper.h"
@ -33,9 +31,6 @@
#include "config.h"
#include "protocol.h"
// The number of linear motions that can be in the plan at any give time
#define BLOCK_BUFFER_SIZE 18
static block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instructions
static volatile uint8_t block_buffer_head; // Index of the next block to be pushed
static volatile uint8_t block_buffer_tail; // Index of the block to process now
@ -335,7 +330,7 @@ uint8_t plan_check_full_buffer()
// Block until all buffered steps are executed.
void plan_synchronize()
{
while (plan_get_current_block() || sys.cycle_start) {
while (plan_get_current_block()) {
protocol_execute_runtime(); // Check and execute run-time commands
if (sys.abort) { return; } // Check for system abort
}

View File

@ -22,7 +22,8 @@
#ifndef planner_h
#define planner_h
#include <inttypes.h>
// The number of linear motions that can be in the plan at any give time
#define BLOCK_BUFFER_SIZE 18
// This struct is used when buffering the setup for each linear movement "nominal" values are as specified in
// the source g-code and may never actually be reached if acceleration management is active.

View File

@ -23,7 +23,6 @@
used to be a part of the Arduino project. */
#include <math.h>
#include <avr/pgmspace.h>
#include "config.h"
#include "serial.h"
@ -109,6 +108,8 @@ void printInteger(long n)
// Convert float to string by immediately converting to a long integer, which contains
// more digits than a float. Number of decimal places, which are tracked by a counter,
// may be set by the user. The integer is then efficiently converted to a string.
// NOTE: AVR '%' and '/' integer operations are very efficient. Bitshifting speed-up
// techniques are actually just slightly slower. Found this out the hard way.
void printFloat(float n)
{
if (n < 0) {

View File

@ -26,11 +26,8 @@
#include "print.h"
#include "settings.h"
#include "config.h"
#include <math.h>
#include "nuts_bolts.h"
#include <avr/pgmspace.h>
#include "stepper.h"
#include "planner.h"
#include "report.h"
#include "motion_control.h"
@ -43,8 +40,24 @@ void protocol_init()
{
char_counter = 0; // Reset line input
iscomment = false;
report_init_message(); // Welcome message
}
// Executes user startup script, if stored.
void protocol_execute_startup()
{
uint8_t n;
for (n=0; n < N_STARTUP_LINE; n++) {
if (!(settings_read_startup_line(n, line))) {
report_status_message(STATUS_SETTING_READ_FAIL);
} else {
if (line[0] != 0) {
printString(line); // Echo startup line to indicate execution.
report_status_message(gc_execute_line(line));
}
}
}
}
// Executes run-time commands, when required. This is called from various check points in the main
// program, primarily where there may be a while loop waiting for a buffer to clear space or any
@ -65,7 +78,16 @@ void protocol_execute_runtime()
// System alarm. Something has gone wrong. Disable everything by entering an infinite
// loop until system reset/abort.
if (rt_exec & EXEC_ALARM) {
if (bit_isfalse(rt_exec,EXEC_RESET)) { // Ignore loop if reset is already issued
// Report the cause of the alarm here in the main program.
if (sys.state == STATE_LIMIT) { report_status_message(STATUS_HARD_LIMIT); }
if (sys.state == STATE_CYCLE) { // Pick up abort during active cycle.
report_status_message(STATUS_ABORT_CYCLE);
sys.state = STATE_LOST;
}
// Ignore loop if reset is already issued. In other words, a normal system abort/reset
// will not enter this loop, only a critical event not controlled by the user will.
if (bit_isfalse(rt_exec,EXEC_RESET)) {
sys.state = STATE_ALARM;
report_feedback_message(MESSAGE_SYSTEM_ALARM);
while (bit_isfalse(sys.execute,EXEC_RESET)) { sleep_mode(); }
}
@ -75,14 +97,6 @@ void protocol_execute_runtime()
// System abort. Steppers have already been force stopped.
if (rt_exec & EXEC_RESET) {
sys.abort = true;
// If the cycle is active before killing the motion, the event will likely caused a loss
// of position since there is no controlled deceleration(feed hold) to a stop.
// TODO: Add force home option upon position lost. Need to verify that cycle start isn't
// set false by anything but the stepper module. Also, need to look at a better place for
// this. Main.c?
// if (sys.cycle_start) { protocol_feedback_message(MESSAGE_POSITION_LOST); }
return; // Nothing else to do but exit.
}
@ -98,7 +112,7 @@ void protocol_execute_runtime()
bit_false(sys.execute,EXEC_FEED_HOLD);
}
// Reinitializes the stepper module running flags and re-plans the buffer after a feed hold.
// Reinitializes the stepper module running state and, if a feed hold, re-plans the buffer.
// NOTE: EXEC_CYCLE_STOP is set by the stepper subsystem when a cycle or feed hold completes.
if (rt_exec & EXEC_CYCLE_STOP) {
st_cycle_reinitialize();
@ -133,6 +147,7 @@ uint8_t protocol_execute_line(char *line)
if(line[0] == '$') {
uint8_t char_counter = 1;
uint8_t helper_var = 0; // Helper variable
float parameter, value;
switch( line[char_counter] ) {
case 0 : report_grbl_help(); break;
@ -149,8 +164,11 @@ uint8_t protocol_execute_line(char *line)
else { report_gcode_modes(); }
break;
case 'H' : // Perform homing cycle
if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) { mc_go_home(); }
else { return(STATUS_SETTING_DISABLED); }
if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) {
// Only perform homing if Grbl is idle or lost.
if ( sys.state==STATE_IDLE || sys.state==STATE_LOST ) { mc_go_home(); }
else { return(STATUS_HOMING_ERROR); }
} else { return(STATUS_SETTING_DISABLED); }
break;
// case 'J' : break; // Jogging methods
// TODO: Here jogging can be placed for execution as a seperate subprogram. It does not need to be
@ -164,42 +182,63 @@ uint8_t protocol_execute_line(char *line)
// handled by the planner. It would be possible for the jog subprogram to insert blocks into the
// block buffer without having the planner plan them. It would need to manage de/ac-celerations
// on its own carefully. This approach could be effective and possibly size/memory efficient.
// case 'N' : // Start up blocks
// if(!read_float(line, &char_counter, &parameter)) { return(STATUS_BAD_NUMBER_FORMAT); }
// if(line[char_counter++] != '=') { return(STATUS_UNSUPPORTED_STATEMENT); }
// // Extract startup block, execute, and store.
// for (char_counter = 0; char_counter < LINE_BUFFER_SIZE-3; char_counter++) {
// line[char_counter] = line[char_counter+3];
// }
// uint8_t status = gc_execute_line(line);
// if (status) { return(status); }
// else { settings_store_startup_block(line); }
// break;
case 'B' : // Toggle block delete
case 'S' : // Switch modes
// Set helper_var as switch bitmask or clearing flag
switch (line[++char_counter]) {
case 0 : helper_var = 0; break;
case '0' : helper_var = BITFLAG_CHECK_GCODE; break;
case '1' : helper_var = BITFLAG_DRY_RUN; break;
case '2' : helper_var = BITFLAG_BLOCK_DELETE; break;
case '3' : helper_var = BITFLAG_SINGLE_BLOCK; break;
case '4' : helper_var = BITFLAG_OPT_STOP; break;
default : return(STATUS_INVALID_STATEMENT);
}
if (helper_var) {
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
sys.switches ^= BITFLAG_BLOCK_DELETE;
if (bit_istrue(sys.switches,BITFLAG_BLOCK_DELETE)) { report_feedback_message(MESSAGE_SWITCH_ON); }
gc.switches ^= helper_var;
if (bit_istrue(gc.switches,helper_var)) { report_feedback_message(MESSAGE_SWITCH_ON); }
else { report_feedback_message(MESSAGE_SWITCH_OFF); }
} else {
gc.switches = helper_var; // Clear all switches
report_feedback_message(MESSAGE_SWITCHES_CLEARED);
}
break;
case 'S' : // Toggle single block mode
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
sys.switches ^= BITFLAG_SINGLE_BLOCK;
if (bit_istrue(sys.switches,BITFLAG_SINGLE_BLOCK)) { report_feedback_message(MESSAGE_SWITCH_ON); }
else { report_feedback_message(MESSAGE_SWITCH_OFF); }
case 'N' : // Startup lines.
if ( line[++char_counter] == 0 ) { // Print startup lines
for (helper_var=0; helper_var < N_STARTUP_LINE; helper_var++) {
if (!(settings_read_startup_line(helper_var, line))) {
report_status_message(STATUS_SETTING_READ_FAIL);
} else {
report_startup_line(helper_var,line);
}
}
break;
case 'O' : // Toggle optional stop
if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); }
sys.switches ^= BITFLAG_OPT_STOP;
if (bit_istrue(sys.switches,BITFLAG_OPT_STOP)) { report_feedback_message(MESSAGE_SWITCH_ON); }
else { report_feedback_message(MESSAGE_SWITCH_OFF); }
break;
default : // Store global setting
} else { // Store startup line
helper_var = true; // Set helper_var to flag storing method.
// No break. Continues into default: to read remaining command characters.
}
default : // Storing setting methods
if(!read_float(line, &char_counter, &parameter)) { return(STATUS_BAD_NUMBER_FORMAT); }
if(line[char_counter++] != '=') { return(STATUS_UNSUPPORTED_STATEMENT); }
if (helper_var) { // Store startup line
// Prepare sending gcode block to gcode parser by shifting all characters
helper_var = char_counter; // Set helper variable as counter to start of gcode block
do {
line[char_counter-helper_var] = line[char_counter];
} while (line[char_counter++] != 0);
// Execute gcode block to ensure block is valid.
helper_var = gc_execute_line(line); // Set helper_var to returned status code.
if (helper_var) { return(helper_var); }
else {
helper_var = trunc(parameter); // Set helper_var to int value of parameter
settings_store_startup_line(helper_var,line);
}
} else { // Store global setting.
if(!read_float(line, &char_counter, &value)) { return(STATUS_BAD_NUMBER_FORMAT); }
if(line[char_counter] != 0) { return(STATUS_UNSUPPORTED_STATEMENT); }
return(settings_store_global_setting(parameter, value));
}
}
return(STATUS_OK); // If '$' command makes it to here, then everything's ok.
} else {
@ -249,7 +288,7 @@ void protocol_process()
// Throw away whitepace and control characters
} else if (c == '/') {
// Disable block delete and throw away characters. Will ignore until EOL.
if (bit_istrue(sys.switches,BITFLAG_BLOCK_DELETE)) {
if (bit_istrue(gc.switches,BITFLAG_BLOCK_DELETE)) {
iscomment = true;
}
} else if (c == '(') {

View File

@ -21,6 +21,8 @@
#ifndef protocol_h
#define protocol_h
#include <avr/sleep.h>
// Line buffer size from the serial input stream to be executed.
// NOTE: Not a problem except for extreme cases, but the line buffer size can be too small
// and g-code blocks can get truncated. Officially, the g-code standards support up to 256
@ -42,4 +44,7 @@ uint8_t protocol_execute_line(char *line);
// Checks and executes a runtime command at various stop points in main program
void protocol_execute_runtime();
// Execute the startup script lines stored in EEPROM upon initialization
void protocol_execute_startup();
#endif

View File

@ -9,25 +9,26 @@ It accepts standards-compliant G-code and has been tested with the output of sev
Grbl includes full acceleration management with look ahead. That means the controller will look up to 18 motions into the future and plan its velocities ahead to deliver smooth acceleration and jerk-free cornering.
*Changelog for v0.8 from v0.7:*
- *BETA status: _Under development. Code state may significantly change with each push as new features are integrated._*
- Major structural overhaul to allow for multi-tasking events and new feature sets
- New run-time command control: Feed hold (pause), Cycle start (resume), Reset (abort), Status reporting
- *BETA status: _Under development but nearing completion. Code state may change with each push as new features are integrated or when bugs are squashed._*
- Major structural overhaul to allow for multi-tasking events and new feature sets.
- Run-time command control: Feed hold (pause), Cycle start (resume), Reset (abort), Status reporting
- Controlled feed hold with deceleration to ensure no skipped steps and loss of location.
- After feed hold, cycle accelerations are re-planned and may be resumed.
- Advanced homing cycle with direction and speed configuration options. (Requires limit switches.)
- Limit pins are held normal high with an internal pull-up resister. Wiring only requires a normally-open switch connected to ground. (For both ends of an axis, simply wire two in parallel into the same pin.)
- Advanced homing cycle with direction and speed configuration options. (Requires limit switches.) When enabled, homing is required before use to ensure safety.
- Limit pins are held normal high with internal pull-up resistors. Wiring only requires a normally-open switch connected to ground. (For both ends of an axis, simply wire two in parallel into the same pin.)
- Hard limits option and plays nice with homing cycle, so switches can be used for both homing and hard limits.
- New switch commands: Dry-run, block delete, single block mode, optional stop. A check g-code switch has also been added to allow users to error check their programs. This feature can also be used as a "program restart" by enabling the check g-code switch, begin streaming, and disable the check g-code switch at the desired point with minimal additional g-code.
- Re-factored g-code parser with robust error-checking.
- 6 work coordinate systems (G54-G59), offsets(G92), and machine coordinate system support. Work systems are stored in EEPROM and persistent.
- 6 work coordinate systems (G54-G59), offsets(G92), and machine coordinate system support. Work coordinate systems are stored in EEPROM and persistent.
- G10 L2 and L20 work coordinate settings support. L2 sets one or more axes values. L20 sets the current machine position to the specified work origin.
- Program stop(M0,M1*,M2,M30) initial support. Optional stop to do.
- Program stop(M0,M1,M2,M30) initial support.
- Coolant control(M7*,M8,M9) support. (M7 is a compile-time option).
- System reset re-initializes grbl without resetting the Arduino and retains machine/home position and work coordinates.
- Restructured planner and stepper modules to become independent and ready for future features.
- Settings re-factoring to allow configuration without compiling of most features. (Still in progress).
- Settings overhauled and dozens of new settings and internal commands are now available, when most were compile-time only.
- New startup line setting. Allows users to store a custom g-code block into Grbl's startup routine. Executes immediately upon startup or reset. May be used to set g-code defaults like G20.
- Misc bug fixes and removed deprecated acceleration enabled code.
- Planned features: Axis acceleration and max speed individual settings, full-featured status reporting, runtime settings such as toggling block delete.
- Advanced compile-time options: Up to 6 work coordinate systems(G54-G59), XON/XOFF flow control (limited support), direction and step pulse time delay.
- Planned features: Axis acceleration and max speed individual settings, full-featured status reporting.
- Advanced compile-time options: XON/XOFF flow control (limited support), direction and step pulse time delay, and up to 5 startup lines.
*Important note for Atmega 168 users:* Going forward, support for Atmega 168 will be dropped due to its limited memory and speed. However, legacy Grbl v0.51 "in the branch called 'v0_51' is still available for use.

165
report.c
View File

@ -26,14 +26,11 @@
methods to accomodate their needs.
*/
#include <avr/io.h>
#include "print.h"
#include "settings.h"
#include <math.h>
#include "nuts_bolts.h"
#include <avr/pgmspace.h>
#include "report.h"
#include "protocol.h"
#include "print.h"
#include "settings.h"
#include "nuts_bolts.h"
#include "gcode.h"
#include "coolant_control.h"
@ -75,6 +72,10 @@ void report_status_message(uint8_t status_code)
printPgmString(PSTR("Step pulse must be >= 3 microseconds")); break;
case STATUS_SETTING_READ_FAIL:
printPgmString(PSTR("Failed to read EEPROM settings. Using defaults")); break;
case STATUS_HOMING_ERROR:
printPgmString(PSTR("Grbl must be idle to home")); break;
case STATUS_ABORT_CYCLE:
printPgmString(PSTR("Abort during cycle")); break;
}
printPgmString(PSTR("\r\n"));
}
@ -84,78 +85,91 @@ void report_status_message(uint8_t status_code)
// 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
// are messages such as setup warnings and how to exit alarms.
// NOTE: For interfaces, messages are always placed within chevrons. 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.
// TODO: Install silence feedback messages option in settings
void report_feedback_message(int8_t message_code)
{
printPgmString(PSTR("<"));
printPgmString(PSTR("["));
switch(message_code) {
case MESSAGE_SYSTEM_ALARM:
printPgmString(PSTR("ALARM: Check and reset Grbl")); break;
case MESSAGE_POSITION_LOST:
printPgmString(PSTR("warning: Position may be lost")); break;
printPgmString(PSTR("Position unknown. '$H' to home")); break;
case MESSAGE_HOMING_ENABLE:
printPgmString(PSTR("'$H' to home. Ensure all limit switches are installed")); break;
printPgmString(PSTR("WARNING: All limit switches must be installed before homing")); break;
case MESSAGE_SWITCH_ON:
printPgmString(PSTR("Switch enabled")); break;
case MESSAGE_SWITCH_OFF:
printPgmString(PSTR("Switch disabled")); break;
case MESSAGE_SWITCHES_CLEARED:
printPgmString(PSTR("Switches cleared")); break;
}
printPgmString(PSTR(">\r\n"));
printPgmString(PSTR("]\r\n"));
}
// Welcome message
void report_init_message()
{
printPgmString(PSTR("\r\nGrbl " GRBL_VERSION " ['$' for help]\r\n"));
}
// Grbl help message
void report_grbl_help() {
// char st_line[LINE_BUFFER_SIZE];
// printPgmString(PSTR("\r\n\r\n Startup\r\n$100 = ")); printString(settings_read_startup(st_line,0));
// printPgmString(PSTR("\r\n$101 = ")); printString(settings_read_startup(st_line,1));
// char buf[4];
// settings_startup_string((char *)buf);
// printPgmString(PSTR("\r\n Startup: ")); printString(buf);
printPgmString(PSTR("$ (help)\r\n$$ (print Grbl settings)\r\n$# (print gcode parameters)\r\n$G (print gcode parser state)"));
printPgmString(PSTR("\r\n$x=value (store Grbl setting)\r\n$Nx=line (store startup block)\r\n$H (run homing cycle, if enabled)"));
printPgmString(PSTR("\r\n$B (toggle block delete)\r\n$S (toggle single block mode)\r\n$O (toggle opt stop)"));
printPgmString(PSTR("\r\n~ (cycle start)\r\n! (feed hold)\r\n? (current position)\r\n^x (reset Grbl)\r\n"));
printPgmString(PSTR("$ (help)\r\n"
"$$ (print Grbl settings)\r\n"
"$# (print gcode parameters)\r\n"
"$G (print gcode parser state)\r\n"
"$N (print startup blocks)\r\n"
"$x=value (store Grbl setting)\r\n"
"$Nx=line (store startup block)\r\n"
"$H (perform homing cycle)\r\n"
"$S (clear all switches)\r\n"
"$S0 (toggle check gcode)\r\n"
"$S1 (toggle dry run)\r\n"
"$S2 (toggle block delete)\r\n"
"$S3 (toggle single block)\r\n"
"$S4 (toggle optional stop)\r\n"
"~ (cycle start)\r\n"
"! (feed hold)\r\n"
"? (current position)\r\n"
"^x (reset Grbl)\r\n"));
}
// Grbl global settings print out.
// NOTE: The numbering scheme here must correlate to storing in settings.c
void report_grbl_settings() {
printPgmString(PSTR("$0 = ")); printFloat(settings.steps_per_mm[X_AXIS]);
printPgmString(PSTR(" (x axis, steps/mm)\r\n$1 = ")); printFloat(settings.steps_per_mm[Y_AXIS]);
printPgmString(PSTR(" (y axis, steps/mm)\r\n$2 = ")); printFloat(settings.steps_per_mm[Z_AXIS]);
printPgmString(PSTR(" (z axis, steps/mm)\r\n$3 = ")); printInteger(settings.pulse_microseconds);
printPgmString(PSTR(" (step pulse, usec)\r\n$4 = ")); printFloat(settings.default_feed_rate);
printPgmString(PSTR(" (default feed rate, mm/min)\r\n$5 = ")); printFloat(settings.default_seek_rate);
printPgmString(PSTR(" (default seek rate, mm/min)\r\n$6 = ")); printFloat(settings.mm_per_arc_segment);
printPgmString(PSTR(" (arc resolution, mm/segment)\r\n$7 = ")); printInteger(settings.invert_mask);
printPgmString(PSTR(" (step port invert mask, int:binary = ")); print_uint8_base2(settings.invert_mask);
printPgmString(PSTR(")\r\n$8 = ")); printFloat(settings.acceleration/(60*60)); // Convert from mm/min^2 for human readability
printPgmString(PSTR(" (acceleration, mm/sec^2)\r\n$9 = ")); printFloat(settings.junction_deviation);
printPgmString(PSTR(" (cornering junction deviation, mm)\r\n$10 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_REPORT_INCHES));
printPgmString(PSTR(" (status report inches, bool)\r\n$11 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_AUTO_START));
printPgmString(PSTR(" (auto start enable, bool)\r\n$12 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE));
printPgmString(PSTR(" (invert stepper enable, bool)\r\n$13 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE));
printPgmString(PSTR(" (hard limit enable, bool)\r\n$14 = ")); printInteger(bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE));
printPgmString(PSTR(" (homing enable, bool)\r\n$15 = ")); printInteger(settings.homing_dir_mask);
printPgmString(PSTR(" (homing direction mask, int:binary = ")); print_uint8_base2(settings.homing_dir_mask);
printPgmString(PSTR(")\r\n$16 = ")); printFloat(settings.homing_feed_rate);
printPgmString(PSTR(" (homing feed rate, mm/min)\r\n$17 = ")); printFloat(settings.homing_seek_rate);
printPgmString(PSTR(" (homing seek rate, mm/min)\r\n$18 = ")); printInteger(settings.homing_debounce_delay);
printPgmString(PSTR(" (homing debounce delay, msec)\r\n$19 = ")); printFloat(settings.homing_pulloff);
printPgmString(PSTR(" (homing pull-off travel, mm)\r\n$20 = ")); printInteger(settings.stepper_idle_lock_time);
printPgmString(PSTR(" (stepper idle lock time, msec)\r\n$21 = ")); printInteger(settings.decimal_places);
printPgmString(PSTR(" (decimal places, int)\r\n$22 = ")); printInteger(settings.n_arc_correction);
printPgmString(PSTR("$0=")); printFloat(settings.steps_per_mm[X_AXIS]);
printPgmString(PSTR(" (x axis, steps/mm)\r\n$1=")); printFloat(settings.steps_per_mm[Y_AXIS]);
printPgmString(PSTR(" (y axis, steps/mm)\r\n$2=")); printFloat(settings.steps_per_mm[Z_AXIS]);
printPgmString(PSTR(" (z axis, steps/mm)\r\n$3=")); printInteger(settings.pulse_microseconds);
printPgmString(PSTR(" (step pulse, usec)\r\n$4=")); printFloat(settings.default_feed_rate);
printPgmString(PSTR(" (default feed rate, mm/min)\r\n$5=")); printFloat(settings.default_seek_rate);
printPgmString(PSTR(" (default seek rate, mm/min)\r\n$6=")); printFloat(settings.mm_per_arc_segment);
printPgmString(PSTR(" (arc resolution, mm/segment)\r\n$7=")); printInteger(settings.invert_mask);
printPgmString(PSTR(" (step port invert mask, int:binary=")); print_uint8_base2(settings.invert_mask);
printPgmString(PSTR(")\r\n$8=")); printFloat(settings.acceleration/(60*60)); // Convert from mm/min^2 for human readability
printPgmString(PSTR(" (acceleration, mm/sec^2)\r\n$9=")); printFloat(settings.junction_deviation);
printPgmString(PSTR(" (cornering junction deviation, mm)\r\n$10=")); printInteger(bit_istrue(settings.flags,BITFLAG_REPORT_INCHES));
printPgmString(PSTR(" (report inches, bool)\r\n$11=")); printInteger(bit_istrue(settings.flags,BITFLAG_AUTO_START));
printPgmString(PSTR(" (auto start enable, bool)\r\n$12=")); printInteger(bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE));
printPgmString(PSTR(" (invert stepper enable, bool)\r\n$13=")); printInteger(bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE));
printPgmString(PSTR(" (hard limit enable, bool)\r\n$14=")); printInteger(bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE));
printPgmString(PSTR(" (homing enable, bool)\r\n$15=")); printInteger(settings.homing_dir_mask);
printPgmString(PSTR(" (homing dir invert mask, int:binary=")); print_uint8_base2(settings.homing_dir_mask);
printPgmString(PSTR(")\r\n$16=")); printFloat(settings.homing_feed_rate);
printPgmString(PSTR(" (homing feed rate, mm/min)\r\n$17=")); printFloat(settings.homing_seek_rate);
printPgmString(PSTR(" (homing seek rate, mm/min)\r\n$18=")); printInteger(settings.homing_debounce_delay);
printPgmString(PSTR(" (homing debounce delay, msec)\r\n$19=")); printFloat(settings.homing_pulloff);
printPgmString(PSTR(" (homing pull-off travel, mm)\r\n$20=")); printInteger(settings.stepper_idle_lock_time);
printPgmString(PSTR(" (stepper idle lock time, msec)\r\n$21=")); printInteger(settings.decimal_places);
printPgmString(PSTR(" (decimal places, int)\r\n$22=")); printInteger(settings.n_arc_correction);
printPgmString(PSTR(" (n arc correction, int)\r\n"));
}
// Prints gcode coordinate offset parameters
void report_gcode_parameters()
{
float coord_data[N_AXIS];
@ -174,7 +188,7 @@ void report_gcode_parameters()
case 5: printPgmString(PSTR("G59")); break;
case 6: printPgmString(PSTR("G28")); break;
case 7: printPgmString(PSTR("G30")); break;
// case 8: printPgmString(PSTR("G92")); break; // G92.2, G92.3 currently not supported.
// case 8: printPgmString(PSTR("G92")); break; // G92.2, G92.3 not supported. Hence not stored.
}
printPgmString(PSTR(":["));
for (i=0; i<N_AXIS; i++) {
@ -193,6 +207,8 @@ void report_gcode_parameters()
}
}
// Print current gcode parser mode state and active switches
void report_gcode_modes()
{
switch (gc.motion_mode) {
@ -220,8 +236,6 @@ void report_gcode_modes()
if (gc.inverse_feed_rate_mode) { printPgmString(PSTR(" G93")); }
else { printPgmString(PSTR(" G94")); }
// TODO: Check if G92 needs to be here. If so, how to track it.
switch (gc.program_flow) {
case PROGRAM_FLOW_RUNNING : printPgmString(PSTR(" M0")); break;
case PROGRAM_FLOW_PAUSED : printPgmString(PSTR(" M1")); break;
@ -237,7 +251,9 @@ void report_gcode_modes()
switch (gc.coolant_mode) {
case COOLANT_DISABLE : printPgmString(PSTR(" M9")); break;
case COOLANT_FLOOD_ENABLE : printPgmString(PSTR(" M8")); break;
// case COOLANT_MIST_ENABLE : printPgmString(PSTR(" M7")); break;
#ifdef ENABLE_M7
case COOLANT_MIST_ENABLE : printPgmString(PSTR(" M7")); break;
#endif
}
printPgmString(PSTR(" T"));
@ -247,36 +263,37 @@ void report_gcode_modes()
if (gc.inches_mode) { printFloat(gc.feed_rate*INCH_PER_MM); }
else { printFloat(gc.feed_rate); }
if (sys.switches) {
if (bit_istrue(sys.switches,BITFLAG_BLOCK_DELETE)) { printPgmString(PSTR(" $B")); }
if (bit_istrue(sys.switches,BITFLAG_SINGLE_BLOCK)) { printPgmString(PSTR(" $S")); }
if (bit_istrue(sys.switches,BITFLAG_OPT_STOP)) { printPgmString(PSTR(" $O")); }
// Print active switches
if (gc.switches) {
if (bit_istrue(gc.switches,BITFLAG_CHECK_GCODE)) { printPgmString(PSTR(" $S0")); }
if (bit_istrue(gc.switches,BITFLAG_DRY_RUN)) { printPgmString(PSTR(" $S1")); }
if (bit_istrue(gc.switches,BITFLAG_BLOCK_DELETE)) { printPgmString(PSTR(" $S2")); }
if (bit_istrue(gc.switches,BITFLAG_SINGLE_BLOCK)) { printPgmString(PSTR(" $S3")); }
if (bit_istrue(gc.switches,BITFLAG_OPT_STOP)) { printPgmString(PSTR(" $S4")); }
}
printPgmString(PSTR("\r\n"));
}
// Prints specified startup line
void report_startup_line(uint8_t n, char *line)
{
printPgmString(PSTR("N")); printInteger(n);
printPgmString(PSTR("=")); printString(line);
printPgmString(PSTR("\r\n"));
}
// Prints real-time data. This function grabs a real-time snapshot of the stepper subprogram
// and the actual location of the CNC machine. Users may change the following function to their
// specific needs, but the desired real-time data report must be as short as possible. This is
// requires as it minimizes the computational overhead and allows grbl to keep running smoothly,
// especially during g-code programs with fast, short line segments and high frequency reports (5-20Hz).
void report_realtime_status()
{
// TODO: Status report data is written to the user here. This function should be able to grab a
// real-time snapshot of the stepper subprogram and the actual location of the CNC machine. At a
// minimum, status report should return real-time location information. Other important information
// 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. '[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).
// **Under construction** Bare-bones status report. Provides real-time machine position relative to
// the system power on location (0,0,0) and work coordinate position (G54 and G92 applied).
// The following are still needed: user setting of output units (mm|inch), compressed (non-human
// readable) data for interfaces?, save last known position in EEPROM?, code optimizations, solidify
// the reporting schemes, move to a separate .c file for easy user accessibility, and setting the
// 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.
// the system power on location (0,0,0) and work coordinate position (G54 and G92 applied). Eventually
// to be added are distance to go on block, processed block id, and feed rate. Also a settings bitmask
// for a user to select the desired real-time data.
uint8_t i;
int32_t current_position[3]; // Copy current state of the system position variable
memcpy(current_position,sys.position,sizeof(sys.position));

View File

@ -34,6 +34,8 @@
#define STATUS_SETTING_VALUE_NEG 9
#define STATUS_SETTING_STEP_PULSE_MIN 10
#define STATUS_SETTING_READ_FAIL 11
#define STATUS_HOMING_ERROR 12
#define STATUS_ABORT_CYCLE 13
// Define Grbl feedback message codes. Less than zero to distinguish message from error.
#define MESSAGE_SYSTEM_ALARM -1
@ -41,6 +43,7 @@
#define MESSAGE_HOMING_ENABLE -3
#define MESSAGE_SWITCH_ON -4
#define MESSAGE_SWITCH_OFF -5
#define MESSAGE_SWITCHES_CLEARED -6
// Prints system status messages.
void report_status_message(uint8_t status_code);
@ -54,6 +57,7 @@ void report_init_message();
// Prints Grbl help and current global settings
void report_grbl_help();
// Prints Grbl global settings
void report_grbl_settings();
// Prints realtime status report
@ -62,6 +66,10 @@ void report_realtime_status();
// Prints Grbl persistent coordinate parameters
void report_gcode_parameters();
// Prints current g-code parser mode state and active switches
void report_gcode_modes();
// Prints startup line
void report_startup_line(uint8_t n, char *line);
#endif

View File

@ -23,16 +23,11 @@
used to be a part of the Arduino project. */
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include "serial.h"
#include "config.h"
#include "motion_control.h"
#include "nuts_bolts.h"
#include "protocol.h"
#define RX_BUFFER_SIZE 128
#define TX_BUFFER_SIZE 64
uint8_t rx_buffer[RX_BUFFER_SIZE];
uint8_t rx_buffer_head = 0;
uint8_t rx_buffer_tail = 0;
@ -42,14 +37,6 @@ uint8_t tx_buffer_head = 0;
volatile uint8_t tx_buffer_tail = 0;
#ifdef ENABLE_XONXOFF
#define RX_BUFFER_FULL 96 // XOFF high watermark
#define RX_BUFFER_LOW 64 // XON low watermark
#define SEND_XOFF 1
#define SEND_XON 2
#define XOFF_SENT 3
#define XON_SENT 4
#define XOFF_CHAR 0x13
#define XON_CHAR 0x11
volatile uint8_t flow_ctrl = XON_SENT; // Flow control state variable
// Returns the number of bytes in the RX buffer. This replaces a typical byte counter to prevent

View File

@ -25,8 +25,23 @@
#ifndef serial_h
#define serial_h
#include "nuts_bolts.h"
#define RX_BUFFER_SIZE 128
#define TX_BUFFER_SIZE 64
#define SERIAL_NO_DATA 0xff
#ifdef ENABLE_XONXOFF
#define RX_BUFFER_FULL 96 // XOFF high watermark
#define RX_BUFFER_LOW 64 // XON low watermark
#define SEND_XOFF 1
#define SEND_XON 2
#define XOFF_SENT 3
#define XON_SENT 4
#define XOFF_CHAR 0x13
#define XON_CHAR 0x11
#endif
void serial_init(long baud);
void serial_write(uint8_t data);

View File

@ -20,15 +20,12 @@
*/
#include <avr/io.h>
#include <math.h>
#include "protocol.h"
#include "report.h"
#include "stepper.h"
#include "nuts_bolts.h"
#include "settings.h"
#include "eeprom.h"
#include "print.h"
#include <avr/pgmspace.h>
#include "protocol.h"
#include "config.h"
#include "report.h"
settings_t settings;
@ -45,49 +42,29 @@ typedef struct {
float junction_deviation;
} settings_v4_t;
// Default settings (used when resetting eeprom-settings)
#define MICROSTEPS 8
#define DEFAULT_X_STEPS_PER_MM (94.488188976378*MICROSTEPS)
#define DEFAULT_Y_STEPS_PER_MM (94.488188976378*MICROSTEPS)
#define DEFAULT_Z_STEPS_PER_MM (94.488188976378*MICROSTEPS)
#define DEFAULT_STEP_PULSE_MICROSECONDS 30
#define DEFAULT_MM_PER_ARC_SEGMENT 0.1
#define DEFAULT_RAPID_FEEDRATE 500.0 // mm/min
#define DEFAULT_FEEDRATE 500.0
#define DEFAULT_ACCELERATION (DEFAULT_FEEDRATE*60*60/10.0) // mm/min^2
#define DEFAULT_JUNCTION_DEVIATION 0.05 // mm
#define DEFAULT_STEPPING_INVERT_MASK ((1<<X_STEP_BIT)|(1<<Y_STEP_BIT)|(1<<Z_STEP_BIT))
// Developmental default settings
#define DEFAULT_REPORT_INCHES 0 // false
#define DEFAULT_AUTO_START 1 // true
#define DEFAULT_INVERT_ST_ENABLE 0 // false
#define DEFAULT_HARD_LIMIT_ENABLE 0 // false
#define DEFAULT_HOMING_ENABLE 0 // false
#define DEFAULT_HOMING_DIR_MASK 0 // move positive dir
#define DEFAULT_HOMING_RAPID_FEEDRATE 250.0 // mm/min
#define DEFAULT_HOMING_FEEDRATE 50 // mm/min
#define DEFAULT_HOMING_DEBOUNCE_DELAY 100 // msec (0-65k)
#define DEFAULT_HOMING_PULLOFF 1 // mm
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-255)
#define DEFAULT_DECIMAL_PLACES 3
#define DEFAULT_N_ARC_CORRECTION 25
// Method to store startup lines into EEPROM
void settings_store_startup_line(uint8_t n, char *line)
{
uint16_t addr = n*(LINE_BUFFER_SIZE+1)+EEPROM_ADDR_STARTUP_BLOCK;
memcpy_to_eeprom_with_checksum(addr,(char*)line, LINE_BUFFER_SIZE);
}
// Method to store coord data parameters into EEPROM
void settings_write_coord_data(uint8_t coord_select, float *coord_data)
{
uint16_t addr = coord_select*(sizeof(float)*N_AXIS+1) + EEPROM_ADDR_PARAMETERS;
memcpy_to_eeprom_with_checksum(addr,(char*)coord_data, sizeof(float)*N_AXIS);
}
// Method to store Grbl global settings struct and version number into EEPROM
void write_global_settings()
{
eeprom_put_char(0, SETTINGS_VERSION);
memcpy_to_eeprom_with_checksum(EEPROM_ADDR_GLOBAL, (char*)&settings, sizeof(settings_t));
}
// Method to reset Grbl global settings back to defaults.
void settings_reset(bool reset_all) {
// Reset all settings or only the migration settings to the new version.
if (reset_all) {
@ -118,13 +95,20 @@ void settings_reset(bool reset_all) {
settings.decimal_places = DEFAULT_DECIMAL_PLACES;
settings.n_arc_correction = DEFAULT_N_ARC_CORRECTION;
write_global_settings();
}
// Zero all coordinate parameter data.
float coord_data[N_AXIS];
clear_vector_float(coord_data);
uint8_t i = 0;
for (i=0; i<=SETTING_INDEX_NCOORD; i++) {
settings_write_coord_data(i,coord_data);
// Reads startup line from EEPROM. Updated pointed line string data.
uint8_t settings_read_startup_line(uint8_t n, char *line)
{
uint16_t addr = n*(LINE_BUFFER_SIZE+1)+EEPROM_ADDR_STARTUP_BLOCK;
if (!(memcpy_from_eeprom_with_checksum((char*)line, addr, LINE_BUFFER_SIZE))) {
// Reset line with default value
// TODO: Need to come up with a method to do this.
line[0] = 0;
settings_store_startup_line(n, line);
return(false);
} else {
return(true);
}
}
@ -132,8 +116,9 @@ void settings_reset(bool reset_all) {
uint8_t settings_read_coord_data(uint8_t coord_select, float *coord_data)
{
uint16_t addr = coord_select*(sizeof(float)*N_AXIS+1) + EEPROM_ADDR_PARAMETERS;
if ((!memcpy_from_eeprom_with_checksum((char*)coord_data, addr, sizeof(float)*N_AXIS))) {
clear_vector_float(coord_data); // Default zero vector
if (!(memcpy_from_eeprom_with_checksum((char*)coord_data, addr, sizeof(float)*N_AXIS))) {
// Reset with default zero vector
clear_vector_float(coord_data);
settings_write_coord_data(coord_select,coord_data);
return(false);
} else {
@ -141,7 +126,7 @@ uint8_t settings_read_coord_data(uint8_t coord_select, float *coord_data)
}
}
// Reads Grbl global settings struct from EEPROM.
uint8_t read_global_settings() {
// Check version-byte of eeprom
uint8_t version = eeprom_get_char(0);
@ -164,7 +149,7 @@ uint8_t read_global_settings() {
// should be re-written to the default value, if the developmental version number changed.
// Grab settings regardless of error.
memcpy_from_eeprom_with_checksum((char*)&settings, 1, sizeof(settings_t));
memcpy_from_eeprom_with_checksum((char*)&settings, EEPROM_ADDR_GLOBAL, sizeof(settings_t));
settings_reset(false);
} else {
return(false);
@ -195,9 +180,14 @@ uint8_t settings_store_global_setting(int parameter, float value) {
} else { settings.flags &= ~BITFLAG_REPORT_INCHES; }
break;
case 11:
// Immediately apply auto_start to sys struct.
if (value) {
settings.flags |= BITFLAG_AUTO_START;
} else { settings.flags &= ~BITFLAG_AUTO_START; }
sys.auto_start = true;
} else {
settings.flags &= ~BITFLAG_AUTO_START;
sys.auto_start = false;
}
break;
case 12:
if (value) {
@ -212,6 +202,8 @@ uint8_t settings_store_global_setting(int parameter, float value) {
case 14:
if (value) {
settings.flags |= BITFLAG_HOMING_ENABLE;
sys.state = STATE_LOST;
report_feedback_message(MESSAGE_POSITION_LOST);
report_feedback_message(MESSAGE_HOMING_ENABLE);
} else { settings.flags &= ~BITFLAG_HOMING_ENABLE; }
break;
@ -224,7 +216,12 @@ uint8_t settings_store_global_setting(int parameter, float value) {
settings.homing_pulloff = value; break;
case 20:
settings.stepper_idle_lock_time = round(value);
// TODO: Immediately check and toggle steppers from always enable or disable?
// Immediately toggle stepper enable/disable functions to ensure change from always
// enable or disable. Will not start or stop a cycle.
if (!sys.state) { // Only if idle.
st_wake_up();
st_go_idle();
}
break;
case 21: settings.decimal_places = round(value); break;
case 22: settings.n_arc_correction = round(value); break;
@ -240,17 +237,15 @@ void settings_init() {
if(!read_global_settings()) {
report_status_message(STATUS_SETTING_READ_FAIL);
settings_reset(true);
report_grbl_help();
report_grbl_settings();
}
// Read all parameter data into a dummy variable. If error, reset to zero, otherwise do nothing.
float coord_data[N_AXIS];
uint8_t i;
for (i=0; i<=SETTING_INDEX_NCOORD; i++) {
if (!settings_read_coord_data(i, coord_data)) {
report_status_message(STATUS_SETTING_READ_FAIL);
}
}
// NOTE: Startup lines are handled and called by protocol_init().
}
// int8_t settings_execute_startup() {
//
// char buf[4];
// settings_startup_string((char *)buf);
// uint8_t i = 0;
// while (i < 4) {
// serial_write(buf[i++]);
// }
// return(gc_execute_line(buf));
// }

View File

@ -23,7 +23,6 @@
#define settings_h
#include <math.h>
#include <inttypes.h>
#include "nuts_bolts.h"
#define GRBL_VERSION "0.8c"
@ -45,7 +44,7 @@
// developments.
#define EEPROM_ADDR_GLOBAL 1
#define EEPROM_ADDR_PARAMETERS 512
#define EEPROM_ADDR_STARTUP_SCRIPT 768
#define EEPROM_ADDR_STARTUP_BLOCK 768
// Define EEPROM address indexing for coordinate parameters
#define N_COORDINATE_SYSTEM 6 // Number of supported work coordinate systems (from index 1)
@ -85,12 +84,16 @@ void settings_init();
// A helper method to set new settings from command line
uint8_t settings_store_global_setting(int parameter, float value);
// Stores the protocol line variable as a startup line in EEPROM
void settings_store_startup_line(uint8_t n, char *line);
// Reads an EEPROM startup line to the protocol line variable
uint8_t settings_read_startup_line(uint8_t n, char *line);
// Writes selected coordinate data to EEPROM
void settings_write_coord_data(uint8_t coord_select, float *coord_data);
// Reads selected coordinate data from EEPROM
uint8_t settings_read_coord_data(uint8_t coord_select, float *coord_data);
// int8_t settings_execute_startup();
#endif

View File

@ -19,14 +19,9 @@
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#include "spindle_control.h"
#include "settings.h"
#include "motion_control.h"
#include "config.h"
#include "spindle_control.h"
#include "planner.h"
#include "stepper.h"
#include <stdint.h>
static uint8_t current_direction;

View File

@ -22,19 +22,12 @@
/* The timer calculations of this module informed by the 'RepRap cartesian firmware' by Zack Smith
and Philipp Tiefenbacher. */
#include <avr/interrupt.h>
#include "stepper.h"
#include "config.h"
#include "settings.h"
#include <math.h>
#include <stdlib.h>
#include <util/delay.h>
#include "nuts_bolts.h"
#include <avr/interrupt.h>
#include "planner.h"
// Some useful constants
#define TICKS_PER_MICROSECOND (F_CPU/1000000)
#define CYCLES_PER_ACCELERATION_TICK ((TICKS_PER_MICROSECOND*1000000)/ACCELERATION_TICKS_PER_SECOND)
// Stepper state variable. Contains running data and trapezoid variables.
typedef struct {
@ -94,7 +87,7 @@ void st_wake_up()
} else {
STEPPERS_DISABLE_PORT &= ~(1<<STEPPERS_DISABLE_BIT);
}
if (sys.cycle_start) {
if (sys.state == STATE_CYCLE) {
// Initialize stepper output bits
out_bits = (0) ^ (settings.invert_mask);
// Initialize step pulse timing from settings. Here to ensure updating after re-writing.
@ -176,7 +169,7 @@ ISR(TIMER1_COMPA_vect)
// Anything in the buffer? If so, initialize next motion.
current_block = plan_get_current_block();
if (current_block != NULL) {
if (!sys.feed_hold) {
if (sys.state == STATE_CYCLE) {
// During feed hold, do not update rate and trap counter. Keep decelerating.
st.trapezoid_adjusted_rate = current_block->initial_rate;
set_step_events_per_minute(st.trapezoid_adjusted_rate); // Initialize cycles_per_step_event
@ -190,7 +183,6 @@ ISR(TIMER1_COMPA_vect)
st.step_events_completed = 0;
} else {
st_go_idle();
sys.cycle_start = false;
bit_true(sys.execute,EXEC_CYCLE_STOP); // Flag main program for cycle end
}
}
@ -224,7 +216,7 @@ ISR(TIMER1_COMPA_vect)
// While in block steps, check for de/ac-celeration events and execute them accordingly.
if (st.step_events_completed < current_block->step_event_count) {
if (sys.feed_hold) {
if (sys.state == STATE_HOLD) {
// Check for and execute feed hold by enforcing a steady deceleration from the moment of
// execution. The rate of deceleration is limited by rate_delta and will never decelerate
// faster or slower than in normal operation. If the distance required for the feed hold
@ -240,7 +232,6 @@ ISR(TIMER1_COMPA_vect)
// remain intact to ensure the stepper path is exactly the same. Feed hold is still
// active and is released after the buffer has been reinitialized.
st_go_idle();
sys.cycle_start = false;
bit_true(sys.execute,EXEC_CYCLE_STOP); // Flag main program that feed hold is complete.
} else {
st.trapezoid_adjusted_rate -= current_block->rate_delta;
@ -430,24 +421,18 @@ static void set_step_events_per_minute(uint32_t steps_per_minute)
// variable will manage all of Grbl's processes and keep them separate.
void st_cycle_start()
{
if (!sys.cycle_start) {
if (!sys.feed_hold) {
if (bit_isfalse(sys.execute,EXEC_ALARM)) {
sys.cycle_start = true; // Only place this variable is set true.
if (sys.state == STATE_QUEUED) {
sys.state = STATE_CYCLE;
st_wake_up();
}
}
}
}
// Execute a feed hold with deceleration, only during cycle. Called by main program.
void st_feed_hold()
{
if (!sys.feed_hold) {
if (sys.cycle_start) {
if (sys.state == STATE_CYCLE) {
sys.state = STATE_HOLD;
sys.auto_start = false; // Disable planner auto start upon feed hold.
sys.feed_hold = true;
}
}
}
@ -466,6 +451,8 @@ void st_cycle_reinitialize()
set_step_events_per_minute(st.trapezoid_adjusted_rate);
st.trapezoid_tick_cycle_counter = CYCLES_PER_ACCELERATION_TICK/2; // Start halfway for midpoint rule.
st.step_events_completed = 0;
sys.state = STATE_QUEUED;
} else {
sys.state = STATE_IDLE;
}
sys.feed_hold = false; // Release feed hold. Cycle is ready to re-start.
}

View File

@ -23,7 +23,6 @@
#define stepper_h
#include <avr/io.h>
#include <avr/sleep.h>
// Some useful constants
#define STEP_MASK ((1<<X_STEP_BIT)|(1<<Y_STEP_BIT)|(1<<Z_STEP_BIT)) // All step bits
@ -31,6 +30,10 @@
#define STEPPING_MASK (STEP_MASK | DIRECTION_MASK) // All stepping-related bits (step/direction)
#define STEPPERS_DISABLE_MASK (1<<STEPPERS_DISABLE_BIT)
#define TICKS_PER_MICROSECOND (F_CPU/1000000)
#define CYCLES_PER_ACCELERATION_TICK ((TICKS_PER_MICROSECOND*1000000)/ACCELERATION_TICKS_PER_SECOND)
// Initialize and setup the stepper motor subsystem
void st_init();