dda.c: re-introduce ACCELERATION_TEMPORAL.
The implementation is slightly different this time, as it's not using these famous bresenham algorithms. The intention is to allow axis-independent movements, as it's required for EMC-quality look-ahead.
This commit is contained in:
parent
6864268df8
commit
fd91ee7e8b
122
dda.c
122
dda.c
|
|
@ -288,7 +288,7 @@ void dda_create(DDA *dda, TARGET *target) {
|
|||
|
||||
#ifdef ACCELERATION_TEMPORAL
|
||||
// bracket part of this equation in an attempt to avoid overflow: 60 * 16MHz * 5mm is >32 bits
|
||||
uint32_t move_duration = distance * (60 * F_CPU / startpoint.F);
|
||||
uint32_t move_duration = distance * ((60 * F_CPU) / (target->F * 1000));
|
||||
#else
|
||||
// pre-calculate move speed in millimeter microseconds per step minute for less math in interrupt context
|
||||
// mm (distance) * 60000000 us/min / step (total_steps) = mm.us per step.min
|
||||
|
|
@ -399,6 +399,36 @@ void dda_create(DDA *dda, TARGET *target) {
|
|||
if (dda->rampup_steps > dda->total_steps / 2)
|
||||
dda->rampup_steps = dda->total_steps / 2;
|
||||
dda->rampdown_steps = dda->total_steps - dda->rampup_steps;
|
||||
#elif defined ACCELERATION_TEMPORAL
|
||||
// TODO: limit speed of individual axes to MAXIMUM_FEEDRATE
|
||||
// TODO: calculate acceleration/deceleration for each axis
|
||||
dda->x_step_interval = dda->y_step_interval = \
|
||||
dda->z_step_interval = dda->e_step_interval = 0xFFFFFFFF;
|
||||
if (dda->x_delta)
|
||||
dda->x_step_interval = move_duration / dda->x_delta;
|
||||
if (dda->y_delta)
|
||||
dda->y_step_interval = move_duration / dda->y_delta;
|
||||
if (dda->z_delta)
|
||||
dda->z_step_interval = move_duration / dda->z_delta;
|
||||
if (dda->e_delta)
|
||||
dda->e_step_interval = move_duration / dda->e_delta;
|
||||
|
||||
dda->axis_to_step = 'x';
|
||||
dda->c = dda->x_step_interval;
|
||||
if (dda->y_step_interval < dda->c) {
|
||||
dda->axis_to_step = 'y';
|
||||
dda->c = dda->y_step_interval;
|
||||
}
|
||||
if (dda->z_step_interval < dda->c) {
|
||||
dda->axis_to_step = 'z';
|
||||
dda->c = dda->z_step_interval;
|
||||
}
|
||||
if (dda->e_step_interval < dda->c) {
|
||||
dda->axis_to_step = 'e';
|
||||
dda->c = dda->e_step_interval;
|
||||
}
|
||||
|
||||
dda->c <<= 8;
|
||||
#else
|
||||
dda->c = (move_duration / target->F) << 8;
|
||||
if (dda->c < c_limit)
|
||||
|
|
@ -454,6 +484,10 @@ void dda_start(DDA *dda) {
|
|||
#ifdef ACCELERATION_RAMPING
|
||||
move_state.step_no = 0;
|
||||
#endif
|
||||
#ifdef ACCELERATION_TEMPORAL
|
||||
move_state.x_time = move_state.y_time = \
|
||||
move_state.z_time = move_state.e_time = 0UL;
|
||||
#endif
|
||||
|
||||
// ensure this dda starts
|
||||
dda->live = 1;
|
||||
|
|
@ -486,6 +520,7 @@ void dda_start(DDA *dda) {
|
|||
void dda_step(DDA *dda) {
|
||||
uint8_t endstop_stop; ///< Stop due to endstop trigger
|
||||
uint8_t endstop_not_done = 0; ///< Which axes haven't finished homing
|
||||
uint32_t c_candidate;
|
||||
|
||||
#if defined X_MIN_PIN || defined X_MAX_PIN
|
||||
if (dda->endstop_check & 0x1) {
|
||||
|
|
@ -511,7 +546,8 @@ void dda_step(DDA *dda) {
|
|||
#endif
|
||||
endstop_stop = 0;
|
||||
|
||||
if ((move_state.x_steps) && !endstop_stop) {
|
||||
#if ! defined ACCELERATION_TEMPORAL
|
||||
if ((move_state.x_steps) && ! endstop_stop) {
|
||||
move_state.x_counter -= dda->x_delta;
|
||||
if (move_state.x_counter < 0) {
|
||||
x_step();
|
||||
|
|
@ -519,6 +555,14 @@ void dda_step(DDA *dda) {
|
|||
move_state.x_counter += dda->total_steps;
|
||||
}
|
||||
}
|
||||
#else // ACCELERATION_TEMPORAL
|
||||
if ((dda->axis_to_step == 'x') && ! endstop_stop) {
|
||||
x_step();
|
||||
move_state.x_steps--;
|
||||
move_state.x_time += dda->x_step_interval;
|
||||
move_state.all_time = move_state.x_time;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined Y_MIN_PIN || defined Y_MAX_PIN
|
||||
if (dda->endstop_check & 0x2) {
|
||||
|
|
@ -544,7 +588,8 @@ void dda_step(DDA *dda) {
|
|||
#endif
|
||||
endstop_stop = 0;
|
||||
|
||||
if ((move_state.y_steps) && !endstop_stop) {
|
||||
#if ! defined ACCELERATION_TEMPORAL
|
||||
if ((move_state.y_steps) && ! endstop_stop) {
|
||||
move_state.y_counter -= dda->y_delta;
|
||||
if (move_state.y_counter < 0) {
|
||||
y_step();
|
||||
|
|
@ -552,6 +597,14 @@ void dda_step(DDA *dda) {
|
|||
move_state.y_counter += dda->total_steps;
|
||||
}
|
||||
}
|
||||
#else // ACCELERATION_TEMPORAL
|
||||
if ((dda->axis_to_step == 'y') && ! endstop_stop) {
|
||||
y_step();
|
||||
move_state.y_steps--;
|
||||
move_state.y_time += dda->y_step_interval;
|
||||
move_state.all_time = move_state.y_time;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined Z_MIN_PIN || defined Z_MAX_PIN
|
||||
if (dda->endstop_check & 0x4) {
|
||||
|
|
@ -577,7 +630,8 @@ void dda_step(DDA *dda) {
|
|||
#endif
|
||||
endstop_stop = 0;
|
||||
|
||||
if ((move_state.z_steps) && !endstop_stop) {
|
||||
#if ! defined ACCELERATION_TEMPORAL
|
||||
if ((move_state.z_steps) && ! endstop_stop) {
|
||||
move_state.z_counter -= dda->z_delta;
|
||||
if (move_state.z_counter < 0) {
|
||||
z_step();
|
||||
|
|
@ -585,7 +639,16 @@ void dda_step(DDA *dda) {
|
|||
move_state.z_counter += dda->total_steps;
|
||||
}
|
||||
}
|
||||
#else // ACCELERATION_TEMPORAL
|
||||
if ((dda->axis_to_step == 'z') && ! endstop_stop) {
|
||||
z_step();
|
||||
move_state.z_steps--;
|
||||
move_state.z_time += dda->z_step_interval;
|
||||
move_state.all_time = move_state.z_time;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ! defined ACCELERATION_TEMPORAL
|
||||
if (move_state.e_steps) {
|
||||
move_state.e_counter -= dda->e_delta;
|
||||
if (move_state.e_counter < 0) {
|
||||
|
|
@ -594,6 +657,14 @@ void dda_step(DDA *dda) {
|
|||
move_state.e_counter += dda->total_steps;
|
||||
}
|
||||
}
|
||||
#else // ACCELERATION_TEMPORAL
|
||||
if (dda->axis_to_step == 'e') {
|
||||
e_step();
|
||||
move_state.e_steps--;
|
||||
move_state.e_time += dda->e_step_interval;
|
||||
move_state.all_time = move_state.e_time;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if STEP_INTERRUPT_INTERRUPTIBLE
|
||||
// Since we have sent steps to all the motors that will be stepping
|
||||
|
|
@ -680,6 +751,49 @@ void dda_step(DDA *dda) {
|
|||
// as we stop without ramping down, we have to re-init our ramping here
|
||||
dda_init();
|
||||
}
|
||||
#ifdef ACCELERATION_TEMPORAL
|
||||
/** How is this ACCELERATION TEMPORAL expected to work?
|
||||
|
||||
All axes work independently of each other, as if they were on four different, synchronized timers. As we have not enough suitable timers, we have to share one for all axes.
|
||||
|
||||
To do this, each axis maintains the time of its last step in move_state.{xyze}_time. This time is updated as the step is done, see early in dda_step(). To find out which axis is the next one to step, the time of each axis' next step is compared to the time of the step just done. Zero means this actually is the axis just stepped, the smallest value > 0 wins.
|
||||
|
||||
One problem undoubtly arising is, steps should sometimes be done at {almost,exactly} the same time. We trust the timer to deal properly with very short or even zero periods. If a step can't be done in time, the timer shall do the step as soon as possible and compensate for the delay later. In turn we promise here to send a maximum of four such short-delays consecutively and to give sufficient time on average.
|
||||
*/
|
||||
|
||||
// TODO: why is this line needed? If all steps are done, dda_steps()
|
||||
// shouldn't be called any longer, until after a dda_start().
|
||||
dda->axis_to_step = ' '; // start with no axis to step
|
||||
if (move_state.x_steps) {
|
||||
c_candidate = move_state.x_time + dda->x_step_interval - move_state.all_time;
|
||||
dda->axis_to_step = 'x';
|
||||
dda->c = c_candidate;
|
||||
}
|
||||
if (move_state.y_steps) {
|
||||
c_candidate = move_state.y_time + dda->y_step_interval - move_state.all_time;
|
||||
if (c_candidate < dda->c) {
|
||||
dda->axis_to_step = 'y';
|
||||
dda->c = c_candidate;
|
||||
}
|
||||
}
|
||||
if (move_state.z_steps) {
|
||||
c_candidate = move_state.z_time + dda->z_step_interval - move_state.all_time;
|
||||
if (c_candidate < dda->c) {
|
||||
dda->axis_to_step = 'z';
|
||||
dda->c = c_candidate;
|
||||
}
|
||||
}
|
||||
if (move_state.e_steps) {
|
||||
c_candidate = move_state.e_time + dda->e_step_interval - move_state.all_time;
|
||||
if (c_candidate < dda->c) {
|
||||
dda->axis_to_step = 'e';
|
||||
dda->c = c_candidate;
|
||||
}
|
||||
}
|
||||
if (dda->c == 0) dda->c = 10000; // hack, as we currently need another timer
|
||||
// set after everything is done.
|
||||
dda->c <<= 8;
|
||||
#endif
|
||||
|
||||
// If there are no steps left, we have finished.
|
||||
if (move_state.x_steps == 0 && move_state.y_steps == 0 &&
|
||||
|
|
|
|||
14
dda.h
14
dda.h
|
|
@ -131,6 +131,13 @@ typedef struct {
|
|||
/// tracking variable
|
||||
int32_t n;
|
||||
#endif
|
||||
#ifdef ACCELERATION_TEMPORAL
|
||||
uint32_t x_time; ///< time of the last x step
|
||||
uint32_t y_time; ///< time of the last y step
|
||||
uint32_t z_time; ///< time of the last z step
|
||||
uint32_t e_time; ///< time of the last e step
|
||||
uint32_t all_time; ///< time of the last step of any axis
|
||||
#endif
|
||||
|
||||
/// Endstop debouncing
|
||||
uint8_t debounce_count_xmin, debounce_count_ymin, debounce_count_zmin;
|
||||
|
|
@ -192,6 +199,13 @@ typedef struct {
|
|||
/// 24.8 fixed point timer value, maximum speed
|
||||
uint32_t c_min;
|
||||
#endif
|
||||
#ifdef ACCELERATION_TEMPORAL
|
||||
uint32_t x_step_interval; ///< time between steps on X axis
|
||||
uint32_t y_step_interval; ///< time between steps on Y axis
|
||||
uint32_t z_step_interval; ///< time between steps on Z axis
|
||||
uint32_t e_step_interval; ///< time between steps on E axis
|
||||
uint8_t axis_to_step; ///< axis to be stepped on the next interrupt
|
||||
#endif
|
||||
|
||||
/// Endstop homing
|
||||
uint8_t endstop_check; ///< Do we need to check endstops? 0x1=Check X, 0x2=Check Y, 0x4=Check Z
|
||||
|
|
|
|||
1
timer.c
1
timer.c
|
|
@ -148,6 +148,7 @@ void setTimer(uint32_t delay)
|
|||
// from one step to the next one, which should be more or less the same
|
||||
// as from one step interrupt to the next one. The last step interrupt happend
|
||||
// at OCR1A, so start delay from there.
|
||||
#warning This can't work. If it took some time since the last setTimer() and the delay is very short, the timer will wait almost a full round (3,27 ms).
|
||||
step_start = OCR1A;
|
||||
if (next_step_time == 0) {
|
||||
// new move, take current time as start value
|
||||
|
|
|
|||
Loading…
Reference in New Issue