New report module. 6 persistent work coordinates. New G-codes and settings. README and minor bug updates

(NOTE: This push is likely buggy so proceed with caution. Just
uploading to let people know where we're going.)

- New report.c module. Moved all feedback functions into this module to
centralize these processes. Includes realtime status reports, status
messages, feedback messages.

- Official support 6 work coordinate systems (G54-G59), which are
persistently held in EEPROM memory.

- New g-code support: G28.1, G30.1 stores current machine position as a
home position into EEPROM. G10 L20 Px stores current machine position
into work coordinates without needing to explicitly send XYZ words.

- Homing performed with '$H' command. G28/G30 no longer start the
homing cycle. This is how it's supposed to be.

- New settings: Stepper enable invert and n_arc correction installed.

- Updated and changed up some limits and homing functionality. Pull-off
travel will now move after the homing cycle regardless of hard limits
enabled. Fixed direction of pull-off travel (went wrong way).

- Started on designing an internal Grbl command protocol based on the
'$' settings letter. Commands with non numeric characters after '$'
will perform switch commands, homing cycle, jogging, printing
paramters, etc. Much more to do here.

- Updated README to reflect all of the new features.
This commit is contained in:
Sonny Jeon
2012-11-01 09:37:27 -06:00
parent 5d8c3dcbd7
commit e0a9054e32
17 changed files with 847 additions and 621 deletions

View File

@ -31,124 +31,16 @@
#include <avr/pgmspace.h>
#include "stepper.h"
#include "planner.h"
#include "report.h"
#include "motion_control.h"
static char line[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated.
static uint8_t char_counter; // Last character counter in line variable.
static uint8_t iscomment; // Comment/block delete flag for processor to ignore comment characters.
// Method to handle status messages, from an 'ok' to report any 'error' that has occurred.
// Errors can originate from the g-code parser, settings module, or a critical error, such
// as a triggered hard limit.
void protocol_status_message(uint8_t status_code)
{
// TODO: Compile time option to only return numeric codes for GUIs.
if (status_code == 0) { // STATUS_OK
printPgmString(PSTR("ok\r\n"));
} else {
printPgmString(PSTR("error: "));
switch(status_code) {
case STATUS_BAD_NUMBER_FORMAT:
printPgmString(PSTR("Bad number format")); break;
case STATUS_EXPECTED_COMMAND_LETTER:
printPgmString(PSTR("Expected command letter")); break;
case STATUS_UNSUPPORTED_STATEMENT:
printPgmString(PSTR("Unsupported statement")); break;
case STATUS_FLOATING_POINT_ERROR:
printPgmString(PSTR("Floating point error")); break;
case STATUS_MODAL_GROUP_VIOLATION:
printPgmString(PSTR("Modal group violation")); break;
case STATUS_INVALID_STATEMENT:
printPgmString(PSTR("Invalid statement")); break;
case STATUS_HARD_LIMIT:
printPgmString(PSTR("Limit triggered")); break;
case STATUS_SETTING_DISABLED:
printPgmString(PSTR("Grbl setting disabled")); break;
case STATUS_SETTING_STEPS_NEG:
printPgmString(PSTR("Steps/mm must be > 0.0")); break;
case STATUS_SETTING_STEP_PULSE_MIN:
printPgmString(PSTR("Step pulse must be >= 3 microseconds")); break;
case STATUS_SETTING_READ_FAIL:
printPgmString(PSTR("Failed to read EEPROM settings. Using defaults")); break;
}
printPgmString(PSTR("\r\n"));
}
}
// Prints miscellaneous messages. This serves as a centralized method to provide additional
// user feedback for things that do not pass through the protocol_execute_line() function
// and are not errors or confirmations, such as setup warnings and how to exit alarms.
void protocol_misc_message(uint8_t message_code)
{
// TODO: Install silence misc messages option in settings
switch(message_code) {
case MESSAGE_SYSTEM_ALARM:
printPgmString(PSTR("<ALARM: Reset to continue>")); break;
case MESSAGE_HOMING_ENABLE:
printPgmString(PSTR("warning: Install all axes limit switches before use")); break;
}
printPgmString(PSTR("\r\n"));
}
void protocol_status_report()
{
// 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.
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(",")); }
else { 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(",")); }
else { printPgmString(PSTR("]")); }
}
printPgmString(PSTR("\r\n"));
}
void protocol_init()
{
// Print grbl initialization message
printPgmString(PSTR("\r\nGrbl " GRBL_VERSION));
printPgmString(PSTR("\r\n'$' to dump current settings\r\n"));
char_counter = 0; // Reset line input
iscomment = false;
}
@ -160,29 +52,43 @@ void protocol_init()
// This is a way to execute runtime commands asynchronously (aka multitasking) with grbl's g-code
// parsing and planning functions. This function also serves as an interface for the interrupts to
// set the system runtime flags, where only the main program handles them, removing the need to
// define more computationally-expensive volatile variables.
// NOTE: The sys.execute variable flags are set by the serial read subprogram, except where noted.
// define more computationally-expensive volatile variables. This also provides a controlled way to
// execute certain tasks without having two or more instances of the same task, such as the planner
// recalculating the buffer upon a feedhold or override.
// NOTE: The sys.execute variable flags are set by the serial read subprogram, except where noted,
// but may be set by any process, such as a switch pin change interrupt when pinouts are installed.
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.
// 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(sys.execute,EXEC_RESET)) { protocol_misc_message(MESSAGE_SYSTEM_ALARM); }
while (bit_isfalse(sys.execute,EXEC_RESET)) { sleep_mode(); }
if (bit_isfalse(rt_exec,EXEC_RESET)) { // Ignore loop if reset is already issued
report_feedback_message(MESSAGE_SYSTEM_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) {
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.
}
// Execute and serial print status
if (rt_exec & EXEC_STATUS_REPORT) {
protocol_status_report();
report_realtime_status();
bit_false(sys.execute,EXEC_STATUS_REPORT);
}
@ -206,41 +112,95 @@ void protocol_execute_runtime()
}
bit_false(sys.execute,EXEC_CYCLE_START);
}
}
}
// Overrides flag byte (sys.override) and execution should be installed here, since they
// are runtime and require a direct and controlled interface to the main stepper program.
}
// Executes one line of input according to protocol
// Directs and executes one line of formatted input from protocol_process. While mostly
// incoming streaming g-code blocks, this also executes Grbl internal commands, such as
// settings, initiating the homing cycle, and toggling switch states. This differs from
// the runtime command module by being susceptible to when Grbl is ready to execute the
// next line during a cycle, so for switches like block delete, the switch only effects
// the lines that are processed afterward, not necessarily real-time during a cycle,
// since there are motions already stored in the buffer. However, this 'lag' should not
// be an issue, since these commands are not typically used during a cycle.
uint8_t protocol_execute_line(char *line)
{
{
// Grbl internal command and parameter lines are of the form '$4=374.3' or '$' for help
if(line[0] == '$') {
// TODO: Re-write this '$' as a way to change runtime settings without having to reset, i.e.
// auto-starting, status query output formatting and type, jog mode (axes, direction, and
// nominal feedrate), toggle block delete, etc. This differs from the EEPROM settings, as they
// are considered defaults and loaded upon startup/reset.
// This use is envisioned where '$' itself dumps settings and help. Defined characters
// proceeding the '$' may be used to setup modes, such as jog mode with a '$J=X100' for X-axis
// motion with a nominal feedrate of 100mm/min. Writing EEPROM settings will likely stay the
// same or similar. Should be worked out in upcoming releases.
return(settings_execute_line(line)); // Delegate lines starting with '$' to the settings module
// } else if {
//
// JOG MODE
//
// TODO: Here jogging can be placed for execution as a seperate subprogram. It does not need to be
// susceptible to other runtime commands except for e-stop. The jogging function is intended to
// be a basic toggle on/off with controlled acceleration and deceleration to prevent skipped
// steps. The user would supply the desired feedrate, axis to move, and direction. Toggle on would
// start motion and toggle off would initiate a deceleration to stop. One could 'feather' the
// motion by repeatedly toggling to slow the motion to the desired location. Location data would
// need to be updated real-time and supplied to the user through status queries.
// More controlled exact motions can be taken care of by inputting G0 or G1 commands, which are
// 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.
uint8_t char_counter = 1;
float parameter, value;
switch( line[char_counter] ) {
case 0 :
report_grbl_help();
return(STATUS_OK);
break;
// case '#' :
// if ( line[++char_counter] == 0 ) {
// // Print all parameters
// return(STATUS_OK);
// } else {
// return(STATUS_UNSUPPORTED_STATEMENT);
// }
// case 'G' : // 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 'H' : // Perform homing cycle
if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) {
mc_go_home();
return(STATUS_OK);
} 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
// // susceptible to other runtime commands except for e-stop. The jogging function is intended to
// // be a basic toggle on/off with controlled acceleration and deceleration to prevent skipped
// // steps. The user would supply the desired feedrate, axis to move, and direction. Toggle on would
// // start motion and toggle off would initiate a deceleration to stop. One could 'feather' the
// // motion by repeatedly toggling to slow the motion to the desired location. Location data would
// // need to be updated real-time and supplied to the user through status queries.
// // More controlled exact motions can be taken care of by inputting G0 or G1 commands, which are
// // 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 'P' : // Print g-code parameters and parser state
// if(line[char_counter] != 0) { return(STATUS_UNSUPPORTED_STATEMENT); }
//
// break;
// case 'S' : // Switch methods
// // Opt stop and block delete are referred to as switches.
// // How to store home position and work offsets real-time??
// break;
// // Parse $parameter=value settings
default :
if(!read_float(line, &char_counter, &parameter)) {
return(STATUS_BAD_NUMBER_FORMAT);
}
if(line[char_counter++] != '=') {
return(STATUS_UNSUPPORTED_STATEMENT);
}
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));
}
} else {
return(gc_execute_line(line)); // Everything else is gcode
// TODO: Install option to set system alarm upon any error code received back from the
@ -250,7 +210,8 @@ uint8_t protocol_execute_line(char *line)
}
// Process one line of incoming serial data. Remove unneeded characters and capitalize.
// Process and report status one line of incoming serial data. Performs an initial filtering
// by removing spaces and comments and capitalizing all letters.
void protocol_process()
{
uint8_t c;
@ -265,10 +226,10 @@ void protocol_process()
if (char_counter > 0) {// Line is complete. Then execute!
line[char_counter] = 0; // Terminate string
protocol_status_message(protocol_execute_line(line));
report_status_message(protocol_execute_line(line));
} else {
// Empty or comment line. Skip block.
protocol_status_message(STATUS_OK); // Send status message for syncing purposes.
report_status_message(STATUS_OK); // Send status message for syncing purposes.
}
char_counter = 0; // Reset line buffer index
iscomment = false; // Reset comment flag