a new (slightly inelegant) stab at eliminating the slow tail problem
This commit is contained in:
parent
c02a6e2366
commit
1ed2195e11
@ -123,12 +123,12 @@ inline double intersection_distance(double initial_rate, double final_rate, doub
|
|||||||
|
|
||||||
void calculate_trapezoid_for_block(block_t *block, double entry_factor, double exit_factor) {
|
void calculate_trapezoid_for_block(block_t *block, double entry_factor, double exit_factor) {
|
||||||
block->initial_rate = ceil(block->nominal_rate*entry_factor);
|
block->initial_rate = ceil(block->nominal_rate*entry_factor);
|
||||||
int32_t final_rate = ceil(block->nominal_rate*exit_factor);
|
block->final_rate = ceil(block->nominal_rate*exit_factor);
|
||||||
int32_t acceleration_per_minute = block->rate_delta*ACCELERATION_TICKS_PER_SECOND*60.0;
|
int32_t acceleration_per_minute = block->rate_delta*ACCELERATION_TICKS_PER_SECOND*60.0;
|
||||||
int32_t accelerate_steps =
|
int32_t accelerate_steps =
|
||||||
ceil(estimate_acceleration_distance(block->initial_rate, block->nominal_rate, acceleration_per_minute));
|
ceil(estimate_acceleration_distance(block->initial_rate, block->nominal_rate, acceleration_per_minute));
|
||||||
int32_t decelerate_steps =
|
int32_t decelerate_steps =
|
||||||
floor(estimate_acceleration_distance(block->nominal_rate, final_rate, -acceleration_per_minute));
|
floor(estimate_acceleration_distance(block->nominal_rate, block->final_rate, -acceleration_per_minute));
|
||||||
|
|
||||||
// Calculate the size of Plateau of Nominal Rate.
|
// Calculate the size of Plateau of Nominal Rate.
|
||||||
int32_t plateau_steps = block->step_event_count-accelerate_steps-decelerate_steps;
|
int32_t plateau_steps = block->step_event_count-accelerate_steps-decelerate_steps;
|
||||||
@ -138,7 +138,7 @@ void calculate_trapezoid_for_block(block_t *block, double entry_factor, double e
|
|||||||
// in order to reach the final_rate exactly at the end of this block.
|
// in order to reach the final_rate exactly at the end of this block.
|
||||||
if (plateau_steps < 0) {
|
if (plateau_steps < 0) {
|
||||||
accelerate_steps = ceil(
|
accelerate_steps = ceil(
|
||||||
intersection_distance(block->initial_rate, final_rate, acceleration_per_minute, block->step_event_count));
|
intersection_distance(block->initial_rate, block->final_rate, acceleration_per_minute, block->step_event_count));
|
||||||
plateau_steps = 0;
|
plateau_steps = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,6 +394,7 @@ void plan_buffer_line(double x, double y, double z, double feed_rate, int invert
|
|||||||
calculate_trapezoid_for_block(block, safe_speed_factor, safe_speed_factor);
|
calculate_trapezoid_for_block(block, safe_speed_factor, safe_speed_factor);
|
||||||
} else {
|
} else {
|
||||||
block->initial_rate = block->nominal_rate;
|
block->initial_rate = block->nominal_rate;
|
||||||
|
block->final_rate = block->nominal_rate;
|
||||||
block->accelerate_until = 0;
|
block->accelerate_until = 0;
|
||||||
block->decelerate_after = block->step_event_count;
|
block->decelerate_after = block->step_event_count;
|
||||||
block->rate_delta = 0;
|
block->rate_delta = 0;
|
||||||
|
@ -45,6 +45,7 @@ typedef struct {
|
|||||||
|
|
||||||
// Settings for the trapezoid generator
|
// Settings for the trapezoid generator
|
||||||
uint32_t initial_rate; // The jerk-adjusted step rate at start of block
|
uint32_t initial_rate; // The jerk-adjusted step rate at start of block
|
||||||
|
uint32_t final_rate; // The minimal rate at exit
|
||||||
int32_t rate_delta; // The steps/minute to add or subtract when changing speed (must be positive)
|
int32_t rate_delta; // The steps/minute to add or subtract when changing speed (must be positive)
|
||||||
uint32_t accelerate_until; // The index of the step event on which to stop acceleration
|
uint32_t accelerate_until; // The index of the step event on which to stop acceleration
|
||||||
uint32_t decelerate_after; // The index of the step event on which to start decelerating
|
uint32_t decelerate_after; // The index of the step event on which to start decelerating
|
||||||
|
78
script/trapezoid_simulator.rb
Normal file
78
script/trapezoid_simulator.rb
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
require 'pp'
|
||||||
|
|
||||||
|
def estimate_acceleration_distance(initial_rate, target_rate, acceleration)
|
||||||
|
(target_rate*target_rate-initial_rate*initial_rate)/(2*acceleration)
|
||||||
|
end
|
||||||
|
|
||||||
|
def intersection_distance(initial_rate, final_rate, acceleration, distance)
|
||||||
|
(2*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/(4*acceleration)
|
||||||
|
end
|
||||||
|
|
||||||
|
ACCELERATION_TICKS_PER_SECOND = 20
|
||||||
|
|
||||||
|
def trapezoid_params(step_event_count, nominal_rate, rate_delta, entry_factor, exit_factor)
|
||||||
|
initial_rate = (nominal_rate * entry_factor).round
|
||||||
|
final_rate = (nominal_rate * exit_factor).round
|
||||||
|
acceleration_per_minute = rate_delta*ACCELERATION_TICKS_PER_SECOND*60
|
||||||
|
|
||||||
|
accelerate_steps =
|
||||||
|
estimate_acceleration_distance(initial_rate, nominal_rate, acceleration_per_minute).round;
|
||||||
|
decelerate_steps =
|
||||||
|
estimate_acceleration_distance(nominal_rate, final_rate, -acceleration_per_minute).round;
|
||||||
|
|
||||||
|
# Calculate the size of Plateau of Nominal Rate.
|
||||||
|
plateau_steps = step_event_count-accelerate_steps-decelerate_steps;
|
||||||
|
|
||||||
|
# Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will
|
||||||
|
# have to use intersection_distance() to calculate when to abort acceleration and start braking
|
||||||
|
# in order to reach the final_rate exactly at the end of this block.
|
||||||
|
if (plateau_steps < 0)
|
||||||
|
accelerate_steps =
|
||||||
|
intersection_distance(initial_rate, final_rate, acceleration_per_minute, step_event_count).round
|
||||||
|
plateau_steps = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
accelerate_until = accelerate_steps;
|
||||||
|
decelerate_after = accelerate_steps+plateau_steps;
|
||||||
|
{:step_event_count => step_event_count,
|
||||||
|
:initial_rate => initial_rate,
|
||||||
|
:final_rate => final_rate,
|
||||||
|
:nominal_rate => nominal_rate,
|
||||||
|
:rate_delta => rate_delta,
|
||||||
|
:accelerate_until => accelerate_until,
|
||||||
|
:decelerate_after => decelerate_after}
|
||||||
|
end
|
||||||
|
|
||||||
|
def simulate_trapezoid(params)
|
||||||
|
result = {}
|
||||||
|
rate = params[:initial_rate]
|
||||||
|
step_event = 0.0
|
||||||
|
max_rate = 0
|
||||||
|
while(step_event < params[:step_event_count]) do
|
||||||
|
step_events_in_frame = rate/60.0/ACCELERATION_TICKS_PER_SECOND
|
||||||
|
step_event += step_events_in_frame
|
||||||
|
max_rate = rate if rate > max_rate
|
||||||
|
if (step_event < params[:accelerate_until])
|
||||||
|
rate += params[:rate_delta]
|
||||||
|
elsif (step_event > params[:decelerate_after])
|
||||||
|
if rate > params[:final_rate]
|
||||||
|
rate -= params[:rate_delta]
|
||||||
|
else
|
||||||
|
return :underflow_at => step_event, :final_rate => rate, :max_rate => max_rate
|
||||||
|
end
|
||||||
|
end
|
||||||
|
# puts "#{step_event} #{rate}"
|
||||||
|
end
|
||||||
|
{:final_rate => rate, :max_rate => max_rate}
|
||||||
|
end
|
||||||
|
|
||||||
|
(10..100).each do |rate|
|
||||||
|
(1..5).each do |steps|
|
||||||
|
params = trapezoid_params(steps*1000, rate*100, 10, 0.1, 0.1)
|
||||||
|
result = simulate_trapezoid(params)
|
||||||
|
# puts params.inspect
|
||||||
|
line = "#{steps*10} final: #{result[:final_rate]} == #{params[:final_rate]} peak: #{result[:max_rate]} == #{params[:nominal_rate]} d#{params[:nominal_rate]-result[:max_rate]} "
|
||||||
|
line << " (underflow at #{result[:underflow_at]})" if result[:underflow_at]
|
||||||
|
puts line
|
||||||
|
end
|
||||||
|
end
|
@ -90,6 +90,7 @@ void st_wake_up() {
|
|||||||
// block begins.
|
// block begins.
|
||||||
inline void trapezoid_generator_reset() {
|
inline void trapezoid_generator_reset() {
|
||||||
trapezoid_adjusted_rate = current_block->initial_rate;
|
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);
|
set_step_events_per_minute(trapezoid_adjusted_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,9 +105,12 @@ inline void trapezoid_generator_tick() {
|
|||||||
} else if (step_events_completed > current_block->decelerate_after) {
|
} else if (step_events_completed > current_block->decelerate_after) {
|
||||||
// NOTE: We will only reduce speed if the result will be > 0. This catches small
|
// 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.
|
// rounding errors that might leave steps hanging after the last trapezoid tick.
|
||||||
if(current_block->rate_delta < trapezoid_adjusted_rate) {
|
if (trapezoid_adjusted_rate > current_block->rate_delta) {
|
||||||
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);
|
set_step_events_per_minute(trapezoid_adjusted_rate);
|
||||||
} else {
|
} else {
|
||||||
// Make sure we cruise at exactly nominal rate
|
// Make sure we cruise at exactly nominal rate
|
||||||
|
Loading…
Reference in New Issue
Block a user