Skip to content

Commit

Permalink
Merge branch 'dev' of https://github.com/grbl/grbl into dev
Browse files Browse the repository at this point in the history
Conflicts:
	limits.c
  • Loading branch information
chamnit committed Dec 30, 2013
1 parent 3054b2d commit 903b462
Show file tree
Hide file tree
Showing 14 changed files with 416 additions and 318 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Grbl includes full acceleration management with look ahead. That means the contr
- Soft limits: Checks if any motion command exceeds workspace limits. Alarms out when found. Another safety feature, but, unlike hard limits, position does not get lost, as it forces a feed hold before erroring out.
- Pin mapping: In an effort for Grbl to be compatible with other AVR architectures, such as the 1280 or 2560, a new pin_map.h 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: 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.
- Homing routine updated: Sets workspace volume in all negative space regardless of limit switch position. Common on pro CNCs. Also reduces soft limits CPU overhead.
- Homing routine updated: 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.
- Feedrate overrides: In the works, but planner has begun to be re-factored for this feature.
- Jogging controls: Methodology needs to be to figured out first. Could be dropped due to flash space concerns. Last item on the agenda.

Expand Down
50 changes: 23 additions & 27 deletions config.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@
#define CMD_STATUS_REPORT '?'
#define CMD_FEED_HOLD '!'
#define CMD_CYCLE_START '~'
#define CMD_RESET 0x18 // ctrl-x
#define CMD_RESET 0x18 // ctrl-x.

// Uncomment the following define if you are using hardware that drives high when your limits
// are reached. You will need to ensure that you have appropriate pull-down resistors on the
// limit switch input pins, or that your hardware drives the pins low when they are open (non-
// triggered).
// #define LIMIT_SWITCHES_ACTIVE_HIGH
// #define LIMIT_SWITCHES_ACTIVE_HIGH // Uncomment to enable

// If homing is enabled, homing init lock sets Grbl into an alarm state upon power up. This forces
// the user to perform the homing cycle (or override the locks) before doing anything else. This is
Expand Down Expand Up @@ -88,27 +88,22 @@
// ---------------------------------------------------------------------------------------
// ADVANCED CONFIGURATION OPTIONS:

// The "Stepper Driver Interrupt" employs an inverse time algorithm to manage the Bresenham line
// stepping algorithm. The value ISR_TICKS_PER_SECOND is the frequency(Hz) at which the inverse time
// algorithm ticks at. Recommended step frequencies are limited by the inverse time frequency by
// approximately 0.75-0.9 * ISR_TICK_PER_SECOND. Meaning for 30kHz, the max step frequency is roughly
// 22.5-27kHz, but 30kHz is still possible, just not optimal. An Arduino can safely complete a single
// interrupt of the current stepper driver algorithm theoretically up to a frequency of 35-40kHz, but
// CPU overhead increases exponentially as this frequency goes up. So there will be little left for
// other processes like arcs.
#define ISR_TICKS_PER_SECOND 30000L // Integer (Hz)

// The temporal resolution of the acceleration management subsystem. Higher number give smoother
// acceleration but may impact performance. If you run at very high feedrates (>15kHz or so) and
// very high accelerations, this will reduce the error between how the planner plans the velocity
// profiles and how the stepper program actually performs them. The correct value for this parameter
// is machine dependent, so it's advised to set this only as high as needed. Approximate successful
// values can widely range from 50 to 200 or more. Cannot be greater than ISR_TICKS_PER_SECOND/2.
// NOTE: Ramp count variable type in stepper module may need to be updated if changed.
#define ACCELERATION_TICKS_PER_SECOND 120L

// NOTE: Make sure this value is less than 256, when adjusting both dependent parameters.
#define ISR_TICKS_PER_ACCELERATION_TICK (ISR_TICKS_PER_SECOND/ACCELERATION_TICKS_PER_SECOND)
// The temporal resolution of the acceleration management subsystem. A higher number gives smoother
// acceleration, particularly noticeable on machines that run at very high feedrates, but may negatively
// impact performance. The correct value for this parameter is machine dependent, so it's advised to
// set this only as high as needed. Approximate successful values can widely range from 50 to 200 or more.
#define ACCELERATION_TICKS_PER_SECOND 100

// Creates a delay between the direction pin setting and corresponding step pulse by creating
// another interrupt (Timer2 compare) to manage it. The main Grbl interrupt (Timer1 compare)
// sets the direction pins, and does not immediately set the stepper pins, as it would in
// normal operation. The Timer2 compare fires next to set the stepper pins after the step
// pulse delay time, and Timer2 overflow will complete the step pulse, except now delayed
// by the step pulse time plus the step pulse delay. (Thanks langwadt for the idea!)
// NOTE: Uncomment to enable. The recommended delay must be > 3us, and, when added with the
// user-supplied step pulse time, the total time must not exceed 127us. Reported successful
// values for certain setups have ranged from 5 to 20us.
// #define STEP_PULSE_DELAY 10 // Step pulse delay in microseconds. Default disabled.

// Minimum planner junction speed. Sets the default minimum junction speed the planner plans to at
// every buffer block junction, except for starting from rest and end of the buffer, which are always
Expand Down Expand Up @@ -145,7 +140,7 @@
// block velocity profile is traced exactly. The size of this buffer governs how much step
// execution lead time there is for other Grbl processes have to compute and do their thing
// before having to come back and refill this buffer, currently at ~50msec of step moves.
// #define SEGMENT_BUFFER_SIZE 7 // Uncomment to override default in stepper.h.
// #define SEGMENT_BUFFER_SIZE 6 // Uncomment to override default in stepper.h.

// Line buffer size from the serial input stream to be executed. Also, governs the size of
// each of the startup blocks, as they are each stored as a string of this size. Make sure
Expand Down Expand Up @@ -176,6 +171,7 @@
// case, please report any successes to grbl administrators!
// #define ENABLE_XONXOFF // Default disabled. Uncomment to enable.

#define ENABLE_SOFTWARE_DEBOUNCE

// ---------------------------------------------------------------------------------------

Expand All @@ -184,9 +180,9 @@
// ---------------------------------------------------------------------------------------
// COMPILE-TIME ERROR CHECKING OF DEFINE VALUES:

#if (ISR_TICKS_PER_ACCELERATION_TICK > 255)
#error Parameters ACCELERATION_TICKS / ISR_TICKS must be < 256 to prevent integer overflow.
#endif
// #if (ISR_TICKS_PER_ACCELERATION_TICK > 255)
// #error Parameters ACCELERATION_TICKS / ISR_TICKS must be < 256 to prevent integer overflow.
// #endif

// ---------------------------------------------------------------------------------------
#endif
168 changes: 94 additions & 74 deletions limits.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
}


Expand All @@ -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);
Expand All @@ -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.
}


Expand Down
6 changes: 4 additions & 2 deletions limits.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@
// Initialize the limits module
void limits_init();

// Perform the homing cycle
void limits_go_home();
void limits_disable();

// Perform one portion of the homing cycle based on the input settings.
void limits_go_home(uint8_t cycle_mask, bool approach, bool invert_pin, float homing_rate);

// Check for soft limit violations
void limits_soft_check(float *target);
Expand Down
Loading

0 comments on commit 903b462

Please sign in to comment.