Settings refactoring. Bug fixes. Misc new features.

This is likely the last major change to the v0.9 code base before push
to master. Only two minor things remain on the agenda (CoreXY support,
force clear EEPROM, and an extremely low federate bug).

- NEW! Grbl is now compile-able and may be flashed directly through the
Arduino IDE. Only minor changes were required for this compatibility.
See the Wiki to learn how to do it.

- New status reporting mask to turn on and off what Grbl sends back.
This includes machine coordinates, work coordinates, serial RX buffer
usage, and planner buffer usage. Expandable to more information on user
request, but that’s it for now.

- Settings have been completely renumbered to allow for future new
settings to be installed without having to constantly reshuffle and
renumber all of the settings every time.

- All settings masks have been standardized to mean bit 0 = X, bit 1 =
Y, and bit 2 = Z, to reduce confusion on how they work. The invert
masks used by the internal Grbl system were updated to accommodate this
change as well.

- New invert probe pin setting, which does what it sounds like.

- Fixed a probing cycle bug, where it would freeze intermittently, and
removed some redundant code.

- Homing may now be set to the origin wherever the limit switches are.
Traditionally machine coordinates should always be in negative space,
but when limit switches on are on the opposite side, the machine
coordinate would be set to -max_travel for the axis. Now you can always
make it [0,0,0] via a compile-time option in config.h. (Soft limits
routine was updated to account for this as well.)

 - Probe coordinate message immediately after a probing cycle may now
be turned off via a compile-time option in config.h. By default the
probing location is always reported.

- Reduced the N_ARC_CORRECTION default value to reflect the changes in
how circles are generated by an arc tolerance, rather than a fixed arc
segment setting.

- Increased the incoming line buffer limit from 70 to 80 characters.
Had some extra memory space to invest into this.

- Fixed a bug where tool number T was not being tracked and reported
correctly.

- Added a print free memory function for debugging purposes. Not used
otherwise.

- Realtime rate report should now work during feed holds, but it hasn’t
been tested yet.

- Updated the streaming scripts with MIT-license and added the simple
streaming to the main stream.py script to allow for settings to be sent.

- Some minor code refactoring to improve flash efficiency. Reduced the
flash by several hundred KB, which was re-invested in some of these new
features.
This commit is contained in:
Sonny Jeon 2014-07-26 15:01:34 -06:00
parent 1c74be0625
commit 71f333ddca
34 changed files with 5686 additions and 562 deletions

View File

@ -13,7 +13,7 @@ Grbl includes full acceleration management with look ahead. That means the contr
* For more information and help, check out our **[Wiki pages!](https://github.com/grbl/grbl/wiki)** If you find that the information is out-dated, please to help us keep it updated by editing it or notifying our community! Thanks! * For more information and help, check out our **[Wiki pages!](https://github.com/grbl/grbl/wiki)** If you find that the information is out-dated, please to help us keep it updated by editing it or notifying our community! Thanks!
* Lead Developers: Sungeun "Sonny" Jeon, Ph.D. (2011-2014) and Simen Svale Skogsrud, a.k.a the O.G. (2009-2011) * Lead Developers: Sonny Jeon, Ph.D. (2011-2014) and Simen Svale Skogsrud, a.k.a the O.G. (2009-2011)
------------ ------------
@ -23,6 +23,7 @@ Grbl includes full acceleration management with look ahead. That means the contr
- **_NEW_ Super Smooth Stepper Algorithm:** Complete overhaul of the handling of the stepper driver to simplify and reduce task time per ISR tick. Much smoother operation with the new Adaptive Multi-Axis Step Smoothing (AMASS) algorithm which does what its name implies (see stepper.c source for details). Users should immediately see significant improvements in how their machines move and overall performance! - **_NEW_ Super Smooth Stepper Algorithm:** Complete overhaul of the handling of the stepper driver to simplify and reduce task time per ISR tick. Much smoother operation with the new Adaptive Multi-Axis Step Smoothing (AMASS) algorithm which does what its name implies (see stepper.c source for details). Users should immediately see significant improvements in how their machines move and overall performance!
- **Stability and Robustness Updates:** Grbl's overall stability has been focused on for this version. The planner and step-execution interface has been completely re-written for robustness and incorruptibility by the introduction of an intermediate step segment buffer that "checks-out" steps from the planner buffer in real-time. This means we can now fearlessly drive Grbl to it's highest limits. Combined with the new stepper algorithm and planner optimizations, this translated to **5x to 10x** overall performance increases in our testing! Also, stability and robustness tests have been reported to easily take 1.4 million (yes, **million**) line g-code programs like a champ! - **Stability and Robustness Updates:** Grbl's overall stability has been focused on for this version. The planner and step-execution interface has been completely re-written for robustness and incorruptibility by the introduction of an intermediate step segment buffer that "checks-out" steps from the planner buffer in real-time. This means we can now fearlessly drive Grbl to it's highest limits. Combined with the new stepper algorithm and planner optimizations, this translated to **5x to 10x** overall performance increases in our testing! Also, stability and robustness tests have been reported to easily take 1.4 million (yes, **million**) line g-code programs like a champ!
- **(x4)+ Faster Planner:** Planning computations improved four-fold or more by optimizing end-to-end operations, which included streamlining the computations and introducing a planner pointer to locate un-improvable portions of the buffer and not waste cycles recomputing them. - **(x4)+ Faster Planner:** Planning computations improved four-fold or more by optimizing end-to-end operations, which included streamlining the computations and introducing a planner pointer to locate un-improvable portions of the buffer and not waste cycles recomputing them.
- **Compile-able via Arduino IDE!:** Grbl's source code may be now download and altered, and then be compiled and flashed directly through the Arduino IDE, which should work on all platforms. See the Wiki for details on how to do it.
- **G-Code Parser Overhaul:** Completely re-written from the ground-up for 100%-compliance* to the g-code standard. (* Parts of the NIST standard are a bit out-dated and arbitrary, so we altered some minor things to make more sense. Differences are outlined in the source code.) We also took steps to allow us to break up the g-code parser into distinct separate tasks, which is key for some future development ideas and improvements. - **G-Code Parser Overhaul:** Completely re-written from the ground-up for 100%-compliance* to the g-code standard. (* Parts of the NIST standard are a bit out-dated and arbitrary, so we altered some minor things to make more sense. Differences are outlined in the source code.) We also took steps to allow us to break up the g-code parser into distinct separate tasks, which is key for some future development ideas and improvements.
- **Independent Acceleration and Velocity Settings:** Each axes may be defined with unique acceleration and velocity parameters and Grbl will automagically calculate the maximum acceleration and velocity through a path depending on the direction traveled. This is very useful for machines that have very different axes properties, like the ShapeOko's z-axis. - **Independent Acceleration and Velocity Settings:** Each axes may be defined with unique acceleration and velocity parameters and Grbl will automagically calculate the maximum acceleration and velocity through a path depending on the direction traveled. This is very useful for machines that have very different axes properties, like the ShapeOko's z-axis.
- **Soft Limits:** Checks if any motion command exceeds workspace limits before executing it, and alarms out, if detected. Another safety feature, but, unlike hard limits, position does not get lost, as it forces a feed hold before erroring out. NOTE: This still requires limit switches for homing so Grbl knows where the machine origin is, and the new max axis travel settings configured correctly for the machine. - **Soft Limits:** Checks if any motion command exceeds workspace limits before executing it, and alarms out, if detected. Another safety feature, but, unlike hard limits, position does not get lost, as it forces a feed hold before erroring out. NOTE: This still requires limit switches for homing so Grbl knows where the machine origin is, and the new max axis travel settings configured correctly for the machine.
@ -31,12 +32,28 @@ Grbl includes full acceleration management with look ahead. That means the contr
- **Improved Arc Performance:** The larger the arc radius, the faster Grbl will trace it! We are now defining arcs in terms of arc chordal tolerance, rather than a fixed segment length. This automatically scales the arc segment length such that maximum radial error of the segment from the true arc is never more than the chordal tolerance value of a super-accurate default of 0.002 mm. - **Improved Arc Performance:** The larger the arc radius, the faster Grbl will trace it! We are now defining arcs in terms of arc chordal tolerance, rather than a fixed segment length. This automatically scales the arc segment length such that maximum radial error of the segment from the true arc is never more than the chordal tolerance value of a super-accurate default of 0.002 mm.
- **CPU Pin Mapping:** In an effort for Grbl to be compatible with other AVR architectures, such as the 1280 or 2560, a new cpu_map.h pin configuration file has been created to allow Grbl to be compiled for them. This is currently user supported, so your mileage may vary. If you run across a bug, please let us know or better send us a fix! Thanks in advance! - **CPU Pin Mapping:** In an effort for Grbl to be compatible with other AVR architectures, such as the 1280 or 2560, a new cpu_map.h pin configuration file has been created to allow Grbl to be compiled for them. This is currently user supported, so your mileage may vary. If you run across a bug, please let us know or better send us a fix! Thanks in advance!
- **New Grbl SIMULATOR! (by @jgeisler and @ashelly):** A completely independent wrapper of the Grbl main source code that may be compiled as an executable on a computer. No Arduino required. Simply simulates the responses of Grbl as if it was on an Arduino. May be used for many things: checking out how Grbl works, pre-process moves for GUI graphics, debugging of new features, etc. Much left to do, but potentially very powerful, as the dummy AVR variables can be written to output anything you need. - **New Grbl SIMULATOR! (by @jgeisler and @ashelly):** A completely independent wrapper of the Grbl main source code that may be compiled as an executable on a computer. No Arduino required. Simply simulates the responses of Grbl as if it was on an Arduino. May be used for many things: checking out how Grbl works, pre-process moves for GUI graphics, debugging of new features, etc. Much left to do, but potentially very powerful, as the dummy AVR variables can be written to output anything you need.
- **Updated Homing Routine:** Sets workspace volume in all negative space regardless of limit switch position. Common on pro CNCs. Now tied directly into the main planner and stepper modules to reduce flash space and allow maximum speeds during seeking. - **Configurable Real-time Status Reporting:** Users can now customize the type of real-time data Grbl reports back when they issue a '?' status report. This includes data such as: machine position, work position, planner buffer usage, serial RX buffer usage.
- **Updated Homing Routine:** Sets workspace volume in all negative space regardless of limit switch position. Common on pro CNCs. But, the behavior may be changed by a compile-time option though. Now tied directly into the main planner and stepper modules to reduce flash space and allow maximum speeds during seeking.
- **Optional Limit Pin Sharing:** Limit switches can be combined to share the same pins to free up precious I/O pins for other purposes. When combined, users must adjust the homing cycle mask in config.h to not home the axes on a shared pin at the same time. Don't worry; hard limits and the homing cycle still work just like they did before. - **Optional Limit Pin Sharing:** Limit switches can be combined to share the same pins to free up precious I/O pins for other purposes. When combined, users must adjust the homing cycle mask in config.h to not home the axes on a shared pin at the same time. Don't worry; hard limits and the homing cycle still work just like they did before.
- **Optional Variable Spindle Speed Output:** Available only as a compile-time option through the config.h file. Enables PWM output for 'S' g-code commands. Enabling this feature will swap the Z-limit D11 pin and spindle enable D12 pin to access the hardware PWM on pin D12. The Z-limit pin, now on D12, should work just as it did before. - **Optional Variable Spindle Speed Output:** Available only as a compile-time option through the config.h file. Enables PWM output for 'S' g-code commands. Enabling this feature will swap the Z-limit D11 pin and spindle enable D12 pin to access the hardware PWM on pin D12. The Z-limit pin, now on D12, should work just as it did before.
- **Additional Compile-Time Feature Options:** Line number tracking, real-time feed rate reporting. - **Additional Compile-Time Feature Options:** Line number tracking, real-time feed rate reporting.
- **SLATED FOR v1.0 DEVELOPMENT** Jogging controls and feedrate/spindle/coolant overrides. (In v0.9, the framework for feedrate overrides are in-place, only the minor details to complete it have yet to be installed.) - **SLATED FOR v1.0 DEVELOPMENT** Jogging controls and feedrate/spindle/coolant overrides. (In v0.9, the framework for feedrate overrides are in-place, only the minor details to complete it have yet to be installed.)
-
```
List of Supported G-Codes in Grbl v0.9
- Non-Modal Commands: G4, G10 L2, G10 L20, G28, G30, G28.1, G30.1, G53, G92, G92.1
- Motion Modes: G0, G1, G2, G3, G38.1, G80
- Feed Rate Modes: G93, G94
- Unit Modes: G20, G21
- Distance Modes: G90, G91
- Plane Select Modes: G17, G18, G19
- Tool Length Offset Modes: G43.1, G49
- Coordinate System Modes: G54, G55, G56, G57, G58, G59
- Program Flow: M0, M1, M2, M30*
- Coolant Control: M7*, M8, M9
- Spindle Control: M3, M4, M5
```
------------- -------------
Grbl is an open-source project and fueled by the free-time of our intrepid administrators and altruistic users. If you'd like to donate, all proceeds will be used to help fund supporting hardware and testing equipment. Thank you! Grbl is an open-source project and fueled by the free-time of our intrepid administrators and altruistic users. If you'd like to donate, all proceeds will be used to help fund supporting hardware and testing equipment. Thank you!

View File

@ -27,6 +27,8 @@
#ifndef config_h #ifndef config_h
#define config_h #define config_h
#include <system.h>
// Default settings. Used when resetting EEPROM. Change to desired name in defaults.h // Default settings. Used when resetting EEPROM. Change to desired name in defaults.h
#define DEFAULTS_GENERIC #define DEFAULTS_GENERIC
@ -78,6 +80,11 @@
// greater. // greater.
#define N_HOMING_LOCATE_CYCLE 2 // Integer (1-128) #define N_HOMING_LOCATE_CYCLE 2 // Integer (1-128)
// After homing, Grbl will set by default the entire machine space into negative space, as is typical
// for professional CNC machines, regardless of where the limit switches are located. Uncomment this
// define to force Grbl to always set the machine origin at the homed location despite switch orientation.
// #define HOMING_FORCE_SET_ORIGIN // Uncomment to enable.
// Number of blocks Grbl executes upon startup. These blocks are stored in EEPROM, where the size // Number of blocks Grbl executes upon startup. These blocks are stored in EEPROM, where the size
// and addresses are defined in settings.h. With the current settings, up to 3 startup blocks may // and addresses are defined in settings.h. With the current settings, up to 3 startup blocks may
// be stored and executed in order. These startup blocks would typically be used to set the g-code // be stored and executed in order. These startup blocks would typically be used to set the g-code
@ -104,6 +111,11 @@
// NOTE: This is experimental and doesn't quite work 100%. Maybe fixed or refactored later. // NOTE: This is experimental and doesn't quite work 100%. Maybe fixed or refactored later.
// #define REPORT_REALTIME_RATE // Disabled by default. Uncomment to enable. // #define REPORT_REALTIME_RATE // Disabled by default. Uncomment to enable.
// Upon a successful probe cycle, this option provides immediately feedback of the probe coordinates
// through an automatically generated message. If disabled, users can still access the last probe
// coordinates through Grbl '$#' print parameters.
#define MESSAGE_PROBE_COORDINATES // Enabled by default. Comment to disable.
// Enables a second coolant control pin via the mist coolant g-code command M7 on the Arduino Uno // Enables a second coolant control pin via the mist coolant g-code command M7 on the Arduino Uno
// analog pin 5. Only use this option if you require a second coolant control pin. // analog pin 5. Only use this option if you require a second coolant control pin.
// NOTE: The M8 flood coolant control pin on analog pin 4 will still be functional regardless. // NOTE: The M8 flood coolant control pin on analog pin 4 will still be functional regardless.
@ -156,12 +168,10 @@
#define MINIMUM_JUNCTION_SPEED 0.0 // (mm/min) #define MINIMUM_JUNCTION_SPEED 0.0 // (mm/min)
// Number of arc generation iterations by small angle approximation before exact arc trajectory // Number of arc generation iterations by small angle approximation before exact arc trajectory
// correction. This parameter maybe decreased if there are issues with the accuracy of the arc // correction with expensive sin() and cos() calcualtions. This parameter maybe decreased if there
// generations. In general, the default value is more than enough for the intended CNC applications // are issues with the accuracy of the arc generations, or increased if arc execution is getting
// of grbl, and should be on the order or greater than the size of the buffer to help with the // bogged down by too many trig calculations.
// computational efficiency of generating arcs. #define N_ARC_CORRECTION 12 // Integer (1-255)
// NOTE: Arcs are now generated by a chordal tolerance
#define N_ARC_CORRECTION 20 // Integer (1-255)
// Time delay increments performed during a dwell. The default value is set at 50ms, which provides // Time delay increments performed during a dwell. The default value is set at 50ms, which provides
// a maximum time delay of roughly 55 minutes, more than enough for most any application. Increasing // a maximum time delay of roughly 55 minutes, more than enough for most any application. Increasing
@ -200,11 +210,11 @@
// each of the startup blocks, as they are each stored as a string of this size. Make sure // each of the startup blocks, as they are each stored as a string of this size. Make sure
// to account for the available EEPROM at the defined memory address in settings.h and for // to account for the available EEPROM at the defined memory address in settings.h and for
// the number of desired startup blocks. // the number of desired startup blocks.
// NOTE: 70 characters is not a problem except for extreme cases, but the line buffer size // NOTE: 80 characters is not a problem except for extreme cases, but the line buffer size
// can be too small and g-code blocks can get truncated. Officially, the g-code standards // can be too small and g-code blocks can get truncated. Officially, the g-code standards
// support up to 256 characters. In future versions, this default will be increased, when // support up to 256 characters. In future versions, this default will be increased, when
// we know how much extra memory space we can re-invest into this. // we know how much extra memory space we can re-invest into this.
// #define LINE_BUFFER_SIZE 70 // Uncomment to override default in protocol.h // #define LINE_BUFFER_SIZE 80 // Uncomment to override default in protocol.h
// Serial send and receive buffer size. The receive buffer is often used as another streaming // Serial send and receive buffer size. The receive buffer is often used as another streaming
// buffer to store incoming blocks to be processed by Grbl when its ready. Most streaming // buffer to store incoming blocks to be processed by Grbl when its ready. Most streaming
@ -212,6 +222,7 @@
// increase the receive buffer if a deeper receive buffer is needed for streaming and avaiable // increase the receive buffer if a deeper receive buffer is needed for streaming and avaiable
// memory allows. The send buffer primarily handles messages in Grbl. Only increase if large // memory allows. The send buffer primarily handles messages in Grbl. Only increase if large
// messages are sent and Grbl begins to stall, waiting to send the rest of the message. // messages are sent and Grbl begins to stall, waiting to send the rest of the message.
// NOTE: Buffer size values must be greater than zero and less than 256.
// #define RX_BUFFER_SIZE 128 // Uncomment to override defaults in serial.h // #define RX_BUFFER_SIZE 128 // Uncomment to override defaults in serial.h
// #define TX_BUFFER_SIZE 64 // #define TX_BUFFER_SIZE 64
@ -246,4 +257,6 @@
// #endif // #endif
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
#endif #endif

View File

@ -43,8 +43,9 @@
#define DEFAULT_Z_MAX_TRAVEL 200.0 // mm #define DEFAULT_Z_MAX_TRAVEL 200.0 // mm
#define DEFAULT_STEP_PULSE_MICROSECONDS 10 #define DEFAULT_STEP_PULSE_MICROSECONDS 10
#define DEFAULT_STEPPING_INVERT_MASK 0 #define DEFAULT_STEPPING_INVERT_MASK 0
#define DEFAULT_DIRECTION_INVERT_MASK ((1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT)) #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_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled)
#define DEFAULT_STATUS_REPORT_MASK ((BITFLAG_RT_STATUS_MACHINE_POSITION)|(BITFLAG_RT_STATUS_WORK_POSITION))
#define DEFAULT_JUNCTION_DEVIATION 0.02 // mm #define DEFAULT_JUNCTION_DEVIATION 0.02 // mm
#define DEFAULT_ARC_TOLERANCE 0.002 // mm #define DEFAULT_ARC_TOLERANCE 0.002 // mm
#define DEFAULT_DECIMAL_PLACES 3 #define DEFAULT_DECIMAL_PLACES 3
@ -82,8 +83,9 @@
#define DEFAULT_Z_MAX_TRAVEL 170.0 // mm #define DEFAULT_Z_MAX_TRAVEL 170.0 // mm
#define DEFAULT_STEP_PULSE_MICROSECONDS 10 #define DEFAULT_STEP_PULSE_MICROSECONDS 10
#define DEFAULT_STEPPING_INVERT_MASK 0 #define DEFAULT_STEPPING_INVERT_MASK 0
#define DEFAULT_DIRECTION_INVERT_MASK ((1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT)) #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_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled)
#define DEFAULT_STATUS_REPORT_MASK ((BITFLAG_RT_STATUS_MACHINE_POSITION)|(BITFLAG_RT_STATUS_WORK_POSITION))
#define DEFAULT_JUNCTION_DEVIATION 0.02 // mm #define DEFAULT_JUNCTION_DEVIATION 0.02 // mm
#define DEFAULT_ARC_TOLERANCE 0.002 // mm #define DEFAULT_ARC_TOLERANCE 0.002 // mm
#define DEFAULT_DECIMAL_PLACES 3 #define DEFAULT_DECIMAL_PLACES 3
@ -124,8 +126,9 @@
#define DEFAULT_Z_MAX_TRAVEL 200.0 // mm #define DEFAULT_Z_MAX_TRAVEL 200.0 // mm
#define DEFAULT_STEP_PULSE_MICROSECONDS 10 #define DEFAULT_STEP_PULSE_MICROSECONDS 10
#define DEFAULT_STEPPING_INVERT_MASK 0 #define DEFAULT_STEPPING_INVERT_MASK 0
#define DEFAULT_DIRECTION_INVERT_MASK ((1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT)) #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_STEPPER_IDLE_LOCK_TIME 255 // msec (0-254, 255 keeps steppers enabled)
#define DEFAULT_STATUS_REPORT_MASK ((BITFLAG_RT_STATUS_MACHINE_POSITION)|(BITFLAG_RT_STATUS_WORK_POSITION))
#define DEFAULT_JUNCTION_DEVIATION 0.05 // mm #define DEFAULT_JUNCTION_DEVIATION 0.05 // mm
#define DEFAULT_ARC_TOLERANCE 0.002 // mm #define DEFAULT_ARC_TOLERANCE 0.002 // mm
#define DEFAULT_DECIMAL_PLACES 3 #define DEFAULT_DECIMAL_PLACES 3
@ -166,8 +169,9 @@
#define DEFAULT_Z_MAX_TRAVEL 200.0 // mm #define DEFAULT_Z_MAX_TRAVEL 200.0 // mm
#define DEFAULT_STEP_PULSE_MICROSECONDS 10 #define DEFAULT_STEP_PULSE_MICROSECONDS 10
#define DEFAULT_STEPPING_INVERT_MASK 0 #define DEFAULT_STEPPING_INVERT_MASK 0
#define DEFAULT_DIRECTION_INVERT_MASK ((1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT)) #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_STEPPER_IDLE_LOCK_TIME 255 // msec (0-254, 255 keeps steppers enabled)
#define DEFAULT_STATUS_REPORT_MASK ((BITFLAG_RT_STATUS_MACHINE_POSITION)|(BITFLAG_RT_STATUS_WORK_POSITION))
#define DEFAULT_JUNCTION_DEVIATION 0.05 // mm #define DEFAULT_JUNCTION_DEVIATION 0.05 // mm
#define DEFAULT_ARC_TOLERANCE 0.002 // mm #define DEFAULT_ARC_TOLERANCE 0.002 // mm
#define DEFAULT_DECIMAL_PLACES 3 #define DEFAULT_DECIMAL_PLACES 3
@ -206,8 +210,9 @@
#define DEFAULT_Z_MAX_TRAVEL 150.0 // mm #define DEFAULT_Z_MAX_TRAVEL 150.0 // mm
#define DEFAULT_STEP_PULSE_MICROSECONDS 10 #define DEFAULT_STEP_PULSE_MICROSECONDS 10
#define DEFAULT_STEPPING_INVERT_MASK 0 #define DEFAULT_STEPPING_INVERT_MASK 0
#define DEFAULT_DIRECTION_INVERT_MASK ((1<<Y_DIRECTION_BIT)) #define DEFAULT_DIRECTION_INVERT_MASK ((1<<Y_AXIS))
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled) #define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled)
#define DEFAULT_STATUS_REPORT_MASK ((BITFLAG_RT_STATUS_MACHINE_POSITION)|(BITFLAG_RT_STATUS_WORK_POSITION))
#define DEFAULT_JUNCTION_DEVIATION 0.02 // mm #define DEFAULT_JUNCTION_DEVIATION 0.02 // mm
#define DEFAULT_ARC_TOLERANCE 0.002 // mm #define DEFAULT_ARC_TOLERANCE 0.002 // mm
#define DEFAULT_DECIMAL_PLACES 3 #define DEFAULT_DECIMAL_PLACES 3

34
gcode.c
View File

@ -95,6 +95,7 @@ uint8_t gc_execute_line(char *line)
memcpy(&gc_block.modal,&gc_state.modal,sizeof(gc_modal_t)); // Copy current modes memcpy(&gc_block.modal,&gc_state.modal,sizeof(gc_modal_t)); // Copy current modes
uint8_t axis_command = AXIS_COMMAND_NONE; uint8_t axis_command = AXIS_COMMAND_NONE;
uint8_t axis_0, axis_1, axis_linear; uint8_t axis_0, axis_1, axis_linear;
uint8_t coord_select = 0; // Tracks G10 P coordinate selection for execution
float coordinate_data[N_AXIS]; // Multi-use variable to store coordinate data for execution float coordinate_data[N_AXIS]; // Multi-use variable to store coordinate data for execution
float parameter_data[N_AXIS]; // Multi-use variable to store parameter data for execution float parameter_data[N_AXIS]; // Multi-use variable to store parameter data for execution
@ -526,8 +527,8 @@ uint8_t gc_execute_line(char *line)
// [G10 L20 Errors]: P must be 0 to nCoordSys(max 9). Axis words missing. // [G10 L20 Errors]: P must be 0 to nCoordSys(max 9). Axis words missing.
if (!axis_words) { FAIL(STATUS_GCODE_NO_AXIS_WORDS) }; // [No axis words] if (!axis_words) { FAIL(STATUS_GCODE_NO_AXIS_WORDS) }; // [No axis words]
if (bit_isfalse(value_words,((1<<WORD_P)|(1<<WORD_L)))) { FAIL(STATUS_GCODE_VALUE_WORD_MISSING); } // [P/L word missing] if (bit_isfalse(value_words,((1<<WORD_P)|(1<<WORD_L)))) { FAIL(STATUS_GCODE_VALUE_WORD_MISSING); } // [P/L word missing]
int_value = trunc(gc_block.values.p); // Convert p value to int. coord_select = trunc(gc_block.values.p); // Convert p value to int.
if (int_value > N_COORDINATE_SYSTEM) { FAIL(STATUS_GCODE_UNSUPPORTED_COORD_SYS); } // [Greater than N sys] if (coord_select > N_COORDINATE_SYSTEM) { FAIL(STATUS_GCODE_UNSUPPORTED_COORD_SYS); } // [Greater than N sys]
if (gc_block.values.l != 20) { if (gc_block.values.l != 20) {
if (gc_block.values.l == 2) { if (gc_block.values.l == 2) {
if (bit_istrue(value_words,bit(WORD_R))) { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); } // [G10 L2 R not supported] if (bit_istrue(value_words,bit(WORD_R))) { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); } // [G10 L2 R not supported]
@ -535,10 +536,12 @@ uint8_t gc_execute_line(char *line)
} }
bit_false(value_words,(bit(WORD_L)|bit(WORD_P))); bit_false(value_words,(bit(WORD_L)|bit(WORD_P)));
// Load EEPROM coordinate data and pre-calculate the new coordinate data. // Determine coordinate system to change and try to load from EEPROM.
if (int_value > 0) { int_value--; } // Adjust P1-P6 index to EEPROM coordinate data indexing. if (coord_select > 0) { coord_select--; } // Adjust P1-P6 index to EEPROM coordinate data indexing.
else { int_value = gc_block.modal.coord_select; } // Index P0 as the active coordinate system else { coord_select = gc_block.modal.coord_select; } // Index P0 as the active coordinate system
if (!settings_read_coord_data(int_value,parameter_data)) { FAIL(STATUS_SETTING_READ_FAIL); } // [EEPROM read fail] if (!settings_read_coord_data(coord_select,parameter_data)) { FAIL(STATUS_SETTING_READ_FAIL); } // [EEPROM read fail]
// Pre-calculate the coordinate data changes. NOTE: Uses parameter_data since coordinate_data may be in use by G54-59.
for (idx=0; idx<N_AXIS; idx++) { // Axes indices are consistent, so loop may be used. for (idx=0; idx<N_AXIS; idx++) { // Axes indices are consistent, so loop may be used.
// Update axes defined only in block. Always in machine coordinates. Can change non-active system. // Update axes defined only in block. Always in machine coordinates. Can change non-active system.
if (bit_istrue(axis_words,bit(idx)) ) { if (bit_istrue(axis_words,bit(idx)) ) {
@ -801,7 +804,7 @@ uint8_t gc_execute_line(char *line)
} }
} }
// [21. Program flow ]: No error check required. // [21. Program flow ]: No error checks required.
// [0. Non-specific error-checks]: Complete unused value words check, i.e. IJK used when in arc // [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. // radius mode, or axis words that aren't used in the block.
@ -832,7 +835,8 @@ uint8_t gc_execute_line(char *line)
if (gc_state.modal.spindle != SPINDLE_DISABLE) { spindle_run(gc_state.modal.spindle, gc_state.spindle_speed); } if (gc_state.modal.spindle != SPINDLE_DISABLE) { spindle_run(gc_state.modal.spindle, gc_state.spindle_speed); }
} }
// [5. Select tool ]: NOT SUPPORTED // [5. Select tool ]: NOT SUPPORTED. Only tracks tool value.
gc_state.tool = gc_block.values.t;
// [6. Change tool ]: NOT SUPPORTED // [6. Change tool ]: NOT SUPPORTED
@ -891,15 +895,9 @@ uint8_t gc_execute_line(char *line)
// [19. Go to predefined position, Set G10, or Set axis offsets ]: // [19. Go to predefined position, Set G10, or Set axis offsets ]:
switch(gc_block.non_modal_command) { switch(gc_block.non_modal_command) {
case NON_MODAL_SET_COORDINATE_DATA: case NON_MODAL_SET_COORDINATE_DATA:
settings_write_coord_data(coord_select,parameter_data);
// TODO: See if I can clean up this int_value.
int_value = trunc(gc_block.values.p); // Convert p value to int.
if (int_value > 0) { int_value--; } // Adjust P1-P6 index to EEPROM coordinate data indexing.
else { int_value = gc_state.modal.coord_select; } // Index P0 as the active coordinate system
settings_write_coord_data(int_value,parameter_data);
// Update system coordinate system if currently active. // Update system coordinate system if currently active.
if (gc_state.modal.coord_select == int_value) { memcpy(gc_state.coord_system,parameter_data,sizeof(parameter_data)); } if (gc_state.modal.coord_select == coord_select) { memcpy(gc_state.coord_system,parameter_data,sizeof(parameter_data)); }
break; break;
case NON_MODAL_GO_HOME_0: case NON_MODAL_GO_HOME_1: case NON_MODAL_GO_HOME_0: case NON_MODAL_GO_HOME_1:
// Move to intermediate position before going home. Obeys current coordinate system and offsets // Move to intermediate position before going home. Obeys current coordinate system and offsets
@ -964,6 +962,8 @@ uint8_t gc_execute_line(char *line)
#endif #endif
break; break;
case MOTION_MODE_PROBE: case MOTION_MODE_PROBE:
// 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.
#ifdef USE_LINE_NUMBERS #ifdef USE_LINE_NUMBERS
mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, gc_block.values.n); mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, gc_block.values.n);
#else #else
@ -992,7 +992,7 @@ uint8_t gc_execute_line(char *line)
else { gc_state.modal.program_flow = PROGRAM_FLOW_RUNNING; } else { gc_state.modal.program_flow = PROGRAM_FLOW_RUNNING; }
} }
// TBD: % to denote start of program. Sets auto cycle start? // TODO: % to denote start of program. Sets auto cycle start?
return(STATUS_OK); return(STATUS_OK);
} }

View File

@ -22,7 +22,6 @@
#ifndef gcode_h #ifndef gcode_h
#define gcode_h #define gcode_h
#include "system.h"
// Define modal group internal numbers for checking multiple command violations and tracking the // Define modal group internal numbers for checking multiple command violations and tracking the
// type of command that is called in the block. A modal group is a group of g-code commands that are // type of command that is called in the block. A modal group is a group of g-code commands that are
@ -128,7 +127,7 @@
// NOTE: When this struct is zeroed, the above defines set the defaults for the system. // NOTE: When this struct is zeroed, the above defines set the defaults for the system.
typedef struct { typedef struct {
uint8_t motion; // {G0,G1,G2,G3,G80} uint8_t motion; // {G0,G1,G2,G3,G38.2,G80}
uint8_t feed_rate; // {G93,G94} uint8_t feed_rate; // {G93,G94}
uint8_t units; // {G20,G21} uint8_t units; // {G20,G21}
uint8_t distance; // {G90,G91} uint8_t distance; // {G90,G91}
@ -149,7 +148,7 @@ typedef struct {
// float q; // G82 peck drilling // float q; // G82 peck drilling
float r; // Arc radius float r; // Arc radius
float s; // Spindle speed float s; // Spindle speed
// uint8_t t; // Tool selection uint8_t t; // Tool selection
float xyz[3]; // X,Y,Z Translational axes float xyz[3]; // X,Y,Z Translational axes
} gc_values_t; } gc_values_t;

View File

@ -28,8 +28,8 @@
#include "limits.h" #include "limits.h"
#include "report.h" #include "report.h"
// Homing axis search distance multiplier. Computed by this value times the axis max travel.
#define HOMING_AXIS_SEARCH_SCALAR 1.5 // Axis search distance multiplier. Must be > 1. #define HOMING_AXIS_SEARCH_SCALAR 1.5 // Must be > 1 to ensure limit switch will be engaged.
void limits_init() void limits_init()
@ -128,11 +128,17 @@ void limits_go_home(uint8_t cycle_mask)
uint8_t n_cycle = (2*N_HOMING_LOCATE_CYCLE+1); uint8_t n_cycle = (2*N_HOMING_LOCATE_CYCLE+1);
float target[N_AXIS]; float target[N_AXIS];
uint8_t limit_pin[N_AXIS], step_pin[N_AXIS];
float max_travel = 0.0;
for (idx=0; idx<N_AXIS; idx++) {
// Initialize limit and step pin masks
limit_pin[idx] = get_limit_pin_mask(idx);
step_pin[idx] = get_step_pin_mask(idx);
// Determine travel distance to the furthest homing switch based on user max travel settings. // Determine travel distance to the furthest homing switch based on user max travel settings.
// NOTE: settings.max_travel[] is stored as a negative value. // NOTE: settings.max_travel[] is stored as a negative value.
float max_travel = settings.max_travel[X_AXIS]; if (max_travel > settings.max_travel[idx]) { max_travel = settings.max_travel[idx]; }
if (max_travel > settings.max_travel[Y_AXIS]) { max_travel = settings.max_travel[Y_AXIS]; } }
if (max_travel > settings.max_travel[Z_AXIS]) { max_travel = settings.max_travel[Z_AXIS]; }
max_travel *= -HOMING_AXIS_SEARCH_SCALAR; // Ensure homing switches engaged by over-estimating max travel. max_travel *= -HOMING_AXIS_SEARCH_SCALAR; // Ensure homing switches engaged by over-estimating max travel.
plan_reset(); // Reset planner buffer to zero planner current position and to clear previous motions. plan_reset(); // Reset planner buffer to zero planner current position and to clear previous motions.
@ -142,9 +148,12 @@ void limits_go_home(uint8_t cycle_mask)
if (bit_isfalse(settings.flags,BITFLAG_INVERT_LIMIT_PINS)) { invert_pin = approach; } if (bit_isfalse(settings.flags,BITFLAG_INVERT_LIMIT_PINS)) { invert_pin = approach; }
else { invert_pin = !approach; } else { invert_pin = !approach; }
// Set target location and rate for active axes. // Initialize and declare variables needed for homing routine.
uint8_t n_active_axis = 0; uint8_t n_active_axis = 0;
uint8_t axislock = 0;
for (idx=0; idx<N_AXIS; idx++) { for (idx=0; idx<N_AXIS; idx++) {
// Set target location for active axes and setup computation for homing rate.
if (bit_istrue(cycle_mask,bit(idx))) { if (bit_istrue(cycle_mask,bit(idx))) {
n_active_axis++; n_active_axis++;
if (!approach) { target[idx] = -max_travel; } if (!approach) { target[idx] = -max_travel; }
@ -152,41 +161,35 @@ void limits_go_home(uint8_t cycle_mask)
} else { } else {
target[idx] = 0.0; target[idx] = 0.0;
} }
// Set target direction based on cycle mask
if (bit_istrue(settings.homing_dir_mask,bit(idx))) { target[idx] = -target[idx]; }
// Apply axislock to the step port pins active in this cycle.
if (bit_istrue(cycle_mask,bit(idx))) { axislock |= step_pin[idx]; }
} }
if (bit_istrue(settings.homing_dir_mask,(1<<X_DIRECTION_BIT))) { target[X_AXIS] = -target[X_AXIS]; }
if (bit_istrue(settings.homing_dir_mask,(1<<Y_DIRECTION_BIT))) { target[Y_AXIS] = -target[Y_AXIS]; }
if (bit_istrue(settings.homing_dir_mask,(1<<Z_DIRECTION_BIT))) { target[Z_AXIS] = -target[Z_AXIS]; }
homing_rate *= sqrt(n_active_axis); // [sqrt(N_AXIS)] Adjust so individual axes all move at homing rate. homing_rate *= sqrt(n_active_axis); // [sqrt(N_AXIS)] Adjust so individual axes all move at homing rate.
// Reset homing axis locks based on cycle mask.
uint8_t axislock = 0;
if (bit_istrue(cycle_mask,bit(X_AXIS))) { axislock |= (1<<X_STEP_BIT); }
if (bit_istrue(cycle_mask,bit(Y_AXIS))) { axislock |= (1<<Y_STEP_BIT); }
if (bit_istrue(cycle_mask,bit(Z_AXIS))) { axislock |= (1<<Z_STEP_BIT); }
sys.homing_axis_lock = axislock; sys.homing_axis_lock = axislock;
// Perform homing cycle. Planner buffer should be empty, as required to initiate the homing cycle. // Perform homing cycle. Planner buffer should be empty, as required to initiate the homing cycle.
uint8_t limit_state; uint8_t limit_state;
#ifdef USE_LINE_NUMBERS #ifdef USE_LINE_NUMBERS
plan_buffer_line(target, homing_rate, false, HOMING_CYCLE_LINE_NUMBER); // Bypass mc_line(). Directly plan homing motion. plan_buffer_line(target, homing_rate, false, HOMING_CYCLE_LINE_NUMBER); // Bypass mc_line(). Directly plan homing motion.
#else #else
plan_buffer_line(target, homing_rate, false); // Bypass mc_line(). Directly plan homing motion. plan_buffer_line(target, homing_rate, false); // Bypass mc_line(). Directly plan homing motion.
#endif #endif
st_prep_buffer(); // Prep and fill segment buffer from newly planned block. st_prep_buffer(); // Prep and fill segment buffer from newly planned block.
st_wake_up(); // Initiate motion st_wake_up(); // Initiate motion
do { do {
// Check limit state. Lock out cycle axes when they change. // Check limit state. Lock out cycle axes when they change.
limit_state = LIMIT_PIN; limit_state = LIMIT_PIN;
if (invert_pin) { limit_state ^= LIMIT_MASK; } if (invert_pin) { limit_state ^= LIMIT_MASK; }
if (axislock & (1<<X_STEP_BIT)) { for (idx=0; idx<N_AXIS; idx++) {
if (limit_state & (1<<X_LIMIT_BIT)) { axislock &= ~(1<<X_STEP_BIT); } if (axislock & step_pin[idx]) {
if (limit_state & limit_pin[idx]) { axislock &= ~(step_pin[idx]); }
} }
if (axislock & (1<<Y_STEP_BIT)) {
if (limit_state & (1<<Y_LIMIT_BIT)) { axislock &= ~(1<<Y_STEP_BIT); }
}
if (axislock & (1<<Z_STEP_BIT)) {
if (limit_state & (1<<Z_LIMIT_BIT)) { axislock &= ~(1<<Z_STEP_BIT); }
} }
sys.homing_axis_lock = axislock; sys.homing_axis_lock = axislock;
st_prep_buffer(); // Check and prep segment buffer. NOTE: Should take no longer than 200us. st_prep_buffer(); // Check and prep segment buffer. NOTE: Should take no longer than 200us.
@ -217,18 +220,27 @@ void limits_go_home(uint8_t cycle_mask)
// do not move them. // do not move them.
// NOTE: settings.max_travel[] is stored as a negative value. // NOTE: settings.max_travel[] is stored as a negative value.
if (cycle_mask & bit(idx)) { if (cycle_mask & bit(idx)) {
if ( settings.homing_dir_mask & get_direction_mask(idx) ) {
#ifdef HOMING_FORCE_SET_ORIGIN
sys.position[idx] = 0; // Set axis homed location as axis origin
target[idx] = settings.homing_pulloff;
if ( bit_isfalse(settings.homing_dir_mask,bit(idx)) ) { target[idx] = -target[idx]; }
#else
if ( bit_istrue(settings.homing_dir_mask,bit(idx)) ) {
target[idx] = settings.homing_pulloff+settings.max_travel[idx]; target[idx] = settings.homing_pulloff+settings.max_travel[idx];
sys.position[idx] = lround(settings.max_travel[idx]*settings.steps_per_mm[idx]); sys.position[idx] = lround(settings.max_travel[idx]*settings.steps_per_mm[idx]);
} else { } else {
target[idx] = -settings.homing_pulloff; target[idx] = -settings.homing_pulloff;
sys.position[idx] = 0; sys.position[idx] = 0;
} }
#endif
} else { // Non-active cycle axis. Set target to not move during pull-off. } else { // Non-active cycle axis. Set target to not move during pull-off.
target[idx] = (float)sys.position[idx]/settings.steps_per_mm[idx]; target[idx] = (float)sys.position[idx]/settings.steps_per_mm[idx];
} }
} }
plan_sync_position(); // Sync planner position to current machine position for pull-off move. plan_sync_position(); // Sync planner position to current machine position for pull-off move.
#ifdef USE_LINE_NUMBERS #ifdef USE_LINE_NUMBERS
plan_buffer_line(target, settings.homing_seek_rate, false, HOMING_CYCLE_LINE_NUMBER); // Bypass mc_line(). Directly plan motion. plan_buffer_line(target, settings.homing_seek_rate, false, HOMING_CYCLE_LINE_NUMBER); // Bypass mc_line(). Directly plan motion.
#else #else
@ -252,9 +264,23 @@ void limits_go_home(uint8_t cycle_mask)
void limits_soft_check(float *target) void limits_soft_check(float *target)
{ {
uint8_t idx; uint8_t idx;
uint8_t soft_limit_error = false;
for (idx=0; idx<N_AXIS; idx++) { for (idx=0; idx<N_AXIS; idx++) {
if (target[idx] > 0 || target[idx] < settings.max_travel[idx]) { // NOTE: max_travel is stored as negative
#ifdef HOMING_FORCE_SET_ORIGIN
// When homing forced set origin is enabled, soft limits checks need to account for directionality.
// NOTE: max_travel is stored as negative
if (bit_istrue(settings.homing_dir_mask,bit(idx))) {
if (target[idx] < 0 || target[idx] > -settings.max_travel[idx]) { soft_limit_error = true; }
} else {
if (target[idx] > 0 || target[idx] < settings.max_travel[idx]) { soft_limit_error = true; }
}
#else
// NOTE: max_travel is stored as negative
if (target[idx] > 0 || target[idx] < settings.max_travel[idx]) { soft_limit_error = true; }
#endif
if (soft_limit_error) {
// Force feed hold if cycle is active. All buffered blocks are guaranteed to be within // Force feed hold if cycle is active. All buffered blocks are guaranteed to be within
// workspace volume so just come to a controlled stop so position is not lost. When complete // workspace volume so just come to a controlled stop so position is not lost. When complete
// enter alarm mode. // enter alarm mode.
@ -270,7 +296,6 @@ void limits_soft_check(float *target)
bit_true_atomic(sys.execute, (EXEC_ALARM | EXEC_CRIT_EVENT)); // Indicate soft limit critical event bit_true_atomic(sys.execute, (EXEC_ALARM | EXEC_CRIT_EVENT)); // Indicate soft limit critical event
protocol_execute_runtime(); // Execute to enter critical event loop and system abort protocol_execute_runtime(); // Execute to enter critical event loop and system abort
return; return;
} }
} }
} }

View File

@ -142,16 +142,18 @@ void mc_arc(float *position, float *target, float *offset, float radius, float f
For arc generation, the center of the circle is the axis of rotation and the radius vector is For arc generation, the center of the circle is the axis of rotation and the radius vector is
defined from the circle center to the initial position. Each line segment is formed by successive defined from the circle center to the initial position. Each line segment is formed by successive
vector rotations. Single precision values can accumulate error greater than tool precision in some vector rotations. Single precision values can accumulate error greater than tool precision in rare
cases. So, exact arc path correction is implemented. This approach avoids the problem of too many very cases. So, exact arc path correction is implemented. This approach avoids the problem of too many very
expensive trig operations [sin(),cos(),tan()] which can take 100-200 usec each to compute. expensive trig operations [sin(),cos(),tan()] which can take 100-200 usec each to compute.
Small angle approximation may be used to reduce computation overhead further. A third-order approximation Small angle approximation may be used to reduce computation overhead further. A third-order approximation
(second order sin() has too much error) holds for nearly all CNC applications, except for possibly very (second order sin() has too much error) holds for most, if not, all CNC applications. Note that this
small radii (~0.5mm). In other words, theta_per_segment would need to be greater than 0.25 rad(14 deg) approximation will begin to accumulate a numerical drift error when theta_per_segment is greater than
and N_ARC_CORRECTION would need to be large to cause an appreciable drift error (>5% of radius, for very ~0.25 rad(14 deg) AND the approximation is successively used without correction several dozen times. This
small radii, 5% of 0.5mm is very, very small). N_ARC_CORRECTION~=20 should be more than small enough to scenario is extremely unlikely, since segment lengths and theta_per_segment are automatically generated
correct for numerical drift error. Also decreasing the tolerance will improve the approximation too. and scaled by the arc tolerance setting. Only a very large arc tolerance setting, unrealistic for CNC
applications, would cause this numerical drift error. However, it is best to set N_ARC_CORRECTION from a
low of ~4 to a high of ~20 or so to avoid trig operations while keeping arc generation accurate.
This approximation also allows mc_arc to immediately insert a line segment into the planner This approximation also allows mc_arc to immediately insert a line segment into the planner
without the initial overhead of computing cos() or sin(). By the time the arc needs to be applied without the initial overhead of computing cos() or sin(). By the time the arc needs to be applied
@ -274,57 +276,59 @@ void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate, in
void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate) void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate)
#endif #endif
{ {
if (sys.state != STATE_CYCLE) protocol_auto_cycle_start(); protocol_buffer_synchronize(); // Finish all queued commands and empty planner buffer.
protocol_buffer_synchronize(); // Finish all queued commands
if (sys.abort) { return; } // Return if system reset has been issued. if (sys.abort) { return; } // Return if system reset has been issued.
// Perform probing cycle. Planner buffer should be empty at this point. // Setup and queue probing motion. Auto cycle-start should not start the cycle.
#ifdef USE_LINE_NUMBERS #ifdef USE_LINE_NUMBERS
mc_line(target, feed_rate, invert_feed_rate, line_number); mc_line(target, feed_rate, invert_feed_rate, line_number);
#else #else
mc_line(target, feed_rate, invert_feed_rate); mc_line(target, feed_rate, invert_feed_rate);
#endif #endif
// Activate the probing monitor in the stepper module.
// NOTE: Parser error-checking ensures the probe isn't already closed/triggered. // NOTE: Parser error-checking ensures the probe isn't already closed/triggered.
sys.probe_state = PROBE_ACTIVE; sys.probe_state = PROBE_ACTIVE;
// Perform probing cycle. Wait here until probe is triggered or motion completes.
bit_true_atomic(sys.execute, EXEC_CYCLE_START); bit_true_atomic(sys.execute, EXEC_CYCLE_START);
do { do {
protocol_execute_runtime(); protocol_execute_runtime();
if (sys.abort) { return; } // Check for system abort if (sys.abort) { return; } // Check for system abort
} while ((sys.state != STATE_IDLE) && (sys.state != STATE_QUEUED)); } while ((sys.state != STATE_IDLE) && (sys.state != STATE_QUEUED));
// If motion completes without probe triggering, error out.
if (sys.probe_state == PROBE_ACTIVE) { bit_true_atomic(sys.execute, EXEC_CRIT_EVENT); } if (sys.probe_state == PROBE_ACTIVE) { bit_true_atomic(sys.execute, EXEC_CRIT_EVENT); }
protocol_execute_runtime(); // Check and execute run-time commands protocol_execute_runtime(); // Check and execute run-time commands
if (sys.abort) { return; } // Check for system abort if (sys.abort) { return; } // Check for system abort
//Prep the new target based on the position that the probe triggered // Reset the stepper and planner buffers to remove the remainder of the probe motion.
uint8_t i; st_reset(); // Reest step segment buffer.
for(i=0; i<N_AXIS; ++i){ plan_reset(); // Reset planner buffer. Zero planner positions. Ensure probing motion is cleared.
target[i] = (float)sys.probe_position[i]/settings.steps_per_mm[i]; plan_sync_position(); // Sync planner position to current machine position.
// Probing motion is complete, but we'll pull-off triggered probe to the trigger location since
// we had to decelerate a little beyond it to stop the machine in a controlled manner.
uint8_t idx;
for(idx=0; idx<N_AXIS; idx++){
// NOTE: The target[] variable updated here will be sent back and synced with the g-code parser.
target[idx] = (float)sys.probe_position[idx]/settings.steps_per_mm[idx];
} }
protocol_execute_runtime();
st_reset(); // Immediately force kill steppers and reset step segment buffer.
plan_reset(); // Reset planner buffer. Zero planner positions. Ensure homing motion is cleared.
plan_sync_position(); // Sync planner position to current machine position for pull-off move.
#ifdef USE_LINE_NUMBERS #ifdef USE_LINE_NUMBERS
mc_line(target, feed_rate, invert_feed_rate, line_number); // Bypass mc_line(). Directly plan homing motion. mc_line(target, feed_rate, invert_feed_rate, line_number);
#else #else
mc_line(target, feed_rate, invert_feed_rate); // Bypass mc_line(). Directly plan homing motion. mc_line(target, feed_rate, invert_feed_rate);
#endif #endif
// Execute pull-off motion and wait until it completes.
bit_true_atomic(sys.execute, EXEC_CYCLE_START); bit_true_atomic(sys.execute, EXEC_CYCLE_START);
protocol_buffer_synchronize(); // Complete pull-off motion. protocol_buffer_synchronize();
if (sys.abort) { return; } // Did not complete. Alarm state set by mc_alarm. if (sys.abort) { return; } // Return if system reset has been issued.
// Gcode parser position was circumvented by the this routine, so sync position now. #ifdef MESSAGE_PROBE_COORDINATES
gc_sync_position(); // All done! Output the probe position as message.
// Output the probe position as message.
report_probe_parameters(); report_probe_parameters();
#endif
} }

View File

@ -20,6 +20,7 @@
*/ */
#include "system.h" #include "system.h"
#include "print.h"
#define MAX_INT_DIGITS 8 // Maximum number of digits in int32 (and float) #define MAX_INT_DIGITS 8 // Maximum number of digits in int32 (and float)
@ -139,21 +140,5 @@ void delay_us(uint32_t us)
} }
// Returns direction mask according to Grbl internal axis indexing. // Simple hypotenuse computation function.
uint8_t get_direction_mask(uint8_t axis_idx) float hypot_f(float x, float y) { return(sqrt(x*x + y*y)); }
{
uint8_t axis_mask = 0;
switch( axis_idx ) {
case X_AXIS: axis_mask = (1<<X_DIRECTION_BIT); break;
case Y_AXIS: axis_mask = (1<<Y_DIRECTION_BIT); break;
case Z_AXIS: axis_mask = (1<<Z_DIRECTION_BIT); break;
}
return(axis_mask);
}
float hypot_f(float x, float y)
{
return(sqrt(x*x + y*y));
}

View File

@ -63,8 +63,7 @@ void delay_ms(uint16_t ms);
// Delays variable-defined microseconds. Compiler compatibility fix for _delay_us(). // Delays variable-defined microseconds. Compiler compatibility fix for _delay_us().
void delay_us(uint32_t us); void delay_us(uint32_t us);
uint8_t get_direction_mask(uint8_t i); // Computes hypotenuse, avoiding avr-gcc's bloated version and the extra error checking.
float hypot_f(float x, float y); float hypot_f(float x, float y);
#endif #endif

View File

@ -295,7 +295,7 @@ void plan_buffer_line(float *target, float feed_rate, uint8_t invert_feed_rate)
unit_vec[idx] = delta_mm; // Store unit vector numerator. Denominator computed later. unit_vec[idx] = delta_mm; // Store unit vector numerator. Denominator computed later.
// Set direction bits. Bit enabled always means direction is negative. // Set direction bits. Bit enabled always means direction is negative.
if (delta_mm < 0 ) { block->direction_bits |= get_direction_mask(idx); } if (delta_mm < 0 ) { block->direction_bits |= get_direction_pin_mask(idx); }
// Incrementally compute total move distance by Euclidean norm. First add square of each term. // Incrementally compute total move distance by Euclidean norm. First add square of each term.
block->millimeters += delta_mm*delta_mm; block->millimeters += delta_mm*delta_mm;
@ -406,6 +406,14 @@ void plan_sync_position()
} }
// Returns the number of active blocks are in the planner buffer.
uint8_t plan_get_block_buffer_count()
{
if (block_buffer_head >= block_buffer_tail) { return(block_buffer_head-block_buffer_tail); }
return(BLOCK_BUFFER_SIZE - (block_buffer_tail-block_buffer_head));
}
// Re-initialize buffer plan with a partially completed block, assumed to exist at the buffer tail. // Re-initialize buffer plan with a partially completed block, assumed to exist at the buffer tail.
// Called after a steppers have come to a complete stop for a feed hold and the cycle is stopped. // Called after a steppers have come to a complete stop for a feed hold and the cycle is stopped.
void plan_cycle_reinitialize() void plan_cycle_reinitialize()

View File

@ -22,7 +22,6 @@
#ifndef planner_h #ifndef planner_h
#define planner_h #define planner_h
#include "system.h"
// The number of linear motions that can be in the plan at any give time // The number of linear motions that can be in the plan at any give time
#ifndef BLOCK_BUFFER_SIZE #ifndef BLOCK_BUFFER_SIZE
@ -89,6 +88,9 @@ void plan_sync_position();
// Reinitialize plan with a partially completed block // Reinitialize plan with a partially completed block
void plan_cycle_reinitialize(); void plan_cycle_reinitialize();
// Returns the number of active blocks are in the planner buffer.
uint8_t plan_get_block_buffer_count();
// Returns the status of the block ring buffer. True, if buffer is full. // Returns the status of the block ring buffer. True, if buffer is full.
uint8_t plan_check_full_buffer(); uint8_t plan_check_full_buffer();

21
print.c
View File

@ -19,9 +19,6 @@
along with Grbl. If not, see <http://www.gnu.org/licenses/>. along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* This code was initially inspired by the wiring_serial module by David A. Mellis which
used to be a part of the Arduino project. */
#include "system.h" #include "system.h"
#include "serial.h" #include "serial.h"
#include "settings.h" #include "settings.h"
@ -33,6 +30,7 @@ void printString(const char *s)
serial_write(*s++); serial_write(*s++);
} }
// Print a string stored in PGM-memory // Print a string stored in PGM-memory
void printPgmString(const char *s) void printPgmString(const char *s)
{ {
@ -41,6 +39,7 @@ void printPgmString(const char *s)
serial_write(c); serial_write(c);
} }
// void printIntegerInBase(unsigned long n, unsigned long base) // void printIntegerInBase(unsigned long n, unsigned long base)
// { // {
// unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars. // unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
@ -62,6 +61,7 @@ void printPgmString(const char *s)
// 'A' + buf[i - 1] - 10); // 'A' + buf[i - 1] - 10);
// } // }
void print_uint8_base2(uint8_t n) void print_uint8_base2(uint8_t n)
{ {
unsigned char buf[8]; unsigned char buf[8];
@ -76,6 +76,7 @@ void print_uint8_base2(uint8_t n)
serial_write('0' + buf[i - 1]); serial_write('0' + buf[i - 1]);
} }
void print_uint8_base10(uint8_t n) void print_uint8_base10(uint8_t n)
{ {
if (n == 0) { if (n == 0) {
@ -95,6 +96,7 @@ void print_uint8_base10(uint8_t n)
serial_write(buf[i - 1]); serial_write(buf[i - 1]);
} }
void print_uint32_base10(unsigned long n) void print_uint32_base10(unsigned long n)
{ {
if (n == 0) { if (n == 0) {
@ -114,6 +116,7 @@ void print_uint32_base10(unsigned long n)
serial_write('0' + buf[i-1]); serial_write('0' + buf[i-1]);
} }
void printInteger(long n) void printInteger(long n)
{ {
if (n < 0) { if (n < 0) {
@ -124,6 +127,7 @@ void printInteger(long n)
} }
} }
// Convert float to string by immediately converting to a long integer, which contains // Convert float to string by immediately converting to a long integer, which contains
// more digits than a float. Number of decimal places, which are tracked by a counter, // more digits than a float. Number of decimal places, which are tracked by a counter,
// may be set by the user. The integer is then efficiently converted to a string. // may be set by the user. The integer is then efficiently converted to a string.
@ -190,3 +194,14 @@ void printFloat_RateValue(float n) {
} }
void printFloat_SettingValue(float n) { printFloat(n,N_DECIMAL_SETTINGVALUE); } void printFloat_SettingValue(float n) { printFloat(n,N_DECIMAL_SETTINGVALUE); }
// Debug tool to print free memory in bytes at the called point. Not used otherwise.
void printFreeMemory()
{
extern int __heap_start, *__brkval;
uint16_t free; // Up to 64k values.
free = (int) &free - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
printInteger((int32_t)free);
printString(" ");
}

View File

@ -25,6 +25,7 @@
#ifndef print_h #ifndef print_h
#define print_h #define print_h
void printString(const char *s); void printString(const char *s);
void printPgmString(const char *s); void printPgmString(const char *s);
@ -49,4 +50,7 @@ void printFloat_RateValue(float n);
void printFloat_SettingValue(float n); void printFloat_SettingValue(float n);
// Debug tool to print free memory in bytes at the called point. Not used otherwise.
void printFreeMemory();
#endif #endif

16
probe.c
View File

@ -19,22 +19,30 @@
*/ */
#include "system.h" #include "system.h"
#include "settings.h"
#include "probe.h" #include "probe.h"
// Inverts the probe pin state depending on user settings.
uint8_t probe_invert_mask;
// Probe pin initialization routine. // Probe pin initialization routine.
void probe_init() void probe_init()
{ {
PROBE_DDR &= ~(PROBE_MASK); // Configure as input pins PROBE_DDR &= ~(PROBE_MASK); // Configure as input pins
if (bit_istrue(settings.flags,BITFLAG_INVERT_PROBE_PIN)) {
PROBE_PORT &= ~(PROBE_MASK); // Normal low operation. Requires external pull-down.
probe_invert_mask = 0;
} else {
PROBE_PORT |= PROBE_MASK; // Enable internal pull-up resistors. Normal high operation. PROBE_PORT |= PROBE_MASK; // Enable internal pull-up resistors. Normal high operation.
probe_invert_mask = PROBE_MASK;
}
} }
// Returns the probe pin state. Triggered = true. Called by gcode parser and probe state monitor. // Returns the probe pin state. Triggered = true. Called by gcode parser and probe state monitor.
uint8_t probe_get_state() uint8_t probe_get_state() { return((PROBE_PIN & PROBE_MASK) ^ probe_invert_mask); }
{
return(!(PROBE_PIN & PROBE_MASK));
}
// Monitors probe pin state and records the system position when detected. Called by the // Monitors probe pin state and records the system position when detected. Called by the
// stepper ISR per ISR tick. // stepper ISR per ISR tick.

View File

@ -136,7 +136,7 @@ void protocol_main_loop()
// everything until the next '%' sign. This will help fix resuming issues with certain // everything until the next '%' sign. This will help fix resuming issues with certain
// functions that empty the planner buffer to execute its task on-time. // functions that empty the planner buffer to execute its task on-time.
} else if (char_counter >= LINE_BUFFER_SIZE-1) { } else if (char_counter >= (LINE_BUFFER_SIZE-1)) {
// Detect line buffer overflow. Report error and reset line buffer. // Detect line buffer overflow. Report error and reset line buffer.
report_status_message(STATUS_OVERFLOW); report_status_message(STATUS_OVERFLOW);
iscomment = false; iscomment = false;

View File

@ -28,7 +28,7 @@
// memory space we can invest into here or we re-write the g-code parser not to have this // memory space we can invest into here or we re-write the g-code parser not to have this
// buffer. // buffer.
#ifndef LINE_BUFFER_SIZE #ifndef LINE_BUFFER_SIZE
#define LINE_BUFFER_SIZE 70 #define LINE_BUFFER_SIZE 80
#endif #endif
// Starts Grbl main loop. It handles all incoming characters from the serial port and executes // Starts Grbl main loop. It handles all incoming characters from the serial port and executes

105
report.c
View File

@ -35,6 +35,7 @@
#include "planner.h" #include "planner.h"
#include "spindle_control.h" #include "spindle_control.h"
#include "stepper.h" #include "stepper.h"
#include "serial.h"
// Handles the primary confirmation protocol response for streaming interfaces and human-feedback. // Handles the primary confirmation protocol response for streaming interfaces and human-feedback.
@ -155,43 +156,67 @@ void report_grbl_help() {
"ctrl-x (reset Grbl)\r\n")); "ctrl-x (reset Grbl)\r\n"));
} }
// Grbl global settings print out. // Grbl global settings print out.
// NOTE: The numbering scheme here must correlate to storing in settings.c // NOTE: The numbering scheme here must correlate to storing in settings.c
void report_grbl_settings() { void report_grbl_settings() {
printPgmString(PSTR("$0=")); printFloat_SettingValue(settings.steps_per_mm[X_AXIS]); // Print Grbl settings.
printPgmString(PSTR(" (x, step/mm)\r\n$1=")); printFloat_SettingValue(settings.steps_per_mm[Y_AXIS]); printPgmString(PSTR("$0=")); print_uint8_base10(settings.pulse_microseconds);
printPgmString(PSTR(" (y, step/mm)\r\n$2=")); printFloat_SettingValue(settings.steps_per_mm[Z_AXIS]); printPgmString(PSTR(" (step pulse, usec)\r\n$1=")); print_uint8_base10(settings.stepper_idle_lock_time);
printPgmString(PSTR(" (z, step/mm)\r\n$3=")); printFloat_SettingValue(settings.max_rate[X_AXIS]); printPgmString(PSTR(" (step idle delay, msec)\r\n$2=")); print_uint8_base10(settings.step_invert_mask);
printPgmString(PSTR(" (x max rate, mm/min)\r\n$4=")); printFloat_SettingValue(settings.max_rate[Y_AXIS]);
printPgmString(PSTR(" (y max rate, mm/min)\r\n$5=")); printFloat_SettingValue(settings.max_rate[Z_AXIS]);
printPgmString(PSTR(" (z max rate, mm/min)\r\n$6=")); printFloat_SettingValue(settings.acceleration[X_AXIS]/(60*60)); // Convert from mm/min^2 for human readability
printPgmString(PSTR(" (x accel, mm/sec^2)\r\n$7=")); printFloat_SettingValue(settings.acceleration[Y_AXIS]/(60*60)); // Convert from mm/min^2 for human readability
printPgmString(PSTR(" (y accel, mm/sec^2)\r\n$8=")); printFloat_SettingValue(settings.acceleration[Z_AXIS]/(60*60)); // Convert from mm/min^2 for human readability
printPgmString(PSTR(" (z accel, mm/sec^2)\r\n$9=")); printFloat_SettingValue(-settings.max_travel[X_AXIS]); // Grbl internally store this as negative.
printPgmString(PSTR(" (x max travel, mm)\r\n$10=")); printFloat_SettingValue(-settings.max_travel[Y_AXIS]); // Grbl internally store this as negative.
printPgmString(PSTR(" (y max travel, mm)\r\n$11=")); printFloat_SettingValue(-settings.max_travel[Z_AXIS]); // Grbl internally store this as negative.
printPgmString(PSTR(" (z max travel, mm)\r\n$12=")); print_uint8_base10(settings.pulse_microseconds);
printPgmString(PSTR(" (step pulse, usec)\r\n$13=")); print_uint8_base10(settings.step_invert_mask);
printPgmString(PSTR(" (step port invert mask:")); print_uint8_base2(settings.step_invert_mask); printPgmString(PSTR(" (step port invert mask:")); print_uint8_base2(settings.step_invert_mask);
printPgmString(PSTR(")\r\n$14=")); print_uint8_base10(settings.dir_invert_mask); printPgmString(PSTR(")\r\n$3=")); print_uint8_base10(settings.dir_invert_mask);
printPgmString(PSTR(" (dir port invert mask:")); print_uint8_base2(settings.dir_invert_mask); printPgmString(PSTR(" (dir port invert mask:")); print_uint8_base2(settings.dir_invert_mask);
printPgmString(PSTR(")\r\n$15=")); print_uint8_base10(settings.stepper_idle_lock_time); printPgmString(PSTR(")\r\n$4=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE));
printPgmString(PSTR(" (step idle delay, msec)\r\n$16=")); printFloat_SettingValue(settings.junction_deviation); printPgmString(PSTR(" (step enable invert, bool)\r\n$5=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_INVERT_LIMIT_PINS));
printPgmString(PSTR(" (junction deviation, mm)\r\n$17=")); printFloat_SettingValue(settings.arc_tolerance); printPgmString(PSTR(" (limit pins invert, bool)\r\n$6=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_INVERT_PROBE_PIN));
printPgmString(PSTR(" (arc tolerance, mm)\r\n$19=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)); printPgmString(PSTR(" (probe pin invert, bool)\r\n$10=")); print_uint8_base10(settings.status_report_mask);
printPgmString(PSTR(" (report inches, bool)\r\n$20=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_AUTO_START)); printPgmString(PSTR(" (status report mask:")); print_uint8_base2(settings.status_report_mask);
printPgmString(PSTR(" (auto start, bool)\r\n$21=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)); printPgmString(PSTR(")\r\n$11=")); printFloat_SettingValue(settings.junction_deviation);
printPgmString(PSTR(" (invert step enable, bool)\r\n$22=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_INVERT_LIMIT_PINS)); printPgmString(PSTR(" (junction deviation, mm)\r\n$12=")); printFloat_SettingValue(settings.arc_tolerance);
printPgmString(PSTR(" (invert limit pins, bool)\r\n$23=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_SOFT_LIMIT_ENABLE)); printPgmString(PSTR(" (arc tolerance, mm)\r\n$13=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_REPORT_INCHES));
printPgmString(PSTR(" (soft limits, bool)\r\n$24=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)); printPgmString(PSTR(" (report inches, bool)\r\n$14=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_AUTO_START));
printPgmString(PSTR(" (hard limits, bool)\r\n$25=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)); printPgmString(PSTR(" (auto start, bool)\r\n$20=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_SOFT_LIMIT_ENABLE));
printPgmString(PSTR(" (homing cycle, bool)\r\n$26=")); print_uint8_base10(settings.homing_dir_mask); 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:")); print_uint8_base2(settings.homing_dir_mask); printPgmString(PSTR(" (homing dir invert mask:")); print_uint8_base2(settings.homing_dir_mask);
printPgmString(PSTR(")\r\n$27=")); printFloat_SettingValue(settings.homing_feed_rate); printPgmString(PSTR(")\r\n$24=")); printFloat_SettingValue(settings.homing_feed_rate);
printPgmString(PSTR(" (homing feed, mm/min)\r\n$28=")); printFloat_SettingValue(settings.homing_seek_rate); printPgmString(PSTR(" (homing feed, mm/min)\r\n$25=")); printFloat_SettingValue(settings.homing_seek_rate);
printPgmString(PSTR(" (homing seek, mm/min)\r\n$29=")); print_uint8_base10(settings.homing_debounce_delay); printPgmString(PSTR(" (homing seek, mm/min)\r\n$26=")); print_uint8_base10(settings.homing_debounce_delay);
printPgmString(PSTR(" (homing debounce, msec)\r\n$30=")); printFloat_SettingValue(settings.homing_pulloff); printPgmString(PSTR(" (homing debounce, msec)\r\n$27=")); printFloat_SettingValue(settings.homing_pulloff);
printPgmString(PSTR(" (homing pull-off, mm)\r\n")); printPgmString(PSTR(" (homing pull-off, mm)\r\n"));
// Print axis settings
uint8_t idx, set_idx;
uint8_t val = AXIS_SETTINGS_START_VAL;
for (set_idx=0; set_idx<AXIS_N_SETTINGS; set_idx++) {
for (idx=0; idx<N_AXIS; idx++) {
printPgmString(PSTR("$"));
print_uint8_base10(val+idx);
printPgmString(PSTR("="));
switch (set_idx) {
case 0: printFloat_SettingValue(settings.steps_per_mm[idx]); break;
case 1: printFloat_SettingValue(settings.max_rate[idx]); break;
case 2: printFloat_SettingValue(settings.acceleration[idx]/(60*60)); break;
case 3: printFloat_SettingValue(-settings.max_travel[idx]); break;
}
printPgmString(PSTR(" ("));
switch (idx) {
case X_AXIS: printPgmString(PSTR("x")); break;
case Y_AXIS: printPgmString(PSTR("y")); break;
case Z_AXIS: printPgmString(PSTR("z")); break;
}
switch (set_idx) {
case 0: printPgmString(PSTR(", step/mm")); break;
case 1: printPgmString(PSTR(" max rate, mm/min")); break;
case 2: printPgmString(PSTR(" accel, mm/sec^2")); break;
case 3: printPgmString(PSTR(" max travel, mm")); break;
}
printPgmString(PSTR(")\r\n"));
}
val += AXIS_SETTINGS_INCREMENT;
}
} }
@ -354,21 +379,37 @@ void report_realtime_status()
} }
// Report machine position // Report machine position
if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_MACHINE_POSITION)) {
printPgmString(PSTR(",MPos:")); printPgmString(PSTR(",MPos:"));
for (i=0; i< N_AXIS; i++) { for (i=0; i< N_AXIS; i++) {
print_position[i] = current_position[i]/settings.steps_per_mm[i]; print_position[i] = current_position[i]/settings.steps_per_mm[i];
printFloat_CoordValue(print_position[i]); printFloat_CoordValue(print_position[i]);
printPgmString(PSTR(",")); if (i < (N_AXIS-1)) { printPgmString(PSTR(",")); }
}
} }
// Report work position // Report work position
printPgmString(PSTR("WPos:")); if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_WORK_POSITION)) {
printPgmString(PSTR(",WPos:"));
for (i=0; i< N_AXIS; i++) { for (i=0; i< N_AXIS; i++) {
print_position[i] -= gc_state.coord_system[i]+gc_state.coord_offset[i]; print_position[i] -= gc_state.coord_system[i]+gc_state.coord_offset[i];
if (i == TOOL_LENGTH_OFFSET_AXIS) { print_position[i] -= gc_state.tool_length_offset; } if (i == TOOL_LENGTH_OFFSET_AXIS) { print_position[i] -= gc_state.tool_length_offset; }
printFloat_CoordValue(print_position[i]); printFloat_CoordValue(print_position[i]);
if (i < (N_AXIS-1)) { printPgmString(PSTR(",")); } if (i < (N_AXIS-1)) { printPgmString(PSTR(",")); }
} }
}
// Returns the number of active blocks are in the planner buffer.
if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_PLANNER_BUFFER)) {
printPgmString(PSTR(",Buf:"));
print_uint8_base10(plan_get_block_buffer_count());
}
// Report serial read buffer status
if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_SERIAL_RX)) {
printPgmString(PSTR(",RX:"));
print_uint8_base10(serial_get_rx_buffer_count());
}
#ifdef USE_LINE_NUMBERS #ifdef USE_LINE_NUMBERS
// Report current line number // Report current line number

View File

@ -1,5 +0,0 @@
socat -d -d READLINE /dev/tty.usbmodem26221,nonblock=1,clocal=1
socat -d -d READLINE /dev/tty.usbmodem621,nonblock=1,clocal=1
socat -d -d READLINE /dev/tty.usbserial-A700e0GO,clocal=1,nonblock=1,cread=1,cs8,ixon=1,ixoff=1
socat -d -d READLINE /dev/tty.usbserial-A9007QcR,clocal=1,nonblock=1,cread=1,cs8,ixon=1,ixoff=1
#socat -d -d READLINE /dev/tty.FireFly-A964-SPP-1,clocal=1,nonblock=1,cread=1,cs8,ixon=1,ixoff=1

View File

@ -1,2 +0,0 @@
socat -d -d tcp4-listen:5001,fork /dev/tty.usbserial-A4001o6L,clocal=1,nonblock=1,cread=1,cs8,ixon=1,ixoff=1

View File

@ -1,2 +0,0 @@
#!/usr/bin/ruby
require 'script/stream'

View File

@ -1,50 +0,0 @@
require 'rubygems'
require 'optparse'
require 'serialport'
options_parser = OptionParser.new do |opts|
opts.banner = "Usage: stream [options] gcode-file"
opts.on('-v', '--verbose', 'Output more information') do
$verbose = true
end
opts.on('-p', '--prebuffer', 'Prebuffer commands') do
$prebuffer = true
end
opts.on('-h', '--help', 'Display this screen') do
puts opts
exit
end
end
options_parser.parse!
if ARGV.empty?
puts options_parser
exit
end
# SerialPort.open('/dev/tty.FireFly-A964-SPP-1', 115200) do |sp|
SerialPort.open('/dev/tty.usbserial-A700e0GO', 9600) do |sp|
sp.write("\r\n\r\n");
sleep 1
ARGV.each do |file|
puts "Processing file #{file}"
prebuffer = $prebuffer ? 20 : 0
File.readlines(file).each do |line|
next if line.strip == ''
puts line.strip
sp.write("#{line.strip}\r\n");
if prebuffer == 0
begin
result = sp.gets.strip
puts "Grbl >> #{result}" #unless result == 'ok'
end while !(result =~ /^ok|^error/)
else
prebuffer -= 1
end
end
end
puts "Done."
sleep 500
end

View File

@ -1,78 +0,0 @@
require 'pp'
def estimate_acceleration_distance(initial_rate, target_rate, acceleration)
(target_rate*target_rate-initial_rate*initial_rate)/(2*acceleration)
end
def intersection_distance(initial_rate, final_rate, acceleration, distance)
(2*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/(4*acceleration)
end
ACCELERATION_TICKS_PER_SECOND = 20
def trapezoid_params(step_event_count, nominal_rate, rate_delta, entry_factor, exit_factor)
initial_rate = (nominal_rate * entry_factor).round
final_rate = (nominal_rate * exit_factor).round
acceleration_per_minute = rate_delta*ACCELERATION_TICKS_PER_SECOND*60
accelerate_steps =
estimate_acceleration_distance(initial_rate, nominal_rate, acceleration_per_minute).round;
decelerate_steps =
estimate_acceleration_distance(nominal_rate, final_rate, -acceleration_per_minute).round;
# Calculate the size of Plateau of Nominal Rate.
plateau_steps = step_event_count-accelerate_steps-decelerate_steps;
# Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will
# have to use intersection_distance() to calculate when to abort acceleration and start braking
# in order to reach the final_rate exactly at the end of this block.
if (plateau_steps < 0)
accelerate_steps =
intersection_distance(initial_rate, final_rate, acceleration_per_minute, step_event_count).round
plateau_steps = 0;
end
accelerate_until = accelerate_steps;
decelerate_after = accelerate_steps+plateau_steps;
{:step_event_count => step_event_count,
:initial_rate => initial_rate,
:final_rate => final_rate,
:nominal_rate => nominal_rate,
:rate_delta => rate_delta,
:accelerate_until => accelerate_until,
:decelerate_after => decelerate_after}
end
def simulate_trapezoid(params)
result = {}
rate = params[:initial_rate]
step_event = 0.0
max_rate = 0
while(step_event < params[:step_event_count]) do
step_events_in_frame = rate/60.0/ACCELERATION_TICKS_PER_SECOND
step_event += step_events_in_frame
max_rate = rate if rate > max_rate
if (step_event < params[:accelerate_until])
rate += params[:rate_delta]
elsif (step_event > params[:decelerate_after])
if rate > params[:final_rate]
rate -= params[:rate_delta]
else
return :underflow_at => step_event, :final_rate => rate, :max_rate => max_rate
end
end
# puts "#{step_event} #{rate}"
end
{:final_rate => rate, :max_rate => max_rate}
end
(10..100).each do |rate|
(1..5).each do |steps|
params = trapezoid_params(steps*1000, rate*100, 10, 0.1, 0.1)
result = simulate_trapezoid(params)
# puts params.inspect
line = "#{steps*10} final: #{result[:final_rate]} == #{params[:final_rate]} peak: #{result[:max_rate]} == #{params[:nominal_rate]} d#{params[:nominal_rate]-result[:max_rate]} "
line << " (underflow at #{result[:underflow_at]})" if result[:underflow_at]
puts line
end
end

View File

@ -10,13 +10,37 @@ grbl will not send a response until the planner buffer clears space.
G02/03 arcs are special exceptions, where they inject short line G02/03 arcs are special exceptions, where they inject short line
segments directly into the planner. So there may not be a response segments directly into the planner. So there may not be a response
from grbl for the duration of the arc. from grbl for the duration of the arc.
---------------------
The MIT License (MIT)
Copyright (c) 2012 Sungeun K. Jeon
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------
""" """
import serial import serial
import time import time
# Open grbl serial port # Open grbl serial port
s = serial.Serial('/dev/tty.usbmodem1811',9600) s = serial.Serial('/dev/tty.usbmodem1811',115200)
# Open g-code file # Open g-code file
f = open('grbl.gcode','r'); f = open('grbl.gcode','r');

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
"""\ """\
Stream g-code to grbl controller Stream g-code to grbl controller
This script differs from the simple_stream.py script by This script differs from the simple_stream.py script by
@ -9,9 +10,36 @@ from the serial buffer and does not have to wait for a
response from the computer. This effectively adds another response from the computer. This effectively adds another
buffer layer to prevent buffer starvation. buffer layer to prevent buffer starvation.
TODO: - Add runtime command capabilities CHANGELOG:
- 20140714: Updated baud rate to 115200. Added a settings
write mode via simple streaming method. MIT-licensed.
Version: SKJ.20120110 TODO:
- Add runtime command capabilities
---------------------
The MIT License (MIT)
Copyright (c) 2012-2014 Sungeun K. Jeon
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------
""" """
import serial import serial
@ -31,6 +59,8 @@ parser.add_argument('device_file',
help='serial device path') help='serial device path')
parser.add_argument('-q','--quiet',action='store_true', default=False, parser.add_argument('-q','--quiet',action='store_true', default=False,
help='suppress output text') help='suppress output text')
parser.add_argument('-s','--settings',action='store_true', default=False,
help='settings write mode')
args = parser.parse_args() args = parser.parse_args()
# Periodic timer to query for status reports # Periodic timer to query for status reports
@ -41,10 +71,12 @@ args = parser.parse_args()
# t.start() # t.start()
# Initialize # Initialize
s = serial.Serial(args.device_file,9600) s = serial.Serial(args.device_file,115200)
f = args.gcode_file f = args.gcode_file
verbose = True verbose = True
if args.quiet : verbose = False if args.quiet : verbose = False
settings_mode = False
if args.settings : settings_mode = True
# Wake up grbl # Wake up grbl
print "Initializing grbl..." print "Initializing grbl..."
@ -55,8 +87,25 @@ time.sleep(2)
s.flushInput() s.flushInput()
# Stream g-code to grbl # Stream g-code to grbl
print "Streaming ", args.gcode_file.name, " to ", args.device_file
l_count = 0 l_count = 0
if settings_mode:
# Send settings file via simple call-response streaming method. Settings must be streamed
# in this manner since the EEPROM accessing cycles shut-off the serial interrupt.
print "SETTINGS MODE: Streaming", args.gcode_file.name, " to ", args.device_file
for line in f:
l_count += 1 # Iterate line counter
# l_block = re.sub('\s|\(.*?\)','',line).upper() # Strip comments/spaces/new line and capitalize
l_block = line.strip() # Strip all EOL characters for consistency
if verbose: print 'SND: ' + str(l_count) + ':' + l_block,
s.write(l_block + '\n') # Send g-code block to grbl
grbl_out = s.readline().strip() # Wait for grbl response with carriage return
if verbose: print 'REC:',grbl_out
else:
# Send g-code program via a more agressive streaming protocol that forces characters into
# Grbl's serial read buffer to ensure Grbl has immediate access to the next g-code command
# rather than wait for the call-response serial protocol to finish. This is done by careful
# counting of the number of characters sent by the streamer to Grbl and tracking Grbl's
# responses, such that we never overflow Grbl's serial read buffer.
g_count = 0 g_count = 0
c_line = [] c_line = []
# periodic() # Start status report periodic timer # periodic() # Start status report periodic timer
@ -74,9 +123,9 @@ for line in f:
grbl_out += out_temp; grbl_out += out_temp;
g_count += 1 # Iterate g-code counter g_count += 1 # Iterate g-code counter
grbl_out += str(g_count); # Add line finished indicator grbl_out += str(g_count); # Add line finished indicator
del c_line[0] del c_line[0] # Delete the block character count corresponding to the last 'ok'
if verbose: print "SND: " + str(l_count) + " : " + l_block, if verbose: print "SND: " + str(l_count) + " : " + l_block,
s.write(l_block + '\n') # Send block to grbl s.write(l_block + '\n') # Send g-code block to grbl
if verbose : print "BUF:",str(sum(c_line)),"REC:",grbl_out if verbose : print "BUF:",str(sum(c_line)),"REC:",grbl_out
# Wait for user input after streaming is completed # Wait for user input after streaming is completed

View File

@ -29,29 +29,39 @@
#include "protocol.h" #include "protocol.h"
uint8_t rx_buffer[RX_BUFFER_SIZE]; uint8_t serial_rx_buffer[RX_BUFFER_SIZE];
uint8_t rx_buffer_head = 0; uint8_t serial_rx_buffer_head = 0;
volatile uint8_t rx_buffer_tail = 0; volatile uint8_t serial_rx_buffer_tail = 0;
uint8_t tx_buffer[TX_BUFFER_SIZE]; uint8_t serial_tx_buffer[TX_BUFFER_SIZE];
uint8_t tx_buffer_head = 0; uint8_t serial_tx_buffer_head = 0;
volatile uint8_t tx_buffer_tail = 0; volatile uint8_t serial_tx_buffer_tail = 0;
#ifdef ENABLE_XONXOFF #ifdef ENABLE_XONXOFF
volatile uint8_t flow_ctrl = XON_SENT; // Flow control state variable volatile uint8_t flow_ctrl = XON_SENT; // Flow control state variable
// Returns the number of bytes in the RX buffer. This replaces a typical byte counter to prevent
// the interrupt and main programs from writing to the counter at the same time.
static uint8_t get_rx_buffer_count()
{
if (rx_buffer_head == rx_buffer_tail) { return(0); }
if (rx_buffer_head < rx_buffer_tail) { return(rx_buffer_tail-rx_buffer_head); }
return (RX_BUFFER_SIZE - (rx_buffer_head-rx_buffer_tail));
}
#endif #endif
// Returns the number of bytes used in the RX serial buffer.
uint8_t serial_get_rx_buffer_count()
{
uint8_t rtail = serial_rx_buffer_tail; // Copy to limit multiple calls to volatile
if (serial_rx_buffer_head >= rtail) { return(serial_rx_buffer_head-rtail); }
return (RX_BUFFER_SIZE - (rtail-serial_rx_buffer_head));
}
// Returns the number of bytes used in the TX serial buffer.
// NOTE: Not used except for debugging and ensuring no TX bottlenecks.
uint8_t serial_get_tx_buffer_count()
{
uint8_t ttail = serial_tx_buffer_tail; // Copy to limit multiple calls to volatile
if (serial_tx_buffer_head >= ttail) { return(serial_tx_buffer_head-ttail); }
return (TX_BUFFER_SIZE - (ttail-serial_tx_buffer_head));
}
void serial_init() void serial_init()
{ {
// Set baud rate // Set baud rate
@ -76,19 +86,21 @@ void serial_init()
} }
// Writes one byte to the TX serial buffer. Called by main program.
// TODO: Check if we can speed this up for writing strings, rather than single bytes.
void serial_write(uint8_t data) { void serial_write(uint8_t data) {
// Calculate next head // Calculate next head
uint8_t next_head = tx_buffer_head + 1; uint8_t next_head = serial_tx_buffer_head + 1;
if (next_head == TX_BUFFER_SIZE) { next_head = 0; } if (next_head == TX_BUFFER_SIZE) { next_head = 0; }
// Wait until there is space in the buffer // Wait until there is space in the buffer
while (next_head == tx_buffer_tail) { while (next_head == serial_tx_buffer_tail) {
if (sys.execute & EXEC_RESET) { return; } // Only check for abort to avoid an endless loop. if (sys.execute & EXEC_RESET) { return; } // Only check for abort to avoid an endless loop.
} }
// Store data and advance head // Store data and advance head
tx_buffer[tx_buffer_head] = data; serial_tx_buffer[serial_tx_buffer_head] = data;
tx_buffer_head = next_head; serial_tx_buffer_head = next_head;
// Enable Data Register Empty Interrupt to make sure tx-streaming is running // Enable Data Register Empty Interrupt to make sure tx-streaming is running
UCSR0B |= (1 << UDRIE0); UCSR0B |= (1 << UDRIE0);
@ -98,7 +110,7 @@ void serial_write(uint8_t data) {
// Data Register Empty Interrupt handler // Data Register Empty Interrupt handler
ISR(SERIAL_UDRE) ISR(SERIAL_UDRE)
{ {
uint8_t tail = tx_buffer_tail; // Temporary tx_buffer_tail (to optimize for volatile) uint8_t tail = serial_tx_buffer_tail; // Temporary serial_tx_buffer_tail (to optimize for volatile)
#ifdef ENABLE_XONXOFF #ifdef ENABLE_XONXOFF
if (flow_ctrl == SEND_XOFF) { if (flow_ctrl == SEND_XOFF) {
@ -111,34 +123,35 @@ ISR(SERIAL_UDRE)
#endif #endif
{ {
// Send a byte from the buffer // Send a byte from the buffer
UDR0 = tx_buffer[tail]; UDR0 = serial_tx_buffer[tail];
// Update tail position // Update tail position
tail++; tail++;
if (tail == TX_BUFFER_SIZE) { tail = 0; } if (tail == TX_BUFFER_SIZE) { tail = 0; }
tx_buffer_tail = tail; serial_tx_buffer_tail = tail;
} }
// Turn off Data Register Empty Interrupt to stop tx-streaming if this concludes the transfer // Turn off Data Register Empty Interrupt to stop tx-streaming if this concludes the transfer
if (tail == tx_buffer_head) { UCSR0B &= ~(1 << UDRIE0); } if (tail == serial_tx_buffer_head) { UCSR0B &= ~(1 << UDRIE0); }
} }
// Fetches the first byte in the serial read buffer. Called by main program.
uint8_t serial_read() uint8_t serial_read()
{ {
uint8_t tail = rx_buffer_tail; // Temporary rx_buffer_tail (to optimize for volatile) uint8_t tail = serial_rx_buffer_tail; // Temporary serial_rx_buffer_tail (to optimize for volatile)
if (rx_buffer_head == tail) { if (serial_rx_buffer_head == tail) {
return SERIAL_NO_DATA; return SERIAL_NO_DATA;
} else { } else {
uint8_t data = rx_buffer[tail]; uint8_t data = serial_rx_buffer[tail];
tail++; tail++;
if (tail == RX_BUFFER_SIZE) { tail = 0; } if (tail == RX_BUFFER_SIZE) { tail = 0; }
rx_buffer_tail = tail; serial_rx_buffer_tail = tail;
#ifdef ENABLE_XONXOFF #ifdef ENABLE_XONXOFF
if ((get_rx_buffer_count() < RX_BUFFER_LOW) && flow_ctrl == XOFF_SENT) { if ((serial_get_serial_rx_buffer_count() < RX_BUFFER_LOW) && flow_ctrl == XOFF_SENT) {
flow_ctrl = SEND_XON; flow_ctrl = SEND_XON;
UCSR0B |= (1 << UDRIE0); // Force TX UCSR0B |= (1 << UDRIE0); // Force TX
} }
@ -162,16 +175,16 @@ ISR(SERIAL_RX)
case CMD_FEED_HOLD: bit_true_atomic(sys.execute, EXEC_FEED_HOLD); break; // Set as true case CMD_FEED_HOLD: bit_true_atomic(sys.execute, EXEC_FEED_HOLD); break; // Set as true
case CMD_RESET: mc_reset(); break; // Call motion control reset routine. case CMD_RESET: mc_reset(); break; // Call motion control reset routine.
default: // Write character to buffer default: // Write character to buffer
next_head = rx_buffer_head + 1; next_head = serial_rx_buffer_head + 1;
if (next_head == RX_BUFFER_SIZE) { next_head = 0; } if (next_head == RX_BUFFER_SIZE) { next_head = 0; }
// Write data to buffer unless it is full. // Write data to buffer unless it is full.
if (next_head != rx_buffer_tail) { if (next_head != serial_rx_buffer_tail) {
rx_buffer[rx_buffer_head] = data; serial_rx_buffer[serial_rx_buffer_head] = data;
rx_buffer_head = next_head; serial_rx_buffer_head = next_head;
#ifdef ENABLE_XONXOFF #ifdef ENABLE_XONXOFF
if ((get_rx_buffer_count() >= RX_BUFFER_FULL) && flow_ctrl == XON_SENT) { if ((serial_get_serial_rx_buffer_count() >= RX_BUFFER_FULL) && flow_ctrl == XON_SENT) {
flow_ctrl = SEND_XOFF; flow_ctrl = SEND_XOFF;
UCSR0B |= (1 << UDRIE0); // Force TX UCSR0B |= (1 << UDRIE0); // Force TX
} }
@ -185,7 +198,7 @@ ISR(SERIAL_RX)
void serial_reset_read_buffer() void serial_reset_read_buffer()
{ {
rx_buffer_tail = rx_buffer_head; serial_rx_buffer_tail = serial_rx_buffer_head;
#ifdef ENABLE_XONXOFF #ifdef ENABLE_XONXOFF
flow_ctrl = XON_SENT; flow_ctrl = XON_SENT;

View File

@ -48,11 +48,20 @@
void serial_init(); void serial_init();
// Writes one byte to the TX serial buffer. Called by main program.
void serial_write(uint8_t data); void serial_write(uint8_t data);
// Fetches the first byte in the serial read buffer. Called by main program.
uint8_t serial_read(); uint8_t serial_read();
// Reset and empty data in read buffer. Used by e-stop and reset. // Reset and empty data in read buffer. Used by e-stop and reset.
void serial_reset_read_buffer(); void serial_reset_read_buffer();
// Returns the number of bytes used in the RX serial buffer.
uint8_t serial_get_rx_buffer_count();
// Returns the number of bytes used in the TX serial buffer.
// NOTE: Not used except for debugging and ensuring no TX bottlenecks.
uint8_t serial_get_tx_buffer_count();
#endif #endif

View File

@ -62,20 +62,19 @@ void write_global_settings()
// Method to reset Grbl global settings back to defaults. // Method to reset Grbl global settings back to defaults.
void settings_reset() { void settings_reset() {
settings.steps_per_mm[X_AXIS] = DEFAULT_X_STEPS_PER_MM;
settings.steps_per_mm[Y_AXIS] = DEFAULT_Y_STEPS_PER_MM;
settings.steps_per_mm[Z_AXIS] = DEFAULT_Z_STEPS_PER_MM;
settings.pulse_microseconds = DEFAULT_STEP_PULSE_MICROSECONDS; settings.pulse_microseconds = DEFAULT_STEP_PULSE_MICROSECONDS;
settings.max_rate[X_AXIS] = DEFAULT_X_MAX_RATE; settings.stepper_idle_lock_time = DEFAULT_STEPPER_IDLE_LOCK_TIME;
settings.max_rate[Y_AXIS] = DEFAULT_Y_MAX_RATE;
settings.max_rate[Z_AXIS] = DEFAULT_Z_MAX_RATE;
settings.acceleration[X_AXIS] = DEFAULT_X_ACCELERATION;
settings.acceleration[Y_AXIS] = DEFAULT_Y_ACCELERATION;
settings.acceleration[Z_AXIS] = DEFAULT_Z_ACCELERATION;
settings.arc_tolerance = DEFAULT_ARC_TOLERANCE;
settings.step_invert_mask = DEFAULT_STEPPING_INVERT_MASK; settings.step_invert_mask = DEFAULT_STEPPING_INVERT_MASK;
settings.dir_invert_mask = DEFAULT_DIRECTION_INVERT_MASK; settings.dir_invert_mask = DEFAULT_DIRECTION_INVERT_MASK;
settings.status_report_mask = DEFAULT_STATUS_REPORT_MASK;
settings.junction_deviation = DEFAULT_JUNCTION_DEVIATION; settings.junction_deviation = DEFAULT_JUNCTION_DEVIATION;
settings.arc_tolerance = DEFAULT_ARC_TOLERANCE;
settings.homing_dir_mask = DEFAULT_HOMING_DIR_MASK;
settings.homing_feed_rate = DEFAULT_HOMING_FEED_RATE;
settings.homing_seek_rate = DEFAULT_HOMING_SEEK_RATE;
settings.homing_debounce_delay = DEFAULT_HOMING_DEBOUNCE_DELAY;
settings.homing_pulloff = DEFAULT_HOMING_PULLOFF;
settings.flags = 0; settings.flags = 0;
if (DEFAULT_REPORT_INCHES) { settings.flags |= BITFLAG_REPORT_INCHES; } if (DEFAULT_REPORT_INCHES) { settings.flags |= BITFLAG_REPORT_INCHES; }
if (DEFAULT_AUTO_START) { settings.flags |= BITFLAG_AUTO_START; } if (DEFAULT_AUTO_START) { settings.flags |= BITFLAG_AUTO_START; }
@ -84,15 +83,20 @@ void settings_reset() {
if (DEFAULT_SOFT_LIMIT_ENABLE) { settings.flags |= BITFLAG_SOFT_LIMIT_ENABLE; } if (DEFAULT_SOFT_LIMIT_ENABLE) { settings.flags |= BITFLAG_SOFT_LIMIT_ENABLE; }
if (DEFAULT_HARD_LIMIT_ENABLE) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; } if (DEFAULT_HARD_LIMIT_ENABLE) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; }
if (DEFAULT_HOMING_ENABLE) { settings.flags |= BITFLAG_HOMING_ENABLE; } if (DEFAULT_HOMING_ENABLE) { settings.flags |= BITFLAG_HOMING_ENABLE; }
settings.homing_dir_mask = DEFAULT_HOMING_DIR_MASK;
settings.homing_feed_rate = DEFAULT_HOMING_FEED_RATE; settings.steps_per_mm[X_AXIS] = DEFAULT_X_STEPS_PER_MM;
settings.homing_seek_rate = DEFAULT_HOMING_SEEK_RATE; settings.steps_per_mm[Y_AXIS] = DEFAULT_Y_STEPS_PER_MM;
settings.homing_debounce_delay = DEFAULT_HOMING_DEBOUNCE_DELAY; settings.steps_per_mm[Z_AXIS] = DEFAULT_Z_STEPS_PER_MM;
settings.homing_pulloff = DEFAULT_HOMING_PULLOFF; settings.max_rate[X_AXIS] = DEFAULT_X_MAX_RATE;
settings.stepper_idle_lock_time = DEFAULT_STEPPER_IDLE_LOCK_TIME; settings.max_rate[Y_AXIS] = DEFAULT_Y_MAX_RATE;
settings.max_rate[Z_AXIS] = DEFAULT_Z_MAX_RATE;
settings.acceleration[X_AXIS] = DEFAULT_X_ACCELERATION;
settings.acceleration[Y_AXIS] = DEFAULT_Y_ACCELERATION;
settings.acceleration[Z_AXIS] = DEFAULT_Z_ACCELERATION;
settings.max_travel[X_AXIS] = (-DEFAULT_X_MAX_TRAVEL); settings.max_travel[X_AXIS] = (-DEFAULT_X_MAX_TRAVEL);
settings.max_travel[Y_AXIS] = (-DEFAULT_Y_MAX_TRAVEL); settings.max_travel[Y_AXIS] = (-DEFAULT_Y_MAX_TRAVEL);
settings.max_travel[Z_AXIS] = (-DEFAULT_Z_MAX_TRAVEL); settings.max_travel[Z_AXIS] = (-DEFAULT_Z_MAX_TRAVEL);
write_global_settings(); write_global_settings();
} }
@ -158,70 +162,90 @@ uint8_t read_global_settings() {
// A helper method to set settings from command line // A helper method to set settings from command line
uint8_t settings_store_global_setting(int parameter, float value) { uint8_t settings_store_global_setting(uint8_t parameter, float value) {
if (value < 0.0) { return(STATUS_NEGATIVE_VALUE); } if (value < 0.0) { return(STATUS_NEGATIVE_VALUE); }
if (parameter >= AXIS_SETTINGS_START_VAL) {
// Store axis configuration. Axis numbering sequence set by AXIS_SETTING defines.
// NOTE: Ensure the setting index corresponds to the report.c settings printout.
parameter -= AXIS_SETTINGS_START_VAL;
uint8_t set_idx = 0;
while (set_idx < AXIS_N_SETTINGS) {
if (parameter < N_AXIS) {
// Valid axis setting found.
switch (set_idx) {
case 0: settings.steps_per_mm[parameter] = value; break;
case 1: settings.max_rate[parameter] = value; break;
case 2: settings.acceleration[parameter] = value*60*60; break; // Convert to mm/min^2 for grbl internal use.
case 3: settings.max_travel[parameter] = -value; break; // Store as negative for grbl internal use.
}
break; // Exit while-loop after setting has been configured and proceed to the EEPROM write call.
} else {
set_idx++;
// If axis index greater than N_AXIS or setting index greater than number of axis settings, error out.
if ((parameter < AXIS_SETTINGS_INCREMENT) || (set_idx == AXIS_N_SETTINGS)) { return(STATUS_INVALID_STATEMENT); }
parameter -= AXIS_SETTINGS_INCREMENT;
}
}
} else {
// Store non-axis Grbl settings
uint8_t int_value = trunc(value);
switch(parameter) { switch(parameter) {
case 0: case 1: case 2: case 0:
settings.steps_per_mm[parameter] = value; break; if (int_value < 3) { return(STATUS_SETTING_STEP_PULSE_MIN); }
case 3: settings.max_rate[X_AXIS] = value; break; settings.pulse_microseconds = int_value; break;
case 4: settings.max_rate[Y_AXIS] = value; break; case 1: settings.stepper_idle_lock_time = int_value; break;
case 5: settings.max_rate[Z_AXIS] = value; break; case 2: settings.step_invert_mask = int_value; break;
case 6: settings.acceleration[X_AXIS] = value*60*60; break; // Convert to mm/min^2 for grbl internal use. case 3: settings.dir_invert_mask = int_value; break;
case 7: settings.acceleration[Y_AXIS] = value*60*60; break; // Convert to mm/min^2 for grbl internal use. case 4: // Reset to ensure change. Immediate re-init may cause problems.
case 8: settings.acceleration[Z_AXIS] = value*60*60; break; // Convert to mm/min^2 for grbl internal use. if (int_value) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; }
case 9: settings.max_travel[X_AXIS] = -value; break; // Store as negative for grbl internal use.
case 10: settings.max_travel[Y_AXIS] = -value; break; // Store as negative for grbl internal use.
case 11: settings.max_travel[Z_AXIS] = -value; break; // Store as negative for grbl internal use.
case 12:
if (value < 3) { return(STATUS_SETTING_STEP_PULSE_MIN); }
settings.pulse_microseconds = round(value); break;
case 13: settings.step_invert_mask = trunc(value); break;
case 14: settings.dir_invert_mask = trunc(value); break;
case 15: settings.stepper_idle_lock_time = round(value); break;
case 16: settings.junction_deviation = fabs(value); break;
case 17: settings.arc_tolerance = value; break;
case 19:
if (value) { settings.flags |= BITFLAG_REPORT_INCHES; }
else { settings.flags &= ~BITFLAG_REPORT_INCHES; }
break;
case 20: // Reset to ensure change. Immediate re-init may cause problems.
if (value) { settings.flags |= BITFLAG_AUTO_START; }
else { settings.flags &= ~BITFLAG_AUTO_START; }
break;
case 21: // Reset to ensure change. Immediate re-init may cause problems.
if (value) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; }
else { settings.flags &= ~BITFLAG_INVERT_ST_ENABLE; } else { settings.flags &= ~BITFLAG_INVERT_ST_ENABLE; }
break; break;
case 22: // Reset to ensure change. Immediate re-init may cause problems. case 5: // Reset to ensure change. Immediate re-init may cause problems.
if (value) { settings.flags |= BITFLAG_INVERT_LIMIT_PINS; } if (int_value) { settings.flags |= BITFLAG_INVERT_LIMIT_PINS; }
else { settings.flags &= ~BITFLAG_INVERT_LIMIT_PINS; } else { settings.flags &= ~BITFLAG_INVERT_LIMIT_PINS; }
break; break;
case 23: case 6: // Reset to ensure change. Immediate re-init may cause problems.
if (value) { if (int_value) { settings.flags |= BITFLAG_INVERT_PROBE_PIN; }
else { settings.flags &= ~BITFLAG_INVERT_PROBE_PIN; }
break;
case 10: settings.status_report_mask = int_value;
case 11: settings.junction_deviation = value; break;
case 12: settings.arc_tolerance = value; break;
case 13:
if (int_value) { settings.flags |= BITFLAG_REPORT_INCHES; }
else { settings.flags &= ~BITFLAG_REPORT_INCHES; }
break;
case 14: // Reset to ensure change. Immediate re-init may cause problems.
if (int_value) { settings.flags |= BITFLAG_AUTO_START; }
else { settings.flags &= ~BITFLAG_AUTO_START; }
break;
case 20:
if (int_value) {
if (bit_isfalse(settings.flags, BITFLAG_HOMING_ENABLE)) { return(STATUS_SOFT_LIMIT_ERROR); } if (bit_isfalse(settings.flags, BITFLAG_HOMING_ENABLE)) { return(STATUS_SOFT_LIMIT_ERROR); }
settings.flags |= BITFLAG_SOFT_LIMIT_ENABLE; settings.flags |= BITFLAG_SOFT_LIMIT_ENABLE;
} else { settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; } } else { settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; }
break; break;
case 24: case 21:
if (value) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; } if (int_value) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; }
else { settings.flags &= ~BITFLAG_HARD_LIMIT_ENABLE; } else { settings.flags &= ~BITFLAG_HARD_LIMIT_ENABLE; }
limits_init(); // Re-init to immediately change. NOTE: Nice to have but could be problematic later. limits_init(); // Re-init to immediately change. NOTE: Nice to have but could be problematic later.
break; break;
case 25: case 22:
if (value) { settings.flags |= BITFLAG_HOMING_ENABLE; } if (int_value) { settings.flags |= BITFLAG_HOMING_ENABLE; }
else { else {
settings.flags &= ~BITFLAG_HOMING_ENABLE; settings.flags &= ~BITFLAG_HOMING_ENABLE;
settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; // Force disable soft-limits. settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; // Force disable soft-limits.
} }
break; break;
case 26: settings.homing_dir_mask = trunc(value); break; case 23: settings.homing_dir_mask = int_value; break;
case 27: settings.homing_feed_rate = value; break; case 24: settings.homing_feed_rate = value; break;
case 28: settings.homing_seek_rate = value; break; case 25: settings.homing_seek_rate = value; break;
case 29: settings.homing_debounce_delay = round(value); break; case 26: settings.homing_debounce_delay = int_value; break;
case 30: settings.homing_pulloff = value; break; case 27: settings.homing_pulloff = value; break;
default: default:
return(STATUS_INVALID_STATEMENT); return(STATUS_INVALID_STATEMENT);
} }
}
write_global_settings(); write_global_settings();
return(STATUS_OK); return(STATUS_OK);
} }
@ -244,3 +268,30 @@ void settings_init() {
} }
// NOTE: Startup lines are handled and called by main.c at the end of initialization. // NOTE: Startup lines are handled and called by main.c at the end of initialization.
} }
// Returns step pin mask according to Grbl internal axis indexing.
uint8_t get_step_pin_mask(uint8_t axis_idx)
{
if ( axis_idx == X_AXIS ) { return((1<<X_STEP_BIT)); }
if ( axis_idx == Y_AXIS ) { return((1<<Y_STEP_BIT)); }
return((1<<Z_STEP_BIT));
}
// Returns direction pin mask according to Grbl internal axis indexing.
uint8_t get_direction_pin_mask(uint8_t axis_idx)
{
if ( axis_idx == X_AXIS ) { return((1<<X_DIRECTION_BIT)); }
if ( axis_idx == Y_AXIS ) { return((1<<Y_DIRECTION_BIT)); }
return((1<<Z_DIRECTION_BIT));
}
// Returns limit pin mask according to Grbl internal axis indexing.
uint8_t get_limit_pin_mask(uint8_t axis_idx)
{
if ( axis_idx == X_AXIS ) { return((1<<X_LIMIT_BIT)); }
if ( axis_idx == Y_AXIS ) { return((1<<Y_LIMIT_BIT)); }
return((1<<Z_LIMIT_BIT));
}

View File

@ -22,15 +22,13 @@
#ifndef settings_h #ifndef settings_h
#define settings_h #define settings_h
#include "system.h"
#define GRBL_VERSION "0.9g"
#define GRBL_VERSION "0.9f" #define GRBL_VERSION_BUILD "20140725"
#define GRBL_VERSION_BUILD "20140706"
// Version of the EEPROM data. Will be used to migrate existing data from older versions of Grbl // Version of the EEPROM data. Will be used to migrate existing data from older versions of Grbl
// when firmware is upgraded. Always stored in byte 0 of eeprom // when firmware is upgraded. Always stored in byte 0 of eeprom
#define SETTINGS_VERSION 8 #define SETTINGS_VERSION 9
// Define bit flag masks for the boolean settings in settings.flag. // Define bit flag masks for the boolean settings in settings.flag.
#define BITFLAG_REPORT_INCHES bit(0) #define BITFLAG_REPORT_INCHES bit(0)
@ -40,6 +38,13 @@
#define BITFLAG_HOMING_ENABLE bit(4) #define BITFLAG_HOMING_ENABLE bit(4)
#define BITFLAG_SOFT_LIMIT_ENABLE bit(5) #define BITFLAG_SOFT_LIMIT_ENABLE bit(5)
#define BITFLAG_INVERT_LIMIT_PINS bit(6) #define BITFLAG_INVERT_LIMIT_PINS bit(6)
#define BITFLAG_INVERT_PROBE_PIN bit(7)
// Define status reporting boolean enable bit flags in settings.status_report_mask
#define BITFLAG_RT_STATUS_MACHINE_POSITION bit(0)
#define BITFLAG_RT_STATUS_WORK_POSITION bit(1)
#define BITFLAG_RT_STATUS_PLANNER_BUFFER bit(2)
#define BITFLAG_RT_STATUS_SERIAL_RX bit(3)
// Define EEPROM memory address location values for Grbl settings and parameters // Define EEPROM memory address location values for Grbl settings and parameters
// NOTE: The Atmega328p has 1KB EEPROM. The upper half is reserved for parameters and // NOTE: The Atmega328p has 1KB EEPROM. The upper half is reserved for parameters and
@ -58,25 +63,35 @@
#define SETTING_INDEX_G30 N_COORDINATE_SYSTEM+1 // Home position 2 #define SETTING_INDEX_G30 N_COORDINATE_SYSTEM+1 // Home position 2
// #define SETTING_INDEX_G92 N_COORDINATE_SYSTEM+2 // Coordinate offset (G92.2,G92.3 not supported) // #define SETTING_INDEX_G92 N_COORDINATE_SYSTEM+2 // Coordinate offset (G92.2,G92.3 not supported)
// Define Grbl axis settings numbering scheme. Starts at START_VAL, every INCREMENT, over N_SETTINGS.
#define AXIS_N_SETTINGS 4
#define AXIS_SETTINGS_START_VAL 100 // NOTE: Reserving settings values >= 100 for axis settings. Up to 255.
#define AXIS_SETTINGS_INCREMENT 10 // Must be greater than the number of axis settings
// Global persistent settings (Stored from byte EEPROM_ADDR_GLOBAL onwards) // Global persistent settings (Stored from byte EEPROM_ADDR_GLOBAL onwards)
typedef struct { typedef struct {
// Axis settings
float steps_per_mm[N_AXIS]; float steps_per_mm[N_AXIS];
float max_rate[N_AXIS]; float max_rate[N_AXIS];
float acceleration[N_AXIS]; float acceleration[N_AXIS];
float max_travel[N_AXIS]; float max_travel[N_AXIS];
// Remaining Grbl settings
uint8_t pulse_microseconds; uint8_t pulse_microseconds;
uint8_t step_invert_mask; uint8_t step_invert_mask;
uint8_t dir_invert_mask; uint8_t dir_invert_mask;
uint8_t stepper_idle_lock_time; // If max value 255, steppers do not disable. uint8_t stepper_idle_lock_time; // If max value 255, steppers do not disable.
uint8_t status_report_mask; // Mask to indicate desired report data.
float junction_deviation; float junction_deviation;
float arc_tolerance; float arc_tolerance;
uint8_t flags; // Contains default boolean settings uint8_t flags; // Contains default boolean settings
uint8_t homing_dir_mask; uint8_t homing_dir_mask;
float homing_feed_rate; float homing_feed_rate;
float homing_seek_rate; float homing_seek_rate;
uint16_t homing_debounce_delay; uint16_t homing_debounce_delay;
float homing_pulloff; float homing_pulloff;
// uint8_t status_report_mask; // Mask to indicate desired report data.
} settings_t; } settings_t;
extern settings_t settings; extern settings_t settings;
@ -84,7 +99,7 @@ extern settings_t settings;
void settings_init(); void settings_init();
// A helper method to set new settings from command line // A helper method to set new settings from command line
uint8_t settings_store_global_setting(int parameter, float value); uint8_t settings_store_global_setting(uint8_t parameter, float value);
// Stores the protocol line variable as a startup line in EEPROM // Stores the protocol line variable as a startup line in EEPROM
void settings_store_startup_line(uint8_t n, char *line); void settings_store_startup_line(uint8_t n, char *line);
@ -92,8 +107,10 @@ void settings_store_startup_line(uint8_t n, char *line);
// Reads an EEPROM startup line to the protocol line variable // Reads an EEPROM startup line to the protocol line variable
uint8_t settings_read_startup_line(uint8_t n, char *line); uint8_t settings_read_startup_line(uint8_t n, char *line);
// Stores build info user-defined string
void settings_store_build_info(char *line); void settings_store_build_info(char *line);
// Reads build info user-defined string
uint8_t settings_read_build_info(char *line); uint8_t settings_read_build_info(char *line);
// Writes selected coordinate data to EEPROM // Writes selected coordinate data to EEPROM
@ -102,4 +119,14 @@ void settings_write_coord_data(uint8_t coord_select, float *coord_data);
// Reads selected coordinate data from EEPROM // Reads selected coordinate data from EEPROM
uint8_t settings_read_coord_data(uint8_t coord_select, float *coord_data); uint8_t settings_read_coord_data(uint8_t coord_select, float *coord_data);
// Returns the step pin mask according to Grbl's internal axis numbering
uint8_t get_step_pin_mask(uint8_t i);
// Returns the direction pin mask according to Grbl's internal axis numbering
uint8_t get_direction_pin_mask(uint8_t i);
// Returns the limit pin mask according to Grbl's internal axis numbering
uint8_t get_limit_pin_mask(uint8_t i);
#endif #endif

View File

@ -77,6 +77,7 @@ void spindle_run(uint8_t direction, float rpm)
} }
#ifdef VARIABLE_SPINDLE #ifdef VARIABLE_SPINDLE
// TODO: Install the optional capability for frequency-based output for servos.
#define SPINDLE_RPM_RANGE (SPINDLE_MAX_RPM-SPINDLE_MIN_RPM) #define SPINDLE_RPM_RANGE (SPINDLE_MAX_RPM-SPINDLE_MIN_RPM)
TCCRA_REGISTER = (1<<COMB_BIT) | (1<<WAVE1_REGISTER) | (1<<WAVE0_REGISTER); TCCRA_REGISTER = (1<<COMB_BIT) | (1<<WAVE1_REGISTER) | (1<<WAVE0_REGISTER);
TCCRB_REGISTER = (TCCRB_REGISTER & 0b11111000) | 0x02; // set to 1/8 Prescaler TCCRB_REGISTER = (TCCRB_REGISTER & 0b11111000) | 0x02; // set to 1/8 Prescaler

View File

@ -109,6 +109,10 @@ static volatile uint8_t segment_buffer_tail;
static uint8_t segment_buffer_head; static uint8_t segment_buffer_head;
static uint8_t segment_next_head; static uint8_t segment_next_head;
// Step and direction port invert masks.
static uint8_t step_port_invert_mask;
static uint8_t dir_port_invert_mask;
// Used to avoid ISR nesting of the "Stepper Driver Interrupt". Should never occur though. // Used to avoid ISR nesting of the "Stepper Driver Interrupt". Should never occur though.
static volatile uint8_t busy; static volatile uint8_t busy;
@ -189,8 +193,8 @@ void st_wake_up()
if (sys.state & (STATE_CYCLE | STATE_HOMING)){ if (sys.state & (STATE_CYCLE | STATE_HOMING)){
// Initialize stepper output bits // Initialize stepper output bits
st.dir_outbits = settings.dir_invert_mask; st.dir_outbits = dir_port_invert_mask;
st.step_outbits = settings.step_invert_mask; st.step_outbits = step_port_invert_mask;
// Initialize step pulse timing from settings. Here to ensure updating after re-writing. // Initialize step pulse timing from settings. Here to ensure updating after re-writing.
#ifdef STEP_PULSE_DELAY #ifdef STEP_PULSE_DELAY
@ -330,7 +334,7 @@ ISR(TIMER1_COMPA_vect)
st.counter_z = st.counter_x; st.counter_z = st.counter_x;
} }
st.dir_outbits = st.exec_block->direction_bits ^ settings.dir_invert_mask; st.dir_outbits = st.exec_block->direction_bits ^ dir_port_invert_mask;
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
// With AMASS enabled, adjust Bresenham axis increment counters according to AMASS level. // With AMASS enabled, adjust Bresenham axis increment counters according to AMASS level.
@ -399,7 +403,7 @@ ISR(TIMER1_COMPA_vect)
if ( ++segment_buffer_tail == SEGMENT_BUFFER_SIZE) { segment_buffer_tail = 0; } if ( ++segment_buffer_tail == SEGMENT_BUFFER_SIZE) { segment_buffer_tail = 0; }
} }
st.step_outbits ^= settings.step_invert_mask; // Apply step port invert mask st.step_outbits ^= step_port_invert_mask; // Apply step port invert mask
busy = false; busy = false;
// SPINDLE_ENABLE_PORT ^= 1<<SPINDLE_ENABLE_BIT; // Debug: Used to time ISR // SPINDLE_ENABLE_PORT ^= 1<<SPINDLE_ENABLE_BIT; // Debug: Used to time ISR
} }
@ -419,7 +423,7 @@ ISR(TIMER1_COMPA_vect)
ISR(TIMER0_OVF_vect) ISR(TIMER0_OVF_vect)
{ {
// Reset stepping pins (leave the direction pins) // Reset stepping pins (leave the direction pins)
STEP_PORT = (STEP_PORT & ~STEP_MASK) | (settings.step_invert_mask & STEP_MASK); STEP_PORT = (STEP_PORT & ~STEP_MASK) | (step_port_invert_mask & STEP_MASK);
TCCR0B = 0; // Disable Timer0 to prevent re-entering this interrupt when it's not needed. TCCR0B = 0; // Disable Timer0 to prevent re-entering this interrupt when it's not needed.
} }
#ifdef STEP_PULSE_DELAY #ifdef STEP_PULSE_DELAY
@ -441,15 +445,28 @@ void st_reset()
// Initialize stepper driver idle state. // Initialize stepper driver idle state.
st_go_idle(); st_go_idle();
// Initialize stepper algorithm variables.
memset(&prep, 0, sizeof(prep)); memset(&prep, 0, sizeof(prep));
memset(&st, 0, sizeof(st)); memset(&st, 0, sizeof(st));
st.exec_segment = NULL; st.exec_segment = NULL;
pl_block = NULL; // Planner block pointer used by segment buffer pl_block = NULL; // Planner block pointer used by segment buffer
segment_buffer_tail = 0; segment_buffer_tail = 0;
segment_buffer_head = 0; // empty = tail segment_buffer_head = 0; // empty = tail
segment_next_head = 1; segment_next_head = 1;
busy = false; busy = false;
// Setup step and direction port invert masks.
uint8_t idx;
step_port_invert_mask = 0;
dir_port_invert_mask = 0;
for (idx=0; idx<N_AXIS; idx++) {
if (bit_istrue(settings.step_invert_mask,bit(idx))) { step_port_invert_mask |= get_step_pin_mask(idx); }
if (bit_istrue(settings.dir_invert_mask,bit(idx))) { dir_port_invert_mask |= get_direction_pin_mask(idx); }
}
// Initialize step and direction port pins.
STEP_PORT = (STEP_PORT & ~STEP_MASK) | step_port_invert_mask;
DIRECTION_PORT = (DIRECTION_PORT & ~DIRECTION_MASK) | dir_port_invert_mask;
} }
@ -458,10 +475,8 @@ void stepper_init()
{ {
// Configure step and direction interface pins // Configure step and direction interface pins
STEP_DDR |= STEP_MASK; STEP_DDR |= STEP_MASK;
STEP_PORT = (STEP_PORT & ~STEP_MASK) | settings.step_invert_mask;
STEPPERS_DISABLE_DDR |= 1<<STEPPERS_DISABLE_BIT; STEPPERS_DISABLE_DDR |= 1<<STEPPERS_DISABLE_BIT;
DIRECTION_DDR |= DIRECTION_MASK; DIRECTION_DDR |= DIRECTION_MASK;
DIRECTION_PORT = (DIRECTION_PORT & ~DIRECTION_MASK) | settings.dir_invert_mask;
// Configure Timer 1: Stepper Driver Interrupt // Configure Timer 1: Stepper Driver Interrupt
TCCR1B &= ~(1<<WGM13); // waveform generation = 0100 = CTC TCCR1B &= ~(1<<WGM13); // waveform generation = 0100 = CTC
@ -815,9 +830,6 @@ void st_prep_buffer()
} }
} }
// int32_t blength = segment_buffer_head - segment_buffer_tail;
// if (blength < 0) { blength += SEGMENT_BUFFER_SIZE; }
// printInteger(blength);
} }
} }
@ -829,7 +841,7 @@ void st_prep_buffer()
#ifdef REPORT_REALTIME_RATE #ifdef REPORT_REALTIME_RATE
float st_get_realtime_rate() float st_get_realtime_rate()
{ {
if (sys.state & (STATE_CYCLE | STATE_HOMING)){ if (sys.state & (STATE_CYCLE | STATE_HOMING | STATE_HOLD)){
return prep.current_speed; return prep.current_speed;
} }
return 0.0f; return 0.0f;

View File

@ -193,7 +193,7 @@ uint8_t system_execute_line(char *line)
} else { // Store global setting. } else { // Store global setting.
if(!read_float(line, &char_counter, &value)) { return(STATUS_BAD_NUMBER_FORMAT); } if(!read_float(line, &char_counter, &value)) { return(STATUS_BAD_NUMBER_FORMAT); }
if(line[char_counter] != 0) { return(STATUS_INVALID_STATEMENT); } if(line[char_counter] != 0) { return(STATUS_INVALID_STATEMENT); }
return(settings_store_global_setting(parameter, value)); return(settings_store_global_setting((uint8_t)parameter, value));
} }
} }
} }

4919
test/gcode/8x_gear_test.nc Normal file

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@ G0X0.000Y0.000S8000M3
G0X0.000Y-33.519Z6.000 G0X0.000Y-33.519Z6.000
G1Z-1.000 G1Z-1.000
G1X0.327Y-33.521 G1X0.327Y-33.521
F1000.0 F7000.0
X0.654Y-33.526 X0.654Y-33.526
X0.980Y-33.534 X0.980Y-33.534
X1.304Y-33.546 X1.304Y-33.546

View File

@ -0,0 +1,31 @@
(Machine settings provided by @kikigey89)
$0=87.489 (x, step/mm)
$1=87.489 (y, step/mm)
$2=1280.000 (z, step/mm)
$3=1000.000 (x max rate, mm/min)
$4=1000.000 (y max rate, mm/min)
$5=500.000 (z max rate, mm/min)
$6=10.000 (x accel, mm/sec^2)
$7=10.000 (y accel, mm/sec^2)
$8=10.000 (z accel, mm/sec^2)
$9=211.000 (x max travel, mm)
$10=335.000 (y max travel, mm)
$11=70.000 (z max travel, mm)
$12=20 (step pulse, usec)
$13=160 (step port invert mask:10100000)
$14=160 (dir port invert mask:10100000)
$15=50 (step idle delay, msec)
$16=0.010 (junction deviation, mm)
$17=0.002 (arc tolerance, mm)
$19=0 (report inches, bool)
$20=1 (auto start, bool)
$21=0 (invert step enable, bool)
$22=0 (invert limit pins, bool)
$23=0 (soft limits, bool)
$24=0 (hard limits, bool)
$25=0 (homing cycle, bool)
$26=0 (homing dir invert mask:00000000)
$27=50.000 (homing feed, mm/min)
$28=500.000 (homing seek, mm/min)
$29=10 (homing debounce, msec)
$30=3.000 (homing pull-off, mm)