DIY — MCGBot Engine Treibersoftware (Teil 1) Theorie

Schrittmotor Treiber: Grundlagen zur Eigenentwicklung

Zunächst einmal ist es um einiges einfacher mit dem Motor Shield von Ladyada zwei Schrittmotoren zu steuern. Der einzige Nachteil ist, dass das Motor Shield so viel kann und deshalb sehr viele digitale Pin verwendet. Für den ersten Prototyp werde ich das Shield von Ladyada und die beiden zugehörigen Bibliotheken (AFmotor und AccelStepper) verwenden. Die beiden Bibliotheken sind gut durchdacht und sehr gut dokumentiert.

Ich habe mich ein letzter Zeit mit der Steuerung von Schrittmotoren befasst und möchte daher die Grundzüge einer eigenen Bibliothek zur Steuerung von zwei Schrittmotoren vorstellen. Mein Startpunkt war der Blog-Eintrag S-Curve for EasyDriver v3 Stepper Motor Driver von Chris E. Er stellt einen Sketch vor, der eine Schrittmotor eine feste Anzahl von Schritten sich drehen lässt. Dabei aber zuerst eine vorgegebene Zeitspanne beschleunigt, die erreichte Geschwindigkeit hält und dann eine vorgegebene Zeitspanne den Motor abbremst. Eigentlich genau das, was man für ein Fahrzeug haben möchte.

Ich habe das Shield S-Curve for EasyDriver v3 Stepper Motor Driver verwendet. Aber man kann auch auf der Grundlage des A3967 Microstepping Driver und einem Breadboard sein eigenes Motorshield zusammenbauen.

Von den Zeitschritten zur Anzahl der Schritte

Als erste Aufgabe soll der Bot ein Stück Weg gerade aus fahren. Dabei soll er zuerst beschleunigen bis zu einer Vorgegebenen maximalen Geschwindigkeit, diese eine bestimmte Zeit beibehalten und dann abbremsen. Da sich die Schrittmotoren bei jedem Puls um einen festen Winkel  $\Delta \theta = \frac{360}{n}$ weiter drehen. Wird die Winkelgeschwindigkeit \phi = \frac{\Delta \theta}{\Delta t} nur durch die Wartezeit  $\Delta t zwischen zwei Pulsen beeinflusst. Wenn  $\Delta t größer wird ist die Winkelgeschwindigkeit kleiner und umgekehrt.

<br /> \begin{tikzpicture}[scale=2]</p> <p>% Include tikz into local preamble<br /> [+preamble]<br />      \usepackage{tikz}<br /> [/preamble]<br />   %\draw[style=help lines] (0,0) grid (7,4);<br />   % dt(t) function<br />   \draw[blue, line width=2] (0,3) -- (2,1);<br />   \draw[blue, line width=2] (2,1) -- (5,1);<br />   \draw[blue, line width=2] (5,1) -- (7,3);  </p> <p>  \draw[grey, dotted, line width=1] (2,3.1) -- (2,-0.1) node[below] {$t_1$};<br />   \draw[grey, dotted, line width=1] (5,3.1) -- (5,-0.1) node[below] {$t_2$};<br />   \draw[grey, dotted, line width=1] (7,3.1) -- (7,-0.1) node[below] {$t_{end}$}; </p> <p>  \draw[grey, dotted, line width=1] (7,3) -- (-0.1,3) node[left] {$\Delta t_{max}$};<br />   \draw[grey, dotted, line width=1] (7,1) -- (-0.1,1) node[left] {$\Delta t_{min}$}; </p> <p>  \draw[->]  (-0.2,0) -- (7.2,0) node[right] {\Large $t$};<br />   \draw[->]  (0,-0.2) -- (0,3.4) node[above] {\Large $\Delta t(t)$};</p> <p>  \node [above] at (1,2.6) {\Lage I};<br />   \node [above] at (3.5,2.6) {\Lage II};<br />   \node [above] at (6,2.6) {\Lage III};</p> <p>\end{tikzpicture}<br />
<br /> \begin{tikzpicture}[scale=2]</p> <p>% Include tikz into local preamble<br /> [+preamble]<br />      \usepackage{tikz}<br /> [/preamble]<br />   %\draw[style=help lines] (0,0) grid (7,4);<br />   % phi(t) function<br />   \draw[red, line width=2] (0,1) -- (2,3);<br />   \draw[red, line width=2] (2,3) -- (5,3);<br />   \draw[red, line width=2] (5,3) -- (7,1);  </p> <p>  \draw[grey, dotted, line width=1] (2,3.1) -- (2,-0.1) node[below] {$t_1$};<br />   \draw[grey, dotted, line width=1] (5,3.1) -- (5,-0.1) node[below] {$t_2$};<br />   \draw[grey, dotted, line width=1] (7,3.1) -- (7,-0.1) node[below] {$t_{end}$}; </p> <p>  \draw[grey, dotted, line width=1] (7,3) -- (-0.1,3) node[left] {$\phi_{max}$};<br />   \draw[grey, dotted, line width=1] (7,1) -- (-0.1,1) node[left] {$\phi_{min}$}; </p> <p>  \draw[->]  (-0.2,0) -- (7.2,0) node[right] {\Large $t$};<br />   \draw[->]  (0,-0.2) -- (0,3.4) node[above] {\Large $\phi(t)$};</p> <p>  \node [above] at (1,2.6) {\Lage I};<br />   \node [above] at (3.5,2.6) {\Lage II};<br />   \node [above] at (6,2.6) {\Lage III};</p> <p>\end{tikzpicture}<br />

Ziel: Berechnung der Schrittanzahl

Die Frage ist nun, welche Anzahl an einzelne Schritte führen die Schrittmotoren im Zeitintervall  $ \left[0,t_{end}\right] $ aus? Dann weiß man um auch welche Gesamtwinkel sich die Schrittmotoren gedreht haben und damit die Länge des zurückgelegten Weges.

Berechnung der Gesamtzeit  $t_N$

Da die Bereiche I und III die identische Anzahl von Schritten haben, genügt es nur Bereich III zu betrachten. Um das Problem einfach zu halten, betrachte ich die Funktion  $\Delta t(t) = a t$ . Damit erhält man die interativen Formel für den neuen Zeitpunkt  $t_{k+1}$ zu:

\begin{eqnarray*} t_{k+1} = t_k + dt  \end{eqnarray*} oder
\begin{eqnarray} t_{k+1} = (1+a) t_k \end{eqnarray} .
Der Ausdruck  $(1+a)$ kann als Propergator der Dynamik verstanden werden.
Der Zusammenhang ist in der Abbildung verdeutlicht.
<br /> \begin{tikzpicture}[scale=1]</p> <p>% Include tikz into local preamble<br /> [+preamble]<br />      \usepackage{tikz}<br /> [/preamble]<br />   %\draw[style=help lines] (0,0) grid (4,4);<br />   % dt(t) function<br />   \draw[blue, line width=2] (0,0) -- (3.7,4);    </p> <p>  \draw[grey, line width=1] (0.7,0.1) -- (0.7,-0.1) node[below] {$t_k$};<br />   \draw[grey, line width=1] (1.3,0.1) -- (1.3,-0.1) node[below] {$t_{k+2}$};<br />   \draw[grey, dotted, line width=1] (3.2,4.2) -- (3.2,-0.1) node[below] {$t_N$}; </p> <p>  \draw[->]  (-0.2,0) -- (4.2,0) node[right] {\Large $t$};<br />   \draw[->]  (0,-0.2) -- (0,4.4) node[above] {\Large $dt(t)$};</p> <p>\end{tikzpicture}<br />

Nun muss man von der interativen Darstellung der Dynamik zu einer expliziten Darstellung übergehen. Dazu schaut man sich die ersten Schritte der Dynamik an:

<br />         \begin{eqnarray*}<br />           t_{0} && \quad \intertext{gegeben} \\<br /> 	  t_{1} &=& (1+a)t_{0} \\<br /> 	  t_{2} &=& (1+a)t_{1} = (1+a)(1+a)t_0 = (1+a)^2 t_0<br /> 	\end{eqnarray*}<br />
Somit erhält man die Vermutung:
<br />         \begin{eqnarray}<br />           t_{k} = (1+a)t_{k-1} = \dots = (1+a)^k t_0<br />         \end{eqnarray}<br />

Beweis dieser Vermutung mit Hilfe der vollständigen Induktion:
Induktions Anfang:  $ k = 0 $ ist ok
Induktions Behauptung:  $ t_k = (1+a)^k t_0 $ sei richtig
Induktionsschritt:  $ k \to k+1 $
<br />         \begin{eqnarray*}<br />           t_{k+1} = (1+a)t_{k} = (1+a) (1+a)^k t_0 = (1+a)^{k+1}t_0<br />         \end{eqnarray*}<br />
Damit ist die Behauptung (2) bewiesen.

Berechnung der Gesamtzeit  $t_N$ nach  $N$ Schritten:
Die Gesamtzeit ergibt sich aus der Summe aller  $dt_k$ für  $k =1 ... N$.
<br />         \begin{eqnarray}<br />           t_N = \sum_{k=1}^N dt_k =  \sum_{k=1}^N a t_k = a \sum_{k=1}^N (1+a)^k t_0<br />         \end{eqnarray}<br />
Mit Hilfe der Formel
<br /> \begin{eqnarray}<br />     \sum_{k=1}^N q^k = \frac{q[q^N - 1]}{q-1} \qquad \intertext{f\"ur} \quad q > 0<br /> \end{eqnarray}<br />
erhält man den Ausdruck:
<br /> \begin{eqnarray}<br />    t_N = (a+1) [(a+1)^N -1] t_0<br /> \end{eqnarray}<br />

Berechnung der Anzahl der Schritte  $N$

Dazu muss man die Gleichung (5) nach der Anzahl der Gesamtschritte  $N$ auflösen:
<br /> \begin{eqnarray*}<br />    t_N $=$ (a+1) [(a+1)^N -1] t_0 \end{eqnarray*}<br />
Auslösen nach $(a+1)^N$ ergibt:
<br /> \begin{eqnarray*}<br />    (a+1)^N = \frac{t_N}{(a+1)t_0} +1<br /> \end{eqnarray*}<br />
Jetzt muss die Gleichung logarithmiert werden. Mit Hilfe der Formel  $log(q^N) = N log(q)$ erhält man:
<br /> \begin{eqnarray*}<br />    (a+1)^N &=& \frac{t_N}{(a+1)t_0} +1 \\<br />    N log(a+1) &=& log(\frac{t_N}{(a+1)t_0} +1).<br /> \end{eqnarray*}<br />
Diese Gleichung kann jetzt nach  $N$ aufgelöst werden. Und somit erhält man die
Formel für die Gesamtanzahl der Schritte im Bereich III:
<br /> \begin{eqnarray}<br />    N_{III} = \frac{log(\frac{t_N}{(a+1)t_0} +1)}{log(a+1)}<br /> \end{eqnarray}<br />
wobei  $t_N$ der Zeit entspricht in der die Schrittmotoren anbremsen (oder beschleunigen).
Die Anzahl der Schritte im Bereich II in welchem die Schrittmotoren mit konstanter Geschwindigkeit laufen ergibt sich zu:
<br /> \begin{eqnarray}<br />    N_{II} = \frac{t_{II}}{\Delta t{min}}.<br /> \end{eqnarray}<br />
Und somit die Gesamtanzahl der Schritte in den Bereichen I bis III:
<br /> \begin{eqnarray}<br />     N = \frac{log(\frac{t_I}{(a_{I}+1)t_0} +1)}{log(a_{I}+1)} +  \frac{t_{II}}{dt{min}} + \frac{log(\frac{t_{III}}{(a_{III}+1)t_0} +1)}{log(a_{III}+1)}<br /> \end{eqnarray}<br />
mit  $ a_i = \frac{dt_{max} - dt_{min}}{t_i} $.

Quellen:

  1. [Arduino]Stepper Motor + EasyDriver + Arduin
  2. S-Curve for EasyDriver v3 Stepper Motor Driver
  3. Datasheet of Dual stepper motor shield

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert