v1.1b: Tweaked Bf reports, jogging doc, saved another 160 bytes, minor bug fixes
- Increment to v1.1b due to status report tweak. - Tweaked the buffer state status reports to show bytes and blocks available, rather than in use. This does not require knowing the buffer sizes beforehand. It’s implicit. - Also, since buffer states are not used by most devs (after inquiries), it is no longer enabled by default and a status mask option was added for this. - Fixed some typos and updated for the report tweak in the documentation. - Wrote a joystick implementation concept in the jogging markdown document. Outlines how to get a low-latency feel to a joystick (and other input devices). - Removed XON/XOFF support. It’s not used by anyone because of its inherent problems. Remains in older versions for reference. - Added a compile option on how to handle the probe position during a check mode. - Fixed a jogging bug. If G93 is the modal state before a jogging motion, the feed rate did not get calculated correctly. Fixed the issue. - Refactored some code to save another 160+ bytes. Included an improved float vector comparison macro and reducing a few large and repetitive function calls. - Fixed a probing bug (existing in v0.9 too) where the target positions were not set correct and error handling was improper.
This commit is contained in:
parent
b04faaf0d3
commit
d21e06a201
@ -1,3 +1,26 @@
|
||||
----------------
|
||||
Date: 2016-09-25
|
||||
Author: Sonny Jeon
|
||||
Subject: Addressed much larger flash size with avr-gcc v4.9.2. Refactored reports to save 160KB.
|
||||
|
||||
- The newest Arduino IDE 1.6.12 has recently updated to avr-gcc v4.9.2.
|
||||
Unfortunately, it produces a compiled size almost 0.7KB to 1KB larger
|
||||
than prior versions! This can easily cause the base build to exceed the
|
||||
Arduino Duemilanove/Nano flash limit of 30.5KB. The Arduino Uno seems
|
||||
to be ok still with its 31.5KB flash limit.
|
||||
|
||||
- Makefile `-flto` compile flag added to cut down on the horrible flash
|
||||
size when using the new avr-gcc. (Edit Makefile and remove comment on
|
||||
COMPILE definition). This brings it in-line with what the IDE produces.
|
||||
|
||||
- Functionalized repetitive tasks in report.c to try to reduce overall
|
||||
flash size. Successfully cut down about 160bytes.
|
||||
|
||||
- Removed printFloat_SettingValue() and printFloat_RPMValue()
|
||||
functions. These aren’t required and can be replaced with a direct call
|
||||
to printFloat() because they don’t require a unit conversion check.
|
||||
|
||||
|
||||
----------------
|
||||
Date: 2016-09-24
|
||||
Author: Sonny Jeon
|
||||
|
@ -13,7 +13,7 @@ Grbl v1.1's interface protocol has been tweaked in the attempt to make GUI devel
|
||||
|
||||
- `< >` : Enclosed chevrons contains status report data.
|
||||
|
||||
- `Grbl vX.Xx ['$' for help]` : Welcome message indicates initialization.
|
||||
- `Grbl X.Xx ['$' for help]` : Welcome message indicates initialization.
|
||||
|
||||
- `ALARM:x` : Indicates an alarm has been thrown. Grbl is now in an alarm state.
|
||||
|
||||
@ -72,7 +72,8 @@ On a final note, this interface tweak came about out of necessity, as more data
|
||||
|
||||
- Buffer data (planner and serial RX) reports have been tweaked and combined.
|
||||
|
||||
- `Bf:0,0`. The first value is planner blocks in use and the second is RX bytes in use.
|
||||
- `Bf:15,128`. The first value is the available blocks in the planner buffer and the second is available bytes in the serial RX buffer.
|
||||
- Note that this is different than before, where it reported blocks/bytes "in-use", rather than "available". This change does not require a GUI to know how many blocks/bytes Grbl has been compiled with, which can be substantially different on a Grbl-Mega build.
|
||||
|
||||
|
||||
- Override reports are intermittent since they don't change often once set.
|
||||
|
@ -11,11 +11,11 @@ In other words, both commands sent to Grbl and messages received from Grbl have
|
||||
|
||||
#### Start Up Message
|
||||
|
||||
**`Grbl vX.Xx ['$' for help]`**
|
||||
**`Grbl X.Xx ['$' for help]`**
|
||||
|
||||
The start up message always prints upon startup and after a reset. Whenever you see this message, this also means that Grbl has completed re-initializing all its systems, so everything starts out the same every time you use Grbl.
|
||||
|
||||
* `vX.Xx` indicates the major version number, followed by a minor version letter. The major version number indicates the general release, while the letter simply indicates a feature update or addition from the preceding minor version letter.
|
||||
* `X.Xx` indicates the major version number, followed by a minor version letter. The major version number indicates the general release, while the letter simply indicates a feature update or addition from the preceding minor version letter.
|
||||
* Bug fix revisions are tracked by the build info version number, printed when an `$I` command is sent. These revisions don't update the version number and are given by date revised in year, month, and day, like so `20160820`.
|
||||
|
||||
#### Grbl `$` Help Message
|
||||
@ -423,11 +423,19 @@ Feedback messages provide non-critical information on what Grbl is doing, what i
|
||||
|
||||
- **Buffer State:**
|
||||
|
||||
- `Bf:0,0`. The first value is planner blocks in use and the second is RX bytes in use.
|
||||
- `Bf:15,128`. The first value is the number of available blocks in the planner buffer and the second is number of available bytes in the serial RX buffer.
|
||||
|
||||
- The usage of this data is generally for debugging an interface, but is known to be used to control some GUI-specific tasks. While this is disabled by default, GUIs should expect this data field to appear, but they may ignore it, if desired.
|
||||
|
||||
- NOTE: The buffer state values changed from showing "in-use" blocks or bytes to "available". This change does not require the GUI knowing how many block/bytes Grbl has been compiled with.
|
||||
|
||||
- This data field appears:
|
||||
|
||||
- In every status report when enabled. It is disabled in the settings mask by default.
|
||||
|
||||
- This data field will not appear if:
|
||||
|
||||
- It is disabled by the `$` status report mask setting.
|
||||
- It is disabled by the `$` status report mask setting or disabled in the config.h file.
|
||||
|
||||
- **Line Number:**
|
||||
|
||||
@ -547,7 +555,7 @@ Grbl v1.1's interface protocol has been tweaked in the attempt to make GUI devel
|
||||
|
||||
- `< >` : Enclosed chevrons contains status report data.
|
||||
|
||||
- `Grbl vX.Xx ['$' for help]` : Welcome message indicates initialization.
|
||||
- `Grbl X.Xx ['$' for help]` : Welcome message indicates initialization.
|
||||
|
||||
- `ALARM:x` : Indicates an alarm has been thrown. Grbl is now in an alarm state.
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
## Grbl v1.0 Jogging
|
||||
# Grbl v1.1 Jogging
|
||||
|
||||
## How to Use
|
||||
Executing a jog requires a specific command structure, as described below:
|
||||
|
||||
- The first three characters must be '$J=' to indicate the jog.
|
||||
@ -27,6 +28,7 @@ command is not valid, Grbl will return an 'error:'. Multiple jogging commands ma
|
||||
queued in sequence.
|
||||
|
||||
The main differences are:
|
||||
|
||||
- During a jog, Grbl will report a 'Jog' state while executing the jog.
|
||||
- A jog command will only be accepted when Grbl is in either the 'Idle' or 'Jog' states.
|
||||
- Jogging motions may not be mixed with g-code commands while executing, which will return
|
||||
@ -39,3 +41,54 @@ The main differences are:
|
||||
'G91G1X1F100'. Since G91, G1, and F feed rates are modal and if they are not changed
|
||||
back prior to resuming/starting a job, a job may not run how its was intended and result
|
||||
in a crash.
|
||||
|
||||
------
|
||||
|
||||
## Joystick Implementation
|
||||
|
||||
Jogging in Grbl v1.1 is generally intended to address some prior issues with old bootstrapped jogging methods. Unfortunately, the new Grbl jogging is not a complete solution. Flash and memory restrictions prevent the original envisioned implementation, but most of these can be mimicked by the following suggested methods.
|
||||
|
||||
With a combination of the new jog cancel and moving in `G91` incremental mode, the following implementation can create low latency feel for an analog joystick.
|
||||
|
||||
- Basic Implementation Overview:
|
||||
- Create a loop to read the joystick signal and translate it to a desired jog motion vector.
|
||||
- Send Grbl a very short `G91` incremental distance jog command with a feed rate based on the joystick throw.
|
||||
- Wait for an 'ok' acknowledgement before restarting the loop.
|
||||
- Continually read the joystick input and send Grbl short jog motions to keep Grbl's planner buffer full.
|
||||
- If the joystick is returned to its neutral position, stop the jog loop and simply send Grbl a `!` feed hold command. This will stop motion immediately somewhere along the programmed jog path with virtually zero-latency and automatically flush Grbl's planner queue.
|
||||
|
||||
|
||||
The overall idea is to minimize the total distance in the planner queue to provide a low-latency feel to joystick control. The main trick is ensuring there is just enough distance in the planner queue, such that the programmed feed rate is always met. How to compute this will be explain later. In practice, most machines will have a 0.5 second latency. When combined with the immediate joy cancel by a feed hold command, joystick interaction can be quite enjoyable and satisfying.
|
||||
|
||||
However, please note, if a machine has a low acceleration and is being asked to move at a high programmed feed rate, joystick latency can get up to a handful of seconds. It may sound bad, but this is how long it'll take for a low acceleration machine, traveling at a high feed rate, to slow down to a stop. The argument can be made for a low acceleration machine that you really shouldn't be traveling at a high feed rate. It is difficult for a user to gauge where the machine will come to a stop. You risk overshooting your target destination, which can result in an expensive or dangerous crash.
|
||||
|
||||
One of the advantages of this approach is that a GUI can deterministically track where Grbl will go by the jog commands it has already sent to Grbl. As long as a feed hold doesn't cancel the jog state, every jog command is guaranteed to execute. In the event a feed hold is sent, the GUI would just need to refresh their internal position from a status report after Grbl has cleared planner buffer and returned to the IDLE state from the JOG state. This stopped position will always be somewhere along the programmed jog path. If desired, jogging can then be quickly and easily restarted with a new tracked path.
|
||||
|
||||
In combination with `G53` move in machine coordinates, a GUI can restrict jogging from moving into "keep-out" zones inside the machine space. This can be very useful for avoiding crashing into delicate probing hardware, workholding mechanisms, or other fixed features inside machine space that you don't want to damage.
|
||||
|
||||
#### How to compute incremental distances
|
||||
|
||||
The quickest and easiest way to determine what the length of a jog motion needs to be to minimize latency are defined by the following equations.
|
||||
|
||||
`d = v * dt` - Computes distance traveled for next jog command.
|
||||
|
||||
where:
|
||||
|
||||
- `dt` - Estimated execution time of a single jog command in seconds.
|
||||
- `v` - Current jog feed rate in **mm/sec**, not mm/min. Less than or equal to max jog rate.
|
||||
- `N` - Number of Grbl planner blocks (`N=15`)
|
||||
- `T = dt * N` - Computes total estimated latency in seconds.
|
||||
|
||||
The time increment `dt` may be defined to whatever value you need. Obviously, you'd like the lowest value, since that translates to lower overall latency `T`. However, it is constrained by two factors.
|
||||
|
||||
- `dt > 10ms` - The time it takes Grbl to parse and plan one jog command and receive the next one. Depending on a lot of factors, this can be around 1 to 5 ms. To be conservative, `10ms` is used. Keep in mind that on some systems, this value may be greater than `10ms`.
|
||||
|
||||
- `dt > v^2 / (2 * a * (N-1))` - The time increment needs to be large enough to ensure the jog feed rate will be acheived. Grbl always plans to a stop over the total distance queued in the planner buffer. This is primarily to ensure the machine will safely stop if a disconnection occurs. This equation simply ensures that `dt` is big enough to satisfy this constraint.
|
||||
|
||||
- For simplicity, use the max jog feed rate for `v` in mm/sec and the smallest acceleration setting between the jog axes being moved in mm/sec^2.
|
||||
|
||||
- For a lower latency, `dt` can be computed for each jog motion, where `v` is the current rate and `a` is the max acceleration along the jog vector. This is very useful if traveling a very slow speeds to locate a part zero. The `v` rate would be much lower in this scenario and the total latency would decrease quadratically.
|
||||
|
||||
In practice, most CNC machines will operate with a jogging time increment of `0.025 sec` < `dt` < `0.06 sec`, which translates to about a `0.4` to `0.9` second total latency when traveling at the max jog rate. Good enough for most people.
|
||||
|
||||
However, if jogging at a slower speed and a GUI adjusts the `dt` with it, you can get very close to the 0.1 second response time by human-interface guidelines for "feeling instantaneous". Not to shabby!
|
@ -254,10 +254,10 @@
|
||||
// NOTE: This feature is new and experimental. Make sure the GUI you are using supports this mode.
|
||||
#define REPORT_GUI_MODE // Default enabled. Comment to disable.
|
||||
|
||||
// The status report change for Grbl v1.0 and after also removed the ability to disable/enable data fields
|
||||
// from the report. This caused issues for GUI developers, who've had to manage several scenarios and
|
||||
// configurations. The increased efficiency of the new reporting style allows for all data fields to be
|
||||
// sent without potential performance issues.
|
||||
// The status report change for Grbl v1.0 and after also removed the ability to disable/enable most data
|
||||
// fields from the report. This caused issues for GUI developers, who've had to manage several scenarios
|
||||
// and configurations. The increased efficiency of the new reporting style allows for all data fields to
|
||||
// be sent without potential performance issues.
|
||||
// NOTE: The options below are here only provide a way to disable certain data fields if a unique
|
||||
// situation demands it, but be aware GUIs may depend on this data. If disabled, it may not be compatible.
|
||||
#define REPORT_FIELD_BUFFER_STATE // Default enabled. Comment to disable.
|
||||
@ -453,16 +453,6 @@
|
||||
// #define RX_BUFFER_SIZE 128 // (1-254) Uncomment to override defaults in serial.h
|
||||
// #define TX_BUFFER_SIZE 90 // (1-254)
|
||||
|
||||
// Toggles XON/XOFF software flow control for serial communications. Not officially supported
|
||||
// due to problems involving the Atmega8U2 USB-to-serial chips on current Arduinos. The firmware
|
||||
// on these chips do not support XON/XOFF flow control characters and the intermediate buffer
|
||||
// in the chips cause latency and overflow problems with standard terminal programs. However,
|
||||
// using specifically-programmed UI's to manage this latency problem has been confirmed to work.
|
||||
// As well as, older FTDI FT232RL-based Arduinos(Duemilanove) are known to work with standard
|
||||
// terminal programs since their firmware correctly manage these XON/XOFF characters. In any
|
||||
// case, please report any successes to grbl administrators!
|
||||
// #define ENABLE_XONXOFF // Default disabled. Uncomment to enable.
|
||||
|
||||
// A simple software debouncing feature for hard limit switches. When enabled, the interrupt
|
||||
// monitoring the hard limit switch pins will enable the Arduino's watchdog timer to re-check
|
||||
// the limit pin state after a delay of about 32msec. This can help with CNC machines with
|
||||
@ -472,6 +462,10 @@
|
||||
// work well and are cheap to find) and wire in a low-pass circuit into each limit pin.
|
||||
// #define ENABLE_SOFTWARE_DEBOUNCE // Default disabled. Uncomment to enable.
|
||||
|
||||
// Configures the position after a probing cycle during Grbl's check mode. Disabled sets
|
||||
// the position to the probe target, when enabled sets the position to the start position.
|
||||
// #define SET_CHECK_MODE_PROBE_TO_START // Default disabled. Uncomment to enable.
|
||||
|
||||
// Force Grbl to check the state of the hard limit switches when the processor detects a pin
|
||||
// change inside the hard limit ISR routine. By default, Grbl will trigger the hard limits
|
||||
// alarm upon any pin change, since bouncing switches can cause a state check like this to
|
||||
|
@ -47,7 +47,7 @@
|
||||
#define DEFAULT_STEPPING_INVERT_MASK 0
|
||||
#define DEFAULT_DIRECTION_INVERT_MASK 0
|
||||
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled)
|
||||
#define DEFAULT_STATUS_REPORT_MASK 255 // All enabled
|
||||
#define DEFAULT_STATUS_REPORT_MASK 1 // MPos enabled
|
||||
#define DEFAULT_JUNCTION_DEVIATION 0.01 // mm
|
||||
#define DEFAULT_ARC_TOLERANCE 0.002 // mm
|
||||
#define DEFAULT_REPORT_INCHES 0 // false
|
||||
@ -89,7 +89,7 @@
|
||||
#define DEFAULT_STEPPING_INVERT_MASK 0
|
||||
#define DEFAULT_DIRECTION_INVERT_MASK ((1<<Y_AXIS)|(1<<Z_AXIS))
|
||||
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled)
|
||||
#define DEFAULT_STATUS_REPORT_MASK 255 // All enabled
|
||||
#define DEFAULT_STATUS_REPORT_MASK 1 // MPos enabled
|
||||
#define DEFAULT_JUNCTION_DEVIATION 0.01 // mm
|
||||
#define DEFAULT_ARC_TOLERANCE 0.002 // mm
|
||||
#define DEFAULT_REPORT_INCHES 0 // true
|
||||
@ -134,7 +134,7 @@
|
||||
#define DEFAULT_STEPPING_INVERT_MASK 0
|
||||
#define DEFAULT_DIRECTION_INVERT_MASK ((1<<Y_AXIS)|(1<<Z_AXIS))
|
||||
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 255 // msec (0-254, 255 keeps steppers enabled)
|
||||
#define DEFAULT_STATUS_REPORT_MASK 255 // All enabled
|
||||
#define DEFAULT_STATUS_REPORT_MASK 1 // MPos enabled
|
||||
#define DEFAULT_JUNCTION_DEVIATION 0.02 // mm
|
||||
#define DEFAULT_ARC_TOLERANCE 0.002 // mm
|
||||
#define DEFAULT_REPORT_INCHES 0 // false
|
||||
@ -179,7 +179,7 @@
|
||||
#define DEFAULT_STEPPING_INVERT_MASK 0
|
||||
#define DEFAULT_DIRECTION_INVERT_MASK ((1<<X_AXIS)|(1<<Z_AXIS))
|
||||
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 255 // msec (0-254, 255 keeps steppers enabled)
|
||||
#define DEFAULT_STATUS_REPORT_MASK 255 // All enabled
|
||||
#define DEFAULT_STATUS_REPORT_MASK 1 // MPos enabled
|
||||
#define DEFAULT_JUNCTION_DEVIATION 0.02 // mm
|
||||
#define DEFAULT_ARC_TOLERANCE 0.002 // mm
|
||||
#define DEFAULT_REPORT_INCHES 0 // false
|
||||
@ -223,7 +223,7 @@
|
||||
#define DEFAULT_STEPPING_INVERT_MASK 0
|
||||
#define DEFAULT_DIRECTION_INVERT_MASK ((1<<X_AXIS)|(1<<Z_AXIS))
|
||||
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 255 // msec (0-254, 255 keeps steppers enabled)
|
||||
#define DEFAULT_STATUS_REPORT_MASK 255 // All enabled
|
||||
#define DEFAULT_STATUS_REPORT_MASK 1 // MPos enabled
|
||||
#define DEFAULT_JUNCTION_DEVIATION 0.02 // mm
|
||||
#define DEFAULT_ARC_TOLERANCE 0.01 // mm
|
||||
#define DEFAULT_REPORT_INCHES 0 // false
|
||||
@ -268,7 +268,7 @@
|
||||
#define DEFAULT_STEPPING_INVERT_MASK 0
|
||||
#define DEFAULT_DIRECTION_INVERT_MASK ((1<<X_AXIS)|(1<<Y_AXIS))
|
||||
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 255 // msec (0-254, 255 keeps steppers enabled)
|
||||
#define DEFAULT_STATUS_REPORT_MASK 255 // All enabled
|
||||
#define DEFAULT_STATUS_REPORT_MASK 1 // MPos enabled
|
||||
#define DEFAULT_JUNCTION_DEVIATION 0.02 // mm
|
||||
#define DEFAULT_ARC_TOLERANCE 0.002 // mm
|
||||
#define DEFAULT_REPORT_INCHES 0 // false
|
||||
@ -313,7 +313,7 @@
|
||||
#define DEFAULT_STEPPING_INVERT_MASK 0
|
||||
#define DEFAULT_DIRECTION_INVERT_MASK ((1<<X_AXIS)|(1<<Y_AXIS))
|
||||
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 255 // msec (0-254, 255 keeps steppers enabled)
|
||||
#define DEFAULT_STATUS_REPORT_MASK 255 // All enabled
|
||||
#define DEFAULT_STATUS_REPORT_MASK 1 // MPos enabled
|
||||
#define DEFAULT_JUNCTION_DEVIATION 0.02 // mm
|
||||
#define DEFAULT_ARC_TOLERANCE 0.002 // mm
|
||||
#define DEFAULT_REPORT_INCHES 0 // false
|
||||
@ -356,7 +356,7 @@
|
||||
#define DEFAULT_STEPPING_INVERT_MASK 0
|
||||
#define DEFAULT_DIRECTION_INVERT_MASK ((1<<Y_AXIS))
|
||||
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled)
|
||||
#define DEFAULT_STATUS_REPORT_MASK 255 // All enabled
|
||||
#define DEFAULT_STATUS_REPORT_MASK 1 // MPos enabled
|
||||
#define DEFAULT_JUNCTION_DEVIATION 0.02 // mm
|
||||
#define DEFAULT_ARC_TOLERANCE 0.002 // mm
|
||||
#define DEFAULT_REPORT_INCHES 0 // false
|
||||
@ -395,7 +395,7 @@
|
||||
#define DEFAULT_STEPPING_INVERT_MASK 0
|
||||
#define DEFAULT_DIRECTION_INVERT_MASK 0
|
||||
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled)
|
||||
#define DEFAULT_STATUS_REPORT_MASK 255 // All enabled
|
||||
#define DEFAULT_STATUS_REPORT_MASK 1 // MPos enabled
|
||||
#define DEFAULT_JUNCTION_DEVIATION 0.02 // mm
|
||||
#define DEFAULT_ARC_TOLERANCE 0.002 // mm
|
||||
#define DEFAULT_REPORT_INCHES 0 // false
|
||||
@ -434,7 +434,7 @@
|
||||
#define DEFAULT_STEPPING_INVERT_MASK 0
|
||||
#define DEFAULT_DIRECTION_INVERT_MASK 0
|
||||
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled)
|
||||
#define DEFAULT_STATUS_REPORT_MASK 255 // All enabled
|
||||
#define DEFAULT_STATUS_REPORT_MASK 1 // MPos enabled
|
||||
#define DEFAULT_JUNCTION_DEVIATION 0.01 // mm
|
||||
#define DEFAULT_ARC_TOLERANCE 0.002 // mm
|
||||
#define DEFAULT_REPORT_INCHES 0 // false
|
||||
|
66
grbl/gcode.c
66
grbl/gcode.c
@ -57,15 +57,6 @@ void gc_sync_position()
|
||||
}
|
||||
|
||||
|
||||
static uint8_t gc_check_same_position(float *pos_a, float *pos_b)
|
||||
{
|
||||
uint8_t idx;
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
if (pos_a[idx] != pos_b[idx]) { return(false); }
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
// Executes one line of 0-terminated G-Code. The line is assumed to contain only uppercase
|
||||
// characters and signed floating point values (no whitespace). Comments and block delete
|
||||
// characters have been removed. In this function, all units and positions are converted and
|
||||
@ -430,6 +421,11 @@ 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 (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 {
|
||||
if (gc_block.modal.feed_rate == FEED_RATE_MODE_INVERSE_TIME) { // = G93
|
||||
// NOTE: G38 can also operate in inverse time, but is undefined as an error. Missing F word check added here.
|
||||
if (axis_command == AXIS_COMMAND_MOTION_MODE) {
|
||||
@ -455,11 +451,11 @@ uint8_t gc_execute_line(char *line)
|
||||
if (bit_istrue(value_words,bit(WORD_F))) {
|
||||
if (gc_block.modal.units == UNITS_MODE_INCHES) { gc_block.values.f *= MM_PER_INCH; }
|
||||
} else {
|
||||
// NOTE: Jogging mode does not pass modal feed rate and requires unique values for each command.
|
||||
if (!is_jog_motion) { gc_block.values.f = gc_state.feed_rate; } // Push last state feed rate
|
||||
gc_block.values.f = gc_state.feed_rate; // Push last state feed rate
|
||||
}
|
||||
} // Else, switching to G94 from G93, so don't push last state feed rate. Its undefined or the passed F word value.
|
||||
}
|
||||
}
|
||||
// bit_false(value_words,bit(WORD_F)); // NOTE: Single-meaning value word. Set at end of error-checking.
|
||||
|
||||
// [4. Set spindle speed ]: S is negative (done.)
|
||||
@ -712,7 +708,7 @@ uint8_t gc_execute_line(char *line)
|
||||
|
||||
if (value_words & bit(WORD_R)) { // Arc Radius Mode
|
||||
bit_false(value_words,bit(WORD_R));
|
||||
if (gc_check_same_position(gc_state.position, gc_block.values.xyz)) { FAIL(STATUS_GCODE_INVALID_TARGET); } // [Invalid target]
|
||||
if (isequal_position_vector(gc_state.position, gc_block.values.xyz)) { FAIL(STATUS_GCODE_INVALID_TARGET); } // [Invalid target]
|
||||
|
||||
// Convert radius value to proper units.
|
||||
if (gc_block.modal.units == UNITS_MODE_INCHES) { gc_block.values.r *= MM_PER_INCH; }
|
||||
@ -836,7 +832,7 @@ uint8_t gc_execute_line(char *line)
|
||||
// an error, it issues an alarm to prevent further motion to the probe. It's also done there to
|
||||
// allow the planner buffer to empty and move off the probe trigger before another probing cycle.
|
||||
if (!axis_words) { FAIL(STATUS_GCODE_NO_AXIS_WORDS); } // [No axis words]
|
||||
if (gc_check_same_position(gc_state.position, gc_block.values.xyz)) { FAIL(STATUS_GCODE_INVALID_TARGET); } // [Invalid target]
|
||||
if (isequal_position_vector(gc_state.position, gc_block.values.xyz)) { FAIL(STATUS_GCODE_INVALID_TARGET); } // [Invalid target]
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1021,42 +1017,38 @@ uint8_t gc_execute_line(char *line)
|
||||
gc_state.modal.motion = gc_block.modal.motion;
|
||||
if (gc_state.modal.motion != MOTION_MODE_NONE) {
|
||||
if (axis_command == AXIS_COMMAND_MOTION_MODE) {
|
||||
switch (gc_state.modal.motion) {
|
||||
case MOTION_MODE_SEEK:
|
||||
uint8_t gc_update_pos = GC_UPDATE_POS_TARGET;
|
||||
if (gc_state.modal.motion == MOTION_MODE_LINEAR) {
|
||||
mc_line(gc_block.values.xyz, pl_data);
|
||||
} else if (gc_state.modal.motion == MOTION_MODE_SEEK) {
|
||||
pl_data->condition |= PL_COND_FLAG_RAPID_MOTION; // Set rapid motion condition flag.
|
||||
mc_line(gc_block.values.xyz, pl_data);
|
||||
break;
|
||||
case MOTION_MODE_LINEAR:
|
||||
mc_line(gc_block.values.xyz, pl_data);
|
||||
break;
|
||||
case MOTION_MODE_CW_ARC:
|
||||
} 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, true);
|
||||
break;
|
||||
case MOTION_MODE_CCW_ARC:
|
||||
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, false);
|
||||
break;
|
||||
case MOTION_MODE_PROBE_TOWARD:
|
||||
axis_0, axis_1, axis_linear, is_clockwise_arc);
|
||||
} 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.
|
||||
mc_probe_cycle(gc_block.values.xyz, pl_data, false, false);
|
||||
break;
|
||||
case MOTION_MODE_PROBE_TOWARD_NO_ERROR:
|
||||
mc_probe_cycle(gc_block.values.xyz, pl_data, false, true);
|
||||
break;
|
||||
case MOTION_MODE_PROBE_AWAY:
|
||||
mc_probe_cycle(gc_block.values.xyz, pl_data, true, false);
|
||||
break;
|
||||
case MOTION_MODE_PROBE_AWAY_NO_ERROR:
|
||||
mc_probe_cycle(gc_block.values.xyz, pl_data, true, true);
|
||||
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);
|
||||
}
|
||||
|
||||
// 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
|
||||
// in any intermediate location.
|
||||
if (gc_update_pos == GC_UPDATE_POS_TARGET) {
|
||||
memcpy(gc_state.position, gc_block.values.xyz, sizeof(gc_block.values.xyz)); // gc_state.position[] = gc_block.values.xyz[]
|
||||
} else if (gc_update_pos == GC_UPDATE_POS_SYSTEM) {
|
||||
gc_sync_position(); // gc_state.position[] = sys_position
|
||||
} // == GC_UPDATE_POS_NONE
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// [21. Program flow ]:
|
||||
|
18
grbl/gcode.h
18
grbl/gcode.h
@ -123,7 +123,6 @@
|
||||
// Modal Group G12: Active work coordinate system
|
||||
// N/A: Stores coordinate system value (54-59) to change to.
|
||||
|
||||
|
||||
// Define parameter word mapping.
|
||||
#define WORD_F 0
|
||||
#define WORD_I 1
|
||||
@ -139,6 +138,23 @@
|
||||
#define WORD_Y 11
|
||||
#define WORD_Z 12
|
||||
|
||||
// Define g-code parser position updating flags
|
||||
#define GC_UPDATE_POS_TARGET 0
|
||||
#define GC_UPDATE_POS_SYSTEM 1
|
||||
#define GC_UPDATE_POS_NONE 2
|
||||
|
||||
// Define probe cycle exit states and assign proper position updating.
|
||||
#define GC_PROBE_FOUND GC_UPDATE_POS_SYSTEM
|
||||
#define GC_PROBE_ABORT GC_UPDATE_POS_NONE
|
||||
#define GC_PROBE_FAIL_INIT GC_UPDATE_POS_NONE
|
||||
#define GC_PROBE_FAIL_END GC_UPDATE_POS_TARGET
|
||||
#ifdef SET_CHECK_MODE_PROBE_TO_START
|
||||
#define GC_PROBE_CHECK_MODE GC_UPDATE_POS_NONE
|
||||
#else
|
||||
#define GC_PROBE_CHECK_MODE GC_UPDATE_POS_TARGET
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// NOTE: When this struct is zeroed, the above defines set the defaults for the system.
|
||||
typedef struct {
|
||||
|
@ -22,8 +22,8 @@
|
||||
#define grbl_h
|
||||
|
||||
// Grbl versioning system
|
||||
#define GRBL_VERSION "1.1a"
|
||||
#define GRBL_VERSION_BUILD "20160925"
|
||||
#define GRBL_VERSION "1.1b"
|
||||
#define GRBL_VERSION_BUILD "20160926"
|
||||
|
||||
// Define standard libraries used by Grbl.
|
||||
#include <avr/io.h>
|
||||
|
@ -237,13 +237,14 @@ void mc_homing_cycle()
|
||||
|
||||
// Perform tool length probe cycle. Requires probe switch.
|
||||
// NOTE: Upon probe failure, the program will be stopped and placed into ALARM state.
|
||||
void 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 is_probe_away, uint8_t is_no_error)
|
||||
{
|
||||
// TODO: Need to update this cycle so it obeys a non-auto cycle start.
|
||||
if (sys.state == STATE_CHECK_MODE) { return; }
|
||||
if (sys.state == STATE_CHECK_MODE) { return(GC_PROBE_CHECK_MODE); }
|
||||
|
||||
// Finish all queued commands and empty planner buffer before starting probe cycle.
|
||||
protocol_buffer_synchronize();
|
||||
if (sys.abort) { return(GC_PROBE_ABORT); } // Return if system reset has been issued.
|
||||
|
||||
// Initialize probing control variables
|
||||
sys.probe_succeeded = false; // Re-initialize probe history before beginning cycle.
|
||||
@ -254,8 +255,9 @@ void mc_probe_cycle(float *target, plan_line_data_t *pl_data, uint8_t is_probe_a
|
||||
if ( probe_get_state() ) { // Check probe pin state.
|
||||
system_set_exec_alarm(EXEC_ALARM_PROBE_FAIL_INITIAL);
|
||||
protocol_execute_realtime();
|
||||
probe_configure_invert_mask(false); // Re-initialize invert mask before returning.
|
||||
return(GC_PROBE_FAIL_INIT); // Nothing else to do but bail.
|
||||
}
|
||||
if (sys.abort) { return; } // Return if system reset has been issued.
|
||||
|
||||
// Setup and queue probing motion. Auto cycle-start should not start the cycle.
|
||||
mc_line(target, pl_data);
|
||||
@ -267,7 +269,7 @@ void mc_probe_cycle(float *target, plan_line_data_t *pl_data, uint8_t is_probe_a
|
||||
system_set_exec_state_flag(EXEC_CYCLE_START);
|
||||
do {
|
||||
protocol_execute_realtime();
|
||||
if (sys.abort) { return; } // Check for system abort
|
||||
if (sys.abort) { return(GC_PROBE_ABORT); } // Check for system abort
|
||||
} while (sys.state != STATE_IDLE);
|
||||
|
||||
// Probing cycle complete!
|
||||
@ -280,8 +282,8 @@ void mc_probe_cycle(float *target, plan_line_data_t *pl_data, uint8_t is_probe_a
|
||||
sys.probe_succeeded = true; // Indicate to system the probing cycle completed successfully.
|
||||
}
|
||||
sys_probe_state = PROBE_OFF; // Ensure probe state monitor is disabled.
|
||||
probe_configure_invert_mask(false); // Re-initialize invert mask.
|
||||
protocol_execute_realtime(); // Check and execute run-time commands
|
||||
if (sys.abort) { return; } // Check for system abort
|
||||
|
||||
// Reset the stepper and planner buffers to remove the remainder of the probe motion.
|
||||
st_reset(); // Reset step segment buffer.
|
||||
@ -290,12 +292,21 @@ void mc_probe_cycle(float *target, plan_line_data_t *pl_data, uint8_t is_probe_a
|
||||
|
||||
// TODO: Update the g-code parser code to not require this target calculation but uses a gc_sync_position() call.
|
||||
// NOTE: The target[] variable updated here will be sent back and synced with the g-code parser.
|
||||
system_convert_array_steps_to_mpos(target, sys_position);
|
||||
|
||||
//!!! This is the problem. Need to set the g-code parser to update the position appropriately.
|
||||
// - Probe initialization fail: Retain current position.
|
||||
// - Probe successful: Update new positions across everything, since held before the target.
|
||||
// - Probe did not contact (alarm or not): Copy original target position as normal
|
||||
|
||||
// system_convert_array_steps_to_mpos(target, sys_position);
|
||||
|
||||
#ifdef MESSAGE_PROBE_COORDINATES
|
||||
// All done! Output the probe position as message.
|
||||
report_probe_parameters();
|
||||
#endif
|
||||
|
||||
if (sys.probe_succeeded) { return(GC_PROBE_FOUND); } // Successful probe cycle.
|
||||
else { return(GC_PROBE_FAIL_END); } // Failed to trigger probe within travel. With or without error.
|
||||
}
|
||||
|
||||
|
||||
|
@ -46,7 +46,7 @@ void mc_dwell(float seconds);
|
||||
void mc_homing_cycle();
|
||||
|
||||
// Perform tool length probe cycle. Requires probe switch.
|
||||
void 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 is_probe_away, uint8_t is_no_error);
|
||||
|
||||
// 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);
|
||||
|
@ -55,6 +55,7 @@
|
||||
// #define clear_vector_long(a) memset(a, 0.0, sizeof(long)*N_AXIS)
|
||||
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
||||
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#define isequal_position_vector(a,b) !(memcmp(a, b, sizeof(float)*N_AXIS))
|
||||
|
||||
// Bit field and masking macros
|
||||
#define bit(n) (1 << n)
|
||||
|
@ -487,7 +487,16 @@ void plan_sync_position()
|
||||
}
|
||||
|
||||
|
||||
// Returns the number of available blocks are in the planner buffer.
|
||||
uint8_t plan_get_block_buffer_available()
|
||||
{
|
||||
if (block_buffer_head >= block_buffer_tail) { return((BLOCK_BUFFER_SIZE-1)-(block_buffer_head-block_buffer_tail)); }
|
||||
return((block_buffer_tail-block_buffer_head-1));
|
||||
}
|
||||
|
||||
|
||||
// Returns the number of active blocks are in the planner buffer.
|
||||
// NOTE: Deprecated. Not used unless classic status reports are enabled in config.h
|
||||
uint8_t plan_get_block_buffer_count()
|
||||
{
|
||||
if (block_buffer_head >= block_buffer_tail) { return(block_buffer_head-block_buffer_tail); }
|
||||
|
@ -131,7 +131,11 @@ void plan_sync_position();
|
||||
// Reinitialize plan with a partially completed block
|
||||
void plan_cycle_reinitialize();
|
||||
|
||||
// Returns the number of available blocks are in the planner buffer.
|
||||
uint8_t plan_get_block_buffer_available();
|
||||
|
||||
// Returns the number of active blocks are in the planner buffer.
|
||||
// NOTE: Deprecated. Not used unless classic status reports are enabled in config.h
|
||||
uint8_t plan_get_block_buffer_count();
|
||||
|
||||
// Returns the status of the block ring buffer. True, if buffer is full.
|
||||
|
@ -725,10 +725,12 @@ void report_realtime_status()
|
||||
|
||||
// Returns planner and serial read buffer states.
|
||||
#ifdef REPORT_FIELD_BUFFER_STATE
|
||||
if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_BUFFER_STATE)) {
|
||||
printPgmString(PSTR("|Bf:"));
|
||||
print_uint8_base10(plan_get_block_buffer_count());
|
||||
print_uint8_base10(plan_get_block_buffer_available());
|
||||
serial_write(',');
|
||||
print_uint8_base10(serial_get_rx_buffer_count());
|
||||
print_uint8_base10(serial_get_rx_buffer_available());
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
|
@ -33,12 +33,17 @@ uint8_t serial_tx_buffer_head = 0;
|
||||
volatile uint8_t serial_tx_buffer_tail = 0;
|
||||
|
||||
|
||||
#ifdef ENABLE_XONXOFF
|
||||
volatile uint8_t flow_ctrl = XON_SENT; // Flow control state variable
|
||||
#endif
|
||||
// Returns the number of bytes available in the RX serial buffer.
|
||||
uint8_t serial_get_rx_buffer_available()
|
||||
{
|
||||
uint8_t rtail = serial_rx_buffer_tail; // Copy to limit multiple calls to volatile
|
||||
if (serial_rx_buffer_head >= rtail) { return(RX_BUFFER_SIZE - (serial_rx_buffer_head-rtail)); }
|
||||
return((rtail-serial_rx_buffer_head-1));
|
||||
}
|
||||
|
||||
|
||||
// Returns the number of bytes used in the RX serial buffer.
|
||||
// NOTE: Deprecated. Not used unless classic status reports are enabled in config.h.
|
||||
uint8_t serial_get_rx_buffer_count()
|
||||
{
|
||||
uint8_t rtail = serial_rx_buffer_tail; // Copy to limit multiple calls to volatile
|
||||
@ -104,16 +109,6 @@ ISR(SERIAL_UDRE)
|
||||
{
|
||||
uint8_t tail = serial_tx_buffer_tail; // Temporary serial_tx_buffer_tail (to optimize for volatile)
|
||||
|
||||
#ifdef ENABLE_XONXOFF
|
||||
if (flow_ctrl == SEND_XOFF) {
|
||||
UDR0 = XOFF_CHAR;
|
||||
flow_ctrl = XOFF_SENT;
|
||||
} else if (flow_ctrl == SEND_XON) {
|
||||
UDR0 = XON_CHAR;
|
||||
flow_ctrl = XON_SENT;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
// Send a byte from the buffer
|
||||
UDR0 = serial_tx_buffer[tail];
|
||||
|
||||
@ -122,7 +117,6 @@ ISR(SERIAL_UDRE)
|
||||
if (tail == TX_RING_BUFFER) { tail = 0; }
|
||||
|
||||
serial_tx_buffer_tail = tail;
|
||||
}
|
||||
|
||||
// Turn off Data Register Empty Interrupt to stop tx-streaming if this concludes the transfer
|
||||
if (tail == serial_tx_buffer_head) { UCSR0B &= ~(1 << UDRIE0); }
|
||||
@ -142,13 +136,6 @@ uint8_t serial_read()
|
||||
if (tail == RX_RING_BUFFER) { tail = 0; }
|
||||
serial_rx_buffer_tail = tail;
|
||||
|
||||
#ifdef ENABLE_XONXOFF
|
||||
if ((serial_get_rx_buffer_count() < RX_BUFFER_LOW) && flow_ctrl == XOFF_SENT) {
|
||||
flow_ctrl = SEND_XON;
|
||||
UCSR0B |= (1 << UDRIE0); // Force TX
|
||||
}
|
||||
#endif
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -201,14 +188,6 @@ ISR(SERIAL_RX)
|
||||
if (next_head != serial_rx_buffer_tail) {
|
||||
serial_rx_buffer[serial_rx_buffer_head] = data;
|
||||
serial_rx_buffer_head = next_head;
|
||||
|
||||
#ifdef ENABLE_XONXOFF
|
||||
if ((serial_get_rx_buffer_count() >= RX_BUFFER_FULL) && flow_ctrl == XON_SENT) {
|
||||
flow_ctrl = SEND_XOFF;
|
||||
UCSR0B |= (1 << UDRIE0); // Force TX
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -218,8 +197,4 @@ ISR(SERIAL_RX)
|
||||
void serial_reset_read_buffer()
|
||||
{
|
||||
serial_rx_buffer_tail = serial_rx_buffer_head;
|
||||
|
||||
#ifdef ENABLE_XONXOFF
|
||||
flow_ctrl = XON_SENT;
|
||||
#endif
|
||||
}
|
||||
|
@ -36,16 +36,6 @@
|
||||
|
||||
#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();
|
||||
|
||||
@ -58,7 +48,11 @@ uint8_t serial_read();
|
||||
// Reset and empty data in read buffer. Used by e-stop and reset.
|
||||
void serial_reset_read_buffer();
|
||||
|
||||
// Returns the number of bytes available in the RX serial buffer.
|
||||
uint8_t serial_get_rx_buffer_available();
|
||||
|
||||
// Returns the number of bytes used in the RX serial buffer.
|
||||
// NOTE: Deprecated. Not used unless classic status reports are enabled in config.h.
|
||||
uint8_t serial_get_rx_buffer_count();
|
||||
|
||||
// Returns the number of bytes used in the TX serial buffer.
|
||||
|
@ -51,6 +51,7 @@
|
||||
#define BITFLAG_RT_STATUS_OVERRIDES bit(7)
|
||||
#else
|
||||
#define BITFLAG_RT_STATUS_POSITION_TYPE bit(0)
|
||||
#define BITFLAG_RT_STATUS_BUFFER_STATE bit(1)
|
||||
#endif
|
||||
|
||||
// Define settings restore bitflags.
|
||||
|
Loading…
Reference in New Issue
Block a user