PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Fragen zu Druckregelung mit AtMega



Mr Bean
14.05.2007, 21:33
Hallo

Ich hab da ein paar Fragen zu einer Schaltung die ich für ein Projekt während meines Studiums machen muss.
Ich muss eine Luftdruck regelt. Hierzu hab ich einen Drucksensor welcher mir eine Analoge Spannung zwischen 0 und 5V ausgibt. Jetzt ist mit schon klar ich die über den AD Wandler in mein µC bekommen muss.
In abhängigkeit zu dem Druck soll dann ein Servo angesteuert werden. Das größere Problem ist jetzt die Digitalen Werte Welche bei 8 bit ja zwischen 0 und 255 liegen weiter zu verarbeiten. Und zwar ist das ja so, daß später dann der Wert 255 für 5bar steht und 0 für 0bar. Wie lege ich diesen Wertebereich in dem Controller fest?
Außerdem soll das nachher so funktionieren daß ich einen Wert vor gebe also z.B. 1,5bar und das Servo nachher über eine art Ventil den Druck auf diesen Wert regelt.
Könnt ihr mir da ein paar Denkanstöße geben und ein paar Tips? Ich werde heut Abend erstmal versuchen den AD-Wandler sauber an zu sprechen.
Bin aber wie gesagt für jede Hilfe dankbar. Vor allem weil diese Problem so schnell wie möglich gelöst werden sollte.
Vielen dank im Voraus!

MFG

Bean

Vitis
15.05.2007, 10:03
Zunächst mal währe es wichtig zu wissen welcher µC,
davon hängt dann ab ob externer ADC oder interner.
Viele AVRs haben nämlich inerne ADC mit 10 Bit Auflösung.

Bei einem Projekt hab ich festgestellt, dass nicht nur der
momentane Istwert wichtig für die Regelung ist, sondern auch
die Tendenz (lineare Regression), sprich der Verlauf der Werte
innerhalb eines bestimmten Zeitraums und auch der Mittelwert.

Hab nämlich schon schöne Regelstrecken schwingen sehen ;)

Mr Bean
15.05.2007, 11:43
Hallo

Also Controller setze ich grad einen ATMega 8 ein. Ich hab den AD-Wandler gestern gestartet bekommen und Simuliere den Sensor nun mit einem Poti... 8-[ .
Habe externe Ref. Spg. gewählt, da mir der Sensor später eh einen Wert zwischen 0 und 5 V ausgibt. Auf Vref liegt bei mir jetzt Vcc also 5V.

Kann mir die Digitalen Werte auch auf dem Port über LED`s anzeigen lassen. Das funktioniert. Heute werde ich mal versuchen noch ein Servo anzusteuern. Nur für die eigentliche Regelung mit Sollwert vorgabe und so hab ich echt keinen Plan und auch keine Idee. Einer meiner Professoren hat mir heute gesagt dass es passieren kann daß das so gar nicht funktioniert und ich Probleme mit dem Speicherplatz auf dem Controller bekommen werde. :-k

AD-Wandler hab ich jetzt mal den 8 Bit genommen. Ach ja Quarz ist ein 4 MHz drin.

Wäre euch wirklich für weitere Hilfe dankbar. Vor allem was die Regelung angeht...

Grüße!!

Bean

PS: Hier mal noch mein bisheriger Code:

#include <avr/io.h>
#include <inttypes.h>

uint16_t readADC(uint8_t channel)

{
uint8_t i;
uint16_t result = 0;

// Den ADC aktivieren und Teilungsfaktor auf 32 stellen
ADCSRA = (1<<ADEN) | (1<<ADPS0) | (1<<ADPS2);

// Kanal des Multiplexers waehlen (ADC 0)
ADMUX = (!(1<<MUX0)) | (!(1<<MUX1)) | (!(1<<MUX2));

// externe Referenzspannung verwenden (also 5,0 V)
ADMUX |= (!(1<<REFS1)) | (!(1<<REFS0));

// Den ADC initialisieren und einen sog. Dummyreadout machen
ADCSRA |= (1<<ADSC);
while(ADCSRA & (1<<ADSC));

// Jetzt 3x die analoge Spannung and Kanal channel auslesen
// und dann Durchschnittswert ausrechnen.
for(i=0; i<3; i++) {
// Eine Wandlung
ADCSRA |= (1<<ADSC);
// Auf Ergebnis warten...
while(ADCSRA & (1<<ADSC));

result += ADCW;
}

// ADC wieder deaktivieren
ADCSRA &= ~(1<<ADEN);

result /= 3;

return result;
}

int main(void)

{
uint16_t result = readADC(0); //Auslesen der analogen Spannungen an Pin 0,
// also ADC0. In result steht das Ergebnis.
DDRD = 0xff; //PORT D als Ausgang definieren (Hier sind 8 LED`s angeschlossen)
PORTD = result;//Den Digitalen Wert mit Hilfe der LED`s anzeigen
return 0;
}

Hubert.G
15.05.2007, 14:45
Du weisst doch welcher Druck dir welche Spannung erzeugt und machst einen Ist-Soll vergleich, das Servo lässt du schön langsam laufen, damit ist die Schwingneigung schon sehr gering.
Platzprobleme kannst du eigentlich nur mit den Eingabe- und Anzeigemodulen bekommen.
Hubert

Mr Bean
15.05.2007, 17:17
Hallo

Ja das kann ich mir natürlich ausrechnen. Aber wie würde denn dann solch eine Regelung aussehen? Ist das eine if...else abfrage oder wie? Könnt ihr mir da vielleicht ein rudimentäres Beispiel liefern? Ich versuch jetzt mal das Servo zum laufen zu bekommen. Was auch noch interessant wäre, wäre zu wissen wie ich nachher in Abhängigkeit zu dieser Regelung das Servo ansteuer.

Ein Problem kann auch noch sein daß der Druck der eingestellt werden soll vielleicht noch nicht vorhanden ist. dann soll das Servo natürilch ganz auf machen und Wenn der Druck ansteigt langsam schließen bzw. den eingestellten Wert beibehalten.

Vielen Dank trotzdem schonmal!

Grüße!!

Bean

wkrug
15.05.2007, 18:45
Ein Problem kann auch noch sein daß der Druck der eingestellt werden soll vielleicht noch nicht vorhanden ist. dann soll das Servo natürilch ganz auf machen und Wenn der Druck ansteigt langsam schließen bzw. den eingestellten Wert beibehalten.
Du willst also mit dem Servo ein Ventil ansteuern, das den Durchfluss der zuströmenden Luft ändert.
Vieleicht geht sowas ja mit einer vorberechneten inkrement / dekrement Tabelle ?
Je größer die Abweichung vom Sollwert zum Istwert um so größer sind die Bewegung des Servos in die eine oder andere Richtung.
Die Regelabweichungen (z.B. bei Schwingungsneigung) lassen sich einfach durch Ändern der Tabellenwerte einstellen, ohne das Programm neu schreiben zu müssen.

Bei der Mischeransteuerung für Zentralheizungen wird das so ähnlich gemacht und die reagiert äusserst träge auf die Sollwerte.
Zu der aktuellen Sevostellung werden also Werte inkrementiert oder dekrementiert, je nach Abweichung vom Sollwert sind die inkremente (dekremente) größer oder kleiner.

Durch die A/D Wandlung und die anschließende Verrechnung der Werte geht natürlich etwas Zeit verloren, was wieder zu Regelschwingungen führen kann. Ausserdem gibt es Modellbauservos mit unterschiedlichen Stellgeschwindigkeiten.
Prinzipbedingt werden auch die Servoimpulse nur alle 20ms neu übertragen. Es gibt aber auch Heckrotorservos für Modellhubschrauber, die schnellere Übertragungszyklen zulassen(Braucht man manchmal wegen Kreiselsteuerung).

Wenn Dir der Speicherplatz im ATMEGA 8 ausgeht (glaub ich aber nicht) kannst du den C-Quellcode immer noch für einen ATMEGA 16 oder 32 umcoden.

Ich muss ehrlicherweise zugeben, das ich kein Regelungstechniker bin und an so ein Projekt eher Experimentell herangehen würde (Mal ne Software schreiben und schauen ob's klappt).

Hubert.G
15.05.2007, 22:51
Ich würde wie "wkrug" auch experimentell an die Sache herangehen.
if (druck_a > druck_b)
timer_servo++;
if (druck_a< druck_b)
timer_servo--;
So etwa würde ich mal starten, hysterese noch etwas vergrößern und Servogeschwindigkeit erhöhen wäre dann das nächste.

Hubert

Vitis
15.05.2007, 23:10
@Hubert.G:
naja, n schneller Algorithmus und n schneller Servo, das gibt n Gezucke.


@Mr Bean:
mach dich mal schlau über Ringpuffer, lineare regression und Regelkreise,
das hat mir viel geholfen.

Mr Bean
16.05.2007, 00:39
Oh man im Moment scheiter ich schon an der Initialisierung des PWM Timers um das Servo anzusteuern.
Ich hab ja wie gesagt einen AtMega8. Ich wollte da den 8Bit PWM Timer verwenden. Dazu muss ich doch WGM20 auf 1 und WGM21 auf 0 setzen oder sehe ich das falsch? Außerdem bin ich mir nicht sicher was ich bei COM20&21 einstellen muss. Ich hab mir jetzt mal 0&1 überlegt. Dann wäre die Frage an Welchem Pin das Signal dann anliegt. Ist das dann schon OC2? Also PortB3? DDRB für Pin3 müsste ich dann ja auch auf Ausgang stellen oder?
Dann hab ich noch Probleme beim berechnen des PrescaleWerts. Ich brauche doch 5 Impulse pro Sekunde. Mit diesem Wert bekomme ich aber kein brauchbaren PrescaleWert. Ich weiß Fragen über Fragen... aber ihr könnt mir da bestimmt weiter helfen. Vielleicht ist es auch einfach schon zu spät...

Ich schlaf ersmal ne Nacht drüber...

Grüße!!

Bean

Mr Bean
16.05.2007, 02:48
OK, habe jetzt schon einen Fehler gefunden. Ist bei 20ms natürlich eine Frequenz von 20Hz. Das ergibt mit denn einen Reloadewert von 178 und ein Prescaler von 1024 wenn ich mich so spät nicht mal wieder verrechnet hab... :-$ O:) . Tut sich aber trotzdem nicht wirklich was mit meinem Servo. Naja werde jetzt wirklich erstmal schlafen...

Grüße!!

Bean

Hubert.G
16.05.2007, 11:47
20msec sind zwar 50Hz, aber es war ja wohl schon spät.
@Vitis Wenn man keine Ahnung von der Regelung hat und man rasch ein Ergebnis braucht gleich mit Ringpuffer, lineare regression und Regelkreise zu beginnen halte ich für etwas gewagt, auch wenn es für professionelle Anwendung der richtige Weg sein mag.
Hubert

wkrug
16.05.2007, 19:01
Ich würd die Servoroutine mit Comparematch A und Comparematch B machen.
Comparematchinterrupt A schaltet nach 20 ms (10ms) einen Ausgang auf high = Pause zwischen 2 Impulsen. Im Comparematch A werden dann auch gleich die neuen Werte für die Pulsbreite (1...2ms) an das Comparematch B Register übergeben.
Die Werte für die Pulsbreite (Comparematch B) werden zum Inhalt des Comparematch A Registers dazuaddiert.

Comparematchinterrupt B schaltet 1....2ms später den Ausgang wieder auf low, setzt den Timer (TCNT 1) auf 0 und startet eine neue Werte Ermittlung (nur Flag setzen Werteermittlung erfolgt im Hauptprogramm).

Das Hauptprogramm hat somit 20ms (10ms) Zeit um die Werte für einen neuen Zyklus zu Berechnen das sind 80.000 Takte (~Befehle) bei 4MHz. Und da lässt sich schon was draus machen.

Der Vorteil der Methode ist, das allein durch Verändern des Comparematch A Wertes die Zykluszeit beliebig verändert werden kann.

Wenn Du einen 8MHz Quarz einsetzt und den Prescaler des Timers 1 auf /8 setzt kannst Du die Comparematchwerte direkt in µS in die entsprechenden Register eingeben - ist doch praktisch - oder?

Nur zur Info - ein Modellbauservo braucht positive Impulse von 1ms....2ms für minimal bis maximal Ausschlag. Die Pausezeit zwischen 2 Impulsen beträgt üblicherweise 20ms - aber das wusstest Du vermutlich schon.

Der A/D Wandler braucht auch ein wenig Zeit um eine Wandlung durchzuführen. Zweckmäßigerweise würde ich deshalb eine neue Wandlung im Comparematch A Interrupt starten.