diff --git a/config.h b/config.h index 614fcd1..9df2677 100644 --- a/config.h +++ b/config.h @@ -29,7 +29,7 @@ #define config_h // Default settings. Used when resetting EEPROM. Change to desired name in defaults.h -#define DEFAULTS_ZEN_TOOLWORKS_7x7 +#define DEFAULTS_SHERLINE_5400 // Serial baud rate #define BAUD_RATE 115200 @@ -49,76 +49,17 @@ #define CMD_CYCLE_START '~' #define CMD_RESET 0x18 // ctrl-x -// 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 inverse time algorithm can use either floating point or long integers for its counters (usually -// very small values ~10^-6), but with integers, the counter values must be scaled to be greater than -// one. This multiplier value scales the floating point counter values for use in a long integer, which -// are significantly faster to compute with a slightly higher precision ceiling than floats. Long -// integers are finite so select the multiplier value high enough to avoid any numerical round-off -// issues and still have enough range to account for all motion types. However, in most all imaginable -// CNC applications, the following multiplier value will work more than well enough. If you do have -// happened to weird stepper motion issues, try modifying this value by adding or subtracting a -// zero and report it to the Grbl administrators. -#define INV_TIME_MULTIPLIER 100000 - -// Minimum stepper rate for the "Stepper Driver Interrupt". Sets the absolute minimum stepper rate -// in the stepper program and never runs slower than this value. If the INVE_TIME_MULTIPLIER value -// changes, it will affect how this value works. So, if a zero is add/subtracted from the -// INV_TIME_MULTIPLIER value, do the same to this value if you want to same response. -// NOTE: Compute by (desired_step_rate/60) * INV_TIME_MULTIPLIER/ISR_TICKS_PER_SECOND. (mm/min) -// #define MINIMUM_STEP_RATE 1000L // Integer (mult*mm/isr_tic) - -// Minimum stepper rate. Only used by homing at this point. May be removed in later releases. -#define MINIMUM_STEPS_PER_MINUTE 800 // (steps/min) - Integer value only - -// 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 -// zero. This value controls how fast the machine moves through junctions with no regard for acceleration -// limits or angle between neighboring block line move directions. This is useful for machines that can't -// tolerate the tool dwelling for a split second, i.e. 3d printers or laser cutters. If used, this value -// should not be much greater than zero or to the minimum value necessary for the machine to work. -#define MINIMUM_JUNCTION_SPEED 0.0 // (mm/min) - -// 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 -// this delay will increase the maximum dwell time linearly, but also reduces the responsiveness of -// run-time command executions, like status reports, since these are performed between each dwell -// time step. Also, keep in mind that the Arduino delay timer is not very accurate for long delays. -#define DWELL_TIME_STEP 50 // Integer (1-255) (milliseconds) +// 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 // 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 // mainly a safety feature to remind the user to home, since position is unknown to Grbl. #define HOMING_INIT_LOCK // Comment to disable -// The homing cycle seek and feed rates will adjust so all axes independently move at the homing -// seek and feed rates regardless of how many axes are in motion simultaneously. If disabled, rates -// are point-to-point rates, as done in normal operation. For example in an XY diagonal motion, the -// diagonal motion moves at the intended rate, but the individual axes move at 70% speed. This option -// just moves them all at 100% speed. -#define HOMING_RATE_ADJUST // Comment to disable - // Define the homing cycle search patterns with bitmasks. The homing cycle first performs a search // to engage the limit switches. HOMING_SEARCH_CYCLE_x are executed in order starting with suffix 0 // and searches the enabled axes in the bitmask. This allows for users with non-standard cartesian @@ -144,6 +85,39 @@ // parser state depending on user preferences. #define N_STARTUP_LINE 2 // Integer (1-5) +// --------------------------------------------------------------------------------------- +// 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) + +// 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 +// zero. This value controls how fast the machine moves through junctions with no regard for acceleration +// limits or angle between neighboring block line move directions. This is useful for machines that can't +// tolerate the tool dwelling for a split second, i.e. 3d printers or laser cutters. If used, this value +// should not be much greater than zero or to the minimum value necessary for the machine to work. +#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 @@ -151,8 +125,12 @@ // computational efficiency of generating arcs. #define N_ARC_CORRECTION 20 // Integer (1-255) -// --------------------------------------------------------------------------------------- -// FOR ADVANCED USERS ONLY: +// 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 +// this delay will increase the maximum dwell time linearly, but also reduces the responsiveness of +// run-time command executions, like status reports, since these are performed between each dwell +// time step. Also, keep in mind that the Arduino delay timer is not very accurate for long delays. +#define DWELL_TIME_STEP 50 // Integer (1-255) (milliseconds) // The number of linear motions in the planner buffer to be planned at any give time. The vast // majority of RAM that Grbl uses is based on this buffer size. Only increase if there is extra @@ -198,11 +176,6 @@ // case, please report any successes to grbl administrators! // #define ENABLE_XONXOFF // Default disabled. Uncomment to enable. -// 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 // --------------------------------------------------------------------------------------- diff --git a/defaults.h b/defaults.h index d71ce09..bfbb88e 100644 --- a/defaults.h +++ b/defaults.h @@ -56,8 +56,8 @@ #define DEFAULT_HOMING_ENABLE 0 // false #define DEFAULT_HOMING_DIR_MASK 0 // move positive dir #define DEFAULT_HOMING_FEED_RATE 25.0 // mm/min - #define DEFAULT_HOMING_SEEK_RATE 250.0 // mm/min - #define DEFAULT_HOMING_DEBOUNCE_DELAY 100 // msec (0-65k) + #define DEFAULT_HOMING_SEEK_RATE 500.0 // mm/min + #define DEFAULT_HOMING_DEBOUNCE_DELAY 250 // msec (0-65k) #define DEFAULT_HOMING_PULLOFF 1.0 // mm #endif @@ -76,9 +76,9 @@ #define DEFAULT_X_ACCELERATION (50.0*60*60) // 10 mm/min^2 #define DEFAULT_Y_ACCELERATION (50.0*60*60) // 10 mm/min^2 #define DEFAULT_Z_ACCELERATION (50.0*60*60) // 10 mm/min^2 - #define DEFAULT_X_MAX_TRAVEL 200.0 // mm - #define DEFAULT_Y_MAX_TRAVEL 200.0 // mm - #define DEFAULT_Z_MAX_TRAVEL 200.0 // mm + #define DEFAULT_X_MAX_TRAVEL 225.0 // mm + #define DEFAULT_Y_MAX_TRAVEL 125.0 // mm + #define DEFAULT_Z_MAX_TRAVEL 170.0 // mm #define DEFAULT_STEP_PULSE_MICROSECONDS 10 #define DEFAULT_FEEDRATE 254.0 // mm/min (10 ipm) #define DEFAULT_STEPPING_INVERT_MASK ((1< dt_min) { dt = dt_min; } // Disable acceleration for very slow rates. - - // Set default out_bits. - uint8_t out_bits0 = settings.invert_mask; - out_bits0 ^= (settings.homing_dir_mask & DIRECTION_MASK); // Apply homing direction settings - if (!pos_dir) { out_bits0 ^= DIRECTION_MASK; } // Invert bits, if negative dir. - - // Initialize stepping variables - int32_t counter_x = -(step_event_count >> 1); // Bresenham counters - int32_t counter_y = counter_x; - int32_t counter_z = counter_x; - uint32_t step_delay = dt-settings.pulse_microseconds; // Step delay after pulse - uint32_t step_rate = 0; // Tracks step rate. Initialized from 0 rate. (in step/min) - uint32_t trap_counter = MICROSECONDS_PER_ACCELERATION_TICK/2; // Acceleration trapezoid counter - uint8_t out_bits; + if (sys.execute & EXEC_RESET) { return; } uint8_t limit_state; - for(;;) { + #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. + 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. + + // Setup homing axis locks based on cycle mask. + uint8_t axislock = (STEPPING_MASK & ~STEP_MASK); + if (bit_istrue(cycle_mask,bit(X_AXIS))) { axislock |= (1< 0) { - if (limit_state & (1< 0) { - if (limit_state & (1< 0) { - if (limit_state & (1< dt_min) { // Unless cruising, check for time update. - trap_counter += dt; // Track time passed since last update. - if (trap_counter > MICROSECONDS_PER_ACCELERATION_TICK) { - trap_counter -= MICROSECONDS_PER_ACCELERATION_TICK; - step_rate += delta_rate; // Increment velocity - dt = (1000000*60)/step_rate; // Compute new time increment - if (dt < dt_min) {dt = dt_min;} // If target rate reached, cruise. - step_delay = dt-settings.pulse_microseconds; - } + if (axislock & (1< 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); } } - - st_go_idle(); // Call main stepper shutdown routine. } diff --git a/nuts_bolts.h b/nuts_bolts.h index 3c5c951..59aeff6 100644 --- a/nuts_bolts.h +++ b/nuts_bolts.h @@ -89,6 +89,7 @@ typedef struct { uint8_t abort; // System abort flag. Forces exit back to main loop for reset. uint8_t state; // Tracks the current state of Grbl. volatile uint8_t execute; // Global system runtime executor bitflag variable. See EXEC bitmasks. + uint8_t homing_axis_lock; int32_t position[N_AXIS]; // Real-time machine (aka home) position vector in steps. // NOTE: This may need to be a volatile variable, if problems arise. uint8_t auto_start; // Planner auto-start flag. Toggled off during feed hold. Defaulted by settings. diff --git a/planner.c b/planner.c index 1fc8e1a..d4b4326 100644 --- a/planner.c +++ b/planner.c @@ -326,7 +326,7 @@ void plan_buffer_line(float *target, float feed_rate, uint8_t invert_feed_rate) for (idx=0; idxdist_per_tick; // Execute Bresenham step event, when it's time to do so. - if (st.counter_dist > INV_TIME_MULTIPLIER) { + if (st.counter_dist > STEP_FTOL_MULTIPLIER) { if (st.step_count > 0) { // Block phase correction from executing step. - st.counter_dist -= INV_TIME_MULTIPLIER; // Reload inverse time counter + st.counter_dist -= STEP_FTOL_MULTIPLIER; // Reload inverse time counter st.step_count--; // Decrement step events count // Execute step displacement profile by Bresenham line algorithm st.execute_step = true; - st.out_bits = st.exec_block->direction_bits; // Reset out_bits and reload direction bits + st.out_bits = st.exec_block->direction_bits; // Reset out_bits and reload direction bits st.counter_x -= st.exec_block->steps[X_AXIS]; if (st.counter_x < 0) { st.out_bits |= (1<step_event_count; prep.step_per_mm = prep.steps_remaining/pl_block->millimeters; - if (sys.state == STATE_HOLD) { + if (sys.state == STATE_HOLD) { + // Override planner block entry speed and enforce deceleration during feed hold. prep.current_speed = prep.exit_speed; pl_block->entry_speed_sqr = prep.exit_speed*prep.exit_speed; } @@ -497,7 +503,7 @@ void st_prep_buffer() planner has updated it. For a commanded forced-deceleration, such as from a feed hold, override the planner velocities and decelerate to the target exit speed. */ - prep.mm_complete = 0.0; + prep.mm_complete = 0.0; // Default velocity profile complete at 0.0mm from end of block. float inv_2_accel = 0.5/pl_block->acceleration; if (sys.state == STATE_HOLD) { // Compute velocity profile parameters for a feed hold in-progress. This profile overrides @@ -506,7 +512,7 @@ void st_prep_buffer() float decel_dist = inv_2_accel*pl_block->entry_speed_sqr; if (decel_dist < pl_block->millimeters) { prep.exit_speed = 0.0; - prep.mm_complete = pl_block->millimeters-decel_dist; + prep.mm_complete = pl_block->millimeters-decel_dist; // End of feed hold. } else { prep.exit_speed = sqrt(pl_block->entry_speed_sqr-2*pl_block->acceleration*pl_block->millimeters); } @@ -634,13 +640,13 @@ void st_prep_buffer() supported by Grbl (i.e. exceeding 10 meters axis travel at 200 step/mm). */ // Use time_var to pre-compute dt inversion with integer multiplier. - time_var = (INV_TIME_MULTIPLIER/(60.0*ISR_TICKS_PER_SECOND))/dt; // (mult/isr_tic) + time_var = (STEP_FTOL_MULTIPLIER/(60.0*ISR_TICKS_PER_SECOND))/dt; // (ftol_mult/isr_tic) if (mm_remaining > 0.0) { // Block still incomplete. Distance remaining to be executed. float steps_remaining = prep.step_per_mm*mm_remaining; - prep_segment->dist_per_tick = ceil( (prep.steps_remaining-steps_remaining)*time_var ); // (mult*step/isr_tic) + prep_segment->dist_per_tick = ceil( (prep.steps_remaining-steps_remaining)*time_var ); // (ftol_mult*step/isr_tic) // Compute number of steps to execute and segment step phase correction. - prep_segment->phase_dist = ceil(INV_TIME_MULTIPLIER*(ceil(steps_remaining)-steps_remaining)); + prep_segment->phase_dist = ceil(STEP_FTOL_MULTIPLIER*(ceil(steps_remaining)-steps_remaining)); prep_segment->n_step = ceil(prep.steps_remaining)-ceil(steps_remaining); // Update step execution variables. @@ -648,7 +654,7 @@ void st_prep_buffer() // NOTE: Currently only feed holds qualify for this scenario. May change with overrides. prep.current_speed = 0.0; prep.steps_remaining = ceil(steps_remaining); - pl_block->millimeters = prep.steps_remaining/prep.step_per_mm; + pl_block->millimeters = prep.steps_remaining/prep.step_per_mm; // Update with full steps. plan_cycle_reinitialize(); sys.state = STATE_QUEUED; // End cycle. } else { @@ -682,12 +688,14 @@ void st_prep_buffer() // int32_t blength = segment_buffer_head - segment_buffer_tail; // if (blength < 0) { blength += SEGMENT_BUFFER_SIZE; } // printInteger(blength); + + if ((sys.state == STATE_HOMING) || (sys.state == STATE_QUEUED)) { return; } // Force only one prepped segment. } } /* TODO: With feedrate overrides, increases to the override value will not significantly - change the planner and stepper current operation. When the value increases, we simply + change the current planner and stepper operation. When the value increases, we simply need to recompute the block plan with new nominal speeds and maximum junction velocities. However with a decreasing feedrate override, this gets a little tricky. The current block plan is optimal, so if we try to reduce the feed rates, it may be impossible to create @@ -704,4 +712,10 @@ void st_prep_buffer() equal to the block maximum speed and is in an acceleration or cruising ramp. At this point, we know that we can recompute the block velocity profile to meet and continue onto the new block plan. + One "easy" way to do this is to have the step segment buffer enforce a deceleration and + continually re-plan the planner buffer until the plan becomes feasible. This can work + and may be easy to implement, but it expends a lot of CPU cycles and may block out the + rest of the functions from operating at peak efficiency. Still the question is how do + we know when the plan is feasible in the context of what's already in the code and not + require too much more code? */