avatar_Mucit23

PID kontrol Sistemleri

Başlatan Mucit23, 30 Kasım 2011, 11:30:30

0nur

Merhaba arkadaşlar,

Uzun zamandır pid konusu ile uğraşıyordum, mikroC ile bir kod yazdım. Şuanda motoru istenen konumda tutabiliyorum fakat yükte iken motorun istenen konuma yaklaştığında hızının yavaşlamasından dolayı belirli değerden sonra dönemiyordu. Bu konu ile ilgili gidilmesi gereken konum belirli bir değerin üstünde ise duty i kademeli olarak düşürüyor.

Şimdi motoru yükte test edip PD parametlerelerini ayarlayacağım. Kodu buraya mı eklemeliyim yoksa MikroC kısmına mı bilemediğim için şuanda kodu yazmadım fakat hangi bölümde uygunsa oraya ekleyebilirim.


ete

Buraya eklemen daha doru gözüküyor

Ete

0nur

//*******************************************************************************
////////////////////////////////////////////////////////////////////////////////*
///////////////           EASY PIC PID APP.     ////////////////////////////////*
////////////////////////////////////////////////////////////////////////////////*
//*******************************************************************************



////////////////////////////////////////////////////////////////////////////////
//////////////////////BAĞLANTILAR///////////////////////////////////////////////

sbit LCD_RS at LATD3_bit;
sbit LCD_EN at LATE1_bit;
sbit LCD_D4 at LATb4_bit;
sbit LCD_D5 at LATb5_bit;
sbit LCD_D6 at LATb6_bit;
sbit LCD_D7 at LATb7_bit;
sbit LCD_RS_Direction at TRISD3_bit;
sbit LCD_EN_Direction at TRISE1_bit;
sbit LCD_D4_Direction at TRISb4_bit;
sbit LCD_D5_Direction at TRISb5_bit;
sbit LCD_D6_Direction at TRISb6_bit;
sbit LCD_D7_Direction at TRISb7_bit;


// encoder bağlantısı
sbit puls_girisA at RB0_bit;              // ENCODER A KANALI
sbit puls_giris_directionA at TRISB0_bit;
sbit puls_girisB at RB1_bit;
sbit puls_giris_directionB at TRISB1_bit; // ENCODER B KANALI
// motor bilgi pinleri
sbit motori at RC0_bit;
sbit motori_direction at TRISC0_bit;
sbit motorg at RC1_bit;
sbit motorg_direction at TRISC1_bit;
sbit led at RD1_bit;
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// sabitler
unsigned int hedef_puls =0, adc_in=0; //0.25 * 485 * 16 = 1940 puls
unsigned int sayac=0, sayac_eski=0, yon=0;  // işaretsiz değişkenler         6
float duty = 0 ;  // işaretli değişkenler
signed int eror = 0 ; // işaretli değişkenler
signed int erorlast = 0 ; // işaretli değişkenler

float P_eror = 0 ; // işaretli değişkenler
float I_eror = 0 ; // işaretli değişkenler
float D_eror = 0 ; // işaretli değişkenler
//float aci = 0 ; // işaretli değişkenler
float hiz=0, Kp=0.50, Ki=0,  Kd=0.15 ;  //        Kp=0.25, Ki=0,  Kd=0.35
unsigned char tmpstr[10]; // genel maksat array

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//////////////////---------------------------- INTERRUPTLAR-----------------------------------////////////////////////////////////////
void interrupt() {
  // RB0 interruptı
  if(INT0IF_bit == 1) {
    INT0IF_bit = 0;
    yon = puls_girisB;
  if (yon==1) {
    sayac--;
    }
    else {
    sayac++;
    }
  }
  // TMR1 interruptı
  if (TMR1IF_bit == 1) {
    TMR1IF_bit = 0;
    // timer 1 registerlarını tekrar ayarla
    TMR1ON_bit = 0;
    TMR1H = 0x0B; // 65536 - 3036 = 62500, 62500 * 8 * 0.2ns = 100ms
    TMR1L = 0xDC;
    TMR1ON_bit = 1;
    eror = hedef_puls  - sayac; // hata değeri
    adc_in=adc_read(0);
    hedef_puls=adc_in*(7760/1023) ;

  if (duty>0)   {
    if (duty>255) {
      duty= 255;
      }
    led=1;
    motori = 0;
    motorg = 1;
    }

  else {
    duty=abs(duty);
    if (duty>255){
      duty=255;
      }
    led=0;
    motori = 1;
    motorg = 0;
    }

  D_eror  = Kd * (eror-erorlast);   /// Derivated error
  I_eror += Ki * eror; /// Integrated error
  P_eror  = Kp * eror;
  duty =  P_eror + I_eror + D_eror ;
 
  if(hedef_puls>500){
    if((eror<400) && (eror>150)) duty=duty/2;   //
    if((eror<150) && (eror>50)) duty=duty/3;
    if(eror<50) duty=0;
    }

  else{
    if(eror<100) duty=0;
    }

  hiz = (sayac-sayac_eski) * 4;  // 100ms'de bu kadar puls varsa 1 saniyede 10 katı puls alırız
  hiz = (hiz*60) / (485*16) ; // puls sa"yısını 16'ya bölüp motor devir sayısını buluruz
  sayac_eski = sayac; // puls sayacını sıfırla
  erorlast=eror  ;

  }
}
//////////////////---------------------------- INTERRUPTLAR-----------------------------------////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void main() {
  ANSELA = 0x01;
  ANSELB=0;
  ANSELC=0;
  ANSELD=0;
  ANSELe=0;

  /*ADCON1 = 0b00001111;*/
  motorg_direction=0;
  motori_direction=0;
  LCD_RS_Direction=0;
  LCD_EN_Direction=0;
  LCD_D4_Direction=0;
  LCD_D5_Direction=0;
  LCD_D6_Direction=0;
  LCD_D7_Direction=0;
  motori=0;
  motorg=0;

  PWM1_Init(2000);                    // Initialize PWM1 module at 5KHz
  ADC_Init();
  PWM1_Start();                       // start PWM1
  // portları dijital yap
  //ADCON1 = 0b00001111;
  // giriş olması gereken pinleri giriş yap
  puls_giris_directionA = 1;
  puls_giris_directionB = 1;
  // osilatörün dengelenmesi için bekle
  Delay_ms(1000);
  // timer ve interruptları ayarla
  T1CON = 0b00110000; // 1:8 prescale, osc shut-off, internal clock(Fosc/4)
  // timer 1'i 100ms'de bir interrupt oluşturmak için ayarla
  TMR1H = 0x0B; // 65536 - 3036 = 62500, 62500 * 8 * 0.2ns = 100ms
  TMR1L = 0xDC;
  // timer 1 interruptını etkin hale getir ve flag bitini sıfırla
  TMR1IF_bit = 0;
  TMR1IE_bit = 1;
  // timer 1'i başlat
  TMR1ON_bit = 1;
  //RB0 interruptını ayarla
  INT0IF_bit = 0;
  INT0IE_bit = 1;
  INTEDG0_bit = 1; // RB0 interruptı yükselen kenarda oluşacak
  // genel interruptları etkin hale getir
  GIE_bit = 1;
  PEIE_bit = 1;
  // LCD sıfırlama
  Lcd_Init();
  Lcd_Cmd(_LCD_CLEAR);
  Lcd_Cmd(_LCD_CURSOR_OFF);
  Delay_ms(500);

  duty=1;

    // ana döngü
    while(1) {



      PWM1_Set_Duty(duty);        // Set current duty for PWM1

      FloattoStr(hiz,tmpstr);
      Lcd_Out(1,1,"Hiz= ");
      Lcd_Out_Cp(Ltrim(tmpstr));
      Lcd_Out(1,13," RPM ");

      WordtoStr(sayac,tmpstr);
      Lcd_Out(2,1,"P= ");
      Lcd_Out_Cp(Ltrim(tmpstr));
      Lcd_Out_Cp(" // ");

      inttoStr(hedef_puls,tmpstr);
      Lcd_Out_Cp(Ltrim(tmpstr));
      Lcd_Out_Cp("  ");


    }
  }



Kodda B0 interrupt'ı ile encoder palsi algılanıp diğer encoder kanalıda yön tayini için kullanılıyor.


  if(hedef_puls>500){
    if((eror<400) && (eror>150)) duty=duty/2;   //
    if((eror<150) && (eror>50)) duty=duty/3;
    if(eror<50) duty=0;
    }

  else{
    if(eror<100) duty=0;
    }

bu kısımda belirli bir aralığa girdiğinde motoru ani yavaşlatmayı sağlıyor.


Projeyi dsPIC Servo şu videodaki hale getirebilirsek çok iyi olacak.

Şimdi vakit bulunca bu konu Protondada yazıp yine paylaşacağım ama buradaki parametreleri nasıl hassas ayarlayabiliriz ve bu şekilde kontrolü nasıl sağlayabiliriz, bu konuda sizlerinde önerilerini bekliyorum...

Could

Merhaba Arkadaşlar,

Benim sormak istediğim konu; step motorları sürülmesi ile ilgili.Elimde leadshine'nın DM422C diye sürücüsü var. ben bu sürücüye bağlı olan step motoru PI kontrol ile sürmek istiyorum. Ya da PI kontrol kullanmadan da yapabilir miyim?
Teşekkür ederim.

ete

Soru eksik sorulmuş yine. Ne sorduğun pek belli olmuyor.
Bir motoru sürmek farklı şey onu PI ile sürmek yine farklı şey.
Bir sürücü ile motor her koşulda sürülür bunu sormaya gerek varmı sence? Bence yok.
Elinde bir motor sürücüsü var bununla motoru sürebilirmiyim diye soruyorsun.
PI ile sürme isteği motoru belirli koşulda tutma amacından kaynaklanır.
Mesela devrini kontrol etmek ve yük altında da sabit bir devirle dönmesini sağlamak için PID yada yalnızca PI ile motoru kontrol edebilirsin. Ama ortada bir sebep yada amaç yok iken PI kullanmanında bir anlamı olmaz herhalde.

Ete

Could

Daha açık sormak gerekirse, motorun devrini kontrol etmek, rampalama yapmak ve yük altında sabit bir devirle dönmesini sağlamak için PI kontrol kullanacağım ama DM422C'nin kendi içinde bu Kp ve Ki değerlerini giren bi sistem varsa kullanmama gerek yok sanırım.Yok eğer yoksa bunu yazılım olarak nasıl yapabilirim? (Bunun aslında Protuner diye bir yazılımı var orada Kp ve Ki değerlerini girebiliyorum.Ama bu yazılımı kullanmak istemiyorum)

ete

Bak şimdi oldu soru doğru sorulunca anlaşılıyor ne istediğin.
Ne yazıkki  DM422C' isimli sürücüyü hiç tanımıyorum. Varsa bir kullanım talimatı araştır oradan çözmeye çalış.
Yoksa,  zaten bu tür özelliği yokmuş gibi davranacaksın.
Sitede PID kontrol mekanizması uzun uzadıya tartışıldı ve güzel bilgiler ortaya konuldu. Onları bulup iyice okuman gerekecek.
Bu işte işin en zor kısmı Kp, Ki, ve Kd parametrelerini doğru olarak tespit etmek. İşin yorucu ve zor kısmı bu bence.
Onun içinde ya matlap kullanmak yada Nicholas (ziegler di galiba)  bilmem kimin metodunu su gibi içmek gerekiyor.
Ondan sonrası artık programlama gücüne kalmış. Kolay iş değil elbette. Ama çalışırsan yakalarsın.
Ete

Could


DigMan

#113
Arkadaşlar merhaba,

bu başlığı başından itibaren okudum. PID ile ilgili güzel bir paylaşım olmuş. Fakat röle kullanımına ait bir örnek verilmemiş sanki. Röle ile sanırım zaman oransal kontrol yapılıyor.  Ben bilinen formülden küçük bir algoritma yaptım fakat ilk turdan(sete ulaştıktan) sonra yavaş kalıyor ve yine dalgalanma oluyor ayrıca set değeri aşımlarında düzgün çalıştıramadım.

   START:

   Inc SAYI_1
   If SAYI_1 > 10 Then SAYI_1 = 0  ' timer kesmesi sonucu her saniye bir artıyor
   
       
   GoSub SICAKLIK_OKU   
     
   PID_Sure = KP * (Set_Deger - Okunan_ISI) ' KP = 1
   HataFark = Abs Set_Deger - Okunan_ISI
   If Okunan_ISI <= Set_Deger - 20 Then High L1 '
   If Okunan_ISI > Set_Deger Then Low L1         
   
   
   If Set_Deger >= Okunan_ISI Then  ' bu rutin; rölenin 10 saniye peryot boyunca on-off süresini belirliyor.
      If SAYI_1 < HataFark Then          ' ve fark = 10 ve altındayken rutin devreye giriyor.
         High L1
      Else
         Low L1
      EndIf     
   EndIf
...
...
...

   GOTO START

okunan_ISI ve set_degerleri 3 hanedir. örn:

okunan_ISI = 254  displayde görülen = 25.4
set_deger = 300   displayde görülen = 30.0

Ete hocam, inventor hocam veya tecrübeli diğer arkadaşlar,
çok araştırdım ama örnek bulamadım. formülü kendim uygulamaya çalıştım belli bir yere kadar gelebildim. röleli zaman oransalı nasıl uygulayabiliriz?


ete

Kodlarına baktım. Röle kontrollu bir sistem için rölenin ne kadar açık ne kadar kapalı tutulacağına dair bir hesap yada satır göremedim. Bir şeyler hesaplıyorsun ama tamamen pid mantığına uygun teorik hesaptan başka bir şey değil ve devamını getirememişsin bana kalırsa. PID konusu epeyce karmaşık bir konudur ve anlaşılması için epeyce uygulama yapılmasını gerektirir. Özellikle KP ve diğer parametrelerin seçimi yada tespiti için uğraşmak gerekiyor. AKsi taktirde hesaplarınız havada kalıyor yada başka bir deyişle kontrolünüz sistemin hızına yetişemiyor.

Bu nedenle ben olaya daha farklı yaklaşırım. Sıcaklık kontrollerinde sıklıkla kullandığım bir yöntem var. Yöntem sonuta belirli oranda PID mantığına dayanıyor. Ama tamamen kendi mantığımla bulup denediğim bir sistemdir. Bir kaç ısı kontrol projesinde uyguladım sonuç gayet tatmin edici çıktı.

Sıcaklık kontrolünde amaç nedir?
SET sıcaklığına bir an önce ulaşıp orada kalmaktır. Bunu ister röle ile yap ister başka bir sürücü ile yap fark etmeyecektir. Ancak röle nede olsa mekanik bir araçtır ve kısa süreli aç kapalara pek uygun olmayacaktır. Zira kullandığım yöntem ısıtma elemanını 1 sn lik peryot içinde set ile ölçülen sıcaklığın durumuna göre bu 1 sn (1000 ms) lik peryodu ortantılayarak kullanma esasına dayanıyor. Örnek ile açıklayayım.
Elimizde 1000 ms lik süre bulunuyor. Şimdi senin verdiğin örnek üzerinden yürüyecek olursak;
SET sıcalığımız :30,0 derece
Ortam sıcaklığımız :25,4 derece ancak şimdlik bunu daha düşük alalım mesela diyelimki 15 derece.
Tecrübelerime göre set sıcaklığından 2-3 derece farka kadar sistemin (ısıtma elemanının) %100 oranda sürülmesi gerekiyor.
Bu durumda Öncelikle fark sıcaklığını hesaplıyoruz. Bu hesapta iki alternatif durum söz konusu olacaktır. Birincisi SET>ORTAM, ikincisi ORTAM>SET her iki duruma göre hesap şekli farklı olacağı için program dilinde şöyle yapıyoruz.
FARK=ABS(SET-OKUNAN) bu formül mutlak değer vereceğinden dolayı her şekilde sonuç doğru olacaktır.
Şimdi elimizde bir fark değerimiz var.
Bunu aşağıdaki şekilde değerlendirmemiz gerekecek. Sıcaklık kademelerini 0,5 çözünürlükle düşünürsek ve sıcaklığın 10 ile çarpılmış halini (ondalık kısmınıda hesaba katarak) değerlendirirsek
300  -----.-Fark=0   , ısıtma elemanı sürülme oranı soğuma yı kompanse etmek için az bir miktar sürülmeli 100 ms
295--------Fark=5   , ısıtma elemanı 200 ms sürülecek 800 ms off
290..........Fark=10  , ısıtma elemanı 300 ms sürülecek 700 ms off
285..........Fark=15  , ısıtma elemanı 400 ms sürülecek 600 ms off
280..........Fark=20  , ısıtma elemanı 500 ms sürülecek 500 ms off
275..........Fark=25  , ısıtma elemanı 600 ms sürülecek, 400 ms off
270..........Fark=30  , ısıtma elemanı 700 ms sürülecek 300 ms off
265 .........Fark=35  , ısıtma elemanı 800 ms sürülecek 200 ms off
260..........Fark=40   ısıtma elemanı 900 ms sürülecek 100 ms off
255..........Fark=45  , ısıtma elemanı 1000 ms sürülecek 0 ms off
Bu tablo bize sabit çarpanı (KP) belirleme imkanı sağlayacaktır. Hesaplanan Fark değerini 20 ile çarparsak her bir sıcaklık farkında şu değerleri bulmuş oluruz.
300.............fark=0     fark * 20=0
295.............fark=5     fark*20= 100
290.............fark=10   fark*20=200
285.............fark=15   fark*20=300
280.............fark=20   fark*20=400
275.............fark=25   fark*20=500
270.............fark=30   fark*20=600
265.............fark=35   fark*20=700
260.............fark=40   fark*20=800
255.............fark=45   fark*20=900
250.............fark=50   fark*20=1000
bu hesaplama sonucunda elde ettiğimiz bu değerler bizim sürme oranımız olmalı. Ancak bir hususu göz önünde bulundurmamız gerekiyor. Isıtılan bir cisim ısıtılma oranına bağlı olarak sıcaklığını korur. Isıtılmaz ise hızla soğur.
Bu nedenle set sıcaklığına ulaşmış olsak bile cisimi az miktar ısıtmaya devam ederek soğuma payını sıcaklık olarak cisme vermemiz gerekir. Bu nedenle yukarıda hesapladığımız değerlere 100 ms soğuma karşılığı ısıtma payınıda eklememiz gerekir.
Bu durumda formüllerimizi genelleştirirsek;
Fark=ABS(SET-OKUNAN)  SURME=(FARK*20)+100  ve KAPALI=1000-SURME
şeklinde iki değer elde ediyoruz.
Bu şekilde senin örneğine göre konuşursak, FARK hesaplanıp oradan SURME ve KAPALI değerleri hesaplanarak,
Röle Sürme miktarı kadar sürülecek , KAPALI miktarı kadar kapalı (OFF) konumunda tutulacaktır.
Bu işlemin frekansı 1Hz dir. Röle için uygun düşmez ise peryodu 2 sn ye çıkartabilirsin. Buna göre sonuçları 2 ile çarparsan sonuç doğru çıkacaktır. 
Bütün bu hassas hesaplamalara rağmen sistemin de ısınma gecikmesi , yada set noktasını aşırı aşma gibi durumlar görülürse parametrelerini değiştirip yeni hesaplar yapman gerekebilir.

Ete

elektro77

#115
Kurban bayramı nedeniyle arabamla memleketime gidiyordum. Yol boyunca aklıma takılan bir şey oldu.
Arabanın hız sabitleme sisteminin, başından sonuna kadar okuduğum bu konuyla ne kadar uyuştuğunu tespit etmeye çalıştım. Sürüş boyunca hız sabitleme sistemini değişik şekillerde test etmeye çalıştım. Düz yolda nasıl, rampa çıkarken nasıl davrandığını gözlemleyip algoritmasını çözmeye çalıştım. set ettiğim hızla o anki süratim arasındaki fark fazla olursa nasıl, az olursa nasıl diye aracın motor sesini ve ivmeyi de hissetmeye çalışarak çözmeye çalıştım.
Sonuç olarak pıd bir sistem olduğunun farkına vardım. Sanırım...
Sizce otomobillerdeki hız sabitleme  sistemleri pıd bir sistem midir.
Eğer evet ise mekanik olarak hangi bilgilere ve sensörlere bakılıp nasıl tasarlanmış olabilirler. İş akışı nasıl dır. Hem fikirlerinizi almak istiyorum ve hemde size fikir vermesi açısından yazıyorum.
İyi Bayramlar.
"Eğer bir konuyu öğrenmek istiyorsan o konunun öğretmeni ol; daha iyi öğrenmek istiyorsan o konuda bir kitap yaz; daha da iyi öğrenmek istiyorsan yazdığın kitabi oku"

ete

Araçların hız sabitleme sistemi PID uygulamalarına en güzel örnektir.
Ete

İlyas KAYA

#117
PID konusunda epey uğraştım baktım işin içinden çıkamıyorum ve matematiğim de iyi değil,  kendi sürme tekniğimi kullanıyorum  :)

Hata= set-motorunhizi

Set ettiğimiz hız ile motorun gerçek hızı (Bunu encoder ile sürekli ölçüyor olmanız gerekir) arasındaki farkı buluyorum.

Örneğin: hata= 100-60

Aradaki fark 40
Bunu ister şu şekilde yapıp pwm çıkışına eklersiniz;

Pwmsurus= set+hata

Isterseniz de şunu yapabilirsiniz;

If motorhizi<SET-5 then
Pwm=pwm+1
Endif

Motor hizi set ettiğimiz değerden düşük ise sürekli hızlanacak ve set değerine yaklaşınca hızlanma duracaktır.

Tabi buna bir limit koymanız gerekir.

Ne kadar artacağını siz belirleyin.

If pwm>(set×30)/100 then motorudurdur

Gibi.

Burada pwm değeri set edilen değerin yüzde 30 undan fazla olursa motor sıkışmış yada başka bir sorun var demektir ve motoru durdurursunuz.

If motorhizi>(set*10)/100 then pwm=0 veya pwm= pwm-1

Yaparsak bu seferde motorun hızı set değerinin yüzde 10 undan fazla olursa pwm değerini düşürürüz ki motor daha fazla hızlanmasın.


BU biraz manüel pid gibi bir şey  Ama ise yarıyor  :)
Göz odur ki dağ ardını görsün,
Akıl odur ki başa geleceği bilsin.!

Hattuşa

Alıntı YapHata= set-motorunhizi

bence bu PID olamaz olsa olsa PID ın sadece P sidir.

https://www.elektrikport.com/teknik-kutuphane/pid-denetleyiciler/11787#ad-image-0

burada daha detaylı bir bilgi var, şu sıralar bende PID ve kalman üzerine kafa patlatıyorum.
1ms lik interrupt içerisinden okuduğum adc değerini kalman&PID karışımı bir filtre algoritması ile stabil hale getirebilirmiyim diye uğraşıp duruyorum. bu işin püf noktası ise iyi bir matematik ve ileri derece ingilizce gerektiriyor yoksa olmayacak bişey değil

İlyas KAYA

Alıntı yapılan: pro-TR - 31 Temmuz 2020, 17:57:50bence bu PID olamaz olsa olsa PID ın sadece P sidir.

https://www.elektrikport.com/teknik-kutuphane/pid-denetleyiciler/11787#ad-image-0

burada daha detaylı bir bilgi var, şu sıralar bende PID ve kalman üzerine kafa patlatıyorum.
1ms lik interrupt içerisinden okuduğum adc değerini kalman&PID karışımı bir filtre algoritması ile stabil hale getirebilirmiyim diye uğraşıp duruyorum. bu işin püf noktası ise iyi bir matematik ve ileri derece ingilizce gerektiriyor yoksa olmayacak bişey değil

Pid olmadığını yazmıştım zaten  :)
Göz odur ki dağ ardını görsün,
Akıl odur ki başa geleceği bilsin.!

Powered by EzPortal