STM32 İLE PID KONTROL ALTINDA DC MOTOR SÜRMEK

Bu yayın ile oldukça kapsamlı bir konuya el atıyoruz. Küçük bir DC motoru, sabit bir hızda çalıştırmak için bir kapalı çevrim süreç kontrol sistemi oluşturacağız.

Bunu yapabilmek için, mikro denetleyici sistemleri geliştirirken edindiğimiz neredeyse tüm birikimimize ihtiyacımız olacak. Öyle ki :

  • Motoru istediğimiz hızda sürebilmek için bir TIMER ile PWM kontrol sinyali üreteceğiz
  • Motoru sürmek için bir L298 Motor sürücüyü kontrol edeceğiz.
  • Motorun devir hızını bir Hall Effect sensör ile algılayıp bir TIMER’in “Input Capture” fonksiyonundan yararlanarak ölçeceğiz.
  • İstediğimiz çalışma hızını bir potansiyometre ile ayarlamak üzere bir ADC kullanacağız.
  • Geliştirdiğimiz kodun kontrolu ve hata ayıklaması için ARM Cortex M çekirdeğinin SWV/ITM araçlarını kullanacağız.

Bu tekniğin bir çubuğu dengede tutmak için geliştirilmiş başka bir uygulamasını görmek için daha yeni bir yayınım var. Ona ulaşmak için burayı tıklayabilirsiniz.

Bu yayındaki projede motora akım sınırlaması uygulamıyoruz. Akım sınırlaması ile daha gelişmiş bir motor sürücü için “Akım sınırlaması altında DC motor sürmek” yayınıma başvurabilirsiniz.

İşimiz çok yani, hadi başlayalım.

DONANIM VE KULLANILAN MALZEMELER

MİKRO DENETLEYİCİ

STM32 ailesinin alt seviye üyelerinden bir MCU kullanıyoruz. STM32F103C8 tabanlı bir Mapple Leaf modülü. Bu modülü 36MHz de çalıştıracağız. Bağlantı kolaylığı açısından bu modülü Mapple adaptör kartıma takılı olarak kullanıyorum.

MOTOR VE MİL ÜZERİNDE DÖNEN MIKNATIS

Hobi uygulamaları için satılan redüktörlü minik bir motor kullanıyoruz. Bu motorun miline plastik bir dişli, bu dişlinin bir kenarına da 2 mm çapında 1 mm kalınlığında bir neodyum mıknatısı gömerek yapıştırdım. Bu mıknatıs milin dönüşü esnasında her turda bir defa hall effect sensörün altından geçerek onu uyaracak.

Bu fotoda motor miline takılı plastik dişli ve bunun tepesinde gömülü bulunan mıknatısın manyetik alanını algılayan hall effect sensör görülüyor. Küçük bir PCB üzerine monteli olarak satın aldığım bu sensör modülünü bu şekilde monte edebilmek için biraz uğraşmam gerekti.

HALL EFFECT SENSÖR

Keyes markalı bu sensör minik PCB si ile bir yerlere iliştirirken kolaylık sağlıyor. Bunlar çok ucuz şeyler, Aliexpress de 10 tanesi 2.5 dolar civarında.

Bunu motor milinin yakınına monte edebilmek için iki deliğin olduğu kenara yakın olarak 4 mm lik bir delik daha açmam gerekti. PCB yi, motor mili o delikten geçecek şekilde yerleştirip epoksi yapıştırıcıyla sabitledim.

MOTOR SÜRÜCÜ

Motor ne kadar küçük olursa olsun, mikro denetleyici ile doğrudan süremeyeceğime göre bir de motor sürücü gerekiyor. Şu popüler L298 sürücülerden birisi işimi görecek. L298 in iki H köprüsünden birisini kullanıyorum.

Bu modülün H köprülerinden birisine ait iki giriş konnektörü bizim STM32F103 ün PA2 ve PA3 pinlerine bağlı. STM32 nin bu pinleri GPIO output olarak yapılandırılmış durumda. L298 bu pinlerden, motora istenen yönde akım uygulatan sinyalleri alıyor. Bu H köprüye ait Enable pinine PA0 dan gelen PWM sinyalini uyguluyoruz. İki adet çıkış klemensine de motorumuzu bağlıyoruz.

LCD EKRAN

I2C Arayüzlü 20×4 popüler LCD ekranlardan birini kullanıyorum.



POTANSİYOMETRE

Motorun dönüş hızını ayarlamak için 10 kOhm luk çok turlu bir potansiyometre kullanıyorum. Bunun değeri kritik değil, 0.5K dan 20K ya kadar herhangi bir potansiyometre olabilir ama mutlaka lineer tipte olmalı, daha hassas ayarlama için çok turlu olmasında yarar var. Küçük değerlerde seçilirse besleme yolundan gereksiz yere fazla akım çekeriz.

Bunun iki dış ucundan birisini GND, diğerini de 3V3 Vcc ye bağlıyoruz. Orta ucunu da ADC1 girişi olarak kullandığımız PA1 e bağlıyoruz.

BESLEME KAYNAKLARI

Mikrodenetleyici modülü 5 Vdc veren bir USB kaynaktan besliyorum, modülün kendi 3V3 gerilim regülatörü var. Potansiyometreye ve hall sensöre 3V3 gerilimlerini mikro denetleyici modülden veriyorum.

Motor beslemesi için ayrı bir 12 VDC besleme kaynağı kullanıyorum. Bu besleme gerilimi L298 motor sürücü modüle bağlı.






BAĞLANTILAR

Mikrodenetleyici

PA0 (PWM çıkışı) –> L298 Enable_A klemensine
PA1 (ADC girişi) –> Potansiyometrenin gezinen ucuna
PA2 (GPIO Output) –> L298 kontrol girişi 1
PA3 (GPIO Output) –> L298 kontrol girişi 2
PA6 (TIM3_CH1) –> Hall effect sensor sinyal çıkışı (S)
PA13 SWDIO –> ST_link
PA14 SWCLK –> ST_Link
PB3 SWO –> ST Link (SWV Debug çıktıları için)
PB6 I2C1 CLK –> LCD I2C CLK
PB7 I2C1 DIO –> LCD I2C DI

Motor –> L298 in çıkış klemenslerine
12 VDC Motor beslemesi –> L298 motor besleme klemenslerine
LCD Besleme –> Mapple adaptör kartı I2C konnektörü
LCD GND –> Mapple adaptör I2C konnektörü

STM32 CUBE IDE İLE YAPILANDIRMA İŞLEMLERİ

Yeni proje oluşturmak için geçilen ilk birkaç adımı atlıyorum. CubeMX yapılandırıcısı açıldıktan sonraki adımlar aşağıdaki gibi.

SİSTEM SAAT AYARLARI

CubeMX üzerinde sistem saat ayarlarını aşağıdaki gibi yaparak dahili osilatör ile 36 MHz e ayarlıyoruz. ADC1,2 ayarının 6 MHz olmasına dikkat edelim, bu bizim uygulamamız açısından çok kritik değil ama geçersiz bir değer olmasın. Potansiyometre değişim hızı ne kadar yüksek olabilir ki?

KODLAMA – PWM ÜRETİMİ

Motoru süreceğimiz PWM sinyalini üretmek için TIM2 zamanlayıcısını kullanacağız. PWM i Channel 1 de üreterek bu kanalın bağlı olduğu PA0 portuna veriyoruz.

Sistem saatini 36 MHz e ayarlamış durumdayız. PWM periyodunun 1 milisaniye olmasını istiyorum. TIM2 nin sayıcı frekansını 1µs yaparsam uygun olur. Bu nedenle Prescaler ayarını sistem saatini 36 ya bölecek şekilde “35” olarak yapıyorum. Bu ayarı, istediğimiz bölme faktörünün 1 eksiği olarak yapıyoruz, çünkü cubeMX yapılandırıcısı buna 1 ekleyerek değerlendiriyor. (0 verildiğinde bölme işleminin sonsuz vermemesi için.)

PWM periyodunu belirleyecek olan “Counter Period” değerini de “1000” olarak ayarlıyorum, böylece 1000µs, yani 1 milisaniye periyodlar elde edeceğim.

PWM darbe genişliğini belirleyecek olan parametre yukarıdaki ekran görüntüsünde “Pulse” olarak verilmiş olan. Burada bir değer vermemize gerek yok, çünkü bu değeri yazılım içinde
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, pwm); komutu ile ayarlıyoruz.

Programımız içinde Timeri aşağıdaki komut ile başlatmamız gerekiyor :
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);

Değişik PWM değerleri ile PA0 dan aldığımız iki osiloskop görüntüsünü vereyim:

İlki düşük (%40 gibi, PWM 400 civarında seçilmiş) :









İkincisi de yüksek PWM, değerli, %90 seçilmiş PWM 900 olarak ayarlanmış.







TIM3 – INPUT CAPTURE, HALL SENSOR ALGILANMASI

Hall effect sensörden gelen motor devir sinyallerini TIM3 zamanlayıcısının PA5 portuna bağlı Channel 1 girişinden algılayacağız. Bunun için TIM3 ayarlarını yapalım:

TIM3 ZAMANLAYICISININ PRESCALER PARAMETRESİNİN HESAPLANMASI

Bu zamanlayıcının sayıcısı ile motorun her turunun ne kadar sürdüğünü ölçeceğiz. Bu sayıcı 0 dan başlayıp 65535 e kadar sayabiliyor. Motorun bir turu bu süre içinde tamamlanmazsa, ölçüm yapamayız. Çünkü sayıcı değeri 65535 den sonra sıfırlanarak yeniden saymaya başlayacaktır.

Öte yandan sistem saatimiz 36 MHz, bunun bir periyodu, 0.028 µs ediyor. Bunu sayıcıya doğrudan verirsek 65535 sayımını 1.834 µs de aşacaktır. Bu durumda 545 devir/sn den daha yavaş dönüş hızlarını ölçemeyiz demektir.

O halde bir prescaler faktörü ile sayıcının periyodunu uzatmamız gerekecek. Bu prescaler değerini hesaplayalım:

Kullandığım motor 5 devir/sn nin altında pek stabil çalışmıyor. Bu nedenle minimum devir hızını 5 devir/sn olarak belirledim. Bu da 200 milisaniyelik bir devir süresine karşı düşüyor. Eğer bu süreye karşı 7000 sayıcı periyodunu denk getirecek bir prescaler belirlersem uygun olacak. Neden 7000 diye sormayın, bunu 10000 ya da 20000 diye de seçebilirdik, o an aklıma bu gelmiş işte.

Bu durumda sayıcı periyodu 200 ms/7000 = 28.5 µs oluyor. 36 MHz ilk MCU saatini 1028 e bölersek bu periyodu elde ederiz. Ben bana daha sempatik gelen 1024 değerini tercih ettim. Buradan hareketle hesapladığım devir/dk değerini LCD ekranda gösterdiğim için sonuçta doğru bilgilendirilmiş oluyoruz.

TIM3 INPUT CAPTURE GİRİŞ FİLTRE AYARI

Hall sensörden gelen darbelerin kenarlarında kararsız bölgeler olabilir. Bu nedenle TIM3 girişindeki filtreyi devreye sokmakta yarar var. En uzun filtreleme periyodu olan 15 saat periyodunu seçiyorum.

TIM3 ile kesmeleri kullanıyoruz. O nedenle NVIC ayarları altında Global Interrupt ları etkinleştirelim.

ADC AYARLARI

Motorun hız ayarını potansiyometre ile yapacağız. Bunun için potansiyometrenin orta ucundaki gerilimi STM32 nin ADC1 analog sayısal çeviricisi ile okuyacağız. Okuduğumuz değeri motordan istediğimiz devir periyoduna çevirecek şekilde bir hesaplama yapacağız.

Hesap şöyle : Motorun en yüksek devrine karşı düşen periyod 2000 sayaç atımı. Buradan başlayarak 5000 e kadar giden bir ayar sahamız olsun istiyorum. Böylece motor devrini 420d/dk – 1050 devir/dk aralığında ayarlayabileceğiz.

Potansiyometreden okunan gerilime karşılık gelen ADC okuma değerini periyoda çevirmek için kullanacağımız formül şöyle:

setPoint = (adc * periodSpan) / 4095 + minPeriyod;

Burada periodSpan değeri 5000-2000=3000, minimum periyod da 2000.

Şimdi ADC ayarlarına gelelim. ADC1 in INPUT 1 girişi PA1 portunda, potansiyometremizin orta ucu da buraya bağlı.

Yukarıda görüldüğü gibi ADC1 i etkinleştirmek için IN1 girişini seçiyoruz. Parametre ayarları da burada göründüğü gibi. Yalnız alt pencerenin biraz aşağısını görmek üzere yukarı kaydırmamız gerekiyor.

Burada “Rank” altındaki “Sampling Time” ı 1.5 saat çevrimi olarak seçtim. Potansiyometreden gelen gerilim oldukça stabil, daha uzun bir örnekleme süresine ihtiyaç yok.

Bu ayarlarla, ADC1 girişine potansiyometreden gelen gerilim 0 ila 3V3 arasında değişecek. ADC1 de buna karşılık 0 ila 4095 arasında değişen ölçüm sonuçları verecek. Okuduğumuz bu değerlerden “0” minimum motor periyoduna, “4095” maksimum periyoda karşı gelecek şekilde periyod hesaplayıp “setPoint” olarak PID kontroluna vereceğiz.

I2C AYARLARI

Kullanıcıya bilgi vermek üzere I2C arayüzlü LCD kullanıyoruz. Bunun için I2C1 i etkinleştirmek gerekiyor:

Varsayılan ayarlarda bir değişiklik yapmaya gerek yok, sadece etkinleştirip kapatıyoruz.

CUBE MX YAPILANDIRMALARI TAMAM – ŞİMDİ DEVAM

PID KONTROL BLOK DİYAGRAMI

Önce şu meşhur PID kontrol blok diyagramını buraya koyalım.

Buraya bakınca korkunç bir matematik gerekecekmiş gibi geliyor ama öyle değil. Bu diyagram şunu diyor:

Motorun (proses oluyor bu) devir hızını ölç. Bu hızı hall effect sensörden her turda bir gelen sinyalleri algılayan TIM3 ile motor devir süresi olarak ölçüyoruz.

Bu hız bizim istediğimizden farklı mı? Fark ne kadar ? Bu fark Error yani hata olarak adlandırılıyor. İstediğimiz hızı STM32 ye potansiyometremiz ile ADC üzerinden bildiriyoruz.

Şimdi ölçtüğümüz hata değerine bağlı olarak motor akımını PWM değerini arttırıp azaltarak ayarlayacağız. Bu ayarlamayı yaparken 3 faktöre bakmamızı söylüyor yukarıdaki diyagram.

Birincisi : Hata ne kadar büyükse o kadar büyük bir düzeltme yap. Yani PWM e hata ile orantılı bir ekleme ya da çıkartma yapacağız. Çok büyük ekleme çıkartmalar yaparsak bu sefer de hedefi aşabiliriz, küçük ekleme çıkartmalar da hedefe ulaşmamızı geciktirir. O halde Kp dediğimiz bir çarpanla düzeltme miktarını ayarlayalım. Bu PID nin Proportional, yani oransal düzeltme faktörü oluyor. Şu anki durumumuzu değerlendiriyoruz.

İkincisi : Hata ne süredir devam ediyor ? Buna göre de bir düzeltme gerekebilir. Hata küçük olduğu için çok küçük düzeltemeler yapıyor, hatta hiç düzeltmeye gerek görmüyor olabiliriz. Örneğin motor sürtünmeleri ya da üzerindeki yükten dolayı sürekli olarak hedef hızın biraz altında çalışıyor olabilir. Hatta duruyor, ama seçtiğimiz düşük çalışma hızından dolayı uyguladığımız küçük PWM değerleri -hata küçük ya- başlangıç sürtünmelerini ve ataletini aşmaya yetmiyor olabilir. O halde, başlangıçtan itibaren biriken hataların toplamına da bakmak lazım. Hata küçük ama uzun süredir devam etmekte ise düzeltme faktörünü büyütelim. İşte bu da PID nin Integral faktörü oluyor. zaman içinde biriken hatayı da bir katsayı ile düzeltme faktörüne eklemek gerekiyor. Bu faktör ile geçmişteki durumu değerlendirmeye katıyoruz.

Üçüncüsü : uygulamakta olduğumuz düzeltmelere motorumuz ne kadar hızlı tepki gösteriyor. Örneğin ; motorun üzerindeki yük hızlanmasını yavaşlatıyor olabilir, o zaman hedef hıza çok uzun sürede ulaşacaktır. Bu durumda motorun hızının artış hızına – yani ivmeye bakarak da bir düzeltme faktörü eklemek gerecektir. Bu faktör de PID nin “D” si, yani türev bileşenini oluşturuyor. Bu faktör ile de geleceğe bakıyoruz.

Bir başka deyişle, düzeltme faktörümüzün içinde şu an (P: Proportional – oransal), geçmiş zaman (I : integral) ve gelecek zaman (D : derivatives – türevsel) üç bileşen var.

Ben bu çalışmayı yaparken adım adım ilerleyeceğim. Önce sadece P-Proportional/oransal faktör ile çalıştıracağım. Ardından buna I-Integral faktörü ekleyeceğim, en sonunda da D-Derivative türevsel faktörü ekleyeceğim. Bu şekilde üç bileşenin sisteme katkısını ayrı ayrı gözlemlemiş olacağız.

PROPORTIONAL – ORANSAL KONTROL İLE ÇALIŞMA

Önce sadece orantısal kontrol ile çalışan bir sistem kurarak çalıştıralım.

Yukarıdaki paragraflarda anlatılan adımları izleyerek projenin genel kurulumunu yapıp bu noktaya kadar gelelim.

LCD yi sürmek için LCD_I2C kütüphanesinin projeye eklenmesi gerekiyor. Ya da hangi ekran kullanılacaksa ona ait sürücülerin eklenmesi gerekir. Bunun için cube IDE – Link vererek projeye kaynak kodu eklemek başlıklı yayınım yol gösterici olacaktır.

Projenin cubeIDE Project Explorer penceresindeki görünümü şöyle olacak. sağ penceredeki main loop çevrimi içindeki kodları şimdilik yok sayın. Bunları ileriki paragraflarda anlatacağım :

SWV üzerinden hata ayıklamak ve değişkenleri izlemek için STM32 cubeIDE – SWV ile hata ayıklamak başlıklı yayınımda anlattığım ayarlar yapılmalı. SWV yapılandırma ayarlarında izlenecek değişkenler olarak pwm ve ICValue (Input Capture Value) i seçelim. Bu şekilde her okunan motor devir periyoduna karşılık hesaplanan yeni PWM değerini SWV ITM Data konsolu üzerinden canlı olarak izleyebileceğiz. Gerçi bu bilgileri LCD üzerinde de gösteriyoruz ama, LCD nin bulunmadığı bir durum için alternatifimiz hazır olsun.

ANALOG SAYISAL ÇEVİRİCİYİ (ADC) OKUMAK

Motor dönüş hızını bir potansiyometre ile seçiyoruz. Bunun için potansiyometrenin orta ucundaki gerilimi okumamız gerekiyor. Bu okumayı da ADC1 ile yapıyoruz. Bunun ayarlarını projenin kurulum aşamasında iken yapmıştık. Şimdi, ADC den okuma yapan fonksiyonu programımıza ekleyelim. Bu programı Cube IDE nin bize ayırdığı User Code 0 ya da User Code 4 bölümlerinden birisine koyabiliriz. Ben ilkini tercih ettim:

Bundan sonra ana çevrim içindeki aşağıdaki iki satırda ADC yi okuyup, okuduğumuz değere karşı düşen motor periyodunu “setPoint” olarak hesaplıyoruz:

adc = ADC_Read();
setPoint = (adc * periodSpan) / 4095 + minPeriyod;


Potansiyometrenin orta ucundaki gerilim 0 ila 3V3 Vcc arasında değişiyor. Bu gerilim ADC1 in Input 1 (Port A1) girişinden okunuyor. ADC1, okuduğu gerilimi 0 ila 4095 arasında (12 bit) kodlanmış bir sayı olarak veriyor. Bu değeri, ikinci satırda minimum motor periyodu ile maksimum motor periyodu arasında bir setPoint parametresine dönüştürüyoruz. Minimum periyod motorun en yüksek, maksimum periyod da en düşük devir hızı oluyor.

TIM3 – ZAMANLAYICI KESME FONKSİYONLARI (IRQ callBack)

Motorun her dönüşünde hall effect sensörümüz bir darbe üretiyor. Ardışıl iki darbe arasındaki süreyi ölçerek motor dönüş periyodunu buluyoruz.

Hall sensör sinyallerini TIM3 zamanlayıcısının “Input Capture” fonksiyonunu kullanarak yakalıyoruz. TIM3 bu modda iken algıladığı her darbe ile bir “Input Capture” kesmesi üretip o anki sayaç değerini kaydediyor. Bu kesme oluştuğunda yapılacak işlemler için programımıza bir “input capture call back” fonksiyonu eklememiz gerekiyor. Bu fonksiyonu main.c içindeki user code 4 bölümüne koydum:

HAL_TIM_IC_CaptureCallback() fonksiyonu, kaydedilmiş olan sayaç değerini ICValue değişkenine koyuyor, bir sonraki periyodu ölçmek üzere sayacı başa alıyor.

Bir overflow kontrolu TIM3 Period period elapsed kesmesinin diktiği bayrağa bakarak, hatalı kaydedilmiş olan sayaç değerlerinin dikkate alınmamasını sağlıyor. Parazitik tetiklemeleri ayıklayan bir kontrol da var. Maalesef jumper tellerle yapılan montajlarda parazitler sorun yaratabiliyor. Montajın dağınıklığı bir yana, motor tellerine verdiğimiz PWM akım darbelerinden endüklenen parazitler var.

Yukarıdaki ekran görünümünde bir ikinci call back fonksiyonu daha var. O da şunun için: Eğer motor duruyor ya da çok yavaş hareket ediyor ise TIM3 sayacı 65535 i aşıp tekrar sıfırdan saymaya devam edecektir. Bu durumda okuduğumuz sayaç değerleri bize motorun devir süresini doğru olarak vermeyecektir. Hele motor durmakta ise, input capture kesmesi hiç oluşmayacak, dolayısı ile ICValue değeri güncellenmeyecektir bile.

Bu durumlarda sayacın 65535 değerini aştığından haberdar olup, ona göre bir şeyler yapmamız gerekiyor. O nedenle TIM3 ün overflow kesmesini de etkinleştiriyoruz. Overflow olduğunda bu IRQ, tim3_overflow_flag bayrağını dikerek diğer fonksiyonlara haber veriyor.

CALLBACK FONKSİYONLARININ PROTOTİPLERİNE ULAŞMAK

Gerek TIM kesintileri, gerekse başka kesintiler olsun, HAL fonksiyonları ile çalışmaya kalkıştığımızda böyle CallBack fonksiyonları hazırlamamız gerekiyor. Bu fonksiyonların HAL kütüphaneleri içinde prototiplerini bulup, buraya kopyalayıp içlerine kendi kodlarımızı yazmak zorundayız. O halde, ilgilendiğimiz kesmeye ilişkin CallBack fonksiyonunu nereden bileceğiz?

Bunu “STM32 CUBE IDE INTERRUPT CALL BACK FONKSİYONLARI” başlıklı yayınımda anlatmıştım.

ANA ÇEVRİME GİRMEDEN ÖNCEKİ İŞLEMLER

Programın ana çevrimi içine girilmeden önce TIM3 ü başlatmak gerekiyor. Bu satırları main() fonksiyonun başına, User Code 2 bölümüne koyuyoruz.

Burada LCD yi başlatıp ilk mesajı yazan komutları da görüyoruz.

Motora başlangıç seviyesinde bir PWM sinyali verip çalıştıralım. PWM oranı ayarını, bunu üretmekte kullandığımız TIM2 zamanlayıcısının Pulse değerini değiştirerek yapıyoruz. Bunun için de __HAL_TIM_SET_COMPARE() fonksiyonunu kullanıyoruz. Ondan sonra TIM2 yi HAL_TIM_PWM_Start() fonksiyonunu çağırarak PWM üretimini başlatıyoruz.

PWM başlangıç değeri, main.c global alanında %10 duty cycle a karşı düşecek şekilde “100” olarak tanımlanmış durumda.

L298 köprüsünü bir yönde açmak üzere motor_1 (PA2) ve motor_2 (PA3) pinlerinden birisini “1” diğerini de “0” yaparak yol da veriyoruz. Bu noktadan itibaren motor bir yönde %10 PWM ile dönmeye başlayacaktır.

Bu ilk aşamada motoru tek yönde çeviriyoruz, yön kontrolu yok. Yön kontrolu daha sonra.

DEĞİŞKEN BİLDİRİMLERİ

Burada, main.c dosyasının başında, User Code PV bölümü içinde tanımlanan global değişken bildirimlerini vereyim. Bunlar sadece Proportional Kontrol için olanlar. “I” ve “D” kontrollarını ekledikçe onlara ait değişkenler de bu bölüme eklenecek.

PID DÜZELTME FAKTÖRÜNÜN HESAPLANMASI – ORANSAL FAKTÖR

Ölçülen hataya bağlı olarak PWM süresinde düzeltme yapacağız. Bu aşamada sadece oransal/proportional düzeltme faktörünü dikkate alıyoruz. Bu faktörü hesaplayan fonksiyonumuz User Code 4 bölümüne koyduğumuz computePID():

Parametre olarak verdiğimiz input, TIM3 Input Capture ile yakalayıp ölçmüş olduğumuz motor devir periyodu, ICValue.

Bu fonksiyona ilerideki bölümlerde Integral ve türevsel/derivative faktör hesaplamalarını da katacağız.

ORANSAL (PROPORTIONAL) KONTROL TEST PROGRAMI

Buraya kadar PID kontrolun sadece “Proportional/oransal” faktörünü dikkate alan bir kod geliştirdik. Ancak, diğer faktörlerin hesaplanmasında ihtiyaç duyulacak tüm ortak fonksiyonları da hazırlamış olduk. Integral ve Derivatives-Türevsel kısımları çok daha kısa olacak.

Şimdi bu haliyle programımızı bir test edelim:

Bu çevrim saniyede bir defa hata değerlendirerek PWM düzeltmesi yapacak şekilde hazırlanmış durumda.

TIM3 input capture kesmeleri ile çağrılan call back fonksiyonu arka planda motorun her turunda bir defa devir periyodunu ölçmekte. Ama biz saniyede bir defa ölçülen değere bakarak düzeltme yapıyoruz. Bu düzeltme işlemi, kesme fonksiyonunun içine konarak her motor devrinde bir defa olacak şekilde de yapılabilir – hatta öyle yapılmalı. Ama bu sunum açısından şimdilik böyle çalışalım.

Bu kod içinde dikkat çekebilecek bir “anormal değişimleri ayıklama” algoritması var. Yukarılarda arada bir parazitik kesmeler gelebileceğini belirtmiştim. Bu ayıklama işlemi için son 5 ölçüm değerini ICbuffer[] dizisi içinde saklayıp ortalamasını alıyorum. Yeni gelen ölçüm sonucu ortalamaya göre %50 den fazla ya da düşük ise bunu değerlendirmeye almıyorum. Motor hızında bu kadar kısa sürede bu kadar değişmesi bir anormal ölçüm sonucuna işaret ediyor olabilir.

Kodun geri kalanı kendi kendini açıklar gibi görünüyor. Şimdi programı çalıştırıp sonucu görelim. Motorun istediğimiz dönüş hızının değişimini ve hedefe ne kadar sürede ulaşıldığını görmek için SWV ITM Data konsolundan yararlanacağım. Örneğimizdeki motoru 710 Devir(dakika hızla çalıştırmak için gereken dönüş periyodu 3000 sayaç adımı. Bunu setPoint olarak LCD ekrana bakarak potansiyometre ile ayarlıyoruz. Programı SWV ITM konsolu kayıtta iken koşturduğumuzda aşağıdaki gibi bir çıktı elde ediyoruz.

Ben bu çıktıları kopyalayıp bir Excel (aslında Mac OS kullandığım için Numbers) tabloya aktararak grafiğe dökmeyi tercih ettim.

Bu çalışmanın bir parçası da, uygulamamız için en uygun Kp değerinin belirlenmesi. Bunun için programı Kp katsayısının farklı değerleri ile çalıştırarak aldığım çıktıları aynı grafik üzerinde görselleştirdim. Sonuç aşağıdaki gibi:

Bu sonuçlara göre Kp katsayısının 0.01 olması halinde overshot olmuyor ama istenen hıza ulaşmak uzun sürüyor. Kp nin 0.1 olması durumunda da biraz fazla overShoot oluyor. Bu dört Kp katsayısı arasında 0.02 en optimal değer olarak görünüyor. hem over shoot yok, hem de 3 saniye içinde istenen devir hızı yakalanıyor.

Burada bir not : Kp, Ki ve Kd faktörleri aslında birer çarpan. Yukarılarda 0.01 çarpanından söz ettiğimde kodun içinde bunu 100 olarak ayarlamış olduğum görülebilir. Çünkü kayan nokta aritmetiğinden ve float tipi değişkenlerden kaçınmak için, bu faktörleri "çarpan" değil, "bölen" olarak kullanmayı tercih ettim. Örneğin 0.05 katsayısı istediğimde bunu 20 olarak tanımlıyorum.

Birkaç farklı setPoint ayarı ile alınan ekran ve Hall sensörden gelen sinyalin osiloskop görüntülerini de vereyim:

Böylece PID nin sadece “P” si ile nasıl kapalı çevrim çalışılabildiğini görmüş olduk. Bu kadarı yeterli imiş gibi görünse de, küçük fakat uzun süren hataların giderilmesi için “I” faktörüne de ihtiyaç oluyor. Şimdi sıra onda.

INTEGRAL FAKTÖRÜNÜN SİSTEME KATILMASI

Integral faktörü hesaplarken, ölçülen hatanın süregeldiği dönem içindeki birikimini hesaplıyoruz. Böylece küçüklüğü nedeniyle oransal faktörü etkilemeyen hataların uzun sürelerdeki birikimli değerlerini de hesaba katmış olacağız.

Bu çalışmada entegrasyon periyodunu ana programdaki örnekleme süresi ile sınırladım. Daha sonra daha da rafine bir yaklaşıma gidebilirim.

Bu faktörün düzeltme katsayısına katılması için computePID() fonksiyonumuza aşağıdaki gibi eklemeler yapıyoruz:

Burada ıntegral faktörün devreye sokulmasını biraz geciktirerek, hatanın IcStart adlı parametre ile belirlenen bir seviyenin (%20) altına düşürülmesinden sonra yaptığımız görülüyor. Yani hata büyük iken sadece “P” faktörü devrede, aksi halde iki faktör birlikte iken büyük over shoot lara yol açıyor.

Burada kullanılan yeni değişkenleri de main.c global alanında aşağıdaki gibi bildiriyoruz:

Integral faktör için değişiklik ve ilaveler bu kadar. Şimdi çalıştırıp sonucu görelim. Bu test çalıştırmasını ilk aşamada en iyi sonucu veren Kp = 0.02 değeri ve Ki = 0.01 değerleri için yapalım.

SWV ile aldığımız sonuçları sadece “P” oransal faktör ve buna “I” integral faktörünün de katıldığı iki durumu yan yana aynı tabloda vereyim, böylece Integral faktörün sonuca etkisini daha kolay görebiliriz. Tablodaki ilk ikişer “5000” değeri gerçek değil, aslında 10.000 in üzerinde değerler. Grafik eksenlerinin uygun boyutlarda olması için gerçek değerleri silip 5000 yaptım.

Burada sadece oransal kontrolun olduğu durumda 2.8 saniyede stabil duruma gelinmesine karşın, buna Integral kontrolu da eklediğimizde 1.6 saniyede stabil hıza ulaşıldığı görülüyor.

Sadece oransal kontrol var iken 3000 olan setPoint’e karşılık motor periyodunun 3070 civarında kaldığını, bu “70” ilk farkı bir türlü gideremediğini de görüyoruz.

Halbuki Integral faktör de devreye sokulunca motor periyodu setPoint’e ulaşıp bunun civarında küçük salınımlar yapıyor.

Bir de bu iki karakteristiği grafik üzerinde karşılaştıralım:

Burada da Integral faktörü devreye almadığımda, hedef civarındaki küçük hataların bir türlü düzeltilemediğini görebiliyoruz. Mavi çizgi : sadece oransal faktör devrede, Yeşil çizgi : Oransal ve Integral faktörler birlikte devrede.

Evet, böylece Integral faktörü de devreye sokarak PID ye varış hedefimizde “PI” aşamasını tamamlamış olduk.

Bütün bu sonuçlar kod içindeki Kp, Ki parametrelerinin seçimine, Integral alma periyoduna çok bağlı. Burada optimizasyon ve ince ayarlama için yapılacak çok şey var. Bunlar benim ilk denediğim katsayılar.

Şimdi motorun boşta çalışması halini ve milini el ile tutup yavaşlatmaya çalıştığımdaki regülasyonu gözlemleyelim:

Burada motor yüksüz çalışarak 703 Devir/Dk hızla dönüyor. Bunun için %34.5 PWM ile sürülüyor.
















Burada da motor milini el ile tutarak yavaşlatmaya çalışıyorum, sistem de hızı 700 de sabit tutmak için ayarları değiştiriyor, PWM %91.4 e kadar yükselmiş, bu boyuttaki bir motor için fena bir sonuç değil. Artık bundan ötesi motor gücüne de bağlı.











“PI” kontrolumuz da çalıştı. Geriye “D” türevsel kontrol kısmı kaldı. Ama o kısmını ileriye, bir başka yayına bırakıyorum. Şimdi aklıma gelen daha heyacanlı projeler var.

Güncelleme Ağustos 2021 : Yeni yayınım “Bir çubuğu PID kontrol altında istenen eğimde tutmak”. Burada P, I ve D bileşenleri için daha ayrıntılı bir açıklama var, D değişkeninin neden her zaman işin içine katılmadığı konusuna da değiniyorum. Pervaneli bir drone motoru bir çubuğu belirli bir eğimde tutuyor.

Güncelleme Haziran 2022 : Bu yayında DC motoru L298 e PWM ile yol vererek sürüyordum, motorun akımı besleme gerilimine bağlı idi. Bu durumda motorun hareketini engelleyen, zorlaştıran bir yük altında motoru döndürebilmek içi PWM oranı yükselecek, motor gene de istenen hıza ulaşamazssa akım aşırı yükselebilecektir. Bunun önüne geçmek için sistemi akım sınırlaması altında çalıştırmak gerekir. L298 ü akım sınırlaması ile nasıl kullanabileceğimizi “Akım sınırlaması altında DC motor sürmek” başlıklı yayınımda anlatıyorum. O konuya da el atmadan bu proje tamamlanmış olmayacaktır.

Bu yayının sonu – Selçuk Özbayraktar Ağustos 2020

60 Replies to “STM32 İLE PID KONTROL ALTINDA DC MOTOR SÜRMEK”

    1. Onur Bey merhaba,

      İstediği bilgiyi aldıktan sonra teşekkür bile etmeden arkasını dönüp giden arkadaşlar oluyor sıklıkla. Bu nedenle eğer benden çalışmalarımın ayrıntılarını istiyorsanız, sizden bir söz istiyorum. Bu bilgi ile yürüteceğiniz proje hakkında kısa bir bilgi, bilgiyi aldıktan sonra da sonuç hakkında geri besleme istiyorum. Emeğimin faydalı bir sonuca yol açıp açmadığını bilmek istiyorum. Bu mütevazi koşul size uygun geliyorsa yanıtınızı aldıktan sonra istediğiniz bilgileri verebileceğim. Anlayışınız için teşekkür ediyorum.
      Selamlarımla,

      1. Selcuk Bey merhabalar,
        Mühendislik son sınıf ogrencisiyim eger izniniz olursa çalışmanızın ayrıntılarını benle paylaşırsanız cok müteşekkür olurum . Bana fikir vermesi acısından cok faydalı olabilir, aynı zamanda okulda PID kontrol üzerine proje aldım projemi gelistirme acısından cok yardımı dokunabilir.

        1. Ömer Bey merhaba,

          Yayına tekrar baktım da, her şeyi tüm ayrıntılarıyla paylaşmış durumdayım. Bunların dışında özellikle anlaşılmayan bir nokta var ise yardımcı olmaya çalışayım.

          Selamlarımla,

      2. Merhaba Selçuk Bey , ben mühendislik öğrencisi son sınıfım . Bu konular üzerinde çalışıyorum bana yardımcı olması açısından kaynak kodlarını paylaşırsanız çok müteşekkür olurum

        1. Kayra kardeşim, yayında kodları tüm ayrıntılarıyla vermiş durumdayım. Bundan öte ne verebilirim bilemiyorum. Birşeyler yapmaya çalışıp takıldığın yerde spesifik olarak sorarsan yardımcı olmaya çalışayım.

          Selamlarımla,

  1. Öncelikle merhaba hocam
    Hocam diyorum çünkü sitenize ufak bir göz attım projeleriniz çok spesifik ve çok güzel elinize sağlık.
    Hocam soruma gelecek olursam burada siz potansiyometreden aldığımız bir hızı sabit olarak bozucu etkilere rağmen döndürmeyi göstermişsiniz. Ben ise bir gyro sensörden aldığım verilerle bir drone’u havada stabil tutmayı amaçlıyorum. Burdaki projeyi ona nasıl uyarlayabilirim. Fikir verebilir misiniz?
    Saygı ve selam ile …

    1. Hüseyin Bey, siteme göstermiş olduğunuz ilgi ve övgüleriniz için teşekkür ederim.
      Drone’larla hiç ilgilenmedim, hatta elime alıp uçurmadım bile. Drone geliştirmek ile uğraşmış bir arkadaş daha yardımcı olabilir sanırım, ama prensipler üzerinden birkaç şey söyleyebilirim.
      Diyelim ki drone’u yatay tutmak istiyorsunuz ve bunu tek bir motoru kontrol ederek yapabileceksiniz. Şunu da ekleyeyim, dronu yatay tumak için tek motor değil, karşılıklı çalışan iki motor çiftini kontrol etmek zorundasınız. Neyse, diyelim ki sizin dronunuz Y ekseni doğrultusunda zaten yatay durumda ve siz X eksenini yatay duruma getirmek istiyorsunuz.
      Gyro/ivme sensörünüzle X ekseninin yataydan ne kadar saptığını ölçeceksiniz, bu sizin “hata” faktörünüz. Bunu sıfırlamak üzere ayarlamalar yapacaksınız. Bu işlemin benim yayınımda yapılandan bir farkı yok. Ben motor hızının istenen değerden sapmasını hata faktörü olarak alıyorum, siz ise X ekseninin yataydan sapmasını hata faktörü olarak alacaksınız. X ivme değerini tam yataya karşı düşen “0” (ya da, sensörünüzün yerleştirilişine göre 9.8m/s) yapmak üzere X eksenindeki motor çiftinden birsinin hızını düşürürken diğerininkini arttıracaksınız. Bu işlem için motor hızındaki değişimi değil, X eksenindeki ivme değişikliğini ve Y eksenindeki açısal ivme (gyro) değerlerini izleyerek Oransal, Entegral ve Türevsel düzeltme faktörlerini hesaplayacaksınız. Motor hızı bir yan faktör olarak hesabınıza katılabilir, hızın çok düşüp dronun düşmesine engel olmak için.

      Umarım faydası olmuştur.

      Selamlarımla,

      1. Hüseyin Bey,

        Konuyu biraz daha açarsam, yükseklik kontrolu için motor devir hızını ayarlayan bir PID çevrimi, eğim kontrolu için de ilk mesajımda anlattığım gibi X ekseninin iki motoru arasındaki devir farkını ayarlayan bir ikinci PID kontroluna ihtiyacınız var. Y yönü kontrolu için de bir üçüncü PID gerekecek.

        Benim yayınımda potansiyometre ile verilen hedef değer girişinin yerine drone uygulamasında kablosuz kontrol cihazından gelen hedef eğim – yatay konum için ‘0’ ya da ‘9.8’- değeri olacak. Drone’u bir yöne doğru iletmek istediğinizde bu değerler ‘0’ ya da ‘9.8’ değil arada bir şey olacak ki dronunuz gidiş yönünüze göre eğim alsın.
        Eğer bu çalışmalarda yeni iseniz drone ile başlamamanızı öneririm, çok çetin bir konu, moraliniz bozulup başlamanızla vazgeçmeniz bir olur. İyisi mi önce bir ucundan bağlı tahta çubuğu servo motor ile yatay konumda tutmakla işe başlayın. Elbette servo motoru “şu açıya gel” şeklinde bir PWM ile sürerek değil de, bir ivme ölçer ile yataydan sapmasını ölçerek PID kontrolu ile yapacaksınız bu işi.

        Vakit bulabilirsem drone olmasa da bu önerdiğim şekilde bir çalışma yapıp blog siteme koyabilirim. Hatta bunu önce tek eksen, ardından da iki eksenli çalışır hale getirmeyi deneyebilirim. Yani bir çubuğu yatay tutmak değil, bir levhayı yatay tutmak şeklinde. Hatta sadece yatay değil, istenen herhangi bir açıda tutmak hedeflenebilir. Bence siz de böyle adım adım ilerlemelisiniz.

        Kolay gelsin.

        1. Hocam çok teşekkür ederim ilgilendiğiniz için.
          Araştırmalarıma verdiğiniz bilgiler doğrultusunda tekrar başlicam. İyi çalışmalar…

  2. Hocam saygılar,
    Projeyi benimle paylaşabilir misiniz rica etsem. Yukarıda istediğiniz sözü veriyor ve tek ders projem sonrası size gerekli dönüşü yapacağımı belirtmek istiyorum. Teşekkürler saygılar.

  3. Bu açıklayıcı bilgiler için size çok teşekkür ederiz hocam. Yüksek lisans projemiz olan “Otonom Kara Aracı” projemizde motor hızını ayarlamak için sizin bilgilerinizden yararlandık. Size çok teşekkür ederiz.

  4. Merhaba hocam paylaşımınız için teşekkür ediyorum öncelikle.Ben bitirme projem bu konu ile ilgili.Rica etsem proje ayrıntılarını ve kodları paylasabilir misiniz? Mesajınızda belirttiğiniz şartı sağlayacağımdan şüpheniz olmasın geri dönüş yapacam size.Şimdiden teşekkür ederim

    1. Mesut Bey merhaba,
      Şu günlerde çok meşgulüm, bana biraz zaman verirseniz ilgileneceğim. Selamlarımla.

    2. Mesut Bey, bu arada vakit kazanmak için aşağıdaki çalışmaları yapıp sonucunu bildirir misiniz?

      1) STM32 ile bir Timer kullanarak PWM üretilmesi
      2) Bu PWM sinyalinden yararlanarak bir DC motorun sürülmesi
      3) Bir ADC kullanarak bir potansiyometrenin orta ucundaki gerilimin ölçülmesi
      4) Ölçülen gerilim ile orantılı olarak PWM oranının değiştirilmesi
      5) Bir timer in “input capture” fonksiyonundan yararlanarak girişine gelen bir darbenin süresinin ölçülmesi.

      Bu konularda biraz çalışma yaptıktan ve sonuçlarını paylaştıktan sonra kodlarımı paylaşırım. Önce bunları yapmayı öğrenmeniz lazım, bunun için de zorlandığınızda yardımcı olmaya hazırım.

      Selamlarımla,

  5. Selçuk Bey merhaba iyi çalışmalar.
    Web sitesindeki görsellerinin hepsi kaldırılmış durumda bunun düzeltilmesini sağlamanız mümkün mü?

    1. Ne zaman oldu bu bilemiyorum, siz söyleyince haberim oldu. Blog Press’e ilettim, bakalım ne diyecekler.
      Slm

    1. Mehmet Bey merhaba,

      Yayına tekrar baktımda, bu sürece ilişkin tüm fonksiyon ve kodları zaten vermişim. Deneyip takıldığınız bir yer mi var?

      Selamlarımla,

  6. Selçuk Bey, öncelikle örnek niteliğindeki çalışmanız için teşekkür ederim. Gömülü sistemler konusunda gelişimimde PID control ile bir sistem kontrol etmenin önemli bir adım olacağını düşünüyorum . Bu konuda ilerlerken sitenize rastladım ve incelemedim. Acaba çalışmayı benimle paylaşma şansınız var mı? Şu an yapmaya çalıştığım ve bir sonraki adım olarak yapmak istediğim projeler için kaynak olarak kullanmayı planlıyorum. Belirttiğiniz şartı sağlayacağım. Kendim birkaç deneme yaptım fakat kodumu oluşturamadım, sizin çalışmanızın projeme büyük katkılı olacağını düşünüyorum. Teşekkürler…

    1. Ömer bey günaydın,

      Siteme ilginiz için teşekkür ediyorum.

      Şu an çok yoğun bir çalışmanın içindeyim. Yayınlamak istediğim yeni konular var, onlara dahi vakit bulamıyorum. O nedenle gündemimdeki işler biraz hafifleyince haberleşelim derim. O zamana kadar siz de biraz daha yol almış olursunuz, daha spesifik sorunlarınız üzerinde yardımcı olurum. Şu anda ne yaptığınızı, ne seviyede olduğunuzu, hangi noktaya kadar ilerleyip takıldığınızı bilmiyorum. Örneğin motor sürmek için bir PWM üretebiliyor musunuz? Motoru bundan yararlanarak döndürebiliyor musunuz? Bunun için gereken sürücü devreleriniz var mı? Devir sayısını Timer’ları kullanarak ölçebiliyor musunuz? ADC leri kullanabiliyor musunuz? Bunları yapabiliyorsanız zaten bir sorununuz olmaması gerekir. Yok herhangi birisini yapamıyorsanız sadece o konuya odaklı bir çalışma yaparak ilerlemelisiniz. Körü körüne toplayıp gödereceğim bir kod bu işleri öğrenmeniz için bir destek değil, engel oluşturacaktır, bana inanınız.

      Selamlarımla,

      1. Tekrar Merhabalar Selçuk Bey,
        Öncelikle ilginiz ve açıklayıcı tavrınız için teşekkür ederim. Düşüncelerinize katılıyorum sanırım benim için en uygun öğrenme süreci bu sorunlarla yüzleşerek öğrenme süreci olacak. Şu an motorumu gerek devre olarak gerek yazılımsal olarak sorunsuz bir şekilde hareket ettirebilmekteyim, PID işleminin matematiğine de hakim olduğumu düşünüyorum ve araştırmalarımı sürdürüyorum. Kodu oluşturmak için biraz üstüne düşmem gerektiğini farkettim. Bu konudaki tavsiye ve önerilerinizi dikkate alacağımdan şüpheniz olmasın. Gelecek çalışmalarınızı merakla bekliyorum, başarılar dilerim 🙂

  7. Merhabalar Sn. Selçuk Hocam, içeriklerinizin çoğunu çok beğeniyorum. Lütfen sizin gibi ustalarımızdan daha çok istifade etmemiz için know-how bilgilerinizi-tecrübelerinizi kaliteli içeriklerle bize daha fazla sunmanızı talep ederim. Konuyla alakalı olarakta bir bldc motor controller tasarladım , fakat yazdığım yazılımdan kaynaklı olarak sürekli iki mosfet açılıyorve sonuç hüsran ile bitiyor. Yazılımımı düzenledim mikroişlemcinin datasheetini daha ayrıntılı inceledim , herşeyi tekrardan düzenlendim , devremi onardım. Fakat test etmeden önce sizlerden projenizi yukarıda belirmiş olduğunuz söze tabi olarak rica edeceğim.

    Saygılarımla ,
    Ömer KARSLIOĞLU

    1. Ömer Bey merhaba,

      Bir ara fırsat bulduğumda kodlarımı paketleyip göndereyim ama bu vakit alacak. Biraz yoğunum.

      Her bir MOSFET çiftinin aynı anda iletime geçmesi Timer fonksiyonlarının ayarlarında bir sorun olduğunu gösteriyor. Timer ayarlarında “dead time” özelliğini etkinleştirmiyor olabilirsiniz. Bir başka ihtimal de akım sınırlaması yapmadığınız için motor herhangi bir nedenle dönmeye başlayamıyorsa bu durumda akacak yüksek akımlardan dolayı MOSFET’lerin yanması olacaktır.
      Yorumunuzu “DC motor sürmek” başlıklı yayına koyduğunuz için benim BLDC sürme konusundaki yayınıma bakıp bakmadığınızdan emin olamadım. Ben mosfet leri özel sürücü entegreler ile sürüyordum ve böyle bir sorunla karşılaşmamıştım. Bu nedenle büyük ihtimalle sizin donanımınız ile benim kodlarım uyumlu olmayabilir.

      Selamlarımla,

      1. Tekrardan merhabalar Sn. Selçuk Hocam ,

        mosfetlerimi ir2110 gate driver’lar ile sürüyorum. Mosfetlerimin yanma sebebi timer biriminin ilgili registerlarında CCxNP bitinde polarını ayarlayarak mosfetleri deactive duruma düşürmeye çalıştığımdan dolayı olmaktaydı. Şuanda pwm’i 0 olarak ayarlayarak mosfetleri deactive duruma düşürdüm. Akım sınırlayıcı devresi maalesef bulunmamakta kartın ikinci revizyonunu tasarladığım zaman eklemeyi planlamaktayım.

        Saygılarımla,
        Ömer KARSLIOĞLU

        1. Ömer bey merhaba,

          Sorununuzu bir şekilde PWM ayarları ile halletmiş olduğunuz izlenimi edindiğimden pek üzerinde durmamıştım. Ama merak ettim CCxP ve CCxNP bitlerini ne şekilde ayarladınız da MOSFET leriniz yandı? Dead time süresini nasıl ayarlamıştınız?

          Selamlarımla,

          1. Merhabalar Selçuk Hocam ,

            Yanlış hatırlamıyorsam CCxP ve CCxNP bitlerini 0’a çekmiştim pinler kararsız kalıyorudu. Kararsız kalması sonucunda mosfetler aynı anda açık kalabiliyor ve yanabiliyorlardı. Deadtime süresi için projeye tekrar bakmam lazım.

            Saygılarımla,
            Ömer Karslıoğlu

          2. Tamam, ben de bu ayarlarla bir kurulum yapıp bakayım, sonuçları sizinle paylaşırım.

            Selamlar,

  8. Hoam merhaba, selçuk üniversitesi elektrik elektronik mühendisliği 3. sınıf öğrencisiyim, teknofest için elektrkli araç kategorisine hazırlanıyoruz yarışma için projenizdeki kodlardan faydalanmak istiyorum kodlara ulaşabilme şansım varmıdır hocam.
    Saygılarımla.

    1. Ali Talha bey merhaba,

      Geri dönüşümdeki gecikme için kusura bakmayın, biraz yoğunum. Blog sitemdeki yayınıma tekrar baktım da, tüm fonksiyon kodları ve proje ayarlarını vermiş durumdayım. Özellikle eksik olduğunu gördüğünüz bir fonksiyon varsa yardımcı olayım.

      Selamlarımla,

  9. Hocam saygılar,
    Projeyi benimle paylaşabilir misiniz rica etsem. Yukarıda istediğiniz sözü veriyor ve Mikrodenetleyiciler ders projem sonrası size gerekli dönüşü yapacağımı belirtmek istiyorum. Teşekkürler saygılar.

    1. Burak Bey, şu ana kadar neler yaptınız, hangi noktaya kadar geldiniz? Takıldığınız yer neresi?

      Bu bilgilerden sonra göre daha fazla yardımcı olabilirim sanırım.

      Selamlarımla,

      1. ADC, Timer ve I2C kullanarak bir uygulama yapmaya çalışıyorum fakat internetteki uygulamalar yeterli olmuyor. Mesela kestirme kullanarak servo motor döndürmek istiyorum fakat servoyu döndürmek için bir timer kullanmam gerekiyor. EXT1 in içine servo fonksiyonunu stm32f1xx_it.c’ye yazdığımda timer girmediğimi söylüyor fakat timer config dosyaları zaten mainde yer alıyor. bu sorunu da çözemedim. Sizin projenize benzer proje yapmaya çalıştım fakat çok zorlanıyorum yaparken. 2 gün içinde sunum yapmam gerekiyor. Dosyaları benimle paylaşabilirseniz çok sevinirim.

        1. Aynı zamanda LCD’m çalışmıyor. Ne kadar I2C kütüphanesi bulabildiysem hepsini denedim fakat string yollayamıyorum lcd’ye. data geliyor fakat okunabilir bir yazı çıkmıyor ortaya. Farklı bir STM kartı denesem de sonuç aynı.

  10. Merhaba Selcuk bey pid kontrol ile sıcaklık ve motorun hızını kontrol etmek istiyorum yardımcı olailir misiniz ? Bu konuda çalışmalarınız olacak mı

    1. Süleyman Bey merhaba,

      Yorum yaptığınız bu yayın zaten PID kontrolu altında motor sürmeye yönelik değil mi?

      PID kontrol altında motor sürülmesi konulu bundan başka 3-4 yayınım daha var, onlara da bakabilirsiniz. Örneğin 3 bölümlük bir yayın olan “Bir çubuğu PID kontrolu ile istenen açıda tutmak”.
      Sıcaklık kontrolu için de bir uygulamam var ama yayınlamamıştım, ilk fırsatta yayınlarım.
      Selamlarımla,

  11. Selçuk Bey, Merhabalar
    Bu değerli bilgileri bizimle paylaştığınız için teşekkür ederiz. Değişken yük altında sabit devirle çalışan motor projemiz için, çalışmalarınızdan yararlanmak istiyoruz. projenizin içeriğini paylaşırsanız memnun oluruz.

  12. Merhaba sayın hocam. Çalışmanız şu an okulda yapmaya çalıştığım projeye benzer. Eğer referans olması açısından kodlarınızı paylaşabilirseniz çok makbule geçer. Çalışmam bittiğinde ise size bilgi vermek ve konu hakkında tartışmak isterim.

    1. Hasan Bey merhaba,

      Kodları paket olarak paylaşmak malesef benim için külfetli oluyor. Zira makinamdaki kodlar içinde sadece anlattığım konuya ait olanlar değil, üzerinde çalıştığım pek çok başka işe ait kodlar, notlar, bazıları fikri mülkiyet kaygıları taşıyan algortimalar yer alıyor. Bunları başkalarına verilebilir hale getirmek için ayıklamak zor oluyor.

      Konuyu ilgilendiren kısımları blog yazısı içinde zaten veriyorum. Projeye girişip takıldığını yerlerde bana yazarsanız memnuniyetle yardımcı olurum.

      Selamlarımla,

  13. Selçuk Bey merhaba, iyi çalışmalar. Bunu izin verirseniz okulda bir projem olarak yapmak istiyorum. Birkaç sorum olacak. DC motorun üstüne taktığınız çarkın dişlilik sayısının ya da aralığının bir önemi var mı? Ve çarkın çapı önemli mi? Mıknatısın sensöre yakınlığı ne seviyede olması gerekmektedir? Herhangi bir voltajda DC motor uygun olur mu? Detaylı bir şekilde projeyi benimle paylaşabilir misiniz? Teşekkür ederim.

    1. Berkay bey merhaba,

      Sorularınız henüz işin çok başında olduğunuzu gösteriyor. Mıknatısın motorun her devrinde bir sinyal üretmek için konulduğunu görüyorsunuz. Bu durumda bunu taşıyan plastik silindirin çapının, bunun üzerindeki diş sayısının hatta diş olup olmamasının hiçbir önemi olmadığını görebilirsiniz.
      Bu mıknatısın hall effect sensörü tetiklemesi için 1-2 mm yakınınından geçmesi gerekir. Projeyi zaten tüm detayları ile paylaşmış durumdayım, daha fazla hangi detaya ihtiyacınız var ise özellikle belirtirseniz yardımcı olmaya çalışayım. Ama önce konuya biraz kafa yorup kavramaya çalışın.

      Selamlarımla,

  14. Merhaba,
    Projemde kullandıktan sonra geri besleme vermeye çalışacağım. Rica etsem kodu paylaşabilir misiniz?

    1. Osman Bey merhaba,

      Çok yoğun durumdayım, bu nedenle artık kod paylaşım taleplerine olumlu yaklaşamıyorum maalesef. Yayınlarımda kodlama için gereken kilit bilgileri ve programların neredeyse tamamını veriyorum zaten. Ancak belirli bir sorunu ya da sorusu olup bunu ileten arkadaşlara öncelik verip yardımcı olmayı tercih ediyorum. Bir şeyler yapıp da bir noktada takıldı iseniz, yardımcı olmaya her zaman hazırım.

      Selamlarımla,

  15. Merhaba, Üniversitemizde bldc motor sürücü projesi üzerinde çalışan öğrencileriz. Rica etsem kodu bizimle paylaşabilir misiniz? Bir de sorum olacak. Hall effect’e göre motor sürüyoruz, işin içine geri beslemeyi nasıl katarız?

    1. Halit Bey merhaba,
      Malesef bir süredir yayınlarımda zaten vermiş olduğumun ötesinde kod paylaşmaya son verdim. Zira, yayında önemli kod bölümlerini hatta, platform ayarlarını olabildiğince veriyorum. Ayrıca “kod paylaşmak” benim için çalışmanın tekrarı oluyor ve bunun öğrenci arkadaşlara bir yararı olduğunu sanmıyorum.

      Selamlarımla,

  16. Merhaba Selçuk Bey.
    Kodları yazıp derledim ve bir hata ya da uyarı ile karşılaşmadım. Ancak karta yükleyip tasarladığım motor sürücü kartına taktığım zaman motorda dönme hareketi gözlemleyemedim. PWM üretmesi gereken timer kanalını ölçtüğümde lojik 1 gibi davrandığını gördüm. Sizce sebebi ne olabilir.

    1. Hasan Bey merhaba,

      PWM sinyalini nasıl ölçüyorsunuz, osiloskop ile mi? Multimetre ile ölçmeye kalkışıyorsanız bu sizi yanıltır.
      Eğer PWM sinyaliniz sürekli “1” seviyesinde kalıyor (yani motora %100 PWM uyguluyorsunuz) ve motor dönmüyorsa sürücünüzde bir sorun var demektir. Sürücünüz ile ilgili daha fazla bilgi verirseniz bakabilirim. Bunun için [email protected] adresine yazabilirsiniz.

      Selamlarımla,

  17. Merhaba Selçuk Hocam,
    Kodu derleyip çalıştırdığımda motor en yuksek hızda dönüyor lakin potansiyometre ile hızını ayarlayamiyorum (tepki vermiyor). Sizin aksine ben tek turlu 10k pot kullandım. Ayrica enkoder olarak kullandigim motorun arkasındaki optoswitchi kullanmaya çalışıyorum ve bu sizin kullandığınız hall effect sensörünün aksine her turda bir kere değil bir turda birden fazla darbe üretiyor( optoswitchi arasında motor miline bağlı bir disk var ve diskte pek çok delik var). Sizce hatam nerdedir? Ayrıca kodları paylaşma imkanınız varsa çok iyi olur belki bir şeyleri atılıyorumdur.
    İyi günler.

    1. Emrah Bey merhaba,

      Adım adım ilerlemekte yarar var. Porgramınızı ADC okumasının yapıldığı yerde duraklatarak okunan değerin potansiyometre konumunu iizlediğinden emin olmalısınız.

      1) Potansiyometre gerilimini ADC ile doğru olarak okuyabiliyor musunuz? Bunun için sadece ASC okuması yapan bir while çevrimi kullanmanızız iyi olur.

      2) PWM sinyalini doğru olarak üretebiliyor musunuz? PWM sinyalini görüntüleyebileceğiniz bir osiloskopunuz var mı?

      Bunlar için önce PID kontrolunu devre dışı bırakıp potansiyometre ile değiştirebildiğiniz bir PWM üretmeye ve motoru bu sinyal ile sürmeye odaklanmalısınız. PID kontrolunu bunu başardıktan sonra devreye sokarsınız.

      Bundan sonrası için bana [email protected] adresi üzerinden başvurabilirsiniz.

      Selamlarımla,

  18. Selçuk hocam,
    merhaba, size yazmayalı çok oldu.depremdi , tayindi vs baya ara vermek zorunda kaldım.

    Hocam, size bir sorum olacak
    microdenetleyici ile bldc motor kontrolünde ,Hall sensörden okuduğumuz veriye göre,sadece Hız bilgisi değil en önemli konu olan Komutasyonu da sağlıyoruz
    ancak,capture girişlerine bağlaln Hall sensör uçlarından gelen bilgi,ham bilgidir,Capture modunda yükselen Kenar – Düşen Kenar algılanıyor,biz bu bilgiyi Capture Registerine nasıl yüklüyoruz ve Komutasyonu hangi Registerlerle sağlıyoruz

  19. bilmiyorum ifade edebildim mi
    hall sensörden okuduğumuz ham veriyi capture registerine nasıl kodluyoruz ki bu veri anahtarlama sırası için ilgili registerlere aktarılıyor

    1. Mehmet Ali Bey merhaba,

      Sorunuzu anlayamadım. Ham bilgiden ne kastediyorsunuz? Timer girişine HAL effect switchden sinyal gelince TIM3 bir kesme sinyali yayınlayıp o andaki sayaç değerini de capture registerine aktarıyor, biz de bu değeri okuyup kullanıyoruz. Ham veriyi capture registere aktarmak gibi bir işlem yok, o işlemi TIM3 kendiliğinden yapıyor.

      Selamlarımla,

      1. Cevap için teşekkür ederim, Hall1=010 ise aktif pwm cikisi T1 ve T4 numarali anahtarlar
        Hall2=110 ise T1 ve T2 numarali anahtarlar aktif oluyor, Hall1,2 ve 3 numarali sensörlerden gelen bu sinyali capture registerlerine 010 – 110- 100 – 101 – 001 – 011 olarak yükleyemiyoruz ,bunun yerine kesmeleri kullaniyoruz, bu durumda uretilen kesme bu kodu nasil temsil eciyor,zira Hsll1=010 bana T1-T4 çikişlarini enable yap diyor.bu Hall bilgisine göre Timx_Enable registerindeki CCxE ve CCxNE bitlerine iletime geçecek anahtar gruplarini yükleyecrgim
        Ama, 3 kesmeden hangisi Hall1, hangisi Hall2 ,Hall3
        Zaman ayirdiginiz icin cok sagolun,yazilarinizdam meşgul olduginuzu anliyorum , kolay gelsin

    1. Mehmet Ali Bey merhaba, açık çevrimde BLDC motor sürmek hakkındaki sorularınızı PID kontrol altında DC motor sürmek konulu yayına yazınca karıştırdım.
      Ben BLDC sürme deneyimde HALL effect sensörlerle konum okuması yapmadım, hatta hiçbir şekilde konum okuması yapmadım. O konuyu ileriye bırakmıştım ama dönüp devam edecek vaktim de olmadı.
      Capture registere sadece okuma yaparak çalıştığımız bir register, içine birşeyler yazmamız söz konusu değil. Hall effect sensörlerden gelen bilgileri kesmeler ile algılayıp komütasyonu sizin yapmanız gerekiyor. İşin bu yönünü denemediğim için daha fazla bir şey söylemem mümkün değil. BLDC ile ilgili olarak verdiğiim referans yayınlarda güzel anlatıyorlar aslında.
      Yoğunluk nedeni ile daha fazla yardımcı olamıyorum, kusura bakmayın.

      Selamlar,

      1. Selçuk hocam,
        cevabınız için teşekkür ederim , sitenizden çok şey öğrendim, bilhassa pid kontrolün mantiğını çok güzel anlattınız,
        Capture registeri, kesme gelince bunu logic 1 olarak mi kaydediyor, capture registerine , Hall sensör sinyalleri capture registere kayıt edilemez ,sadece hall sinyal tetiklemesi ,, kesme olarak olarak yakalanir-algilanir
        Doğru mu anladım, Selçuk Hocam .

Comments are closed.