PID Salınım

Başlatan aRci, 23 Ocak 2022, 23:18:23

aRci

Merhaba;
Bir süredir zaman ayırıp üzerinde çalışama yapamadığım PID konusunda fikir almak istiyorum. Yaptığım projede pwm duty değeri sürekli bir salınım içerisinde bunu durduracak bir yöntem aramaktayım.

örnek çalışma için bir kutu içerisindeki sıcaklık değerini set edilen değerde tutmak üzerinedir. Kutu içerisindeki havya (: kutu sıcaklığını artırırken fan ile ise bu sıcaklık değeri düşürülmeye çalışıyor. pwm ile fanın devrini ayarlıyoruz. Sıcaklık değeri içinde Ds18B20 kullanılıyor.

Resimdeki çizgilerin anlamları ise
Mavi= Set edilen değer
Kırmızı= Okunan sıcaklık değeri
Yeşil= Hesaplanan duty değeri
turuncu= Cıkışa uygulanan duty değeri
Mor= Kazanc toplamı

Paylaştığım kodla +- 0.2 farkla set edilen değerde ısı tutuluyor ama uygun test koşulları ama yazılımsal bir sebeple salınım oluyor. motor aralıklarla devreye girip çıkıyor. Motorun olabildiğince sabit bir devirle hızını kontrol etmek istiyorum.
asm
 __CONFIG    _CONFIG1H, _FOSC_INTIO7_1H & _FCMEN_ON_1H & _IESO_ON_1H
 __CONFIG    _CONFIG2L, _PWRT_OFF_2L & _BOREN_OFF_2L 
 __CONFIG    _CONFIG2H, _WDTEN_OFF_2H 
 __CONFIG    _CONFIG3H, _MCLRE_ON_3H & _HFOFST_ON_3H & _LPT1OSC_OFF_3H & _PBADEN_OFF_3H & _CCP2MX_PORTC_3H 
 __CONFIG    _CONFIG4L, _STVREN_OFF_4L & _LVP_OFF_4L & _XINST_OFF_4L & _DEBUG_OFF_4L 
 __CONFIG    _CONFIG5L, _CP0_ON_5L & _CP1_ON_5L & _CP2_ON_5L & _CP3_ON_5L
 __CONFIG    _CONFIG5H, _CPB_ON_5H & _CPD_ON_5H 
 __CONFIG    _CONFIG6L, _WRT0_ON_6L & _WRT1_ON_6L & _WRT2_ON_6L & _WRT3_ON_6L
 __CONFIG    _CONFIG6H, _WRTB_ON_6H & _WRTC_ON_6H & _WRTD_ON_6H  
 __CONFIG    _CONFIG7L, _EBTR0_ON_7L & _EBTR1_ON_7L & _EBTR2_ON_7L & _EBTR3_ON_7L 
 __CONFIG    _CONFIG7H, _EBTRB_ON_7H
endasm

    'OSCCON =%01110000 
    'OSCTUNE=%01000000
    define OSC 64
    
    OSCCON = %01110000      '8 mhz internal clock, PLL on
    OSCTUNE= %01000000
    
    ADCON0           = 0        'AN0 Seçildi
    Symbol GODONE    = ADCON0.1  'Dönüştürme Durum Biti Devam ediyor = 1
    Symbol ADONE     = ADCON0.0  'Dönüştürme Modülü Etkin = 1
    ADCON1           = %00001001
    ADCON2           = %10111001
    
    DEFINE CCP2_REG PORTC 'Hpwm 2 pin port
    DEFINE CCP2_BIT 1 'Hpwm 2 pin bit
    
    INTCON=%11000000
    PIE1= %00100000
    PIR1= %00000000
    IPR1= %00100000
    RCSTA= %10010000
    TXSTA= %00100100
    SSPSTAT =%11000111
    SSPCON1 =%00100010  
    
    SYMBOL GIE          = INTCON.7   'genel interruptları açıyor
    SYMBOL PEIE         = INTCON.6   'peripheralinterruptları açıyor
    SYMBOL RCIE         = PIE1.5     'USART Recive interrupt enable bit
    SYMBOL RCIF         = PIR1.5     'USART Receive interrupt flag bit
    SYmbol RB0          = INTCON.1   'Portb.0 Kesme Biti
    Symbol TMRF         = INTCON.2   'timer kesme bayraği
    
    Symbol TMR0ON    = T0CON.7    'TMR0 Etkinleştir = 1
    Symbol T08BIT    = T0CON.6    '8bit = 1 /16bit = 0 Zamanlayıcı Seç
    Symbol T0CS      = T0CON.5    'Saat Kaynağı T0CKI = 1 / CLKo = 0
    Symbol T0SE      = T0CON.4    'Kenar Seçme Yükselkten alta geçiş = 1
    Symbol PSA       = T0CON.3    'Ön yükleyici Ön ölçekleyiciyi atanmamış = 1  
    Symbol TOPS2     = T0CON.2    'bölme oranı
    Symbol TOPS1     = T0CON.1    'bölme oranı
    Symbol TOPS0     = T0CON.0    'bölme oranı
      
    T08BIT           = 0  '8bit = 1 /16bit = 0 Zamanlayıcı Seç
    T0CS             = 0  'Saat Kaynağı T0CKI = 1 / CLKo = 0
    T0SE             = 1  'Kenar Seçme Yükselkten alta geçiş = 1
    PSA              = 0  'Ön yükleyici Ön ölçekleyiciyi atanmamış = 1
    TOPS2= 1:TOPS1 = 1:TOPS0 = 1
    'TMR0E            = 1  'TMR0 Kesme Açık
    TMR0ON           = 0  'TMR0 Etkinleştir = 1
      
      RCIE=1
      PEIE=1
      GIE=1
      INTCON.5=1 ;TMR0 KESMESİ AKTİF = 1
      ON INTERRUPT GoTo KESME

Symbol SPEN      = RCSTA.7    'Seri Bağlantı Noktası Etkin = 1
Symbol CREN      = RCSTA.4    '
Symbol OERR      = RCSTA.1    '
Symbol FERR      = RCSTA.2    '


RCSTA = $90   ' Enable serial port & continuous receive
TXSTA = $24   ' Enable transmit, BRGH = 1
SPBRG = 130   ' 9600 Baud @ 64MHz, -0,02%
SPBRGH = 6
BAUDCON.3 = 1 ' Enable 16 bit baudrate generator

TRISA = %00000001
TRISB = %00000000
TRISC = %11000000
TRISD = %00000000
TRISE.0=0
TRISE.1=0
TRISE.2=0
TRISE.3=0


'ON INTERRUPT GOTO KESME

clear
pause 250
porta=0
portb=0
portc=%10000000
portd=0
porte=0
      '/////////////////////---------Ds18b20 değişkenler-------/////////////////////////
'/////////////////////---------------------------------/////////////////////////     
    ds1820           var  portb.0 'okuma bacağı
    mesgul           var  byte    'ısı okuma bittimi
    okunan           var  word    'ds1820 gonderdiği word degerindeki ısı bilgisi
    Derece           var  byte   'sıcaklık
    Isaret           var  byte    ' - / +
    Ondalik          var  byte    'ds1820 gonderdiği word degerindeki ısı bilgisi
    isaret_biti      var okunan.bit11
    sensor           var byte 'sensor = 255 se sensör yoktur
    DsDeg            var word
    
'/////////////////////---------------------------------///////////////////////// 
'/////////////////////---------------------------------/////////////////////////         
      Set       var word           'Hedeflenen değer
      PID       var word           'kazanc toplam cıkışı
      Fark_e    var word
      Hata_i    var byte
      Say       var byte
      Fark      var word
      Temp      var byte
      Ofset_PWM var byte           'kazanc değeri haricinde duty kalibre değeri
      P_W_M     var byte           'Elde edilen duty değeri
      Adim      Var byte           'duty değerinin değişimi sırasında basamak değeri
      
      Kp        var word           'Oransal işlem katsayı
      Kpe       var word           'Oransal işlem hata değeri
      PID_Kp    var word           'Oransal işlem hesaplanan kazanc
      Kp_i      var bit            'Oransal işlem kazanc değerinin polaritesi 
      KpMax     var byte           'Oransal işlem kazanc max değeri
      
      Ki        var word           'İngral işlem Katsayısı
      Kie       var word           'İngral işlem hata değeri
      PID_Ki    var word           'İngral işlem hesaplanan kazanç
      Ki_i      var bit            'İngral işlem kazanc polaritesi
      KiMax     var byte           'İngral işlem kazanç max değeri
      
      Kd        var word           'Türev işlem Katsayısı
      Kde       var word           'Türev işlem hata değeri
      PID_Kd    var word           'Türev işlem hesaplanan kazanc
      Kd_i      var bit            'Türev işlem kazanc polaritesi
      KdMax     var byte           'Türev işlem kazanc max değeri
      Onceki    var word           'Onceki okunan değer
      
      Gosub Ds18B20
      Gosub Ds18B20
      
      Set = okunan + 30            'Burada ornekte okunan sıcaklık değerine 50 ekleniyor.
      Kp  = 10'27
      Ki  = 8'28
      Kd  = 3
      
      KpMax = 75'140
      KiMax = 75'90
      KdMax = 10'25
      Ofset_PWM = 90
      hserout ["0 0",13,10]        'arduino ide serial çizici serout değer yazılıyor.
      P_W_M = 0 
      Adim = 0
basla:
    Kie = 32767                    'değişken değeri 32767 den küçükse değer eksi değerdir.                             
    for Say = 0 to 9               'sıcaklık ölçülerek ortalama sıcaklık bulunuyor.
        Gosub Ds18B20              'Sensörden sıcaklık değeri okunuyor.
        PID = 32767                'Sonuc hata değişkeni ofset değeri veriliyor.işlemler sona erince
'///////////////////////////////////////////////////////////////////////////////
        'Oransal değer için Okunan ile Set arasındaki fark alınıyor.
        if Set >= okunan then          'Kp hata değerinin pozitif yada negatif durumuna göre 
        PID_Kp = Kp * ( Set - okunan ) 'Aradaki fark Kp katsayısı ile çarpılıyor.
        Fark = Set - okunan            'program takip yardımı için 2 değer arasındaki farkı hesaplıyoruz.
        if PID_Kp > KpMax then PID_Kp = KpMax  'Elde edilen değer belirtilen miktarla sınırlıyoruz. (KpMax)
        Kp_i = 0                       'Kp_i değerin işaret biti sıfırsa pozitif 
        PID = PID - PID_Kp             'Sistem Sogutma yapılacağı için ters işleniyor
        else
        PID_Kp = Kp * ( okunan - Set )
        Fark = okunan - Set
        if PID_Kp > KpMax then PID_Kp = KpMax  'Elde edilen değer belirtilen miktarla sınırlıyoruz. (KpMax)
        Kp_i = 1                       'Kp_i değerin işaret biti sıfırsa negatif
        PID = PID + PID_Kp             'Sistem Sogutma yapılacağı için ters işleniyor
        endif
'///////////////////////////////////////////////////////////////////////////////
        'İntegral için ölçülen değer ile set değer arasındaki fark alınıyor.
        'alınan değerlerin pozitif ve negatif olacak şekilde takip ediliyor.
        if Set > Okunan then           'Ki hata bulunuyor
        Kie = Kie + (Set - Okunan)     'Set değeri ile anlık değer arasındaki fark
        else                           'toplanıyor eksi değer dikkate alarak.
        Kie = Kie - (Okunan - Set)     'Kat sayı döngü sonunda ortalama alındıktan sonra yapılacak.
        endif
        if Ki_i = 0 then               'Sistem Sogutma yapılacağı için ters işleniyor
           PID = PID - PID_Ki
        else                           'son olarak Ki değeri PID sonuç değişkenine aktarılıyor.
           PID = PID + PID_Ki
        endif
'///////////////////////////////////////////////////////////////////////////////
        'Türev hesap için 2 ölçüm arasındaki farkı alıyoruz. 
        'Tekrar iki değer arasındaki farkı almak için karşılaştırıyoruz.
        if okunan >= Onceki then
            Kd_i = 0
            Kde = okunan - Onceki 
        else
            Kd_i = 1
            Kde = Onceki - okunan
        endif
        Onceki = okunan                'son okun an değer onceki değişkene aktarılıyor.
        PID_Kd = Kd * (Kde + 1)        'Hata değerini kat sayı ile çarpıp türev değeri alıyoruz.
        if PID_Kd > KdMax then PID_Kd = KdMax   'Elde edilen değer belirtilen miktarla sınırlıyoruz. (KdMax)
        if Kd_i = 0 then               'Sistem Sogutma yapılacağı için ters işleniyor
           PID = PID - PID_Kd
        Else
            PID = PID + PID_Kd
        endif
'///////////////////////////////////////////////////////////////////////////////
        'Tüm kazanc değerleri toplanarak cıkış ( PID ) elde ediliyor.
        if PID >= 32767 then
            Fark_e = PID - 32767
            PID = PID - 32767 + Ofset_PWM
            if Fark_e > 230 then PID = 255
            Hata_i="+"
        else
            Fark_e = 32767 - PID
            PID = Ofset_PWM'32767 - PID
            if Fark_e > 150 then PID = 0 
            Hata_i = "-"
        endif
'///////////////////////////////////////////////////////////////////////////////
        'Pwm duty değeri değişimi daha eğimli olması için iki değer arası farkına göre duty değeri değişiyor.    
        if P_W_M != PID then
            Adim = Adim + 1
            if P_W_M > PID then
                if P_W_M < 3 then P_W_M = 0
                if P_W_M < (PID - 3 ) then 
                   P_W_M = PID
                else
                    P_W_M = P_W_M - 3
                endif
            endif
            
            if P_W_M < PID then
                if P_W_M > 252 then P_W_M = 255
                if P_W_M > (PID + 3 ) then 
                   P_W_M = PID
                else
                    P_W_M = P_W_M + 3
                endif
            endif
            if Adim > 10 then P_W_M = PID
        else
            Adim = 0 
        endif
        HPWM 1,P_W_M,10000             'hesaplana duty değeri uygulanıyor.
        pause 30
'///////////////////////////////////////////////////////////////////////////////
        'Arduino ide serial çizici için serout kodları        
        'hserout [dec Set," ",dec okunan,13,10]
        'hserout [dec PID_Kp," ",dec PID_Ki," ",dec PID_Kd,13,10]
        hserout [dec Set," ",dec okunan," ",dec PID," ",dec P_W_M," ",dec Fark_e,13,10]
    next Say
'///////////////////////////////////////////////////////////////////////////////
    'İntegral hesap için alınan fark toplamlarının ortalamasını alıyoruz.
    if Kie < 32767 then            'Ki hata değerinin negatif yada pozitif olduğuna bakılıyor.
    Ki_i = 1                       
    Kie = 32767 - Kie
    else
    Ki_i = 0
    Kie = Kie - 32767
    endif
    PID_Ki = Ki * ( Kie / 10 )     'Ki Hata değerinin ortalaması alınıp Ki çarpanı ile çarpılıyor.    
    if PID_Ki > KiMax then PID_Ki = KiMax    'Elde edilen değer belirtilen miktarla sınırlıyoruz. (KiMax)
'///////////////////////////////////////////////////////////////////////////////
goto basla

'değer takipi için kullanılacak serout kodları.
hserout ["Set:",dec5 Set," Oku:",dec5 Okunan," PID:",dec5 PID," Fark:"]
    if Kp_i = 1 then
    Temp = "+"
    else
    Temp = "-"
    endif
    hserout[ temp,dec5 Fark]
    if Kp_i = 1 then
    Temp = "+"
    else
    Temp = "-"
    endif
    Hserout [" Hata:",Hata_i,dec5 Fark_e]
    Hserout [" Kp:",temp,dec5 PID_Kp," Ki:"]
    if Ki_i = 1 then
    Temp = "+"
    else
    Temp = "-"
    endif
    hserout [Temp,dec5 PID_Ki," Kd:"]
    if Kd_i = 1 then
    Temp = "+"
    else
    Temp = "-"
    endif
    hserout[temp,dec5 PID_Kd,13]
'///////////////////////////////////////////////////////////////////////////////  
'///////////////////////////////////////////////////////////////////////////////
Ds18B20:
OWOUT DS1820,1,[$CC, $44]    'isi olçme emri
Dsbekle:
OWIN DS1820,0,[MESGUL]       'okuma bittimi ?
if mesgul=1 then goto DsBekle 
OWOUT DS1820,1,[$CC, $BE]    'bilgi okuma emri 
OWIN DS1820,0,[OKUNAN.LOWBYTE,OKUNAN.HIGHBYTE,skip 4,temp]  'ds1820 bilgi okunuyor

IF ISARET_BITI=1 THEN                           'okunan bilgi word tipinde bir bilgi 
            Isaret="-"  			'bu verinin 11. biti isaret bitidir ( + / - )
            Derece=(65535-OKUNAN+1)/16	'isaret biti 1 ise ( - ) , sıfır ise ( + )  
    ELSE    					'hesaplanan isaret bitine gore islem değişikliklerine uğrayarak bulunur	
            Isaret="+"
            Derece=OKUNAN/16
ENDIF

'yard1 = OKUNAN.LOWBYTE & %00001111
ondalik= OKUNAN.3 *50 + OKUNAN.2 *25 + OKUNAN.1 *12 + OKUNAN.0 *6 
'Okunan = (derece * 100) + ondalik'Hserout ["Ds: ",dec derece,".",dec Ondalik,"   ",dec okunan,"   ",dec sensor,13]
return
'///////////////////////////////////////////////////////////////////////////////   
'///////////////////////////////////////////////////////////////////////////////

DISABLE         
KESME:
INTCON.7 = 0
TEMP=RCREG
PIR1.5 = 0
INTCON.7=1
RESUME         
ENABLE









ete

#1
Güzel çalışma tebrik ederim. Sıcaklık kontrollerinde genellikle PID yerine PI kontrolün daha uygun olduğu söylenir. Bende bir çok uygulama yaptım ve bir iki PID denemesinden sonra yanlızca oransal kontrol ile baaşrılı sonuçlar almıştım Genelde uyguladığım mantık şöyle oluyor.
Isıtıcının gücüne bağlı olarak set sıcaklığından 20 derece veya 10 derece veya 5 derece öncesine kadar tam güçte sistemi ısıtıp o noktadan sonra oransal kontrrole başlarım. Yaklaşık 1 sn lik duruma görede 2 sn lik peryotları uygularım. Bu peryotta set sıcaklığına yaklaştıkça peryodun ısıtma süresini set-okunan arasındaki farka bağlı olarak azaltırım. Set sıcaklığına ulaştıktan sonra ısıtımayı kesmem. Çünki ne şekilde olursa olsun sistemin bir ısı kaybı vardır ve bunu kompanse etmek için az da olsa bir ısıtma payı vermeniz gerekiyor. Bu mantıkla pek çok proje yaptım hepsinde genellikle set sıcaklığında çakılıp kalan kontroller elde ettim.

Her neyse senin sistemindeki sapmaların sebebini bulmak çok zor. Hele bizim gibi programa tam olarak hakim değilsen bulmak iki katı zorlaşır. Bulmak için hem hesap yöntemini sorgulamak hemde alınan sonuçlarda parametre değerlendirmesi yapmak gerekir.
Programı da şöyle bir taradım bazı olumsuzluklar var. Mesela ;
USART kesmesini aktive etmişsin ama yanında ; INTCON.5=1 ;TMR0 KESMESİ AKTİF = 1 komut satırı ile timer0 kesmesinide aktive etmişsin. Hemde bu kesmeye ait hiç bir parametre vermeden bunu yapmışsın. hiç bir parametre vermesen bile tmr0 bir noktada kesme yaratacak ve kesme bayrağını aktive edecektir. Ancak kesme alt programın bu kesmeye ait bir bayrak sıfırlaması vs göremedim.
Bu durumda TMR0 kesme bayrağı aktive olduktan sonra program kesmeye gider orada bayrak sıfırlanmadığı için kesmeden çıkar çıkmaz yeniden kesmeye girmeye meyleder çünki bayrak onu bu işe zorlar. Buda programda bir yavaşlamaya sebep olacaktır yada en azından sıcaklığın doğru okunmamasına sebep olabilir. Nede olsa o sensörde sıcaklık okuması yaklaşık 750 ms sürmektedir.
Gözüme ilk çarpan olumsuzluk bu oldu. İncelemeye devam ediyorum. Başka bir şey bulursam yazarım.

Ete

aRci

Merhaba;
ilk olarak teşekkür ederim yorum ve tavsiyeniz için.

Projemde referans olarak formda pid konusundaki "inverter" adlı üyenin paylaşımını dikkate alarak anladığım kadarı ile yapmaya çalıştım.Verdiğiniz kontrol örneğini bende Ofset_PWm değişkeni ile yapmaya çalışmıştım. Aslında olan PID hesabı için alttaki kodu kullanıyordum ama bu durum oluşunca Ofset_PWm  dahil ettim.

PID = PID_Kp + PID_Ki + PID_Kd

PID kazançların toplamını tutan word değişkeni eğer kazançlar sıfır olursa PID dolayısı ile pwm duty değeri sıfır oluyordu bende sıfır noktasında fanın durmaması için Ofset_PWm ile sabit değer verdim deneme yanılma ile değer veriyorum. Ama bu değer bazen yüksek bazense düşük geliyordu ve sürekli değiştirmek zorunda kaldığım.

PID = PID_Kp + PID_Ki + PID_Kd + Ofset_PWm

Ofset_PWm nin dahil olması ile kazanç hesaplamalarından gelen sonuçlar ise bu değere göre 255 i geçmeyecek şekilde birbirleri ile orantılamak zorunda kalıyordum. Sonuç olarak oranlar değiştikce çarpanlar değişti ve tepki sürelerinde değişiklikler olduğu için çarpan değerelerinide değiştirmek zorunda kalıyorum. Anlaşılacağı gibi toleranslı bir çalışma yapmak gerekiyor.

Aslında test ortamı da çalışmada farklı sonuçlar alınmasına sebep oluyor. Kutu içerisinde fanın çalışması yada ısıtıcı olan havya dan gelen ısı direk sensöre etki etmesi yüzünden hızlı değişimler dalgalanmaya sebep oluyor. Bunu şu şekilde test ettim. havyayı kapatıp sıcaklığı oda sıcaklığına kadar soğumasını bekledim. Ardından kutu kapalı iken ısınmak için kullandığım ufoyu açtım ve aralarında engel olmayacak sekilde koydum sonuçta ufo çalışmaya başladıktan sonra kutu içindeki sensör değeri yükselmeye başladı. Başka bir testimde ise Fan önüne koyduğum sıcak bardaklaydı. fan çalıştıkca kutu içi sıcaklık düşmek yerine artıyordu. kısaca hesaplamalarım ne olursa olsun ortamdaki havanın sıcaklığı sistemi dengesizleştiriyor. O sebeple deneyle daha fazla test yapmanın anlamsızlaştığı nı gördüm. Daha sabit bir çalışma için ikinci bir sensör ile dış ortam sıcaklığını ölçüp Ofset değerinin değişken yapmak gerekiyor gibi.

Programdan bahsedersem. "For Say = 0 to 9" döngüsü ile İntegral kazanc için isi fark değerlerinin toplamını hesaplamak için kullanıyorum. bu döngü içerisinde ise Oran ve Türev kazançları için her ölçümden sonra kendi hesaplamalarını yapılıyor. Döngü içerisine İntegral için sadece önceki ortalamaya ait kazanç değeri değişmeden hesaba dahil ediliyor.

Her kazancın pozitif ve negatif değeri olabileceği için ilave sorgulama ve toplama çıkarma var.
Örnek olarak Oransal kazanç hesabına bakalım.
burada Set ile okunan değer arasındaki farka göre çıkarma işlemi yaptırıyoruz. ardından Kp kat sayısı ile çarpıp çıkan sonucun belirtilen max değeri geçiyorsa değeri belirlenen max değere sabitliyoruz. Kp_i ile de bu sonucun pozitif ise "0" negatif ise "1" olacak şekilde değer atıyoruz. Artık oransal kazanc PID_Kp de ve polaritesi ise Kp_i değişkenine aktarmış olduk. Elde edilen değer PID adlı değişkene ekleniyor veya çıkartılıyor.

        'Oransal değer için Okunan ile Set arasındaki fark alınıyor.
        if Set >= okunan then          'Kp hata değerinin pozitif yada negatif durumuna göre 
        PID_Kp = Kp * ( Set - okunan ) 'Aradaki fark Kp katsayısı ile çarpılıyor.
        Fark = Set - okunan            'program takip yardımı için 2 değer arasındaki farkı hesaplıyoruz.
        if PID_Kp > KpMax then PID_Kp = KpMax  'Elde edilen değer belirtilen miktarla sınırlıyoruz. (KpMax)
        Kp_i = 0                      'Kp_i değerin işaret biti sıfırsa pozitif 
        PID = PID - PID_Kp            'Sistem Sogutma yapılacağı için ters işleniyor
        else
        PID_Kp = Kp * ( okunan - Set )
        Fark = okunan - Set
        if PID_Kp > KpMax then PID_Kp = KpMax  'Elde edilen değer belirtilen miktarla sınırlıyoruz. (KpMax)
        Kp_i = 1                      'Kp_i değerin işaret biti sıfırsa negatif
        PID = PID + PID_Kp            'Sistem Sogutma yapılacağı için ters işleniyor
        endif

Ayni şekilde PID_ki ve PID_Kd içinde aynı şekilde tekrarlıyoruz.

PID değişkeni tüm kazançların sonucunu toplandığı değişkendir. PID her döngü başında 32767 değeri yükleniyor. Her kazanç hesabından sonra kazancın poleritesine göre PID ile toplayıp çıkartıyorum. Kazançların hepsi ile toplama yapıldıktan sonra "If PID >= 32767 then" satırında sonucun pozitif veya negatif durumuna göre P_W_M değeri belirleyip pwm çıkışı değiştiriliyor.

Test sırasında karşılaştığım ve hata yaptığımı düşündüğüm şeylerden biri PID_Kd değeri çok anlık değişiyor olması. türev kazancı iki ölçüm arasındaki farkı alıyoruz. sistem ısı değişimi anlı olarak 1 derece düştüğünde 1 kereye mahsus kazanç oluşuyor ama sonraki ölçümde yeni değer geleince kazanç direk sıfır oluyor. Bu bir hatamı yada dediğiniz gibi türev burada gereksiz mi oluyor bilemedim.

Alttaki resimde çalışma sırasında değişkenlerin durumu gösteriliyor. Renklere göre değişkenler ise

Mavi    :Hedeflenen Set değeri
Kırmızı :anlık olarak ölçülen sıcaklık değeri
Yeşil   :Çıkış ( Duty ) değeri
Turuncu : PID_Kp (Oransal) Kazanç
Mor     : PID_Ki (İntegral) Kazanç
Gri     : PID_Kd (Türev) Kazanç
 
Dikkat ederseniz anlık değer değişimi gerçekleştiğinde o an için kısa bir süre türev kazancı yükselip düşüyor. Bu şekilde çalışması normalmi. Ben hata mı yapmışım.



ete

#3
Programa henüz detaylı bakamadım bürodaki işlerden dolayı. Ancak grafiğe bakınca şöyle bir şey hisediyorum. Her maksimuma ulaşma noktasından sonra bir taşma yada aşma olup duty sıfırlanıyor hatta sıfırın biraz üzerine geçiyor bu sanki hesaplamadaki bir kritik eşik olmasından kaynaklanıyor gibi geldi bana. Olaya tam hakim olamadığım için daha detaylı teşhis koyamıyorum maalesef.

Ben olsam türevin etkisini hesaptan çıkartıp o şekilde bir deneme yapardım aradaki farkı kolayca görmek mümkün o şekilde.
Ete

aRci

Merhaba;
Duty değerinde taşma yaşanmıyor bunu değerlerin rakamsal çıktılarını takip ederek söylüyorum gerekli kontrolleri yaparak duty değeri veriyorum bu konuda eminim. uygulamada türevin dahil olması ve genele yansıtılmaması söz konusu sanırım burada hata yapıyorum çünkü pid konusunda anlatımda türev kazanc değerinin sıfır olmaması gerektiği yazıyor bu durumda ya hata kazanc değeri değiştiğinde 1 kereye mahsus hesap yapıp sonraki değere kadar hesabı değiştirmeden kullanmak gerek yada tamamen çıkarmalıyım.

ete

Hesaplama şeklin bana çok karmaşık geliyor işin içinden çıkamıyorum.
Normalda bu işin temeli aşağıdaki formülasyona dayanır. Eksi değer hesaplama yüzünden hesabını bir sürü if satırları ile desteklemek zorunda kalmışsın ama onun bile az da olsa kolayı var.
  OncekiHata=SetDeger-OkunanDeger
  Integral=0
  Basla:
        Hata=SetDeger-OkunanDeger
        Integral=Integral+(Hata*Sure)
        Turev=(Hata-OncekiHata)/Sure
        CIKIS=(Kp*Hata) + (Ki*Integral) + (Kd*Turev)
        OncekiHata=Hata
        PAUSE SURE
        Goto Basla
Tabiiki benim açımdan bir takım bilinmeyenler var. Mesela en önemlisi hesaplanan PWM değerinin hangi aralıklarda olacağını bilemiyorum. Programda bir PWM komut desteği yok belkide ikinci bir işlemci ile bunu hallediyorsun. Bu durumda tepki süresi epeyce etkilenir bunu dikkate alman gerekir.
Bu işi profesyonelce yapanlar MATLAP ortamında parametre tespiti yapabiliyorlar. Bu işin kilit noktası Kp, Ki ve Kt parametrelerinin doğru şekilde tespitine dayanıyor.

Bir zamanler benzer konudaki çalışma için ben şöyle düşünmüştüm. Isıtma düzeneğini hazırlayayım ve belirli bir sıcaklıkta (SET Sıcaklığı) sistemi tutmak için ısıtıcıya ne değer vermeliyim yada ne kadar süre ile ısıtıcıyı çalıştırmalıyım. Senin düzeneğine göre konuşursak PWM Duty değerim ne olmalıdır. Daha öncede belirtmiştim. SET sıcaklığında ısı kayıplarını karşılayıp sistemi o sıcakıkta tutmak için ısıtıcıyı belirli sürelerde aktif tutmak gerekiyor. Bu değeri tespit ettikten sonra bir örnek hesaplama yapardım. Muhtemelen bir Excel tablosu ile bir ortamdaki sıcaklığın 23 dereceden 50 dereceye çıkartılması ve o sıcaklıkta tutulması amacı ile nasıl bir tablo ortaya çıkmalı bunu hesaplar bu hesaplar üzerinden de paramtereleri doğru şekilde tespit etmeye çalışırdım.

Basic matematiğinde maalesef signed (işaretli işlem yok.) ancak yardımcı bazı operatörler var. Bunların başında ABS operatörü yada komutu geliyor.
Senin hesap sistemine bakacak olursak;
 if Set >= okunan then          'Kp hata değerinin pozitif yada negatif durumuna göre 
          PID_Kp = Kp * ( Set - okunan ) 'Aradaki fark Kp katsayısı ile çarpılıyor.
          Fark = Set - okunan            'program takip yardımı için 2 değer arasındaki farkı hesaplıyoruz.
          if PID_Kp > KpMax then PID_Kp = KpMax  'Elde edilen değer belirtilen miktarla sınırlıyoruz. (KpMax)
          Kp_i = 0                       'Kp_i değerin işaret biti sıfırsa pozitif 
          PID = PID - PID_Kp             'Sistem Sogutma yapılacağı için ters işleniyor
        else
          PID_Kp = Kp * ( okunan - Set )
          Fark = okunan - Set
          if PID_Kp > KpMax then PID_Kp = KpMax  'Elde edilen değer belirtilen miktarla sınırlıyoruz. (KpMax)
          Kp_i = 1                       'Kp_i değerin işaret biti sıfırsa negatif
          PID = PID + PID_Kp             'Sistem Sogutma yapılacağı için ters işleniyor
        endif
Bu hesabı aşağıdaki şekilde de yapmak mümkün olabilir. Fark eden biraz daha az kod kullanılması olur.
        FARK=ABS(Set-Okunan)
        PID_Kp=Kp*Fark
        If PID_Kp > KpMax THen PID_Kp=Kp
        IF Okunan>SET then 
          KP_i=1
          PID=PID+PID_Kp
        else
          Kp_i=0
          PID=PID-PID_Kp
        ENDIF
BU mantık diğer hesaplarada uygulanabilir.

Ete

aRci

Merhaba;
program içerisinde HPWM komutu ile pwm i aynı pic ile yönetiyorum. Verdiğiniz örnek program için teşekkür ederim ben yaptığım uygulamamda süre faktörünü hesaba dahil etmedim. sizin hesaplama ile benimki arasında farklılıklar var.

Mesala türev hesaplarken onceki ve sonraki hatalar arasındaki farkı alıp bu Kd ile çarpıyordum. Ama sizin örnekte set ile okunan arasındaki farkı önceki hata ile farkını süreye bölmüşsünüz. bu şekilde benim çalışmam arasında hesaplamalarda farklılık var.

Akşam programda verdiğiniz örnekle deneme yapacağım sonucu paylaşırım.

ete

Diğer bir dşkkat konusuda Kp-Ki ve Kt parametreleridir. Bunların normalde 1 den küçük olmaları beklenir. Aksi taktirde sonucu hayli etkiliyorlar ve sayının birden bire çok büyümeine sebep olabiliyorlar. Ondalıksız aritmetik nedeni ile başlangıçta değerleri 1-2 digitli rakamlar şeklinde kullanmak mümkün ama parametre çarpımlarından sonra sayıyı 10 a bölerek belirtilen parametreleri 0-1 aralığında kullanmış olabilirsin.

Ete

Powered by EzPortal