Make lookahead basically working.
This means, modify existing code to let the lookahead algorithms do their work. It also means to remove some unused code in dda_lookahead.c and reordering some code to make it work with LOOKAHEAD undefined.
This commit is contained in:
parent
e04b69b9c6
commit
1aca61c277
71
dda.c
71
dda.c
|
|
@ -10,6 +10,7 @@
|
||||||
#include <avr/interrupt.h>
|
#include <avr/interrupt.h>
|
||||||
|
|
||||||
#include "dda_maths.h"
|
#include "dda_maths.h"
|
||||||
|
#include "dda_lookahead.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
#include "sermsg.h"
|
#include "sermsg.h"
|
||||||
|
|
@ -82,9 +83,13 @@ void dda_new_startpoint(void) {
|
||||||
|
|
||||||
This algorithm is probably the main limiting factor to print speed in terms of firmware limitations
|
This algorithm is probably the main limiting factor to print speed in terms of firmware limitations
|
||||||
*/
|
*/
|
||||||
void dda_create(DDA *dda, TARGET *target) {
|
void dda_create(DDA *dda, TARGET *target, DDA *prev_dda) {
|
||||||
uint32_t steps, x_delta_um, y_delta_um, z_delta_um, e_delta_um;
|
uint32_t steps, x_delta_um, y_delta_um, z_delta_um, e_delta_um;
|
||||||
uint32_t distance, c_limit, c_limit_calc;
|
uint32_t distance, c_limit, c_limit_calc;
|
||||||
|
#ifdef LOOKAHEAD
|
||||||
|
// Number the moves to identify them; allowed to overflow.
|
||||||
|
static uint8_t idcnt = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
// initialise DDA to a known state
|
// initialise DDA to a known state
|
||||||
dda->allflags = 0;
|
dda->allflags = 0;
|
||||||
|
|
@ -95,6 +100,15 @@ void dda_create(DDA *dda, TARGET *target) {
|
||||||
// we end at the passed target
|
// we end at the passed target
|
||||||
memcpy(&(dda->endpoint), target, sizeof(TARGET));
|
memcpy(&(dda->endpoint), target, sizeof(TARGET));
|
||||||
|
|
||||||
|
#ifdef LOOKAHEAD
|
||||||
|
// Set the start and stop speeds to zero for now = full stops between
|
||||||
|
// moves. Also fallback if lookahead calculations fail to finish in time.
|
||||||
|
dda->F_start = 0;
|
||||||
|
dda->F_end = 0;
|
||||||
|
// Give this move an identifier.
|
||||||
|
dda->id = idcnt++;
|
||||||
|
#endif
|
||||||
|
|
||||||
// TODO TODO: We should really make up a loop for all axes.
|
// TODO TODO: We should really make up a loop for all axes.
|
||||||
// Think of what happens when a sixth axis (multi colour extruder)
|
// Think of what happens when a sixth axis (multi colour extruder)
|
||||||
// appears?
|
// appears?
|
||||||
|
|
@ -129,6 +143,14 @@ void dda_create(DDA *dda, TARGET *target) {
|
||||||
dda->e_direction = (target->E >= startpoint.E)?1:0;
|
dda->e_direction = (target->E >= startpoint.E)?1:0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LOOKAHEAD
|
||||||
|
// Also displacements in micrometers, but for the lookahead alogrithms.
|
||||||
|
dda->delta.X = target->X - startpoint.X;
|
||||||
|
dda->delta.Y = target->Y - startpoint.Y;
|
||||||
|
dda->delta.Z = target->Z - startpoint.Z;
|
||||||
|
dda->delta.E = target->e_relative ? target->E : target->E - startpoint.E;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (DEBUG_DDA && (debug_flags & DEBUG_DDA))
|
if (DEBUG_DDA && (debug_flags & DEBUG_DDA))
|
||||||
sersendf_P(PSTR("%ld,%ld,%ld,%ld] ["), target->X - startpoint.X, target->Y - startpoint.Y, target->Z - startpoint.Z, target->E - startpoint.E);
|
sersendf_P(PSTR("%ld,%ld,%ld,%ld] ["), target->X - startpoint.X, target->Y - startpoint.Y, target->Z - startpoint.Z, target->E - startpoint.E);
|
||||||
|
|
||||||
|
|
@ -285,13 +307,43 @@ void dda_create(DDA *dda, TARGET *target) {
|
||||||
dda->c_min = c_limit;
|
dda->c_min = c_limit;
|
||||||
// This section is plain wrong, like in it's only half of what we need. This factor 960000 is dependant on STEPS_PER_MM.
|
// This section is plain wrong, like in it's only half of what we need. This factor 960000 is dependant on STEPS_PER_MM.
|
||||||
// overflows at target->F > 65535; factor 16. found by try-and-error; will overshoot target speed a bit
|
// overflows at target->F > 65535; factor 16. found by try-and-error; will overshoot target speed a bit
|
||||||
dda->rampup_steps = target->F * target->F / (uint32_t)(STEPS_PER_M_X * ACCELERATION / 960000.);
|
//dda->rampup_steps = target->F * target->F / (uint32_t)(STEPS_PER_M_X * ACCELERATION / 960000.);
|
||||||
//sersendf_P(PSTR("rampup calc %lu\n"), dda->rampup_steps);
|
//sersendf_P(PSTR("rampup calc %lu\n"), dda->rampup_steps);
|
||||||
dda->rampup_steps = 100000; // replace mis-calculation by a safe value
|
//dda->rampup_steps = 100000; // replace mis-calculation by a safe value
|
||||||
// End of wrong section.
|
// End of wrong section.
|
||||||
if (dda->rampup_steps > dda->total_steps / 2)
|
/**
|
||||||
dda->rampup_steps = dda->total_steps / 2;
|
Assuming: F is in mm/min, STEPS_PER_M_X is in steps/m, ACCELERATION is in mm/s²
|
||||||
dda->rampdown_steps = dda->total_steps - dda->rampup_steps;
|
Given:
|
||||||
|
- Velocity v at time t given acceleration a: v(t) = a*t
|
||||||
|
- Displacement s at time t given acceleration a: s(t) = 1/2 * a * t²
|
||||||
|
- Displacement until reaching target velocity v: s = 1/2 * (v² / a)
|
||||||
|
- Final result: steps needed to reach velocity v given acceleration a:
|
||||||
|
steps = (STEPS_PER_M_X * F^2) / (7200000 * ACCELERATION)
|
||||||
|
To keep precision, break up in floating point and integer part:
|
||||||
|
F^2 * (int)(STEPS_PER_M_X / (7200000 * ACCELERATION))
|
||||||
|
Note: the floating point part is static so its calculated during compilation.
|
||||||
|
Note 2: the floating point part will be smaller than one, invert it:
|
||||||
|
steps = F^2 / (int)((7200000 * ACCELERATION) / STEPS_PER_M_X)
|
||||||
|
Note 3: As mentioned, setting F to 65535 or larger will overflow the
|
||||||
|
calculation. Make sure this does not happen.
|
||||||
|
Note 4: Anyone trying to run their machine at 65535 mm/min > 1m/s is nuts
|
||||||
|
*/
|
||||||
|
if (target->F > 65534) target->F = 65534;
|
||||||
|
dda->rampup_steps = ACCELERATE_RAMP_LEN(target->F);
|
||||||
|
// Quick hack: we do not do Z move joins as jerk on the Z axis is undesirable;
|
||||||
|
// as the ramp length is calculated for XY, its incorrect for Z: apply the original
|
||||||
|
// 'fix' to simply specify a large enough ramp for any speed.
|
||||||
|
if (x_delta_um == 0 && y_delta_um == 0) {
|
||||||
|
dda->rampup_steps = 100000; // replace mis-calculation by a safe value
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dda->rampup_steps > dda->total_steps / 2)
|
||||||
|
dda->rampup_steps = dda->total_steps / 2;
|
||||||
|
dda->rampdown_steps = dda->total_steps - dda->rampup_steps;
|
||||||
|
|
||||||
|
#ifdef LOOKAHEAD
|
||||||
|
dda_join_moves(prev_dda, dda);
|
||||||
|
#endif
|
||||||
#elif defined ACCELERATION_TEMPORAL
|
#elif defined ACCELERATION_TEMPORAL
|
||||||
// TODO: limit speed of individual axes to MAXIMUM_FEEDRATE
|
// TODO: limit speed of individual axes to MAXIMUM_FEEDRATE
|
||||||
// TODO: calculate acceleration/deceleration for each axis
|
// TODO: calculate acceleration/deceleration for each axis
|
||||||
|
|
@ -617,6 +669,8 @@ void dda_step(DDA *dda) {
|
||||||
move_state.n += 4;
|
move_state.n += 4;
|
||||||
// be careful of signedness!
|
// be careful of signedness!
|
||||||
move_state.c = (int32_t)move_state.c - ((int32_t)(move_state.c * 2) / (int32_t)move_state.n);
|
move_state.c = (int32_t)move_state.c - ((int32_t)(move_state.c * 2) / (int32_t)move_state.n);
|
||||||
|
//sersendf_P(PSTR("n:%ld; c:%ld; steps: %ld / %lu\n"), move_state.n,
|
||||||
|
// move_state.c, move_state.step_no, move_state.y_steps);
|
||||||
}
|
}
|
||||||
move_state.step_no++;
|
move_state.step_no++;
|
||||||
// Print the number of steps actually needed for ramping up
|
// Print the number of steps actually needed for ramping up
|
||||||
|
|
@ -687,6 +741,11 @@ void dda_step(DDA *dda) {
|
||||||
if (move_state.x_steps == 0 && move_state.y_steps == 0 &&
|
if (move_state.x_steps == 0 && move_state.y_steps == 0 &&
|
||||||
move_state.z_steps == 0 && move_state.e_steps == 0) {
|
move_state.z_steps == 0 && move_state.e_steps == 0) {
|
||||||
dda->live = 0;
|
dda->live = 0;
|
||||||
|
#ifdef LOOKAHEAD
|
||||||
|
// If look-ahead was using this move, it could have missed our activation:
|
||||||
|
// make sure the ids do not match.
|
||||||
|
dda->id--;
|
||||||
|
#endif
|
||||||
#ifdef DC_EXTRUDER
|
#ifdef DC_EXTRUDER
|
||||||
heater_set(DC_EXTRUDER, 0);
|
heater_set(DC_EXTRUDER, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
33
dda.h
33
dda.h
|
|
@ -15,6 +15,9 @@
|
||||||
types
|
types
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Enum to denote an axis
|
||||||
|
enum axis_e { X, Y, Z, E };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\struct TARGET
|
\struct TARGET
|
||||||
\brief target is simply a point in space/time
|
\brief target is simply a point in space/time
|
||||||
|
|
@ -34,6 +37,19 @@ typedef struct {
|
||||||
uint8_t e_relative :1; ///< bool: e axis relative? Overrides all_relative
|
uint8_t e_relative :1; ///< bool: e axis relative? Overrides all_relative
|
||||||
} TARGET;
|
} TARGET;
|
||||||
|
|
||||||
|
/**
|
||||||
|
\struct VECTOR4D
|
||||||
|
\brief 4 dimensional vector used to describe the difference between moves.
|
||||||
|
|
||||||
|
Units are in micrometers and usually based off 'TARGET'.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
int32_t X;
|
||||||
|
int32_t Y;
|
||||||
|
int32_t Z;
|
||||||
|
int32_t E;
|
||||||
|
} VECTOR4D;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\struct MOVE_STATE
|
\struct MOVE_STATE
|
||||||
\brief this struct is made for tracking the current state of the movement
|
\brief this struct is made for tracking the current state of the movement
|
||||||
|
|
@ -128,6 +144,21 @@ typedef struct {
|
||||||
uint32_t rampdown_steps;
|
uint32_t rampdown_steps;
|
||||||
/// 24.8 fixed point timer value, maximum speed
|
/// 24.8 fixed point timer value, maximum speed
|
||||||
uint32_t c_min;
|
uint32_t c_min;
|
||||||
|
#ifdef LOOKAHEAD
|
||||||
|
// With the look-ahead functionality, it is possible to retain physical
|
||||||
|
// movement between G1 moves. These variables keep track of the entry and
|
||||||
|
// exit speeds between moves.
|
||||||
|
uint32_t F_start;
|
||||||
|
uint32_t F_end;
|
||||||
|
// Displacement vector, in um, based between the difference of the starting
|
||||||
|
// point and the target. Required to obtain the jerk between 2 moves.
|
||||||
|
// Note: x_delta and co are in steps, not um.
|
||||||
|
VECTOR4D delta;
|
||||||
|
// Number the moves to be able to test at the end of lookahead if the moves
|
||||||
|
// are the same. Note: we do not need a lot of granularity here: more than
|
||||||
|
// MOVEBUFFER_SIZE is already enough.
|
||||||
|
uint8_t id;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#ifdef ACCELERATION_TEMPORAL
|
#ifdef ACCELERATION_TEMPORAL
|
||||||
uint32_t x_step_interval; ///< time between steps on X axis
|
uint32_t x_step_interval; ///< time between steps on X axis
|
||||||
|
|
@ -166,7 +197,7 @@ void dda_init(void);
|
||||||
void dda_new_startpoint(void);
|
void dda_new_startpoint(void);
|
||||||
|
|
||||||
// create a DDA
|
// create a DDA
|
||||||
void dda_create(DDA *dda, TARGET *target);
|
void dda_create(DDA *dda, TARGET *target, DDA *prev_dda);
|
||||||
|
|
||||||
// start a created DDA (called from timer interrupt)
|
// start a created DDA (called from timer interrupt)
|
||||||
void dda_start(DDA *dda) __attribute__ ((hot));
|
void dda_start(DDA *dda) __attribute__ ((hot));
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "sersendf.h"
|
#include "sersendf.h"
|
||||||
#include "pinio.h"
|
#include "pinio.h"
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
extern uint8_t use_lookahead;
|
extern uint8_t use_lookahead;
|
||||||
|
|
||||||
|
|
@ -144,7 +143,7 @@ void dda_emergency_shutdown(PGM_P msg) {
|
||||||
serial_writestr_P(PSTR("error: emergency stop:"));
|
serial_writestr_P(PSTR("error: emergency stop:"));
|
||||||
if(msg!=NULL) serial_writestr_P(msg);
|
if(msg!=NULL) serial_writestr_P(msg);
|
||||||
serial_writestr_P(PSTR("\r\n"));
|
serial_writestr_P(PSTR("\r\n"));
|
||||||
delay(20000); // Delay so the buffer can be flushed - otherwise the message is never sent
|
delay_ms(20); // Delay so the buffer can be flushed - otherwise the message is never sent
|
||||||
timer_stop();
|
timer_stop();
|
||||||
queue_flush();
|
queue_flush();
|
||||||
power_off();
|
power_off();
|
||||||
|
|
@ -168,8 +167,6 @@ void dda_emergency_shutdown(PGM_P msg) {
|
||||||
* last move (= 'current'); as a result a lot of small moves will still limit the speed.
|
* last move (= 'current'); as a result a lot of small moves will still limit the speed.
|
||||||
*/
|
*/
|
||||||
void dda_join_moves(DDA *prev, DDA *current) {
|
void dda_join_moves(DDA *prev, DDA *current) {
|
||||||
// Run-time option: only proceed if we are enabled.
|
|
||||||
if(use_lookahead==0) return;
|
|
||||||
|
|
||||||
// Calculating the look-ahead settings can take a while; before modifying
|
// Calculating the look-ahead settings can take a while; before modifying
|
||||||
// the previous move, we need to locally store any values and write them
|
// the previous move, we need to locally store any values and write them
|
||||||
|
|
@ -181,7 +178,6 @@ void dda_join_moves(DDA *prev, DDA *current) {
|
||||||
// Note: we assume 'current' will not be dispatched while this function runs, so we do not to
|
// Note: we assume 'current' will not be dispatched while this function runs, so we do not to
|
||||||
// back up the move settings: they will remain constant.
|
// back up the move settings: they will remain constant.
|
||||||
uint32_t this_F_start, this_rampup, this_rampdown;
|
uint32_t this_F_start, this_rampup, this_rampdown;
|
||||||
enum axis_e prev_lead;
|
|
||||||
int32_t jerk, jerk_e; // Expresses the forces if we would change directions at full speed
|
int32_t jerk, jerk_e; // Expresses the forces if we would change directions at full speed
|
||||||
static uint32_t la_cnt = 0; // Counter: how many moves did we join?
|
static uint32_t la_cnt = 0; // Counter: how many moves did we join?
|
||||||
#ifdef LOOKAHEAD_DEBUG
|
#ifdef LOOKAHEAD_DEBUG
|
||||||
|
|
@ -224,7 +220,6 @@ void dda_join_moves(DDA *prev, DDA *current) {
|
||||||
prev_rampup = prev->rampup_steps;
|
prev_rampup = prev->rampup_steps;
|
||||||
prev_rampdown = prev->rampdown_steps;
|
prev_rampdown = prev->rampdown_steps;
|
||||||
prev_total_steps = prev->total_steps;
|
prev_total_steps = prev->total_steps;
|
||||||
prev_lead = prev->lead;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The initial crossing speed is the minimum between both target speeds
|
// The initial crossing speed is the minimum between both target speeds
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,6 @@
|
||||||
#error "Look-ahead requires steps per m to be identical on the X and Y axis (for now)"
|
#error "Look-ahead requires steps per m to be identical on the X and Y axis (for now)"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Note: the floating point bit is optimized away during compilation
|
|
||||||
#define ACCELERATE_RAMP_LEN(speed) (((speed)*(speed)) / (uint32_t)((7200000.0f * ACCELERATION) / (float)STEPS_PER_M_X))
|
|
||||||
// This is the same to ACCELERATE_RAMP_LEN but now the steps per m can be switched.
|
// This is the same to ACCELERATE_RAMP_LEN but now the steps per m can be switched.
|
||||||
// Note: use this with a macro so the float is removed by the preprocessor
|
// Note: use this with a macro so the float is removed by the preprocessor
|
||||||
#define ACCELERATE_RAMP_SCALER(spm) (uint32_t)((7200000.0f * ACCELERATION) / (float)spm)
|
#define ACCELERATE_RAMP_SCALER(spm) (uint32_t)((7200000.0f * ACCELERATION) / (float)spm)
|
||||||
|
|
|
||||||
|
|
@ -63,4 +63,7 @@ uint16_t int_sqrt(uint32_t a);
|
||||||
// 2 ^ msbloc(v) >= v
|
// 2 ^ msbloc(v) >= v
|
||||||
const uint8_t msbloc (uint32_t v);
|
const uint8_t msbloc (uint32_t v);
|
||||||
|
|
||||||
|
// Note: the floating point bit is optimized away during compilation
|
||||||
|
#define ACCELERATE_RAMP_LEN(speed) (((speed)*(speed)) / (uint32_t)((7200000.0f * ACCELERATION) / (float)STEPS_PER_M_X))
|
||||||
|
|
||||||
#endif /* _DDA_MATHS_H */
|
#endif /* _DDA_MATHS_H */
|
||||||
|
|
|
||||||
|
|
@ -100,9 +100,10 @@ void enqueue_home(TARGET *t, uint8_t endstop_check, uint8_t endstop_stop_cond) {
|
||||||
h &= (MOVEBUFFER_SIZE - 1);
|
h &= (MOVEBUFFER_SIZE - 1);
|
||||||
|
|
||||||
DDA* new_movebuffer = &(movebuffer[h]);
|
DDA* new_movebuffer = &(movebuffer[h]);
|
||||||
|
DDA* prev_movebuffer = (queue_empty() != 0) ? NULL : &movebuffer[mb_head];
|
||||||
if (t != NULL) {
|
|
||||||
dda_create(new_movebuffer, t);
|
if (t != NULL) {
|
||||||
|
dda_create(new_movebuffer, t, prev_movebuffer);
|
||||||
new_movebuffer->endstop_check = endstop_check;
|
new_movebuffer->endstop_check = endstop_check;
|
||||||
new_movebuffer->endstop_stop_cond = endstop_stop_cond;
|
new_movebuffer->endstop_stop_cond = endstop_stop_cond;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue