Isıtıcı veya motor kontrolü için pid kodlarım, p i ve d parametleri sorunu

Başlatan eR2, 17 Aralık 2013, 15:16:51

eR2

Merhaba arkadaşlar, 500w lık bir rezistansı pwm yöntemi ve triac ile ısıtıyorum, birkaç if deyimiyle "duty"i azaltarak sıcaklığı ayarlayabiliyorum fakat yeterli gelmedi, pid ile kontrol etmem lazım..

kodlarım aşağıdadır, http://www.koumekatronik.com/media/kunena/attachments/775/HAFTA13.pdf adresindeki pid kontrolü referans alarak yapmaya çalıştım fakat duty de hiçbir değişiklik olmuyor..

(sicakliği max6675 ile ölçüyorum)

edit: dosyalar eklendi " http://s3.dosya.tc/server15/gTtDIc/isipid.rar.html " , duty değiştirebildim fakat p i ve d parametreleri ni bir türlü düzenleyemedim..

#include <16F877a.h>
#device adc=8

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES XT                       //Crystal osc <= 4mhz for PCM/PCH , 3mhz to 10 mhz for PCD
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected
#FUSES NODEBUG                  //No Debug mode for ICD
#include <math.h>
#use delay(clock=4000000)


#include <lcd.c>
         
unsigned int8 data1,data2,setpoint,control,error,pre_error=0,integral,derivative,Kp,Ki,Kd,P,I,D;   
unsigned int16 bilgi=0,sicaklik,feedback=0;

void main()
{
  
   setup_psp(PSP_DISABLED);
   setup_timer_1(RTCC_INTERNAL); 
   setup_timer_2(T2_DIV_BY_16,255,1);
   setup_CCP2(CCP_PWM);             // ccp1 PWM 
   setup_CCP1(CCP_OFF);              
   setup_adc(adc_clock_div_32);    
   setup_adc_ports(AN0);   


   lcd_init();                   
   set_adc_channel(0);          
   delay_us(20);                 
                        
   
   printf(lcd_putc,"\fisi kontrolu");
   delay_ms(1000);
   
   
   
   while(1)
   {
                  
         setpoint=read_adc();    
         delay_us(20);
             
         if(control>=250)
         control=250;
         
         
         
         
         /////////////PID RUTINI
         
         feedback=sicaklik;                   // feedback
         error=setpoint-feedback;             //                          ---hata belirlendi
         
         integral=error+pre_error;            // Accumulated sum of error ---integral
         derivative=error-pre_error;          // Derivative of error      ---türev
         
         Kp = 10;   
         Ki = 2;
         Kd = 1; // Assign value for Kp, Ki, Kd
           
         P=Kp*error;                //oransal
         I=Ki*integral;          //integral
         D=Kd*derivative;        //türev
           
         control=(P+I+D);
         set_pwm1_duty(control);
         pre_error = error;         // Update error
                        
     
         /////////////PID RUTINI
     
                  
        
         
         
         printf(lcd_putc,"\fSicaklik = %Lu%c \nset      = %Lu%c ",sicaklik,0xdf,setpoint,0xdf);
         delay_ms(500);
       
   
   }
}

selimkoc

a) Yükün kullanıldığı gerilim AC yükte mi kullanıyorsun?
b) Triakı AC yükte pwm ile nasıl kontrol ediyorsun?
c) Zero Crossing Detector kullanmıyormusun? Eğer kullanıyorsan alternansı bölerek (digital dimmer) kontrol etmen gerekir.

eR2

Evet, Ac gerilimde kullanıyorum, moc3061 (dahili zero crosslu)opto üzerinden triac ı sürüyorum onda sorun yok, pid ile proteus da baktıgımda pwm değişmiyor, önceden yaptıgım birkaç if döngüsü vardı sıcaklık istenilen değere yaklaştıkça darbe genişliğini azaltıyorum fakat bana daha profesyonel bir şey lazım, pid tek çözümüm..

Sanırım sorunum değişkenlerle ilgili ama anlamadım..Bu arada set sıcaklığını pot üzerinden 8bit adc ile alıyorum 0-255 arası..

skara1214

zero crosslu bir sistemi pwm ile nasıl sürüyorsun?Sen kendin algılayıp ona göre tetiklemeyi sen yapsaydın(belli zaman gecikmesi koyup tetikleme )duty cycle i kendin ayarlardın ama bu şekilde olabileceğini düşünmüyorum
Herkes ölür ama herkes gerçekten yaşamaz

sadogan

Alıntı yapılan: eR2 - 17 Aralık 2013, 22:44:51
Evet, Ac gerilimde kullanıyorum, moc3061 (dahili zero crosslu)opto üzerinden triac ı sürüyorum onda sorun yok, pid ile proteus da baktıgımda pwm değişmiyor, önceden yaptıgım birkaç if döngüsü vardı sıcaklık istenilen değere yaklaştıkça darbe genişliğini azaltıyorum fakat bana daha profesyonel bir şey lazım, pid tek çözümüm..

Sanırım sorunum değişkenlerle ilgili ama anlamadım..Bu arada set sıcaklığını pot üzerinden 8bit adc ile alıyorum 0-255 arası..
Arkadaşların uyarılarını göz önüne almalısın. Yaptığın yapısal hatayı söylemişler.
Triac tetiklendikten sonra kesime girmesi için yükün üzerinden alınması gerekir.
Birde moc3061 gibi  zero crossing ile sürdügünde yanlızca şebekenin zero olduğu anlarda triac iletime gecebilecek.
Triac transitör gibi turn on turn off çalışmaz

eR2

http://www.sonelec-musique.com/electronique_theorie_triac.html buradaki en alttaki  dizaynları baz aldım, ilk başta bende olmaz sanıyordum fakat, devre gayet güzel çalıştı, tek eksiğim örneğin 100e set edildiyse, 115 -120 gibi değerlere çıkıp sonradan düşmesi, biraz daha örneklere bölersem devrem daha hassas olur fakat bana pid lazım, ısıtıcı için olmasa bile motor kontrolü yapacağım..

Şu anda proteusta sadece ccp1 bacağındaki pwm e bakıyorum, eğer duty min sıcaklığa göre değiştiğini gözlemlersem devreyi pid ile çalıştırıp optimum katsayıları (kp ki kd) bulmaya çalışacağım..

Dediğim gibi sorunumu triac olarak düşünmeyin, proteusta sadece lcd ve osiloskop bağladım, kodları öğrenirsem motor için de aynı sistemi kullanacağım..

Devreyi bugün ankara üniversitesinden hocam da gördü, dilerseniz yarın if deyimli haliyle bir video paylaşayım.. Devreyi ilk önce bir ampül ile denedim, şimdi rezistans bağlı, ve 60 a set edildiyse 85 lere çıkıyor fakat sonra 60da çok güzel sabitliyor, tabi bu çok amatör işi, bana daha yüksek hassasiyet lazım..

edit : linkteki en alt devre şemasını baz aldım, forumda bir arkadaşımız paylaşmış teşekkürlerimi sunuyorum (kullandığım komponentler aynılarıdır).. https://www.picproje.org/index.php/topic,46898.0.html

selimkoc

youtube'da tam linkini bilmiyorum ama dijital dimmer pic16f628 kelimeleriyle arama yarsan orada yapmış olduğum bir uygulama var. Dijital dimmer mantığı ile yapmalısın.

0 noktasını algıladıktan sonra timer kesmesi ile 10ms'yi eşit miktarlar bölerek (mesela 1ms yani 10'a bölerek) dilediğin noktada triyağı iletime sok(tetikleme ver) 0 noktasında kendisi zaten yalıtıma geçecektir.   

sadogan

Alıntı yapılan: eR2 - 18 Aralık 2013, 00:45:55
http://www.sonelec-musique.com/electronique_theorie_triac.html buradaki en alttaki  dizaynları baz aldım, ilk başta bende olmaz sanıyordum fakat, devre gayet güzel çalıştı, tek eksiğim örneğin 100e set edildiyse, 115 -120 gibi değerlere çıkıp sonradan düşmesi, biraz daha örneklere bölersem devrem daha hassas olur fakat bana pid lazım, ısıtıcı için olmasa bile motor kontrolü yapacağım..

Şu anda proteusta sadece ccp1 bacağındaki pwm e bakıyorum, eğer duty min sıcaklığa göre değiştiğini gözlemlersem devreyi pid ile çalıştırıp optimum katsayıları (kp ki kd) bulmaya çalışacağım..

Dediğim gibi sorunumu triac olarak düşünmeyin, proteusta sadece lcd ve osiloskop bağladım, kodları öğrenirsem motor için de aynı sistemi kullanacağım..

Devreyi bugün ankara üniversitesinden hocam da gördü, dilerseniz yarın if deyimli haliyle bir video paylaşayım.. Devreyi ilk önce bir ampül ile denedim, şimdi rezistans bağlı, ve 60 a set edildiyse 85 lere çıkıyor fakat sonra 60da çok güzel sabitliyor, tabi bu çok amatör işi, bana daha yüksek hassasiyet lazım..

edit : linkteki en alt devre şemasını baz aldım, forumda bir arkadaşımız paylaşmış teşekkürlerimi sunuyorum (kullandığım komponentler aynılarıdır).. https://www.picproje.org/index.php/topic,46898.0.html
Bol sans

superconductor

setup_CCP2(CCP_PWM);
setup_CCP1(CCP_OFF);

set_pwm1_duty(control);

Sanıyorum sıkıntın burada. CCP1 kullanmışsın ama CCP2'yi pwm çıkışı olarak ayarlamışsın.

Bir nokta daha var.

integral=error+pre_error;

Bu integral terimi kalıcı hatayı sıfırlamaya yetmez. Yerine integral+=error yazılırsa ve integrali limitlersen daha iyi bir çözüm olur.

eR2

Alıntı yapılan: superconductor - 18 Aralık 2013, 11:20:15
setup_CCP2(CCP_PWM);
setup_CCP1(CCP_OFF);

set_pwm1_duty(control);

Sanıyorum sıkıntın burada. CCP1 kullanmışsın ama CCP2'yi pwm çıkışı olarak ayarlamışsın.

Bir nokta daha var.

integral=error+pre_error;

Bu integral terimi kalıcı hatayı sıfırlamaya yetmez. Yerine integral+=error yazılırsa ve integrali limitlersen daha iyi bir çözüm olur.

Öncelikle yardımınlarınız için çok teşekkür ederim..

Pwm çıkışında dediğiniz gibi gözden kaçırmışım, 2 adet pwm kullanıyordum başta sonradan birini çıkarınca böyle oldu demekki.. çok teşekkür ederim..

integral kısmını dediğiniz gibi yaptım, 100 değerinde sınırladım fakat başaramadım..

edit: Proteus ve c dosyalarını ekledim, şimdi sorunum sanırım değişkenlerle..

http://s3.dosya.tc/server15/gTtDIc/isipid.rar.html

Erol YILMAZ

Mesajlara bakıyorum,
Yaklaşık 5 kişi aynı problemi görmüş, ve uyarmış ama halen devam ediliyor..
ben de söyleyeyim de eksik kalmasın.

Proje mantığında hata var!

Öncelikle triyağı CCP modülü ile süremezsin.   (İstisnai durumlardan bahsetmiyoruz)

Sıfır geçişleri takip ederek,
şebekenin sinus eğrisini bir noktada tetikleyerek aktaracağın için,
hangi açı da tetikleyince, yüzde kaç lık bir RMS aktarım yapacağını güzelce hesaplaman lazım.
(Hesaplanmışı nette olabilir.) Tablo yapacaksın.

Ve misal PID kontrol %30 çıkış istiyorsa, bu tablodan %30 luk çıkışı sağlayan AÇI ya göre tetiklemen lazım.

Kısaca projede 3 kısım var.

1) PID kontrol algoritması
2) PID sonucuna göre açının belirlenmesi,
3) Sıfır geçiş takibi ile TRIYAK tetiklenmesi

Hepsini ayrı ayrı test edip, optimize edip o şekilde birleştirmen lazım.

2 sıfır geçişi arasında bir adet + ve - alternans olacağı için sen de bütün periyodu sadece bir alternans zamanı
olarak kabul etmelisin.

Yani 50 hz, 20 mS değil, 100 Hz, 10 ms olarak. 
Eğer ki 20 mS kabul edersen tam orta noktada sıfır geçişle beraber TRIYAK yalıtıma geçecektir.

eR2

Alıntı yapılan: Allegro - 18 Aralık 2013, 12:05:57
Mesajlara bakıyorum,
Yaklaşık 5 kişi aynı problemi görmüş, ve uyarmış ama halen devam ediliyor..
ben de söyleyeyim de eksik kalmasın.

Proje mantığında hata var!

Öncelikle triyağı CCP modülü ile süremezsin.   (İstisnai durumlardan bahsetmiyoruz)

Sıfır geçişleri takip ederek,
şebekenin sinus eğrisini bir noktada tetikleyerek aktaracağın için,
hangi açı da tetikleyince, yüzde kaç lık bir RMS aktarım yapacağını güzelce hesaplaman lazım.
(Hesaplanmışı nette olabilir.) Tablo yapacaksın.

Ve misal PID kontrol %30 çıkış istiyorsa, bu tablodan %30 luk çıkışı sağlayan AÇI ya göre tetiklemen lazım.

Kısaca projede 3 kısım var.

1) PID kontrol algoritması
2) PID sonucuna göre açının belirlenmesi,
3) Sıfır geçiş takibi ile TRIYAK tetiklenmesi

Hepsini ayrı ayrı test edip, optimize edip o şekilde birleştirmen lazım.

Tabiki dediklerinizi uygulayacağım, konu başlığını belki yanlış açmış olabilirim, benim için önemli olan pid algoritmasını ccs de başarabilmem, encoderli pwm motor sürücü devrem de kurulu, motor kısmında da pid kodlarımı denemek istiyorum, eğer proteusta gelişmeyi görebilirsem ilk önce motor kontrolünde sonra ısıtıcımda kullanacağım.. Şu anda sanırım değişkenler ve integral kısmında bir problemim var çözemedim..


eR2

Yazılımı buraya kadar getirebildim arkadaşlar, bir hata görebiliyormusunuz?, pwm i şu anda sicaklik la denememin sebebi simulasyonda uygulayabildiğim içindir, motor kontrolünde encoderdan gelen pulsları simulasyon yapılırken değiştiremiyorum (rc osilatörü dışında fakat oda programı kasıyor), bu nedenle sıcaklık kullandım..

kp yi 2 ve üzeri seçtiğimde duty 8 bit olduğu için taşma meydana geliyor bunu engelleyemedim yardımcı olabilir misiniz?

örneğin sıcaklık 200e set edildiyse ortam sıcaklığı 30 C ---> hata=200-30=170 170*2 =340 taşma meydana geliyor,Kp Kd ve Ki için sınırlamalar koydum fakat bu seferde pid düzgün çalışmıyor..

#include <16F877a.h>
#device adc=8

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES XT                       //Crystal osc <= 4mhz for PCM/PCH , 3mhz to 10 mhz for PCD
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected
#FUSES NODEBUG                  //No Debug mode for ICD
#include <math.h>

#use delay(clock=4000000)


#include <lcd.c>
unsigned int8 data1,data2,setpoint,control;          //duty,isi;
unsigned int16 bilgi=0,sicaklik;
float Kp,Ki,KD,error,pre_error=0,feedback=0,proportional=0,derivative=0,integral=0; 
   
   

        read_max6675(void)
     
     {
      
      output_high(pin_b1);
      delay_ms(10);
      output_low(pin_b1);
      data1=spi_read(10);

      data2=spi_read(10);
      output_high(pin_b1);

      bilgi=make16(data1,data2);
      bilgi=bilgi&(0b0111111111111000);
      bilgi=bilgi>>3;

      bilgi=bilgi/4;


      sicaklik=bilgi;        // 0 - 160 arası icin -24

      }


 
void main()
{
  
   setup_psp(PSP_DISABLED);
   setup_spi(SPI_MASTER|SPI_L_TO_H|SPI_CLK_DIV_4);
   setup_timer_1(RTCC_INTERNAL); 
   setup_timer_2(T2_DIV_BY_16,255,1);
   setup_CCP2(CCP_PWM);             // ccp1 PWM 
   setup_CCP1(CCP_OFF);             // COPY PASTE YAPARKEN UNUTMA! CCP2 OLCAK
   setup_adc(adc_clock_div_32);    //adc ayarları
   setup_adc_ports(ALL_ANALOG);   //tüm analog girişleri tanmlandı;


   lcd_init();                   //lcd unutma...
   set_adc_channel(0);           //an0 portu analog
   delay_us(20);                 //beklemeyi unutma!!!
                        
   
   printf(lcd_putc,"\feR2 \n isi kontrolu");
   delay_ms(1000);
   
   
   
   while(1)
   {
         read_max6675();
         
         setpoint=read_adc();    
         delay_us(20);
             
         if(control>=250)
         control=250;
         
         
                  
         
         /////////////PID RUTINI
         
         
         
         feedback=sicaklik;                   // feedback
         error=setpoint-feedback;             // error
        
         derivative=error-pre_error;               //türev
         
         if(integral>-80000 && integral<80000)     //integral
         integral+=error;
         
         Kp = 2.5;   // idi
         Ki = 0.2;
         Kd = 0.1;
         
         proportional = Kp * error;
         integral = Ki * integral;
         derivative = Kd * derivative;
         
     
           
         control=(proportional+integral+derivative);
         
         pre_error=error;                               // Update error
         
         if(control>250) set_pwm2_duty(250);
         //if(control<0) control=0;
        
         set_pwm2_duty(control);
         
         if(sicaklik>=setpoint) set_pwm2_duty(0);
         
         
                        
     
         /////////////PID RUTINI
     
                  
        
         //printf(lcd_putc,"\fP=%u is=%Lu%c\nse=%u%c%u ",P,sicaklik,0xdf,setpoint,0xdf,control);
         
         printf(lcd_putc,"\fP:%u I:%u D:%u\nisi=%Ld%cset=%u%c ",Proportional,integral,derivative,sicaklik,0xdf,setpoint,0xdf);
         delay_ms(500);
       
         
   }
}

eR2

Yardımlarınız için çok teşekkür ederim, pwm ile olamayacağını anladım ve triyak ı pwm yerine, on-off ile sürdüm, şu anda çok güzel çalışıyor.. kodlarım aşağıdadır.. (ısı ayarını pot ile yapıyorum adc 8 bit olduğu için sıcaklık 256 nın üzerine çıkabilmesi için 2 ile çarptım)

while(1)
   {
          
         setpoint=read_adc();    
         delay_us(20);
         
         pidonoff=setpoint*2;
         
         if(control>=500)
         control=500;
         
         
                  
         
         /////////////PID RUTINI
         
         feedback=sicaklik;                   // feedback
         
         error=pidonoff-feedback;             //                          ---hata belirlendi
         if(error<=0) error=0;
         integral+=error ;                   // Accumulated sum of error ---integral
         
         if(integral>=180) integral=180;      //120 sınırdı
         if(integral<=0) integral=0;
         
         derivative=error-pre_error;          // Derivative of error      ---türev
         

         
         Kp = 0.98;   // 2 idi 0.8142 ideal
         Ki = 0.361;  //    1 idi 0,261 ideal
         Kd = 0.59;   // 0.1 idi 0,19 ideal Assign value for Kp, Ki, Kd
    
         P=Kp*error;                //oransal
         I=Ki*integral;          //integral
         D=Kd*derivative;        //türev
         
         
         control=(P+I+D);

         if(control>=499) control=499;

         off=500-control;
         
         if(sicaklik<setpoint)
         {
         output_high(pin_C1);
         delay_ms(control);
         
         output_low(pin_C1);
         delay_ms(off);
         }
         else
         {
         output_low(pin_C1);
         }
         pre_error = error;         // Update error