- 12V Akku mit 280 Ah bauen         
Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 13

Thema: PID - Parameter on the fly ändern

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    10.03.2005
    Alter
    35
    Beiträge
    967

    PID - Parameter on the fly ändern

    Hallo zusammen,

    ich habe für eine Hydraulik ein digitalen PID Regler gebaut. Differenzsignal geht auf einen AD, dann in den µC und am Ende wird die Stellgröße mit einem DAC ausgespuckt. Soweit so gut. Im Prinzip läuft das Ding auch recht gut.

    Abtastfrequenz beträgt 10kHz. Mein Code sieht so aus (ein paar Dinge rausgemacht, die damit nichts zu tun haben):


    Code:
    #include <avr/io.h>
    #include <avr/interrupt.h>
    //#include <avr/eeprom.h>
    
    #include <pid.h>
    #include <adc.h>
    #include <dac.h>
    
    double Kp = 0;
    double Ki = 0;
    double Kd = 0;
    double y = 0;
    double e = 0;
    double e_alt = 0;
    double e_sum = 0;
    
    #define Ta 0.0001
    
    //unsigned char Kp_eeprom EEMEM;
    //unsigned char Ki_eeprom EEMEM;
    //unsigned char Kd_eeprom EEMEM;
    
    void init_pid(void)
    {
    	// die gespeicherten Parameter laden und Regler initialisieren
    	//Kp = (double) eeprom_read_byte(&Kp_eeprom);
    	//Ki = (double) eeprom_read_byte(&Ki_eeprom);
    	//Kd = (double) eeprom_read_byte(&Kd_eeprom);
    	// PID Timer
    	TCCR0 |= (1 << WGM01) | (1 << CS01) | (1 << CS00);
    	//OCR0 = 250 ergibt 1kHz
    	OCR0 = 25; // ergibt 10kHz
    }
    
    void pid_set_parameters(unsigned char p, unsigned char i, unsigned char d)
    {
    	// Den aktuellen Variablen die neuen Parameter zuweisen
    	Kp = (double) p;
    	Ki = (double) i;
    	Kd = (double) d;
    	// Die neuen Parameter nicht-flüchtig ablegen, damit sie beim nächsten mal geladen werden können
    	//eeprom_write_byte(&Kp_eeprom, (unsigned char) Kp);
    	//eeprom_write_byte(&Ki_eeprom, (unsigned char) Ki);
    	//eeprom_write_byte(&Kd_eeprom, (unsigned char) Kd);
    }
    
    void pid_start(void)
    {
    	// Regler starten
    	TIMSK |= (1 << OCIE0);
    }
    
    void pid_stop(void)
    {
    	// Regler stoppen
    	TIMSK &= ~(1 << OCIE0);
    }
    
    void pid_calculate(void)
    {
    	// e = w-x ; Differenz soll-ist
    	e = (double) adc_read();
    	// ADC Wert transformieren
    	if (e >= 2048)
    	{
    		e -= 4096; 
    	}
    	// WindUp vermeiden
    	if (y < 4095)
    	{
    		e_sum += e;
    	}
    	// PID Stellgrößen Berechnung
    	y = -Kp*0.1*e;
    	y -= Ki*e_sum;
    	y -= Kd*(e-e_alt);
    
    	e_alt = e;
    	// Stellgröße beschränken
    	if (y > 2047){y = 2047;}
    	if (y < -2048){y = -2048;}
    	// Stellgröße für den DAC transformieren
    	y += 2048;
    	// Stellgröße für das Ventil ausgeben
    	dac_write((unsigned short)y);
    }
    
    ISR(TIMER0_COMP_vect)
    {
    	// mit 10kHz Abtastrate PID Algorithmus aufrufen, also alle 100µs
    	pid_calculate();
    }
    So, nun zu dem Problem:

    Ich möchte während der Regler seinen Dienst tut die Regelparameter on the fly ändern.
    Angesprochen wird der Regler über Rx/Tx und der Fleury Lib für UART, interruptgesteuerter Empfang.

    Wenn der Regler noch nicht gestartet wurde, kann ich wunderbar die Parameter ändern. Starte ich diesen jedoch einmal, kann ich ihn weder anhalten noch Parameter ändern.

    Sprich er reagiert über UART nicht mehr.



    Wo liegt hier das Problem? Ist die Abtastfrequenz zu hoch und die UART Interrupts kommen nicht "durch", weil ständig der Timer Interrupt zuschläge oder was ist hier los?

    Abtastfrequenz muss bei 10kHz bleiben, da ich die Hydraulik sonst nicht stabil bekomme.



    Viele Grüße,
    hacker
    Ich würde ja gern die Welt verändern..., doch Gott gibt mir den Quellcode nicht!

  2. #2
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    04.04.2005
    Ort
    Hamburg
    Alter
    36
    Beiträge
    826
    Ich muss zugeben, dass ich nicht der Fachmann bin, aber zur Problemlösung ist sicherlich noch dein CPU-Takt interessant!
    www.subms.de
    Aktuell: Flaschcraft Funkboard - Informationssammlung

  3. #3
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    06.02.2005
    Ort
    Hamburg
    Alter
    38
    Beiträge
    4.255
    Für so zeitkritische Sachen würde ich auf nem AVR nicht mit floats arbeiten, sondern auf Festkommaarithmetik umstellen. Wenn es an der Rechenleistung liegt, dann dürfte das schon helfen.

  4. #4
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.05.2006
    Beiträge
    184
    Hi,

    also ganz wichtig wäre erst mal:
    Controller ?
    Taktrate ?

    Wie schnell und wie oft wird der ADC Wert bestimmt?
    Wird der ADC Wert gefiltert?
    bzw. Was passiert in adc_read() ?

    Wird der Algorithmus wirklich in double gerechnet oder macht der Compiler daraus in wirklichkeit ne Fload? (Bin ich mir nicht sicher?)
    Eine Festkommarechnung ist hier aber sicher vorzuziehen.

    Was benutzt du für einen DAC? (allgemeine Frage)


    gruß ch

  5. #5
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    09.04.2008
    Beiträge
    384
    Was steht eigentlich in "Main" ? Scheinbar lauft nur noch der Timer Interrupt, und wird auch nur "PID calculate" ausgefuhrt.

  6. #6
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    10.03.2005
    Alter
    35
    Beiträge
    967
    Ok, Festkommaarithmetik werde ich mal versuchen.

    Controller ist Mega32 und läuft mit 16MHz. Der ADC wird einmal in der PID Berechnungs-Funktion geholt, also alle 100µs. Die reine Wandlung des externen ADCs beträgt ca. 1,5µs + die paar Befehle zum Daten abrufen (die Daten kommen parallel).
    Nein, der ADC - Wert wird nicht gefiltert. In adc_read() passiert also nichts zeitaufwendiges. Es wird rein der ADC ausgelesen, mehr nicht.

    Als DAC benutzte ich einen AD767.

    In der Endlosschleife Main läuft rein gar nichts.

    Kann ich mittels AVR Studio irgendwie rausbekommen, wie lange die PID Berechnung dauert?


    Was passiert eigentlich, wenn eine ISR momentan ausgeführt wird und während dessen trifft ein neuer Interrupt ein? Verpufft dieser, oder wird der gemerkt, bis die akutelle ISR vorbei ist?



    /*schluck*

    Laut Simulator soll die Berechnung 350µs dauern...kommt mir arg lang vor.

    /*holla*

    Mit Shorts brauchts nur ganze 7,6µs!
    Ich würde ja gern die Welt verändern..., doch Gott gibt mir den Quellcode nicht!

  7. #7
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    06.02.2005
    Ort
    Hamburg
    Alter
    38
    Beiträge
    4.255
    Ich hab grad keine Zahlen für den AVR, aber bei einem XC161 (16bit, 40MHz) braucht eine Float-Multiplikation etwa 6,4µs. Ganz grob geschätzt würde ich beim AVR mit dem fünffachen rechnen.
    Du machst fünf Multiplikationen, macht also etwa 160µs. Daher dürfte der AVR die ganze Zeit im Timer-Interrupt hängen.

    Wenn der Timer-Int aktiv ist und der serielle Interrupt tritt ein, wird dieser erst mal gespeichert. Wenn der Timer nun fertig ist, führt der AVR einen Befehl aus main aus. Dann bearbeitet er den nächsten anstehenden Interrupt. Inzwischen ist aber auch der Timer_interrupt nochmal aufgetreten, und wurde ebenfalls gespeichert. Nun wird nach der Priorität entschieden, wer zuerst drankommt. Und das ist der Timer...

  8. #8
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    09.04.2008
    Beiträge
    384
    Ich siehe keinen Grund warum etwas anderes als die function "PID_calculate" ausgefuhrt werden soll. Da stehts nicht in main, und nur diese ISR(TIMER0_COMP_vect) ist programmiert. Du muss auch einen function für diese serielle comm. programmieren.

  9. #9
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    Wenn die Ausführungszeit der Timer ISR länger ist als der Abstand der ISRs, dann kommt eine ISR von der USRT nie zur ausführung, denn die Timer interrupts haben die größere Priorität.
    Da hilft also nichts als die ISR zu beschleunigen, indem man von den Floats weg kommt.

    Die oben genannten 350 µs sind für Floats nicht besonders lang.

  10. #10
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Man könnte ja auch einfach sagen "ich will die Regelfunktion mit maximaler Frequenz ausgeführt haben", und einfach die Funktion in die (im Moment leere) Main-Schleife packen (und auf den Timer-Interrupt verzichten). Dann hast du auch keine Probleme mehr mit Interrupt gesteuertem UART-Empfang nebenher.
    MfG
    Stefan

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

LiFePO4 Speicher Test