PID döngü yaptım calısıyor anck sıkıntı var

Başlatan zamzam23, 24 Haziran 2011, 11:59:45

zamzam23

#15
şöyle bir sıkıntı var: 50m/sn ye ye kdr motor hızlanıyor sonra sapıtıyor PID yanlıs ve dogrusunu nasıl yapıcam bılmıyorum katsayıları bulmak cok sıkıntılı. deneme yanılmayla yaptım sanıyordum ama yapamamısım yük binince titreme yapıyor tam oturmuyor ref hız degerıne

zamzam23

arkadaslar baska konu acıp da kalabalıklık olusturmak ıstemıyorum forumda. PID dongusu yazdım ama sıra katsayıları bulmaya geldi. motorun PID katsayılarını nasıl bulabılırım?kp>ki mi olmalı yoksa tersi mi? kd=0.001 gibi birsey mi olmalı yoksa kd>1 mi olmalı nerden baslamalıyım? deneme yanılmayla bulucam artık baska yol yok sanırım

zamzam23

bana bu pid konusunda hakkıyla yardım edecek bi allahın kulu yok mu ya

Tagli

Ziegler–Nichols yöntemi olarak bilinen bir yöntem başlangıç değerleri hakkında fikir verir, ama bu yöntemi uygulamak her zaman mümkün olmayabilir.

Genelde deneme yanılma ile yapılıyor ayar. Microchip'in ters sarkaç konusundaki bir uygulama notunda bir dizi adım önerilmiş, ama tabi bunlar senin sistemin için geçerli olmayabilir.

Gökçe Tağlıoğlu

Klein

#19
PID'yi zaten yapmışsın. Parametre ayarları tamamen senin sisteminin dinaiği ile ilgili oduğu için , birşey söylemek gerçekten zor.  Bu yüzden yardımcı olmak da oldukça zor. 
Genel olarak hangi parametrenin etkisi nasıl olacaktır bundan bahsedeyim. Belki oturmayan taşlar biraz olsun yerine yerleşir.

Kp parametresi:Bu parametre set değerimiz ile çıkışımız arasındaki farka yani hataya göre çıkışa hangi büyüklükte bir sinyal uygulayacağımızı belirler. 
Örneğin:
Bir motor kontrolümüz var. Kontrolü PWM ile ayarlıyoruz.
PWM %0 olduğunda motor 0 devir %100 olduğunda ise  motorumuz 1000 devir oluyor.  Eğer PID kullanmasaydık  500 devir istediğimizde  motora %50 PWM uygulayacaktık.  İşte Kp katsayısı da bunu belirler.  Yani bizim Kp katayımız burda 0.1 dir. her bir RPM değişim için çıkışa uygulamamız gereken değer.
Eğer KP yüksek olursa ne olur:Çıkışa her zaman olması gerekenden daha fazla veya daha az güç uygulanacağı için sistem osilasyona girer.
Şöyle örnekleyebiliriz. Bir otomobiliniz var , güzel de bir gaz pedalı var ama sizin ayağınızın ayarı yok.  istediğiniz hıza ulaşmak için gaza yüklendiniz araba hızlandı ,baktınız ki fazla hızlandı ayağı gazdan çektiniz. bu sefer de fazla yavaşladı. Gaza ne kadar basacağınızı ayarlayamazsanız bir hızlanır bir yavaşlarsınız.
Düşük olursa ne olur:Sisteme olması gerekenden daha az güç uygulayacağımız için, ya istediğimiz değere ulaşamaz , ya da en ufak yüklenmede kendini bırakır.
Yine otomobilden örnekleyecek olursak:
Gaza az bastığınızda arabanın ivmelenmesi düşük olacaktır. 10 saniyede 100Km hıza çıkmak isteyeceğiz ama gaza yumurtaya basar gibi bastığımız için  daha biz 50 km hıza çıkmadan bir kırmızı ışık göreceğiz ve durmak zorunda kalacağız. Tabiki istediğimiz yere olmamız gereken zamandan çok daha uzun zamanda varacağız.
Ya da kırmızı ışık görmedik yolumuz uzun. Gaza hafif hafif bastık , ama istediğimiz hıza bir türlü çıkamadık.
Diyelim ki yeterince gaza basmışız, istediğimiz hıza geldik. 
Ama o da ne bir rampa! Eğer biz gaza aynı şekilde basmaya devam edersek  yokuşta araba bayılacak ve hızımız yine düşecek.
Bunu  motorun yüke binmesine benzetebiliriz.

Ki Parametresi:Ki parametresi  bizim ivmelenmemizi artıran parametre. Arabamızdaki vites değiştiren adam.
Herseferinde bir önceki sefer ile şimdiki arasındaki hataya bakarak, sistemin daha hızlı tepki vermesini sağlar.
Örneğin Kp düşük. veya tam değerde. 500 devir dönmesi gereken motora %50 PWM verdik. Bu değer bize sonuçta seti yakalattıracak. Ama ne kadar zaman sonra?
Sisteme yarım güç uyguladığımız için ivmelenmemiz de daha az olacak. Yükselttiğimiz zama da osilasyona girecek.
Peki ne yapacağız?
Buarada yardımımıza Ki yetişir. Bir önceki periyottaki hataya bakar , şimdiki periyottaki hataya bakar ,
Der ki biz çok yavaş hızlanıyoruz. Ya da bir yokuşa geldik araba hız kaybetmeye başladı,  hemen duruma el koyar. Hemen arabanın vitesini küçültür. Biz gaza aynı da bassak,
Vitesimiz küçüldüğü için daha hızlı ivmeleniriz. Ama sonra bir bakar ki araba almış başını gitmiş. Demek ki bu vites düşük geldi der ve
vitesi yarım vites büyütür. Ve böylece ivmelenme azalır. Daha sonra yine bakar bu sefer de vites fazla büyük , bu sefer vitesi
çeyrek viter küçültür. Tabi ivmelenmemiz yine artar, ama daha öncekinden daha az artar. Bu şekilde
vitesi biraz büyütüp biraz küçülterek doğru vitesi bulur. Biraz deneme yanılmacı bir kişiliği vardır.
Eğer yüksek olursa:Vitesi her zaman daha yüksek oranlarda artırıp azaltacağı için doğru vitesi bulana kadar bir hızlanır bir yavaşlarız.
Düşük olursa: İvmelenmemiz de yavaş olacaktır.

Kd Parametresi:Güvensiz bir kişiliktir. Arabadaki vites değiştiren adama güvenmediği için ayağı her zaman frenin üzerindedir.
Gözü de her zaman hız göstergesinde olur.
Ki adamımız vitesi küçülttüğünde ivmelenme artınca tırsar. Gözü hemen göstergeye kayar. Bakar ki çok hızlı ivmeleniyoruz.
Hemen ufak ufak frene basmaya başlar. Hızımız istenilen hıza yaklaştıkça frene daha fazla asılmaya başlar. Kontrollü kişiliğinden dolayı
nerede ne kadar frene basacağını bildiği için , hız limiti aşılmadan önce hızlanmayı düşürür.

Yüksek olursa: Frene biraz fazla asılacağı için ivmelenmeyi fazla düşüteceği için , Ki adamı sürekli vitesle oynar
ve sistem osilasyona girer.
Düşük olursa : Yeterince etkili olamadığı için kaderimiz Ki adamına bağlı kalır.


Ekleme:
Kendmi elindeki dandik malı kakalamaya çalışan pazarlamacı gibi hissetmeye başladım ama,
PID parametrelerinin çıkışa etkisini grafik üzerinde görmek sistemi anlamayı kolaylaştırıyor.
Bu yüzden yine başka bir proje için yazdığım basit simülatörün linkini veriyorum.
Simülasyonda volan etkisi vs.. olmadığı için ihtiyacı tam karşılamayabilir. Ama yine de fikir veriyor.
Program basit bir .exe programcık. makinenizi kasmaz.
http://hotfile.com/dl/123755653/6020228/PID_TEST_PRJ.rar.html

Diğer konuyu takip etmediyseniz ,  kullanımını tekrar açıklarım.

NaMcHo

Alıntı yapılan: bunalmis - 24 Haziran 2011, 12:53:39
Timer rutini içindeki kodların işlenmesi ne kadar zaman alıyor?

Merhabalar konu dışında bir sorum olucak ama, bir if bloğu içindeki kodların ne kadar sürede işletildiğini nasıl hesaplarızı?

while(1)
{
    if(kontrol1)
    {
        TRISB=0x00;
        PORTB=5;
    }
    if(kontrol2)
    {
        for(x=1;x<=8;x++)
            PORTB>>1;
    }
}


Bu kod için Fosc=4MHz olsun herhangi bir PIC entegre kullanıyo olalım,kontrol1 içine girildiğinde  1/( (Fosc/4)*2 )  kadarlık bir sürede,
kontrol2 kısmında ise 1/( (Fosc/4)*8 ) kadarlık bir sürede mi tam olarak işletişmiş olucak kodlarımız?
Birde yine benzer olarak bu hesaplamaları ARM veya MSP serisi entegrelerle yaparken Fosc'yi 4'e bölmeden mi yapıcaz( Mimarisine bakarak mı kara vericez bu dörde bölme olayında )?

Klein

İf bloğu için oluşturulan ASM kodu bilmeden , hesaplamak zor.  İf bloğu işletilmeden önce timer'i sıfırlayıp , blok bitiminde de timer'i okursanız olabilir.

zamzam23

#22
Klein arkadaş. programın kullanılısını hangi linkte bulabılırım ya da bıraz anlatır mısın?
birde sundan bahsedeyım PID dongusunde D parametresını iptal ettim. kullandıgım parametrelere gore sıstemın davranısı şöyle:
set değerine oturuyor ancak bu baya zaman alıyor 10 sn gibi. bu süreyi kısmak için parametrelrle asagı yukarı oynuyorum ama sistem osilasyona giriyor ne yapmam lazım?yazdıgın uzun paragrafa göre ki yi artırmalıyım artırıyorum ancak osilasyona giriyor. D parametreli döngüyü de henüz calısıtırabılmek nasip olmadı.PID timer içinde oldugu için süremi uzun geliyor anlamadım D parametresin devreye alınca sistem  iyice sapıtıyor

Klein

Programın kullanımı basit.
Sol üstte Set , Pset , Iset, Dset var. Bunların ne olduğu zaten belli.  Bulardan herhengi birini değiştirmek için , değeri girdikten sonra enter tuşuna basmak yeterli.  Noktalı sayı  kullanırken nokta yerine  virgül kullanmak gerekiyor.

Bir de en sağda üstte varsayılan değeri 20 olan kutucuk var.  O değer , set değerinin sürekli olarak değiştiği bir durumu simüle etmek için kullanıldı.  Set değerine oradaki kadar sayıyı , belirli bir zaman aralığında ekler ve çıkarır.  Sabit bir set değeri istiyorsan onu 0 yapmalısın.
Bunun dışında diğer parametrelerle girmene gerek yok. Onlar başka bir konu için vardı. Bu başlık için gereksiz.
Mavi çizgi set değerimizi , kırmızı çizgi ise çıkış değerimizi gösteriyor.

İlk mesajında da yanılmıyorsam yüke binince motorun titrediğinden bahsetmiştin.  Bu titremenin PID ile ilgili olduğu kesin mi? PID olmadan çıkış değerini el ile ayarladığında motor dönüyor mu? Eğer  yüke binince tork düşüyorsa Ki değerini artırmalısın.

zamzam23

yüke binince titreme yapıyordu o şimdi bitti kaysayıları biraz oturtunca. ancak şimdi de oturma süresi baya bi uzun onu kısaltmak için sanırım ya kesmenin süresini kısaltıcam ya da ki kp değerleriyle oynayacam. birde türev parametresi için şu formul dogru mu:

derivative=kd*( (hata-hata2)/dt )
döngü sonunda da
hata2=hata;

Tagli

İfade doğru. Yavaş oturuyorsa Kp'yi arttırman gerekiyor. Bence önde Ki'yi kapatıp Kd'yi kurcala osilasyonu engellemek için. Bir diğer mesele de kullandığın sensörde parazit varsa özellikle D bundan çok etkilenir. Sistem Kd'yi arttırırken saçmalamaya başlıyorsa sorun bundan olabilir.
Gökçe Tağlıoğlu

zamzam23

#26
D yi iptal ettim K ve I gzl çalısın bana yeter. söylediklerinizin ışıgında calısmalarım sonunda şu noktaya vardım:
başlangıcta set değeri=20cm/sn
motor ilk harekette 12m/sn
sonra yavas yavas artıyor 20 ye oturuyor fark sıfır olunca da öyle devam ediyor.yük bindirsem d 1-2 cm/sn hız azalıyor sonra kendını toparlıyor set değerine gelip oturuyor. sonra
set değerini 50 ye kadar belırlı aralıklarla cıkarıyorum. yine benim peşim sıra yavas yavas hız artarak gelıyor 5-10sn ıcerısınde set değerine oturuyor.
sonra set değerini azaltmaya baslıyorum 50 den yavas yavas belırlı aralıklarla iniyorum yine benim peşim sıra beni takip ediyor ve set değerine gelip oturuyor ta ki set değeri=2 ye kadar.
diyelim ki hız=3 set değer 3. bu durumda stabıl calısırken
set değerini 1 yapıyorum. hız gelıyor 2 oluyor sonra tam 1 olup değer oturacakken birden 50 ye cıkıyor hız sonra yine kendını azaltmaya baslıyor 1 e gelıyor sonra yıne 50 ye fırlıyor.halbukı bu durumlarda set değerim hep 1

sıkıntı nedir sizce? programı tekrar veriyorum acaba sağa sola shift işlemleri var onları yaparken mi bit kayboluyor ne yapıyor anlamadım

#int_timer0  //15 msn.
void  timer0_kesme ()   
    {
    hiz=(pals1<<6)/xx;
    //if(hiz>50) hiz=50;
    hata=reff-hiz;
    if(hata>5) hata=5;  if(hata<-5) hata=-5;
     integral=integral+hata;
     if(integral > 10000) integral = 10000; 
     else if(integral < -10000) integral = -10000;
     P=gp*hata; //9.99
     II=gi*(integral>>6);//0.0594
        yeni=(unsigned int8)(P+II);
        if(yeni >150)  yeni = 150;
                set_pwm1_duty(yeni);
         pals1=0;set_timer0(63093);

    }

Tagli

Kafamı karıştıran noktalar var, bilmiyorum belki de ben kodu anlamadım.

Öncelikle, sorun sanki yeni değişkeninin bir şekilde fazla yükselmesinden kaynaklanıyor gibi. Bence sorun "yeni=(unsigned int8)(P+II);" kod parçasıyla ilgili. P+II değeri yavaşlama sırasında negatif olacak. Ama sen bunu işaretsiz bir hale getirmeye çalışıyorsun. Dönen değer işaretsiz olarak ifade edildiğinde doğal olarak 150'den büyük oluyor. Ayrıca yine "II=gi*(integral>>6)" satırı da bana tehlikeli gözüktü. Sanırım burada bölme işlemi yapmak istiyorsun ama negatif bir sayıyı bu şekilde bölmeye çalışırken işaretine de dikkat etmelisin. Muhtemelen soldan sıfır giriyor ve eksi olan işaret artıya dönüşüyor. Önce bir bu dediklerimi kontrol et, mümkünse debug yaparak.

Tabi tamamen yanılıyor da olabilirim, ilk şüphelendiğim şeyleri yazdım.
Gökçe Tağlıoğlu

Klein

Aşağıdaki kodu bir dener misin?

float ref,hiz;
float output=0;
float error=0;
float olderror=0;
float oldolderror=0;
float Kp = 1;
float Ki=0;
float Kd=0;


void pid(void){
            error = (ref-hiz)/10;
            output = output + Kp * (error - olderror + (Ki * error) + (Kd * (error - olderror * 2 + oldolderror)));
             oldolderror=olderror;
             olderror = error;
             if(output>150)  output =150;
             if(output<0) output = 0;
}

zamzam23

Alıntı yapılan: Tagli - 12 Temmuz 2011, 14:19:11
Kafamı karıştıran noktalar var, bilmiyorum belki de ben kodu anlamadım.

Öncelikle, sorun sanki yeni değişkeninin bir şekilde fazla yükselmesinden kaynaklanıyor gibi. Bence sorun "yeni=(unsigned int8)(P+II);" kod parçasıyla ilgili. P+II değeri yavaşlama sırasında negatif olacak. Ama sen bunu işaretsiz bir hale getirmeye çalışıyorsun. Dönen değer işaretsiz olarak ifade edildiğinde doğal olarak 150'den büyük oluyor. Ayrıca yine "II=gi*(integral>>6)" satırı da bana tehlikeli gözüktü. Sanırım burada bölme işlemi yapmak istiyorsun ama negatif bir sayıyı bu şekilde bölmeye çalışırken işaretine de dikkat etmelisin. Muhtemelen soldan sıfır giriyor ve eksi olan işaret artıya dönüşüyor. Önce bir bu dediklerimi kontrol et, mümkünse debug yaparak.

Tabi tamamen yanılıyor da olabilirim, ilk şüphelendiğim şeyleri yazdım.
P+II negatif nasıl olur set_pwm_1 degerine negatif değer yüklenmezki benım bıldıgım. 0 sa %0, 150 ise %100 pwm.
II=gi*(integral>>6) satırında dediğin gibi negatif bölmede işaret kayboluyor olabılır debug yok yapamıyorum ama negatif bolmede işaretin kybolmaması ıcın ne yapmam lazım onu da bılmıyorum sonucta ccs nin kendı fonksıyonu işareti kaybetmemesı lazım.
Alıntı yapılan: Klein - 12 Temmuz 2011, 14:35:14
Aşağıdaki kodu bir dener misin?

float ref,hiz;
float output=0;
float error=0;
float olderror=0;
float oldolderror=0;
float Kp = 1;
float Ki=0;
float Kd=0;


void pid(void){
            error = (ref-hiz)/10;
            output = output + Kp * (error - olderror + (Ki * error) + (Kd * (error - olderror * 2 + oldolderror)));
             oldolderror=olderror;
             olderror = error;
             if(output>150)  output =150;
             if(output<0) output = 0;
}

bu fonksiyonu ne kdr sıklıkla cagırıcam? türevde ve integralde kullanılan dt değeri ne olmalı?