PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Schrittmotor zeitpräzise steuern



Geistesblitz
08.07.2011, 17:08
Ich probiere in letzter Zeit mit Schrittmotorsteuerungen herum, allerdings bin ich mit dem jetzigen noch nicht so ganz zufrieden. Bisher Lasse ich einfach Schleifen laufen, in denen dann um einen konstanten Wert gewartet wird bevor der Port einen kurzen Impuls erhält. Allerdings addiert sich zu der eingestellten Wartezeit die kurze Rechenzeit für Schleife und Portsetzen. In diesem Fall ist das noch nicht ganz so problematisch, wenn man allerdings Rampenprofile oder inverse Kinematiken zwischendurch ausrechnen möchte beeinflusst das die Genauigkeit der Impulszeiten doch schon. Wie geht man das denn besser an? Ich versuche mich auch gerade, mit Timern und Interrupt einzulesen, allerdings weiß ich nicht, wie man sowas auf Schrittmotorprogramme anwenden kann. Erst recht weiß ich nicht, wie man mehrere Schrittmotoren unabhängig voneinander steuern kann. Es gibt doch sicherlich Leute hier, die sowas schonmal gemacht haben, oder?

Besserwessi
08.07.2011, 18:17
Genau für diese Aufgabe gibt es Timer und Interrupts. Über Timerinterrupts kann man Aufgaben zu recht genau definierten Zeiten Ausführen lassen. Insbesondere addieren sich dabei kleine Fehler nicht auf, weil die Zeit unabhängig per Hardware läuft. Damit kann man dann auch mehrere Motoren unabhängig laufen lassen.

Ein mögliche Form wäre es die Schrittmotorsteuerung komplett den Interrupt zu verlegen. Für das Hauptprogramm kann das dann so aussehen als hätte man einen unabhängigen Controller für die Schrittmotoren, dem man nur noch sagen muss, wo der Motor hin soll, und ggf. wie schnell. Nach jedem Schritt wird die Zeit für den nächsten Schritt berechnet und der Timer (als eine Art Wecker) entsprechend gesetzt das dann der nächste Interrupts auftritt. Auch werden die schon gemachten Schritte mit gezählt um zu sehen ob das Ziel schon erreicht ist.

Richtig gemacht sollte dabei keine Warteschleife mehr auftreten und die Zeiten allein durch den Timer bestimmt werden.

Geistesblitz
08.07.2011, 21:06
Das hört sich wirklich nach dem an, was ich suche. Jetzt wäre es nur interessant zu wissen, wie sowas für die konkrete Problemstellung aussehen muss. Wo kann man denn Beispielskripte dazu ansehen (vorzugsweise in Bascom)? Und wie realisiert man eine Steuerung für mehrere Motoren? Mehrere Timer verwenden? Wobei, man hat ja nur 3 zur Verfügung...

Besserwessi
08.07.2011, 21:40
Man braucht nicht für jeden Motor einen eigenen Timer. Es reicht 1 Timer, der die ganze Zeit durch läuft und es wird nur das Output compare Register angepasst. Das entspricht in etwa der Weckzeit für einen Wecker. Man hat bei Timer 1 in der Regel 2 solcher Register. Für mehr Motoren wird es aber schon etwas aufwendiger.

Geistesblitz
08.07.2011, 23:05
Ich bin jetzt gerade dabei, ein wenig mit dem Timer herum zu probieren, allerdings gibts da wohl noch ein paar Verständnisprobleme. Ich habe jetzt folgenden einfachen Code geschrieben:

$regfile = "m32def.dat"
$framesize = 32
$swstack = 32
$hwstack = 32
$crystal = 1000000
$baud = 9600


Config Portc.1 = Output
Config Timer1 = Timer , Prescale = 256
Enable Timer1
On Timer1 Led
Enable Interrupts

Led:
Toggle Portc.1
Timer1 = 34215
Return

Eigentlich müsste die LED etwa alle 16 Sekunden an/aus gehen, stattdessen flackert sie aber nur ziemlich schnell...was mache ich falsch?

Besserwessi
09.07.2011, 19:15
Es fehlt irgendwie noch ein Hauptprogramm. Da sollte einfach eine Endlosschleife rein, oder wenn man es ganz vornehm will, auch noch den µC in den Idel- Mode versetzen. Ich weiss nicht was BASCOM am Ende des Programms macht, und wie der µC darauf dann reagiert. Das könnte aber die Ursache sein.

Geistesblitz
09.07.2011, 19:27
Hab das mittlerweile auch schon herausgefunden und mit einem !Nop in einer schleife gelöst (hab ich beim Suchen so gefunden). Zur Erzeugung einer Rampe habe ich folgenden Link entdeckt:
http://www.mikrocontroller.net/articles/Schrittmotoren#Beschleunigungsrampen_richtig_w.C3. A4hlen_und_berechnen
Besonders das hier:

Häufigster Fehler
Die Rampe wird unter der Prämisse erstellt, die Zeit zwischen den Einträgen sei konstant, man könne also die linear berechneten Frequenz- oder Timerwerte einfach so eintragen. DEM IST NICHT SO. Die Mitte der Liste ist bei Weitem nicht nach der halben Rampenzeit erreicht, da Schritte am Anfang wesentlich langsamer ausgeführt werden. Die Liste muss bei niedrigen Geschwindigkeiten grobe, bei hohen Geschwindigkeiten feine Abstufungen haben.

Richtig ist: nach jedem Step die Zeit seit Beschleunigungsbeginn (einfach die Timer-Werte aufaddieren), daraus die gewünschte Frequenz und daraus den benötigten Timer-Wert berechnen.

Hatte den Fehler erst auch gemacht *schäm*
und versuche das nun irgendwie umzusetzen, irgendwie steh ich da aber noch auf dem Schlauch...

edit:
Hab den Code jetzt so weit gebracht:

$regfile = "m32def.dat"
$framesize = 32
$swstack = 32
$hwstack = 32
$crystal = 1000000
$baud = 9600

Config Portc.0 = Output
Config Portc.1 = Output
Config Timer1 = Timer , Prescale = 8
Enable Timer1
On Timer1 Led
Enable Interrupts

Dim A As Word
Dim V As Word
Dim V0 As Word
Dim S As Word
Dim Sk As Word
Dim Sa As Word
Dim Sv As Word
Dim Temp As Single
Dim Temp1 As Word
Dim T As Single
Dim Ta As Single
Dim Tp As Word
Dim B As Long
Dim Zeit As Single

S = 20000
V = 1000
A = 200
V0 = 100

Temp1 = V - V0
Temp = Temp1 * Temp1
Sa = Temp1 / A

Sk = S - Sa
T = 1 / V0

Zeit = T
B = 0

Do

If B = S Then B = 0

If B < Sa Then
Temp = A * Zeit
Temp = Temp + V0
T = 1 / Temp
Temp = 125000 * T
Tp = Round(temp)
Elseif B > Sk Then
Temp = Ta - Zeit
Temp = A * Temp
Temp = Temp + V0
T = 1 / Temp
Temp = 125000 * T
T = Round(temp)
Else
T = 1 / V
Temp = 125000 * T
Tp = Round(temp)
Zeit = 0
End If

If B = Sa Then Ta = Zeit
Loop
End

Led:
Toggle Portc.1
Load Timer1 , Tp
Zeit = Zeit + T
Incr B
Toggle Portc.1
Return

Allerdings ergibt das Ganze nur ein seltsames Stocken am Schrittmotor. Findet wer den Fehler?

Geistesblitz
12.07.2011, 22:07
Auch wenn sich keiner weiter gemeldet hat, nach langem Herumprobieren habe ich es doch so halbwegs hinbekommen. Hier mal ein Video davon:


http://www.youtube.com/watch?v=xkUrS9IjVAc

Am Ende kann man etwas sehen, was mich sehr stört und ich weiß auch nicht, wo das her kommt. Der Motor fährt nicht bis auf die Mindestgeschwindigkeit und kehrt dann um, sondern fährt bis ganz herunter und bekommt dann Probleme, da dann die Frequenz zu klein für den Timer wird. Das Piepen ist der Chopper zur Stromregelung (keine Ahnung, warum man das nur manchmal hört...).
Ansonsten muss ich noch die Fallunterscheidung einbauen, falls der Beschleunigungsweg größer als der Gesamtweg ist, sollte jetzt aber nicht mehr das Problem darstellen.

Hier der Code (ist reichlich kompakter geworden, hab sämtliche Floats rausgeschmissen)



$regfile = "m32def.dat"
$framesize = 32
$swstack = 32
$hwstack = 32
$crystal = 1000000
$baud = 9600

Config Portc.0 = Output
Config Portc.1 = Output
Config Timer1 = Timer , Prescale = 8
Enable Timer1
On Timer1 Isr
Enable Interrupts

Dim A As Word
Dim V As Word
Dim V0 As Word
Dim S As Word
Dim Sk As Word
Dim Sa As Word
Dim Temp As Long
Dim Dt As Long
Dim T As Long
Dim B As Long

S = 10000
V = 2000
A = 1500
V0 = 2

Temp = V - V0
Temp = Temp * Temp
Temp = Temp / A
Sa = Temp / 2

Sk = S - Sa
Sk = Sk + 1
Dt = 0
T = 0
B = 0
V0 = 125 * V0

Do

If B = S Then
B = 0
Toggle Portc.0
End If

If B >= Sa And B <= Sk Then
Dt = 125000 / V
Else
Temp = T / 1000
Temp = A * Temp
Temp = Temp + V0
Dt = 17000000 / Temp
End If

Loop
End

Isr:
Load Timer1 , Dt
Toggle Portc.1
If B < Sa Then
T = T + Dt
Elseif B > Sk Then
T= T - Dt
Else
T=T
End If
Incr B
Toggle Portc.1
Return