www.mikrocontroller.net

Forum: Compiler & IDEs PID läuft in falsche Richtung


Autor: Mark Pisani (pisy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,
folgendes Problem, die Variable die in den OCR1A geschrieben wird, zählt 
fortlaufend hoch und läuft in die Begrenzung rein.
Ich erläutere jetzt die Hardware und die Software.

Ich habe ein Netzteil mit dessen V+ ein Widerstandsdraht verbunden ist, 
dieser hat ca 1 Ohm. An dem Widerstand ist dann ein Spannungsteiler 
angeschlossen, an diesem Spannungsteiler ist parallel eine Lastsenke. 
Ende des Teilers und der Senke sind mit der Masse des Netzgeräts 
verbunden. Auch die Massen der Controller liegen alle auf dem gleichen 0 
Potential.
Ich will über den Spannungsteiler, der 24 in Reihe liegende Widerstände 
hat, die Spannung messen und diese einlesen, manch einer hat mir ja 
schon hierbei geholfen.
Die Erfassung läuft einwandfrei und die Spannungswerte werden in einem 
Array gesammelt.
Alle 24 Schleifendurchläufe wenn alle Spannungen gesammelt sind, soll 
geregelt werden.
Dazu werden alle Spannungen im Array mit einem Sollwert verglichen und 
die niedrigste Spannung wird dann als Istwert verwendet.
Liegen alle Spannung größer gleich dem Sollwert soll nichts getan 
werden.
Mein Problem ist, dass der Wert "Senke" den ich in den OCR1A schreibe 
fortlaufend hochgezählt wird und somit der Strom steigt. Wenn der Strom 
aber steigt, dann steigt auch der Spannungsabfall an dem 1 Ohm 
Widerstand und die Spannung am Spannungsteiler wird noch geringer.
Jedoch soll das ganze umgekehrt laufen. Wenn Die Spannung fällt, soll 
Strom reduziert werden.
Die Regelung lief einwandfrei als ich den Strom als Istwert genommen 
habe, bzw über den Strom alles geregelt habe.

Der Regler ist von einem niederländischen Kollegen.
Gemeten=Istwert
Gewenst=Sollwert


volatile int8_t gewenst=0; //Sollwert
volatile int8_t gemeten=0; //Istwert
volatile uint16_t senke=0; //Wert für OCR1C
volatile int16_t i_hold_value=0; //Variable für Spannungsvergleich


int PID(void)
{
  static int _first=1;
  static int sec=0;
  static double Ts,Kc,Ti,Td;
  static double gemeten_1=0;
  static double K_LPF,c1,c2,lpf=1,lpf_1=1,lpf_2=1;
  static double ek,ek1;
  static uint16_t output;
  static double P,I,D;
  Kc=0.5;
  Ti=1;
  Td=1;
  Ts=1;
  

  K_LPF = (double)Td * 0.1;  
  c1 = (1.0*K_LPF-(double)Ts)/(1.0*K_LPF+(double)Ts); 
  c2 = (double)Ts / (1.0*K_LPF + (double)Ts); 
  lpf = c1 * lpf_1 + c2 * (gemeten+gemeten_1);

  ek=gewenst-gemeten;  //error berekenen

  P=-Kc * (gemeten-gemeten_1);//  vor Kc
  I=Kc * ((double) Ts/(double)Ti * ek);
  D=((-Kc * (double)Td/(double)Ts) * (lpf-2*lpf_1+lpf_2));
  output=output+P+I+D;

  ek1=ek;
  gemeten_1=gemeten;
  lpf_2 = lpf_1;
  lpf_1 = lpf;
  

  return output;
}


//---------------------------------------------------------------------------
// Main-Funktion
//---------------------------------------------------------------------------

main ()
{

  init();

  //----------------------------------------------------------------------    

  // Timer 1 initialisieren
  TCCR1A=(1<<WGM11)|(1<<WGM10)|(1<<COM1A1);
  TCCR1B=(1<<DDB1);
  //----------------------------------------------------------------------  

  // Variablen deklarieren
  uint16_t result=0;
  char c_buffer[20];
  char c_zeichen;
  int16_t i_temp;      //Sollwert Strom oder anzahl_zellen
  int i_anzahl_zellen;
  uint16_t i_zellspannungen[23];
  int i_volt_setpoint=0;
  int i_low_volt=0;  
  int counter;
  float f_help=0;
  char standby=0;
  //----------------------------------------------------------------------  

  uint8_t i_index=0;
  int count=0;
  int checksum=0;

  count=1;
  PORTC&=~(1<<DDC5);
  while (true) // Mainloop

  {
    
    init_timer_2 ();    //aktivieren des Timers 
    i_abbruch=1;      //Setzt Abbruchkriterium
    standby=0; //Um Senke abzuschalten

    
    i_zellspannungen[count]=einlesen(0);  //Sammeln der Spannungen

    

    if (count==24)  //Regle erst nachdem alle Zellen abgetastet sind
    {

    gewenst=10;  //Sollwert
    i_hold_value=gewenst;

    for (i_index=1;i_index<25;i_index++)
      {
        //Beginn der 25 For Schleife

        if(i_zellspannungen[i_index]<i_hold_value) //mit i_hold_value als SOLLWERT
        {

          i_hold_value=i_zellspannungen[i_index];//suche geringste Zellspannung und benutze die als Istwert

        }

      }
      //Ende der 25er For Schleife

      //Regelkriterium

      if (gewenst>i_hold_value) //ist Sollwert größer als Istwert dann regel
      {

        gemeten=i_hold_value;//Istwert=Wert der niedrigsten Zelle
        senke=PID(); //Speicher PWM Compare in Zwischenvariable

        //Schränke PWM ein
        if (senke>1023)
        {
          senke=1023;
        }
      else if (senke<0)
        {
          senke=1; //hier kommt später ein Highpegel hin, der über einen Thyristor die Senke in standby schaltet
        }
      else
        {
          ;
        }

        OCR1A=senke;

      }

    else //andersfalls mache gar nichts

      ;

    }

    do              //wartet so lange bis Timer übergelaufen
    {              //springt in Timer 2 
    }while(i_abbruch!=0);      

    count++;

  }
  //end mainloop
}


Entweder ich muss ein Vorzeichen im PID ändern, ich weiss aber nicht 
welches, ich habe die allgemeine Konstante K_C schon negiert und die 
Differenz zwischen Sollt und Ist umgekehrt, aber es läuft immer wieder 
hoch.
Vielleicht kann mir einer helfen bzw mit Fehlersuchen.

Danke im Voraus

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also die Richtung der Regelung könntest du einfach ändern mit:
   return -output;
anstatt:
   return output;
am Ende von PID().
Andere mögliche Stellen gibt es natürlich auch...

Autor: Mark Pisani (pisy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn ich da ein minus Vorsetze, dreht dann erhalte ich ja einen 
negativen Wert. versteht das ORC1A negative Werte?
Und wenn ja, negiert er dann die Spannung? Habe jetzt kein Board zum 
ausprobieren hier, aber mich würde es wundern wenn es so einfach wäre, 
weil die Lastsenke ja dann auch ein negatives PWM erhält und PWM ist ja 
nichts anderes als ein digitaler Code.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mark Pisani schrieb:
> Wenn ich da ein minus Vorsetze, dreht dann erhalte ich ja einen
> negativen Wert. versteht das ORC1A negative Werte?

Da OCR1A unsigned ist: Nein
Aber diese Negierung kommt praktisch aufs gleiche raus, als wie wenn du 
sagen würdest

   return MAXIMAL_WERT - output;

> Und wenn ja, negiert er dann die Spannung?

Nein

Autor: brrrrrrrrrrrrrhhhhmmmmmmmmmm (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie wäre es von 100% deinen Stellwert abzuziehen ???
Invertiern ???

Autor: Mark Pisani (pisy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit den 100% das habe ich versucht, ich habe gesagt 1023-output, er hat 
trotzdem hochgerechnt. Ganz so dämlich bin ich auch nicht;)

Autor: B e r n d W. (smiley46)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ek = gemeten-gewenst;  //error berekenen

MfG, Bernd

Autor: Mark Pisani (pisy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Bernd, danke aber das war auch mein erster Ansatz, leider hat das 
nicht funktioniert.

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe Deine Anwendung zwar nicht wirklich verstanden, aber meiner 
Meinung nach machst Du zwei entscheidende Fehler:

1.) Eine Regelung macht nur dann Sinn, wenn immer geregelt wird,
    nicht nur wenn Dein Ist-Wert < Soll-Wert ist

2.) Du aktualisierst die PWM nur wenn Du auch regelst,
    also Ist < Soll. Dann muss der Ist-Wert ja auch größer werden.
    Sobald aber Ist > Soll aktualisierst Du die PWM nicht mehr,
    wie soll Ist dann jemals wieder kleiner werden?

Autor: Mark Pisani (pisy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja ich verstehe,
das habe ich mich auch gefragt. Mein Arbeitskollege meinte, die Senke 
soll keinen Strom mehr ziehen, wenn Ist=Soll ist oder Ist>Soll.
Mein Problem ist, ich weiss nicht welchen Wert ich dann übergeben soll 
als PWM.
Oder ich mache eine Schleife, das er in jedem Fall regelt und sonst den 
letzten PWM Wert wieder übergibt, dieser ist ja relativ nah an dem 
Sollwert wenn dieser wieder erreicht wird.

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da ist jetzt nicht böse gemeint, aber ich habe den Eindruck, Du fummelst 
an einem bestehenden Programm herum, von dem Du keinen blassen Dunst 
hast.
Das ist immer gefährlich, wenn man nicht weiß, was man tut oder tun 
soll.

Das tolle an einer Regelung ist ja, dass man sich eigentlich überhaupt 
keine Gedanken mehr darüber machen muss, welchen PWM-Wert man übergeben 
soll, denn das "Denken" übernimmt ja gerade der Regler... vorausgesetzt, 
man hat die Regelparameter "vernünftig" eingestellt.

Sich drumherum winden und Schleifen programmieren, falls nicht ... oder 
vielleicht doch... oder was denn nun...?!

Mach Dich mit der Regelungstechnik vertraut und dem zu regelnden System 
vertraut und programmier den Regler neu, so dass Du ihn auch 
verstehst... sonst wird das nix... mein guter Rat zur Nacht ;-)

Autor: kurz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zustimmung!

Autor: B e r n d W. (smiley46)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bedingung ist, dass ein Ausregeln überhaupt möglich ist.

Gruss, Bernd

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.