Etiket arşivi: speed regulation

Motor Kontrolü için PID

PID kontrol veri tipi:

typedef struct
{
    unsigned int pv;                    // olculen deger (feedback)
    signed int ev;                      // hata
    signed int ev_pre;                  // bir onceki hata
    signed int ev_sum;                  // hata integrali
    signed long int P;                  // hesaplanan PID komponentleri
    signed long int I;
    signed long int D;
    signed long int out;                // hesaplanan cikis
    unsigned int controlcounter;
    unsigned overloaded: 1;             // loadlevel belirlenen esigi asti ise bu bayrak 1 olur.
    unsigned restart : 1;               // pid ara degerleri baslatilir, akümülatörler sifirlanir
    unsigned nocontrol: 1;              // MDC = speedref, no pid control.. kullanici sifirlamali
    unsigned controlphase: 2;           // siradaki speedcontrol cevriminde ne is yapilacak?
} PIDParType;

pv: Process Value
motor encoder’ından örneklenen dönüş hızı değerinin PID çıkış veri tipine göre ölçeklenmiş halidir.
ev: Error Value
Referans değeri ile geçerli değerin farkı. pv çıkış gücü değeri cinsinden ölçekli olduğu için sadece çıkarma işlemi yeterlidir: ev = speedref – pv.
ev_pre:
Previous Error Value, Bir önceki hesaplama çevriminde saklanan hata değeri (türev hesabında kullanılır).
ev_sum:
Sum of Error Values, Hata değerlerinin toplamı (integral hesabında kullanılır)
P,I,D:
Hesaplanan P,I,D bileşenleri
out:
Hesaplanan çıkış. Basitçe, P,I ve D bileşenlerinin toplamından oluşur ancak bu değer fiziksel çıkışın ötesinde olabilir.
controlcounter:
Her SpeedControl( ) çevriminde +1 ilerleyen serbest sayaç. Motor kontrol zamanlamaları sırasında kullanılabilir, PID çevrimiyle eşzamanlı zamanlama sağlar.
overloaded:
Aşırı yüklenme bayrağı. Sürücü thread’i içinde motor akımı izleme ile ya da PID çıkışı üzerinden tetikleniyor olabilir. Kontrol onu sadece set eder. Haricen sıfırlanmalıdır.
restart:
Kontrol biti: Bu bit 1 yapıldığında tüm PID ara değerleri sıfırlanır. İşlem yapılınca bit sıfırlanır.
nocontrol:
Kontrol biti: Bu bit 1 yapıldığında PID kontrol devre dışı olur. speedref = MDC
controlphase
PID scheduling control flag. SpeedControl( ) fonksiyonunun her çağrılmasında hangi PID işlem parçalarının yapılacağını belirler.

Kontrol Çevrimi

Motor Kontrolü için PID hesaplama blok şeması

Motor Kontrolü için PID hesaplama blok şeması

 
// motor hiz kontrolü yapmak için 10ms'de bir çagrilmali:
void SpeedControl(void)
{
    LongData w;

    PID.controlcounter++;

    if (PID.nocontrol)
    {
        MDC = speedref;
        position.i[0] = POS1CNTL;    // position update
        position.i[1] = POS1HLD;
        return;
    }

// controlphase scheduling'e gore pv guncellemeleri:
////////////////////////////////////////////////////////////////////////////////////
    switch (PID.controlphase)
    {
        case 0:
            position.i[0] = POS1CNTL;    // position update
            position.i[1] = POS1HLD;

            // hiz bilgisini guncelle (40ms'de bir)
            rpm  = VEL1CNT;        
            w.ul = abs(rpm);
            w.ul *= 5000;
            w.ul /= pm;
            PID.pv = w.ul;

            PID.ev = speedref - PID.pv;

            PID.controlphase = 1;
        break;


        case 1:
            // integral icin, errorvalue_sum'i güncelle:
            PID.ev_sum += PID.ev;
            // ev_sum limitleme (anti windup)
            if (PID.ev_sum > 3000) PID.ev_sum = 3000;
            else if (PID.ev_sum < -4000) PID.ev_sum = -4000;
            // I komponentini hesapla:
            PID.I = (signed long*)(KiN * PID.ev_sum);

            PID.controlphase = 2;
        break;


        case 2:
            // hiz bilgisini guncelle (40ms'de bir)
            rpm  = VEL1CNT;
            w.ul = abs(rpm);
            w.ul *= 5000;
            w.ul /= pm;
            PID.pv = w.ul;
            // hata degerini guncelle:
            PID.ev_pre = PID.ev;        // simdiki deger onceki deger olarak kaydedilir
            PID.ev = speedref - PID.pv;

            PID.controlphase = 3;
        break;


        case 3:
            // D komponentini hesapla:
            w.i[0] = PID.ev - PID.ev_pre;
            if (w.i[0] > 2000) w.i[0] = 2000;
            else if (w.i[0] < -2000) w.i[0] = -2000;

            PID.D = (signed long*)(KdN * w.i[0]);

            PID.controlphase = 0;
        break;
    }
//////////////////////////////////////////////////////////////////////////////////////////

    if (PID.restart)
    {
        PID.ev = speedref;
        PID.ev_pre = 0;
        PID.ev_sum = 0;
        PID.I = speedref / 3;
        PID.D = speedref / 3;
        PID.controlphase = 0;
        PID.restart = 0;
    }

//// P bileseninin hesabi: P = Kp * ev
///////////////////////////////////////////////////////////////////////////////
    PID.P = (signed long*) (KpN * PID.ev);
///////////////////////////////////////////////////////////////////////////////
    

//// cikisin birlestirilmesi:
//////////////////////////////////////////////////////////////////////////////
   PID.out = (signed long*)(PID.P + PID.I + PID.D);
   PID.out = PID.out / 10;
//////////////////////////////////////////////////////////////////////////////

//// output update: (with limiting)
//////////////////////////////////////////////////////////////////////////////
   if (PID.out < -1000)
   {
        MDC = 2000;
        MOTOR_BRK_L;
        return;
   }
    
   if (PID.out < 0)
   {
        MDC = 500;
        MOTOR_BRK_L;
        return;
   }

   if (PID.out > 5000)
   {
       MDC = 4900;
       SetDir();
       return;
   }

   MDC = PID.out;
   SetDir();
/////////////////////////////////////////////////////////////////////////////////

}