Forum: Mikrocontroller und Digitale Elektronik Rampenberechnung Schrittmotor


von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Hallo zusammen,

in der Application Note AVR446: Linear speed control of stepper motor 
ist eine schöne Beschleunigungsrampenberechnung für Schrittmotoren 
erklärt.

Dort werden folgende Formeln verwendet:

und dann weiter umgeformt zu:

wobei
 und

Die berechnen also das erste Delay c0, merken sich dieses, und berechnen 
alle weiteren Delays basierend auf diesem initialen Delay. Soweit 
versteh ich das einigermaßen.

Nun bräuchte ich das etwas anders: Ich möchte gerne c(n) nicht aus c(0) 
berechnen, sondern aus c(n-1)

Ich bin mir fast sicher dass ich mal gelernt habe wie das geht, aber ich 
fürchte damals hab ich krankheitshalber gefehlt :-)

mathe ist leider nicht gerade meine Stärke.... kann mir da jemand 
behilflich sein?


(außerdem bin ich ganz stolz auch mich, weil ich grad zum ersten mal in 
meinem leben eine Latex-Formel gesetzt habe!)

von TestX .. (xaos)


Lesenswert?

Michael Reinelt schrieb:
> Nun bräuchte ich das etwas anders: Ich möchte gerne c(n) nicht aus c(0)
> berechnen, sondern aus c(n-1)

was erhoffst du dir dadurch ?

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Andi ... schrieb:
> was erhoffst du dir dadurch ?

ich hab doch gewusst dass diese frage kommt ;-)

Normalerweise will man mit einem Stepper "Positionen" anfahren. Dafür 
ist die Rampenberechnung mit c0 sicherlich gut geeignet.

für meine Anwendung interessieren mich aber keine absoluten Positionen, 
sondern nur (Winkel-)Geschwindigkeiten bzw. Drehzahlen. Das heisst ich 
drehe momentan mit n1 Steps/Second (im einfachsten Fall 0, also 
Stillstand) und will n2 Steps/Second erreichen, muss also beschleunigen 
oder bremsen. Noch schlimmer wirds wenn ich während des 
Beschleunigens/Bremsens eine neue Solldrehzahl bekomme.

von Test (Gast)


Lesenswert?

Hallo,

das steht doch auch in der App note

oder meinst du etwas anderes?

Das hört sich stark nach einem Regler an was du realisieren möchtest.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Test schrieb:
> Hallo,
>
> das steht doch auch in der App note
>
>
>
Oh, das hätte ich überlesen....

> oder meinst du etwas anderes?

Triffts fast: mich stört das "4n+1". Ich möchte zu einem beliebigen 
Zeitpunkt (sprich: sehr großes bzw. beliebiges n) aus momentaner 
Geschwindigkeit (sprich: c(n-1) )  und neuer Sollgeschwindigkeit das 
aktuelle Counter-delay errechnen.

> Das hört sich stark nach einem Regler an was du realisieren möchtest.
Nein, hat mit Regler nix zu tun. ich möchte einfach nur 
geschwindigkeiten stellen können, unter der berücksichtigung der 
aktuellen geschwindigkeit.

: Bearbeitet durch User
von Possetitjel (Gast)


Lesenswert?

Michael Reinelt schrieb:

> Triffts fast: mich stört das "4n+1".

Ich würde versuchen, die Formel für c_n-1 aufzustellen -
dann erscheinen natürlich c_n-2 und 4(n-1)+1 auf der
rechten Seite. Diese neue Formal dann nach n umstellen
und n in der Ursprungsformel substituieren.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Test schrieb:

ich hab das jetzt in der AppNote gefunden: Das ist aber schon die 
Approximation mittels Taylor-Reihe...

ich glaub ich habs aber selbst geschafft (mit etwas Hilfe von Wolfram 
Alpha):

der term

lässt sich folgendermaßen aus c(n-1) errechnen:
Der Lesbarkeit  halber habe ich c(n-1) durch c ersetzt...

Damit bin ich zumindest mathematisch mal am Ziel. Allerdings möchte ich 
das so am AVR nciht berechnen :-) wird wohl noch eine Approximation 
(oder eine Lookup-Tabelle) werden...

: Bearbeitet durch User
von Thorsten O. (Firma: mechapro GmbH) (ostermann) Benutzerseite


Lesenswert?

Ich verstehe dein Problem immer noch nicht. Normalerweise legt man sich 
die Tabelle vorberechnet in den Speicher. Ob man dann den Motor bei v=0 
oder v=v1 loslaufen lässt, ändert nur den Startpunkt in der Tabelle.

Mit freundlichen Grüßen
Thorsten Ostermann

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Thorsten Ostermann schrieb:
> Ich verstehe dein Problem immer noch nicht. Normalerweise legt man sich
> die Tabelle vorberechnet in den Speicher. Ob man dann den Motor bei v=0
> oder v=v1 loslaufen lässt, ändert nur den Startpunkt in der Tabelle.

Das stimmt (zumindest meiner Meinung nach) nicht ganz.

Im normalen "fahr eine Position x an" hast du ein einheitliches 
Beschleunigungsprofil, welches nur wenige, diskrete Werte annehmen kann. 
Und du fährst eigentlich immer aus dem Stillstand los.

Beispiel: der Counter-Wert deiner initialen Beschleunigung wäre 1000, 
und deine Maximalgeschwindigkeit wäre 200. Dann hättest du immer 
folgendes Profil:

1000 - 414 - 318 - 268 - 236 - 213 - 200 (196)

(die letzte 196 liegt unter deiner Maximalgeschwindigkeit, deshalb 
nimmst du 200, oder korrigierst die ganze Rampe nach oben).

Natürlich eignet sich diese Rampe optimal, um sie in einer Tabelle 
abzulegen, und stur abzufahren. Du wirst auch nix anderes brauchen, weil 
du nie andere Geschwindigkeiten fahren wirst (mal unter der Annahme, du 
bremst gleich schnell wie du beschleunigst).

Ich hingegen fahre praktisch beliebige Geschwindigkeiten, aus denen 
heraus ich dann bremsen oder beschleunigen muss. Diese Werte find ich 
dann aber in obiger Tabelle nicht...

natürlich könnte man interpolieren, eine größere Tabelle ablegen, oder 
was auch immer. Die Möglichkeiten stehen mir ja immer noch offen. Ich 
möchte aber zuerst die Theorie im Griff haben. Aber da nähere ich mich 
eh an, ich kämpfe nur noch etwas mit Wolfram Alpha (leider hab ich kein 
Mathematica)

von Thorsten O. (Firma: mechapro GmbH) (ostermann) Benutzerseite


Lesenswert?

Hallo Michael,

es gibt ja eigentlich keine Geschwindigkeit Null, bereits von Schritt 1 
nach Schritt 2 hast du eine Geschwindigkeit. Man kann die Tabelle 
tatsächlich universell anlegen. Hier ist das meiner Meinung nach besser 
erklärt:
http://www.silabs.com/Support%20Documents/TechnicalDocs/an155.pdf

Mit freundlichen Grüßen
Thorsten Ostermann

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Wolfram Alpha hat mir geholfen, den folgenden Ausdruck zu finden:

Excel (igitt!) sagt mir, ich kann das sehr gut mit folgendem Polynom 
annähern:

Welches sich dann in eine "rechenzeit-freunliche Version umformen lässt:
(nur mehr drei Multiplikationen und drei Additionen)

Weiss jemand, wie ich Wolfram Alpha dazu kriege, mir so eine 
Polynom-Approximation zu liefern? Erstens traue ich dem Excel(igitt!) 
nicht, zweitens liefert Excel(igitt!) bei Ordnung 2 schlechte 
Ergebnisse, drittens will ich wissen wie das geht :-)

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Thorsten Ostermann schrieb:
> Hallo Michael,
>
> es gibt ja eigentlich keine Geschwindigkeit Null, bereits von Schritt 1
> nach Schritt 2 hast du eine Geschwindigkeit. Man kann die Tabelle
> tatsächlich universell anlegen. Hier ist das meiner Meinung nach besser
> erklärt:
> http://www.silabs.com/Support%20Documents/TechnicalDocs/an155.pdf

ich muss dich enttäuschen: Die Tabelle ist nicht universell!

Betrachte die ersten beiden Werte: 255 und 105

Und betrachte die zugrundeliegende Formel: c(n) = sqrt(n+1)-sqrt(n)
=> c(0)=1, c(1) = 0.41
Skaliert auf 255 ergibt das: 255, 105

Was wenn ich gerade mit 162 drehe? Wie bremse oder beschleunige ich? 
(162 kommt in der Tabelle nicht vor)

von Karl H. (kbuchegg)


Lesenswert?

Michael Reinelt schrieb:
> Wolfram Alpha hat mir geholfen ....


Ich bin mir noch nicht mal sicher, ob die ganze Vorgehensweise überhaupt 
irgendwo hinführt oder nicht. Im Moment denke ich eher nicht.

Beispiel.
Deine momentane Drehzahl sei 400 U/min.
Jetzt kommt der Befehl die Drehzahl auf 600 U/min zu erhöhen.

Also beginnst du mit der Beschleunigungsrampe, du verkürzt sukzessive 
die Zeitdauer zwischen den Port-Setzungen des Schrittmotors.

Noch während du in dieser Beschleunigungsphase bist, kommt der neue 
Befehl die Drehzahl auf 200 U/min abzusenken.

D.h. du musst jetzt die Beschleunigungsphase abbrechen und in eine 
Bremsphase eintreten, die dich von der jetzigen Zeitdauer der Port 
Aktionen auf die notwendige für 200 U/min bringt.

Ob du das mit dem jetzigen Formalismus mathematisch hinkriegst - aus dem 
Bauch raus hätte ich gesagt: schwierig.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Karl Heinz schrieb:
> Deine momentane Drehzahl sei 400 U/min.
> Jetzt kommt der Befehl die Drehzahl auf 600 U/min zu erhöhen.
> Noch während du in dieser Beschleunigungsphase bist, kommt der neue
> Befehl die Drehzahl auf 200 U/min abzusenken.

Danke, Karl-Heinz! Endlich einer, der mich versteht! :-)

Karl Heinz schrieb:
> Ob du das mit dem jetzigen Formalismus mathematisch hinkriegst - aus dem
> Bauch raus hätte ich gesagt: schwierig.

Du wirst lachen: Ich hatte das schon halbwegs im Griff!

Allerdings nur sehr halbwegs: Da ich aufgrund der komplexen Mathematik 
schon mal die Nerven weggeschmissen hatte, hab ich das auf die brachiale 
gelöst: einen weiteren hochauflösenden Timer mit konstantem Wert 
(entsprechend der maximalen Beschleunigung) der kontinuierlich die 
Geschwindigkeitswerte erhöht/erniedrigt hatte. Funktioniert in der 
Theorie phantastisch: du kriegst absolut lineare Rampen. In der Praxis 
leider ganz schlecht: Du erniedrigst den Timer-Endwert, während sich der 
eigentliche Stepper-Timer schon zwischen altem und neuem Wert befindet. 
Was dazu führt dass der Timer eine "Ehrenrunde" dreht. Und das war nur 
einer der vielen unsympatischen Nebeneffekte.

Auch wenn ich momentan noch auf dünnem Eis herumkrebse, ich hab das 
Gefühl ich krieg das hin... (und nebenbei wärme ich meine spärlichen 
Mathematik-Kenntnisse etwas auf :-)

von Udo S. (urschmitt)


Lesenswert?

Man sollte sich vieleicht mal vor Augen führen was eine 
Beschleunigungsrampe bedeutet und wozu sie da ist.
Der Stepper kann nicht unendlich beschleunigen, also muss man 
kontinuierlich die Drehzahl erhöhen oder verkleinern.
In erster Näherung kann man das linear tun, also die Zeit für eine sich 
linear erhöhende/erniedrigende Drehzahl ändern.
Das wäre also eine Konstante (DeltaDrehzahl/Zeit)
Da der Motor aber vieleicht eine drehzahlabhängige Grundlast hat und 
evt. auch eine nichtlineare Drehzahl/Drehmoment Kennlinie braucht man 
eine Tabelle: max. deltaDrehzahl/Zeit) in Abhängigkeit von der absoluten 
Drehzahl.

Das Ganze reicht wenn man es für einige Stützstellen ablegt und 
dazwischen interpoliert.

von rs (Gast)


Lesenswert?

Michael Reinelt schrieb:
> Ich hingegen fahre praktisch beliebige Geschwindigkeiten, aus denen
> heraus ich dann bremsen oder beschleunigen muss. Diese Werte find ich
> dann aber in obiger Tabelle nicht...
>

Einfach nächstliegenden Tabellenwert (in der richtigen Richtung) zum 
"starten" nehmen, die Beschleunigung dorthin ist kleiner als die 
Beschleunigung der Rampe, das sollte der Motor also mitmachen.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

rs schrieb:
> Einfach nächstliegenden Tabellenwert (in der richtigen Richtung) zum
> "starten" nehmen, die Beschleunigung dorthin ist kleiner als die
> Beschleunigung der Rampe, das sollte der Motor also mitmachen.

Ja, aber es muss besser gehen: im Einfachsten Fall mach ich mir dieselbe 
Lookup-Tabelle (auf mit 256 Einträgen) welche die folgende 
Beschleunigung für den aktuellen Geschwindigkeitswert beinhaltet.

Das sind aber fragen der konkreten Implementierung. Mir gehts momentan 
darum, die dahinter liegende Mathematik zu durchschauen.

von Thorsten O. (Firma: mechapro GmbH) (ostermann) Benutzerseite


Lesenswert?

Hallo Karl Heinz,

> Ich bin mir noch nicht mal sicher, ob die ganze Vorgehensweise überhaupt
> irgendwo hinführt oder nicht. Im Moment denke ich eher nicht.
>
> Beispiel.
> Deine momentane Drehzahl sei 400 U/min.
> Jetzt kommt der Befehl die Drehzahl auf 600 U/min zu erhöhen.
...
> Noch während du in dieser Beschleunigungsphase bist, kommt der neue
> Befehl die Drehzahl auf 200 U/min abzusenken.
>
> D.h. du musst jetzt die Beschleunigungsphase abbrechen und in eine
> Bremsphase eintreten, die dich von der jetzigen Zeitdauer der Port
> Aktionen auf die notwendige für 200 U/min bringt.
>
> Ob du das mit dem jetzigen Formalismus mathematisch hinkriegst - aus dem
> Bauch raus hätte ich gesagt: schwierig.

Wo ist das Problem? Du läufst einfach rückwärts durch die Tabelle bis du 
bei der gewünschten Geschwindigkeit ankommst.

Das das auch in der Praxis geht zeigt unser Schrittmotorcontroller 
NC-Pilot USB. Da fahren wir sogar zwei Achsen bahnsynchron bis 50kHz. 
Und die Implementierung ist älter als Mach3 und basiert letztlich auf 
der o.g. App-Note von Silicon Labs.
http://www.mechapro.de/schrittmotorensteuerung.html

Mit freundlichen Grüßen
Thorsten Ostermann

von rs (Gast)


Lesenswert?

Michael Reinelt schrieb:
> Ja, aber es muss besser gehen: im Einfachsten Fall mach ich mir dieselbe
> Lookup-Tabelle (auf mit 256 Einträgen) welche die folgende
> Beschleunigung für den aktuellen Geschwindigkeitswert beinhaltet.
>
> Das sind aber fragen der konkreten Implementierung. Mir gehts momentan
> darum, die dahinter liegende Mathematik zu durchschauen.

Interpretiere "n" als index in die Beschleunigungs-Rampe, und nicht als 
Schritt-Nummer. Bei konstanter Geschwindigkeit ändert sich n nicht.

Ist die Beschleunigung zeitlich konstant, dann reicht eine Tabelle, die 
die Rampe von 0 bis zur maxmimal-Geschwindigkeit abbildet.

Hier gibts das alles nochmal recht kompakt und verständlich (wie ich 
finde): http://hwml.com/LeibRamp.pdf

Statt Tabelle kann man natürlich auch einen entsprechenden µC nehmen, 
ein ARM mit 100MHz schafft es, bei 100kHz Schrittfequenz jeweils das 
nächste Intervall in einer ISR zu berechnen. Und das bei 2-3 Motoren ;-) 
Die hohe Timer-Auflösung bedeutet auch sanfte Beschleunigungen auch bei 
hohen Schrittfequenzen.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

rs schrieb:
> Hier gibts das alles nochmal recht kompakt und verständlich (wie ich
> finde): http://hwml.com/LeibRamp.pdf

Danke danke danke, der Link ist Gold Wert! Geniale Sache, und tut genau 
das wie ich will.

Gibts diesen Algorithmus auch irgendwo in konkreten Code gesetzt? laut 
dem Dokument ist der nämlich optimiert für floating point, welches 
schneller wäre als integer, weil keine Division, und integer würde 
Division brauchen...

von Michael R. (Firma: Brainit GmbH) (fisa)


Angehängte Dateien:

Lesenswert?

Hallo allerseits,

nach langem hin- und herüberlegen, ausprobieren unzähliger Varianten, 
glaube ich jetzt eine sehr gute Lösung gefunden zu haben, die ich euch 
nicht vorenthalten will.

Ausgangspunkt ist die "exakte" Berechnung eines neuen Counter-Wertes 
c_new basierend auf dem aktuellen Counter-Wert c_old, Parameter sind 
Timer-Frequenz F und Beschleunigung a:

Das schaut auf den ersten Blick natürlich beängstigend aus, geht aber 
überraschend schnell: eine Berechnung dauert auf dem ATmega328 rund 1500 
Takte. Das lässt sich mit einer "inversen Quadratwurzel" 
http://en.wikipedia.org/wiki/Fast_inverse_square_root noch auf rund 1200 
Takte beschleunigen. Ist aber natürlich nicht wirklich 
zufriedenstellen...

Dann gibt es den Algorithmus von Aryeh Eiderman, der die Wurzel durch 
eine Taylor-Reihe ersetzt. Leider bedingt diese Variante 
Fließkomma-Berechnung, kommt aber nur mit Multiplikationen und 
Additionen aus. Aber Immerhin eine Steigerung auf rund 600 Takte. Aber 
immer noch unbefriedigend... (abgesehen davon dass die "einfachste" 
Variante doch stark fehlerbehaftet ist). Meine Versuche, das vernünftig 
in integer-Arithemtik zu wandeln, sind gescheitert, das war aber auch 
gut so, denn sonst hätt ich vermutlich meine Lösung nicht mehr gesucht 
und gefunden...

Ich habe dann versucht, obige Formel durch ein Polynom zweiten Grades 
anzunähern, und das funktioniert erstaunlich gut. Die Koeffizienten 
lassen sich dabei sogar automatisch ermitteln, etwas kritisch ist nur 
die geschickte Wahl der Stützstellen.

Mein Polynom für F=16MHz und a=200.000 Steps/sec^2 sieht folgendermaßen 
aus:

mit 0.000016 lässt sich aber schlecht rechnen....

trickreiche Umwandlung in integer-Arithmetik unter Verwendung von 
Schiebeoperationen mit ganzzahligem Vielfachen von 8 führen zu folgender 
Formel:
1
c_neu = ((c*264)>>8) - ((((c*274)>>8)*c)>>16)

Ergebnis: 140 Takte, und genauer als das Eiderman-Verfahren!

Im Diagramm sieht man die drei Verfahren gegenübergestellt, und man 
erkennt auch deutlich den Fehler der Eiderman-Berechnung.

Fazit: Es lohnt sich, angestrengt nachzudenken :-)

von Thorsten O. (Firma: mechapro GmbH) (ostermann) Benutzerseite


Lesenswert?

Vielleicht stehe ich ja einfach nur auf dem Schlauch, aber was zeigt der 
Graph uns? Also was hast du da auf X- und Y-Achse aufgetragen? Eine 
Achsenbeschriftung wäre hilfreich...

Mit freundlichen Grüßen
Thorsten Ostermann

von Thorsten O. (Firma: mechapro GmbH) (ostermann) Benutzerseite


Lesenswert?

Hallo Michael,

>> http://www.silabs.com/Support%20Documents/TechnicalDocs/an155.pdf
>
> ich muss dich enttäuschen: Die Tabelle ist nicht universell!
>
> Betrachte die ersten beiden Werte: 255 und 105
>
> Und betrachte die zugrundeliegende Formel: c(n) = sqrt(n+1)-sqrt(n)
> => c(0)=1, c(1) = 0.41
> Skaliert auf 255 ergibt das: 255, 105
>
> Was wenn ich gerade mit 162 drehe? Wie bremse oder beschleunige ich?
> (162 kommt in der Tabelle nicht vor)

In dem man den nächst größeren oder kleineren Tabelleneintrag nimmt. Das 
führt natürlich zu einem "Beschleunigungsfehler", der aber in den 
meisten Fällen nicht dramatisch ist. Vor allem, wenn man berücksichtigt, 
dass man die Tabelle normalerweise so anlegt, dass man nicht mit den 
ersten Einträgen arbeiten muss, die eine sehr grobe Verteilung 
aufweisen. Man skaliert eben nicht von 0 und 1 nach 255, sondern macht 
die Anzahl der Tabelleneinträge ausreichend groß (z.B. 10.000).

Mit freundlichen Grüßen
Thorsten Ostermann

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Thorsten Ostermann schrieb:
> Eine Achsenbeschriftung wäre hilfreich...
oh sorry...

X: Zeit (in Timer-Ticks)
Y: Counter-Wert (ebenfalls Timer-Ticks)

Würde man die Y-Werte verkehrwerten (als 1/y) ergäbe sich eine lineare 
Rampe.

Thorsten Ostermann schrieb:
> macht
> die Anzahl der Tabelleneinträge ausreichend groß (z.B. 10.000).

Auf einem AVR mit 8kB RAM? :-)

von Thorsten O. (Firma: mechapro GmbH) (ostermann) Benutzerseite


Lesenswert?

Man kann die Tabelle auch im Flash ablegen...

Mit freundlichen Grüßen
Thorsten Ostermann

von m.n. (Gast)


Lesenswert?

Michael Reinelt schrieb:
> Mein Polynom für F=16MHz und a=200.000 Steps/sec^2 sieht folgendermaßen
> aus:
>
> mit 0.000016 lässt sich aber schlecht rechnen....
>
> trickreiche Umwandlung in integer-Arithmetik unter Verwendung von
> Schiebeoperationen mit ganzzahligem Vielfachen von 8 führen zu folgender
> Formel:
> c_neu = ((c*264)>>8) - ((((c*274)>>8)*c)>>16)

Ich habe das mal in mein Programm eingebaut, aber kein brauchbares 
Ergebnis bekommen. Deutlich erfolgreicher (und langsamer) kann ich zur 
Beschleunigung die Formel:
c = c * (1-m*c*c);
verwenden, wobei sinnvolle Werte für m im Bereich 1e-11 bis 1e-10 
liegen.
Das Abbremsen geht ähnlich mit:
c = c * (1+m*c*c);

Geschickterweise nimmt man dafür einen µC mit FPU :-)

von schris (Gast)


Lesenswert?

((c*264)>>8) - ((((c*274)>>8)*c)>>16)

Also
 (c+(c>>5)) - ((((c>>8)*18+c)*c)>>16)

Ist c der Interval als Timerwert (uS/ns/... ) oder was ist c ?

von Martin S. (martinst)


Lesenswert?

Oder man machts wie bei GRBL:
https://github.com/grbl/grbl

Dort stellt ein Timer etwa alle 1/30Hz die Periodendauer eines zweiten 
Timers mittels des Bresenham-Algorithmus nach. Die zweite Timer-ISR 
erzeugt die Schrittpulse und stellt bei den (vorher berechneten) 
richtigen Schrittzahlen den Bresenham-Algorithmus so nach, dass das 
gewünschte Geschwindigkeitsprofil eingehalten wird. (siehe stepper.c) 
Falls sich die gewünschte Endgeschwindigkeit mittendrin plötzlich ändert 
werden die Parameter entsprechend neu berechnet.

Gruß,
Martin

von schris (Gast)


Lesenswert?

Wie ist eigentlich diese Formel:
C = (c*266)>>8;
c = C - ((C*c)>>16);

bzw
C = (c+c>>5)

sowie
c = C - ((C*c)>>16);
und
c = C - ((C*C)>>16);

von m.n. (Gast)


Lesenswert?

Martin St. schrieb:
> (siehe stepper.c)

Auf den 1. Blick ist dort allerdings ein (grober) Schnitzer zu sehen. In 
der T1-Compare-Routine wird per busy-flag, ein wiederholter Aufruf 
verhindert, was zur Folge hat, dass sich in diesem Fall die 
Schrittfrequenz schlagartig halbiert (doppeltes Intervall).
Besser wäre es, den T1-compare Interrupt kurz abzuschalten und am Ende 
der Routine wieder freizugeben. Dann kommt der nächste Interrupt einen 
Tick verzögert, wird aber nicht gänzlich verworfen.

von Martin S. (martinst)


Lesenswert?

Die T1 ISR ist so ausgelegt dass sie auf jeden Fall schneller fertig 
wird als nötig und nie blockiert.
Ich denke dass dieser Codeabschnitt während der anfänglichen Entwicklung 
entstanden ist umd Fehler abzufangen. Beim frühzeitigem Widereintritt 
würde die ganze Programmlogik von GBRL nicht stimmen. Ein while(1); mit 
Fehlerausgabe zum anschließendem Debugging wäre an dieser Stelle sicher 
besser.

von Physiker (Gast)


Lesenswert?

m.n. schrieb:
> c = c * (1-m*c*c);
> verwenden, wobei sinnvolle Werte für m im Bereich 1e-11 bis 1e-10
> liegen.

Das solltest für dich Grund genug sein, mal über die Einheiten 
nachdenken, in denen du deine Werte in die Formel einsetzt. Mit 
vernünftiger Normierung klappt das auch ohne FPU.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Physiker schrieb:
> Das solltest für dich Grund genug sein, mal über die Einheiten
> nachdenken, in denen du deine Werte in die Formel einsetzt. Mit
> vernünftiger Normierung klappt das auch ohne FPU.

Danke, ehrwürdiger Physiker. Auf dich haben wir gewartet. Du wirst uns 
sicher gleich erleuchten, wie wir m=a/F^2 anders normieren, um damit 
vernünftige Timerwerte ohne FPU erhalten.

schris schrieb:
> oder was ist c

c ist das "counter Delay", also die Anzahl Counter Ticks zwischen zwei 
Step-Impulsen (üblicherweise wird das dann ich ein Overflow- oder 
OutputCompare-Register geladen)

schris schrieb:
> Wie ist eigentlich diese Formel
Dieser Satz kein Verb?

GRBL: das läuft dort ganz anders. zugegeben, recht elegant, aber für 
mich so nicht brauchbar.

m.n. schrieb:
> Ich habe das mal in mein Programm eingebaut, aber kein brauchbares
> Ergebnis bekommen.

Mal ohne Programm, in einer Debug- oder Testroutine probieren. Wichtig 
ist auch dass die Variablentypen stimmen (uint16_t)

wenn du das z.B. mit 30.000 aufrufst, solltest du irgendwas in Richtung 
20.000 rauskriegen.

von Physiker (Gast)


Lesenswert?

Michael Reinelt schrieb:
> Danke, ehrwürdiger Physiker. Auf dich haben wir gewartet. Du wirst uns
> sicher gleich erleuchten, wie wir m=a/F^2 anders normieren, um damit
> vernünftige Timerwerte ohne FPU erhalten.

Solange in deiner Formel ein Änderungsfaktor (1-m*c*c) steht, darfst du 
dich natürlich nicht wundern, wenn m größenordnungsmäßig bei 1/c² liegt. 
Probiere es mal mit der Substitution c' := c * 10^-6 zu rechnen und erst 
danach wieder auf deine Clockanzahl umzurechnen.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Physiker schrieb:
> Solange in deiner Formel ein Änderungsfaktor (1-m*c*c) steht, darfst du
> dich natürlich nicht wundern, wenn m größenordnungsmäßig bei 1/c² liegt.
> Probiere es mal mit der Substitution c' := c * 10^-6 zu rechnen und erst
> danach wieder auf deine Clockanzahl umzurechnen.

Das wird nur nichts bringen, weil mir die Rückskalierung genausoviel 
kostet wie die etwaige erleichterung in einer andern größenordnung. Die 
Berechnung ist auf float ausgelegt, und funktioniert in der Domäne auch 
gut. Sie lässt sich schlecht bis gar nicht in eine int-Domain umlegen. 
Aber selbstverständlich bin ich offen für gute ideen...

: Bearbeitet durch User
von m.n. (Gast)


Lesenswert?

Michael Reinelt schrieb:
> Wichtig
> ist auch dass die Variablentypen stimmen (uint16_t)

Das kann nicht sein! Andernfalls könnte ich den Ausdruck mit "(...)>>16" 
gleich durch 0 ersetzen.

Physiker schrieb:
> Solange in deiner Formel ein Änderungsfaktor (1-m*c*c) steht, darfst du
> dich natürlich nicht wundern, wenn m größenordnungsmäßig bei 1/c² liegt.

Ich wundere mich nicht und welcher Wert sich für 'm' ergibt ist mir 
völlig schnuppe, solange er im float-Format darstellbar ist.

von Walter (Gast)


Lesenswert?

m.n. schrieb:
> Ich wundere mich nicht und welcher Wert sich für 'm' ergibt ist mir
> völlig schnuppe, solange er im float-Format darstellbar ist.

float ist kein Allheilmittel, du wirst dich spätestens dann wundern wenn 
du mal zwei annähernd gleichgroße floats voneinander subtrahierst, da 
geht die Genauigkeit nämlich schnell den Bach runter.
Das kann man durch Formelumstellung vermeiden

von m.n. (Gast)


Lesenswert?

Walter schrieb:
> Das kann man durch Formelumstellung vermeiden

Du meinst, ich sollte besser addieren? Oder von welcher "Genauigkeit" 
redest Du?

von Dieter F. (Gast)


Lesenswert?

Michael Reinelt schrieb:
> Nun bräuchte ich das etwas anders: Ich möchte gerne c(n) nicht aus c(0)
> berechnen, sondern aus c(n-1)

Was genau willst Du eigentlich?

Wenn sich die Ausgangs-Parameter ändern muss auch der erste Teil der 
Formel neu berechnet werden - oder?

Ich habe auch schon mal die Bewegung des Mondes relativ zur Erde 
"interpoliert" - aber leider nur das und die Wahrheit sah doch etwas 
anders aus.

Deine "Formel" passt aus meiner Sicht nur genau (in etwa) auf die 
angegebenen Parameter - ändert sich etwas ist auch eine neue Formel 
fällig.

Auch aus dem Parallel-Thread bin ich (wahrscheinlich zu doof) nicht so 
recht schlau geworden.

Eine Schrittmotor-Rampe kann man berechnen (habe ich experimentell 
gemacht) oder vorberechnet hinterlegen und "näherungsweise" ausführen.

Also nochmal - was willst Du erreichen?

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Fortschritte... (oder Rückschritte?)

nachdem die Beschleunigungsrampe so gut funktioniert hat, habe ich mich 
an der Bremsrampe versucht, und bin gescheitert :-( Das Biest lässt sich 
nicht vernünftig durch ein Polynom approximieren, auch nicht wenn man zu 
höheren Ordnungen greift (was aber ohnehin kontraproduktiv wäre)

Im Zuge der Bastlereien bin ich dann noch draufgekommen, dass die 
Polynom-Approximation sowieso ihre "dunklen Seiten" hat: Mal ist das 
Ding nicht monoton steigend, mal schwingt es, mal überschreitet man die 
maximale Beschleunigung....

nachdem die Eiderman-Variante eine wirklich sehr saubere Bremsrampe 
liefert, bin ich wieder reumütig zu dieser zurückgekehrt.

Und nachdem ich jetzt Erfahrung habe, wie man eine Fließkomma-Berechnung 
klug in integer umwandelt, habe ich nun eine recht schöne und schnelle 
Form für die Eiderman-Berechnung gefunden:

Die Basis der Eiderman-Berechnung ist ja bekannterweise:
Das Problem ist das sehr kleine m, welches sich zu +/- a/F^2 berechnet 
(a = Beschleunigung in Steps/sec, F = Timer-Frequenz). Beim 
Beschleunigen ist m negativ, beim bremsen positiv

Durch etwas umformen kommt man auf folgenden Ausdruck:
es reicht also m*p*p*p zu errechnen, beim Beschleunigen erniedrigt man 
den momentan Counter-Endwert, beim Bremsen erhöht man entsprechend.

m ist in meinem Fall (a=20.000 Steps/sec^2, F=16 MHz) 7.8E-10, also 
wirklich sehr sehr klein

Skaliert man das aber mit2^40, kommt man auf 859. Mit 859 lässt sich 
vernünftig rechnen.... problematisch ist natürlich auch noch p^3, bei 
16-Bit-Timerwerten sprengt das natürlich alle 32-Bit-Grenzen...

durch vernünftiges Zwischenschieben funktioneirt das aber wunderbar:
1
#define F 16000000  // Timer Frequency [Hz]
2
#define A 200000    // acceleration [Steps/sec] 
3
4
static inline uint16_t Eiderman (uint16_t p)
5
{
6
    uint16_t m = ((double) A / ((double)F * F) * pow(2, 40) + 0.5);
7
    uint16_t l = (((((((uint32_t)m * p) >> 8) * p) >> 16) * p) >> 16);
8
    return l > 0 ? l : 1;
9
}

Die letzte Zeile sorgt dafür, dass die Funktion niemals 0 zurückliefert, 
weil man sonst in einer Rampenposition "gefangen" sein könnte.

und, schlußendlich: ca. 190 Takte (gegenüber 600+ der float-Variante)

von Physiker (Gast)


Lesenswert?

Michael Reinelt schrieb:
> Das wird nur nichts bringen, weil mir die Rückskalierung genausoviel
> kostet wie die etwaige erleichterung

Du kannst mir nicht erzählen, dass ein c >> 20 genausoviel wie eine 
Floatingpoint Operation ohne FPU kostet.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Physiker schrieb:
> Michael Reinelt schrieb:
>> Das wird nur nichts bringen, weil mir die Rückskalierung genausoviel
>> kostet wie die etwaige erleichterung
>
> Du kannst mir nicht erzählen, dass ein c >> 20 genausoviel wie eine
> Floatingpoint Operation ohne FPU kostet.

Will ich ja gar nicht :-) Der Trick ist: da ist kein >>20. Alle 
Shift-Operationen sind ganzzahlige Vielfache von 8, das ersetzt der GCC 
sehr klug durch einzelne Byte-Zugriffe. Im gesamten Asm-Code ist keine 
einzige Shift-Operation mehr drinnen:
1
Eiderman:
2
  push r12   ; 
3
  push r13   ; 
4
  push r14   ; 
5
  push r15   ; 
6
  movw r12,r24   ;  D.2042, x
7
  mov r14,__zero_reg__   ;  D.2042
8
  mov r15,__zero_reg__   ;  D.2042
9
  movw r18,r24   ; , x
10
  ldi r26,lo8(91)   ; ,
11
  ldi r27,lo8(3)   ; ,
12
  call __umulhisi3
13
  mov r18,r23   ;  D.2042, D.2042
14
  mov r19,r24   ;  D.2042, D.2042
15
  mov r20,r25   ;  D.2042, D.2042
16
  clr r21   ;  D.2042
17
  movw r24,r14   ; , D.2042
18
  movw r22,r12   ; , D.2042
19
  call __mulsi3
20
  movw r18,r24   ;  D.2042, D.2042
21
  clr r20   ;  D.2042
22
  clr r21   ;  D.2042
23
  movw r24,r14   ; , D.2042
24
  movw r22,r12   ; , D.2042
25
  call __mulsi3
26
  clr r26   ;  D.2042
27
  clr r27   ;  D.2042
28
  sbiw r24,0   ;  l,
29
  brne .L3   ; ,
30
  ldi r24,lo8(1)   ;  iftmp.0,
31
  ldi r25,0   ;  iftmp.0
32
.L3:
33
  pop r15   ; 
34
  pop r14   ; 
35
  pop r13   ; 
36
  pop r12   ; 
37
  ret

Drei integer-Multiplikationen, das ist alles.

: Bearbeitet durch User
von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

@Physiker: ich glaub ich hab dich falsch verstanden. Ich vermute du 
wolltest ohnehin darauf hinaus, was ich jetzt mache :-)

von Physiker (Gast)


Lesenswert?

Michael Reinelt schrieb:
> Im gesamten Asm-Code ist keine einzige Shift-Operation mehr drinnen:

Sehr spannend zu lesen, wenn man kryptisches Kopfkino mag. Ohne 
sinntragende Kommentare reizt mich der Code-Ausschnitt gerade soetwas 
von überhaupt nicht.

Wenn du deine ursprünglichen Korrekturfaktor (1-m*c*c) mit unglücklicher 
Normierung berechnest, turnst du mit c*c einfach fürchterlich durch die 
Zehnerpotenzen.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Physiker schrieb:
> Sehr spannend zu lesen, wenn man kryptisches Kopfkino mag. Ohne
> sinntragende Kommentare reizt mich der Code-Ausschnitt gerade soetwas
> von überhaupt nicht.
Das ist der Asm-Output des Compilers, und den werd ich für dich jetzt 
nciht kommentieren. Es ging mir nur darum zu zeigen dass da keine 
Shift-operationen drinnen sind.

> Wenn du deine ursprünglichen Korrekturfaktor (1-m*c*c) mit unglücklicher
> Normierung berechnest, turnst du mit c*c einfach fürchterlich durch die
> Zehnerpotenzen.
ich fürchte du hast nicht verstanden worum es hier geht: Gewisse 
Parameter sind nicht normierbar, weil einfach in der gegebenen Form 
vorhanden: Ein 16-bit-Timer hat nun mal einen 16-Bit Wert, den kann und 
will ich nicht normieren.

von Physiker (Gast)


Lesenswert?

Michael Reinelt schrieb:
> ich fürchte du hast nicht verstanden worum es hier geht: Gewisse
> Parameter sind nicht normierbar

Es geht auch nicht um die Umnormierung deines Timer, sondern einzig um 
alleine um deine quadratische Gleichung. In welchem Bereich bewegt sich 
denn dein Faktor (1-m*c*c)?

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Physiker schrieb:
> Es geht auch nicht um die Umnormierung deines Timer, sondern einzig um
> alleine um deine quadratische Gleichung. In welchem Bereich bewegt sich
> denn dein Faktor (1-m*c*c)?

zwischen 0 und 1

Edit: 0..1 nur beim Beschleunigen, beim Bremsen sieht der Ausdruck etwas 
anders aus: (1+m*c*c) und der kann dann zwischen 1 und 2 liegen

: Bearbeitet durch User
von Michael L. (nightflyer88)


Lesenswert?

Ich habe jetzt nicht im Detail die ganze Problematik durchgelesen, habe 
aber auch schon eine CNC Steuerung für Schrittmotoren entwickelt, dazu 
gehören natürlich auch Rampen.

Hier ist meine Rampenberechnung:

//Beschleunigen
  if Fovrsoll > Fovr then
    A_single = sqr(Fovr^2 + beschlkonst * (1/inkrpermm))
    if A_single > Fovrsoll then
      Fovr = Fovrsoll
    else
      Fovr = A_single
    end if
  end if

//Verzögern
  if Fovrsoll < Fovr then
    A_single = Fovr^2 - beschlkonst * (1/inkrpermm)
    if A_single > 0 then
      A_single = sqr(A_single)
    end if
    if A_single < Fovrsoll then
      Fovr = Fovrsoll
    else
      Fovr = A_single
    end if
  end if


Fovr = ist der Aktuelle Vorschub (oder auch Geschwindigkeit)
Fovrsoll = ist der Soll Vorschub
beschlkonst = Beschleunigungswert

Die Berechnung wird nach jedem Takt des Schrittmotors gemacht. Während 
dem Beschleunigen, wird die Geschwindigkeit nach jedem Takt schrittweise 
erhöht, beim Verzögern verringert.

Vielleicht hilft das jemandem weiter

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Michael L. schrieb:
> A_single = sqr(Fovr^2 + beschlkonst * (1/inkrpermm))

Und genau das will ich adressieren: Die Berechnung verwendet a) 
Fließkomma und b) noch komplexe Funktionen wie Quadratwurzel. Auf 
schnellen Prozessoren oder welchen mit FPU mag das kein Problem sein, 
auf einem AVR braucht dann die ISR viel zu viel Rechenzeit.

von Michael L. (nightflyer88)


Lesenswert?

Michael Reinelt schrieb:
> auf einem AVR braucht dann die ISR viel zu viel Rechenzeit

Gut, bei mir läuft das ganze auf einem INTEL PC mit DOS, ist natürlich 
einiges schneller ;-)

Jedoch mache auch ich die Rampenberechnung nicht in der zeitkritischen 
ISR in der der Takt erzeugt wird. Ich berechne den Timer im 
Hauptprogramm, anschliessend setzte ich ein Start_byte und wenn das 
nächste mal die Timer ISR auftritt wird der Output Pin für den Takt 
einmal gesetzt und das zweitemal zurückgesetzt. In der Zwischenzeit kann 
ich im Hauptprogramm den neuen Timerwert berechnen.

Das ganze läuft für einen Hi/Lo Takt Zyklus grob folgendermaßen ab:

//Hauptprogramm:

Do
-Timer berechnen (Zeit für Hi/Lo Phase des Takts)
-warten bis Start_Byte = 0 (Taktzyklus fertig)
-Start_Byte = 2 (Takt Zyklus starten)
loop until soll = ist


//ISR für Takt Erzeugung:

Takt ISR:
  IF Start_Byte = 2 then
    set Outputpin
    Start_Byte = 1
    goto fertig
  end if
  if Start_Byte = 1 then
    reset Outputpin
    Start_Byte = 0
    goto fertig
  end if

  fertig:
  -Timer mit berechnetem wert laden
end ISR

von Thorsten O. (Firma: mechapro GmbH) (ostermann) Benutzerseite


Lesenswert?

Hallo Dieter, hallo Michael,

>> Nun bräuchte ich das etwas anders: Ich möchte gerne c(n) nicht aus c(0)
>> berechnen, sondern aus c(n-1)
>
> Was genau willst Du eigentlich?
...
> Eine Schrittmotor-Rampe kann man berechnen (habe ich experimentell
> gemacht) oder vorberechnet hinterlegen und "näherungsweise" ausführen.
>
> Also nochmal - was willst Du erreichen?

Das würde mich langsam auch mal interessieren. Was ist das Ziel? Eine 
möglichst gleichförmig beschleunigte Bewegung? Ein möglichst genauer 
Bahnverlauf? Wenig Rechenaufwand?

Mit freundlichen Grüßen
Thorsten Ostermann

von chris (Gast)


Lesenswert?

Soweit ich weiss hat man eine Geschwindigkeit, z.B. 600mm/min = 
10mm/sec=
4000 steps/sec (4mm Spindelsteigung, 200 step Schrittmotor, 8 
microsteps)
als Maximalgeschwindigkeit.

X = 200mm y = 150mm Z = 10mm

sqrt(X*X+Y*Y+Z*Z+A*A) = 250,2 mm

Auf diese 250,2 mm wird dann die Rampe gefahren, und dann
mittels Bresenham Algorithmus wird diese Rampe auf alle Motoren 
aufgeteilt,
sprich interpoliert. Dies bei G1
Bei G0 wird einfach die längste Achse hergenommen, die schnellste 
Geschwindigkeit darauf mittels Rampe gefahren, und die restlichen Achsen 
mittels bresenham interpoliert.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Thorsten Ostermann schrieb:
>> Also nochmal - was willst Du erreichen?
>
> Das würde mich langsam auch mal interessieren. Was ist das Ziel? Eine
> möglichst gleichförmig beschleunigte Bewegung? Ein möglichst genauer
> Bahnverlauf? Wenig Rechenaufwand?

Eigentlich dachte ich, das ginge aus ersten paar Posts recht klar 
hervor: ich kriege eine (fast beliebige) Solldrehzahl (beachte: 
Drehzahl nicht Position) vorgegeben, und möchte den Schrittmotor von 
der aktuellen (beliebigen) Drehzahl möglichst schnell (d.h. möglichst 
nahe an der maximal möglichen Beschleunigung) auf die neue Drehzahl 
bringen. Ein linearer Bahnverlauf ist genauso unwichtig wie eine wie 
immer geartete Schrittzahl. Mich interessieren nur Geschwindigkeiten. 
Eine lineare Geschwindigkeitsänderung ergibt sich automatisch aus der 
Forderung, möglichst nahe an (bzw. im Idealfall mit) der maximalen 
Beschleunigung die Geschwingigkeitsänderung durchzuführen. Da die 
Berechnung innerhalb der ISR durchgeführt werden soll, soll natürlich 
der Rechenaufwand minimal sein.

ich bin aber mit meiner Lösung von oben praktisch am Ziel.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.