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:
parent
1c74be0625
commit
71f333ddca
21
README.md
21
README.md
@ -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!
|
||||
|
||||
* 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!
|
||||
- **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.
|
||||
- **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.
|
||||
- **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.
|
||||
@ -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.
|
||||
- **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.
|
||||
- **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 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.
|
||||
- **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!
|
||||
|
29
config.h
29
config.h
@ -27,6 +27,8 @@
|
||||
|
||||
#ifndef config_h
|
||||
#define config_h
|
||||
#include <system.h>
|
||||
|
||||
|
||||
// Default settings. Used when resetting EEPROM. Change to desired name in defaults.h
|
||||
#define DEFAULTS_GENERIC
|
||||
@ -78,6 +80,11 @@
|
||||
// greater.
|
||||
#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
|
||||
// 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
|
||||
@ -103,6 +110,11 @@
|
||||
// data with each status update.
|
||||
// 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.
|
||||
|
||||
// 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
|
||||
// analog pin 5. Only use this option if you require a second coolant control pin.
|
||||
@ -156,12 +168,10 @@
|
||||
#define MINIMUM_JUNCTION_SPEED 0.0 // (mm/min)
|
||||
|
||||
// Number of arc generation iterations by small angle approximation before exact arc trajectory
|
||||
// correction. This parameter maybe decreased if there are issues with the accuracy of the arc
|
||||
// generations. In general, the default value is more than enough for the intended CNC applications
|
||||
// of grbl, and should be on the order or greater than the size of the buffer to help with the
|
||||
// computational efficiency of generating arcs.
|
||||
// NOTE: Arcs are now generated by a chordal tolerance
|
||||
#define N_ARC_CORRECTION 20 // Integer (1-255)
|
||||
// correction with expensive sin() and cos() calcualtions. This parameter maybe decreased if there
|
||||
// are issues with the accuracy of the arc generations, or increased if arc execution is getting
|
||||
// bogged down by too many trig calculations.
|
||||
#define N_ARC_CORRECTION 12 // Integer (1-255)
|
||||
|
||||
// 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
|
||||
@ -200,11 +210,11 @@
|
||||
// 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
|
||||
// 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
|
||||
// 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.
|
||||
// #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
|
||||
// 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
|
||||
// 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.
|
||||
// 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 TX_BUFFER_SIZE 64
|
||||
|
||||
@ -246,4 +257,6 @@
|
||||
// #endif
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#endif
|
||||
|
15
defaults.h
15
defaults.h
@ -43,8 +43,9 @@
|
||||
#define DEFAULT_Z_MAX_TRAVEL 200.0 // mm
|
||||
#define DEFAULT_STEP_PULSE_MICROSECONDS 10
|
||||
#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_STATUS_REPORT_MASK ((BITFLAG_RT_STATUS_MACHINE_POSITION)|(BITFLAG_RT_STATUS_WORK_POSITION))
|
||||
#define DEFAULT_JUNCTION_DEVIATION 0.02 // mm
|
||||
#define DEFAULT_ARC_TOLERANCE 0.002 // mm
|
||||
#define DEFAULT_DECIMAL_PLACES 3
|
||||
@ -82,8 +83,9 @@
|
||||
#define DEFAULT_Z_MAX_TRAVEL 170.0 // mm
|
||||
#define DEFAULT_STEP_PULSE_MICROSECONDS 10
|
||||
#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_STATUS_REPORT_MASK ((BITFLAG_RT_STATUS_MACHINE_POSITION)|(BITFLAG_RT_STATUS_WORK_POSITION))
|
||||
#define DEFAULT_JUNCTION_DEVIATION 0.02 // mm
|
||||
#define DEFAULT_ARC_TOLERANCE 0.002 // mm
|
||||
#define DEFAULT_DECIMAL_PLACES 3
|
||||
@ -124,8 +126,9 @@
|
||||
#define DEFAULT_Z_MAX_TRAVEL 200.0 // mm
|
||||
#define DEFAULT_STEP_PULSE_MICROSECONDS 10
|
||||
#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_STATUS_REPORT_MASK ((BITFLAG_RT_STATUS_MACHINE_POSITION)|(BITFLAG_RT_STATUS_WORK_POSITION))
|
||||
#define DEFAULT_JUNCTION_DEVIATION 0.05 // mm
|
||||
#define DEFAULT_ARC_TOLERANCE 0.002 // mm
|
||||
#define DEFAULT_DECIMAL_PLACES 3
|
||||
@ -166,8 +169,9 @@
|
||||
#define DEFAULT_Z_MAX_TRAVEL 200.0 // mm
|
||||
#define DEFAULT_STEP_PULSE_MICROSECONDS 10
|
||||
#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_STATUS_REPORT_MASK ((BITFLAG_RT_STATUS_MACHINE_POSITION)|(BITFLAG_RT_STATUS_WORK_POSITION))
|
||||
#define DEFAULT_JUNCTION_DEVIATION 0.05 // mm
|
||||
#define DEFAULT_ARC_TOLERANCE 0.002 // mm
|
||||
#define DEFAULT_DECIMAL_PLACES 3
|
||||
@ -206,8 +210,9 @@
|
||||
#define DEFAULT_Z_MAX_TRAVEL 150.0 // mm
|
||||
#define DEFAULT_STEP_PULSE_MICROSECONDS 10
|
||||
#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_STATUS_REPORT_MASK ((BITFLAG_RT_STATUS_MACHINE_POSITION)|(BITFLAG_RT_STATUS_WORK_POSITION))
|
||||
#define DEFAULT_JUNCTION_DEVIATION 0.02 // mm
|
||||
#define DEFAULT_ARC_TOLERANCE 0.002 // mm
|
||||
#define DEFAULT_DECIMAL_PLACES 3
|
||||
|
64
gcode.c
64
gcode.c
@ -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
|
||||
uint8_t axis_command = AXIS_COMMAND_NONE;
|
||||
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 parameter_data[N_AXIS]; // Multi-use variable to store parameter data for execution
|
||||
|
||||
@ -526,19 +527,21 @@ uint8_t gc_execute_line(char *line)
|
||||
// [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 (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.
|
||||
if (int_value > N_COORDINATE_SYSTEM) { FAIL(STATUS_GCODE_UNSUPPORTED_COORD_SYS); } // [Greater than N sys]
|
||||
coord_select = trunc(gc_block.values.p); // Convert p value to int.
|
||||
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 == 2) {
|
||||
if (bit_istrue(value_words,bit(WORD_R))) { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); } // [G10 L2 R not supported]
|
||||
} else { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); } // [Unsupported L]
|
||||
}
|
||||
bit_false(value_words,(bit(WORD_L)|bit(WORD_P)));
|
||||
|
||||
// Determine coordinate system to change and try to load from EEPROM.
|
||||
if (coord_select > 0) { coord_select--; } // Adjust P1-P6 index to EEPROM coordinate data indexing.
|
||||
else { coord_select = gc_block.modal.coord_select; } // Index P0 as the active coordinate system
|
||||
if (!settings_read_coord_data(coord_select,parameter_data)) { FAIL(STATUS_SETTING_READ_FAIL); } // [EEPROM read fail]
|
||||
|
||||
// Load EEPROM coordinate data and pre-calculate the new coordinate data.
|
||||
if (int_value > 0) { int_value--; } // Adjust P1-P6 index to EEPROM coordinate data indexing.
|
||||
else { int_value = 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]
|
||||
// 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.
|
||||
// Update axes defined only in block. Always in machine coordinates. Can change non-active system.
|
||||
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
|
||||
// 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); }
|
||||
}
|
||||
|
||||
// [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
|
||||
|
||||
@ -890,31 +894,25 @@ uint8_t gc_execute_line(char *line)
|
||||
|
||||
// [19. Go to predefined position, Set G10, or Set axis offsets ]:
|
||||
switch(gc_block.non_modal_command) {
|
||||
case NON_MODAL_SET_COORDINATE_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);
|
||||
case NON_MODAL_SET_COORDINATE_DATA:
|
||||
settings_write_coord_data(coord_select,parameter_data);
|
||||
// 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;
|
||||
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
|
||||
// and absolute and incremental modes.
|
||||
if (axis_command) {
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
mc_line(gc_block.values.xyz, -1.0, false, gc_block.values.n);
|
||||
mc_line(gc_block.values.xyz, -1.0, false, gc_block.values.n);
|
||||
#else
|
||||
mc_line(gc_block.values.xyz, -1.0, false);
|
||||
mc_line(gc_block.values.xyz, -1.0, false);
|
||||
#endif
|
||||
}
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
mc_line(parameter_data, -1.0, false, gc_block.values.n);
|
||||
mc_line(parameter_data, -1.0, false, gc_block.values.n);
|
||||
#else
|
||||
mc_line(parameter_data, -1.0, false);
|
||||
mc_line(parameter_data, -1.0, false);
|
||||
#endif
|
||||
memcpy(gc_state.position, parameter_data, sizeof(parameter_data));
|
||||
break;
|
||||
@ -942,32 +940,34 @@ uint8_t gc_execute_line(char *line)
|
||||
switch (gc_state.modal.motion) {
|
||||
case MOTION_MODE_SEEK:
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
mc_line(gc_block.values.xyz, -1.0, false, gc_block.values.n);
|
||||
mc_line(gc_block.values.xyz, -1.0, false, gc_block.values.n);
|
||||
#else
|
||||
mc_line(gc_block.values.xyz, -1.0, false);
|
||||
mc_line(gc_block.values.xyz, -1.0, false);
|
||||
#endif
|
||||
break;
|
||||
case MOTION_MODE_LINEAR:
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
mc_line(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, gc_block.values.n);
|
||||
mc_line(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate, gc_block.values.n);
|
||||
#else
|
||||
mc_line(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate);
|
||||
mc_line(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate);
|
||||
#endif
|
||||
break;
|
||||
case MOTION_MODE_CW_ARC: case MOTION_MODE_CCW_ARC:
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
mc_arc(gc_state.position, gc_block.values.xyz, gc_block.values.ijk, gc_block.values.r,
|
||||
gc_state.feed_rate, gc_state.modal.feed_rate, axis_0, axis_1, axis_linear, gc_block.values.n);
|
||||
mc_arc(gc_state.position, gc_block.values.xyz, gc_block.values.ijk, gc_block.values.r,
|
||||
gc_state.feed_rate, gc_state.modal.feed_rate, axis_0, axis_1, axis_linear, gc_block.values.n);
|
||||
#else
|
||||
mc_arc(gc_state.position, gc_block.values.xyz, gc_block.values.ijk, gc_block.values.r,
|
||||
gc_state.feed_rate, gc_state.modal.feed_rate, axis_0, axis_1, axis_linear);
|
||||
mc_arc(gc_state.position, gc_block.values.xyz, gc_block.values.ijk, gc_block.values.r,
|
||||
gc_state.feed_rate, gc_state.modal.feed_rate, axis_0, axis_1, axis_linear);
|
||||
#endif
|
||||
break;
|
||||
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
|
||||
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
|
||||
mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate);
|
||||
mc_probe_cycle(gc_block.values.xyz, gc_state.feed_rate, gc_state.modal.feed_rate);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -992,7 +992,7 @@ uint8_t gc_execute_line(char *line)
|
||||
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);
|
||||
}
|
||||
|
||||
|
5
gcode.h
5
gcode.h
@ -22,7 +22,6 @@
|
||||
#ifndef gcode_h
|
||||
#define gcode_h
|
||||
|
||||
#include "system.h"
|
||||
|
||||
// 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
|
||||
@ -128,7 +127,7 @@
|
||||
|
||||
// NOTE: When this struct is zeroed, the above defines set the defaults for the system.
|
||||
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 units; // {G20,G21}
|
||||
uint8_t distance; // {G90,G91}
|
||||
@ -149,7 +148,7 @@ typedef struct {
|
||||
// float q; // G82 peck drilling
|
||||
float r; // Arc radius
|
||||
float s; // Spindle speed
|
||||
// uint8_t t; // Tool selection
|
||||
uint8_t t; // Tool selection
|
||||
float xyz[3]; // X,Y,Z Translational axes
|
||||
} gc_values_t;
|
||||
|
||||
|
173
limits.c
173
limits.c
@ -28,8 +28,8 @@
|
||||
#include "limits.h"
|
||||
#include "report.h"
|
||||
|
||||
|
||||
#define HOMING_AXIS_SEARCH_SCALAR 1.5 // Axis search distance multiplier. Must be > 1.
|
||||
// Homing axis search distance multiplier. Computed by this value times the axis max travel.
|
||||
#define HOMING_AXIS_SEARCH_SCALAR 1.5 // Must be > 1 to ensure limit switch will be engaged.
|
||||
|
||||
|
||||
void limits_init()
|
||||
@ -50,9 +50,9 @@ void limits_init()
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SOFTWARE_DEBOUNCE
|
||||
MCUSR &= ~(1<<WDRF);
|
||||
WDTCSR |= (1<<WDCE) | (1<<WDE);
|
||||
WDTCSR = (1<<WDP0); // Set time-out at ~32msec.
|
||||
MCUSR &= ~(1<<WDRF);
|
||||
WDTCSR |= (1<<WDCE) | (1<<WDE);
|
||||
WDTCSR = (1<<WDP0); // Set time-out at ~32msec.
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -76,38 +76,38 @@ void limits_disable()
|
||||
// special pinout for an e-stop, but it is generally recommended to just directly connect
|
||||
// your e-stop switch to the Arduino reset pin, since it is the most correct way to do this.
|
||||
#ifndef ENABLE_SOFTWARE_DEBOUNCE
|
||||
ISR(LIMIT_INT_vect) // DEFAULT: Limit pin change interrupt process.
|
||||
{
|
||||
// Ignore limit switches if already in an alarm state or in-process of executing an alarm.
|
||||
// When in the alarm state, Grbl should have been reset or will force a reset, so any pending
|
||||
// moves in the planner and serial buffers are all cleared and newly sent blocks will be
|
||||
// locked out until a homing cycle or a kill lock command. Allows the user to disable the hard
|
||||
// limit setting if their limits are constantly triggering after a reset and move their axes.
|
||||
if (sys.state != STATE_ALARM) {
|
||||
if (bit_isfalse(sys.execute,EXEC_ALARM)) {
|
||||
mc_reset(); // Initiate system kill.
|
||||
bit_true_atomic(sys.execute, (EXEC_ALARM | EXEC_CRIT_EVENT)); // Indicate hard limit critical event
|
||||
}
|
||||
}
|
||||
}
|
||||
#else // OPTIONAL: Software debounce limit pin routine.
|
||||
// Upon limit pin change, enable watchdog timer to create a short delay.
|
||||
ISR(LIMIT_INT_vect) { if (!(WDTCSR & (1<<WDIE))) { WDTCSR |= (1<<WDIE); } }
|
||||
ISR(WDT_vect) // Watchdog timer ISR
|
||||
{
|
||||
WDTCSR &= ~(1<<WDIE); // Disable watchdog timer.
|
||||
if (sys.state != STATE_ALARM) { // Ignore if already in alarm state.
|
||||
if (bit_isfalse(sys.execute,EXEC_ALARM)) {
|
||||
uint8_t bits = LIMIT_PIN;
|
||||
// Check limit pin state.
|
||||
if (bit_istrue(settings.flags,BITFLAG_INVERT_LIMIT_PINS)) { bits ^= LIMIT_MASK; }
|
||||
if (bits & LIMIT_MASK) {
|
||||
ISR(LIMIT_INT_vect) // DEFAULT: Limit pin change interrupt process.
|
||||
{
|
||||
// Ignore limit switches if already in an alarm state or in-process of executing an alarm.
|
||||
// When in the alarm state, Grbl should have been reset or will force a reset, so any pending
|
||||
// moves in the planner and serial buffers are all cleared and newly sent blocks will be
|
||||
// locked out until a homing cycle or a kill lock command. Allows the user to disable the hard
|
||||
// limit setting if their limits are constantly triggering after a reset and move their axes.
|
||||
if (sys.state != STATE_ALARM) {
|
||||
if (bit_isfalse(sys.execute,EXEC_ALARM)) {
|
||||
mc_reset(); // Initiate system kill.
|
||||
bit_true_atomic(sys.execute, (EXEC_ALARM | EXEC_CRIT_EVENT)); // Indicate hard limit critical event
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else // OPTIONAL: Software debounce limit pin routine.
|
||||
// Upon limit pin change, enable watchdog timer to create a short delay.
|
||||
ISR(LIMIT_INT_vect) { if (!(WDTCSR & (1<<WDIE))) { WDTCSR |= (1<<WDIE); } }
|
||||
ISR(WDT_vect) // Watchdog timer ISR
|
||||
{
|
||||
WDTCSR &= ~(1<<WDIE); // Disable watchdog timer.
|
||||
if (sys.state != STATE_ALARM) { // Ignore if already in alarm state.
|
||||
if (bit_isfalse(sys.execute,EXEC_ALARM)) {
|
||||
uint8_t bits = LIMIT_PIN;
|
||||
// Check limit pin state.
|
||||
if (bit_istrue(settings.flags,BITFLAG_INVERT_LIMIT_PINS)) { bits ^= LIMIT_MASK; }
|
||||
if (bits & LIMIT_MASK) {
|
||||
mc_reset(); // Initiate system kill.
|
||||
bit_true_atomic(sys.execute, (EXEC_ALARM | EXEC_CRIT_EVENT)); // Indicate hard limit critical event
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@ -128,13 +128,19 @@ void limits_go_home(uint8_t cycle_mask)
|
||||
uint8_t n_cycle = (2*N_HOMING_LOCATE_CYCLE+1);
|
||||
float target[N_AXIS];
|
||||
|
||||
// Determine travel distance to the furthest homing switch based on user max travel settings.
|
||||
// NOTE: settings.max_travel[] is stored as a negative value.
|
||||
float max_travel = settings.max_travel[X_AXIS];
|
||||
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]; }
|
||||
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.
|
||||
// NOTE: settings.max_travel[] is stored as a negative value.
|
||||
if (max_travel > settings.max_travel[idx]) { max_travel = settings.max_travel[idx]; }
|
||||
}
|
||||
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.
|
||||
|
||||
do {
|
||||
@ -142,9 +148,12 @@ void limits_go_home(uint8_t cycle_mask)
|
||||
if (bit_isfalse(settings.flags,BITFLAG_INVERT_LIMIT_PINS)) { 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 axislock = 0;
|
||||
|
||||
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))) {
|
||||
n_active_axis++;
|
||||
if (!approach) { target[idx] = -max_travel; }
|
||||
@ -152,41 +161,35 @@ void limits_go_home(uint8_t cycle_mask)
|
||||
} else {
|
||||
target[idx] = 0.0;
|
||||
}
|
||||
}
|
||||
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.
|
||||
|
||||
// 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); }
|
||||
// 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]; }
|
||||
}
|
||||
homing_rate *= sqrt(n_active_axis); // [sqrt(N_AXIS)] Adjust so individual axes all move at homing rate.
|
||||
sys.homing_axis_lock = axislock;
|
||||
|
||||
// Perform homing cycle. Planner buffer should be empty, as required to initiate the homing cycle.
|
||||
uint8_t limit_state;
|
||||
|
||||
#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
|
||||
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
|
||||
|
||||
st_prep_buffer(); // Prep and fill segment buffer from newly planned block.
|
||||
st_wake_up(); // Initiate motion
|
||||
do {
|
||||
// Check limit state. Lock out cycle axes when they change.
|
||||
limit_state = LIMIT_PIN;
|
||||
if (invert_pin) { limit_state ^= LIMIT_MASK; }
|
||||
if (axislock & (1<<X_STEP_BIT)) {
|
||||
if (limit_state & (1<<X_LIMIT_BIT)) { axislock &= ~(1<<X_STEP_BIT); }
|
||||
}
|
||||
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); }
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
if (axislock & step_pin[idx]) {
|
||||
if (limit_state & limit_pin[idx]) { axislock &= ~(step_pin[idx]); }
|
||||
}
|
||||
}
|
||||
sys.homing_axis_lock = axislock;
|
||||
st_prep_buffer(); // Check and prep segment buffer. NOTE: Should take no longer than 200us.
|
||||
@ -217,22 +220,31 @@ void limits_go_home(uint8_t cycle_mask)
|
||||
// do not move them.
|
||||
// NOTE: settings.max_travel[] is stored as a negative value.
|
||||
if (cycle_mask & bit(idx)) {
|
||||
if ( settings.homing_dir_mask & get_direction_mask(idx) ) {
|
||||
target[idx] = settings.homing_pulloff+settings.max_travel[idx];
|
||||
sys.position[idx] = lround(settings.max_travel[idx]*settings.steps_per_mm[idx]);
|
||||
} else {
|
||||
target[idx] = -settings.homing_pulloff;
|
||||
sys.position[idx] = 0;
|
||||
}
|
||||
|
||||
#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];
|
||||
sys.position[idx] = lround(settings.max_travel[idx]*settings.steps_per_mm[idx]);
|
||||
} else {
|
||||
target[idx] = -settings.homing_pulloff;
|
||||
sys.position[idx] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
} else { // Non-active cycle axis. Set target to not move during pull-off.
|
||||
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.
|
||||
|
||||
#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
|
||||
plan_buffer_line(target, settings.homing_seek_rate, false); // Bypass mc_line(). Directly plan motion.
|
||||
plan_buffer_line(target, settings.homing_seek_rate, false); // Bypass mc_line(). Directly plan motion.
|
||||
#endif
|
||||
|
||||
// Initiate pull-off using main motion control routines.
|
||||
@ -252,9 +264,23 @@ void limits_go_home(uint8_t cycle_mask)
|
||||
void limits_soft_check(float *target)
|
||||
{
|
||||
uint8_t 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
|
||||
uint8_t soft_limit_error = false;
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
|
||||
#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
|
||||
// workspace volume so just come to a controlled stop so position is not lost. When complete
|
||||
// enter alarm mode.
|
||||
@ -265,12 +291,11 @@ void limits_soft_check(float *target)
|
||||
if (sys.abort) { return; }
|
||||
} while ( sys.state != STATE_IDLE || sys.state != STATE_QUEUED);
|
||||
}
|
||||
|
||||
|
||||
mc_reset(); // Issue system reset and ensure spindle and coolant are shutdown.
|
||||
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
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,9 +42,9 @@
|
||||
// mc_line and plan_buffer_line is done primarily to place non-planner-type functions from being
|
||||
// in the planner and to let backlash compensation or canned cycle integration simple and direct.
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
void mc_line(float *target, float feed_rate, uint8_t invert_feed_rate, int32_t line_number)
|
||||
void mc_line(float *target, float feed_rate, uint8_t invert_feed_rate, int32_t line_number)
|
||||
#else
|
||||
void mc_line(float *target, float feed_rate, uint8_t invert_feed_rate)
|
||||
void mc_line(float *target, float feed_rate, uint8_t invert_feed_rate)
|
||||
#endif
|
||||
{
|
||||
// If enabled, check for soft limit violations. Placed here all line motions are picked up
|
||||
@ -78,9 +78,9 @@ void mc_line(float *target, float feed_rate, uint8_t invert_feed_rate)
|
||||
} while (1);
|
||||
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
plan_buffer_line(target, feed_rate, invert_feed_rate, line_number);
|
||||
plan_buffer_line(target, feed_rate, invert_feed_rate, line_number);
|
||||
#else
|
||||
plan_buffer_line(target, feed_rate, invert_feed_rate);
|
||||
plan_buffer_line(target, feed_rate, invert_feed_rate);
|
||||
#endif
|
||||
|
||||
// If idle, indicate to the system there is now a planned block in the buffer ready to cycle
|
||||
@ -97,11 +97,11 @@ void mc_line(float *target, float feed_rate, uint8_t invert_feed_rate)
|
||||
// of each segment is configured in settings.arc_tolerance, which is defined to be the maximum normal
|
||||
// distance from segment to the circle when the end points both lie on the circle.
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
void mc_arc(float *position, float *target, float *offset, float radius, float feed_rate,
|
||||
uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear, int32_t line_number)
|
||||
void mc_arc(float *position, float *target, float *offset, float radius, float feed_rate,
|
||||
uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear, int32_t line_number)
|
||||
#else
|
||||
void mc_arc(float *position, float *target, float *offset, float radius, float feed_rate,
|
||||
uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear)
|
||||
void mc_arc(float *position, float *target, float *offset, float radius, float feed_rate,
|
||||
uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear)
|
||||
#endif
|
||||
{
|
||||
float center_axis0 = position[axis_0] + offset[axis_0];
|
||||
@ -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
|
||||
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
|
||||
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
|
||||
(second order sin() has too much error) holds for nearly all CNC applications, except for possibly very
|
||||
small radii (~0.5mm). In other words, theta_per_segment would need to be greater than 0.25 rad(14 deg)
|
||||
and N_ARC_CORRECTION would need to be large to cause an appreciable drift error (>5% of radius, for very
|
||||
small radii, 5% of 0.5mm is very, very small). N_ARC_CORRECTION~=20 should be more than small enough to
|
||||
correct for numerical drift error. Also decreasing the tolerance will improve the approximation too.
|
||||
(second order sin() has too much error) holds for most, if not, all CNC applications. Note that this
|
||||
approximation will begin to accumulate a numerical drift error when theta_per_segment is greater than
|
||||
~0.25 rad(14 deg) AND the approximation is successively used without correction several dozen times. This
|
||||
scenario is extremely unlikely, since segment lengths and theta_per_segment are automatically generated
|
||||
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
|
||||
without the initial overhead of computing cos() or sin(). By the time the arc needs to be applied
|
||||
@ -193,9 +195,9 @@ void mc_arc(float *position, float *target, float *offset, float radius, float f
|
||||
position[axis_linear] += linear_per_segment;
|
||||
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
mc_line(position, feed_rate, invert_feed_rate, line_number);
|
||||
mc_line(position, feed_rate, invert_feed_rate, line_number);
|
||||
#else
|
||||
mc_line(position, feed_rate, invert_feed_rate);
|
||||
mc_line(position, feed_rate, invert_feed_rate);
|
||||
#endif
|
||||
|
||||
// Bail mid-circle on system abort. Runtime command check already performed by mc_line.
|
||||
@ -204,9 +206,9 @@ void mc_arc(float *position, float *target, float *offset, float radius, float f
|
||||
}
|
||||
// Ensure last segment arrives at target location.
|
||||
#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
|
||||
mc_line(target, feed_rate, invert_feed_rate);
|
||||
mc_line(target, feed_rate, invert_feed_rate);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -269,62 +271,64 @@ void mc_homing_cycle()
|
||||
// Perform tool length probe cycle. Requires probe switch.
|
||||
// NOTE: Upon probe failure, the program will be stopped and placed into ALARM state.
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate, int32_t line_number)
|
||||
void mc_probe_cycle(float *target, float feed_rate, uint8_t invert_feed_rate, int32_t line_number)
|
||||
#else
|
||||
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
|
||||
{
|
||||
if (sys.state != STATE_CYCLE) protocol_auto_cycle_start();
|
||||
protocol_buffer_synchronize(); // Finish all queued commands
|
||||
{
|
||||
protocol_buffer_synchronize(); // Finish all queued commands and empty planner buffer.
|
||||
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
|
||||
mc_line(target, feed_rate, invert_feed_rate, line_number);
|
||||
mc_line(target, feed_rate, invert_feed_rate, line_number);
|
||||
#else
|
||||
mc_line(target, feed_rate, invert_feed_rate);
|
||||
mc_line(target, feed_rate, invert_feed_rate);
|
||||
#endif
|
||||
|
||||
// Activate the probing monitor in the stepper module.
|
||||
// NOTE: Parser error-checking ensures the probe isn't already closed/triggered.
|
||||
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);
|
||||
do {
|
||||
protocol_execute_runtime();
|
||||
if (sys.abort) { return; } // Check for system abort
|
||||
} 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); }
|
||||
protocol_execute_runtime(); // Check and execute run-time commands
|
||||
if (sys.abort) { return; } // Check for system abort
|
||||
|
||||
//Prep the new target based on the position that the probe triggered
|
||||
uint8_t i;
|
||||
for(i=0; i<N_AXIS; ++i){
|
||||
target[i] = (float)sys.probe_position[i]/settings.steps_per_mm[i];
|
||||
// Reset the stepper and planner buffers to remove the remainder of the probe motion.
|
||||
st_reset(); // Reest step segment buffer.
|
||||
plan_reset(); // Reset planner buffer. Zero planner positions. Ensure probing motion is cleared.
|
||||
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
|
||||
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
|
||||
mc_line(target, feed_rate, invert_feed_rate); // Bypass mc_line(). Directly plan homing motion.
|
||||
mc_line(target, feed_rate, invert_feed_rate);
|
||||
#endif
|
||||
|
||||
// Execute pull-off motion and wait until it completes.
|
||||
bit_true_atomic(sys.execute, EXEC_CYCLE_START);
|
||||
protocol_buffer_synchronize(); // Complete pull-off motion.
|
||||
if (sys.abort) { return; } // Did not complete. Alarm state set by mc_alarm.
|
||||
protocol_buffer_synchronize();
|
||||
if (sys.abort) { return; } // Return if system reset has been issued.
|
||||
|
||||
// Gcode parser position was circumvented by the this routine, so sync position now.
|
||||
gc_sync_position();
|
||||
|
||||
// Output the probe position as message.
|
||||
report_probe_parameters();
|
||||
#ifdef MESSAGE_PROBE_COORDINATES
|
||||
// All done! Output the probe position as message.
|
||||
report_probe_parameters();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
21
nuts_bolts.c
21
nuts_bolts.c
@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
#include "print.h"
|
||||
|
||||
|
||||
#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.
|
||||
uint8_t get_direction_mask(uint8_t axis_idx)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
// Simple hypotenuse computation function.
|
||||
float hypot_f(float x, float y) { return(sqrt(x*x + y*y)); }
|
||||
|
@ -63,8 +63,7 @@ void delay_ms(uint16_t ms);
|
||||
// Delays variable-defined microseconds. Compiler compatibility fix for _delay_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);
|
||||
|
||||
#endif
|
||||
|
14
planner.c
14
planner.c
@ -260,9 +260,9 @@ uint8_t plan_check_full_buffer()
|
||||
invert_feed_rate is true, or as seek/rapids rate if the feed_rate value is negative (and
|
||||
invert_feed_rate always false). */
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
void plan_buffer_line(float *target, float feed_rate, uint8_t invert_feed_rate, int32_t line_number)
|
||||
void plan_buffer_line(float *target, float feed_rate, uint8_t invert_feed_rate, int32_t line_number)
|
||||
#else
|
||||
void plan_buffer_line(float *target, float feed_rate, uint8_t invert_feed_rate)
|
||||
void plan_buffer_line(float *target, float feed_rate, uint8_t invert_feed_rate)
|
||||
#endif
|
||||
{
|
||||
// Prepare and initialize new block
|
||||
@ -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.
|
||||
|
||||
// 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.
|
||||
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.
|
||||
// Called after a steppers have come to a complete stop for a feed hold and the cycle is stopped.
|
||||
void plan_cycle_reinitialize()
|
||||
|
@ -22,7 +22,6 @@
|
||||
#ifndef planner_h
|
||||
#define planner_h
|
||||
|
||||
#include "system.h"
|
||||
|
||||
// The number of linear motions that can be in the plan at any give time
|
||||
#ifndef BLOCK_BUFFER_SIZE
|
||||
@ -65,9 +64,9 @@ void plan_reset();
|
||||
// in millimeters. Feed rate specifies the speed of the motion. If feed rate is inverted, the feed
|
||||
// rate is taken to mean "frequency" and would complete the operation in 1/feed_rate minutes.
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
void plan_buffer_line(float *target, float feed_rate, uint8_t invert_feed_rate, int32_t line_number);
|
||||
void plan_buffer_line(float *target, float feed_rate, uint8_t invert_feed_rate, int32_t line_number);
|
||||
#else
|
||||
void plan_buffer_line(float *target, float feed_rate, uint8_t invert_feed_rate);
|
||||
void plan_buffer_line(float *target, float feed_rate, uint8_t invert_feed_rate);
|
||||
#endif
|
||||
|
||||
// Called when the current block is no longer needed. Discards the block and makes the memory
|
||||
@ -89,6 +88,9 @@ void plan_sync_position();
|
||||
// Reinitialize plan with a partially completed block
|
||||
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.
|
||||
uint8_t plan_check_full_buffer();
|
||||
|
||||
|
21
print.c
21
print.c
@ -19,9 +19,6 @@
|
||||
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 "serial.h"
|
||||
#include "settings.h"
|
||||
@ -33,6 +30,7 @@ void printString(const char *s)
|
||||
serial_write(*s++);
|
||||
}
|
||||
|
||||
|
||||
// Print a string stored in PGM-memory
|
||||
void printPgmString(const char *s)
|
||||
{
|
||||
@ -41,6 +39,7 @@ void printPgmString(const char *s)
|
||||
serial_write(c);
|
||||
}
|
||||
|
||||
|
||||
// void printIntegerInBase(unsigned long n, unsigned long base)
|
||||
// {
|
||||
// unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
|
||||
@ -62,6 +61,7 @@ void printPgmString(const char *s)
|
||||
// 'A' + buf[i - 1] - 10);
|
||||
// }
|
||||
|
||||
|
||||
void print_uint8_base2(uint8_t n)
|
||||
{
|
||||
unsigned char buf[8];
|
||||
@ -76,6 +76,7 @@ void print_uint8_base2(uint8_t n)
|
||||
serial_write('0' + buf[i - 1]);
|
||||
}
|
||||
|
||||
|
||||
void print_uint8_base10(uint8_t n)
|
||||
{
|
||||
if (n == 0) {
|
||||
@ -95,6 +96,7 @@ void print_uint8_base10(uint8_t n)
|
||||
serial_write(buf[i - 1]);
|
||||
}
|
||||
|
||||
|
||||
void print_uint32_base10(unsigned long n)
|
||||
{
|
||||
if (n == 0) {
|
||||
@ -114,6 +116,7 @@ void print_uint32_base10(unsigned long n)
|
||||
serial_write('0' + buf[i-1]);
|
||||
}
|
||||
|
||||
|
||||
void printInteger(long n)
|
||||
{
|
||||
if (n < 0) {
|
||||
@ -124,6 +127,7 @@ void printInteger(long n)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Convert float to string by immediately converting to a long integer, which contains
|
||||
// more digits than a float. Number of decimal places, which are tracked by a counter,
|
||||
// may be set by the user. The integer is then efficiently converted to a string.
|
||||
@ -190,3 +194,14 @@ void printFloat_RateValue(float n) {
|
||||
}
|
||||
|
||||
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(" ");
|
||||
}
|
||||
|
4
print.h
4
print.h
@ -25,6 +25,7 @@
|
||||
#ifndef print_h
|
||||
#define print_h
|
||||
|
||||
|
||||
void printString(const char *s);
|
||||
|
||||
void printPgmString(const char *s);
|
||||
@ -49,4 +50,7 @@ void printFloat_RateValue(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
|
18
probe.c
18
probe.c
@ -19,22 +19,30 @@
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
#include "settings.h"
|
||||
#include "probe.h"
|
||||
|
||||
// Inverts the probe pin state depending on user settings.
|
||||
uint8_t probe_invert_mask;
|
||||
|
||||
|
||||
// Probe pin initialization routine.
|
||||
void probe_init()
|
||||
{
|
||||
PROBE_DDR &= ~(PROBE_MASK); // Configure as input pins
|
||||
PROBE_PORT |= PROBE_MASK; // Enable internal pull-up resistors. Normal high operation.
|
||||
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_invert_mask = PROBE_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Returns the probe pin state. Triggered = true. Called by gcode parser and probe state monitor.
|
||||
uint8_t probe_get_state()
|
||||
{
|
||||
return(!(PROBE_PIN & PROBE_MASK));
|
||||
}
|
||||
uint8_t probe_get_state() { return((PROBE_PIN & PROBE_MASK) ^ probe_invert_mask); }
|
||||
|
||||
|
||||
// Monitors probe pin state and records the system position when detected. Called by the
|
||||
// stepper ISR per ISR tick.
|
||||
|
@ -136,7 +136,7 @@ void protocol_main_loop()
|
||||
// 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.
|
||||
|
||||
} 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.
|
||||
report_status_message(STATUS_OVERFLOW);
|
||||
iscomment = false;
|
||||
|
@ -28,7 +28,7 @@
|
||||
// memory space we can invest into here or we re-write the g-code parser not to have this
|
||||
// buffer.
|
||||
#ifndef LINE_BUFFER_SIZE
|
||||
#define LINE_BUFFER_SIZE 70
|
||||
#define LINE_BUFFER_SIZE 80
|
||||
#endif
|
||||
|
||||
// Starts Grbl main loop. It handles all incoming characters from the serial port and executes
|
||||
|
149
report.c
149
report.c
@ -35,6 +35,7 @@
|
||||
#include "planner.h"
|
||||
#include "spindle_control.h"
|
||||
#include "stepper.h"
|
||||
#include "serial.h"
|
||||
|
||||
|
||||
// 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"));
|
||||
}
|
||||
|
||||
|
||||
// Grbl global settings print out.
|
||||
// NOTE: The numbering scheme here must correlate to storing in settings.c
|
||||
void report_grbl_settings() {
|
||||
printPgmString(PSTR("$0=")); printFloat_SettingValue(settings.steps_per_mm[X_AXIS]);
|
||||
printPgmString(PSTR(" (x, step/mm)\r\n$1=")); printFloat_SettingValue(settings.steps_per_mm[Y_AXIS]);
|
||||
printPgmString(PSTR(" (y, step/mm)\r\n$2=")); printFloat_SettingValue(settings.steps_per_mm[Z_AXIS]);
|
||||
printPgmString(PSTR(" (z, step/mm)\r\n$3=")); printFloat_SettingValue(settings.max_rate[X_AXIS]);
|
||||
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);
|
||||
// Print Grbl settings.
|
||||
printPgmString(PSTR("$0=")); print_uint8_base10(settings.pulse_microseconds);
|
||||
printPgmString(PSTR(" (step pulse, usec)\r\n$1=")); print_uint8_base10(settings.stepper_idle_lock_time);
|
||||
printPgmString(PSTR(" (step idle delay, msec)\r\n$2=")); print_uint8_base10(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(")\r\n$15=")); print_uint8_base10(settings.stepper_idle_lock_time);
|
||||
printPgmString(PSTR(" (step idle delay, msec)\r\n$16=")); printFloat_SettingValue(settings.junction_deviation);
|
||||
printPgmString(PSTR(" (junction deviation, mm)\r\n$17=")); printFloat_SettingValue(settings.arc_tolerance);
|
||||
printPgmString(PSTR(" (arc tolerance, mm)\r\n$19=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_REPORT_INCHES));
|
||||
printPgmString(PSTR(" (report inches, bool)\r\n$20=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_AUTO_START));
|
||||
printPgmString(PSTR(" (auto start, bool)\r\n$21=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE));
|
||||
printPgmString(PSTR(" (invert step enable, bool)\r\n$22=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_INVERT_LIMIT_PINS));
|
||||
printPgmString(PSTR(" (invert limit pins, bool)\r\n$23=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_SOFT_LIMIT_ENABLE));
|
||||
printPgmString(PSTR(" (soft limits, bool)\r\n$24=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE));
|
||||
printPgmString(PSTR(" (hard limits, bool)\r\n$25=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE));
|
||||
printPgmString(PSTR(" (homing cycle, bool)\r\n$26=")); print_uint8_base10(settings.homing_dir_mask);
|
||||
printPgmString(PSTR(")\r\n$4=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE));
|
||||
printPgmString(PSTR(" (step enable invert, bool)\r\n$5=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_INVERT_LIMIT_PINS));
|
||||
printPgmString(PSTR(" (limit pins invert, bool)\r\n$6=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_INVERT_PROBE_PIN));
|
||||
printPgmString(PSTR(" (probe pin invert, bool)\r\n$10=")); print_uint8_base10(settings.status_report_mask);
|
||||
printPgmString(PSTR(" (status report mask:")); print_uint8_base2(settings.status_report_mask);
|
||||
printPgmString(PSTR(")\r\n$11=")); printFloat_SettingValue(settings.junction_deviation);
|
||||
printPgmString(PSTR(" (junction deviation, mm)\r\n$12=")); printFloat_SettingValue(settings.arc_tolerance);
|
||||
printPgmString(PSTR(" (arc tolerance, mm)\r\n$13=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_REPORT_INCHES));
|
||||
printPgmString(PSTR(" (report inches, bool)\r\n$14=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_AUTO_START));
|
||||
printPgmString(PSTR(" (auto start, bool)\r\n$20=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_SOFT_LIMIT_ENABLE));
|
||||
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(")\r\n$27=")); printFloat_SettingValue(settings.homing_feed_rate);
|
||||
printPgmString(PSTR(" (homing feed, mm/min)\r\n$28=")); 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 debounce, msec)\r\n$30=")); printFloat_SettingValue(settings.homing_pulloff);
|
||||
printPgmString(PSTR(" (homing pull-off, mm)\r\n"));
|
||||
printPgmString(PSTR(")\r\n$24=")); printFloat_SettingValue(settings.homing_feed_rate);
|
||||
printPgmString(PSTR(" (homing feed, mm/min)\r\n$25=")); printFloat_SettingValue(settings.homing_seek_rate);
|
||||
printPgmString(PSTR(" (homing seek, mm/min)\r\n$26=")); print_uint8_base10(settings.homing_debounce_delay);
|
||||
printPgmString(PSTR(" (homing debounce, msec)\r\n$27=")); printFloat_SettingValue(settings.homing_pulloff);
|
||||
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,38 +379,54 @@ void report_realtime_status()
|
||||
}
|
||||
|
||||
// Report machine position
|
||||
printPgmString(PSTR(",MPos:"));
|
||||
for (i=0; i< N_AXIS; i++) {
|
||||
print_position[i] = current_position[i]/settings.steps_per_mm[i];
|
||||
printFloat_CoordValue(print_position[i]);
|
||||
printPgmString(PSTR(","));
|
||||
if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_MACHINE_POSITION)) {
|
||||
printPgmString(PSTR(",MPos:"));
|
||||
for (i=0; i< N_AXIS; i++) {
|
||||
print_position[i] = current_position[i]/settings.steps_per_mm[i];
|
||||
printFloat_CoordValue(print_position[i]);
|
||||
if (i < (N_AXIS-1)) { printPgmString(PSTR(",")); }
|
||||
}
|
||||
}
|
||||
|
||||
// Report work position
|
||||
printPgmString(PSTR("WPos:"));
|
||||
for (i=0; i< N_AXIS; 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; }
|
||||
printFloat_CoordValue(print_position[i]);
|
||||
if (i < (N_AXIS-1)) { printPgmString(PSTR(",")); }
|
||||
if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_WORK_POSITION)) {
|
||||
printPgmString(PSTR(",WPos:"));
|
||||
for (i=0; i< N_AXIS; 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; }
|
||||
printFloat_CoordValue(print_position[i]);
|
||||
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
|
||||
// Report current line number
|
||||
printPgmString(PSTR(",Ln:"));
|
||||
int32_t ln=0;
|
||||
plan_block_t * pb = plan_get_current_block();
|
||||
if(pb != NULL) {
|
||||
ln = pb->line_number;
|
||||
}
|
||||
printInteger(ln);
|
||||
// Report current line number
|
||||
printPgmString(PSTR(",Ln:"));
|
||||
int32_t ln=0;
|
||||
plan_block_t * pb = plan_get_current_block();
|
||||
if(pb != NULL) {
|
||||
ln = pb->line_number;
|
||||
}
|
||||
printInteger(ln);
|
||||
#endif
|
||||
|
||||
#ifdef REPORT_REALTIME_RATE
|
||||
// Report realtime rate
|
||||
printPgmString(PSTR(",F:"));
|
||||
printFloat_RateValue(st_get_realtime_rate());
|
||||
#endif
|
||||
// Report realtime rate
|
||||
printPgmString(PSTR(",F:"));
|
||||
printFloat_RateValue(st_get_realtime_rate());
|
||||
#endif
|
||||
|
||||
printPgmString(PSTR(">\r\n"));
|
||||
}
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -1,2 +0,0 @@
|
||||
#!/usr/bin/ruby
|
||||
require 'script/stream'
|
@ -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
|
@ -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
|
@ -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
|
||||
segments directly into the planner. So there may not be a response
|
||||
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 time
|
||||
|
||||
# Open grbl serial port
|
||||
s = serial.Serial('/dev/tty.usbmodem1811',9600)
|
||||
s = serial.Serial('/dev/tty.usbmodem1811',115200)
|
||||
|
||||
# Open g-code file
|
||||
f = open('grbl.gcode','r');
|
||||
|
@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
"""\
|
||||
|
||||
Stream g-code to grbl controller
|
||||
|
||||
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
|
||||
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
|
||||
@ -31,6 +59,8 @@ parser.add_argument('device_file',
|
||||
help='serial device path')
|
||||
parser.add_argument('-q','--quiet',action='store_true', default=False,
|
||||
help='suppress output text')
|
||||
parser.add_argument('-s','--settings',action='store_true', default=False,
|
||||
help='settings write mode')
|
||||
args = parser.parse_args()
|
||||
|
||||
# Periodic timer to query for status reports
|
||||
@ -41,10 +71,12 @@ args = parser.parse_args()
|
||||
# t.start()
|
||||
|
||||
# Initialize
|
||||
s = serial.Serial(args.device_file,9600)
|
||||
s = serial.Serial(args.device_file,115200)
|
||||
f = args.gcode_file
|
||||
verbose = True
|
||||
if args.quiet : verbose = False
|
||||
settings_mode = False
|
||||
if args.settings : settings_mode = True
|
||||
|
||||
# Wake up grbl
|
||||
print "Initializing grbl..."
|
||||
@ -55,29 +87,46 @@ time.sleep(2)
|
||||
s.flushInput()
|
||||
|
||||
# Stream g-code to grbl
|
||||
print "Streaming ", args.gcode_file.name, " to ", args.device_file
|
||||
l_count = 0
|
||||
g_count = 0
|
||||
c_line = []
|
||||
# periodic() # Start status report periodic timer
|
||||
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()
|
||||
c_line.append(len(l_block)+1) # Track number of characters in grbl serial read buffer
|
||||
grbl_out = ''
|
||||
while sum(c_line) >= RX_BUFFER_SIZE-1 | s.inWaiting() :
|
||||
out_temp = s.readline().strip() # Wait for grbl response
|
||||
if out_temp.find('ok') < 0 and out_temp.find('error') < 0 :
|
||||
print " Debug: ",out_temp # Debug response
|
||||
else :
|
||||
grbl_out += out_temp;
|
||||
g_count += 1 # Iterate g-code counter
|
||||
grbl_out += str(g_count); # Add line finished indicator
|
||||
del c_line[0]
|
||||
if verbose: print "SND: " + str(l_count) + " : " + l_block,
|
||||
s.write(l_block + '\n') # Send block to grbl
|
||||
if verbose : print "BUF:",str(sum(c_line)),"REC:",grbl_out
|
||||
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
|
||||
c_line = []
|
||||
# periodic() # Start status report periodic timer
|
||||
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()
|
||||
c_line.append(len(l_block)+1) # Track number of characters in grbl serial read buffer
|
||||
grbl_out = ''
|
||||
while sum(c_line) >= RX_BUFFER_SIZE-1 | s.inWaiting() :
|
||||
out_temp = s.readline().strip() # Wait for grbl response
|
||||
if out_temp.find('ok') < 0 and out_temp.find('error') < 0 :
|
||||
print " Debug: ",out_temp # Debug response
|
||||
else :
|
||||
grbl_out += out_temp;
|
||||
g_count += 1 # Iterate g-code counter
|
||||
grbl_out += str(g_count); # Add line finished indicator
|
||||
del c_line[0] # Delete the block character count corresponding to the last 'ok'
|
||||
if verbose: print "SND: " + str(l_count) + " : " + l_block,
|
||||
s.write(l_block + '\n') # Send g-code block to grbl
|
||||
if verbose : print "BUF:",str(sum(c_line)),"REC:",grbl_out
|
||||
|
||||
# Wait for user input after streaming is completed
|
||||
print "G-code streaming finished!\n"
|
||||
|
81
serial.c
81
serial.c
@ -29,27 +29,37 @@
|
||||
#include "protocol.h"
|
||||
|
||||
|
||||
uint8_t rx_buffer[RX_BUFFER_SIZE];
|
||||
uint8_t rx_buffer_head = 0;
|
||||
volatile uint8_t rx_buffer_tail = 0;
|
||||
uint8_t serial_rx_buffer[RX_BUFFER_SIZE];
|
||||
uint8_t serial_rx_buffer_head = 0;
|
||||
volatile uint8_t serial_rx_buffer_tail = 0;
|
||||
|
||||
uint8_t tx_buffer[TX_BUFFER_SIZE];
|
||||
uint8_t tx_buffer_head = 0;
|
||||
volatile uint8_t tx_buffer_tail = 0;
|
||||
uint8_t serial_tx_buffer[TX_BUFFER_SIZE];
|
||||
uint8_t serial_tx_buffer_head = 0;
|
||||
volatile uint8_t serial_tx_buffer_tail = 0;
|
||||
|
||||
|
||||
#ifdef ENABLE_XONXOFF
|
||||
volatile uint8_t flow_ctrl = XON_SENT; // Flow control state variable
|
||||
|
||||
// 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
|
||||
|
||||
|
||||
// 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()
|
||||
@ -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) {
|
||||
// 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; }
|
||||
|
||||
// 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.
|
||||
}
|
||||
|
||||
// Store data and advance head
|
||||
tx_buffer[tx_buffer_head] = data;
|
||||
tx_buffer_head = next_head;
|
||||
serial_tx_buffer[serial_tx_buffer_head] = data;
|
||||
serial_tx_buffer_head = next_head;
|
||||
|
||||
// Enable Data Register Empty Interrupt to make sure tx-streaming is running
|
||||
UCSR0B |= (1 << UDRIE0);
|
||||
@ -98,7 +110,7 @@ void serial_write(uint8_t data) {
|
||||
// Data Register Empty Interrupt handler
|
||||
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
|
||||
if (flow_ctrl == SEND_XOFF) {
|
||||
@ -111,34 +123,35 @@ ISR(SERIAL_UDRE)
|
||||
#endif
|
||||
{
|
||||
// Send a byte from the buffer
|
||||
UDR0 = tx_buffer[tail];
|
||||
UDR0 = serial_tx_buffer[tail];
|
||||
|
||||
// Update tail position
|
||||
tail++;
|
||||
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
|
||||
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 tail = rx_buffer_tail; // Temporary rx_buffer_tail (to optimize for volatile)
|
||||
if (rx_buffer_head == tail) {
|
||||
uint8_t tail = serial_rx_buffer_tail; // Temporary serial_rx_buffer_tail (to optimize for volatile)
|
||||
if (serial_rx_buffer_head == tail) {
|
||||
return SERIAL_NO_DATA;
|
||||
} else {
|
||||
uint8_t data = rx_buffer[tail];
|
||||
uint8_t data = serial_rx_buffer[tail];
|
||||
|
||||
tail++;
|
||||
if (tail == RX_BUFFER_SIZE) { tail = 0; }
|
||||
rx_buffer_tail = tail;
|
||||
serial_rx_buffer_tail = tail;
|
||||
|
||||
#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;
|
||||
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_RESET: mc_reset(); break; // Call motion control reset routine.
|
||||
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; }
|
||||
|
||||
// Write data to buffer unless it is full.
|
||||
if (next_head != rx_buffer_tail) {
|
||||
rx_buffer[rx_buffer_head] = data;
|
||||
rx_buffer_head = next_head;
|
||||
if (next_head != serial_rx_buffer_tail) {
|
||||
serial_rx_buffer[serial_rx_buffer_head] = data;
|
||||
serial_rx_buffer_head = next_head;
|
||||
|
||||
#ifdef ENABLE_XONXOFF
|
||||
if ((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;
|
||||
UCSR0B |= (1 << UDRIE0); // Force TX
|
||||
}
|
||||
@ -185,7 +198,7 @@ ISR(SERIAL_RX)
|
||||
|
||||
void serial_reset_read_buffer()
|
||||
{
|
||||
rx_buffer_tail = rx_buffer_head;
|
||||
serial_rx_buffer_tail = serial_rx_buffer_head;
|
||||
|
||||
#ifdef ENABLE_XONXOFF
|
||||
flow_ctrl = XON_SENT;
|
||||
|
9
serial.h
9
serial.h
@ -48,11 +48,20 @@
|
||||
|
||||
void serial_init();
|
||||
|
||||
// Writes one byte to the TX serial buffer. Called by main program.
|
||||
void serial_write(uint8_t data);
|
||||
|
||||
// Fetches the first byte in the serial read buffer. Called by main program.
|
||||
uint8_t serial_read();
|
||||
|
||||
// Reset and empty data in read buffer. Used by e-stop and reset.
|
||||
void serial_reset_read_buffer();
|
||||
|
||||
// Returns the number of bytes 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
|
||||
|
205
settings.c
205
settings.c
@ -62,20 +62,19 @@ void write_global_settings()
|
||||
|
||||
// Method to reset Grbl global settings back to defaults.
|
||||
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.max_rate[X_AXIS] = DEFAULT_X_MAX_RATE;
|
||||
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.stepper_idle_lock_time = DEFAULT_STEPPER_IDLE_LOCK_TIME;
|
||||
settings.step_invert_mask = DEFAULT_STEPPING_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.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;
|
||||
if (DEFAULT_REPORT_INCHES) { settings.flags |= BITFLAG_REPORT_INCHES; }
|
||||
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_HARD_LIMIT_ENABLE) { settings.flags |= BITFLAG_HARD_LIMIT_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.homing_seek_rate = DEFAULT_HOMING_SEEK_RATE;
|
||||
settings.homing_debounce_delay = DEFAULT_HOMING_DEBOUNCE_DELAY;
|
||||
settings.homing_pulloff = DEFAULT_HOMING_PULLOFF;
|
||||
settings.stepper_idle_lock_time = DEFAULT_STEPPER_IDLE_LOCK_TIME;
|
||||
|
||||
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.max_rate[X_AXIS] = DEFAULT_X_MAX_RATE;
|
||||
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[Y_AXIS] = (-DEFAULT_Y_MAX_TRAVEL);
|
||||
settings.max_travel[Z_AXIS] = (-DEFAULT_Z_MAX_TRAVEL);
|
||||
|
||||
write_global_settings();
|
||||
}
|
||||
|
||||
@ -158,69 +162,89 @@ uint8_t read_global_settings() {
|
||||
|
||||
|
||||
// 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); }
|
||||
switch(parameter) {
|
||||
case 0: case 1: case 2:
|
||||
settings.steps_per_mm[parameter] = value; break;
|
||||
case 3: settings.max_rate[X_AXIS] = value; break;
|
||||
case 4: settings.max_rate[Y_AXIS] = value; break;
|
||||
case 5: settings.max_rate[Z_AXIS] = value; break;
|
||||
case 6: settings.acceleration[X_AXIS] = value*60*60; break; // Convert to mm/min^2 for grbl internal use.
|
||||
case 7: settings.acceleration[Y_AXIS] = value*60*60; break; // Convert to mm/min^2 for grbl internal use.
|
||||
case 8: settings.acceleration[Z_AXIS] = value*60*60; break; // Convert to mm/min^2 for grbl internal use.
|
||||
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; }
|
||||
break;
|
||||
case 22: // Reset to ensure change. Immediate re-init may cause problems.
|
||||
if (value) { settings.flags |= BITFLAG_INVERT_LIMIT_PINS; }
|
||||
else { settings.flags &= ~BITFLAG_INVERT_LIMIT_PINS; }
|
||||
break;
|
||||
case 23:
|
||||
if (value) {
|
||||
if (bit_isfalse(settings.flags, BITFLAG_HOMING_ENABLE)) { return(STATUS_SOFT_LIMIT_ERROR); }
|
||||
settings.flags |= BITFLAG_SOFT_LIMIT_ENABLE;
|
||||
} else { settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; }
|
||||
break;
|
||||
case 24:
|
||||
if (value) { 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.
|
||||
break;
|
||||
case 25:
|
||||
if (value) { settings.flags |= BITFLAG_HOMING_ENABLE; }
|
||||
else {
|
||||
settings.flags &= ~BITFLAG_HOMING_ENABLE;
|
||||
settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; // Force disable soft-limits.
|
||||
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;
|
||||
}
|
||||
break;
|
||||
case 26: settings.homing_dir_mask = trunc(value); break;
|
||||
case 27: settings.homing_feed_rate = value; break;
|
||||
case 28: settings.homing_seek_rate = value; break;
|
||||
case 29: settings.homing_debounce_delay = round(value); break;
|
||||
case 30: settings.homing_pulloff = value; break;
|
||||
default:
|
||||
return(STATUS_INVALID_STATEMENT);
|
||||
}
|
||||
} else {
|
||||
// Store non-axis Grbl settings
|
||||
uint8_t int_value = trunc(value);
|
||||
switch(parameter) {
|
||||
case 0:
|
||||
if (int_value < 3) { return(STATUS_SETTING_STEP_PULSE_MIN); }
|
||||
settings.pulse_microseconds = int_value; break;
|
||||
case 1: settings.stepper_idle_lock_time = int_value; break;
|
||||
case 2: settings.step_invert_mask = int_value; break;
|
||||
case 3: settings.dir_invert_mask = int_value; break;
|
||||
case 4: // Reset to ensure change. Immediate re-init may cause problems.
|
||||
if (int_value) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; }
|
||||
else { settings.flags &= ~BITFLAG_INVERT_ST_ENABLE; }
|
||||
break;
|
||||
case 5: // Reset to ensure change. Immediate re-init may cause problems.
|
||||
if (int_value) { settings.flags |= BITFLAG_INVERT_LIMIT_PINS; }
|
||||
else { settings.flags &= ~BITFLAG_INVERT_LIMIT_PINS; }
|
||||
break;
|
||||
case 6: // Reset to ensure change. Immediate re-init may cause problems.
|
||||
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); }
|
||||
settings.flags |= BITFLAG_SOFT_LIMIT_ENABLE;
|
||||
} else { settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; }
|
||||
break;
|
||||
case 21:
|
||||
if (int_value) { 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.
|
||||
break;
|
||||
case 22:
|
||||
if (int_value) { settings.flags |= BITFLAG_HOMING_ENABLE; }
|
||||
else {
|
||||
settings.flags &= ~BITFLAG_HOMING_ENABLE;
|
||||
settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; // Force disable soft-limits.
|
||||
}
|
||||
break;
|
||||
case 23: settings.homing_dir_mask = int_value; break;
|
||||
case 24: settings.homing_feed_rate = value; break;
|
||||
case 25: settings.homing_seek_rate = value; break;
|
||||
case 26: settings.homing_debounce_delay = int_value; break;
|
||||
case 27: settings.homing_pulloff = value; break;
|
||||
default:
|
||||
return(STATUS_INVALID_STATEMENT);
|
||||
}
|
||||
}
|
||||
write_global_settings();
|
||||
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.
|
||||
}
|
||||
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
41
settings.h
41
settings.h
@ -22,15 +22,13 @@
|
||||
#ifndef settings_h
|
||||
#define settings_h
|
||||
|
||||
#include "system.h"
|
||||
|
||||
|
||||
#define GRBL_VERSION "0.9f"
|
||||
#define GRBL_VERSION_BUILD "20140706"
|
||||
#define GRBL_VERSION "0.9g"
|
||||
#define GRBL_VERSION_BUILD "20140725"
|
||||
|
||||
// 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
|
||||
#define SETTINGS_VERSION 8
|
||||
#define SETTINGS_VERSION 9
|
||||
|
||||
// Define bit flag masks for the boolean settings in settings.flag.
|
||||
#define BITFLAG_REPORT_INCHES bit(0)
|
||||
@ -40,6 +38,13 @@
|
||||
#define BITFLAG_HOMING_ENABLE bit(4)
|
||||
#define BITFLAG_SOFT_LIMIT_ENABLE bit(5)
|
||||
#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
|
||||
// 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_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)
|
||||
typedef struct {
|
||||
// Axis settings
|
||||
float steps_per_mm[N_AXIS];
|
||||
float max_rate[N_AXIS];
|
||||
float acceleration[N_AXIS];
|
||||
float max_travel[N_AXIS];
|
||||
|
||||
// Remaining Grbl settings
|
||||
uint8_t pulse_microseconds;
|
||||
uint8_t step_invert_mask;
|
||||
uint8_t dir_invert_mask;
|
||||
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 arc_tolerance;
|
||||
|
||||
uint8_t flags; // Contains default boolean settings
|
||||
|
||||
uint8_t homing_dir_mask;
|
||||
float homing_feed_rate;
|
||||
float homing_seek_rate;
|
||||
uint16_t homing_debounce_delay;
|
||||
float homing_pulloff;
|
||||
// uint8_t status_report_mask; // Mask to indicate desired report data.
|
||||
} settings_t;
|
||||
extern settings_t settings;
|
||||
|
||||
@ -84,7 +99,7 @@ extern settings_t settings;
|
||||
void settings_init();
|
||||
|
||||
// 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
|
||||
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
|
||||
uint8_t settings_read_startup_line(uint8_t n, char *line);
|
||||
|
||||
// Stores build info user-defined string
|
||||
void settings_store_build_info(char *line);
|
||||
|
||||
// Reads build info user-defined string
|
||||
uint8_t settings_read_build_info(char *line);
|
||||
|
||||
// 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
|
||||
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
|
||||
|
@ -77,6 +77,7 @@ void spindle_run(uint8_t direction, float rpm)
|
||||
}
|
||||
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
// TODO: Install the optional capability for frequency-based output for servos.
|
||||
#define SPINDLE_RPM_RANGE (SPINDLE_MAX_RPM-SPINDLE_MIN_RPM)
|
||||
TCCRA_REGISTER = (1<<COMB_BIT) | (1<<WAVE1_REGISTER) | (1<<WAVE0_REGISTER);
|
||||
TCCRB_REGISTER = (TCCRB_REGISTER & 0b11111000) | 0x02; // set to 1/8 Prescaler
|
||||
|
48
stepper.c
48
stepper.c
@ -109,6 +109,10 @@ static volatile uint8_t segment_buffer_tail;
|
||||
static uint8_t segment_buffer_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.
|
||||
static volatile uint8_t busy;
|
||||
|
||||
@ -189,8 +193,8 @@ void st_wake_up()
|
||||
|
||||
if (sys.state & (STATE_CYCLE | STATE_HOMING)){
|
||||
// Initialize stepper output bits
|
||||
st.dir_outbits = settings.dir_invert_mask;
|
||||
st.step_outbits = settings.step_invert_mask;
|
||||
st.dir_outbits = dir_port_invert_mask;
|
||||
st.step_outbits = step_port_invert_mask;
|
||||
|
||||
// Initialize step pulse timing from settings. Here to ensure updating after re-writing.
|
||||
#ifdef STEP_PULSE_DELAY
|
||||
@ -330,7 +334,7 @@ ISR(TIMER1_COMPA_vect)
|
||||
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
|
||||
// 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; }
|
||||
}
|
||||
|
||||
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;
|
||||
// SPINDLE_ENABLE_PORT ^= 1<<SPINDLE_ENABLE_BIT; // Debug: Used to time ISR
|
||||
}
|
||||
@ -419,7 +423,7 @@ ISR(TIMER1_COMPA_vect)
|
||||
ISR(TIMER0_OVF_vect)
|
||||
{
|
||||
// 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.
|
||||
}
|
||||
#ifdef STEP_PULSE_DELAY
|
||||
@ -441,15 +445,28 @@ void st_reset()
|
||||
// Initialize stepper driver idle state.
|
||||
st_go_idle();
|
||||
|
||||
// Initialize stepper algorithm variables.
|
||||
memset(&prep, 0, sizeof(prep));
|
||||
memset(&st, 0, sizeof(st));
|
||||
st.exec_segment = NULL;
|
||||
pl_block = NULL; // Planner block pointer used by segment buffer
|
||||
|
||||
segment_buffer_tail = 0;
|
||||
segment_buffer_head = 0; // empty = tail
|
||||
segment_next_head = 1;
|
||||
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
|
||||
STEP_DDR |= STEP_MASK;
|
||||
STEP_PORT = (STEP_PORT & ~STEP_MASK) | settings.step_invert_mask;
|
||||
STEPPERS_DISABLE_DDR |= 1<<STEPPERS_DISABLE_BIT;
|
||||
DIRECTION_DDR |= DIRECTION_MASK;
|
||||
DIRECTION_PORT = (DIRECTION_PORT & ~DIRECTION_MASK) | settings.dir_invert_mask;
|
||||
|
||||
// Configure Timer 1: Stepper Driver Interrupt
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -827,13 +839,13 @@ void st_prep_buffer()
|
||||
// in the segment buffer. It will always be behind by up to the number of segment blocks (-1)
|
||||
// divided by the ACCELERATION TICKS PER SECOND in seconds.
|
||||
#ifdef REPORT_REALTIME_RATE
|
||||
float st_get_realtime_rate()
|
||||
{
|
||||
if (sys.state & (STATE_CYCLE | STATE_HOMING)){
|
||||
return prep.current_speed;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
float st_get_realtime_rate()
|
||||
{
|
||||
if (sys.state & (STATE_CYCLE | STATE_HOMING | STATE_HOLD)){
|
||||
return prep.current_speed;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
2
system.c
2
system.c
@ -193,7 +193,7 @@ uint8_t system_execute_line(char *line)
|
||||
} else { // Store global setting.
|
||||
if(!read_float(line, &char_counter, &value)) { return(STATUS_BAD_NUMBER_FORMAT); }
|
||||
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
4919
test/gcode/8x_gear_test.nc
Normal file
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@ G0X0.000Y0.000S8000M3
|
||||
G0X0.000Y-33.519Z6.000
|
||||
G1Z-1.000
|
||||
G1X0.327Y-33.521
|
||||
F1000.0
|
||||
F7000.0
|
||||
X0.654Y-33.526
|
||||
X0.980Y-33.534
|
||||
X1.304Y-33.546
|
||||
|
31
test/settings/kikigey89.settings
Normal file
31
test/settings/kikigey89.settings
Normal 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)
|
Loading…
Reference in New Issue
Block a user