pid motor kontrol

Başlatan bulut_01, 16 Ocak 2018, 22:46:46

bulut_01

iyi aksamlar arkadaslar pid algoritmasını ögrenmeye calısıyorum asagıda kücük bir örnek verecegım. motorun var olan hızı (rpm) birde kendim dönmesini istediğim referans (ref) değeri var.  bu algoritmada dt (pid fonksiyonuna her girdiğindeki geçen zaman) bu kısmın değerini 1 yaptıgımda sacma sapan sinyaller görüyorum similasyonu proteusda yapıyorum algoritmada yanlış yerler varsa sizce nereler ?
I (İntegral) Bu bölüm hiç sabit kalmıyor motor sabit hızda dönerken.

int8 kp=8;
int8 ki=5;
int8 kd=5;
int8 dt=1;

Hata = Ref - rpm  ;
                                                     
HD = Hata - EHata;                                                 

P = Kp * Hata;

I = I + Ki * Hata * dt;

D = Kd * HD/dt;

EHata = Hata;

PID = P + I + D;

set_pwm1_duty(PID);
YENİLMEZ..

Mucit23

Kp ki ve kd katsayıları float türünde olsun. Bazı sistemlerde virgülden sonra 2 hane bile sistemin tepkisini değiştirebiliyor.

OptimusPrime

https://electronicsfreelancer.wordpress.com/2017/05/08/pid-implementasyonu-kodlamasi/

dt surekli zamani ifade eden bir deger. sen burada ayrik zamanda calisiyorsun ayrik zamanda dt yok. dolayisi ile bu deger aslinda katsayinin icine yedirilmis bir deger olmaliydi. daha baska seylerde var. yukaridaki yaziyi okunami tavsiye ederim.
https://donanimveyazilim.wordpress.com || Cihân-ârâ cihân içredir ârâyı bilmezler, O mâhîler ki deryâ içredir deryâyı bilmezler ||

bulut_01

Alıntı yapılan: OptimusPrime - 16 Ocak 2018, 23:26:54
https://electronicsfreelancer.wordpress.com/2017/05/08/pid-implementasyonu-kodlamasi/

dt surekli zamani ifade eden bir deger. sen burada ayrik zamanda calisiyorsun ayrik zamanda dt yok. dolayisi ile bu deger aslinda katsayinin icine yedirilmis bir deger olmaliydi. daha baska seylerde var. yukaridaki yaziyi okunami tavsiye ederim.
Üstad verdiğin link okudum ordaki örneği anlamak isterdim ama fazla anlayamadım ayrık ve sürekli kavramları neyi ifade ediyor tam olarak? birde verdiğim örnek üzerinden anlatım yaparsanız daha iyi anlıyacagım sanırım verdiğim algoritma calısıyor ama istediğim derecede stabil calısmıyor dt değeri 0 oldugunda integral kısmı pasif kalıyor dt değeri 1 yaptıgımda sacma sapan sinyal cıkıyor mcu dan bu pid konusunu daha detaylı ve anlasılır sekılde anlatırsanız benim gibi bu konuda fazla bilgisi olmayan arkadaslar pid konusu daha iyi anlıyacaklardır.
YENİLMEZ..

foseydon

Hocam sen ne PİD mantığını anlamamışsın. Basitçe anlatayım bildiğim kadarı ile.

PİD kontrolü anlamak için şoyle bir grafik duşün. Y ekseni kontrol etmek istediğimiz değişkenin değeri. X ekseni zaman. Birde kontrol değişkenini tutmak istediğimiz değer var. Bu da Y ekseninden x eksenine paralel sabit bir değer. Kontrol degiskenimiz zaman içerisinde değişir, sürekli bir fonksiyondur.

Şimdi pid mantığında 3 bileşen vardır. Proportional : bu herhangi bir t anında kontrol değişkeninin değeri ile onu tutmak istediğimiz değer arasındaki fark. Grafiğe göre düşünürsek. X ekseninden herhangi bir noktadan cekecegimiz dikmenin düz çizgiyi kestiği nokta ile fonksiyonu kestiği nokta arasında kalan fark. Bu farka bakarak istenen noktadan ne kadar uzakta olduğumuza anlık olarak bakar ve kontrolünü buna göre yaparsak P kontrol yapmış oluruz. Bunun dezavantajı geçmiş bilgisi yoktur. Yani sistemin önceki durumundan bağımsız kontrol sağlanır. Anliktir.

İntegral kısmında sistem geçmişinde tutulur. Yine grafiğe göre düşünürsek, sabit fonksiyon ile sürekli değişen fonksiyon arasında kalan alandır. Bunun avantajı şudur, yaptığınız işlemlerin sisteme olan etkisini de hesaba katmış oluruz bu stabiliteyi sağlar.

Derivative, sonuncu bileşen, türevidir. Bu da sistemin gelecekte nereye gittiğini kestirerek kontrole yardımcı olur. Grafikte düşünürsek, sürekli değişen grafikte herhangi bir t anında grafiğe çizilen tegettir. Burada yaptığımız kontrolün sistemi gelecekte nereye götürdugune bakarak kontrolumuzu ayarlamamizi sağlar.

Türev bileşeni genelde kullanılmaz. Çoğu endüstriyel kontrol Pİ dir.

Senin yazdığın koda gelirsek. İntegral bileşenindeki dt yıl çıkarsan bile sonuç değişmez. Çünkü 2 sabiti çarparsan sonuç sabit olur. Bu yüzden 2 sabit yazmak yerine tek sabit yazarsın. Optimus un içine yedirmek dediği bu.

Birde işin katsayı belirmeye kısmı var. Kafana göre pi katsayısı yazamazsin. Hesabı var. Hesap yapmayacağım dersen uygulamalı metotları var. Önce P katsayısını bulursun, diğerlerini sıfır larsin. Sonra P sabit tutup İ katsayısını bulursun (D sıfır) en son D yıl bulursun.

bulut_01

O zaman benim algoritmam tam olar pid mantıgında calışmıyor mu?  evet pid yeniyim ögrenmeye calışıyorum eksen örnegi için tşk ederim bu teorik bilgileri algoritmayı daha stabil hale getirmek için nerelerde düzenlemeler yapmam laZım?
YENİLMEZ..

foseydon

öncelikle yazdığın kodları okunaklı yazman ve (code)(/code) takısı içerisine alman lazım. Kod dökümantasyonunun birinci kaynağı kodun kendisidir. okuyan kişinin bir bakışta anlaması lazım. Ben olsam PID kontrolünü şöyle yazardım.

struct PID{
    int8 kp;
    int8 ki;
    int8 kd;
    int interval;
    int error;
    int lastError;
    int referenceValue;
    int measuredValue;
    unsigned long long buffer;
};

void main(){
    struct PID pid;
    while(1){
        pid.measuredValue = RPM
        pid.error = pid.reference - pid.measuredValue;
        pid.buffer = pid.error + ( pid.ki * pid.error ) + pid.kd * ( pid.error - pid.lastError ) * pid.interval;
        // check for buffer saturation here
        set_pwm1_duty(PID);
    }
}


şu tarz yazarsan daha okunaklı olur. bundan daha iyisi, pid hesabını bir fonksiyon yapıp PID structını argüman olarak vermek. kafan karışmasın diye o şekilde yapmadım. Neyse, önemli olan okunaklı kod yazmak yazmak. Ben misal EHata ne diye düşünmek zorunda kaldım. Oysa EskiHata yazsan direk anlaşılır. Sen 3 tane harfe basmaktan kurtulurken başka birisi saatlarce o kodu çözmek için uğraşabilir. Burada anlaştığımıza göre deval edelim.

Öncelikle, PID kontrol yapmaya çalışma. Madem öğrenmeye çalışıyorsun. Önce, sadece P kontrol yap. Sonra I ya geç, en son D yi ekle. Bu sayede, her kontrolün senin kontrol mekanizmana nasıl etki ettiğini görmüş olursun. Misal, sadece P yaptığın zaman istediğin referans değere oturtamayacaksın offset kalacak. I eklediğinde bu offset azalacak veya yok olacak. D eklediğinde referans değerine çok daha hızlı oturduğunu göreceksin vs. vs. bunları görürerek deneyerek öğrenirsen daha kalıcı olur.

Birde tüm yazılım mantığını göremiyoruz, ama pid buffer'ını direk duty değeri olarak vermezsin çoğu durumda. buffer çok çok büyük olur, kontrol çözünürlüğünü artırmak için. bu değer saturasyona tabidir, sınırlarını kontrol eder duty değerine eşleştirir öyle yazarsın.

ingilizcen varsa, katsuhiko ogata'nın conrol kitabının PID kısmını okusan bayağı faydası olur. Ama matematiği ağır biraz. matematik bilgin zayıfsa uğraşma.

bulut_01

Alıntı yapılan: foseydon - 17 Ocak 2018, 13:32:01
öncelikle yazdığın kodları okunaklı yazman ve (code)(/code) takısı içerisine alman lazım. Kod dökümantasyonunun birinci kaynağı kodun kendisidir. okuyan kişinin bir bakışta anlaması lazım. Ben olsam PID kontrolünü şöyle yazardım.

struct PID{
    int8 kp;
    int8 ki;
    int8 kd;
    int interval;
    int error;
    int lastError;
    int referenceValue;
    int measuredValue;
    unsigned long long buffer;
};

void main(){
    struct PID pid;
    while(1){
        pid.measuredValue = RPM
        pid.error = pid.reference - pid.measuredValue;
        pid.buffer = pid.error + ( pid.ki * pid.error ) + pid.kd * ( pid.error - pid.lastError ) * pid.interval;
        // check for buffer saturation here
        set_pwm1_duty(PID);
    }
}


şu tarz yazarsan daha okunaklı olur. bundan daha iyisi, pid hesabını bir fonksiyon yapıp PID structını argüman olarak vermek. kafan karışmasın diye o şekilde yapmadım. Neyse, önemli olan okunaklı kod yazmak yazmak. Ben misal EHata ne diye düşünmek zorunda kaldım. Oysa EskiHata yazsan direk anlaşılır. Sen 3 tane harfe basmaktan kurtulurken başka birisi saatlarce o kodu çözmek için uğraşabilir. Burada anlaştığımıza göre deval edelim.

Öncelikle, PID kontrol yapmaya çalışma. Madem öğrenmeye çalışıyorsun. Önce, sadece P kontrol yap. Sonra I ya geç, en son D yi ekle. Bu sayede, her kontrolün senin kontrol mekanizmana nasıl etki ettiğini görmüş olursun. Misal, sadece P yaptığın zaman istediğin referans değere oturtamayacaksın offset kalacak. I eklediğinde bu offset azalacak veya yok olacak. D eklediğinde referans değerine çok daha hızlı oturduğunu göreceksin vs. vs. bunları görürerek deneyerek öğrenirsen daha kalıcı olur.

Birde tüm yazılım mantığını göremiyoruz, ama pid buffer'ını direk duty değeri olarak vermezsin çoğu durumda. buffer çok çok büyük olur, kontrol çözünürlüğünü artırmak için. bu değer saturasyona tabidir, sınırlarını kontrol eder duty değerine eşleştirir öyle yazarsın.

ingilizcen varsa, katsuhiko ogata'nın conrol kitabının PID kısmını okusan bayağı faydası olur. Ama matematiği ağır biraz. matematik bilgin zayıfsa uğraşma.


Üstad tsk ederim bilgiler için codların karsısına // acıklama yapacaktım aksam unutmusum o konuda haklısın üstad buffer direk pwm basmamam gerektiğini karşılastırma yapıp öyle yazmam lazım bu kısmı algoritma üzerinden yani kodu belirterek yada yazarak anlatırsanız kafamda daha iyi oturacagına inanıyorum evet p i d hepsi farklı işlevleri var bu algoritmada kp ki kd değerleri oynayarak pwmdeki değişkenlerden görüyorum sizin örneğinizde dt göremedim(pid fonk geçen zaman) pid konusunda çok ilgiliyim elimden geldiğince bişeyler yapmaya calısıyorum sizin yardımlarınızla daha iyi olacagına inanıyorum.
YENİLMEZ..

foseydon

pid.interval = dt oluyor.

bulut_01

#9
Ayrıca şunuda biliyorum ölçtüğümüz rpm ile referans rpm degerleri aynı olması gerekiyor( - 1 +1) pid kullanılan degiskenler farklı degerlerde olursa pid calısmaz bu buffer ve pwm degerleri içinde geçerli değilmidir?

" pid buffer'ını direk duty değeri olarak vermezsin çoğu durumda. buffer çok çok büyük olur, kontrol çözünürlüğünü artırmak için. bu değer saturasyona tabidir, sınırlarını kontrol eder duty değerine eşleştirir öyle yazarsın."
Hocam bu kısmı detaylı anlatırsanız sevinirim.
YENİLMEZ..

foseydon

Alıntı yapılan: bulut_01 - 17 Ocak 2018, 14:02:03
Ayrıca şunuda biliyorum ölçtüğümüz rpm ile referans rpm degerleri aynı olması gerekiyor( - 1 +1) pid kullanılan degiskenler farklı degerlerde olursa pid calısmaz bu buffer ve pwm degerleri içinde geçerli değilmidir?

" pid buffer'ını direk duty değeri olarak vermezsin çoğu durumda. buffer çok çok büyük olur, kontrol çözünürlüğünü artırmak için. bu değer saturasyona tabidir, sınırlarını kontrol eder duty değerine eşleştirir öyle yazarsın."
Hocam bu kısmı detaylı anlatırsanız sevinirim.

Şöyle düşün senin pwm çözünürlüğün 12 bit olsun. Bu durumda maksimum yazacagin duty 2^12 = 4096 olur. ADC çözünürlüğün 12 bit olsun. Send control değişkenini adc bin okuyabilirsiniz en yüksek değere ayarlarsan ve bu değerin sıfır olduğu durumdan kontrole başlarsan pid hatası 4096 olur. Bunun üstüne integrali de eklersen 4096 yıl aşar. Bu durumda gidip bu değeri sütü değeri olarak verirsen duty = değer % 4096 olur. Aslında rastgele birşey yazmış olursun. Kontrol sende olmaz. Bunun için, pid toplamını duty çözünürlüğüne oranlayip yazarsın. Pid toplamını 4096000 Maksim olsun diyelim. Bu 2048000 çıktıysa sütü 2048000 yazmasın. Çıkan sonuç 1e1000 olduğu için 1000e böler yazarsın.

bulut_01

#11
Sütü değeri nedemek? Anladıgım kadarı ile mcu pwm çözürlüğü ile pid çözünürlüğüne eşitleyecegiz burda adc kullanımı yok pid algoritmasında adc neden yazdınız anlamadım?
Rpm nasıl elde ediyorum rb kesmesinden elde ediyorum gerekli matematiksel işlemlerden sonra rpm ölçmüş oluyorum bu detaylar haricinde daha ögrenmemiz gereken pid konusundaki püf noktaları anlatmaya devam ederseniz ögrenmeye devam ediyoruz.
6.  satırdan sonrasını fazla anlayamadım üstad.
YENİLMEZ..

OptimusPrime

@bulut_01
dt yi unut :)

- sistemde P var carpani var, I var carpani var, D var carpani var. (motor uygulamalarinda genel olarak D kullanilmaz)
- PID icin bir ornekleme zamani belirlemen gerekiyor. mesela saniyede bir ornek. bu ornegi PID algoritmasina verip bir sonraki ornekleme zamani gelene kadar tum hesaplamalari bitirmis ve PWM cikisina yeni degeri yazmis olmalisin
- degiskenlerin gercek sayilar olsun ki yuvarlamalardan dolayi sistem kararsiz calismasin
- PID islemlerini -1 +1 araligina olmali veya herhangi bir aralikta tanimlayabilirsin. Bu durumda her girisi bu araliga cekmelisin. PID sonucunda PWM icin bir deger uretecek, bu deger haliyle normalize ettigin aralikta olacak. Bunu tekrar olmasi gereken araliga cekeceksin. verdigim linkte kodlar mevcut.
- bundan sonra sadece ayarlama kismi kaliyor onuda ziegler nichols efendiye gore yapiyorsun. bununda nasil yapildigi verdigim linkte anlatiliyor.

https://donanimveyazilim.wordpress.com || Cihân-ârâ cihân içredir ârâyı bilmezler, O mâhîler ki deryâ içredir deryâyı bilmezler ||

bulut_01

Alıntı yapılan: OptimusPrime - 17 Ocak 2018, 20:51:08
@bulut_01
dt yi unut :)

- sistemde P var carpani var, I var carpani var, D var carpani var. (motor uygulamalarinda genel olarak D kullanilmaz)
- PID icin bir ornekleme zamani belirlemen gerekiyor. mesela saniyede bir ornek. bu ornegi PID algoritmasina verip bir sonraki ornekleme zamani gelene kadar tum hesaplamalari bitirmis ve PWM cikisina yeni degeri yazmis olmalisin
- degiskenlerin gercek sayilar olsun ki yuvarlamalardan dolayi sistem kararsiz calismasin
- PID islemlerini -1 +1 araligina olmali veya herhangi bir aralikta tanimlayabilirsin. Bu durumda her girisi bu araliga cekmelisin. PID sonucunda PWM icin bir deger uretecek, bu deger haliyle normalize ettigin aralikta olacak. Bunu tekrar olmasi gereken araliga cekeceksin. verdigim linkte kodlar mevcut.
- bundan sonra sadece ayarlama kismi kaliyor onuda ziegler nichols efendiye gore yapiyorsun. bununda nasil yapildigi verdigim linkte anlatiliyor.



üstad verdiğin linkdeki kod bana karmasık geldi pid konusuna hakim olmadıgım için benim verdiğim algoritma üzerinden konussak ben daha iyi anlarım anlatımlarınızı benim algoritmamın karsılaması ıcın nerelerinde değişik yapmam gerekiyor verdiğim örnek üzerinden anlatırsanız hem daha iyi anlıyacagım eger diyorsanızkı bu algoritma pid olarak işe yaramaz kaldır at derseniz anlıyacagım sekılde algorıtma yazabilirmisiniz yada örnek gösterirseniz sevinecegim hocam.
dt neden unutmam gerekiyor ?
-1 +1  mantıgını biliyorum asagıdakı algoritmam bu kurala uydurmam lazım sanırım.

int kp=6;
int ki=1;
int kd=1;
float dt=0.005;
unsigned long long pid=0;

Hata = Ref - rpm  ;

HD = Hata - EHata;                                     

P = Kp * Hata;

I = I + Ki * Hata * dt;

D = Kd * HD/dt;

EHata = Hata;

PID = P + I + D;

set_pwm1_duty(PID);

YENİLMEZ..

berat23

bence pid kontrolcüden önce kontrol nedir neden yapılır kısmına bakmak daha doğru. yoksa pid kodu hava cıvadır, önemli olan kontrolcüdür.

yani sistemin modeli nedir, kararlı mıdır bilmeden kontrolcü yapılmaz. sonra ezber oluyor, p olunca responsive olur, ı olunca steady state error olmaz gibi. önce kullandığın sistem yani motorun transfer fonksiyonuna bak. sonra integral neye yarıyor ya da neden derivative kullanımı gerekli değil ortaya çıkıyor. öyle bakınca başka şeyler de göreceksin, mesela integral aslında ne kadar tehlikelidir gibi.

ayıca kod-proteus ikilisinden ziyade bu işin doğrusu bence simulink'tir. hem orda kararlılık ya da parametreleri tune etmek için araçlar da var, teoriyi doğrularsın. sonra mcu'ya gömmekte birşey yok, altı üstü çarpma toplama