Forum: Mikrocontroller und Digitale Elektronik Eine einfache lineare Rampe (z.B. pro Takt x um y beschleunigen)


von Patrick G. (patrick_123)


Lesenswert?

Hallo,

ich versuche mich seit längerem an der Beschleunigung von 
Schrittmotoren. Dabei will ich ganz allgemein belieben so dass die 
daraus entstehende Lib auf möglichst vielen Arduinos läuft. Heißt also 
keine Timer etc. benutzen sondern wenn möglich alles in einer Schleife. 
Das Ganze funktioniert ohne Beschleunigung soweit auch ganz gut. Nur 
lässt sich die maximal Geschwindigkeit nicht erreichen weshalb ich nun 
eben eine Rampe einbauen möchte. Die Stepper selbst hängen an einem 
A4988 Treiber dem man nur noch den Steppimpuls geben muss.

Generelle funktionsweise:

Ohne Beschleundigung:
1.) Jeder Stepper bekommt eine run() methode die inn der Loop() 
aufgerufen wird. Ich arbeite mit Wartezeiten zwischen den Schritten und 
nicht mit einer Frequenz Wobei sich das leicht umrehcnen lassen dürfte.
2.) Jeder Stepper zählt die µSek. bis er wieder einen Schritt machen 
darf
3.) Nach jedem Schritt wird die Zeit bis zum nächsten Schritt um einen 
festen Wert (davor berechneten erhöht
4.) Code run():
1
  if (stepsToDo > 0 && currentMicros >= nextUpdate) { 
2
      nextUpdate += stepDelay_uSec;  
3
      digitalWriteFast(stepPin_, HIGH);   //digtial write is very slow using variables. Using literals for pins is much faster!!!      digitalWriteFast(stepPin_, LOW); //ggf über Bitmask arbeiten da schneller?
4
      digitalWriteFast(stepPin_, LOW);   //delaymicros() pause between digitalWrite() seems not needed…
5
      stepsToDo--;
6
  }

Meine Idee mit Beschleunigung:
1.) Es bleibt alles gleich wie ohne Beschleunigung. Allerdings soll er 
zuvor die Wartezeit zwischen den Schritten etwas höher ansetzen als die 
Wartezeit für V_Max (="finalStepDelay_uSec") diese pro festen Tick (hier 
alle 100µS) um einen bestimmten Wert kleiner werden lassen so dass die 
Wartezeit linear kleiner wird bis sie V_Max erreicht hat.
2.) Code run():
1
  if (currentMicros >= nextAccTick) {
2
    if (stepDelay_uSec > finalStepDelay_uSec) {
3
      stepDelay_uSec -= 1;  //decrement the stepDelay_uSec until the finalStepDelay_uSec (V_Max) is reached. finalStepDelay_uSec is for ex. 30µS
4
    }      
5
    nextAccTick += AccTickTime; //here for ex. 100 uSec -> must be bigger then finalStepDelay_uSec!                    
6
  }
7
  if (stepsToDo > 0 && currentMicros >= nextUpdate) { 
8
      nextUpdate += stepDelay_uSec;  
9
      digitalWriteFast(stepPin_, HIGH);   //digtial write is very slow using variables. Using literals for pins is much faster!!!      digitalWriteFast(stepPin_, LOW); //ggf über Bitmask arbeiten da schneller?
10
      digitalWriteFast(stepPin_, LOW);   //delaymicros() pause between digitalWrite() seems not needed…
11
      stepsToDo--;
12
  }

Eigentlich hatte ich erhofft dass diese einfache Beschleunigung 
problemlos für die meisten Fälle funktionieren wird.
Leider ist dem nicht so und es ist oft der Fall, dass der Stepper sobald 
er eine hohe Geschwindigkeit erreicht einfach aus dem Takt kommt und 
vibrierend stehen bleibt. Ein Erhöhen der AccTickTime hat manchmal etwas 
gebracht und ich konnte eine noch höhere Geschwindigkeit erreichen, war 
aber fummelig und musste jedes Mal durch ausprobieren ermittelt werden 
was eben nicht sein sollte. Die Max. Geschwindigkeit war also definitiv 
noch nicht erreicht.

Weiß jemand was an dieser einfachen linearen Rampe falsch ist? Oder 
kennt jemand eine super einfache Rampe die ohne Timer etc. auskommt und 
mit einfachen Schleifen realisiert werden kann?
Es soll so einfach und kompatibel wie möglich sein ohne dass man davor 
irgendwelche Timer am Arduino einstellen muss. Auch sollte die 
Berechnung nicht während der Beschleunigung durchgeführt werden um die 
Lib auf schwächeren µC (16MHz, keine FPU etc.) laufen lassen zu können.
Es soll außerdem eine andere Lib sein wie die schon existierenden. Die 
habe ich mittlerweile auch soweit erstellt nur dass noch die 
Beschleunigung fehlt.
Also keine AccelStepper Lib Lösungen etc.

von fpga (Gast)


Lesenswert?

Also ohne Timer heist mit delay. Mit delay ist aber blockierend für den 
restlichen Code.

Warum nutzt du nicht millis() aus der Arduino-Standard lib?
Und warum schaust du dir nicht fertigen code an`?

Gruzß J

von Patrick G. (patrick_123)


Lesenswert?

Ah sry, hatte ich vergessen zu erwähnen. Ich benutze natürlich keine 
delay() Funktionen um den µC zu pausieren. Ich benutze Micros() was in 
der "currentMicros" Variable zwischengespeichert wird.

"Und warum schaust du dir nicht fertigen code an`?"
Das habe ich aber meist wurden Timer benutzt oder der Code war komplexer 
als mir augenscheinlich nötig. Es soll wirklich keine komplizierte Rampe 
sein.
+1/-1 pro Takt würde eigentlich schon reichen. Außerdem soll es nichts 
abgekupfertes sein da es für ein Schulprojekt ist.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Patrick G. schrieb:
> if (currentMicros >= nextAccTick) {
Da musst du aber beim Überlauf von currentMicros aufpassen, dass es 
nicht zu sehr ruckelt. Und der kommt relativ schnell: nach nur 1 1/4 
Stunden läuft der unsinged long über...

von Nico W. (nico_w)


Lesenswert?

Patrick G. schrieb:
> +1/-1 pro Takt würde eigentlich schon reichen. Außerdem soll es nichts
> abgekupfertes sein da es für ein Schulprojekt ist.

Der Timer zu linearen Rampen ist reziprok. Also 1/t.

: Bearbeitet durch User
von fpga (Gast)


Lesenswert?

>Außerdem soll es nichts abgekupfertes sein da es für ein Schulprojekt ist.

1. Regel in der Entwicklung (egal was): man erfindet das Rad nicht neu!
2. Regel in der Entwicklung (sich selbst): scheitere schnell und 
scheitere oft!

Die 2. Regel wendest du bereits erfolgreich an, bleibt Regel Nr. 1.
Da gibt es Methoden Probleme zu vereinfachen und erst Lösungen an den 
vereinfachten Problem zu entwickeln. Hast du auch schon teilweise 
gemacht, da du z.B. die quadratische Funktion der Beschleunigung in eine 
lineare Funktion der gleichmäßigen Beschleunigung vereinfacht hast um an 
diesem simpleren Problem deine Lösung zu erproben. Und da würde ich 
jetzt auch genau ansetzen und weitermachen.

Viel Erfolg

von Patrick G. (patrick_123)


Lesenswert?

fpga schrieb:
> 1. Regel in der Entwicklung (egal was): man erfindet das Rad nicht neu!
> 2. Regel in der Entwicklung (sich selbst): scheitere schnell und
> scheitere oft!
Die 2 Regeln sind Top! Werde ich mehr beachten. Wobei das Rad neu 
erfinden möchte ich sicher nicht, auch wenn es so rüber kommt^^. Wills 
einfach selber nachbauen ohne direktes "copy/paste und kein Plan von 
nix" :)

Lothar M. schrieb:
> Da musst du aber beim Überlauf von currentMicros aufpassen...

Ok, habe ich mir nun doch genauer angesehen da ich das Overflow-Problem 
erst vernachlässigen wollte was aber für eine Lib ja eigentlich nicht 
gerade schön ist. Folgende Lösung gefällt mir dabei sehr gut welche ich 
auch anwenden werden: http://playground.arduino.cc/Code/TimingRollover
-> Abfrageprinzip ist hier einfach: "if( ul_CurrentMillis - 
ul_PreviousMillis > ul_Interval)"


Nico W. schrieb:
> Der Timer zu linearen Rampen ist reziprok. Also 1/t.

Hmm iwie kann ich das auf die Schnelle noch nicht auf meine bisherige 
Beschleunigung "umdenken".
1
 if (currentMicros >= nextAccTick) {
2
    if (stepDelay_uSec > finalStepDelay_uSec) {
3
      stepDelay_uSec -= 1;  //decrement the stepDelay_uSec until the finalStepDelay_uSec (V_Max) is reached. finalStepDelay_uSec is for ex. 30µS
4
    }      
5
    nextAccTick += AccTickTime; //here for ex. 100 uSec -> must be bigger then finalStepDelay_uSec!                    
6
  }
Werds mir morgen genauer anschauen. Mein "künstlicher" Timer wäre ja der 
feste "nextAccTick". Wenn ich den a la 1/t kleiner werden lasse wird es 
doch zu einer beschleunigten Beschleunigung? ...Ist jetzt aber zu spät.. 
Zeit zu schlafen.. auch wenn's einem noch wurmt^^

Danke schon mal für die bisherigen und (hoffentlich weiterhin) kommenden 
Antworten :)

: Bearbeitet durch User
von Nico W. (nico_w)


Lesenswert?

Ich habe mich vielleicht bisschen schlecht ausgedrückt.


Für die Geschwindigkeit berechnest du ja, da bei Schrittmotoren der Weg 
pro Schritt ja konstant ist, die Zeit pro Schritt. Vereinfachen wir 
einen Schritt = 1mm.


v = 1mm/dt
dt = 1mm/v

v = a*t (a ist zB 1000mm/s^2)
t_1 = 1ms
t_2 = 2ms usw.


v_1 = 1000*0,001 mm/s = 1mm/s
v_2 = 1000*0,002 mm/s = 2mm/s


dt_1 = 1mm / (1mm/s) = 1s
dt_2 = 1mm / (2mm/s) = 0,5s
dt_3 = 1mm / (3mm/s) = 0,333s
dt_4 = 1/4 = 0,25s


Diese Schrittfrequenz hälst du dann immer für 1ms. Wenn du das ganze bei 
jedem einzelnen Schritt neu berechnen möchtest wird das sicher 
komplizierter. Hier hatte ich und ein paar andere schon mal ein paar 
Papers dazu verlinkt. Musst mal danach suchen. Bin gerade nur am Handy.

von Olaf B. (Firma: OBUP) (obrecht)


Lesenswert?


von Wolfgang (Gast)


Lesenswert?

Die Atmel AppNote AVR446 - Linear speed control of stepper motor zu dem 
Thema hast du gelesen? Dort werden die Rampen mit konstanter 
Beschleunigung, incl. Abbremsung rechtzeitig vorm Ziel, ausführlich 
behandelt.
http://www.atmel.com/images/doc8017.pdf

von Olaf B. (Firma: OBUP) (obrecht)


Lesenswert?


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.