Arduino Nano Levitron - PID Problem

Hi!

Ich versuche einen Neodym-Magneten per Elektromagnet + Lichtschranke(Fotoresistor) zum Schweben zu bekommen.
Als Regelung soll ein PID-Regler zum Einsatz kommen. Allerdings bekomme ich die Regelung einfach nicht stabil, egal wie ich an KI,KP oder KD rumdrehe. Bei kleinem KP bewegt sich erst garnichts, wenn ich KP weiter hochdrehe dann fängt das System unsichtbar zu schwingen an (aber hörbar, wie ein hochfrequenter Lautsprecher), schließlich (noch größeres KP) beginnt der Magnet hin und her zu zappeln und zu springen.

Aktuell läuft die Regelschleife bei ca. 2000Hz.
Herumstellen an KP,KI,KD ändert wie erwartet nur die Amplitude, aber nichts an der Eigenfrequenz des Systems.

Im untersten Bild (Screenshot aus Excel, von d. Seriellen Ausgabe) sieht man schön den "Derivative Kick", der mit größerem D-Term nätürlich größer wird. Um den kümmer ich mich später, wenn das System erstmal stabil ist.

Also verhält sich das System eigentlich so, wie ich es nach Zig Stunden Regelungstehnik-Vorlesung erwarten würde- nur stabil ist es immer noch nicht. Ich steh auf dem Schlauch. Irgendwas mache ich grundfalsch!

int force = 0;
float KI = 0;
int receivedValue = 0;

//Wie oft wurde die Regelschleife durchlaufen?
int Durchlaufzaehler = 0;
int t_Brennstart = 0;
int t_Brenndauer = 0;
int LEDistAN = 0;

int Regelgroesse;
int Fuehrungsgroesse;
int Regelabweichung;
int vorigeRegelabweichung;
int Integral;
int Stellgroesse;
int PTerm;
int ITerm;
int DTerm;

void setup()
{
  // initialize the serial communication:
  Serial.begin(115200);
  // initialize the ledPin as an output:
  pinMode(A3, OUTPUT);
  
  // enable pullup
  pinMode(A6, INPUT);
  digitalWrite(A6, HIGH);
}

void loop() {
  byte brightness;
   
       int sensorValue = analogRead(A6);
       Regelgroesse = sensorValue;
       Fuehrungsgroesse = 650;
       Regelabweichung = Regelgroesse - Fuehrungsgroesse;
       
       //PID-Regler
       //P-Anteil
       PTerm = 0.6*(Regelabweichung);
       if (PTerm <0)   { PTerm=0;   };
       if (PTerm >255) { PTerm=255; };
       //I-Anteil
       ITerm = 0.001*(Integral);
       if (ITerm <0)   { ITerm=0;   };
       if (ITerm >255) { ITerm=255; };
       //D-Anteil
       DTerm =  2.5*(Regelabweichung - vorigeRegelabweichung); 
       if (DTerm <0)   { DTerm=0;   };
       if (DTerm >255) { DTerm=255; };
       
       Stellgroesse = PTerm + ITerm; //DTerm; // ;
       
       vorigeRegelabweichung = Regelabweichung;
       Integral = Integral + 0.01*Regelabweichung;
       
        //Serial.println(Stelle);
        
        //Serial.println(sensorValue);
        Serial.println(Stellgroesse);
        //Serial.write(Stelle);
        
        //magnet unten (laser unverdeckt)   870
        // soll: 600
        //magnet oben (Laser verdeckt)      380
        
        
        //Stellgroeßenbegrenzung
        if (Stellgroesse <0)   { Stellgroesse=0;   };
        if (Stellgroesse >255) { Stellgroesse=255; };
        
        // analogWrite(A3, 255);
        analogWrite(A3, Stellgroesse);
        
        //einmal alle 100 Schleifendurchgänge LED blinken lassen
          blinkeLED();  //dient der Abschätzung der Regelfrequenz 
       //delay(20);   
}

void serialEvent()
{
  int SerialCom3IncomingNumber  = Serial.parseInt();  
  receivedValue = SerialCom3IncomingNumber;
}


void blinkeLED()
{
      Durchlaufzaehler = Durchlaufzaehler + 1;
    if (Durchlaufzaehler > 1000)
    {     
        if (LEDistAN == 0)
        {
          digitalWrite(13, HIGH) ; 
          t_Brennstart = micros();
          LEDistAN = 1;
        }                                    
        else 
        {
          t_Brenndauer = micros() - t_Brennstart;
          if (t_Brenndauer < 10000)
          {
          }
          else
          {
            digitalWrite(13, LOW);
            Durchlaufzaehler = 0;
            LEDistAN = 0;
          }        
        }
    }
}

http://s14.directupload.net/file/d/3105/zz7lrppa_jpg.htm
http://s7.directupload.net/file/d/3105/lkae8hf3_jpg.htm

Ich sehe 3 prinzipielle Denkfehler in Deinem Projekt:

  1. Ein LDR ist zu langsam um auf solch schnelle Ändrungen zu reagieren. Du brauchst eine Fototransistor.
  2. Du mußt den Fotoempfänger vom Umgebungslicht abschirmen
  3. Hast Du eine Luftspule oder eine mit Eisenkern? Beides geht nicht. Ein Elektromagnet als Luftspule hat darum wenig Kraft. An einen Eisenkern würde der Magnet sofort "ankleben"

und einen 4. Fehler: A6 und A7 sind nur Analoge Eingänge; sie können nicht als digitale Ein/Ausgänge verwendet werden und haben darum auch keine Pullupwiderstand. Den internen Pullupwiderstand als Widerstand für den Spannungsteiler mit dem LDR zu verwenden ist eine schlechte Idee da der interne Pullupwiderstand recht ungenau ist (20k bis 50kOhm).
A3 ist kein PWM Ausgang.

Du kannst keine INT variablen mit kommawerten multiplizieren; da werden immer die Kommastellen abgeschnitten, Du mußt float-Variablen benutzen was aber den Sketch erheblich verlangsamt.

Grüße Uwe