Fixed long slope at deceleration issue. Moved things into config.h. New MINIMUM_PLANNER_SPEED parameter.
- The long standing issue of a long slope at deceleration is likely fixed. The stepper program was not tracking and timing the end of acceleration and start of deceleration exactly and now is fixed to start and stop on time. Also, to ensure a better acceleration curve fit used by the planner, the stepper program delays the start of the accelerations by a half trapezoid tick to employ the midpoint rule. - Settings version 3 migration (not fully tested, but should work) - Added a MINIMUM_PLANNER_SPEED user-defined parameter to planner to let a user change this if problems arise for some reason. - Moved all user-definable #define parameters into config.h with clear comments on what they do and recommendations of how to change them. - Minor housekeeping.
This commit is contained in:
parent
6de805441f
commit
2be0d66872
38
config.h
38
config.h
@ -3,6 +3,7 @@
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
Copyright (c) 2011 Sungeun K. Jeon
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -21,6 +22,8 @@
|
||||
#ifndef config_h
|
||||
#define config_h
|
||||
|
||||
// IMPORTANT: Any changes here requires a full re-compiling of the source code to propagate them.
|
||||
|
||||
#define BAUD_RATE 9600
|
||||
|
||||
// Updated default pin-assignments from 0.6 onwards
|
||||
@ -55,12 +58,32 @@
|
||||
|
||||
// The temporal resolution of the acceleration management subsystem. Higher number
|
||||
// give smoother acceleration but may impact performance
|
||||
// NOTE: Increasing this parameter will help remove the long slow motion bug at the end
|
||||
// of very fast de/ac-celerations. This is due to the increased resolution of the
|
||||
// acceleration steps that more accurately predicted by the planner exact integration
|
||||
// of acceleration distance. An efficient solution to this bug is under investigation.
|
||||
// In general, setting this parameter is high as your system will allow is suggested.
|
||||
#define ACCELERATION_TICKS_PER_SECOND 40L
|
||||
// NOTE: Increasing this parameter will help any resolution related issues, especially with machines
|
||||
// requiring very high accelerations and/or very fast feedrates. In general, this will reduce the
|
||||
// error between how the planner plans the motions and how the stepper program actually performs them.
|
||||
// However, at some point, the resolution can be high enough, where the errors related to numerical
|
||||
// round-off can be great enough to cause problems and/or it's too fast for the Arduino. 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 range from 30L to 100L or more.
|
||||
#define ACCELERATION_TICKS_PER_SECOND 50L
|
||||
|
||||
// Minimum planner junction speed. Sets the default minimum speed the planner plans for at the end
|
||||
// of the buffer and all stops. This should not be much greater than zero and should only be changed
|
||||
// if unwanted behavior is observed on a user's machine when running at very slow speeds.
|
||||
#define MINIMUM_PLANNER_SPEED 0.0 // (mm/min)
|
||||
|
||||
// Minimum stepper rate. Sets the absolute minimum stepper rate in the stepper program and never run
|
||||
// slower than this value, except when sleeping. This parameter overrides the minimum planner speed.
|
||||
// This is primarily used to guarantee that the end of a movement is always reached and not stop to
|
||||
// never reach its target. This parameter should always be greater than zero.
|
||||
#define MINIMUM_STEPS_PER_MINUTE 800 // (steps/min) - Integer value only
|
||||
|
||||
// Number of arc generation iterations by small angle approximation before exact arc
|
||||
// trajectory correction. Value must be 1-255. 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 of grbl, and should be on the order or greater than the size of
|
||||
// the buffer to help with the computational efficiency of generating arcs.
|
||||
#define N_ARC_CORRECTION 25
|
||||
|
||||
#endif
|
||||
|
||||
@ -91,5 +114,4 @@
|
||||
//
|
||||
// #define SPINDLE_DIRECTION_DDR DDRD
|
||||
// #define SPINDLE_DIRECTION_PORT PORTD
|
||||
// #define SPINDLE_DIRECTION_BIT 7
|
||||
|
||||
// #define SPINDLE_DIRECTION_BIT 7
|
3
gcode.c
3
gcode.c
@ -388,5 +388,4 @@ static int next_statement(char *letter, double *double_ptr, char *line, uint8_t
|
||||
group 9 = {M48, M49} enable/disable feed and speed override switches
|
||||
group 12 = {G54, G55, G56, G57, G58, G59, G59.1, G59.2, G59.3} coordinate system selection
|
||||
group 13 = {G61, G61.1, G64} path control mode
|
||||
*/
|
||||
|
||||
*/
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include <avr/io.h>
|
||||
#include "settings.h"
|
||||
#include "config.h"
|
||||
#include "motion_control.h"
|
||||
#include <util/delay.h>
|
||||
#include <math.h>
|
||||
@ -29,11 +30,6 @@
|
||||
#include "stepper.h"
|
||||
#include "planner.h"
|
||||
|
||||
// Number of arc generation iterations with small angle approximation before exact arc
|
||||
// trajectory correction. Value must be 1-255.
|
||||
#define N_ARC_CORRECTION 25
|
||||
|
||||
|
||||
// Execute dwell in seconds. Maximum time delay is > 18 hours, more than enough for any application.
|
||||
void mc_dwell(double seconds)
|
||||
{
|
||||
@ -48,7 +44,7 @@ void mc_dwell(double seconds)
|
||||
|
||||
// Execute an arc in offset mode format. position == current xyz, target == target xyz,
|
||||
// offset == offset from current xyz, axis_XXX defines circle plane in tool space, axis_linear is
|
||||
// the direction of helical travel, radius == circle radius, clockwise_sign == -1 or 1. Used
|
||||
// the direction of helical travel, radius == circle radius, isclockwise boolean. Used
|
||||
// for vector transformation direction.
|
||||
// position, target, and offset are pointers to vectors from gcode.c
|
||||
|
||||
|
19
planner.c
19
planner.c
@ -193,6 +193,7 @@ static void planner_forward_pass() {
|
||||
// Calculates trapezoid parameters so that the entry- and exit-speed is compensated by the provided factors.
|
||||
// The factors represent a factor of braking and must be in the range 0.0-1.0.
|
||||
// This converts the planner parameters to the data required by the stepper controller.
|
||||
// NOTE: Final rates must be computed in terms of their respective blocks.
|
||||
static void calculate_trapezoid_for_block(block_t *block, double entry_factor, double exit_factor) {
|
||||
|
||||
block->initial_rate = ceil(block->nominal_rate*entry_factor); // (step/min)
|
||||
@ -212,6 +213,8 @@ static void calculate_trapezoid_for_block(block_t *block, double entry_factor, d
|
||||
if (plateau_steps < 0) {
|
||||
accelerate_steps = ceil(
|
||||
intersection_distance(block->initial_rate, block->final_rate, acceleration_per_minute, block->step_event_count));
|
||||
accelerate_steps = max(accelerate_steps,0); // Check limits due to numerical round-off
|
||||
accelerate_steps = min(accelerate_steps,block->step_event_count);
|
||||
plateau_steps = 0;
|
||||
}
|
||||
|
||||
@ -251,8 +254,9 @@ static void planner_recalculate_trapezoids() {
|
||||
}
|
||||
block_index = next_block_index( block_index );
|
||||
}
|
||||
// Last/newest block in buffer. Exit speed is zero. Always recalculated.
|
||||
calculate_trapezoid_for_block(next, next->entry_speed/next->nominal_speed, 0.0);
|
||||
// Last/newest block in buffer. Exit speed is set with MINIMUM_PLANNER_SPEED. Always recalculated.
|
||||
calculate_trapezoid_for_block(next, next->entry_speed/next->nominal_speed,
|
||||
MINIMUM_PLANNER_SPEED/next->nominal_speed);
|
||||
next->recalculate_flag = false;
|
||||
}
|
||||
|
||||
@ -273,6 +277,9 @@ static void planner_recalculate_trapezoids() {
|
||||
//
|
||||
// 3. Recalculate trapezoids for all blocks using the recently updated junction speeds. Block trapezoids
|
||||
// with no updated junction speeds will not be recalculated and assumed ok as is.
|
||||
//
|
||||
// All planner computations are performed with doubles (float on Arduinos) to minimize numerical round-
|
||||
// off errors. Only when planned values are converted to stepper rate parameters, these are integers.
|
||||
|
||||
static void planner_recalculate() {
|
||||
planner_reverse_pass();
|
||||
@ -396,7 +403,7 @@ void plan_buffer_line(double x, double y, double z, double feed_rate, uint8_t in
|
||||
// path width or max_jerk in the previous grbl version. This approach does not actually deviate
|
||||
// from path, but used as a robust way to compute cornering speeds, as it takes into account the
|
||||
// nonlinearities of both the junction angle and junction velocity.
|
||||
double vmax_junction = 0.0; // Set default zero max junction speed
|
||||
double vmax_junction = MINIMUM_PLANNER_SPEED; // Set default max junction speed
|
||||
|
||||
// Skip first block or when previous_nominal_speed is used as a flag for homing and offset cycles.
|
||||
if ((block_buffer_head != block_buffer_tail) && (previous_nominal_speed > 0.0)) {
|
||||
@ -420,8 +427,8 @@ void plan_buffer_line(double x, double y, double z, double feed_rate, uint8_t in
|
||||
}
|
||||
block->max_entry_speed = vmax_junction;
|
||||
|
||||
// Initialize block entry speed. Compute based on deceleration to rest (zero speed).
|
||||
double v_allowable = max_allowable_speed(-settings.acceleration,0.0,block->millimeters);
|
||||
// Initialize block entry speed. Compute based on deceleration to user-defined MINIMUM_PLANNER_SPEED.
|
||||
double v_allowable = max_allowable_speed(-settings.acceleration,MINIMUM_PLANNER_SPEED,block->millimeters);
|
||||
block->entry_speed = min(vmax_junction, v_allowable);
|
||||
|
||||
// Initialize planner efficiency flags
|
||||
@ -465,4 +472,4 @@ void plan_set_current_position(double x, double y, double z) {
|
||||
position[Z_AXIS] = lround(z*settings.steps_per_mm[Z_AXIS]);
|
||||
previous_nominal_speed = 0.0; // Resets planner junction speeds. Assumes start from rest.
|
||||
clear_vector_double(previous_unit_vec);
|
||||
}
|
||||
}
|
10
settings.c
10
settings.c
@ -80,7 +80,7 @@ void settings_dump() {
|
||||
printPgmString(PSTR(" (step port invert mask. binary = ")); printIntegerInBase(settings.invert_mask, 2);
|
||||
printPgmString(PSTR(")\r\n$8 = ")); printFloat(settings.acceleration);
|
||||
printPgmString(PSTR(" (acceleration in mm/sec^2)\r\n$9 = ")); printFloat(settings.junction_deviation);
|
||||
printPgmString(PSTR(" (junction deviation for cornering in mm)"));
|
||||
printPgmString(PSTR(" (cornering junction deviation in mm)"));
|
||||
printPgmString(PSTR("\r\n'$x=value' to set parameter or just '$' to dump current settings\r\n"));
|
||||
}
|
||||
|
||||
@ -125,12 +125,18 @@ int read_settings() {
|
||||
return(false);
|
||||
}
|
||||
} else if (version == 1) {
|
||||
// Migrate from old settings version
|
||||
// Migrate from settings version 1
|
||||
if (!(memcpy_from_eeprom_with_checksum((char*)&settings, 1, sizeof(settings_v1_t)))) {
|
||||
return(false);
|
||||
}
|
||||
settings.acceleration = DEFAULT_ACCELERATION;
|
||||
settings.junction_deviation = DEFAULT_JUNCTION_DEVIATION;
|
||||
} else if (version == 2) {
|
||||
// Migrate from settings version 2
|
||||
if (!(memcpy_from_eeprom_with_checksum((char*)&settings, 1, sizeof(settings_t)))) {
|
||||
return(false);
|
||||
}
|
||||
settings.junction_deviation = DEFAULT_JUNCTION_DEVIATION;
|
||||
} else {
|
||||
return(false);
|
||||
}
|
||||
|
125
stepper.c
125
stepper.c
@ -3,7 +3,8 @@
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
Modifications Copyright (c) 2011 Sungeun K. Jeon
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
@ -40,8 +41,6 @@
|
||||
#define TICKS_PER_MICROSECOND (F_CPU/1000000)
|
||||
#define CYCLES_PER_ACCELERATION_TICK ((TICKS_PER_MICROSECOND*1000000)/ACCELERATION_TICKS_PER_SECOND)
|
||||
|
||||
#define MINIMUM_STEPS_PER_MINUTE 1200 // The stepper subsystem will never run slower than this, exept when sleeping
|
||||
|
||||
static block_t *current_block; // A pointer to the block currently being traced
|
||||
|
||||
// Variables used by The Stepper Driver Interrupt
|
||||
@ -95,41 +94,27 @@ static void st_go_idle() {
|
||||
// block begins.
|
||||
static void trapezoid_generator_reset() {
|
||||
trapezoid_adjusted_rate = current_block->initial_rate;
|
||||
trapezoid_tick_cycle_counter = 0; // Always start a new trapezoid with a full acceleration tick
|
||||
set_step_events_per_minute(trapezoid_adjusted_rate);
|
||||
trapezoid_tick_cycle_counter = CYCLES_PER_ACCELERATION_TICK/2; // Start halfway for midpoint rule.
|
||||
set_step_events_per_minute(trapezoid_adjusted_rate); // Initialize cycles_per_step_event
|
||||
}
|
||||
|
||||
// This is called ACCELERATION_TICKS_PER_SECOND times per second by the step_event
|
||||
// interrupt. It can be assumed that the trapezoid-generator-parameters and the
|
||||
// current_block stays untouched by outside handlers for the duration of this function call.
|
||||
static void trapezoid_generator_tick() {
|
||||
if (current_block) {
|
||||
if (step_events_completed < current_block->accelerate_until) {
|
||||
trapezoid_adjusted_rate += current_block->rate_delta;
|
||||
set_step_events_per_minute(trapezoid_adjusted_rate);
|
||||
} else if (step_events_completed > current_block->decelerate_after) {
|
||||
// NOTE: We will only reduce speed if the result will be > 0. This catches small
|
||||
// rounding errors that might leave steps hanging after the last trapezoid tick.
|
||||
if (trapezoid_adjusted_rate > current_block->rate_delta) {
|
||||
trapezoid_adjusted_rate -= current_block->rate_delta;
|
||||
}
|
||||
if (trapezoid_adjusted_rate < current_block->final_rate) {
|
||||
trapezoid_adjusted_rate = current_block->final_rate;
|
||||
}
|
||||
set_step_events_per_minute(trapezoid_adjusted_rate);
|
||||
} else {
|
||||
// Make sure we cruise at exactly nominal rate
|
||||
if (trapezoid_adjusted_rate != current_block->nominal_rate) {
|
||||
trapezoid_adjusted_rate = current_block->nominal_rate;
|
||||
set_step_events_per_minute(trapezoid_adjusted_rate);
|
||||
}
|
||||
}
|
||||
// This function determines an acceleration velocity change every CYCLES_PER_ACCELERATION_TICK by
|
||||
// keeping track of the number of elapsed cycles during a de/ac-celeration. The code assumes that
|
||||
// step_events occur significantly more often than the acceleration velocity iterations.
|
||||
static uint8_t iterate_trapezoid_cycle_counter() {
|
||||
trapezoid_tick_cycle_counter += cycles_per_step_event;
|
||||
if(trapezoid_tick_cycle_counter > CYCLES_PER_ACCELERATION_TICK) {
|
||||
trapezoid_tick_cycle_counter -= CYCLES_PER_ACCELERATION_TICK;
|
||||
return(true);
|
||||
} else {
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse of Grbl. It is executed at the rate set with
|
||||
// config_step_timer. It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately.
|
||||
// It is supported by The Stepper Port Reset Interrupt which it uses to reset the stepper port after each pulse.
|
||||
// It is supported by The Stepper Port Reset Interrupt which it uses to reset the stepper port after each pulse.
|
||||
// The bresenham line tracer algorithm controls all three stepper outputs simultaneously with these two interrupts.
|
||||
SIGNAL(TIMER1_COMPA_vect)
|
||||
{
|
||||
// TODO: Check if the busy-flag can be eliminated by just disabeling this interrupt while we are in it
|
||||
@ -157,13 +142,14 @@ SIGNAL(TIMER1_COMPA_vect)
|
||||
counter_x = -(current_block->step_event_count >> 1);
|
||||
counter_y = counter_x;
|
||||
counter_z = counter_x;
|
||||
step_events_completed = 0;
|
||||
step_events_completed = 0;
|
||||
} else {
|
||||
st_go_idle();
|
||||
}
|
||||
}
|
||||
|
||||
if (current_block != NULL) {
|
||||
// Execute step displacement profile by bresenham line algorithm
|
||||
out_bits = current_block->direction_bits;
|
||||
counter_x += current_block->steps_x;
|
||||
if (counter_x > 0) {
|
||||
@ -180,26 +166,73 @@ SIGNAL(TIMER1_COMPA_vect)
|
||||
out_bits |= (1<<Z_STEP_BIT);
|
||||
counter_z -= current_block->step_event_count;
|
||||
}
|
||||
// If current block is finished, reset pointer
|
||||
step_events_completed += 1;
|
||||
if (step_events_completed >= current_block->step_event_count) {
|
||||
|
||||
step_events_completed += 1; // Iterate step events
|
||||
|
||||
// While in block steps, check for de/ac-celeration events and execute them accordingly.
|
||||
if (step_events_completed < current_block->step_event_count) {
|
||||
|
||||
// Always check step event location to ensure de/ac-celerations are executed and terminated at
|
||||
// exactly the right time. This helps prevent over/under-shooting the target position and speed.
|
||||
// Trapezoid de/ac-celeration is approximated by discrete increases or decreases in velocity,
|
||||
// defined by ACCELERATION_TICKS_PER_SECOND and block->rate_delta. The accelerations employ the
|
||||
// midpoint rule to obtain an accurate representation of the exact acceleration curve.
|
||||
|
||||
// NOTE: By increasing the ACCELERATION_TICKS_PER_SECOND in config.h, the resolution of the
|
||||
// discrete velocity changes increase and accuracy can increase as well to a point. Numerical
|
||||
// round-off errors can effect this, if set too high. This is important to note if a user has
|
||||
// very high acceleration and/or feedrate requirements for their machine.
|
||||
|
||||
if (step_events_completed < current_block->accelerate_until) {
|
||||
// Iterate cycle counter and check if speeds need to be increased.
|
||||
if ( iterate_trapezoid_cycle_counter() ) {
|
||||
trapezoid_adjusted_rate += current_block->rate_delta;
|
||||
if (trapezoid_adjusted_rate >= current_block->nominal_rate) {
|
||||
// Reached nominal rate a little early. Cruise at nominal rate until decelerate_after.
|
||||
trapezoid_adjusted_rate = current_block->nominal_rate;
|
||||
}
|
||||
set_step_events_per_minute(trapezoid_adjusted_rate);
|
||||
}
|
||||
} else if (step_events_completed > current_block->decelerate_after) {
|
||||
// Iterate cycle counter and check if speeds need to be reduced.
|
||||
if ( iterate_trapezoid_cycle_counter() ) {
|
||||
// NOTE: We will only reduce speed if the result will be > 0. This catches small
|
||||
// rounding errors that might leave steps hanging after the last trapezoid tick.
|
||||
if (trapezoid_adjusted_rate > current_block->rate_delta) {
|
||||
trapezoid_adjusted_rate -= current_block->rate_delta;
|
||||
}
|
||||
if (trapezoid_adjusted_rate < current_block->final_rate) {
|
||||
// Reached final rate a little early. Cruise to end of block at final rate.
|
||||
trapezoid_adjusted_rate = current_block->final_rate;
|
||||
}
|
||||
set_step_events_per_minute(trapezoid_adjusted_rate);
|
||||
}
|
||||
} else {
|
||||
// No accelerations. Make sure we cruise exactly at nominal rate.
|
||||
if (trapezoid_adjusted_rate != current_block->nominal_rate) {
|
||||
trapezoid_adjusted_rate = current_block->nominal_rate;
|
||||
set_step_events_per_minute(trapezoid_adjusted_rate);
|
||||
}
|
||||
// Check to reset trapezoid tick cycle counter to make sure that the deceleration is
|
||||
// performed the same every time. Reset to CYCLES_PER_ACCELERATION_TICK/2 to follow the
|
||||
// midpoint rule for an accurate approximation of the deceleration curve.
|
||||
if (step_events_completed >= current_block-> decelerate_after) {
|
||||
trapezoid_tick_cycle_counter = CYCLES_PER_ACCELERATION_TICK/2;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// If current block is finished, reset pointer
|
||||
current_block = NULL;
|
||||
plan_discard_current_block();
|
||||
}
|
||||
|
||||
} else {
|
||||
// Still no block? Set the stepper pins to low before sleeping.
|
||||
out_bits = 0;
|
||||
}
|
||||
out_bits ^= settings.invert_mask;
|
||||
|
||||
// In average this generates a trapezoid_generator_tick every CYCLES_PER_ACCELERATION_TICK by keeping track
|
||||
// of the number of elapsed cycles. The code assumes that step_events occur significantly more often than
|
||||
// trapezoid_generator_ticks as they well should.
|
||||
trapezoid_tick_cycle_counter += cycles_per_step_event;
|
||||
if(trapezoid_tick_cycle_counter > CYCLES_PER_ACCELERATION_TICK) {
|
||||
trapezoid_tick_cycle_counter -= CYCLES_PER_ACCELERATION_TICK;
|
||||
trapezoid_generator_tick();
|
||||
}
|
||||
|
||||
out_bits ^= settings.invert_mask; // Apply stepper invert mask
|
||||
busy=false;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user