Merge branch 'dev' of https://github.com/grbl/grbl into dev
Conflicts: limits.c
This commit is contained in:
168
limits.c
168
limits.c
@ -22,6 +22,7 @@
|
||||
#include <util/delay.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/wdt.h>
|
||||
#include "stepper.h"
|
||||
#include "settings.h"
|
||||
#include "nuts_bolts.h"
|
||||
@ -40,17 +41,29 @@ void limits_init()
|
||||
|
||||
#ifndef LIMIT_SWITCHES_ACTIVE_HIGH
|
||||
LIMIT_PORT |= (LIMIT_MASK); // Enable internal pull-up resistors. Normal high operation.
|
||||
#else // LIMIT_SWITCHES_ACTIVE_HIGH
|
||||
#else
|
||||
LIMIT_PORT &= ~(LIMIT_MASK); // Normal low operation. Requires external pull-down.
|
||||
#endif // !LIMIT_SWITCHES_ACTIVE_HIGH
|
||||
#endif
|
||||
|
||||
if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) {
|
||||
LIMIT_PCMSK |= LIMIT_MASK; // Enable specific pins of the Pin Change Interrupt
|
||||
PCICR |= (1 << LIMIT_INT); // Enable Pin Change Interrupt
|
||||
} else {
|
||||
LIMIT_PCMSK &= ~LIMIT_MASK; // Disable
|
||||
PCICR &= ~(1 << LIMIT_INT);
|
||||
limits_disable();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SOFTWARE_DEBOUNCE
|
||||
MCUSR &= ~(1<<WDRF);
|
||||
WDTCSR |= (1<<WDCE) | (1<<WDE);
|
||||
WDTCSR = (1<<WDP0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void limits_disable()
|
||||
{
|
||||
LIMIT_PCMSK &= ~LIMIT_MASK; // Disable specific pins of the Pin Change Interrupt
|
||||
PCICR &= ~(1 << LIMIT_INT); // Disable Pin Change Interrupt
|
||||
}
|
||||
|
||||
|
||||
@ -63,48 +76,83 @@ void limits_init()
|
||||
// homing cycles and will not respond correctly. Upon user request or need, there may be a
|
||||
// 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.
|
||||
ISR(LIMIT_INT_vect)
|
||||
{
|
||||
// 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.
|
||||
sys.execute |= EXEC_CRIT_EVENT; // Indicate hard limit critical event
|
||||
}
|
||||
#ifdef ENABLE_SOFTWARE_DEBOUNCE
|
||||
ISR(LIMIT_INT_vect) { if (!(WDTCSR & (1<<WDIE))) { WDTCSR |= (1<<WDIE); } }
|
||||
ISR(WDT_vect)
|
||||
{
|
||||
WDTCSR &= ~(1<<WDIE);
|
||||
// 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)) {
|
||||
#ifndef LIMIT_SWITCHES_ACTIVE_HIGH
|
||||
if ((LIMIT_PIN & LIMIT_MASK) ^ LIMIT_MASK) {
|
||||
#else
|
||||
if (LIMIT_PIN & LIMIT_MASK) {
|
||||
#endif
|
||||
mc_reset(); // Initiate system kill.
|
||||
sys.execute |= EXEC_CRIT_EVENT; // Indicate hard limit critical event
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
ISR(LIMIT_INT_vect)
|
||||
{
|
||||
// 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.
|
||||
sys.execute |= EXEC_CRIT_EVENT; // Indicate hard limit critical event
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Moves all specified axes in same specified direction (positive=true, negative=false)
|
||||
// and at the homing rate. Homing is a special motion case, where there is only an
|
||||
// acceleration followed by abrupt asynchronous stops by each axes reaching their limit
|
||||
// switch independently. Instead of shoehorning homing cycles into the main stepper
|
||||
// algorithm and overcomplicate things, a stripped-down, lite version of the stepper
|
||||
// algorithm is written here. This also lets users hack and tune this code freely for
|
||||
// their own particular needs without affecting the rest of Grbl.
|
||||
// Moves specified cycle axes all at homing rate, either approaching or disengaging the limit
|
||||
// switches. Homing is a special motion case, where there is only an acceleration followed
|
||||
// by abrupt asynchronous stops by each axes reaching their limit switch independently. The
|
||||
// asynchronous stops are handled by a system level axis lock mask, which prevents the stepper
|
||||
// algorithm from executing step pulses.
|
||||
// NOTE: Only the abort runtime command can interrupt this process.
|
||||
static void homing_cycle(uint8_t cycle_mask, bool pos_dir, bool invert_pin, float homing_rate)
|
||||
void limits_go_home(uint8_t cycle_mask, bool approach, bool invert_pin, float homing_rate)
|
||||
{
|
||||
if (sys.execute & EXEC_RESET) { return; }
|
||||
uint8_t limit_state;
|
||||
#ifndef LIMIT_SWITCHES_ACTIVE_HIGH
|
||||
invert_pin = !invert_pin;
|
||||
#endif
|
||||
|
||||
// Compute target location for homing all axes. Homing axis lock will freeze non-cycle axes.
|
||||
// Determine travel distance to the furthest homing switch based on user max travel settings.
|
||||
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]; }
|
||||
max_travel *= 1.25; // Ensure homing switches engaged by over-estimating max travel.
|
||||
if (approach) { max_travel = -max_travel; }
|
||||
|
||||
// Set target location and rate for active axes.
|
||||
float target[N_AXIS];
|
||||
target[X_AXIS] = settings.max_travel[X_AXIS];
|
||||
if (target[X_AXIS] < settings.max_travel[Y_AXIS]) { target[X_AXIS] = settings.max_travel[Y_AXIS]; }
|
||||
if (target[X_AXIS] < settings.max_travel[Z_AXIS]) { target[X_AXIS] = settings.max_travel[Z_AXIS]; }
|
||||
target[X_AXIS] *= 2.0;
|
||||
if (pos_dir) { target[X_AXIS] = -target[X_AXIS]; }
|
||||
target[Y_AXIS] = target[X_AXIS];
|
||||
target[Z_AXIS] = target[X_AXIS];
|
||||
homing_rate *= 1.7320; // [sqrt(N_AXIS)] Adjust so individual axes all move at homing rate.
|
||||
uint8_t n_active_axis = 0;
|
||||
uint8_t i;
|
||||
for (i=0; i<N_AXIS; i++) {
|
||||
if (bit_istrue(cycle_mask,bit(i))) {
|
||||
n_active_axis++;
|
||||
target[i] = max_travel;
|
||||
} else {
|
||||
target[i] = 0.0;
|
||||
}
|
||||
}
|
||||
if (bit_istrue(settings.homing_dir_mask,(1<<X_LIMIT_BIT))) { target[X_AXIS] = -target[X_AXIS]; }
|
||||
if (bit_istrue(settings.homing_dir_mask,(1<<Y_LIMIT_BIT))) { target[Y_AXIS] = -target[Y_AXIS]; }
|
||||
if (bit_istrue(settings.homing_dir_mask,(1<<Z_LIMIT_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.
|
||||
|
||||
// Setup homing axis locks based on cycle mask.
|
||||
uint8_t axislock = (STEPPING_MASK & ~STEP_MASK);
|
||||
@ -117,55 +165,27 @@ static void homing_cycle(uint8_t cycle_mask, bool pos_dir, bool invert_pin, floa
|
||||
plan_buffer_line(target, homing_rate, false); // Bypass mc_line(). Directly plan homing motion.
|
||||
st_prep_buffer(); // Prep first segment from newly planned block.
|
||||
st_wake_up(); // Initiate motion
|
||||
while (STEP_MASK & axislock) {
|
||||
// Check limit state.
|
||||
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 (axislock & (1<<X_STEP_BIT)) {
|
||||
if (limit_state & (1<<X_LIMIT_BIT)) { axislock &= ~(1<<X_STEP_BIT); }
|
||||
}
|
||||
if (axislock & (1<<Y_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 (axislock & (1<<Z_STEP_BIT)) {
|
||||
if (limit_state & (1<<Z_LIMIT_BIT)) { axislock &= ~(1<<Z_STEP_BIT); }
|
||||
}
|
||||
// }
|
||||
sys.homing_axis_lock = axislock;
|
||||
st_prep_buffer(); // Check and prep one segment. NOTE: Should take no longer than 200us.
|
||||
if (sys.execute & EXEC_RESET) { return; }
|
||||
}
|
||||
} while (STEP_MASK & axislock);
|
||||
st_go_idle(); // Disable steppers. Axes motion should already be locked.
|
||||
plan_init(); // Reset planner buffer. Ensure homing motion is cleared.
|
||||
plan_reset(); // Reset planner buffer. Ensure homing motion is cleared.
|
||||
st_reset(); // Reset step segment buffer. Ensure homing motion is cleared.
|
||||
delay_ms(settings.homing_debounce_delay);
|
||||
}
|
||||
|
||||
|
||||
void limits_go_home()
|
||||
{
|
||||
plan_init(); // Reset planner buffer before beginning homing cycles.
|
||||
|
||||
// Search to engage all axes limit switches at faster homing seek rate.
|
||||
homing_cycle(HOMING_SEARCH_CYCLE_0, true, false, settings.homing_seek_rate); // Search cycle 0
|
||||
#ifdef HOMING_SEARCH_CYCLE_1
|
||||
homing_cycle(HOMING_SEARCH_CYCLE_1, true, false, settings.homing_seek_rate); // Search cycle 1
|
||||
#endif
|
||||
#ifdef HOMING_SEARCH_CYCLE_2
|
||||
homing_cycle(HOMING_SEARCH_CYCLE_2, true, false, settings.homing_seek_rate); // Search cycle 2
|
||||
#endif
|
||||
|
||||
// Now in proximity of all limits. Carefully leave and approach switches in multiple cycles
|
||||
// to precisely hone in on the machine zero location. Moves at slower homing feed rate.
|
||||
int8_t n_cycle = N_HOMING_LOCATE_CYCLE;
|
||||
while (n_cycle--) {
|
||||
// Leave all switches to release them. After cycles complete, this is machine zero.
|
||||
homing_cycle(HOMING_LOCATE_CYCLE, false, true, settings.homing_feed_rate);
|
||||
|
||||
if (n_cycle > 0) {
|
||||
// Re-approach all switches to re-engage them.
|
||||
homing_cycle(HOMING_LOCATE_CYCLE, true, false, settings.homing_feed_rate);
|
||||
}
|
||||
}
|
||||
delay_ms(settings.homing_debounce_delay); // Delay to allow transient dynamics to dissipate.
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user