Settings refactoring. Bug fixes. Misc new features.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

View File

@ -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
}