Move the branch accel_clock into the attic.
This was a very interesting approach, but for the forseeable future it's unlikely the code will replace the current one. However, many parts of it were already moved to the experimental branch. It turns out the approach with recalculating acceleration at a constant time interval is exactly right, but works much more precisely when keeping maths step-based.
This commit is contained in:
parent
5df8eeaacf
commit
1ab42ee8eb
|
|
@ -0,0 +1,363 @@
|
||||||
|
From 1d0b7d8d67c33a6dc6d96ae5de7cc40c755a79c1 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Markus Hitter <mah@jump-ing.de>
|
||||||
|
Date: Mon, 25 Mar 2013 11:19:50 +0100
|
||||||
|
Subject: Implement ACCELERATION_CLOCK.
|
||||||
|
|
||||||
|
This was tried a lot, with the following results:
|
||||||
|
|
||||||
|
1. Doing acceleration calculations (and later, curvature
|
||||||
|
calculations) in an clock based interrupt instead of
|
||||||
|
the step interrupt is an excellent idea. Achievable
|
||||||
|
step rate raised from about 16.000 steps/second
|
||||||
|
to 48.000 steps/second.
|
||||||
|
|
||||||
|
2. The approach to calculate desired speeds from movement time
|
||||||
|
did work not so well. While it's possible to keep geometrical
|
||||||
|
accuracy (continue at minimum speed or stop before decelerating
|
||||||
|
to full stop in case the timing doesn't match), timing
|
||||||
|
calculations are way to inprecise to match a movement's end
|
||||||
|
within +- one step. Missing the movement end by more than 10
|
||||||
|
steps was observed regularly.
|
||||||
|
|
||||||
|
3. Major reasons for 2. are apparently inprecise distance
|
||||||
|
and timer calculations. Even accumulating just 1% of
|
||||||
|
inprecision means more than 100 missed steps at the end
|
||||||
|
of a long move.
|
||||||
|
|
||||||
|
4. To avoid 2., the next approach shall turn back to calculate
|
||||||
|
speeds based on executed steps, like it was done in the step
|
||||||
|
interrupt.
|
||||||
|
|
||||||
|
ACCELERATION_CLOCK is an approach different from the other ones.
|
||||||
|
Acceleration isn't calculated as part of the step interrupt, but
|
||||||
|
on clock based intervals (every 1ms or 2 ms). This not only
|
||||||
|
allows to do these calculations with 16 bit integers, it also
|
||||||
|
reduces the number of these expensive calculations at high speeds.
|
||||||
|
The step interrupt becomes very lean, doing only Bresenham
|
||||||
|
calculations, and should allow much higher step rates (several
|
||||||
|
steps can be done per acceleration calculation). 500 to 1000
|
||||||
|
speed calculations per second should be more than sufficient
|
||||||
|
to give a smooth ride.
|
||||||
|
|
||||||
|
It should be possible to combine this with ACCELERATION_TEMPORAL
|
||||||
|
to give equally spaced steps for _every_ stepper for an even
|
||||||
|
smoother ride.
|
||||||
|
|
||||||
|
More ACCELERATION_CLOCK.
|
||||||
|
|
||||||
|
ACCELERATION_CLOCK: add more refinements and debug code.
|
||||||
|
|
||||||
|
For yet unknown reasons, this strategy falls far below
|
||||||
|
expectations. Configured to 1280 steps/mm, the code works
|
||||||
|
for up to about 500 mm/min, only. ACCELERATION_RAMPING does,
|
||||||
|
despite the expensive acceleration calculation in the step
|
||||||
|
interrupt, manage to move 760 mm/min.
|
||||||
|
|
||||||
|
For finding the cause, I tried to comment out virtually all
|
||||||
|
code out of dda_step() as well as the clock interrupt. Just
|
||||||
|
Bresenham for the X-axis and setTimer() left, the code still
|
||||||
|
acts funny at pretty much the same feedrates. No enhancement
|
||||||
|
at all.
|
||||||
|
|
||||||
|
The debug code currently put in sends a 's' on every step
|
||||||
|
interrupt, a '.' on every clock interrupt. At higher speeds,
|
||||||
|
one should see one '.' every 20 's' or similar. However,
|
||||||
|
from time to time one sees consecutive clock interrupts,
|
||||||
|
apparently step interrupts fail to happen in some
|
||||||
|
situations.
|
||||||
|
|
||||||
|
The good thing: acceleration works reasonably fine now, the
|
||||||
|
situation with clock ticks, and along with them, speed changes,
|
||||||
|
happening more often than actual steps seems to be solved. In
|
||||||
|
earlier code, the first speed calculation right after movement
|
||||||
|
start caused a long pause, leading to something like a delayed,
|
||||||
|
unaccelerated movement.
|
||||||
|
|
||||||
|
Get ACCELERATION_CLOCK finally working. Yikes!
|
||||||
|
|
||||||
|
The problem was: the step interrupt unlocked interrupts and
|
||||||
|
if this resulted in a rush of pending other interrupts,
|
||||||
|
it took a looong time until the step timer was set again.
|
||||||
|
---
|
||||||
|
dda.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
|
||||||
|
dda.h | 13 ++++++
|
||||||
|
2 files changed, 179 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/dda.c b/dda.c
|
||||||
|
index a02f37d..e84f91e 100644
|
||||||
|
--- a/dda.c
|
||||||
|
+++ b/dda.c
|
||||||
|
@@ -25,6 +25,11 @@
|
||||||
|
#ifdef DC_EXTRUDER
|
||||||
|
#include "heater.h"
|
||||||
|
#endif
|
||||||
|
+#include "delay.h"
|
||||||
|
+
|
||||||
|
+#if defined ACCELERATION_RAMPING && defined ACCELERATION_CLOCK
|
||||||
|
+ #error Cant define ACCELERATION_RAMPING and ACCELERATION_CLOCK at the same time.
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
position tracking
|
||||||
|
@@ -347,6 +352,82 @@ void dda_create(DDA *dda, TARGET *target, DDA *prev_dda) {
|
||||||
|
#ifdef LOOKAHEAD
|
||||||
|
dda_join_moves(prev_dda, dda);
|
||||||
|
#endif
|
||||||
|
+ #elif defined ACCELERATION_CLOCK
|
||||||
|
+ uint16_t candidate;
|
||||||
|
+
|
||||||
|
+ // Total time of the unaccelerated move.
|
||||||
|
+ // 1 um/ms = 1 mm/s = 60 mm/min
|
||||||
|
+ dda->time_total = distance * (60 / TICK_TIME_MS) / target->F;
|
||||||
|
+
|
||||||
|
+ // To avoid overspeeding an axis, movement takes at least as
|
||||||
|
+ // long as the slowest axis requires.
|
||||||
|
+ candidate = x_delta_um * (60 / TICK_TIME_MS) / MAXIMUM_FEEDRATE_X;
|
||||||
|
+ if (candidate > dda->time_total)
|
||||||
|
+ dda->time_total = candidate;
|
||||||
|
+ candidate = y_delta_um * (60 / TICK_TIME_MS) / MAXIMUM_FEEDRATE_Y;
|
||||||
|
+ if (candidate > dda->time_total)
|
||||||
|
+ dda->time_total = candidate;
|
||||||
|
+ candidate = z_delta_um * (60 / TICK_TIME_MS) / MAXIMUM_FEEDRATE_Z;
|
||||||
|
+ if (candidate > dda->time_total)
|
||||||
|
+ dda->time_total = candidate;
|
||||||
|
+ candidate = e_delta_um * (60 / TICK_TIME_MS) / MAXIMUM_FEEDRATE_E;
|
||||||
|
+ if (candidate > dda->time_total)
|
||||||
|
+ dda->time_total = candidate;
|
||||||
|
+ if (DEBUG_DDA && (debug_flags & DEBUG_DDA))
|
||||||
|
+ sersendf_P(PSTR("time total %u\n"), dda->time_total);
|
||||||
|
+
|
||||||
|
+ // Re-calculate speeds, as they might have changed.
|
||||||
|
+ dda->F_start = 0;
|
||||||
|
+ dda->F_end = 0;
|
||||||
|
+ dda->F_max = distance * (60 / TICK_TIME_MS) / dda->time_total;
|
||||||
|
+ if (DEBUG_DDA && (debug_flags & DEBUG_DDA))
|
||||||
|
+ sersendf_P(PSTR("corrected F_max %u\n"), dda->F_max);
|
||||||
|
+
|
||||||
|
+ // Time in clock ticks required for acceleration.
|
||||||
|
+ dda->time_accel = ((uint32_t)(dda->F_max - dda->F_start)) *
|
||||||
|
+ ((uint32_t)(1000 / TICK_TIME_MS)) /
|
||||||
|
+ ((uint32_t)(60 * ACCELERATION));
|
||||||
|
+ if (DEBUG_DDA && (debug_flags & DEBUG_DDA))
|
||||||
|
+ sersendf_P(PSTR("time accel %u\n"), dda->time_accel);
|
||||||
|
+
|
||||||
|
+ // Time in clock ticks required for deceleration.
|
||||||
|
+ dda->time_decel = ((uint32_t)(dda->F_max - dda->F_end)) *
|
||||||
|
+ ((uint32_t)(1000 / TICK_TIME_MS)) /
|
||||||
|
+ ((uint32_t)(60 * ACCELERATION));
|
||||||
|
+ if (DEBUG_DDA && (debug_flags & DEBUG_DDA))
|
||||||
|
+ sersendf_P(PSTR("time decel %u\n"), dda->time_decel);
|
||||||
|
+
|
||||||
|
+ // Add time required for acceleration / deceleration.
|
||||||
|
+ dda->time_total += dda->time_accel / 2 + dda->time_decel / 2;
|
||||||
|
+ if (DEBUG_DDA && (debug_flags & DEBUG_DDA))
|
||||||
|
+ sersendf_P(PSTR("time total w. accel %u\n"), dda->time_total);
|
||||||
|
+ dda->time_decel = dda->time_total - dda->time_decel;
|
||||||
|
+ if (DEBUG_DDA && (debug_flags & DEBUG_DDA))
|
||||||
|
+ sersendf_P(PSTR("time decel2 %u\n"), dda->time_decel);
|
||||||
|
+
|
||||||
|
+ // UGLY HACK: to compensate for inaccurate ac- and deceleration
|
||||||
|
+ // time calculations, add a margin here:
|
||||||
|
+// dda->time_decel += (dda->time_accel >> 3);
|
||||||
|
+//sersendf_P(PSTR("time decel hacked %u\n"), dda->time_decel); delay_ms(10);
|
||||||
|
+
|
||||||
|
+ // This is the ratio between F (in mm/min) and c (in CPU clock ticks)
|
||||||
|
+ // and is constant during the entire move, even on curved movements.
|
||||||
|
+ // Essentially, it's the step rate of the fastest stepping stepper
|
||||||
|
+ // of the entire move.
|
||||||
|
+ // For linear movements it's simple:
|
||||||
|
+ dda->f_to_c = (distance * 2400L) / dda->total_steps * (F_CPU / 40000) << 8;
|
||||||
|
+ if (DEBUG_DDA && (debug_flags & DEBUG_DDA))
|
||||||
|
+ sersendf_P(PSTR("f_to_c %lu\n"), dda->f_to_c);
|
||||||
|
+
|
||||||
|
+ // Initial step delays. As we can't start with zero speed, advance
|
||||||
|
+ // all calculations by half a clock tick.
|
||||||
|
+ // v = a * t; c = 1 / v;
|
||||||
|
+// Don't forget F_start!
|
||||||
|
+ dda->c = dda->f_to_c / ((uint32_t)ACCELERATION * 60UL * TICK_TIME_MS / 1000UL);
|
||||||
|
+
|
||||||
|
+sersendf_P(PSTR("c_min new %lu\n"), dda->f_to_c / target->F); delay_ms(10);
|
||||||
|
+sersendf_P(PSTR("c_min trad %lu\n"), (move_duration / target->F) << 8); delay_ms(10);
|
||||||
|
+
|
||||||
|
#elif defined ACCELERATION_TEMPORAL
|
||||||
|
// TODO: limit speed of individual axes to MAXIMUM_FEEDRATE
|
||||||
|
// TODO: calculate acceleration/deceleration for each axis
|
||||||
|
@@ -445,6 +526,10 @@ void dda_start(DDA *dda) {
|
||||||
|
else
|
||||||
|
setTimer(move_state.c >> 8);
|
||||||
|
#else
|
||||||
|
+ #ifdef ACCELERATION_CLOCK
|
||||||
|
+ move_state.time_current = 0;
|
||||||
|
+ move_state.ticks_since_step = 0;
|
||||||
|
+ #endif
|
||||||
|
setTimer(dda->c >> 8);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
@@ -537,7 +622,7 @@ void dda_step(DDA *dda) {
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
- #if STEP_INTERRUPT_INTERRUPTIBLE
|
||||||
|
+ #if defined STEP_INTERRUPT_INTERRUPTIBLE && ! defined ACCELERATION_CLOCK
|
||||||
|
// Since we have sent steps to all the motors that will be stepping
|
||||||
|
// and the rest of this function isn't so time critical, this interrupt
|
||||||
|
// can now be interruptible by other interrupts.
|
||||||
|
@@ -582,7 +667,6 @@ void dda_step(DDA *dda) {
|
||||||
|
//if (move_state.step_no == 0) {
|
||||||
|
// sersendf_P(PSTR("\r\nc %lu c_min %lu n %d"), dda->c, dda->c_min, move_state.n);
|
||||||
|
//}
|
||||||
|
-
|
||||||
|
recalc_speed = 0;
|
||||||
|
if (move_state.step_no < dda->rampup_steps) {
|
||||||
|
if (move_state.n < 0) // wrong ramp direction
|
||||||
|
@@ -678,6 +762,11 @@ void dda_step(DDA *dda) {
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
dda->live = 0;
|
||||||
|
+ #ifdef ACCELERATION_CLOCK
|
||||||
|
+ if (dda->time_total - move_state.time_current > 1)
|
||||||
|
+ sersendf_P(PSTR("undershoot by %u ticks\n"),
|
||||||
|
+ dda->time_total - move_state.time_current);
|
||||||
|
+ #endif
|
||||||
|
#ifdef LOOKAHEAD
|
||||||
|
// If look-ahead was using this move, it could have missed our activation:
|
||||||
|
// make sure the ids do not match.
|
||||||
|
@@ -701,6 +790,9 @@ void dda_step(DDA *dda) {
|
||||||
|
else
|
||||||
|
setTimer(move_state.c >> 8);
|
||||||
|
#else
|
||||||
|
+ #ifdef ACCELERATION_CLOCK
|
||||||
|
+ move_state.ticks_since_step = 0;
|
||||||
|
+ #endif
|
||||||
|
setTimer(dda->c >> 8);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@@ -728,6 +820,8 @@ void dda_clock() {
|
||||||
|
static DDA *last_dda = NULL;
|
||||||
|
static uint8_t endstop_stop = 0; ///< Stop due to endstop trigger
|
||||||
|
|
||||||
|
+ move_state.time_current++;
|
||||||
|
+
|
||||||
|
dda = queue_current_movement();
|
||||||
|
if (dda != last_dda) {
|
||||||
|
move_state.debounce_count_xmin = move_state.debounce_count_ymin =
|
||||||
|
@@ -742,8 +836,11 @@ void dda_clock() {
|
||||||
|
|
||||||
|
// Lengthy calculations ahead!
|
||||||
|
// Make sure we didn't re-enter, then allow nested interrupts.
|
||||||
|
- if (busy)
|
||||||
|
+ if (busy) {
|
||||||
|
+ if (DEBUG_DDA && (debug_flags & DEBUG_DDA))
|
||||||
|
+ serial_writechar('B');
|
||||||
|
return;
|
||||||
|
+ }
|
||||||
|
busy = 1;
|
||||||
|
sei();
|
||||||
|
|
||||||
|
@@ -826,6 +923,72 @@ void dda_clock() {
|
||||||
|
}
|
||||||
|
} /* if (endstop_stop == 0) */
|
||||||
|
|
||||||
|
+ #ifdef ACCELERATION_CLOCK
|
||||||
|
+ uint32_t new_c = 0;
|
||||||
|
+ static uint8_t plateau_done = 0;
|
||||||
|
+
|
||||||
|
+ // Overtime?
|
||||||
|
+ if (move_state.time_current > dda->time_total) {
|
||||||
|
+ // Keep it short to have at least a chance to get it sent.
|
||||||
|
+ #warning Das hier hört nicht auf.
|
||||||
|
+ //serial_writestr_P(PSTR("ot"));
|
||||||
|
+ move_state.time_current = dda->time_total;
|
||||||
|
+ }
|
||||||
|
+ // Acceleration time.
|
||||||
|
+ else if (move_state.time_current < dda->time_accel) {
|
||||||
|
+ // v = a * t; c = 1 / v;
|
||||||
|
+ new_c = dda->f_to_c / ((uint32_t)ACCELERATION * 60UL * (uint32_t)move_state.time_current * TICK_TIME_MS / 1000UL);
|
||||||
|
+ plateau_done = 0;
|
||||||
|
+serial_writechar('a');
|
||||||
|
+ }
|
||||||
|
+ else if (move_state.time_current > dda->time_decel) {
|
||||||
|
+ uint32_t dt = (uint32_t)dda->time_total - (uint32_t)move_state.time_current;
|
||||||
|
+
|
||||||
|
+ if (dt < 1) // we undershot *sigh*
|
||||||
|
+ dt = 1;
|
||||||
|
+ // v = a * t; c = 1 / v;
|
||||||
|
+ new_c = dda->f_to_c / ((uint32_t)ACCELERATION * 60UL * dt * TICK_TIME_MS / 1000UL);
|
||||||
|
+serial_writechar('d');
|
||||||
|
+ plateau_done = 0;
|
||||||
|
+
|
||||||
|
+ }
|
||||||
|
+ // Plateau time.
|
||||||
|
+ else if (plateau_done == 0) {
|
||||||
|
+ new_c = dda->f_to_c / dda->F_max;
|
||||||
|
+ plateau_done = 1;
|
||||||
|
+serial_writechar('r');
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+serial_writechar('.');
|
||||||
|
+
|
||||||
|
+ if (new_c) {
|
||||||
|
+ ATOMIC_START
|
||||||
|
+ dda->c = new_c;
|
||||||
|
+ ATOMIC_END
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Set up or readjust the timer if actual steps happen too slowly. dda_step()
|
||||||
|
+ // resets ticks_since_step to zero, while we increment it here, so we have an
|
||||||
|
+ // idea on how much time is gone since the last actual step.
|
||||||
|
+ // 300 = minimum time setTimer requires.
|
||||||
|
+if (dda->time_total == move_state.time_current)
|
||||||
|
+sersendf_P(PSTR("overshoot by %lu steps\n"), move_state.x_steps);
|
||||||
|
+ if (move_state.ticks_since_step) {
|
||||||
|
+ if ((dda->c >> 8) < ((uint32_t)move_state.ticks_since_step * TICK_TIME) + 300UL) {
|
||||||
|
+ // We're too late already, go as quick as possbile.
|
||||||
|
+ setTimer(300UL);
|
||||||
|
+serial_writechar('-');
|
||||||
|
+ }
|
||||||
|
+ else {
|
||||||
|
+ // TODO: we ignore the time taken until we get here.
|
||||||
|
+ setTimer((dda->c >> 8) - ((uint32_t)move_state.ticks_since_step * TICK_TIME));
|
||||||
|
+serial_writechar('+');
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ sei(); // setTimer locks interrupts
|
||||||
|
+ move_state.ticks_since_step++;
|
||||||
|
+ #endif
|
||||||
|
+
|
||||||
|
cli(); // Compensate sei() above.
|
||||||
|
busy = 0;
|
||||||
|
}
|
||||||
|
diff --git a/dda.h b/dda.h
|
||||||
|
index 5bc4238..76963ac 100644
|
||||||
|
--- a/dda.h
|
||||||
|
+++ b/dda.h
|
||||||
|
@@ -77,6 +77,10 @@ typedef struct {
|
||||||
|
/// tracking variable
|
||||||
|
int32_t n;
|
||||||
|
#endif
|
||||||
|
+ #ifdef ACCELERATION_CLOCK
|
||||||
|
+ uint16_t time_current;
|
||||||
|
+ uint8_t ticks_since_step;
|
||||||
|
+ #endif
|
||||||
|
#ifdef ACCELERATION_TEMPORAL
|
||||||
|
uint32_t x_time; ///< time of the last x step
|
||||||
|
uint32_t y_time; ///< time of the last y step
|
||||||
|
@@ -160,6 +164,15 @@ typedef struct {
|
||||||
|
uint8_t id;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
+ #ifdef ACCELERATION_CLOCK
|
||||||
|
+ uint16_t F_start;
|
||||||
|
+ uint16_t F_end;
|
||||||
|
+ uint16_t F_max;
|
||||||
|
+ uint16_t time_accel; ///< in clock ticks (1ms or 2ms)
|
||||||
|
+ uint16_t time_decel; ///< in clock ticks (1ms or 2ms)
|
||||||
|
+ uint16_t time_total; ///< in clock ticks (1ms or 2ms)
|
||||||
|
+ uint32_t f_to_c;
|
||||||
|
+ #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
|
||||||
|
--
|
||||||
|
1.8.3.2
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,227 @@
|
||||||
|
#ifndef _DDA_H
|
||||||
|
#define _DDA_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifdef ACCELERATION_REPRAP
|
||||||
|
#ifdef ACCELERATION_RAMPING
|
||||||
|
#error Cant use ACCELERATION_REPRAP and ACCELERATION_RAMPING together.
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
types
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Enum to denote an axis
|
||||||
|
enum axis_e { X, Y, Z, E };
|
||||||
|
|
||||||
|
/**
|
||||||
|
\struct TARGET
|
||||||
|
\brief target is simply a point in space/time
|
||||||
|
|
||||||
|
X, Y, Z and E are in micrometers unless explcitely stated. F is in mm/min.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
// TODO TODO: We should really make up a loop for all axes.
|
||||||
|
// Think of what happens when a sixth axis (multi colour extruder)
|
||||||
|
// appears?
|
||||||
|
int32_t X;
|
||||||
|
int32_t Y;
|
||||||
|
int32_t Z;
|
||||||
|
int32_t E;
|
||||||
|
uint32_t F;
|
||||||
|
|
||||||
|
uint8_t e_relative :1; ///< bool: e axis relative? Overrides all_relative
|
||||||
|
} 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
|
||||||
|
\brief this struct is made for tracking the current state of the movement
|
||||||
|
|
||||||
|
Parts of this struct are initialised only once per reboot, so make sure dda_step() leaves them with a value compatible to begin a new movement at the end of the movement. Other parts are filled in by dda_start().
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
// bresenham counters
|
||||||
|
int32_t x_counter; ///< counter for total_steps vs this axis
|
||||||
|
int32_t y_counter; ///< counter for total_steps vs this axis
|
||||||
|
int32_t z_counter; ///< counter for total_steps vs this axis
|
||||||
|
int32_t e_counter; ///< counter for total_steps vs this axis
|
||||||
|
|
||||||
|
// step counters
|
||||||
|
uint32_t x_steps; ///< number of steps on X axis
|
||||||
|
uint32_t y_steps; ///< number of steps on Y axis
|
||||||
|
uint32_t z_steps; ///< number of steps on Z axis
|
||||||
|
uint32_t e_steps; ///< number of steps on E axis
|
||||||
|
|
||||||
|
#ifdef ACCELERATION_RAMPING
|
||||||
|
/// counts actual steps done
|
||||||
|
uint32_t step_no;
|
||||||
|
/// time until next step
|
||||||
|
uint32_t c;
|
||||||
|
/// tracking variable
|
||||||
|
int32_t n;
|
||||||
|
#endif
|
||||||
|
#ifdef ACCELERATION_CLOCK
|
||||||
|
uint16_t time_current;
|
||||||
|
uint8_t ticks_since_step;
|
||||||
|
#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;
|
||||||
|
uint8_t debounce_count_xmax, debounce_count_ymax, debounce_count_zmax;
|
||||||
|
} MOVE_STATE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
\struct DDA
|
||||||
|
\brief this is a digital differential analyser data struct
|
||||||
|
|
||||||
|
This struct holds all the details of an individual multi-axis move, including pre-calculated acceleration data.
|
||||||
|
This struct is filled in by dda_create(), called from enqueue(), called mostly from gcode_process() and from a few other places too (eg \file homing.c)
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/// this is where we should finish
|
||||||
|
TARGET endpoint;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
// status fields
|
||||||
|
uint8_t nullmove :1; ///< bool: no axes move, maybe we wait for temperatures or change speed
|
||||||
|
uint8_t live :1; ///< bool: this DDA is running and still has steps to do
|
||||||
|
#ifdef ACCELERATION_REPRAP
|
||||||
|
uint8_t accel :1; ///< bool: speed changes during this move, run accel code
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// wait for temperature to stabilise flag
|
||||||
|
uint8_t waitfor_temp :1; ///< bool: wait for temperatures to reach their set values
|
||||||
|
|
||||||
|
// directions
|
||||||
|
uint8_t x_direction :1; ///< direction flag for X axis
|
||||||
|
uint8_t y_direction :1; ///< direction flag for Y axis
|
||||||
|
uint8_t z_direction :1; ///< direction flag for Z axis
|
||||||
|
uint8_t e_direction :1; ///< direction flag for E axis
|
||||||
|
};
|
||||||
|
uint8_t allflags; ///< used for clearing all flags
|
||||||
|
};
|
||||||
|
|
||||||
|
// distances
|
||||||
|
uint32_t x_delta; ///< number of steps on X axis
|
||||||
|
uint32_t y_delta; ///< number of steps on Y axis
|
||||||
|
uint32_t z_delta; ///< number of steps on Z axis
|
||||||
|
uint32_t e_delta; ///< number of steps on E axis
|
||||||
|
|
||||||
|
/// total number of steps: set to \f$\max(\Delta x, \Delta y, \Delta z, \Delta e)\f$
|
||||||
|
uint32_t total_steps;
|
||||||
|
|
||||||
|
uint32_t c; ///< time until next step, 24.8 fixed point
|
||||||
|
|
||||||
|
#ifdef ACCELERATION_REPRAP
|
||||||
|
uint32_t end_c; ///< time between 2nd last step and last step
|
||||||
|
int32_t n; ///< precalculated step time offset variable. At every step we calculate \f$c = c - (2 c / n)\f$; \f$n+=4\f$. See http://www.embedded.com/columns/technicalinsights/56800129?printable=true for full description
|
||||||
|
#endif
|
||||||
|
#ifdef ACCELERATION_RAMPING
|
||||||
|
/// number of steps accelerating
|
||||||
|
uint32_t rampup_steps;
|
||||||
|
/// number of last step before decelerating
|
||||||
|
uint32_t rampdown_steps;
|
||||||
|
/// 24.8 fixed point timer value, maximum speed
|
||||||
|
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
|
||||||
|
#ifdef ACCELERATION_CLOCK
|
||||||
|
uint16_t F_start;
|
||||||
|
uint16_t F_end;
|
||||||
|
uint16_t F_max;
|
||||||
|
uint16_t time_accel; ///< in clock ticks (1ms or 2ms)
|
||||||
|
uint16_t time_decel; ///< in clock ticks (1ms or 2ms)
|
||||||
|
uint16_t time_total; ///< in clock ticks (1ms or 2ms)
|
||||||
|
uint32_t f_to_c;
|
||||||
|
#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
|
||||||
|
uint8_t endstop_stop_cond; ///< Endstop condition on which to stop motion: 0=Stop on detrigger, 1=Stop on trigger
|
||||||
|
} DDA;
|
||||||
|
|
||||||
|
/*
|
||||||
|
variables
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// startpoint holds the endpoint of the most recently created DDA, so we know where the next one created starts. could also be called last_endpoint
|
||||||
|
extern TARGET startpoint;
|
||||||
|
|
||||||
|
/// the same as above, counted in motor steps
|
||||||
|
extern TARGET startpoint_steps;
|
||||||
|
|
||||||
|
/// current_position holds the machine's current position. this is only updated when we step, or when G92 (set home) is received.
|
||||||
|
extern TARGET current_position;
|
||||||
|
|
||||||
|
/*
|
||||||
|
methods
|
||||||
|
*/
|
||||||
|
|
||||||
|
// initialize dda structures
|
||||||
|
void dda_init(void);
|
||||||
|
|
||||||
|
// distribute a new startpoint
|
||||||
|
void dda_new_startpoint(void);
|
||||||
|
|
||||||
|
// create a DDA
|
||||||
|
void dda_create(DDA *dda, TARGET *target, DDA *prev_dda);
|
||||||
|
|
||||||
|
// start a created DDA (called from timer interrupt)
|
||||||
|
void dda_start(DDA *dda) __attribute__ ((hot));
|
||||||
|
|
||||||
|
// DDA takes one step (called from timer interrupt)
|
||||||
|
void dda_step(DDA *dda) __attribute__ ((hot));
|
||||||
|
|
||||||
|
// regular movement maintenance
|
||||||
|
void dda_clock(void);
|
||||||
|
|
||||||
|
// update current_position
|
||||||
|
void update_current_position(void);
|
||||||
|
|
||||||
|
#endif /* _DDA_H */
|
||||||
Loading…
Reference in New Issue