Stm32

Stm32 Pid Motor kontrol uygulaması

Stm32 Pid Kontrol yapalım!

Merhabalar arkadaşlar bu paylaşımda sizlere PID ile referans değere göre motorun hız kontrolünü gerçekleştireceğiz. Öncelikle PID den biraz bahsetmek gerekli diye düşünüyorum. Elektronik mühendislik fakültelerinde ne kadar değinilse dahi uygulamaya sokulması hayli sıkıntılı bir konudur neyse lafı fazla uzatmadan sıkıntılı görünen ancak göründüğünden çok daha basit olan sistemi anlamaya geçelim.

PID Nedir ?

PID Kapalı döngü bir sistemdir Bunu kafanızda bir yere yazın Oransal,integral ve türev kelimelerinin baş harflerinden aşağı yukarı tam olarak ne yaptığı belli olmuştur bile kendi içindeki verilerin durumuna göre şekillenir.

Stm32 Pid Grafiği
Stm32 Pid Grafiği

Setpoint olarak belirlediğiniz değer ile motor sensör yada herhangi bir girdiden aldığınız değerin farkı alınır bu değerin farkı oran,türev,integral alarak çarpılır ve çıkış devremize yeni değer aktarılır. bu yeni değerde kıyaslanır fark var ise tekrar tekrar aynı döngü dönmeye devam eder ta ki fark ideal olarak 0 yada çok yakın bir değere gelene kadar….

Peki bu deli neden bu PID ile yapıyor yahu başka şekilde yapılamaz mı ?? Yok dostum yapamazsın motorun yükü artınca yavaşladı ideal rpm de tutmak için bir döngüye ihtiyacın var bu da PID kardeşimiz bu konuyu çok çok iyi anlayın çok işinize yarayacak.

Uygulama sonunda Paylaştığım videoyu üşenmeden izleyin!!

Bu Görselde gördüğünüz tam olarak PID algoritmasıdır. Setpoint sizin istediğiniz değer Error ise istediğiniz değer ile mevcuttaki değerdir. Şimdilik bu kadar açıklama yeterli diye düşünüyor ve Uygulamaya Geçiyorum..

Haydi Şimdi Stm32 Pid uygulamamızı Yapalım

Malzeme Listesi

CubeMX Ayarları

Rcc external Crystal Aktif edelim.

Clock ayarlarını yapalım.

Serial Wire aktif edelim

Timer 2 Pwm çıkış olarak ayarlayalım

Timer 3 Encoder’dan çıkan veriyi frekansa dönüştürmek için gerekli ayarları yapalım.

Nvic’ten Global interrupt aktif etmeyi unutmayalım.

Potansiyometre okumak için adc izni verelim



Son olarak Gpio ayarlarımızı yapalım

Artık kodlama aşamasına geçelim…


Main.h ın altına bir yerlere değişkenlerimizi koyalım.

uint32_t IC1Value, IC2Value; // Input capture 1 ve 2 degerlerimizi atadik.
float Cycle, Width, DutyCycle, Frequency, freq; //Devami…
float adc=0;
uint16_t adc1=0;
uint32_t systick=0;
double kp = 1;
double ki = 0.1;
double kd = 0.3;
long simdiki_zaman, onceki_zaman;
double Gecen_zaman;
double hata;
double Shata;
double input, output, setPoint=0;
double cumError, rateError;

Adc okumak için gerekli fonksiyonumuzu da main fonksiyonunun üstünde kalacak şekilde koyalım.

uint16_t ADC_Read(void)
{
uint16_t adcVal;
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 1);
adcVal = HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);

return adcVal;}

Şimdide Gelen pulse’i frekans olarak sayan fonksiyonumuzu Yerleştirelim.

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
  if(htim -> Instance == TIM3) {
    if(htim -> Channel == HAL_TIM_ACTIVE_CHANNEL_1) { // Yukselen kenar oku
      IC1Value = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); // ch1 okunan deger
      TIM2 ->CNT = 0; // Reset Count
      Cycle = (float)IC1Value; // Cycle of PWM
      }
    else if(htim -> Channel == HAL_TIM_ACTIVE_CHANNEL_2) { // Dusen kenar oku
      IC2Value = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2); // ch2 okunan deger
      Width = (float) IC2Value; // okunan period
      DutyCycle = 100 * Width / Cycle; // DutyCycle
      Frequency = 1000000 / Cycle; // frekans
      }
    else {
      Cycle = 0;
      DutyCycle = 0;
      Frequency = 0;
      }
    }
  }

Geldik zurnanın zırt dediği yere PID fonksiyonumuzu yazdığımız bölüm..

double computePID(double inp){     
        simdiki_zaman = HAL_GetTick()/1000;                //simdiki zamani aldik
        Gecen_zaman = (simdiki_zaman - onceki_zaman);        //gecen zamani belirledik
        hata = setPoint - inp;                                // hatanin farkini aldik
        cumError += hata * Gecen_zaman;                // integral hesaplamasini yaptirdik
        rateError = (hata - Shata)/Gecen_zaman;   // türevsel hesaplama yaptirdik
        double output = kp*hata + ki*cumError + rateError *kd ;                //PID cikisimizi aldik               
        Shata = hata;                                //hata oranizimizi eski hatamiza verdik
        onceki_zaman = simdiki_zaman;                        //gecen zamanida diger degiskene verdik 

        return output;                                        //fonksiyon cikisina dondurduk 
}

Şimdide Timer ve adclerimizi aktif edelim.

	adc=ADC_Read();// adc okuma işimizi yaptık ve map fonksiyonuna benzer bir şekilde çıkışı oranladık
		adc1=(adc*(1540.0/4095.0))/10;
	
	HAL_GPIO_WritePin(GPIOA , ain2_Pin, 1);
	HAL_GPIO_WritePin(GPIOA ,ain1_Pin ,0);
	HAL_GPIO_WritePin(GPIOA , stby_Pin,1);
		freq = Frequency/31;
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,output);//komutu ile pwm duty cycle oranını ayarladığımızı komutumuzu girdik 
 setPoint=adc1; //Setpointimize adcmizin değerini atadık
        input = freq; //fonksiyonumuzun girişine istenen frekansı verdik                
        output = computePID(input);// fonksiyonumuzun çıkışınıda pwm oranını ayarlaması için çıkış değişkenine verdik.

Kodlarımızı Derlediğimiz de Pid kontrolle çalışan bir motorumuz oldu :) Artık bu fonksiyonu bir çok uygulamada kullanabilirsiniz.

Umarım sizlere PID sistemini biraz olsun anlatabilmişimdir. Eğer sorularınız yada sorunlarınız olur ise Mail adresimden ulaşabilirsiniz. İyi Çalışmalar Arkadaşlar :)

Onur NP

Arduino Stm32 gibi Mikrodenetleyici PLC Otomasyon sistemleri ve Genel elektronik projeleri üzerine örnek paylaşımlar yapmaktayım Endüstriyel ve Kişisel proejelerinize Ücretli olarak destek verebilirim.

İlgili Makaleler

2 Yorum

  1. Merhaba ben de dc motor pozisyon kontrolü için PID uygulamaya çalışıyorum. Bir sorunla karşılaştım.
    Ben motorun encoder uçlarının girdiği pinleri mikrodenetleyici tarafında exti_irq olarak tanımladım. Encoderden sinyal geldiğinde bu kesme fonksiyonu içerisinde hem motorun yönüne göre encoder pulse sayıyorum hemde PID hesaplamaları yapıyorum. Fakat bilmek istediğim şey şu
    PID hesaplamalarını hangi süre aralığında yapmalıyım?
    Teşekkür ederim sitenizi ilgiyle takip ediyorum.

    1. Merhabalar Oğuzhan

      Enkoderdan okuduğunuz değerler kesme birimiyle okuduğunuz için özel bir zamanlama durumuna ihtiyacın bulunmamaktadır döngü içerisinde döndürerek bile çalıştırabilirsin. Ancak PID ERROR time soruyor isen onu Systick timerdan alarak sağlayabilirsin.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Göz Atın
Kapalı
Başa dön tuşu
Call Now ButtonAra
Kapalı
Kapalı