Merge branch 'correct_rates' into sg-selector
commit
06d2c2bf7b
|
|
@ -109,7 +109,12 @@ bool PulseGen::PlanMoveTo(pos_t target, steps_t feed_rate, steps_t end_rate) {
|
||||||
|
|
||||||
// Acceleration of the segment, in steps/sec^2
|
// Acceleration of the segment, in steps/sec^2
|
||||||
block->acceleration = acceleration;
|
block->acceleration = acceleration;
|
||||||
block->acceleration_rate = block->acceleration * (rate_t)((float)F_CPU / (F_CPU / config::stepTimerFrequencyDivider));
|
|
||||||
|
// Calculate the ratio to 2^24 so that the rate division in Step() can be a just right shift
|
||||||
|
constexpr float ratio = (float)(1lu << 24) / (F_CPU / config::stepTimerFrequencyDivider);
|
||||||
|
constexpr rate_t mul = 8; // pre-multiply to increase the integer division resolution
|
||||||
|
static_assert(!(mul & (mul - 1)), "mul must be a power of two");
|
||||||
|
block->acceleration_rate = block->acceleration * (rate_t)(ratio * mul) / mul;
|
||||||
|
|
||||||
// Simplified forward jerk: do not handle reversals
|
// Simplified forward jerk: do not handle reversals
|
||||||
steps_t entry_speed;
|
steps_t entry_speed;
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ int main(int argc, const char *argv[]) {
|
||||||
F_CPU / config::stepTimerFrequencyDivider, config::stepTimerQuantum);
|
F_CPU / config::stepTimerFrequencyDivider, config::stepTimerQuantum);
|
||||||
|
|
||||||
for (int ax_cnt = 0; ax_cnt != 2; ++ax_cnt) {
|
for (int ax_cnt = 0; ax_cnt != 2; ++ax_cnt) {
|
||||||
for (int accel = 2000; accel <= 50000; accel *= 2) {
|
for (int accel = 50; accel <= 50000; accel += accel / 2) {
|
||||||
// first axis defines the nominal values
|
// first axis defines the nominal values
|
||||||
motion.SetJerk(ax_a, maxJerk);
|
motion.SetJerk(ax_a, maxJerk);
|
||||||
motion.SetPosition(ax_a, 0);
|
motion.SetPosition(ax_a, 0);
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ def check_axis(info, ax_info, data, fine_check):
|
||||||
tb = info['timebase']
|
tb = info['timebase']
|
||||||
|
|
||||||
# remove duplicate positions (meaning another axis was moved, not the current)
|
# remove duplicate positions (meaning another axis was moved, not the current)
|
||||||
data = data[data['pos'].diff() != 0]
|
data = data[data['pos'].diff() != 0].reset_index()
|
||||||
|
|
||||||
# recalculate intervals just for this axis
|
# recalculate intervals just for this axis
|
||||||
data['int'] = data['ts'].diff()
|
data['int'] = data['ts'].diff()
|
||||||
|
|
@ -61,18 +61,21 @@ def check_axis(info, ax_info, data, fine_check):
|
||||||
data['ts_s'] = data['ts'] / tb
|
data['ts_s'] = data['ts'] / tb
|
||||||
data['int_s'] = data['int'] / tb
|
data['int_s'] = data['int'] / tb
|
||||||
|
|
||||||
maxdev_fine = 20 # absolute maximum deviation
|
if fine_check:
|
||||||
maxdev_acc = 0.05 # 5% acceleration deviation
|
maxdev = 0.1 # 10% rate deviation tolerance
|
||||||
maxdev_coarse = 0.1 # 10% speed deviation
|
else:
|
||||||
ramp_smp_skip = 3 # skip initial null values
|
maxdev = 0.2 # higher tolerance due to quantization
|
||||||
|
|
||||||
|
# initial samples to skip
|
||||||
|
ramp_smp_skip = 3
|
||||||
|
|
||||||
if fine_check:
|
if fine_check:
|
||||||
# exact rate
|
# exact rate
|
||||||
data['rate'] = 1 / data['int_s']
|
data['rate'] = 1 / data['int_s']
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# reconstruct the rate from 3 samples
|
# reconstruct the rate from 5 samples
|
||||||
data['rate'] = 1 / data.rolling(3)['int_s'].median()
|
data['rate'] = 1 / data.rolling(5)['int_s'].median()
|
||||||
data['rate'].bfill(inplace=True)
|
data['rate'].bfill(inplace=True)
|
||||||
|
|
||||||
# ensure we never _exceed_ max feedrate
|
# ensure we never _exceed_ max feedrate
|
||||||
|
|
@ -93,11 +96,10 @@ def check_axis(info, ax_info, data, fine_check):
|
||||||
# check cruising speed
|
# check cruising speed
|
||||||
cruise_data = data[(data['pos'] > acc_dist + 2)
|
cruise_data = data[(data['pos'] > acc_dist + 2)
|
||||||
& (data['pos'] < acc_dist + 2 + c_dist)]
|
& (data['pos'] < acc_dist + 2 + c_dist)]
|
||||||
cruise_maxdev = 1 if fine_check else maxrate * maxdev_coarse
|
assert ((cruise_data['rate'] - maxrate).abs().max() < 1)
|
||||||
assert ((cruise_data['rate'] - maxrate).abs().max() < cruise_maxdev)
|
|
||||||
|
|
||||||
# checking acceleration segments require a decent number of samples for good results
|
# checking acceleration segments require a decent number of samples for good results
|
||||||
if acc_dist < 10:
|
if acc_dist < 20:
|
||||||
return
|
return
|
||||||
|
|
||||||
# TODO: minrate is currently hardcoded in the FW as a function of the timer type (we
|
# TODO: minrate is currently hardcoded in the FW as a function of the timer type (we
|
||||||
|
|
@ -106,49 +108,29 @@ def check_axis(info, ax_info, data, fine_check):
|
||||||
startrate = data['rate'].iat[ramp_smp_skip]
|
startrate = data['rate'].iat[ramp_smp_skip]
|
||||||
endrate = data['rate'].iat[-1]
|
endrate = data['rate'].iat[-1]
|
||||||
|
|
||||||
# check acceleration segment (coarse)
|
# check acceleration segment
|
||||||
acc_data = data[(data['pos'] < acc_dist)][ramp_smp_skip:]
|
acc_data = data[(data['pos'] < acc_dist)][ramp_smp_skip:]
|
||||||
acc_data['ts_s'] -= acc_data['ts_s'].iat[0]
|
acc_data['ts_s'] -= acc_data['ts_s'].iat[0]
|
||||||
acc_time = acc_data['ts_s'].iat[-1]
|
acc_time = acc_data['ts_s'].iat[-1]
|
||||||
acc_data['exp_rate'] = startrate + acc_data['ts_s'] \
|
acc_data['exp_rate'] = startrate + acc_data['ts_s'] * ax_info['accel']
|
||||||
/ acc_time * (maxrate - startrate)
|
|
||||||
assert ((acc_data['exp_rate'] - acc_data['rate']).abs().max() <
|
assert ((acc_data['exp_rate'] - acc_data['rate']).abs().max() <
|
||||||
maxrate * maxdev_coarse)
|
maxrate * maxdev)
|
||||||
|
|
||||||
# acceleration (fine)
|
# check acceleration rate
|
||||||
acc_data['exp_fine'] = acc_data['rate'].iat[0] + acc_data['ts_s'] \
|
acc_acc = (acc_data['rate'].iat[-1] - acc_data['rate'].iat[0]) / acc_time
|
||||||
/ acc_time * (acc_data['rate'].iat[-1] - startrate)
|
assert (abs(acc_acc - ax_info['accel']) / ax_info['accel'] < maxdev)
|
||||||
if fine_check:
|
|
||||||
assert ((acc_data['exp_fine'] - acc_data['rate']).abs().max() <
|
|
||||||
maxdev_fine)
|
|
||||||
|
|
||||||
# check effective acceleration rate
|
# deceleration segment
|
||||||
acc_vel = (acc_data['rate'].iat[-1] - acc_data['rate'].iat[0]) / acc_time
|
dec_data = data[(data['pos'] >
|
||||||
if fine_check:
|
(data['pos'].iat[-1] - acc_dist))][ramp_smp_skip:]
|
||||||
assert (abs(acc_vel - ax_info['accel']) / ax_info['accel'] <
|
|
||||||
maxdev_acc)
|
|
||||||
|
|
||||||
# deceleration (coarse)
|
|
||||||
dec_data = data[(data['pos'] > (data['pos'].iat[-1] - acc_dist))][2:]
|
|
||||||
dec_data['ts_s'] -= dec_data['ts_s'].iat[0]
|
dec_data['ts_s'] -= dec_data['ts_s'].iat[0]
|
||||||
dec_time = dec_data['ts_s'].iat[-1]
|
dec_time = dec_data['ts_s'].iat[-1]
|
||||||
dec_data['exp_rate'] = maxrate - dec_data['ts_s'] \
|
dec_data['exp_rate'] = dec_data['rate'].iat[
|
||||||
/ dec_time * (maxrate - endrate)
|
0] - dec_data['ts_s'] * ax_info['accel']
|
||||||
assert ((dec_data['exp_rate'] - dec_data['rate']).abs().max() <
|
|
||||||
maxrate * maxdev_coarse)
|
|
||||||
|
|
||||||
# deceleration (fine)
|
# check deceleration rate
|
||||||
dec_data['exp_fine'] = dec_data['rate'].iat[0] - dec_data['ts_s'] \
|
dec_acc = (dec_data['rate'].iat[0] - dec_data['rate'].iat[-1]) / dec_time
|
||||||
/ dec_time * (dec_data['rate'].iat[0] - endrate)
|
assert (abs(dec_acc - ax_info['accel']) / ax_info['accel'] < maxdev)
|
||||||
if fine_check:
|
|
||||||
assert ((dec_data['exp_fine'] - dec_data['rate']).abs().max() <
|
|
||||||
maxdev_fine)
|
|
||||||
|
|
||||||
# check effective deceleration rate
|
|
||||||
dec_vel = (dec_data['rate'].iat[0] - dec_data['rate'].iat[-1]) / dec_time
|
|
||||||
if fine_check:
|
|
||||||
# TODO: deceleration rate is not as accurate as acceleration!
|
|
||||||
assert (abs(dec_vel - ax_info['accel']) / ax_info['accel'] < 0.15)
|
|
||||||
|
|
||||||
|
|
||||||
def check_run(info, run):
|
def check_run(info, run):
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue