Added compile time option for jerk controlled motion

This commit is contained in:
Dietz0r
2024-01-07 20:58:26 +01:00
committed by GitHub
parent 9f95af13a2
commit e645ddbdd9
6 changed files with 75 additions and 11 deletions
+2
View File
@@ -189,8 +189,10 @@ or EMI triggering the related interrupt falsely or too many times.
// ---------------------------------------------------------------------------------------
// ADVANCED CONFIGURATION OPTIONS:
// EXPERIMENTAL OPTIONS
#define ENABLE_PATH_BLENDING Off // Do NOT enable unless working on adding this feature!
#define ENABLE_ACCELERATION_PROFILES Off // Enable to allow G-Code changeable acceleration profiles.
#define ENABLE_JERK_ACCELERATION Off // Enable to use 3rd order Acceleration calculations. May need more processing power, tiny chips beware.
// Enables code for debugging purposes. Not for general use and always in constant flux.
//#define DEBUG // Uncomment to enable. Default disabled.
+8 -2
View File
@@ -354,7 +354,7 @@ static inline float limit_acceleration_by_axis_maximum (float *unit_vec)
return limit_value;
}
#if ENABLE_JERK_ACCELERATION
static inline float limit_jerk_by_axis_maximum (float *unit_vec)
{
uint_fast8_t idx = N_AXIS;
@@ -367,7 +367,7 @@ static inline float limit_jerk_by_axis_maximum (float *unit_vec)
return limit_value;
}
#endif
static inline float limit_max_rate_by_axis_maximum (float *unit_vec)
{
uint_fast8_t idx = N_AXIS;
@@ -516,8 +516,12 @@ bool plan_buffer_line (float *target, plan_line_data_t *pl_data)
#endif
block->millimeters = convert_delta_vector_to_unit_vector(unit_vec);
#if ENABLE_ACCELERATION_PROFILES
block->max_acceleration = limit_acceleration_by_axis_maximum(unit_vec);
block->jerk = limit_jerk_by_axis_maximum(unit_vec);
#else
block->acceleration = limit_acceleration_by_axis_maximum(unit_vec);
#endif
block->rapid_rate = limit_max_rate_by_axis_maximum(unit_vec);
// Store programmed rate.
@@ -531,11 +535,13 @@ bool plan_buffer_line (float *target, plan_line_data_t *pl_data)
if (block->condition.inverse_time)
block->programmed_rate *= block->millimeters;
}
#if ENABLE_ACCELERATION_PROFILES
// Calculate effective acceleration over block. Since jerk acceleration takes longer to execute due to ramp up and
// ramp down of the acceleration at the start and end of a ramp we need to adjust the acceleration value the planner
// uses so it still calculates reasonable entry and exit speeds. We do this by adding 2x the time it takes to reach
// full acceleration to the trapezoidal acceleration time and dividing the programmed rate by the value obtained.
block->acceleration = block->programmed_rate / ((block->programmed_rate / block->max_acceleration) + 2.0f * (block->max_acceleration / block->jerk));
#endif
// TODO: Need to check this method handling zero junction speeds when starting from rest.
if ((block_buffer_head == block_buffer_tail) || (block->condition.system_motion)) {
+3 -1
View File
@@ -61,9 +61,11 @@ typedef struct plan_block {
float entry_speed_sqr; // The current planned entry speed at block junction in (mm/min)^2
float max_entry_speed_sqr; // Maximum allowable entry speed based on the minimum of junction limit and
// neighboring nominal speeds with overrides in (mm/min)^2
float acceleration; // Effective acceleration over plannerblock calculated from trapezoidal movement plan.
float acceleration; // Effective acceleration over plannerblock calculated from trapezoidal movement plan. Does not change in trapezoidal mode.
#if ENABLE_JERK_ACCELERATION
float max_acceleration; // Axis-limit adjusted line acceleration in (mm/min^2). Does not change.
float jerk; // Axis-limit adjusted jerk value in (mm/min^3). Does not change.
#endif
float millimeters; // The remaining distance for this block to be executed in (mm).
// NOTE: This value may be altered by stepper algorithm during execution.
+38 -6
View File
@@ -204,7 +204,9 @@ PROGMEM const settings_t defaults = {
.axis[X_AXIS].steps_per_mm = DEFAULT_X_STEPS_PER_MM,
.axis[X_AXIS].max_rate = DEFAULT_X_MAX_RATE,
.axis[X_AXIS].acceleration = (DEFAULT_X_ACCELERATION * 60.0f * 60.0f),
#if ENABLE_JERK_ACCELERATION
.axis[X_AXIS].jerk = (DEFAULT_X_JERK * 60.0f * 60.0f * 60.0f),
#endif
.axis[X_AXIS].max_travel = (-DEFAULT_X_MAX_TRAVEL),
.axis[X_AXIS].dual_axis_offset = 0.0f,
#if ENABLE_BACKLASH_COMPENSATION
@@ -215,7 +217,9 @@ PROGMEM const settings_t defaults = {
.axis[Y_AXIS].max_rate = DEFAULT_Y_MAX_RATE,
.axis[Y_AXIS].max_travel = (-DEFAULT_Y_MAX_TRAVEL),
.axis[Y_AXIS].acceleration = (DEFAULT_Y_ACCELERATION * 60.0f * 60.0f),
#if ENABLE_JERK_ACCELERATION
.axis[Y_AXIS].jerk = (DEFAULT_Y_JERK * 60.0f * 60.0f * 60.0f),
#endif
.axis[Y_AXIS].dual_axis_offset = 0.0f,
#if ENABLE_BACKLASH_COMPENSATION
.axis[Y_AXIS].backlash = 0.0f,
@@ -224,7 +228,9 @@ PROGMEM const settings_t defaults = {
.axis[Z_AXIS].steps_per_mm = DEFAULT_Z_STEPS_PER_MM,
.axis[Z_AXIS].max_rate = DEFAULT_Z_MAX_RATE,
.axis[Z_AXIS].acceleration = (DEFAULT_Z_ACCELERATION * 60.0f * 60.0f),
#if ENABLE_JERK_ACCELERATION
.axis[Z_AXIS].jerk = (DEFAULT_Z_JERK * 60.0f * 60.0f * 60.0f),
#endif
.axis[Z_AXIS].max_travel = (-DEFAULT_Z_MAX_TRAVEL),
.axis[Z_AXIS].dual_axis_offset = 0.0f,
#if ENABLE_BACKLASH_COMPENSATION
@@ -235,7 +241,9 @@ PROGMEM const settings_t defaults = {
.axis[A_AXIS].steps_per_mm = DEFAULT_A_STEPS_PER_MM,
.axis[A_AXIS].max_rate = DEFAULT_A_MAX_RATE,
.axis[A_AXIS].acceleration =(DEFAULT_A_ACCELERATION * 60.0f * 60.0f),
#if ENABLE_JERK_ACCELERATION
.axis[A_AXIS].jerk = (DEFAULT_A_JERK * 60.0f * 60.0f * 60.0f),
#endif
.axis[A_AXIS].max_travel = (-DEFAULT_A_MAX_TRAVEL),
.axis[A_AXIS].dual_axis_offset = 0.0f,
#if ENABLE_BACKLASH_COMPENSATION
@@ -248,7 +256,9 @@ PROGMEM const settings_t defaults = {
.axis[B_AXIS].steps_per_mm = DEFAULT_B_STEPS_PER_MM,
.axis[B_AXIS].max_rate = DEFAULT_B_MAX_RATE,
.axis[B_AXIS].acceleration = (DEFAULT_B_ACCELERATION * 60.0f * 60.0f),
#if ENABLE_JERK_ACCELERATION
.axis[B_AXIS].jerk = (DEFAULT_B_JERK * 60.0f * 60.0f * 60.0f),
#endif
.axis[B_AXIS].max_travel = (-DEFAULT_B_MAX_TRAVEL),
.axis[B_AXIS].dual_axis_offset = 0.0f,
#if ENABLE_BACKLASH_COMPENSATION
@@ -260,7 +270,9 @@ PROGMEM const settings_t defaults = {
#ifdef C_AXIS
.axis[C_AXIS].steps_per_mm = DEFAULT_C_STEPS_PER_MM,
.axis[C_AXIS].acceleration = (DEFAULT_C_ACCELERATION * 60.0f * 60.0f),
#if ENABLE_JERK_ACCELERATION
.axis[C_AXIS].jerk = (DEFAULT_C_JERK * 60.0f * 60.0f * 60.0f),
#endif
.axis[C_AXIS].max_rate = DEFAULT_C_MAX_RATE,
.axis[C_AXIS].max_travel = (-DEFAULT_C_MAX_TRAVEL),
.axis[C_AXIS].dual_axis_offset = 0.0f,
@@ -273,7 +285,9 @@ PROGMEM const settings_t defaults = {
#ifdef U_AXIS
.axis[U_AXIS].steps_per_mm = DEFAULT_U_STEPS_PER_MM,
.axis[U_AXIS].acceleration = (DEFAULT_U_ACCELERATION * 60.0f * 60.0f),
#if ENABLE_JERK_ACCELERATION
.axis[U_AXIS].jerk = (DEFAULT_U_JERK * 60.0f * 60.0f * 60.0f),
#endif
.axis[U_AXIS].max_rate = DEFAULT_U_MAX_RATE,
.axis[U_AXIS].max_travel = (-DEFAULT_U_MAX_TRAVEL),
.axis[U_AXIS].dual_axis_offset = 0.0f,
@@ -285,7 +299,9 @@ PROGMEM const settings_t defaults = {
#ifdef V_AXIS
.axis[V_AXIS].steps_per_mm = DEFAULT_V_STEPS_PER_MM,
.axis[V_AXIS].acceleration = (DEFAULT_V_ACCELERATION * 60.0f * 60.0f),
#if ENABLE_JERK_ACCELERATION
.axis[V_AXIS].jerk = (DEFAULT_V_JERK * 60.0f * 60.0f * 60.0f),
#endif
.axis[V_AXIS].max_rate = DEFAULT_V_MAX_RATE,
.axis[V_AXIS].max_travel = (-DEFAULT_V_MAX_TRAVEL),
.axis[V_AXIS].dual_axis_offset = 0.0f,
@@ -440,7 +456,9 @@ static char spindle_types[100] = "";
static char axis_dist[4] = "mm";
static char axis_rate[8] = "mm/min";
static char axis_accel[10] = "mm/sec^2";
#if ENABLE_JERK_ACCELERATION
static char axis_jerk[15] = "mm/sec^3";
#endif
#if DELTA_ROBOT
static char axis_steps[9] = "step/rev";
#else
@@ -569,7 +587,9 @@ PROGMEM static const setting_detail_t setting_detail[] = {
{ Setting_AxisStepsPerMM, Group_Axis0, "-axis travel resolution", axis_steps, Format_Decimal, "#####0.000##", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS },
{ Setting_AxisMaxRate, Group_Axis0, "-axis maximum rate", axis_rate, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS },
{ Setting_AxisAcceleration, Group_Axis0, "-axis acceleration", axis_accel, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS },
#if ENABLE_JERK_ACCELERATION
{ Setting_AxisJerk, Group_Axis0, "-axis jerk", axis_jerk, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtendedFn, set_axis_setting, get_float, NULL, AXIS_OPTS },
#endif
{ Setting_AxisMaxTravel, Group_Axis0, "-axis maximum travel", axis_dist, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS },
#if ENABLE_BACKLASH_COMPENSATION
{ Setting_AxisBacklash, Group_Axis0, "-axis backlash compensation", axis_dist, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtendedFn, set_axis_setting, get_float, NULL, AXIS_OPTS },
@@ -759,11 +779,13 @@ PROGMEM static const setting_descr_t setting_descr[] = {
{ (setting_id_t)(Setting_AxisStepsPerMM + 1), "Travel resolution in steps per degree." }, // "Hack" to get correct description for rotary axes
{ Setting_AxisMaxRate, "Maximum rate. Used as G0 rapid rate." },
{ Setting_AxisAcceleration, "Acceleration. Used for motion planning to not exceed motor torque and lose steps." },
#if ENABLE_JERK_ACCELERATION
{ Setting_AxisJerk, "Maximum rate of acceleration change - smoothes out acceleration profile up to max axis acceleration.\\n\\n"
"Minimum value of x10 Acceleration setting to ensure decent acceleration times.\\n"
"Maximum is calcualted by current acceleration and stepper segment time.\\n"
"At Maximum value motion is effectively trapezoidal instead of constant jerk.\\n\\n"
"Can be increased by adjusting ACCELERATION_TICKS_PER_SECOND to a larger value before compiling."},
#endif
{ Setting_AxisMaxTravel, "Maximum axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances." },
#if ENABLE_BACKLASH_COMPENSATION
{ Setting_AxisBacklash, "Backlash distance to compensate for." },
@@ -829,7 +851,9 @@ static setting_details_t setting_details = {
static struct {
bool valid;
float acceleration[N_AXIS];
#if ENABLE_JERK_ACCELERATION
float jerk[N_AXIS];
#endif
} override_backup = { .valid = false };
static void save_override_backup (void)
@@ -839,7 +863,9 @@ static void save_override_backup (void)
do {
idx--;
override_backup.acceleration[idx] = settings.axis[idx].acceleration;
#if ENABLE_JERK_ACCELERATION
override_backup.jerk[idx] = settings.axis[idx].jerk;
#endif
} while(idx);
override_backup.valid = true;
@@ -852,7 +878,9 @@ static void restore_override_backup (void)
if(override_backup.valid) do {
idx--;
settings.axis[idx].acceleration = override_backup.acceleration[idx];
#if ENABLE_JERK_ACCELERATION
settings.axis[idx].jerk = override_backup.jerk[idx];
#endif
} while(idx);
}
@@ -873,6 +901,7 @@ bool settings_override_acceleration (uint8_t axis, float acceleration, float jer
save_override_backup();
settings.axis[axis].acceleration = (override_backup.acceleration[axis] >= (acceleration * 60.0f * 60.0f)) ? (acceleration * 60.0f * 60.0f) : override_backup.acceleration[axis]; // Limited to max setting value
}
#if ENABLE_JERK_ACCELERATION
if(jerk <= 0.0f) {
if(override_backup.valid)
settings.axis[axis].jerk = override_backup.jerk[axis];
@@ -881,6 +910,7 @@ bool settings_override_acceleration (uint8_t axis, float acceleration, float jer
save_override_backup();
settings.axis[axis].jerk = (override_backup.jerk[axis] >= (jerk * 60.0f * 60.0f * 60.0f)) ? (jerk * 60.0f * 60.0f * 60.0f) : override_backup.jerk[axis]; // Limited to max setting value
}
#endif
return true;
}
@@ -1377,11 +1407,11 @@ static const char *set_axis_setting_unit (setting_id_t setting_id, uint_fast8_t
case Setting_AxisAcceleration:
unit = is_rotary ? "deg/sec^2" : "mm/sec^2";
break;
#if ENABLE_JERK_ACCELERATION
case Setting_AxisJerk:
unit = is_rotary ? "deg/sec^3" : "mm/sec^3";
break;
#endif
case Setting_AxisMaxTravel:
case Setting_AxisBacklash:
unit = is_rotary ? "deg" : "mm";
@@ -1488,9 +1518,11 @@ static status_code_t set_axis_setting (setting_id_t setting, float value)
case Setting_AxisAcceleration:
settings.axis[idx].acceleration = override_backup.acceleration[idx] = value * 60.0f * 60.0f; // Convert to mm/min^2 for grbl internal use.
#if ENABLE_JERK_ACCELERATION
settings.axis[idx].jerk = (settings.axis[idx].acceleration * 10.0f * 60.0f); //reset jerk to axis minimum.
#endif
break;
#if ENABLE_JERK_ACCELERATION
case Setting_AxisJerk:
if ((value * 60.0f * 60.0f) < (settings.axis[idx].acceleration * 10.0f)) //ensuring that the acceleration time is limited to at maximum 100ms (or 10 stepper segments).
settings.axis[idx].jerk = settings.axis[idx].acceleration * 10.0f * 60.0f; // mm/min^2 -> mm/min^3
@@ -1499,7 +1531,7 @@ static status_code_t set_axis_setting (setting_id_t setting, float value)
else
settings.axis[idx].jerk = value * 60.0f * 60.0f * 60.0f; // Convert to mm/min^3 for grbl internal use.
break;
#endif
case Setting_AxisMaxTravel:
if(settings.axis[idx].max_travel != -value) {
bit_false(sys.homed.mask, bit(idx));
@@ -1562,11 +1594,11 @@ static float get_float (setting_id_t setting)
case Setting_AxisAcceleration:
value = settings.axis[idx].acceleration / (60.0f * 60.0f); // Convert from mm/min^2 to mm/sec^2.
break;
#if ENABLE_JERK_ACCELERATION
case Setting_AxisJerk:
value = settings.axis[idx].jerk / (60.0f * 60.0f * 60.0f); // Convert from mm/min^3 to mm/sec^3.
break;
#endif
case Setting_AxisMaxTravel:
value = -settings.axis[idx].max_travel; // Store as negative for grbl internal use.
break;
+10
View File
@@ -441,7 +441,11 @@ typedef enum {
// Calculated base values for driver/plugin stepper settings
Setting_AxisExtended0 = Setting_AxisSettingsBase2,
Setting_AxisExtended1 = Setting_AxisSettingsBase2 + AXIS_SETTINGS_INCREMENT,
#if ENABLE_JERK_ACCELERATION
Setting_AxisJerk = Setting_AxisSettingsBase2 + 2 * AXIS_SETTINGS_INCREMENT,
#else
Setting_AxisExtended2 = Setting_AxisSettingsBase2 + 2 * AXIS_SETTINGS_INCREMENT,
#endif
Setting_AxisExtended3 = Setting_AxisSettingsBase2 + 3 * AXIS_SETTINGS_INCREMENT,
Setting_AxisExtended4 = Setting_AxisSettingsBase2 + 4 * AXIS_SETTINGS_INCREMENT,
Setting_AxisExtended5 = Setting_AxisSettingsBase2 + 5 * AXIS_SETTINGS_INCREMENT,
@@ -614,7 +618,9 @@ typedef struct {
float steps_per_mm;
float max_rate;
float acceleration;
#if ENABLE_JERK_ACCELERATION
float jerk;
#endif
float max_travel;
float dual_axis_offset;
#if ENABLE_BACKLASH_COMPENSATION
@@ -958,7 +964,11 @@ void settings_write_coord_data(coord_system_id_t id, float (*coord_data)[N_AXIS]
bool settings_read_coord_data(coord_system_id_t id, float (*coord_data)[N_AXIS]);
// Temporarily override acceleration, if 0 restore to configured setting value
#if ENABLE_JERK_ACCELERATION
bool settings_override_acceleration (uint8_t axis, float acceleration, float jerk);
#else
bool settings_override_acceleration (uint8_t axis, float acceleration);
#endif
void settings_register (setting_details_t *details);
setting_details_t *settings_get_details (void);
+14 -2
View File
@@ -892,7 +892,9 @@ void st_prep_buffer (void)
float dt_max = DT_SEGMENT; // Maximum segment time
float dt = 0.0f; // Initialize segment time
float time_var = dt_max; // Time worker variable
#if ENABLE_JERK_ACCELERATION
float last_segment_accel = 0.0f; // Acceleration value of last computed segment. Initialize as 0.0
#endif
float mm_var; // mm - Distance worker variable
float speed_var; // Speed worker variable
float mm_remaining = pl_block->millimeters; // New segment distance from end of block.
@@ -921,15 +923,20 @@ void st_prep_buffer (void)
case Ramp_Accel:
// NOTE: Acceleration ramp only computes during first do-while loop.
#if ENABLE_JERK_ACCELERATION
if (((mm_remaining - prep.accelerate_until) / (prep.current_speed + 1.0f)) <= (last_segment_accel / pl_block->jerk)) {
//+1.0f to avoid divide by 0 speed, minor effect on jerk ramp
// Check if we are on ramp up or ramp down. Ramp down if time to end of acceleration is less than time needed to reach 0 acceleration.
// Then limit acceleration change by jerk up to max acceleration and update for next segment.
last_segment_accel = max(last_segment_accel - pl_block->jerk * time_var, 0.0f);
// Minimum acceleration jerk per time_var to ensure acceleartion completes. Acceleration change at end of ramp is in acceptable jerk range.
last_segment_accel = max(last_segment_accel - pl_block->jerk * time_var, pl_block->jerk * time_var);
} else {
last_segment_accel = min(last_segment_accel + pl_block->jerk * time_var, pl_block->max_acceleration);
}
speed_var = last_segment_accel * time_var;
#else
speed_var = pl_block->acceleration * time_var;
#endif
mm_remaining -= time_var * (prep.current_speed + 0.5f * speed_var);
if (mm_remaining < prep.accelerate_until) { // End of acceleration ramp.
// Acceleration-cruise, acceleration-deceleration ramp junction, or end of block.
@@ -957,15 +964,20 @@ void st_prep_buffer (void)
default: // case Ramp_Decel:
// NOTE: mm_var used as a misc worker variable to prevent errors when near zero speed.
#if ENABLE_JERK_ACCELERATION
if ((mm_remaining / (prep.current_speed + 1.0f)) <= (last_segment_accel / pl_block->jerk)) {
//+1.0f to avoid divide by 0 speed, minor effect on jerk ramp
// Check if we are on ramp up or ramp down. Ramp down if time to end of deceleration is less than time needed to reach 0 acceleration.
// Then limit acceleration change by jerk up to max acceleration and update for next segment.
last_segment_accel = max(last_segment_accel - pl_block->jerk * time_var, 0.0f);
// Minimum acceleration of jerk per time_var to ensure acceleration completes. Acceleration change at end of ramp is in acceptable jerk range.
last_segment_accel = max(last_segment_accel - pl_block->jerk * time_var, pl_block->jerk * time_var);
} else {
last_segment_accel = min(last_segment_accel + pl_block->jerk * time_var, pl_block->max_acceleration);
}
speed_var = last_segment_accel * time_var; // Used as delta speed (mm/min)
#else
speed_var = pl_block->acceleration * time_var; // Used as delta speed (mm/min)
#endif
if (prep.current_speed > speed_var) { // Check if at or below zero speed.
// Compute distance from end of segment to end of block.
mm_var = mm_remaining - time_var * (prep.current_speed - 0.5f * speed_var); // (mm)