A given stepper motor driver connected to some given motor has a maximum mechanical power output. Some of that mechanical power is converted to kinetic energy -- using power proportional to acceleration -- to overcome the inertia of the mass being moved. Attempting to accelerate too fast requires more power than is available, which causes the stepper motor to "skip steps" ("losing steps"), which generally ruins the print. If inertia were zero, then the fastest way to print out a part would be to use constant velocity. Due to inertia, the constant velocity which can be reached from zero speed is very low. Therefore, using a reliable constant velocity results in very slow movement.
Using acceleration we can achieve a variable velocity profile which allows us to reach higher speeds.
Constant acceleration (and deceleration) results in trapezoidal velocity, a velocity profile that gradually "ramps up" and "ramps down" between different speeds. Gradually ramping up the velocity at constant acceleration lets us move things around at much higher speeds without losing steps, compared to early RepRap prototypes which instantly set new speeds without acceleration control.(  ).
The FiveD firmware changes speed by a fixed amount each step, however this also alters the step time. acceleration = dv/dt, so with a fixed dv but a changing dt, acceleration changes during a move. This makes high speeds quite unattainable as the acceleration quickly outstrips the motor's ability to keep up.
I don't remember how I calculated and integrated the acceleration term into the below, feel free to work it out from the article and update this description.
- sf and ef are start and end feedrates in mm/min
- dx, dy and dz are move distances along each axis
- distance is the movement distance, equivalent to sqrt(dx^2 + dy^2 + dz^2)
- ts is total steps, equivalent to max(dx, dy, dz).
- c and end_c are start and end step timer values
- CF shall refer to conversion factors necessary for unit translations but mostly irrelevant to describing this process.
so, here we go
c (tick/step) = um/step * min/mm * CF[min->tick] um/step = distance / ts sf = mm/min c = tick/step = min/step * CF[min->tick] = distance / ts / sf * CF[min->tick]
end_c = distance / ts / ef * CF[min->tick]
from [the article]
n = ts * sf^2 / (ef^2 - sf^2) [Equation 16]
and in each step we calculate
c = c - (2c / (4n + 1)) [Equation 13] n += 1
however I have integrated 4n+1 into the initial setup of n, which simplified this to:
n = (ts * sf^2 / ((ef^2 - sf^2) / 4)) + 1
then after each step
c = c - (2c / n) n += 4
c must be checked against end_c - because this is an integer approximation of a recursive function, mere loss of precision causes significant cumulative error. I had to implement c and end_c as 24.8 fixed point in order to maintain usable resemblance to the ideal values.
As a result of its calculation, n is positive when accelerating and negative when decelerating so we don't need to differentiate between them.
Since sf^2, ef^2 and ((sf^2 - ef^2) / 4) are used fairly often, I precalculate them into ssq, esq and dsq respectively in my implementation.
Also, since ssq, esq and dsq are only ever used in ratio with one another, I can scale sf and ef by any factor I like in order to keep the precision within 32 bits.