Arkadaşlar Merhaba bir PM senkron motoru kontrol etmeye çalışıyorum fakat yaşadığım bazı aksaklıklar ve kafamda soru işaretleri var. Araştırmalarımda pratik bilgiden çok teorik bilgi mevcut ve bunun uygulamada pek bir yararı olmuyor. kodların bir kısmını tamamladım ve test yaparak sisteme dahil etmeye çalışıyorum Aşağıya kullandığım kod bloklarını bırakıyorum.
Kullandığım motor 140TAST-01F2H4P ve PM5182029. iki motorda 83.3 hz 220v 1024 ppr enkoder mevcut.
sinüs ve cosinus hesaplamaları için bir lut tablosu oluşturdum. Doğruluğunu kontrol ettim. SVPWM koduna sırası ile 0 dan 360 a kadar değer gönderdim ve sonucunda ürettiği Ta,Tb ve Tz sürelerini bir excel de sektörlere göre hesaplayıp çıkan grafiği kontrol ettiğimde tam olarak istediğim sinyalleri görmekteyim (60 derecede bir sektör değişimi gerçekleştirdim).
Soruma gelirsek;
Biz sektörleri belirlerken elektriksel açı kullanıyoruz.
Elimdeki motora bakarsak sabit 20 mıknatıs ve 18 iç sargı mevcut. Manyetik kutup çifti göz önüne
alındığında dışta 10, içte 9 çift manyetik alan oluşturacak eleman var.
Delta fi = 360/9 - 360/10 = 360/90 = 4 derece
Her bir 360 derecelik 3 fazlı döngüden yola çıkarsak;
İç bobinin tam turluk dönüşü 360/9 =40 derece ve sabit mıknatısların 360 /90 = 4 derece dönmüş olur.
Arada 10 katlık bir yavaş dönüş farkı var
360/10= 36 derece yani sonuç olarak U, V, W sargılarına yapılacak her 360 derecelik bir faz döngüsü sonunda motor
tam olarak 36 derece döner. (bu hesaba bir forumda veya makalede denk gelmiştim nerede bulduğum konusunda tam emin değilim)
36 derecelik bir rotor hareketi için 360 derecelik elektriksel çevrim yapmak zorundayım. motor her meknaik turda 1024 pulse üretiyor ve her 36 turda 102,4 pulse tekamül ediyor ( pulse değeri tam sayı olduğu için aslında 102 pulse okuyorum). Ben bu 102 pulse içine 360 derecelik elektriksel dönüş sığdırmak zorunda kalıyorum buda bazı değerlerde kayıp yaşadığım anlamına geliyor yani her bir pulse artışında çoktan 3,52 derece geçmiş oluyor. 36 derecelik mekanik harekette 6 sektör sığdırmam lazım ve buda her sektörün 6 derecelik mekanik açıya denk gelmesi demek. Her pulse artışında 3,52 derece yol alırsam her sektörü maksimum 2 parametre sağlamış oluyorum buda kayıplara yol açıyor. Bunun önüne geçmek için enkoder ppr değerini artırmammı gerekli yoksa hesaplarımda bir hatamı mevcut? atladığım bir nokta veya hatam var ise düzeltirseniz sevinirim.
Motora elektriksel açı yerine doğrudan mekanik açıyı verdiğimde ve sektör olarak 60 derecede bir değişim yaptığımda aşağıdaki videolardaki hareketi almaktayım fakat burada da bazı sıkıntılar mevcut( açıyı her turda z pulse i geldiğinde sıfırlıyorum ve +7 eklemek zorunda kalıyorum bunları yapmadığım zaman istediğim hareketi alamamaktayım. aşağıdaki videodan açı eklenmesinin motora etkisi görülmektedir (sadece svpwm fonksiyonu çağırılmıştır ve magnitute değeri 1 verilmiştir, açı girişine doğrudan enkoderden okunan veri girilmiştir).
drive.google.com
Biraz uzun ve karışık olduğunun farkındayım umarım derdimi anlatabilmişimdir. Bu konu haricinde daha önce bu motorun kontrolünü yapan var ise aşağıdaki kodlarımı kontrol ederse çok memnun kalırım. Teşekkürler iyi çalışmalar.
Kullandığım motor 140TAST-01F2H4P ve PM5182029. iki motorda 83.3 hz 220v 1024 ppr enkoder mevcut.
sinüs ve cosinus hesaplamaları için bir lut tablosu oluşturdum. Doğruluğunu kontrol ettim. SVPWM koduna sırası ile 0 dan 360 a kadar değer gönderdim ve sonucunda ürettiği Ta,Tb ve Tz sürelerini bir excel de sektörlere göre hesaplayıp çıkan grafiği kontrol ettiğimde tam olarak istediğim sinyalleri görmekteyim (60 derecede bir sektör değişimi gerçekleştirdim).
Soruma gelirsek;
Biz sektörleri belirlerken elektriksel açı kullanıyoruz.
Elimdeki motora bakarsak sabit 20 mıknatıs ve 18 iç sargı mevcut. Manyetik kutup çifti göz önüne
alındığında dışta 10, içte 9 çift manyetik alan oluşturacak eleman var.
Delta fi = 360/9 - 360/10 = 360/90 = 4 derece
Her bir 360 derecelik 3 fazlı döngüden yola çıkarsak;
İç bobinin tam turluk dönüşü 360/9 =40 derece ve sabit mıknatısların 360 /90 = 4 derece dönmüş olur.
Arada 10 katlık bir yavaş dönüş farkı var
360/10= 36 derece yani sonuç olarak U, V, W sargılarına yapılacak her 360 derecelik bir faz döngüsü sonunda motor
tam olarak 36 derece döner. (bu hesaba bir forumda veya makalede denk gelmiştim nerede bulduğum konusunda tam emin değilim)
36 derecelik bir rotor hareketi için 360 derecelik elektriksel çevrim yapmak zorundayım. motor her meknaik turda 1024 pulse üretiyor ve her 36 turda 102,4 pulse tekamül ediyor ( pulse değeri tam sayı olduğu için aslında 102 pulse okuyorum). Ben bu 102 pulse içine 360 derecelik elektriksel dönüş sığdırmak zorunda kalıyorum buda bazı değerlerde kayıp yaşadığım anlamına geliyor yani her bir pulse artışında çoktan 3,52 derece geçmiş oluyor. 36 derecelik mekanik harekette 6 sektör sığdırmam lazım ve buda her sektörün 6 derecelik mekanik açıya denk gelmesi demek. Her pulse artışında 3,52 derece yol alırsam her sektörü maksimum 2 parametre sağlamış oluyorum buda kayıplara yol açıyor. Bunun önüne geçmek için enkoder ppr değerini artırmammı gerekli yoksa hesaplarımda bir hatamı mevcut? atladığım bir nokta veya hatam var ise düzeltirseniz sevinirim.
Motora elektriksel açı yerine doğrudan mekanik açıyı verdiğimde ve sektör olarak 60 derecede bir değişim yaptığımda aşağıdaki videolardaki hareketi almaktayım fakat burada da bazı sıkıntılar mevcut( açıyı her turda z pulse i geldiğinde sıfırlıyorum ve +7 eklemek zorunda kalıyorum bunları yapmadığım zaman istediğim hareketi alamamaktayım. aşağıdaki videodan açı eklenmesinin motora etkisi görülmektedir (sadece svpwm fonksiyonu çağırılmıştır ve magnitute değeri 1 verilmiştir, açı girişine doğrudan enkoderden okunan veri girilmiştir).
20250422_091149_1.mp4

Biraz uzun ve karışık olduğunun farkındayım umarım derdimi anlatabilmişimdir. Bu konu haricinde daha önce bu motorun kontrolünü yapan var ise aşağıdaki kodlarımı kontrol ederse çok memnun kalırım. Teşekkürler iyi çalışmalar.
Kod:
void motor_control_loop() {
// //Clarke dönüşümü (örnek akım değerleri kullanılabilir)
// clarke_transform(Akim_U, Akim_V, Akim_W, &motor.ialpha, &motor.ibeta);
// // Park dönüşümü
// park_transform(motor.ialpha, motor.ibeta, motor.theta, &pid.id, &pid.iq);
// //PI Kontrol (hata hesapla ve kontrol et)
// pid.vd = pi_controller(pid.kp, pid.ki, current.id_ref - pid.id, &pid.integral_id, pid.dt);
// pid.vq = pi_controller(pid.kp, pid.ki, current.iq_ref - pid.iq, &pid.integral_iq, pid.dt);
//Ters Park dönüşümü
// inverse_park_transform(pid.vd, pid.vq, encoder.angle, &motor.valpha, &motor.vbeta);
//Gerilim vektörünün büyüklüğü ve açısını hesapla
// motor.magnitude = sqrtf(motor.valpha * motor.valpha + motor.vbeta * motor.vbeta);
// V_angle = atan2f(motor.vbeta, motor.valpha) * RAD2DEG; // Atan fonksiyonu radyan cinsinde çıkış verdiği için dereceye çevirildi.
// if (V_angle < 0)
// {// -180 ile +180 arasında çıkış verdiği için düzeltme gerçekleştirildi.
// V_angle += 360.0f;
// }
//SVPWM fonksiyonunu çağır
svpwm(V_angle, motor.magnitude);
}
Kod:
// PI Kontrol Fonksiyonu
float pi_controller(float kp, float ki, float error, float *integral, float dt) {
*integral += error * dt;
return kp * error + ki * (*integral);
}
// Clarke Dönüşümü
void clarke_transform(float a, float b, float c, float *alpha, float *beta) {
*alpha = a; // Basitleştirilmiş versiyon
*beta = (b - c) / Square_3;
// Clarke->Ialpha = Currents->Iu;
// Clarke->Ibeta = SQRT3_OVER_1 * (Currents->Iu + 2.0f * Currents->Iv);
//#define SQRT3_OVER_1 0.57735027f
}
/*
* Park Dönüşümü
*/
void park_transform(float ialpha, float ibeta, int theta, float *id, float *iq) {
float sin_AngR = sin_LUT[theta];
float cos_AngR = cos_LUT[theta];
*id = ialpha * cos_AngR + ibeta * sin_AngR;
*iq = -ialpha * sin_AngR + ibeta * cos_AngR;
}
/*
* Ters Park Dönüşümü
*/
void inverse_park_transform(float vd, float vq, int theta, float *valpha, float *vbeta) {
float sin_AngR = sin_LUT[theta];
float cos_AngR = cos_LUT[theta];
*valpha = vd * cos_AngR - vq * sin_AngR;
*vbeta = vd * sin_AngR + vq * cos_AngR;
}
Kod:
// SVPWM Fonksiyonu
void svpwm(float angle, float Mag) {
/*
* DERECE CİNSİNDEN OLAN AÇI DEĞERİ NORMALDE RADYANA ÇEVİRİLMELİ FAKAT
* BİZ OKUDUĞUMUZ DERECEYE GÖRE DAHA ÖNCEDEN GELECEK 0 İLE 359 ARASINDAKİ TÜM DERECELERİ ÖNCE RADYANA ÇEVİRDİK
* DAHA SONRA TÜM DEĞERLERİN SİN VE COS HESABINI YAPIP TABLO HALİNE GETİRDİK.
*/
// Açıyı LUT indexine çevirme
int indeks = (int)(angle) % 60; // 0-60 arasında bir indeks üret
// LUT'ten değer çekme
float sin_AngR = sin_LUT[indeks];
float cos_AngR = cos_LUT[indeks];
Ta = ((Mag * cos_AngR ) / MOD_INDEX) - (((Mag * sin_AngR ) / MOD_INDEX) * (1 / Square_3));
Tb = ((Mag * sin_AngR ) / MOD_INDEX) * (2 / Square_3);
Tz = (1 - (Ta + Tb)) / 2;
switch (encoder.sector) {
case 1:
motor.MOTOR_U = Tz + Ta + Tb;
motor.MOTOR_V = Tz + Tb;
motor.MOTOR_W = Tz;
break;
case 2:
motor.MOTOR_U = Tz + Ta;
motor.MOTOR_V = Tz + Ta + Tb;
motor.MOTOR_W = Tz;
break;
case 3:
motor.MOTOR_U = Tz;
motor.MOTOR_V = Tz + Ta + Tb;
motor.MOTOR_W = Tz + Tb;
break;
case 4:
motor.MOTOR_U = Tz;
motor.MOTOR_V = Tz + Ta;
motor.MOTOR_W = Tz + Ta + Tb;
break;
case 5:
motor.MOTOR_U = Tz + Tb;
motor.MOTOR_V = Tz;
motor.MOTOR_W = Tz + Ta + Tb;
break;
case 6:
motor.MOTOR_U = Tz + Ta + Tb;
motor.MOTOR_V = Tz;
motor.MOTOR_W = Tz + Ta;
break;
default:
motor.MOTOR_U = Tz + Ta + Tb;
motor.MOTOR_V = Tz;
motor.MOTOR_W = Tz + Ta;
break;
}
motor.MOTOR_U *= htim8.Init.Period;
motor.MOTOR_V *= htim8.Init.Period;
motor.MOTOR_W *= htim8.Init.Period;
TIM8->CCR1 = (uint16_t)motor.MOTOR_W;
TIM8->CCR2 = (uint16_t)motor.MOTOR_V;
TIM8->CCR3 = (uint16_t)motor.MOTOR_U;
TIM8->CCR4 = htim8.Init.Period/2; // akım ölçümü için tetikleme sinyali
}