v1.1e: New laser features. G-code parser refactoring. CoreXY homing fix.

- Increment to v1.1e due to new laser features.

- After several discussions with some prominent laser people, a few
tweaks to the new laser mode has been installed.

- LASER: M3 behaves in a constant power mode.

- LASER: M4 behaves in a dynamic power mode, where the laser power is
automatically adjusted based on how fast Grbl is moving relative to the
programmed feed rate. This is the same as the  CONSTANT_POWER_PER_RATE
config.h option in the last version. NOTE: When not in motion in M4,
Grbl automatically turns off the laser. Again, it only operates while
moving!

- LASER: Only G1, G2, and G3 motion modes will turn on the laser. So,
this means that G0, G80 motion modes will always keep the laser
disabled. No matter if M3/M4 are active!

- LASER: A spindle stop override is automatically invoked when a laser
is put in a feed hold. This behavior may be disabled by a config.h
option.

- Lots of little tweaks to the g-code parser to help streamline it a
bit. It should no effect how it operates. Generally just added a parser
flag to track and execute certain scenarios a little more clearly.

- Jog motions now allow line numbers to be passed to it and will be
displayed in the status reports.

- Fixed a CoreXY homing bug.

- Fixed an issue when $13 is changed, WCO isn’t sent immediately.

- Altered how spindle PWM is set in the stepper ISR. Updated on a step
segment basis now. May need to change this back if there are any
oddities from doing this.

- Updated some documentation. Clarified why M0 no longer showing up in
$G and why a `1.` floating point values are shown with no decimals,
like so `1`.
pull/800/head
Sonny Jeon 2016-12-03 18:02:45 -07:00
rodzic 998f23b9ce
commit b753c542c7
18 zmienionych plików z 219 dodań i 145 usunięć

Wyświetl plik

@ -1,3 +1,18 @@
----------------
Date: 2016-11-12
Author: Sonny Jeon
Subject: PWM calculation correction.
- The PWM calculation was a little bit off and has been corrected.
- Edited the unused settings strings to be smaller and just show what
the settings are, rather than include units. May include this in the
master build, if it fits.
- The minimum spindle PWM define in config.h needed to be update for
cpu map compatibilty.
----------------
Date: 2016-11-04
Author: Sonny Jeon

Wyświetl plik

@ -37,6 +37,11 @@ Grbl v1.1's interface protocol has been tweaked in the attempt to make GUI devel
In addition, all `$x=val` settings, `error:`, and `ALARM:` messages no longer contain human-readable strings, but rather codes that are defined in other documents. The `$` help message is also reduced to just showing the available commands. Doing this saves incredible amounts of flash space. Otherwise, the new overrides features would not have fit.
Other minor changes and bug fixes that may effect GUI parsing include:
- Floating point values printed with zero precision do not show a decimal, or look like an integer. This includes spindle speed RPM and feed rate in mm mode.
- `$G` reports fixed a long time bug with program modal state. It always showed `M0` program pause when running. Now during a normal program run, no program modal state is given until an `M0`, `M2`, or `M30` is active and then the appropriate state will be shown.
On a final note, these interface tweaks came about out of necessity, because more data is being sent back from Grbl, it is capable of doing many more things, and flash space is at a premium. It's not intended to be altered again in the near future, if at all. This is likely the only and last major change to this. If you have any comments or suggestions before Grbl v1.1 goes to master, please do immediately so we can all vet the new alteration before its installed.
----

Wyświetl plik

@ -255,13 +255,18 @@ Feedback messages provide non-critical information on what Grbl is doing, what i
- **Queried Feedback Messages:**
- `[GC:]` G-code Parser State Message
- Initiated by the user via a `$G` command. Grbl replies as follows, where the `[GC:` denotes the message type and is followed by a separate `ok` to confirm the `$G` was executed.
```
[GC:G0 G54 G17 G21 G90 G94 M0 M5 M9 T0 F0. S0.]
- `[GC:]` G-code Parser State Message
```
[GC:G0 G54 G17 G21 G90 G94 M5 M9 T0 F0.0 S0]
ok
```
- The shown g-code are the current modal states of Grbl's g-code parser. This may not correlate to what is executing since there are usually several motions queued in the planner buffer.
```
- Initiated by the user via a `$G` command. Grbl replies as follows, where the `[GC:` denotes the message type and is followed by a separate `ok` to confirm the `$G` was executed.
- The shown g-code are the current modal states of Grbl's g-code parser. This may not correlate to what is executing since there are usually several motions queued in the planner buffer.
- NOTE: Program modal state has been fixed and will show `M0`, `M2`, or `M30` when they are active. During a run state, nothing will appear for program modal state.
- `[HLP:]` : Initiated by the user via a `$` print help command. The help message is shown below with a separate `ok` to confirm the `$` was executed.
```
@ -589,4 +594,11 @@ Grbl v1.1's interface protocol has been tweaked in the attempt to make GUI devel
- `>G54G20:ok` : The open chevron indicates startup line execution. The `:ok` suffix shows it executed correctly without adding an unmatched `ok` response on a new line.
In addition, all `$x=val` settings, `error:`, and `ALARM:` messages no longer contain human-readable strings, but rather codes that are defined in other documents. The `$` help message is also reduced to just showing the available commands. Doing this saves incredible amounts of flash space. Otherwise, the new overrides features would not have fit.
Other minor changes and bug fixes that may effect GUI parsing include:
- Floating point values printed with zero precision do not show a decimal, or look like an integer. This includes spindle speed RPM and feed rate in mm mode.
- `$G` reports fixed a long time bug with program modal state. It always showed `M0` program pause when running. Now during a normal program run, no program modal state is given until an `M0`, `M2`, or `M30` is active and then the appropriate state will be shown.
On a final note, this interface tweak came about out of necessity, as more data is being sent back from Grbl and it is capable of doing many more things. It's not intended to be altered again in the near future, if at all. This is likely the only and last major change to this. If you have any comments or suggestions before Grbl v1.1 goes to master, please do immediately so we can all vet the new alteration before its installed.

Wyświetl plik

@ -13,7 +13,8 @@ Executing a jog requires a specific command structure, as described below:
- G20 or G21 - Inch and millimeter mode
- G90 or G91 - Absolute and incremental distances
- G53 - Move in machine coordinates
- All other g-codes, m-codes, and value words are not accepted in the jog command.
- N line numbers are valid. Will show in reports, if enabled, but is otherwise ignored.
- All other g-codes, m-codes, and value words (including S and T) are not accepted in the jog command.
- Spaces and comments are allowed in the command. These are removed by the pre-parser.
- Example: G21 and G90 are active modal states prior to jogging. These are sequential commands.

Wyświetl plik

@ -569,12 +569,12 @@
#define PARKING_PULLOUT_RATE 100.0 // Pull-out/plunge slow feed rate in mm/min.
#define PARKING_PULLOUT_INCREMENT 5.0 // Spindle pull-out and plunge distance in mm. Incremental distance.
// Must be positive value or equal to zero.
// Experimental feature that adjusts laser power (PWM output) based on current running speed of the
// machine. When laser mode is enabled, Grbl will turn off the spindle PWM pin whenever it is not
// moving, which may be confusing to some users to why their laser is not on. This behavior may change
// in future iterations of this feature, where it will turn on to the minimum rpm value when active.
// #define LASER_CONSTANT_POWER_PER_RATE
// This option will automatically disable the laser during a feed hold by invoking a spindle stop
// override immediately after coming to a stop. However, this also means that the laser still may
// be reenabled by disabling the spindle stop override, if needed. This is purely a safety feature
// to ensure the laser doesn't inadvertently remain powered while at a stop and cause a fire.
#define DISABLE_LASER_DURING_HOLD // Default enabled. Comment to disable.
/* ---------------------------------------------------------------------------------------
OEM Single File Configuration Option

Wyświetl plik

@ -82,17 +82,20 @@ uint8_t gc_execute_line(char *line)
uint8_t axis_words = 0; // XYZ tracking
uint8_t ijk_words = 0; // IJK tracking
// Initialize command and value words variables. Tracks words contained in this block.
uint16_t command_words = 0; // G and M command words. Also used for modal group violations.
uint16_t value_words = 0; // Value words.
// Initialize command and value words and parser flags variables.
uint16_t command_words = 0; // Tracks G and M command words. Also used for modal group violations.
uint16_t value_words = 0; // Tracks value words.
uint8_t gc_parser_flags = GC_PARSER_NONE;
// Determine if the line is a jogging motion or a normal g-code block.
uint8_t is_jog_motion = false;
if (line[0] == '$') { // NOTE: `$J=` already parsed when passed to this function.
// Set G1 and G94 enforced modes to ensure accurate error checks.
is_jog_motion = true;
gc_parser_flags |= GC_PARSER_JOG_MOTION;
gc_block.modal.motion = MOTION_MODE_LINEAR;
gc_block.modal.feed_rate = FEED_RATE_MODE_UNITS_PER_MIN;
#ifdef USE_LINE_NUMBERS
gc_block.values.n = JOG_LINE_NUMBER; // Initialize default line number reported during jog.
#endif
}
/* -------------------------------------------------------------------------------------
@ -107,7 +110,7 @@ uint8_t gc_execute_line(char *line)
float value;
uint8_t int_value = 0;
uint16_t mantissa = 0;
if (is_jog_motion) { char_counter = 3; } // Start parsing after `$J=`
if (gc_parser_flags & GC_PARSER_JOG_MOTION) { char_counter = 3; } // Start parsing after `$J=`
else { char_counter = 0; }
while (line[char_counter] != 0) { // Loop until no more g-code words in line.
@ -127,7 +130,7 @@ uint8_t gc_execute_line(char *line)
// Maybe update this later.
int_value = trunc(value);
mantissa = round(100*(value - int_value)); // Compute mantissa for Gxx.x commands.
// NOTE: Rounding must be used to catch small floating point errors.
// NOTE: Rounding must be used to catch small floating point errors.
// Check if the g-code word is supported or errors due to modal group violations or has
// been repeated in the g-code block. If ok, update the command or record its value.
@ -381,7 +384,7 @@ uint8_t gc_execute_line(char *line)
// [2. Set feed rate mode ]: G93 F word missing with G1,G2/3 active, implicitly or explicitly. Feed rate
// is not defined after switching to G94 from G93.
// NOTE: For jogging, ignore prior feed rate mode. Enforce G94 and check for required F word.
if (is_jog_motion) {
if (gc_parser_flags & GC_PARSER_JOG_MOTION) {
if (bit_isfalse(value_words,bit(WORD_F))) { FAIL(STATUS_GCODE_UNDEFINED_FEED_RATE); }
if (gc_block.modal.units == UNITS_MODE_INCHES) { gc_block.values.f *= MM_PER_INCH; }
} else {
@ -653,9 +656,10 @@ uint8_t gc_execute_line(char *line)
// [G1 Errors]: Feed rate undefined. Axis letter not configured or without real value.
// Axis words are optional. If missing, set axis command flag to ignore execution.
if (!axis_words) { axis_command = AXIS_COMMAND_NONE; }
break;
case MOTION_MODE_CW_ARC: case MOTION_MODE_CCW_ARC:
case MOTION_MODE_CW_ARC:
gc_parser_flags |= GC_PARSER_ARC_IS_CLOCKWISE; // No break intentional.
case MOTION_MODE_CCW_ARC:
// [G2/3 Errors All-Modes]: Feed rate undefined.
// [G2/3 Radius-Mode Errors]: No axis words in selected plane. Target point is same as current.
// [G2/3 Offset-Mode Errors]: No axis words and/or offsets in selected plane. The radius to the current
@ -790,8 +794,11 @@ uint8_t gc_execute_line(char *line)
}
}
break;
case MOTION_MODE_PROBE_TOWARD: case MOTION_MODE_PROBE_TOWARD_NO_ERROR:
case MOTION_MODE_PROBE_AWAY: case MOTION_MODE_PROBE_AWAY_NO_ERROR:
case MOTION_MODE_PROBE_TOWARD_NO_ERROR: case MOTION_MODE_PROBE_AWAY_NO_ERROR:
gc_parser_flags |= GC_PARSER_PROBE_IS_NO_ERROR; // No break intentional.
case MOTION_MODE_PROBE_TOWARD: case MOTION_MODE_PROBE_AWAY:
if ((gc_block.modal.motion == MOTION_MODE_PROBE_AWAY) ||
(gc_block.modal.motion == MOTION_MODE_PROBE_AWAY_NO_ERROR)) { gc_parser_flags |= GC_PARSER_PROBE_IS_AWAY; }
// [G38 Errors]: Target is same current. No axis words. Cutter compensation is enabled. Feed rate
// is undefined. Probe is triggered. NOTE: Probe check moved to probe cycle. Instead of returning
// an error, it issues an alarm to prevent further motion to the probe. It's also done there to
@ -807,29 +814,15 @@ uint8_t gc_execute_line(char *line)
// [0. Non-specific error-checks]: Complete unused value words check, i.e. IJK used when in arc
// radius mode, or axis words that aren't used in the block.
bit_false(value_words,(bit(WORD_N)|bit(WORD_F)|bit(WORD_S)|bit(WORD_T))); // Remove single-meaning value words.
if (gc_parser_flags & GC_PARSER_JOG_MOTION) {
// Jogging only uses the F feed rate and XYZ value words. N is valid, but S and T are invalid.
bit_false(value_words,(bit(WORD_N)|bit(WORD_F)));
} else {
bit_false(value_words,(bit(WORD_N)|bit(WORD_F)|bit(WORD_S)|bit(WORD_T))); // Remove single-meaning value words.
}
if (axis_command) { bit_false(value_words,(bit(WORD_X)|bit(WORD_Y)|bit(WORD_Z))); } // Remove axis words.
if (value_words) { FAIL(STATUS_GCODE_UNUSED_WORDS); } // [Unused words]
/* -------------------------------------------------------------------------------------
STEP 3.5ish : EXECUTE JOG!!
Intercept jog commands and complete error checking for valid jog commands and execute.
NOTE: G-code parser state is not updated, except the position to ensure sequential jog
targets are computed correctly. The final parser position after a jog is updated in
protocol_execute_realtime() when jogging completes or is canceled.
*/
if (is_jog_motion) {
// Only distance and unit modal commands and G53 absolute override command are allowed.
if (command_words & ~(bit(MODAL_GROUP_G3) | bit(MODAL_GROUP_G6 | bit(MODAL_GROUP_G0))) ) { FAIL(STATUS_INVALID_JOG_COMMAND) };
if (!(gc_block.non_modal_command == NON_MODAL_ABSOLUTE_OVERRIDE || gc_block.non_modal_command == NON_MODAL_NO_ACTION)) { FAIL(STATUS_INVALID_JOG_COMMAND); }
// NOTE: Feed rate word and axis word checks have already been performed in STEP 3.
uint8_t status = jog_execute(&gc_block);
if (status == STATUS_OK) { memcpy(gc_state.position, gc_block.values.xyz, sizeof(gc_block.values.xyz)); }
return(status);
}
/* -------------------------------------------------------------------------------------
STEP 4: EXECUTE!!
Assumes that all error-checking has been completed and no failure modes exist. We just
@ -841,6 +834,60 @@ uint8_t gc_execute_line(char *line)
plan_line_data_t *pl_data = &plan_data;
memset(pl_data,0,sizeof(plan_line_data_t)); // Zero pl_data struct
// Intercept jog commands and complete error checking for valid jog commands and execute.
// NOTE: G-code parser state is not updated, except the position to ensure sequential jog
// targets are computed correctly. The final parser position after a jog is updated in
// protocol_execute_realtime() when jogging completes or is canceled.
if (gc_parser_flags & GC_PARSER_JOG_MOTION) {
// Only distance and unit modal commands and G53 absolute override command are allowed.
// NOTE: Feed rate word and axis word checks have already been performed in STEP 3.
if (command_words & ~(bit(MODAL_GROUP_G3) | bit(MODAL_GROUP_G6 | bit(MODAL_GROUP_G0))) ) { FAIL(STATUS_INVALID_JOG_COMMAND) };
if (!(gc_block.non_modal_command == NON_MODAL_ABSOLUTE_OVERRIDE || gc_block.non_modal_command == NON_MODAL_NO_ACTION)) { FAIL(STATUS_INVALID_JOG_COMMAND); }
// Initialize planner data to current spindle and coolant modal state.
pl_data->spindle_speed = gc_state.spindle_speed;
plan_data.condition = (gc_state.modal.spindle | gc_state.modal.coolant);
uint8_t status = jog_execute(&plan_data, &gc_block);
if (status == STATUS_OK) { memcpy(gc_state.position, gc_block.values.xyz, sizeof(gc_block.values.xyz)); }
return(status);
}
// If in laser mode, setup laser power based on current and past parser conditions.
if (bit_istrue(settings.flags,BITFLAG_LASER_MODE)) {
if ( !((gc_block.modal.motion == MOTION_MODE_LINEAR) || (gc_block.modal.motion == MOTION_MODE_CW_ARC)
|| (gc_block.modal.motion == MOTION_MODE_CCW_ARC)) ) {
gc_parser_flags |= GC_PARSER_LASER_DISABLE;
}
// M3 constant power laser requires planner syncs to update the laser in certain conditions.
// certain conditions.
if (gc_state.modal.spindle == SPINDLE_ENABLE_CW) {
if ((gc_state.modal.motion == MOTION_MODE_LINEAR) || (gc_state.modal.motion == MOTION_MODE_CW_ARC)
|| (gc_state.modal.motion == MOTION_MODE_CCW_ARC)) {
if (gc_parser_flags & GC_PARSER_LASER_DISABLE) {
gc_parser_flags |= GC_PARSER_LASER_FORCE_SYNC; // Change from G1/2/3 motion mode.
} else {
// Any non-motion block with M3 enabled and G1/2/3 modal state requires a sync when
// the spindle speed changes. It is otherwise passed onto the planner.
if (gc_state.spindle_speed != gc_block.values.s) {
// NOTE: A G1/2/3 motion will always have axis words and be in AXIS_COMMAND_MOTION_MODE.
// A non-motion G1 or any non-modal command using axis words will alter axis_command.
if (!(axis_words) || (axis_command != AXIS_COMMAND_MOTION_MODE )) {
gc_parser_flags |= GC_PARSER_LASER_FORCE_SYNC;
}
}
}
} else {
// When changing to a G1 motion mode without axis words from a non-G1/2/3 motion mode.
if (bit_isfalse(gc_parser_flags,GC_PARSER_LASER_DISABLE)) {
if (!(axis_words) || (axis_command != AXIS_COMMAND_MOTION_MODE )) {
gc_parser_flags |= GC_PARSER_LASER_FORCE_SYNC;
}
}
}
}
}
// [0. Non-specific/common error-checks and miscellaneous setup]:
// NOTE: If no line number is present, the value is zero.
gc_state.line_number = gc_block.values.n;
@ -859,25 +906,23 @@ uint8_t gc_execute_line(char *line)
pl_data->feed_rate = gc_state.feed_rate; // Record data for planner use.
// [4. Set spindle speed ]:
if (gc_state.spindle_speed != gc_block.values.s) {
#ifdef VARIABLE_SPINDLE
if (gc_state.modal.spindle != SPINDLE_DISABLE) {
if ( bit_istrue(settings.flags, BITFLAG_LASER_MODE) ) {
// Do not stop motion if in laser mode and a G1, G2, or G3 motion is being executed.
if (!( (axis_command == AXIS_COMMAND_MOTION_MODE) && ((gc_block.modal.motion == MOTION_MODE_LINEAR ) || (gc_block.modal.motion == MOTION_MODE_CW_ARC) || (gc_block.modal.motion == MOTION_MODE_CCW_ARC)) ) ) {
spindle_sync(gc_state.modal.spindle, gc_block.values.s);
}
} else {
spindle_sync(gc_state.modal.spindle, gc_block.values.s);
}
}
#else
if (gc_state.modal.spindle != SPINDLE_DISABLE) { spindle_sync(gc_state.modal.spindle, 0.0); }
#endif
gc_state.spindle_speed = gc_block.values.s;
if ((gc_state.spindle_speed != gc_block.values.s) || bit_istrue(gc_parser_flags,GC_PARSER_LASER_FORCE_SYNC)) {
if (gc_state.modal.spindle != SPINDLE_DISABLE) {
#ifdef VARIABLE_SPINDLE
if (bit_istrue(gc_parser_flags,GC_PARSER_LASER_DISABLE)) {
spindle_sync(gc_state.modal.spindle, 0.0);
} else { spindle_sync(gc_state.modal.spindle, gc_block.values.s); }
#else
spindle_sync(gc_state.modal.spindle, 0.0);
#endif
}
gc_state.spindle_speed = gc_block.values.s; // Update spindle speed state.
}
pl_data->spindle_speed = gc_state.spindle_speed; // Record data for planner use.
// NOTE: Pass zero spindle speed for all restricted laser motions.
if (bit_isfalse(gc_parser_flags,GC_PARSER_LASER_DISABLE)) {
pl_data->spindle_speed = gc_state.spindle_speed; // Record data for planner use.
} // else { pl_data->spindle_speed = 0.0; } // Initialized as zero already.
// [5. Select tool ]: NOT SUPPORTED. Only tracks tool value.
gc_state.tool = gc_block.values.t;
@ -886,7 +931,9 @@ uint8_t gc_execute_line(char *line)
// [7. Spindle control ]:
if (gc_state.modal.spindle != gc_block.modal.spindle) {
// Update spindle control and apply spindle speed when enabling it in this block.
spindle_sync(gc_block.modal.spindle, gc_state.spindle_speed);
// NOTE: All spindle state changes are synced, even in laser mode. Also, pl_data,
// rather than gc_state, is used to manage laser state for non-laser motions.
spindle_sync(gc_block.modal.spindle, pl_data->spindle_speed);
gc_state.modal.spindle = gc_block.modal.spindle;
}
pl_data->condition |= gc_state.modal.spindle; // Set condition flag for planner use.
@ -993,23 +1040,16 @@ uint8_t gc_execute_line(char *line)
pl_data->condition |= PL_COND_FLAG_RAPID_MOTION; // Set rapid motion condition flag.
mc_line(gc_block.values.xyz, pl_data);
} else if ((gc_state.modal.motion == MOTION_MODE_CW_ARC) || (gc_state.modal.motion == MOTION_MODE_CCW_ARC)) {
uint8_t is_clockwise_arc;
if (gc_state.modal.motion == MOTION_MODE_CW_ARC) { is_clockwise_arc = true; }
else { is_clockwise_arc = false; }
mc_arc(gc_block.values.xyz, pl_data, gc_state.position, gc_block.values.ijk, gc_block.values.r,
axis_0, axis_1, axis_linear, is_clockwise_arc);
axis_0, axis_1, axis_linear, bit_istrue(gc_parser_flags,GC_PARSER_ARC_IS_CLOCKWISE));
} else {
// NOTE: gc_block.values.xyz is returned from mc_probe_cycle with the updated position value. So
// upon a successful probing cycle, the machine position and the returned value should be the same.
#ifndef ALLOW_FEED_OVERRIDE_DURING_PROBE_CYCLES
pl_data->condition |= PL_COND_FLAG_NO_FEED_OVERRIDE;
#endif
uint8_t is_probe_away = false;
uint8_t is_no_error = false;
if ((gc_state.modal.motion == MOTION_MODE_PROBE_AWAY) || (gc_state.modal.motion == MOTION_MODE_PROBE_AWAY_NO_ERROR)) { is_probe_away = true; }
if ((gc_state.modal.motion == MOTION_MODE_PROBE_TOWARD_NO_ERROR) || (gc_state.modal.motion == MOTION_MODE_PROBE_AWAY_NO_ERROR)) { is_no_error = true; }
gc_update_pos = mc_probe_cycle(gc_block.values.xyz, pl_data, is_probe_away, is_no_error);
}
gc_update_pos = mc_probe_cycle(gc_block.values.xyz, pl_data, gc_parser_flags);
}
// As far as the parser is concerned, the position is now == target. In reality the
// motion control system might still be processing the action and the real tool position
@ -1020,7 +1060,6 @@ uint8_t gc_execute_line(char *line)
gc_sync_position(); // gc_state.position[] = sys_position
} // == GC_UPDATE_POS_NONE
}
}
// [21. Program flow ]:

Wyświetl plik

@ -145,7 +145,7 @@
#define WORD_Z 12
// Define g-code parser position updating flags
#define GC_UPDATE_POS_TARGET 0
#define GC_UPDATE_POS_TARGET 0 // Must be zero
#define GC_UPDATE_POS_SYSTEM 1
#define GC_UPDATE_POS_NONE 2
@ -160,6 +160,15 @@
#define GC_PROBE_CHECK_MODE GC_UPDATE_POS_TARGET
#endif
// Define gcode parser flags for handling special cases.
#define GC_PARSER_NONE 0 // Must be zero.
#define GC_PARSER_JOG_MOTION bit(0)
#define GC_PARSER_CHECK_MANTISSA bit(1)
#define GC_PARSER_ARC_IS_CLOCKWISE bit(2)
#define GC_PARSER_PROBE_IS_AWAY bit(3)
#define GC_PARSER_PROBE_IS_NO_ERROR bit(4)
#define GC_PARSER_LASER_FORCE_SYNC bit(5)
#define GC_PARSER_LASER_DISABLE bit(6)
// NOTE: When this struct is zeroed, the above defines set the defaults for the system.

Wyświetl plik

@ -22,8 +22,8 @@
#define grbl_h
// Grbl versioning system
#define GRBL_VERSION "1.1d"
#define GRBL_VERSION_BUILD "20161112"
#define GRBL_VERSION "1.1e"
#define GRBL_VERSION_BUILD "20161203"
// Define standard libraries used by Grbl.
#include <avr/io.h>

Wyświetl plik

@ -22,18 +22,14 @@
// Sets up valid jog motion received from g-code parser, checks for soft-limits, and executes the jog.
uint8_t jog_execute(parser_block_t *gc_block)
uint8_t jog_execute(plan_line_data_t *pl_data, parser_block_t *gc_block)
{
// Initialize planner data struct for motion blocks.
// Initialize planner data struct for jogging motions.
// NOTE: Spindle and coolant are allowed to fully function with overrides during a jog.
plan_line_data_t plan_data;
plan_line_data_t *pl_data = &plan_data;
memset(pl_data,0,sizeof(plan_line_data_t)); // Zero pl_data struct
pl_data->feed_rate = gc_block->values.f;
pl_data->spindle_speed = gc_block->values.s; // Continue current spindle and coolant condition.
plan_data.condition = (PL_COND_FLAG_NO_FEED_OVERRIDE | gc_block->modal.spindle | gc_block->modal.coolant);
pl_data->condition |= PL_COND_FLAG_NO_FEED_OVERRIDE;
#ifdef USE_LINE_NUMBERS
pl_data->line_number = JOG_LINE_NUMBER;
pl_data->line_number = gc_block.values.n;
#endif
if (bit_istrue(settings.flags,BITFLAG_SOFT_LIMIT_ENABLE)) {

Wyświetl plik

@ -27,6 +27,6 @@
#define JOG_LINE_NUMBER 0
// Sets up valid jog motion received from g-code parser, checks for soft-limits, and executes the jog.
uint8_t jog_execute(parser_block_t *gc_block);
uint8_t jog_execute(plan_line_data_t *pl_data, parser_block_t *gc_block);
#endif

Wyświetl plik

@ -246,7 +246,7 @@ void mc_homing_cycle(uint8_t cycle_mask)
// Perform tool length probe cycle. Requires probe switch.
// NOTE: Upon probe failure, the program will be stopped and placed into ALARM state.
uint8_t mc_probe_cycle(float *target, plan_line_data_t *pl_data, uint8_t is_probe_away, uint8_t is_no_error)
uint8_t mc_probe_cycle(float *target, plan_line_data_t *pl_data, uint8_t parser_flags)
{
// TODO: Need to update this cycle so it obeys a non-auto cycle start.
if (sys.state == STATE_CHECK_MODE) { return(GC_PROBE_CHECK_MODE); }
@ -256,6 +256,8 @@ uint8_t mc_probe_cycle(float *target, plan_line_data_t *pl_data, uint8_t is_prob
if (sys.abort) { return(GC_PROBE_ABORT); } // Return if system reset has been issued.
// Initialize probing control variables
uint8_t is_probe_away = bit_istrue(parser_flags,GC_PARSER_PROBE_IS_AWAY);
uint8_t is_no_error = bit_istrue(parser_flags,GC_PARSER_PROBE_IS_NO_ERROR);
sys.probe_succeeded = false; // Re-initialize probe history before beginning cycle.
probe_configure_invert_mask(is_probe_away);

Wyświetl plik

@ -52,7 +52,7 @@ void mc_dwell(float seconds);
void mc_homing_cycle(uint8_t cycle_mask);
// Perform tool length probe cycle. Requires probe switch.
uint8_t mc_probe_cycle(float *target, plan_line_data_t *pl_data, uint8_t is_probe_away, uint8_t is_no_error);
uint8_t mc_probe_cycle(float *target, plan_line_data_t *pl_data, uint8_t parser_flags);
// Plans and executes the single special motion case for parking. Independent of main planner buffer.
void mc_parking_motion(float *parking_target, plan_line_data_t *pl_data);

Wyświetl plik

@ -331,8 +331,15 @@ uint8_t plan_buffer_line(float *target, plan_line_data_t *pl_data)
uint8_t idx;
// Copy position data based on type of motion being planned.
if (block->condition & PL_COND_FLAG_SYSTEM_MOTION) { memcpy(position_steps, sys_position, sizeof(sys_position)); }
else { memcpy(position_steps, pl.position, sizeof(pl.position)); }
if (block->condition & PL_COND_FLAG_SYSTEM_MOTION) {
#ifdef COREXY
position_steps[X_AXIS] = system_convert_corexy_to_x_axis_steps(sys_position);
position_steps[Y_AXIS] = system_convert_corexy_to_y_axis_steps(sys_position);
position_steps[Z_AXIS] = sys_position[Z_AXIS];
#else
memcpy(position_steps, sys_position, sizeof(sys_position));
#endif
} else { memcpy(position_steps, pl.position, sizeof(pl.position)); }
#ifdef COREXY
target_steps[A_MOTOR] = lround(target[A_MOTOR]*settings.steps_per_mm[A_MOTOR]);

Wyświetl plik

@ -530,6 +530,11 @@ static void protocol_exec_rt_suspend()
restore_condition = block->condition;
restore_spindle_speed = block->spindle_speed;
}
#ifdef DISABLE_LASER_DURING_HOLD
if (bit_istrue(settings.flags,BITFLAG_LASER_MODE)) {
system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_STOP);
}
#endif
#else
if (block == NULL) { restore_condition = (gc_state.modal.spindle | gc_state.modal.coolant); }
else { restore_condition = block->condition; }

Wyświetl plik

@ -295,7 +295,7 @@ void report_grbl_settings() {
printPgmString(PSTR(" (soft limits, bool)\r\n$21=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE));
printPgmString(PSTR(" (hard limits, bool)\r\n$22=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE));
printPgmString(PSTR(" (homing cycle, bool)\r\n$23=")); print_uint8_base10(settings.homing_dir_mask);
printPgmString(PSTR(" (homing dir invert mask\r\n$24=")); printFloat(settings.homing_feed_rate,N_DECIMAL_SETTINGVALUE);
printPgmString(PSTR(" (homing dir invert mask)\r\n$24=")); printFloat(settings.homing_feed_rate,N_DECIMAL_SETTINGVALUE);
printPgmString(PSTR(" (homing feed, mm/min)\r\n$25=")); printFloat(settings.homing_seek_rate,N_DECIMAL_SETTINGVALUE);
printPgmString(PSTR(" (homing seek, mm/min)\r\n$26=")); print_uint8_base10(settings.homing_debounce_delay);
printPgmString(PSTR(" (homing debounce, msec)\r\n$27=")); printFloat(settings.homing_pulloff,N_DECIMAL_SETTINGVALUE);

Wyświetl plik

@ -262,6 +262,7 @@ uint8_t settings_store_global_setting(uint8_t parameter, float value) {
case 13:
if (int_value) { settings.flags |= BITFLAG_REPORT_INCHES; }
else { settings.flags &= ~BITFLAG_REPORT_INCHES; }
system_flag_wco_change(); // Make sure WCO is immediately updated.
break;
case 20:
if (int_value) {

Wyświetl plik

@ -189,10 +189,10 @@ void spindle_stop()
#endif
#ifdef VARIABLE_SPINDLE
#ifdef LASER_CONSTANT_POWER_PER_RATE
// NOTE: Assumes all calls to this function is when Grbl is not moving or must remain off.
if (settings.flags & BITFLAG_LASER_MODE) { rpm = 0.0; } // TODO: May need to be rpm_min*(100/MAX_SPINDLE_SPEED_OVERRIDE);
#endif
// NOTE: Assumes all calls to this function is when Grbl is not moving or must remain off.
if (settings.flags & BITFLAG_LASER_MODE) {
if (state == SPINDLE_ENABLE_CCW) { rpm = 0.0; } // TODO: May need to be rpm_min*(100/MAX_SPINDLE_SPEED_OVERRIDE);
}
spindle_set_speed(spindle_compute_pwm_value(rpm));
#else
// NOTE: Without variable spindle, the enable bit should just turn on or off, regardless

Wyświetl plik

@ -62,11 +62,7 @@ typedef struct {
uint32_t step_event_count;
uint8_t direction_bits;
#ifdef VARIABLE_SPINDLE
#ifdef LASER_CONSTANT_POWER_PER_RATE
uint8_t is_pwm_rate_adjusted; // Tracks motions that require constant laser power/rate
#else
uint8_t spindle_pwm;
#endif
uint8_t is_pwm_rate_adjusted; // Tracks motions that require constant laser power/rate
#endif
} st_block_t;
static st_block_t st_block_buffer[SEGMENT_BUFFER_SIZE-1];
@ -84,8 +80,8 @@ typedef struct {
#else
uint8_t prescaler; // Without AMASS, a prescaler is required to adjust for slow timing.
#endif
#ifdef LASER_CONSTANT_POWER_PER_RATE
uint8_t rate_adjusted_pwm;
#ifdef VARIABLE_SPINDLE
uint8_t spindle_pwm;
#endif
} segment_t;
static segment_t segment_buffer[SEGMENT_BUFFER_SIZE];
@ -159,8 +155,9 @@ typedef struct {
float accelerate_until; // Acceleration ramp end measured from end of block (mm)
float decelerate_after; // Deceleration ramp start measured from end of block (mm)
#ifdef LASER_CONSTANT_POWER_PER_RATE
#ifdef VARIABLE_SPINDLE
float inv_rate; // Used by PWM laser mode to speed up segment calculations.
uint8_t current_spindle_pwm;
#endif
} st_prep_t;
static st_prep_t prep;
@ -360,20 +357,14 @@ ISR(TIMER1_COMPA_vect)
#ifdef VARIABLE_SPINDLE
// Set real-time spindle output as segment is loaded, just prior to the first step.
#ifdef LASER_CONSTANT_POWER_PER_RATE
spindle_set_speed(st.exec_segment->rate_adjusted_pwm);
#else
spindle_set_speed(st.exec_block->spindle_pwm);
#endif
spindle_set_speed(st.exec_segment->spindle_pwm);
#endif
} else {
// Segment buffer empty. Shutdown.
st_go_idle();
#ifdef LASER_CONSTANT_POWER_PER_RATE
// Ensure pwm is set properly upon completion of rate-controlled motion.
if (st.exec_block->is_pwm_rate_adjusted) { spindle_set_speed(SPINDLE_PWM_OFF_VALUE); }
#endif
// Ensure pwm is set properly upon completion of rate-controlled motion.
if (st.exec_block->is_pwm_rate_adjusted) { spindle_set_speed(SPINDLE_PWM_OFF_VALUE); }
system_set_exec_state_flag(EXEC_CYCLE_STOP); // Flag main program for cycle end
return; // Nothing to do but exit.
}
@ -664,16 +655,16 @@ void st_prep_buffer()
prep.current_speed = sqrt(pl_block->entry_speed_sqr);
}
#ifdef LASER_CONSTANT_POWER_PER_RATE
// Setup laser mode variables. PWM rate adjusted motions will always complete a motion with the
// spindle off.
st_prep_block->is_pwm_rate_adjusted = false;
if (settings.flags & BITFLAG_LASER_MODE) {
// Setup laser mode variables. PWM rate adjusted motions will always complete a motion with the
// spindle off.
st_prep_block->is_pwm_rate_adjusted = false;
if (settings.flags & BITFLAG_LASER_MODE) {
if (pl_block->condition & PL_COND_FLAG_SPINDLE_CCW) {
// Pre-compute inverse programmed rate to speed up PWM updating per step segment.
prep.inv_rate = 1.0/pl_block->programmed_rate;
if (!(pl_block->condition & PL_COND_MOTION_MASK)) { st_prep_block->is_pwm_rate_adjusted = true; }
st_prep_block->is_pwm_rate_adjusted = true;
}
#endif
}
}
/* ---------------------------------------------------------------------------------
@ -881,32 +872,23 @@ void st_prep_buffer()
/* -----------------------------------------------------------------------------------
Compute spindle speed PWM output for step segment
*/
#ifdef LASER_CONSTANT_POWER_PER_RATE
if (st_prep_block->is_pwm_rate_adjusted || (sys.step_control & STEP_CONTROL_UPDATE_SPINDLE_PWM)) {
if (pl_block->condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)) {
float rpm = pl_block->spindle_speed;
// NOTE: Feed and rapid overrides are independent of PWM value and do not alter laser power/rate.
if (st_prep_block->is_pwm_rate_adjusted) { rpm *= (prep.current_speed * prep.inv_rate); }
// If current_speed is zero, then may need to be rpm_min*(100/MAX_SPINDLE_SPEED_OVERRIDE)
// but this would be instantaneous only and during a motion. May not matter at all.
prep_segment->rate_adjusted_pwm = spindle_compute_pwm_value(rpm);
} else {
sys.spindle_speed = 0.0;
prep_segment->rate_adjusted_pwm = SPINDLE_PWM_OFF_VALUE;
}
bit_false(sys.step_control,STEP_CONTROL_UPDATE_SPINDLE_PWM);
if (st_prep_block->is_pwm_rate_adjusted || (sys.step_control & STEP_CONTROL_UPDATE_SPINDLE_PWM)) {
if (pl_block->condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)) {
float rpm = pl_block->spindle_speed;
// NOTE: Feed and rapid overrides are independent of PWM value and do not alter laser power/rate.
if (st_prep_block->is_pwm_rate_adjusted) { rpm *= (prep.current_speed * prep.inv_rate); }
// If current_speed is zero, then may need to be rpm_min*(100/MAX_SPINDLE_SPEED_OVERRIDE)
// but this would be instantaneous only and during a motion. May not matter at all.
prep.current_spindle_pwm = spindle_compute_pwm_value(rpm);
} else {
sys.spindle_speed = 0.0;
prep.current_spindle_pwm = SPINDLE_PWM_OFF_VALUE;
}
#else
if (sys.step_control & STEP_CONTROL_UPDATE_SPINDLE_PWM) {
if (pl_block->condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)) {
st_prep_block->spindle_pwm = spindle_compute_pwm_value(pl_block->spindle_speed);
} else {
sys.spindle_speed = 0.0;
st_prep_block->spindle_pwm = SPINDLE_PWM_OFF_VALUE;
}
bit_false(sys.step_control,STEP_CONTROL_UPDATE_SPINDLE_PWM);
}
#endif
bit_false(sys.step_control,STEP_CONTROL_UPDATE_SPINDLE_PWM);
}
prep_segment->spindle_pwm = prep.current_spindle_pwm; // Reload segment PWM value
#endif
/* -----------------------------------------------------------------------------------