518 lines
9.7 KiB
C++
518 lines
9.7 KiB
C++
// 1. Dx Dy Dz De; e_total_offset += De;
|
|
// 2. m = sqrt(Dx * Dx + Dy * Dy + Dz * Dz)
|
|
// 3. Dx /= m; Dy /= m; Dz /= m; De /= m;
|
|
// 4. V = min(speed, Vmax_x / Dx, Vmax_y / Dy, Vmax_z / Dz, Vmax_e / De);
|
|
// 5. A = min(Amax_x / Dx, Amax_y / Dy, Amax_z / Dz, Amax_e / De);
|
|
// 6. Vx = V * Dx; Vy = V * Dy; Vz = V * Dz; Ve = V * De;
|
|
// 6.1 Vend_prev_x = Vx; ... -> Calculate prev move and wait for current Vend
|
|
// 7. Ax = A * Dx; Ay = A * Dy; Az = A * Dz; Ae = A * De;
|
|
// 8. time = max(calc_time_complex(x), ...(y), ...(z), ...(e))
|
|
|
|
#include "TimeCalc.h"
|
|
|
|
#define DEBUG_CALC 0
|
|
|
|
#include <limits>
|
|
#include "math.h"
|
|
|
|
#if DEBUG_CALC
|
|
# include <iostream>
|
|
#endif
|
|
|
|
using namespace std;
|
|
|
|
static double vector_min(const vector<double>& vec)
|
|
{
|
|
double min;
|
|
int idx;
|
|
|
|
if (vec.empty())
|
|
{
|
|
return 0.0;
|
|
}
|
|
|
|
idx = 0;
|
|
min = abs(vec[0]);
|
|
|
|
for (int i = 1; i < vec.size(); ++i)
|
|
{
|
|
if (abs(vec[i]) < min)
|
|
{
|
|
min = abs(vec[i]);
|
|
idx = i;
|
|
}
|
|
}
|
|
|
|
return vec[idx];
|
|
}
|
|
|
|
static double vector_max(const vector<double>& vec)
|
|
{
|
|
double max;
|
|
int idx;
|
|
|
|
if (vec.empty())
|
|
{
|
|
return 0.0;
|
|
}
|
|
|
|
idx = 0;
|
|
max = abs(vec[0]);
|
|
|
|
for (int i = 1; i < vec.size(); ++i)
|
|
{
|
|
if (abs(vec[i]) > max)
|
|
{
|
|
idx = i;
|
|
max = abs(vec[i]);
|
|
}
|
|
}
|
|
|
|
return vec[idx];
|
|
}
|
|
|
|
static double calc_dist(double vel, double accel, double t)
|
|
{
|
|
return vel * t + 0.5 * accel * t * t;
|
|
}
|
|
|
|
static double calc_time_to_accel(double accel, double vel_start, double vel_end)
|
|
{
|
|
return abs((vel_start - vel_end) / accel);
|
|
}
|
|
|
|
// Triangle Velocity
|
|
static double calc_time_very_complex(double dist, double vel_start, double vel_end, double accel)
|
|
{
|
|
double a;
|
|
double b;
|
|
double c;
|
|
double d;
|
|
double val[2];
|
|
double res = 0;
|
|
|
|
if (accel == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
a = accel;
|
|
b = 2 * vel_end;
|
|
c = (vel_end * vel_end - vel_start * vel_start)/(2 * accel) - dist;
|
|
d = b * b - 4 * a * c;
|
|
|
|
d = sqrt(d);
|
|
|
|
val[0] = (-b + d)/(2*a);
|
|
val[1] = (-b - d)/(2*a);
|
|
|
|
if (val[0] >= 0)
|
|
{
|
|
res = val[0];
|
|
}
|
|
|
|
if (val[1] >= 0)
|
|
{
|
|
res = val[1];
|
|
}
|
|
|
|
return (2 * res + (vel_end - vel_start) / accel);
|
|
}
|
|
|
|
static double calc_time_complex(double dist, double accel, double max_vel_change, double vel_start, double vel_end, double vel_max_target)
|
|
{
|
|
double result = 0.0;
|
|
double accel_time;
|
|
double accel_dist;
|
|
double deccel_time;
|
|
double deccel_dist;
|
|
|
|
if (dist == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (accel == 0)
|
|
{
|
|
// Linear calculation - It's something
|
|
return dist/vel_max_target;
|
|
}
|
|
|
|
// "Instant" velocity change on <= "Jerk"
|
|
if (vel_max_target != vel_start)
|
|
{
|
|
if (abs(vel_max_target - vel_start) <= max_vel_change)
|
|
{
|
|
vel_start = vel_max_target;
|
|
}
|
|
}
|
|
|
|
// "Instant" velocity change on <= "Jerk"
|
|
if (vel_max_target != vel_end)
|
|
{
|
|
if (abs(vel_max_target - vel_end) <= max_vel_change)
|
|
{
|
|
vel_end = vel_max_target;
|
|
}
|
|
}
|
|
|
|
accel_time = calc_time_to_accel(accel, vel_start, vel_max_target);
|
|
accel_dist = calc_dist(vel_start, accel, accel_time);
|
|
|
|
deccel_time = calc_time_to_accel(accel, vel_max_target, vel_end);
|
|
deccel_dist = calc_dist(vel_max_target, -accel, deccel_time);
|
|
|
|
// Triangle Velocity
|
|
if (abs(accel_dist + deccel_dist) > abs(dist))
|
|
{
|
|
result = calc_time_very_complex(dist, vel_start, vel_end, accel);
|
|
// Something's fucky
|
|
if (0 == result)
|
|
{
|
|
// Linear calculation - It's something
|
|
return abs(dist/vel_max_target);
|
|
}
|
|
}
|
|
// Trapezoid Velocity
|
|
else
|
|
{
|
|
dist -= (accel_dist + deccel_dist);
|
|
result += (accel_time + deccel_time);
|
|
result += abs(dist / vel_max_target);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
TimeCalc::PrinterMove::PrinterMove()
|
|
: dist(0.0)
|
|
{
|
|
fill_n(delta, AXIS_COUNT, 0.0);
|
|
fill_n(unit, AXIS_COUNT, 0.0);
|
|
fill_n(vel, AXIS_COUNT, 0.0);
|
|
fill_n(accel, AXIS_COUNT, 0.0);
|
|
fill_n(vel_start, AXIS_COUNT, 0.0);
|
|
fill_n(vel_end, AXIS_COUNT, 0.0);
|
|
}
|
|
|
|
TimeCalc::TimeCalc()
|
|
: m_time(0.0), m_print_accel_max(0.0), m_travel_accel_max(0.0),
|
|
m_retract_accel_max(0.0)
|
|
{
|
|
fill_n(m_accel_max, AXIS_COUNT, 0.0);
|
|
fill_n(m_vel_max, AXIS_COUNT, 0.0);
|
|
fill_n(m_jerk_max, AXIS_COUNT, 0.0);
|
|
reset();
|
|
}
|
|
|
|
void TimeCalc::reset()
|
|
{
|
|
m_time = 0.0;
|
|
|
|
fill_n(m_extruder_length, EXTRUDER_COUNT, 0.0);
|
|
fill_n(m_pos, AXIS_COUNT, 0.0);
|
|
|
|
m_moves.clear();
|
|
}
|
|
|
|
void TimeCalc::add_move(Point new_pos, double speed)
|
|
{
|
|
PrinterMove move_new;
|
|
vector<double> temp;
|
|
Point pos_temp;
|
|
double pos_new[AXIS_COUNT];
|
|
double vel;
|
|
double accel;
|
|
double prev_move_idx;
|
|
double special_accel;
|
|
double de_sum;
|
|
static int counter = 0;
|
|
|
|
pos_new[0] = new_pos.x;
|
|
pos_new[1] = new_pos.y;
|
|
pos_new[2] = new_pos.z;
|
|
pos_new[3] = new_pos.e;
|
|
|
|
pos_temp = Point(m_pos[0], m_pos[1], m_pos[2], m_pos[3]);
|
|
|
|
move_new.dist = new_pos.get_dist(pos_temp);
|
|
|
|
#if DEBUG_CALC
|
|
cout << "---" << endl;
|
|
cout << "Dist - " << move_new.dist << endl;
|
|
#endif
|
|
|
|
if (0.0 == move_new.dist)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Calculate Delta And Unit Vector
|
|
for (int i = 0 ; i < AXIS_COUNT; ++i)
|
|
{
|
|
move_new.delta[i] = pos_new[i] - m_pos[i];
|
|
move_new.unit[i] = move_new.delta[i] / move_new.dist;
|
|
#if DEBUG_CALC
|
|
cout << "Unit [" << i << "] - " << move_new.unit[i] << endl;
|
|
#endif
|
|
}
|
|
|
|
// Calculate velocity
|
|
temp.clear();
|
|
temp.push_back(speed);
|
|
for (int i = 0 ; i < AXIS_COUNT; ++i)
|
|
{
|
|
if (0.0 != move_new.unit[i] && 0.0 != m_vel_max[i])
|
|
{
|
|
temp.push_back(m_vel_max[i] / move_new.unit[i]);
|
|
}
|
|
}
|
|
vel = abs(vector_min(temp));
|
|
|
|
#if DEBUG_CALC
|
|
cout << "Vel - " << vel << endl;
|
|
#endif
|
|
|
|
de_sum = 0.0;
|
|
for (int i = 0; i < EXTRUDER_COUNT; ++i)
|
|
{
|
|
de_sum += move_new.delta[3 + i];
|
|
}
|
|
|
|
// Set max acceleration for specific move to be considered
|
|
special_accel = 0.0;
|
|
if (0.0 == de_sum)
|
|
{
|
|
special_accel = m_travel_accel_max;
|
|
}
|
|
else if (move_new.dist == de_sum)
|
|
{
|
|
special_accel = m_retract_accel_max;
|
|
}
|
|
else
|
|
{
|
|
special_accel = m_print_accel_max;
|
|
}
|
|
|
|
// Calculate acceleration
|
|
temp.clear();
|
|
if (0.0 != special_accel)
|
|
{
|
|
temp.push_back(special_accel);
|
|
}
|
|
|
|
for (int i = 0 ; i < AXIS_COUNT; ++i)
|
|
{
|
|
if (0.0 != move_new.unit[i] && 0.0 != m_accel_max[i])
|
|
{
|
|
temp.push_back(m_accel_max[i] / move_new.unit[i]);
|
|
}
|
|
}
|
|
accel = abs(vector_min(temp));
|
|
|
|
#if DEBUG_CALC
|
|
cout << "Accel - " << accel << endl;
|
|
#endif
|
|
|
|
// Calculate Component Velocity and Acceleration
|
|
for (int i = 0 ; i < AXIS_COUNT; ++i)
|
|
{
|
|
move_new.vel[i] = vel * move_new.unit[i];
|
|
move_new.accel[i] = accel * move_new.unit[i];
|
|
}
|
|
|
|
// Calculate veclocities for/from previous move
|
|
if (!m_moves.empty())
|
|
{
|
|
prev_move_idx = m_moves.size() - 1;
|
|
|
|
for (int i = 0; i < AXIS_COUNT; ++i)
|
|
{
|
|
// If we're changing direction
|
|
if (m_moves[prev_move_idx].vel[i] * move_new.vel[i] < 0)
|
|
{
|
|
m_moves[prev_move_idx].vel_end[i] = 0.0;
|
|
}
|
|
else
|
|
{
|
|
// If we're accelerating
|
|
if (abs(m_moves[prev_move_idx].vel[i]) < abs(move_new.vel[i]))
|
|
{
|
|
m_moves[prev_move_idx].vel_end[i] = m_moves[prev_move_idx].vel[i];
|
|
}
|
|
else
|
|
{
|
|
m_moves[prev_move_idx].vel_end[i] = move_new.vel[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Calc end velocity for prev move
|
|
temp.clear();
|
|
for (int i = 0; i < AXIS_COUNT; ++i)
|
|
{
|
|
if (0.0 != m_moves[prev_move_idx].unit[i])
|
|
{
|
|
temp.push_back(m_moves[prev_move_idx].vel_end[i] / m_moves[prev_move_idx].unit[i]);
|
|
}
|
|
}
|
|
vel = vector_min(temp);
|
|
|
|
for (int i = 0; i < AXIS_COUNT; ++i)
|
|
{
|
|
m_moves[prev_move_idx].vel_end[i] = vel * m_moves[prev_move_idx].unit[i];
|
|
move_new.vel_start[i] = m_moves[prev_move_idx].vel_end[i];
|
|
#if DEBUG_CALC
|
|
cout << "Vel Start [" << i << "] - " << m_moves[prev_move_idx].vel_end[i] << endl;
|
|
#endif
|
|
}
|
|
|
|
// Do a move calculation
|
|
flush();
|
|
}
|
|
|
|
m_moves.push_back(move_new);
|
|
for (int i = 0; i < AXIS_COUNT; ++i)
|
|
{
|
|
m_pos[i] = pos_new[i];
|
|
}
|
|
}
|
|
|
|
void TimeCalc::set_pos(Point new_pos)
|
|
{
|
|
flush();
|
|
if (new_pos.e != m_pos[3])
|
|
{
|
|
m_extruder_length[0] += m_pos[3];
|
|
m_extruder_length[0] -= new_pos.e;
|
|
}
|
|
|
|
m_pos[0] = new_pos.x;
|
|
m_pos[1] = new_pos.y;
|
|
m_pos[2] = new_pos.z;
|
|
m_pos[3] = new_pos.e;
|
|
}
|
|
|
|
void TimeCalc::flush()
|
|
{
|
|
vector<double> times;
|
|
double max;
|
|
|
|
for (PrinterMove& move : m_moves)
|
|
{
|
|
// Find the slowest axis and add it to the total time
|
|
times.clear();
|
|
for (int i = 0; i < AXIS_COUNT; ++i)
|
|
{
|
|
times.push_back(calc_time_complex(move.delta[i], move.accel[i],
|
|
m_jerk_max[i], move.vel_start[i], move.vel_end[i], move.vel[i]));
|
|
}
|
|
max = vector_max(times);
|
|
|
|
#if DEBUG_CALC
|
|
if (max < 0)
|
|
{
|
|
printf("Dist - %10.5f - %10.5f\n", move.dist, max);
|
|
|
|
for (int i = 0; i < AXIS_COUNT; ++i)
|
|
{
|
|
printf("Delta [%d] - %10.5f\n", i, move.delta[i]);
|
|
}
|
|
|
|
for (int i = 0; i < AXIS_COUNT; ++i)
|
|
{
|
|
printf("Unit [%d] - %10.5f\n", i, move.unit[i]);
|
|
}
|
|
|
|
for (int i = 0; i < AXIS_COUNT; ++i)
|
|
{
|
|
printf("V0 [%d] - %10.5f\n", i, move.vel_start[i]);
|
|
}
|
|
|
|
for (int i = 0; i < AXIS_COUNT; ++i)
|
|
{
|
|
printf("Vel [%d] - %10.5f\n", i, move.vel[i]);
|
|
}
|
|
|
|
for (int i = 0; i < AXIS_COUNT; ++i)
|
|
{
|
|
printf("V2 [%d] - %10.5f\n", i, move.vel_end[i]);
|
|
}
|
|
|
|
for (int i = 0; i < AXIS_COUNT; ++i)
|
|
{
|
|
printf("Accel [%d] - %10.5f\n", i, move.accel[i]);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
m_time += max;
|
|
}
|
|
m_moves.clear();
|
|
}
|
|
|
|
void TimeCalc::add_time(double time)
|
|
{
|
|
m_time += time;
|
|
}
|
|
|
|
double TimeCalc::get_time() const
|
|
{
|
|
return m_time;
|
|
}
|
|
|
|
double TimeCalc::get_extruder_length(int idx) const
|
|
{
|
|
if (idx >= EXTRUDER_COUNT)
|
|
{
|
|
return 0.0;
|
|
}
|
|
|
|
return m_extruder_length[idx] + m_pos[3 + idx];
|
|
}
|
|
|
|
Point TimeCalc::get_pos() const
|
|
{
|
|
return Point(m_pos[0], m_pos[1], m_pos[2], m_pos[3]);
|
|
}
|
|
|
|
void TimeCalc::set_max_acceleration(int axis, double value)
|
|
{
|
|
if ((axis > 0) && (axis < AXIS_COUNT))
|
|
{
|
|
m_accel_max[axis] = value;
|
|
}
|
|
}
|
|
|
|
void TimeCalc::set_max_velocity(int axis, double value)
|
|
{
|
|
if ((axis > 0) && (axis < AXIS_COUNT))
|
|
{
|
|
m_vel_max[axis] = value;
|
|
}
|
|
}
|
|
|
|
void TimeCalc::set_max_jerk(int axis, double value)
|
|
{
|
|
if ((axis > 0) && (axis < AXIS_COUNT))
|
|
{
|
|
m_jerk_max[axis] = value;
|
|
}
|
|
}
|
|
|
|
void TimeCalc::set_print_accel(double value)
|
|
{
|
|
m_print_accel_max = value;
|
|
}
|
|
|
|
void TimeCalc::set_travel_accel(double value)
|
|
{
|
|
m_travel_accel_max = value;
|
|
}
|
|
|
|
void TimeCalc::set_retract_accel(double value)
|
|
{
|
|
m_retract_accel_max = value;
|
|
}
|