A simple way to achieve an acceleration profile for a stepper motor (fixed step size).

## Math behind it

### Discrete stepping and acceleration

When using a stepper motor, we want to avoid running it immediately at full speed especially if a mass is attached to the motor since it is quite likely to induce miss-stepping. In our case, we use a stepper attached to a lead screw forming a linear stage. The stage now performs a linear motion over a total distance defined as \( \Delta s \). This distance can be defined through a certain number of discrete steps \(n_s\) each having a step length \(s_s\) defined through the number of steps per revolution \(n_r = 400 \frac{steps}{rev} \) and the pitch of the lead screw \( p = 8 \frac{mm}{rev} \):

\begin{equation}

s_s = \frac{p}{n_r}, \Delta s = s_s \cdot n_s

\end{equation}

In the ideal case we would like to follow a linear increase in velocity followed by a constant plateau of maximum movement velocity \(v_m\) followed by a decrease in velocity. In case of the iterative routine in which we step the motor, it makes most sense to have a formula reversely telling us which velocity we want to drive for the upcoming step \(i_s\) which has the center position \(s\):

\begin{equation}

s = (i_s + 0.5) \cdot s_s, i_s \in [0, n_s – 1]

\end{equation}

The velocity of a stepper motor is thereby translated into the delay time \(t_d\) before the next discrete step occurs:

\begin{equation}

t_d = \frac{s_s}{v}

\end{equation}

### Linear acceleration phase

In the acceleration phase, our linearly accelerated velocity profile is described as:

\begin{equation}

s = \frac{1}{2} \cdot a \cdot t^2

\label{eq:lin_acc_dist}

\end{equation}

with the velocity \(v\) being defined as:

\begin{equation}

v = a \cdot t

\label{eq:lin_acc_vel}

\end{equation}

Solving this equation for \(v(s)\) leads to:

\begin{equation}

v = \sqrt{2 \cdot s \cdot a}

\end{equation}

### Constant velocity phase

In this case we just have the velocity at a constant level \(v_m\).

### Linear deceleration phase

For the deceleration phase, we have the following description of the velocity profile:

\begin{equation}

v = v_m – a \cdot (t – t_2)

\end{equation}

or solved after \((t-t_2)\)

\begin{equation}

t – t_2 = \frac{v_m – v}{a}

\end{equation}

with its distance counterpart

\begin{equation}

s = s_2 + v_m \cdot (t – t_2) – \frac{1}{2} \cdot a \cdot (t – t_2)^2

\end{equation}

or

\begin{equation}

-s = -s_2 – v_m \cdot \frac{v_m – v}{a} + \frac{(v_m – v)^2}{2 \cdot a}

\end{equation}

\begin{equation}

0 = \frac{1}{2 \cdot a} \cdot (v_m – v)^2 + \frac{-v_m}{a} \cdot (v_m – v) + (s – s_2)

\end{equation}

Solving the quadratic equation through

\begin{equation}

x_{1,2} = \frac{-b \pm \sqrt{b^2 – 4 ac }}{2a}

\end{equation}

leads to

\begin{equation}

(v_m – v)_{1,2} = \frac{\frac{v_m}{a} \pm \sqrt{\frac{v_m^2}{a^2} – \frac{2}{a}\cdot (s – s_2) }}{\frac{1}{a} }

\end{equation}

\begin{equation}

(v_m – v)_{1,2} = v_m \pm \cdot \sqrt{v_m^2 – 2 \cdot a \cdot (s – s_2) }

\end{equation}

\begin{equation}

v = \sqrt{v_m^2 – 2 \cdot a \cdot (s- s_2)}

\end{equation}

### Case switch

In practice we now need to find the thresholds for the three phases. \(s_1\) is defined as the position where full speed is reached, \(s_2\) is the position where we start decelerating.

We can extract the first distance as

\begin{equation}

s_1 = \frac{v_m^2}{2 \cdot a}

\end{equation}

and the second one as

\begin{equation}

s_2 = \Delta s – s_1

\end{equation}

If \(s_1\) becomes larger then \(s_2\) it means that full velocity will not be reached due to a short travel length or low acceleration. In this case we set \(s_1 = s_2 = \Delta s / 2\) and redefine \(v_m\):

\begin{equation}

v_m = \sqrt{\Delta s \cdot a}

\end{equation}

## Microcontroller implementation (Teensy)

// define before // s --> step size in mm // vmax --> maximum desired linear velocity in mm / s // acc --> acceleration in mm/(s*s) // deltaS --> distance to travel uint32_t absSteps = round(abs(deltaS) / s); // number of steps we need to do // define end point of acceleration and start point of deceleration float s_1 = vmax * vmax / (2 * acc); float s_2 = deltaS - s_1; if (s_1 > s_2) // if we dont even reach full speed { s_1 = deltaS / 2; s_2 = deltaS / 2; vmax = sqrt(deltaS * acc); } float vcurr = 0; bool stepPolarity = 0; for (int32_t incStep = 0; incStep < absSteps; incStep++) { // calculate central position of current step const float s = ((float) incStep + 0.5) * ss; // calculate velocity at current step if (s < s_1) { vcurr = sqrt(2 * s * acc); } else if (s < s_2) { vcurr = vmax; } else { vcurr = sqrt(vmax * vmax - 2 * (s - s_2) * acc); } // convert velocity to delay const uint32_t tDelay = round(ss / vcurr * 1e6); // in micros // act accordingly stepPolarity = !stepPolarity; digitalWriteFast(pinStep, stepPolarity); delayMicroseconds(tDelay); }