Tag zusammen,
ich arbeite im Moment mit dem Attiny25 und der 16MHz internen Clock. Mit
dem Controller werte ich Signale im 10-30µs Bereich aus. Im Prinzip
funktioniert das ganze wie eine Art Servoregelung, nur dass das Signal
kein typisches Servosignal ist, sondern ein 9-Bit Signal mit diesen µs
Pegeln. Der Ablauf des Controllers ist folgender:
-Signal einlesen und auswerten (Sollwert)
-A/D Wandlung für die Ist-Position des Motors
-Regelung
und wieder von vorne.
Soweit klappt das ganze schon ganz gut, nur irgendwie hab ich das Gefühl
das die Regelung dabei zu langsam von statten geht. Der Motor zittert
ein wenig beim einregeln und dieses Zittern häte ich gerne weg.
Nun ist meine Frage jemand einen Controller von der Größe des Attiny25
kennt, der mehr als 16MHz interne Clock besitzt? Einen externen Quarz
kann ich wegen Platzmangel leider nicht verwenden.
Eine andere Frage wäre noch ob es etwas bringen würde, das Programm in
Assembler anstatt C zu schreiben?
Über ein Paar Tips würd ich mich freuen.
Gruß
Kuen
Schau mal das du nicht die CHKDIV/8 Fuse gesezt hast (weiß nicht ob der
Tiny sowas besizt) und lad am besten auch mal die Korrekturwerte des
internen RC Ozilators.
Achja ASM kann natürlich was bringen gerade wenns Zeitkritisch ist...
Hmm ja, prinzipiell gibt es noch 20 MHz Atmel Controller.
Da das aber nicht viel mehr ist, kann es durch optimieren deines Codes
möglich sein, dass du mehr raus holst.
Wenn du mit AVR-GCC proggst, stell die Codeoptimierung mal auf "Speed".
Ansonsten poste mal dein Programm. Grundsätzlich ist es möglich mit ASM
schnellere Programme zu schreiben -Wenn du weisst wie und es dir antun
willst.
Wenn der Motor zittert, kann das auch an ungünstig eingestellten
Regelparametern liegen. Ich denke, dass Deine Regelung schon schnell
genug ist. Vielleicht auch ein Software-Fehler?
Ich denke durch Software-Optimierung kann man vielleicht mehr als die
25% rausholen. Bis jetzt habe ich es immer geschafft, auch wenn es auf
den 1. Blick hoffnungslos aussieht.
Poste doch mal deinen Code. Ich denke die Leute werden dir bestimmt
helfen und Optimierungspotential aufzeigen.
Morgen,
erst eimal vielen Dank für eure Antworten.
Also das CHKDIV/8 Fuse ist nicht gesetzt. Der Controller läuft mit den
16MHz, das hab ich mir am Oscar angeschaut. Zittern tut der Motor nur,
wenn er in Position fährt, aber das liegt denke ich am über bzw. unter
Regeln. Wenn er die Position dann erreicht hat ist das Zittern weg.
Hab den Code mal angehängt, vielleicht habt ihr ja ein paar
Verbesserungsvorschläge für mich.
Gruß
Kuen
@ Kuen (Gast)
>Hab den Code mal angehängt, vielleicht habt ihr ja ein paar>Verbesserungsvorschläge für mich.
Pulsdauer = TCNT0;
Das würde ich als ERSTE Anweisungh in den INterrupt schreiben. Nur so
hat man einen konstanten Zeitbezug zwischen externer Flanke an INT0 und
dem Zähler. Bei dir sind noch die Abfragen davor, die je nach Zweig
unterschiedlich lange dauern. Damit kommt es zu einem Messfehler.
MFG
Falk
> Wenn der Motor zittert, kann das auch an ungünstig eingestellten> Regelparametern liegen.
Das wird mit Sicherheit der Fall sein. Das einzige was an so einer
Regelung schnell sein muss ist die Abtastung des Istwertes von den
Winkelencodern und auch nur deshalb weil die bei Maximalgeschwindigkeit
mithalten muss.
Der eigentliche Regler kann sehr langsam sein.
Olaf
@Falk
Danke für den Tip!
@Olaf
>> Wenn der Motor zittert, kann das auch an ungünstig eingestellten>> Regelparametern liegen.> Das wird mit Sicherheit der Fall sein.
Aber in wie fern. Im Prinzip ist die Regelung ja nur ein Soll- Istwert
Vergleich.
Das ganze läuft ja so ab:
-Sollwert einlesen
-Istwert einlesen
-Vergleichen
-Regeln
Wie kann ich da die Abtastung des Istwertes beschleunigen?
Hab das AD-Wandeln mal etwas beschleunigt indem ich den Wandler etwas
schneller getaktet hab. Bei 8-Bit Auflösung dürfte es dabei eigentlich
keine Probleme geben. Bringt aber keine wesentliche Verbeserung. Was
könnte ich noch optimieren?
Wenn ich es richtig verstehe, Regelst du, wenn c=0.
c wird vom externen Interrupt auf 0 gesetzt. Wann und wieviel Mal pro
Sekunde wird c=0 ?
Kann es sein das du zu schnell regelst? Vielleicht mal eine Totzeit
einbauen?
Sehe ich es richtig, dass du keine P(I)(D) Regelung verwendest sondern
einfach nur auf Schwellwerte schaust und somit eine gewisse Hysterese
hast?
@ Kuen (Gast)
>Aber in wie fern. Im Prinzip ist die Regelung ja nur ein Soll- Istwert>Vergleich.
Wenns soooo einfach wäre . . . ;-) Reglerparametrierung ist eine
Wissenschaft für sich.
>Das ganze läuft ja so ab:>-Sollwert einlesen>-Istwert einlesen>-Vergleichen
Das ist relativ einfach
>-Regeln
Hinter diesen kleinen Wort steckt eine Wissenschaft!
>Wie kann ich da die Abtastung des Istwertes beschleunigen?
Wozu? Du weisst doch gar nicht wodurch das Ruckeln verursacht wird.
>keine Probleme geben. Bringt aber keine wesentliche Verbeserung. Was>könnte ich noch optimieren?
Die Parameter. Wobei ich nicht so recht in deinem Code durchsteige.
Deine Stellgrösse ist rein digital in motor(), wenn ich das recht sehe
ist da reines ON/OFF mit einer Vollbrücke, nicht wahr?
Du hast keinen Filter für deine Istwerte, und der Regelalgorithmus
erschliesst sich mir auch nicht so wirklich.
MfG
Falk
Es ist ein Zweipunktregler und hat keine Regelparameter. Es gibt nur den
Ist- und den Sollwert.
> Wann und wieviel Mal proSekunde wird c=0 ?
Also c wird immer zwischen den Signalpegeln 0. Ein komplettes Signal
dauert ca. 1,5ms. Zwischen den einzelnen Pulsen des Signals hat der
Controller ca. 120µs Zeit die AD-Wandlung und die Regelung zu machen.
Zwischen den Signalen gibt es eine Pause von ca. 60ms in der auch
gewandelt und geregelt wird.
>Sehe ich es richtig, dass du keine P(I)(D) Regelung verwendest sondern>einfach nur auf Schwellwerte schaust und somit eine gewisse Hysterese>hast?
Ist richtig, hab schon überlegt eventuell mal ne PI-Regelung zu
versuchen. Hatte auch mal irgendwo ne Seite gefunden wo die Regler für
Mikrocontroller erklärt waren. RC-Wissen oder Kreatives Chaos, find die
Seite leider nicht mehr wieder.
Ich steige bei deinem Code auch nicht ganz durch.
Ich könnte mir aber vorstellen dass das Zittern von daher kommt:
Du hast ja eine Hyterese von +-3 = 6 von max. 256. Das ist schon
ziemlich viel und ich denke das verursacht das Zittern.
Wahrscheinlich bist du auch viel zu schnell mit "Regeln", der Motor
braucht auch seine Zeit, bis er den Sollwert erreicht hat.
Dann hast Du einen P-Regler gebaut bzw. programmiert und der Kollege
P-Regler hat eine bleibende Regelabweichung. Das heißt, daß die
Ausgangsgröße immer um den Sollwert herum schwankt. Darum wird der Motor
zittern. Ich nehme mal an, daß ein PI-Regler dafür besser wäre, weil der
Motor ja eine gewisse Totzeit hat.
MfG Paul
>Die Parameter. Wobei ich nicht so recht in deinem Code durchsteige.>Deine Stellgrösse ist rein digital in motor(), wenn ich das recht sehe>ist da reines ON/OFF mit einer Vollbrücke, nicht wahr?
Richtig! Also der Motor wird über einen Motortreiber gesteuert. Der
brauch drei Eingangszustände. Zwei Zustände(Ausgänge PB0 und PB3) sagen
der Treiber in welche Richtung der Motor drehen soll), der andere ist
dauerhaft High und sagt Vollgas. Dabei gäbe es eventuell noch die
Möglichkeit anstatt Vollgas die Geschwindigkeit über PWM zu regeln.
>Du hast keinen Filter für deine Istwerte, und der Regelalgorithmus>erschliesst sich mir auch nicht so wirklich.
Das mit den Filtern versteh ich nicht ganz? Der Regelalgorithmus ist
aber Recht einfach. Es wird das Signal über den externen Interrupt
eingelsen(Sollwert). Die Position des Motors wird vom AD-Wandler
eingelsen(Istwert).
Dann wird so geregelt:
if((lenkung_ist <= (lenkung_soll +3))&&(lenkung_ist >= (lenkung_soll -
3)))
{
PORTB &= ~(1 << PB3);
PORTB &= ~(1 << PB0);
}
if((lenkung_ist +3) < (lenkung_soll))
{
PORTB |= (1 << PB3);
PORTB &= ~(1 << PB0);
}
if((lenkung_ist -3) > (lenkung_soll))
{
PORTB |= (1 << PB0);
PORTB &= ~(1 << PB3);
}
es wird also immer der Ist und Sollwert verglichen. In dem einen Fall
dreht der Motor rechts rum, im anderen links rum. Sind sie
"gleich"(+-3)" bleibt der Motor stehen. Wenn ich die Hysterese von +-3
kleiner mache, wird das Zittern stärker.
Ok, du willst bei 16MHz nen Regelintervall von 10-30µs. hast also pro
Intervall 160-480 Taktzyklen.
Wenn du wirklich so nen Intervall willst, würde ich mal in Assembler
schreiben. In C halte ich das für grenzwertig.
Schau mal auf die Atmel-Seite, da gibbet ne AN für nen PID-Regler. Is
nich das optimale, aber sollte reichen.
nen Tiny zu verwenden halte ich auch für gewagt, weil keinen
multiplikator...
@ Kuen (Gast)
>dauerhaft High und sagt Vollgas. Dabei gäbe es eventuell noch die>Möglichkeit anstatt Vollgas die Geschwindigkeit über PWM zu regeln.
Das würde ich mal nicht aus den Augen verlieren wollen.
>>Du hast keinen Filter für deine Istwerte, und der Regelalgorithmus>>erschliesst sich mir auch nicht so wirklich.>Das mit den Filtern versteh ich nicht ganz?
PID Regler wirken wie ein Filter, dadruch wird die Reglung besser.
> Der Regelalgorithmus ist>aber Recht einfach. Es wird das Signal über den externen Interrupt>eingelsen(Sollwert). Die Position des Motors wird vom AD-Wandler>eingelsen(Istwert).
Du willst also ein Servo nachbauen. OK.
>"gleich"(+-3)" bleibt der Motor stehen. Wenn ich die Hysterese von +-3>kleiner mache, wird das Zittern stärker.
Scheint so, dass sich Soll und Istwert überholen, durch das harte
Anfahren vom Motor -> Zittern.
@ Lars Kollros (Gast)
>Ok, du willst bei 16MHz nen Regelintervall von 10-30µs. hast also pro>Intervall 160-480 Taktzyklen.
Ich glaube kaum, dass für diese Servostuerung 30us Zyklus gebraucht
werden. Ich tippe mal, dass 1ms locker reicht. Aber dazu muss konstant
im 1ms Raster geregelt werden! Das sehe ich nicht! Dazu sollte man einen
Timer verwenden. Allerding würde ich dann die Pulsbreitenmessung besser
mit ICP machen, das stresst die CPU WESENTLICH weniger.
MFG
Falk
Also wie würdet ihr denn den Ablauf gestalten?
Nach den ganzen Beiträgen würde ich nun wie folgt vorgehen:
-Timer Compare Interrupt erzeugen welches alle 2ms einen Interrupt
ausführt.
In diesem Interrupt würde ich dann die Regelung machen. (Nur welche?
Zweipunkt PI?) Gut, das kann man ja dann ausprobieren.
-Zwischen diesen 2ms genau einmal das Signal einlesen(Sollwert) und
einmal
AD-Wandeln(Istwert).
> Ich glaube kaum, dass für diese Servostuerung 30us Zyklus gebraucht> werden. Ich tippe mal, dass 1ms locker reicht.
Diese Einschatzun teile ich. :-)
Uebelege doch mal wie schnell sich die Masse deines Motors ueberhaubt
bewegen kann.
> In diesem Interrupt würde ich dann die Regelung machen. (Nur welche?> Zweipunkt PI?) Gut, das kann man ja dann ausprobieren.
Das Problem ist nicht der Regler, ein PI-Regler ist da sicher erstmal
ein guter Anfang, das Problem sind die Regelparameter.
Olaf
Das Signal kommt ja nur alle 60ms. Aber in der Zeit kann ich ja trotzdem
den Istwert einlesen und Regeln. Dann muss nur das Timing passen, dass
das Signal auch alle 60ms eingelsen wird und der Interrupt da nicht
zwischen haut.
@ Kuen (Gast)
>Das Signal kommt ja nur alle 60ms. Aber in der Zeit kann ich ja trotzdem>den Istwert einlesen und Regeln. Dann muss nur das Timing passen, dass
Sicher.
>das Signal auch alle 60ms eingelsen wird und der Interrupt da nicht>zwischen haut.
Lässt sich machen. Wie gesagt, ich würde ICP nehmen.
MFG
Falk