Critical M0/2/30 fix. Homing updates.

- Critical fix for M0 program pause. Due to its recent change, it would
cause Grbl to suspend but wouldn’t notify the user of why Grbl was not
doing anything. The state would show IDLE and a cycle start would
resume it. Grbl now enters a HOLD state to better indicate the state
change.

- Critical fix for M2 and M30 program end. As with M0, the state
previously would show IDLE while suspended. Grbl now does not suspend
upon program end and leaves job control to the GUI. Grbl simply reports
a `[Pgm End]` as a feedback message and resets certain g-code modes.

- M2/30 g-code reseting fix. Previously Grbl would soft-reset after an
M2/30, but this was not complaint to the (linuxcnc) g-code standard. It
simply resets [G1,G17,G90,G94,G40,G54,M5,M9,M48] and keeps all other
modes the same.

- M0/M2/M30 check-mode fix. It now does not suspend the machine during
check-mode.

- Minor bug fix related to commands similar to G90.1, but not G90.1,
not reporting an unsupported command.

- Homing cycle refactoring. To help reduce the chance of users
misunderstanding their limit switch wiring, Grbl only moves a short
distance for the locate cycles only. In addition, the homing cycle
pulls-off the limit switch by the pull-off distance to re-engage and
locate home. This should improve its accuracy.

- HOMING_FORCE_ORIGIN now sets the origin to the pull-off location,
rather than where the limit switch was triggered.

- Updated default junction deviation to 0.01mm. Recent tests showed
that this improves Grbl’s cornering behavior a bit.

- Added the ShapeOko3 defaults.

- Added new feedback message `[Pgm End]` for M2/30 notification.

- Limit pin reporting is now a $10 status report option. Requested by
OEMs to help simplify support troubleshooting.
This commit is contained in:
Sonny Jeon
2015-05-17 13:25:36 -06:00
parent 4c20a2173f
commit 664854b9df
11 changed files with 201 additions and 131 deletions

View File

@ -22,9 +22,13 @@
#include "grbl.h"
// 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.
// Homing axis search distance multiplier. Computed by this value times the cycle travel.
#ifndef HOMING_AXIS_SEARCH_SCALAR
#define HOMING_AXIS_SEARCH_SCALAR 1.5 // Must be > 1 to ensure limit switch will be engaged.
#endif
#ifndef HOMING_AXIS_LOCATE_SCALAR
#define HOMING_AXIS_LOCATE_SCALAR 5.0 // Must be > 1 to ensure limit switch is cleared.
#endif
void limits_init()
{
@ -126,16 +130,12 @@ void limits_go_home(uint8_t cycle_mask)
{
if (sys.abort) { return; } // Block if system reset has been issued.
// Initialize homing in search mode to quickly engage the specified cycle_mask limit switches.
bool approach = true;
float homing_rate = settings.homing_seek_rate;
uint8_t invert_pin, idx;
// Initialize
uint8_t n_cycle = (2*N_HOMING_LOCATE_CYCLE+1);
float target[N_AXIS];
uint8_t limit_pin[N_AXIS], step_pin[N_AXIS];
float target[N_AXIS];
float max_travel = 0.0;
uint8_t idx;
for (idx=0; idx<N_AXIS; idx++) {
// Initialize limit and step pin masks
limit_pin[idx] = get_limit_pin_mask(idx);
@ -149,32 +149,33 @@ void limits_go_home(uint8_t cycle_mask)
// NOTE: settings.max_travel[] is stored as a negative value.
max_travel = max(max_travel,(-HOMING_AXIS_SEARCH_SCALAR)*settings.max_travel[idx]);
}
}
plan_reset(); // Reset planner buffer to zero planner current position and to clear previous motions.
plan_sync_position(); // Sync planner position to current machine position.
// Set search mode with approach at seek rate to quickly engage the specified cycle_mask limit switches.
bool approach = true;
float homing_rate = settings.homing_seek_rate;
uint8_t limit_state, axislock, n_active_axis;
do {
// Initialize invert_pin boolean based on approach and invert pin user setting.
if (bit_isfalse(settings.flags,BITFLAG_INVERT_LIMIT_PINS)) { invert_pin = approach; }
else { invert_pin = !approach; }
system_convert_array_steps_to_mpos(target,sys.position);
// Initialize and declare variables needed for homing routine.
uint8_t axislock = 0;
uint8_t n_active_axis = 0;
system_convert_array_steps_to_mpos(target,sys.position);
axislock = 0;
n_active_axis = 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))) {
if (bit_istrue(cycle_mask,bit(idx))) {
n_active_axis++;
sys.position[idx] = 0;
// Set target direction based on cycle mask and homing cycle approach state.
// NOTE: This happens to compile smaller than any other implementation tried.
if (bit_istrue(settings.homing_dir_mask,bit(idx))) {
if (approach) { target[idx] -= max_travel; }
else { target[idx] += max_travel; }
if (approach) { target[idx] = -max_travel; }
else { target[idx] = max_travel; }
} else {
if (approach) { target[idx] += max_travel; }
else { target[idx] -= max_travel; }
if (approach) { target[idx] = max_travel; }
else { target[idx] = -max_travel; }
}
// Apply axislock to the step port pins active in this cycle.
axislock |= step_pin[idx];
@ -183,10 +184,10 @@ void limits_go_home(uint8_t cycle_mask)
}
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;
plan_sync_position(); // Sync planner position to current machine position.
// Perform homing cycle. Planner buffer should be empty, as required to initiate the homing cycle.
#ifdef USE_LINE_NUMBERS
plan_buffer_line(target, homing_rate, false, HOMING_CYCLE_LINE_NUMBER); // Bypass mc_line(). Directly plan homing motion.
#else
@ -195,36 +196,53 @@ void limits_go_home(uint8_t cycle_mask)
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; }
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.
do {
if (approach) {
// Check limit state. Lock out cycle axes when they change.
limit_state = LIMIT_PIN;
if (bit_isfalse(settings.flags,BITFLAG_INVERT_LIMIT_PINS)) { limit_state ^= LIMIT_MASK; }
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.
// Exit routines: User abort homing and alarm upon safety door or no limit switch found.
// No time to run protocol_execute_realtime() in this loop.
if (sys.rt_exec_state & (EXEC_SAFETY_DOOR | EXEC_RESET | EXEC_CYCLE_STOP)) {
if ((sys.rt_exec_state & (EXEC_SAFETY_DOOR | EXEC_RESET)) ||
((approach) && (sys.rt_exec_state & EXEC_CYCLE_STOP))) {
mc_reset();
protocol_execute_realtime();
return;
} else {
bit_false_atomic(sys.rt_exec_state,EXEC_CYCLE_STOP);
break;
}
}
} while (STEP_MASK & axislock);
// Exit routines: User abort homing and alarm upon safety door or no limit switch found.
// No time to run protocol_execute_realtime() in this loop.
if (sys.rt_exec_state & (EXEC_SAFETY_DOOR | EXEC_RESET | EXEC_CYCLE_STOP)) {
if (sys.rt_exec_state & (EXEC_SAFETY_DOOR | EXEC_CYCLE_STOP)) { mc_reset(); }
protocol_execute_realtime();
return;
}
} while (STEP_MASK & axislock);
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
plan_reset(); // Reset planner buffer to zero planner current position and to clear previous motions.
delay_ms(settings.homing_debounce_delay); // Delay to allow transient dynamics to dissipate.
// Reverse direction and reset homing rate for locate cycle(s).
homing_rate = settings.homing_feed_rate;
approach = !approach;
// After first cycle, homing enters locating phase. Shorten search to pull-off distance.
if (approach) {
max_travel = settings.homing_pulloff*HOMING_AXIS_LOCATE_SCALAR;
homing_rate = settings.homing_feed_rate;
} else {
max_travel = settings.homing_pulloff;
homing_rate = settings.homing_seek_rate;
}
} while (n_cycle-- > 0);
@ -242,13 +260,16 @@ void limits_go_home(uint8_t cycle_mask)
for (idx=0; idx<N_AXIS; idx++) {
// NOTE: settings.max_travel[] is stored as a negative value.
if (cycle_mask & bit(idx)) {
set_axis_position = 0;
#ifndef HOMING_FORCE_SET_ORIGIN
#ifdef HOMING_FORCE_SET_ORIGIN
set_axis_position = 0;
#else
if ( bit_istrue(settings.homing_dir_mask,bit(idx)) ) {
set_axis_position = lround(settings.max_travel[idx]*settings.steps_per_mm[idx]);
set_axis_position = lround((settings.max_travel[idx]+settings.homing_pulloff)*settings.steps_per_mm[idx]);
} else {
set_axis_position = lround(-settings.homing_pulloff*settings.steps_per_mm[idx]);
}
#endif
#ifdef COREXY
if (idx==X_AXIS) {
off_axis_position = (sys.position[B_MOTOR] - sys.position[A_MOTOR])/2;
@ -268,39 +289,6 @@ void limits_go_home(uint8_t cycle_mask)
}
}
plan_sync_position(); // Sync planner position to homed machine position.
// Set pull-off motion target. Seperated from above loop if target is dependent on sys.position.
if (settings.homing_pulloff > 0.0) {
for (idx=0; idx<N_AXIS; idx++) {
if (cycle_mask & bit(idx)) {
#ifdef HOMING_FORCE_SET_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];
} else {
target[idx] = -settings.homing_pulloff;
}
#endif
} else {
// Non-active cycle axis. Set target to not move during pull-off.
target[idx] = system_convert_axis_steps_to_mpos(sys.position, idx);
}
}
#ifdef USE_LINE_NUMBERS
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.
#endif
// Initiate pull-off using main motion control routines.
// TODO : Clean up state routines so that this motion still shows homing state.
sys.state = STATE_IDLE;
bit_true_atomic(sys.rt_exec_state, EXEC_CYCLE_START);
protocol_execute_realtime();
protocol_buffer_synchronize(); // Complete pull-off motion.
}
// Set system state to homing before returning.
sys.state = STATE_HOMING;