PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Atmega 168 bei Beschleunigungsrampe ausgelastet - Abhilfe



erik_wolfram
08.02.2011, 19:22
Hallo,
Ich versuche mich gerade daran, über einen µC einen Schrittmotor sauber anzusteuern. Der Code steht und läuft auch bedingt.

Zum Aufbau:

Atmega 168 - 20 PU
16 Mhz
Verwendeter Timer: Timer1, 16bit, Prescale 64 ->250000Hz
getakteter Ausgang zum Ansteuern eines Schrittmotortreibers mit Halbschritt (800Im/Umdrehung)

Der Atmega 168 berechnet die Beschleunigungsrampe simultan im Interrupt und passt den Timer1 entsprechend an. Die Berechnung muss aus Genauigkeitsgründen mit zwei Variabeln des Typs Single erfolgen da sonst ein Fehler auftritt.
Bei kleineren Drehzahlen, wenn der Timerwert oberhalb von ca. 100 Counts (entspricht 3U/s) bleibt, läuft die Rampe sauber bis zum Ende.
Steigere ich die Drehzahl kommt er hier wahrscheinlich zu Verzögerungen - die Hochlaufzeit erhöht sich deutlich und der Motor dreht unsauber am Ende der Hochlauframpe.

Den hohen Prescale habe ich gewählt, um dem Controller genug Rechenzeit zu lassen, leider kann ich -meines Erachtens nach- nicht viel an der Berechnung ändern. Ohne Float-Werte hängt sich die Rampe irgendwann auf!



$regfile = "m168def.dat"
$crystal = 16000000 ' used crystal frequency
$hwstack = 32 ' default use 32 for the hardware stack
$swstack = 8 ' default use 10 for the SW stack
$framesize = 24
$baud = 19200

Config Timer1 = Timer , Prescale = 64 '250000 Hz
On Timer1 X_irq

Enable Interrupts

Dim C0 As Integer
Dim Cn As Single
Dim Cn_s As Single
Dim Steps As Word

Steps = 0
C0 = 8450
Cn = 8450
Load Timer1 , C0
Enable Timer1

Hier der Code-Ausschnitt aus dem eigentlichen Interrupt:


X_irq:

Toggle Pul

Incr Steps

Cn_s = Cn

Cn = 2 * Steps
Cn = Cn + 0.5

Cn = Cn_s / Cn

Cn = Cn_s - Cn

Load Timer1 , Round(cn)


Nun bin ich mir nicht sicher, ob ich irgendwo am Code etwas ändern kann, oder ob es vielleicht einen stärkeren Atmega für diese Aufgabe gibt?
Würde es eventuell helfen einen Atmega mit mehr Ram zu verwenden, oder eventuell auf 20Mhz umzusteigen?

MFG Erik

Vitis
08.02.2011, 20:36
floating Point bremst den Controller schon mächtig runter ... evtl. wär ne Tabelle ne Lösung

TobiKa
08.02.2011, 20:39
Löst der Timer eventuell schon wieder aus, wenn er mit dem vorherigen Aufruf noch garnicht fertig ist?

erik_wolfram
08.02.2011, 20:52
Also mein Problem bezüglich der Tabellen ist folgendes:
Die Rampe bei 3U/s besteht aus 4000 Schritten (ich kann nicht beurteilen, was für den Atmega viel ist) hinzu kommt, dass noch variable Rampen verfügbar sein sollten.

Ob der Timer sich selbst wieder aufruft weis ich leider nicht - aber eigentlich wird der Timer ja erst nach der Berechnung neu gesetzt. Das sich die hochlaufzeit der Rampe erhöht deutet ja auf eine langsame Abarbeitung hin...

Mir ist klar, dass floating Point den Controller ausbremst, aber ich habe schon alles Mögliche versucht um diesen zu umgehen - immer ohne Erfolg....

Macht es denn Sinn den Singel durch einen Long mit dem Faktor 100 zu erseten? Und diesen dann immer herunterzurechnen? (2 Kommastellen könnten noch reichen)

TobiKa
08.02.2011, 21:02
aber eigentlich wird der Timer ja erst nach der Berechnung neu gesetzt.
Bin in Bascom nicht ganz Fit, aber das sehe ich anders.
Der Startwert wird nach den Berechnungen neu gesetzt, das schliesst doch aber nicht aus das er da schon neu gestartet ist.

leo.vetterli
08.02.2011, 22:58
Mir kommt da spontan etwas in den Sinn. Was glaubst du wie lange ich danach gesucht habe:


'save registers bei single in interrupt nötig
Push R12 ' save registers
Push R13
Push R14
Push R15

code...

'restore registers bei singel in interrupt nötig
Pop R15 ' restore registers
Pop R14
Pop R13
Pop R12

Bei mir war es so, dass sich bei Single - Variabeln im Interrupt plötzlich die Werte selbstständig geändert haben. Nach dem Push und Pop war das nicht mehr der Fall. Warum das bei Bascom so implemeniert wurde.....

Vitis
08.02.2011, 23:48
@TobiKa
Also, zu den Interrupts, Der Interrupt kann ausgelöst werden auch
wenn der µC gerade in einer ISR ist, die Ausführung der zweiten
ISR wird aber normalerweise verschoben bis die erste abgearbeitet ist,
es sei denn man aktiviert die Interrupts in der ISR selbst wieder, was
geht, aber mächtig Probleme verursachen kann. Hat mit
Bascom direkt nicx zu tun, kann man auch in C oder ASM machen.

@leo.vetterli
wenn das pushen und poppen Abhilfe schafft sind zu 99% die Stack-
Frameeinstellungen zu klein, weil Bascom nämlich alle Register versucht
zu pushen und poppen in einer ISR ... leider.

@erik_wolfram
Timer 1, 16-Bit 4000 Schritte sind dann 8000 Byte ... Ist ne ganze Menge,
brauchts wirklich so viele? ... wie auch immer, der 16-Bit Timer kann keine
Kommastellen, shiften, addieren und subtrahieren kann der AVR recht schnell,
Berechnungen gehen sehr schnell wenn man bei Vielfachen von 2 bleibt,
Mittelwerte z.B. über 2,4,8,16,32 Werte z.B. dann kann man einfach durch
schieben um 1,2,3,4,5 Schritte eben dividieren durch 2,4,8,16,32 etc.
Auch immer gerne verwendet für solche Geschichten ist die Tabellen für Sinus,
die kann man vorwärts, rückwärts laufen lassen spiegeln, stecken etc.

Peter1060
09.02.2011, 06:46
moin moin,

welche Form hat die Rampe? Linear oder Sinus^2?
>>der Motor dreht unsauber am Ende der Hochlauframpe.
Wie äussert sich das?
>>floating Point den Controller ausbremst
Bei meiner Fräsensteuerung habe ich per SPI einen 2.MC(100MIPS) als FPU dazugegeben. Für einen Simuswert braucht der ca. 150µs.

Mit Gruß
Peter

WL
09.02.2011, 11:42
Wenn die Rampe linear sein soll / darf:

Warum muß die Berechnung in die ISR ?
Besser:
-Increment /Decrement vorher berechnen
-in der ISR nur Increment / Decrement addieren

erik_wolfram
09.02.2011, 16:45
Also die Rampe ist nicht linear - Sie beruht auf der Taylor-Reihe.

Nachdem ich den Motor jetzt mal unter Last laufen lassen habe, hat sich herausgestellt, dass die Rampe sehr sauber (wenn auch länger) läuft.
Wenn der Motor dann konstant läuft klingt er etwas unschön...
Die Genauigkeit ist aber da ... Schrittfehler (soll/ist) konnte ich nicht feststellen.

Das mit den Tabellen werde ich mir mal genauer angucken, dass ganze einfach vorher zu berechnen ist natürlich eine gute Idee, der ich erstmal nachgehen werde.

Danke für die Hilfe, werde das erstmal ausprobieren und berichten!

Vitis
09.02.2011, 17:14
was mir gerade noch einfällt zu den Tabellen ...
wenn Du nicht direkt den Timer-Wert in die Tabelle, sondern nur
jeweils die Erhöhung von Schritt zu Schritt, dann kannst Du einfach
per Addition eine globale Variable aufsummieren und brauchst nur
4000 Byte. Das ist schnell und "platzsparender" im Flash.

:)

Wenn ich derlei Berechnungen vorab mache verwende ich gern
n Tabellenkalkulationsprogrämmchen und füge die Zeichenketten
per "verketten" zusammen. Dann kann man einfach per Copy & Paste
die Daten in eine Textdatei überführen, die per #include in den
bascom Quelltext eingebunden wird

;)

for_ro
09.02.2011, 18:29
@leo.vetterli
wenn das pushen und poppen Abhilfe schafft sind zu 99% die Stack-
Frameeinstellungen zu klein, weil Bascom nämlich alle Register versucht
zu pushen und poppen in einer ISR ... leider.
@Vitis
leo.vetterli hat vollkommen Recht: Bascom speichert die Register, die nur für floating Point benutzt werden nicht ab. Und das sind R12 - R15. Nutzt man Floating Point in der ISR und außerhalb, muss man die Register selber sichern.
R6, R8 und R9 übrigens auch nicht. Daher dauert der Aufruf der ISR auch nur 53 Takte und nicht 67 (32*2 + 3 für SREG), wie eigentlich anzunehmen wäre.

Hilfe zu On Interrupt:
R12 – R15 are not saved. When you use floating point math in the ISR(not recommended) you must save and restore R12-R15 yourself in the ISR.

erik_wolfram
09.02.2011, 19:12
@for_ro:
danke das werde ich mir mal angucken!

@Vitis
Danke für die ausführlichen und hilfreichen Tips!
Leider - die Tabelle mit den Differenzwerten nimmt sage und schreibe 11kB ein für die 3600 Werte. Leider spielt da die Demoversion von Bascom auch nicht mehr mit (an sowas hatte ich garnicht gedacht).

Das ganze vorher berechnen und in einer Tabelle fällt auch weg, da der SRAM des Atmega 168 nicht dafür ausreicht...

Macht es auf Grund der Demo-Begrenzung von Bascom Sinn auf Ponyprog umzusteigen? Ich kann leider zur Zeit nicht beurteilen, ob mit das durch den zusätzlichen Speicher mehr chancen gibt?!

for_ro
09.02.2011, 19:19
Macht es auf Grund der Demo-Begrenzung von Bascom Sinn auf Ponyprog umzusteigen? Ich kann leider zur Zeit nicht beurteilen, ob mit das durch den zusätzlichen Speicher mehr chancen gibt?!
Nein, du musst ja mit Bascom kompilieren.
Überlege mal, ob du nicht ganz auf die Singles verzichten kannst, indem du mit Long Typen arbeitest.

erik_wolfram
09.02.2011, 19:36
Also das mit den Registern habe ich nochmal probiert.
Ergebnis:
Der µC hängt sich während der Rampe auf und hält eine geringe Geschwindigkeit.

Dann habe ich nochmal gemessen:
Bei 6 U/s verlängert sich die Rampe von berechneten 3s auf 4s.
Der Motor läuft dabei sehr sauber an!

Werde das ganze jetzt mal mit Longvariablen testen!

Vitis
09.02.2011, 20:34
@leo.vetterli
wenn das pushen und poppen Abhilfe schafft sind zu 99% die Stack-
Frameeinstellungen zu klein, weil Bascom nämlich alle Register versucht
zu pushen und poppen in einer ISR ... leider.
@Vitis
leo.vetterli hat vollkommen Recht: Bascom speichert die Register, die nur für floating Point benutzt werden nicht ab. Und das sind R12 - R15. Nutzt man Floating Point in der ISR und außerhalb, muss man die Register selber sichern.
R6, R8 und R9 übrigens auch nicht. Daher dauert der Aufruf der ISR auch nur 53 Takte und nicht 67 (32*2 + 3 für SREG), wie eigentlich anzunehmen wäre.

Hilfe zu On Interrupt:
R12 – R15 are not saved. When you use floating point math in the ISR(not recommended) you must save and restore R12-R15 yourself in the ISR.

echt?? .. Danke für den Hinweis, man lernt eben doch nie aus :)

erik_wolfram
09.02.2011, 20:55
So, ich danke für die Hilfe!
der Austausch von Single gegen Long war vollkommen erfolgreich. Ich musste zwar den Faktor 1000 verwenden (also 3 Nachkommastellen), jetzt funktioniert aber alles super.

Außerdem:
Ich habe noch ein Display angeschlossen, die Störungen die das Interrupt bei Beschleunigung (hohe Rechenleistung) verursacht hat sind verschwunden.


Nebenbei hätte ich nochmal eine Frage in diesen Zusammenhang:

Ich weis, dass ich sehr viele Anweisungen im Timer-Interrupt habe.
Kann ich diese mit dem Timerwert verrechnen, damit diese sich nicht durch ihre Abarbeitunsgzeit auf den Timer aufaddieren?
Gibt es zuverlässige Angaben über die Abarbeitungszeit von Anweisungen?

for_ro
09.02.2011, 22:41
Ich weis, dass ich sehr viele Anweisungen im Timer-Interrupt habe.
Kann ich diese mit dem Timerwert verrechnen, damit diese sich nicht durch ihre Abarbeitunsgzeit auf den Timer aufaddieren?
Es ist ja nicht grundsätzlich schlecht, viele Anweisungen in der Timer ISR zu haben. Es kommt darauf an, was der µC sonst noch abarbeiten muss und ob die ISR fertig wird, bevor der nächste Aufruf kommt.
Zeig doch mal deine ISR, die Timer Config und die Dims der verwendeten Variablen.


Gibt es zuverlässige Angaben über die Abarbeitungszeit von Anweisungen?
Im Simulator kannst du dir sehr gut ansehen, wieviele Takte und Zeit deine Befehle benötigen. Und auch, wie lange die ganze ISR braucht.

erik_wolfram
12.02.2011, 14:46
Also ansonsten hat de µC während der Rampenfahrt nicht viel zu tun. Es wird ein Ausgang für Stop geprüft, ansonsten berechnet er nur 2-5 mal die aktuelle Position und gibt diese auf einem LCD-Display aus.

So läuft das ganze zufriedenstellen - derzeit betreibe ich das ganze an einer Messvorrichtung - Positioniergenauigkeit liegt im µ-Bereich (+-2µ)! Also die Rampen sollten sauber laufen. Lediglich wenn ich die Berechnung am Ende der Rampe abbrechen würde höre ich einen Unterschied (Währscheinlich zu große Zeit differenz) - deshalb lasse ich den Atmega trotzdem weiterrechnen...

Jetzt soll aber noch etwas hinzukommen:
Ein 2. Schrittmotor - lediglich deutlich langsamer in der Drehzahl!
Dafür suche ich zum Ersten einen 28Dip-Atmega mit 2 16-bit Timern (wenn es einen gibt) und 2. bin ich am überlegen ob das generell möglich ist bei solchen Takten (2 x ~1600Takte) oder ob sich diese derart gegenseitig stören?!

Hat schonmal jemand Erfahrung damit gemacht und könnte mir Ratschläge geben?

Den Code würde ich posten sobald er in einer ordentlichen Form steht ... (ich neige dazu meinen ATmega "vollzumüllen")

Mit dem Simulator muss ich mich noch auseinander setzten, ist doch alles Neugebiet für mich...

Aber als Erstes werde ich mir die Vollversion von Bascom beschaffen - darum werde ich nicht herumkommen.
Aber die ersten Versuche haben mirt gezeigt, dass ich auf dem richtigen Weg bin.

for_ro
12.02.2011, 15:32
Dafür suche ich zum Ersten einen 28Dip-Atmega mit 2 16-bit Timern (wenn es einen gibt) und 2. bin ich am überlegen ob das generell möglich ist bei solchen Takten (2 x ~1600Takte) oder ob sich diese derart gegenseitig stören?!

2 16-bit Timer haben die wenigsten. Wofür benötigst du denn unbedingt einen 16-bit Timer? Kannst du das nicht mit einem 8-bit Timer erledigen und die Anzahl der Überläufe mitzählen?
Und was benötigt 1600 Takte?

erik_wolfram
12.02.2011, 15:43
hmmm ich kann leider nicht abschätzen, wie sich mehrere Timer (negativ) gegenseitig beeinflussen.

Bei 8-Bit Timern hätte ich Angst, dass sich die häufigeren Aufrufe beider Schrittmotoren gegenseitig ins "Handwerk" fuschen.
Außerdem steigt so die komplexität des Codes, ich müsste ja die beiden Timer wesentlich komplexer gegenseitig kompensieren (Eine Interrupt-Abartbeitung verzögert die des anderen) (soweit das überhaupt möglich ist).

Derzeit laufen die Motoren im Halbschritt = 400Schritte / Umdrehung. Der eine Motor hätte dafür eine Drehzahl von 3-4U/s -> *400 = 1600 Impulse - kommen noch die Wartezeiten (Ein-Aus) hinzu - werden daraus (habe ich vergessen) sogar 3200 Interrupts/sekunde.
Den Timer verwende ich auch für die Berechnung der Ein-Zeiten um ein maximal langen Ein-Impuls an der Schrittmotorendstufe zu haben.

[EDIT]
Danke für den Tip mit dem Simulator - konnte so genau die Zeitlich gemessene Differenz berechnen/ermitteln - also das haut sehr genau hin.

Jetzt muss ich den Code noch optimieren:
Bei maximaler Drehzahl beträgt der Timer 0.4ms - die Rechen-Verzögerung beläuft sich dabei auf 0.12ms zusätzlich!

E-Fan
27.02.2011, 17:42
Es wäre hilfreich wenn Du etwas mehr von Deinem Code posten würdest damit man verstehen kann was Du vor hast.
Für mich riechts stark nach ner CNC-Steuerung welche direkt mit G-Code gespeist werden soll und Deine Berechnungen könnten für Kreisbahnfahrten/Radiuskorrekturen von Nöten sein.
Das bleibt bei den wenigen Programmschnippseln aber Spekulation und bringt Dich nicht weiter.
Wenn Du die Motoren im Halbschritt betreibst nützt Dir die feine Auflösung der Encoder wenig wenn Dein Getriebe nicht passend aufgebaut und die ganze Anlage nicht in einem vollklimatisiertem Raum steht.

erik_wolfram
27.02.2011, 18:36
Also geplant ist nur eine (langsame) 2-Achs-Steuerung!
Eventuell war noch eine externe Einspeisung von Bewegungsbefehlen (G-Codes) angedacht.
Aber für eine CNC-Steuerung wird ein Atmega (zum jetztigen Zeitpunkt) definitiv nicht reichen - bei einem Vorschub von 1000mm mit 3mm Steigung und Halbschritt bei 2Achsen-Bewegung ist der Atmega rein rechnerisch an der Grenze! Und da ist eine Interpolation noch nicht bedacht.

Jetzt bin ich abert erstmal damit beschäftigt das Ganze unter C++ (gcc) zum Laufen zu bekommen. Die Bascom-Demo schränkt zu stark ein, auch wenn sie wesentlich übersichtlicher/einfacher ist.

Sobald ich den Code übersetzt habe werde ich versuchen ihn zu optimieren. Dann kann ich nochmal mehr über eine CNC-3-Achs-Steuerung spekulieren!

E-Fan
27.02.2011, 20:08
Ohne Dir zu Nahe treten zu wollen:
Ich glaube das Du Dich vorher nochmal ganz intensiv mit G-Code auseinandersetzen solltest. Der kann nämlich schon seines Alters wegen kaum Rechenlast verursachen.
Wie schon weiter vorne geschrieben macht eine Auflösung im µm-Bereich ohne Temperaturkompensation (thermisch wie auch Messtechnisch) keinen Sinn. Alles unter 1/100mm Zustellung lässt sich nur noch mit hochpräzisen Werkzeugmaschinen erreichen die dann ohnehin mit entsprechenden Mess- und Antriebssystemen ausgestattet sind.
Anders beschrieben:
Einmal gegen das Werkstück gehaucht oder in dem Raum, in dem die Maschine steht was vom Tisch geschmissen und der Versuch das Maß auf 2µm genau zu halten ist für'n Arsch. ;)