Servo senkronizasyon modülü

Sumer Yamaner

Moderator
Katılım
17 Eyl 2013
Mesajlar
8,746
Tepkime puanı
23,120
Yaş
61
Konum
İstanbul
Web sitesi
www.sumeryamaner.com
İlgi Alanı
Uçak
Hezarfen'de iki arkadaşımız 50 cc uçak topluyorlar. Birisi Edge 540. Diğeri de ona benzer bir şey muhtemelen. Uçaklarda aileronlarda çift servo var. Dolayısıyla setup biraz zorlayacak gibi. Eşek yükü ile para verip servoları almışlar ama servolar gerçekten çok kaliteli olmalarına rağmen programlanabilir türden değil. Bu da tek kontrol yüzeyine birden fazla servonun kumanda ettiği modellerde ciddi bir sorun. Çünkü en ufak bir mekanik eşitsizlik, servolardaki minik imalat fakrlılıkları falan bir servonun zorlanmasına yol açabilir. Bu da kontrol yüzeyinde burulmaya, fazla akım tüketimine ya da olmadık yerde servonun yanmasına yol açabilir. Şu an bununla ilgili makaleler okuyorum. Görebildiğim kadarıyla bu amaçla yapılmış modüller var. Örneğin:

Şimdi manualini indirip okuyacağım. Benzer bir modülü bir Arduino ile rahatlıkla yapabileceğimizi düşünüyorum. Eğer yapabilirsek iki arkadaşımdan ciddi birer hayır duası da alırız. :D
Şimdilik kafamdaki planı aşağıya yazdım. Devre için bir ön çalışma da yaptım. Takıldığım nokta temel senkronizasyon algoritması. Sadece sıfır noktasından senkronizasyon kolay olur. Ama endpointlerde senkronizasyon yapabilsek çok daha efektif olacak. Orad takılıp kaldım. Okuyacağım manual bu kpnuda bir fikir verecektir. Ne yazık ki az önce göz muayenesinden çıktığım için birkaç saat boyunca sadece yazabiliyor ama okuyamıyor olacağım. :lol: O nedenle konuyu sizlerle paylaşıp fikirlerinizi alayım dedim.

------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Bir kontrol yüzeyine bağlı üçe kadar servonun senkronizasyonu amacıyla oluşturulan Arduino projesidir.

Bağlantılar
Değişken Adı
Servo giriş D03 servoin
Servo1 çıkış D06 servo1
Servo2 çıkış D05 servo2
Servo3 çıkış D04 servo3
Mode1 buton giriş A0 mode1 Active LOW, Internal pullup
Mode2 buton giriş A1 mode2 Active LOW, Internal pullup
Increase buton giriş A2 increase Active LOW, Internal pullup
Decrease buton giriş A3 decrease Active LOW, Internal pullup
Center LED çıkış D12 centerLED
EPA1* LED çıkış D11 epa1LED
EPA2* LED çıkış D10 epa2LED
Servo1 LED çıkış D09 servo1LED
Servo2 LED çıkış D08 servo2LED
Servo3 LED çıkış D07 servo3LED

* EPA1 alt endpoint, EPA2 üst endpoint

EEPROM lokasyonları
Değişken Adı
Servo1 Center 00 servo1cnt
Servo1 Epa1 01 servo1epa1
Servo1 Epa2 02 servo1epa2
Servo2 Center 03 servo2cnt
Servo2 Epa1 04 servo2epa1
Servo2 Epa2 05 servo2epa2
Servo3 Center 06 servo3cnt
Servo3 Epa1 07 servo3epa1
Servo3 Epa2 08 servo3epa2

Pratik çalışma algoritması
Enerji verildiğinde;
- Standart port ayarlamarı
- EEPROM testi
- EEPROM testi başarısız ise üç servo LED’inin sürekli yakılıp söndürülmesi ve program kilidi
- EEPROM testi başarılı ise üç servo LED’inin aktivasyonu (normal çaışma modunu gösterir)
- İki MODE butonunun okunması. Eğer ikisine birden basıldı ise programlama flagının set edilmesi, servo LED’lerinin kapatılması
- MsTimer2 ayarlaması
- Değerlerin EEPROM’dan okunması

Loop() içinde;
Programlama flag’ının durumuna göre iki farklı altprogram çalıştırılacak.
Programlama değil de normal çalışma modunda ise;
- Servo giriş sinyali okunacak
- Gelen servo sinyali her bir servonun EEPROM verileri uyarınca yeniden düzenlenecek
- MsTimer2 set edilmiş olacağı için her 20 mS’de bir çağrılan servoout() altprogramı ile peş peşe üç servoya çıkış değerleri gönderilecek.
- Servo çıkış değerlerinin değişkenleri servo1pwm, servo2pwm, servo3pwm.

Programlama modunuda ise;
- Üç farklı programlama aşaması var. Center, Alt EPA, Üst EPA.
- Üç farklı servo seçimi var.
- Programlamaya girişte Servo1 ve Center seçili olacak. İlgili LED’ler aktive edilecek.
- Mode1 butonu ile Center, Alt EPA ve Üst EPA modları arasında seçim yapılacak.
- Mode2 butonu ile Servo seçimi yapılacak.
- Increase ve Decrease butonları ile de değerler artırılıp azaltılacak.
- Center modunda programlanmakta olan servoya 1500 mikrosaniye + geçerli center değeri kadar sinyal gönderilecek.
- Alt EPA modunda 900 + geçerli EPA1, üst EPA modunda ise 2100 - geçerli EPA2 değerine uygun sinyal gönderilecek.
- Bunlar yapılırken butonlar sürekli olarak okunacak, debounce edilecek.
-

...

------------------------------------------------------------------------------------------------------------------------------------------------------------------------

[attachimg=1]

Buyurun, demo videomuz...

Bu VIDEOYU görmek için izniniz yok. Giriş yap veya üye ol
 

Ekli dosyalar

  • Servo Sync.jpg
    Servo Sync.jpg
    128.2 KB · Görülme: 184
  • Beğen
Tepkiler: cengizhanyurdalan
Bu arada şimdi aklıma gelen bir şeyi de paylaşayım. Yukarıdaki plakete iyice bakın. Şimdi şunu düşünün. Servo giriş ve çıkışları sol tarafa, butonlar sağ taraf alınmış. Sonra buton ve LED'leri kesip ayırın. İki plaketi bir konnektörle birleştirin. Nasıl? Oldu mu? :) Bir tane pragramlama plaketiniz oldu. Üzerinde dört buton ve altı LED olan. Bir de oldukça küçük bir ana plaketiniz. Küçük plaketten her iki kanat için birer tane lazım. Ama programlama modülünden bir tane yeter. Çünkü bunu sadece uçağın ilk setup'ı sırasında kullanacaksınız. Sevdim bu fikri... :D
 
Gerçekten de ilginç bir proje olacak abi. Şu hazır ürünün manual ben de bir göz gezdireyim, demek bu tür ihtiyaçlar için bu tür aletler de üretiliyor :)
 
Servo senkronizasyon modülü

Sümer abiiii... Hastaneden çağırıyorlar abi seni ... :laugh:.
 
Servo senkronizasyon modülü

Sümer Yamaner' Alıntı:
Bu arada şimdi aklıma gelen bir şeyi de paylaşayım. Yukarıdaki plakete iyice bakın. Şimdi şunu düşünün. Servo giriş ve çıkışları sol tarafa, butonlar sağ taraf alınmış. Sonra buton ve LED'leri kesip ayırın. İki plaketi bir konnektörle birleştirin. Nasıl? Oldu mu? :) Bir tane pragramlama plaketiniz oldu. Üzerinde dört buton ve altı LED olan. Bir de oldukça küçük bir ana plaketiniz. Küçük plaketten her iki kanat için birer tane lazım. Ama programlama modülünden bir tane yeter. Çünkü bunu sadece uçağın ilk setup'ı sırasında kullanacaksınız. Sevdim bu fikri... :D
Sonra da programlama modülü, +5 fincan kahve olarak daha ücretlendirilir :). Evet güzel fikir :D .

Yanlız bir cahil sorusu sorabilir miyim ? "Uçaklarda aileronlarda çift servo var." derken, "sağ aileronda çift servo sol aileronda da çift servo" mu yoksa "sağ alieronda tek, sol aileronda tek, toplamda çift servo" mu? Uçak cahili olunca okuduğum satırları pek de anlamadım.

Bu RESMİ görmek için izniniz yok. Giriş yap veya üye ol

Bu RESMİ görmek için izniniz yok. Giriş yap veya üye ol
 
Servo senkronizasyon modülü

Yok yok zaten hastanedeyim. Kod aralarında hasta bakıyorum meraklanmayın. :p

Programı modül modül yazıyorum. Aletin manualini de okudum. Muhtemelen aynı kafadayız. :D

Tekrarlayan çoklu okuma ve yazma işleri için array kullanmak daha akıllıca olabilir diye de düşünüyorum ama onu kod optimizasyonu aşamasında düşünürüz.

Bence kodun en önemli bölümü burası:
Bazı ön bilgiler vermem gerekiyor. servoxcnt değişkenleri var. Üç servo için ayrı ayrı. Yani servo1cnt, servo2cnt, servo3cnt şeklinde. Bunlar integer tipi değişkenler. Yani - 32768 ile + 32767 arasında değer alabiliyorlar. Bunları her bir servonun "subtrim" değeri olarak düşünün. Servo sinyali EPA'lara göre ölçeklendirildikten sonra oluşan değere bu değer eklenerek nihai servo sinyali oluşturuluyor.
EPA1 olan değişkenler alt ucu, EPA2 olanlar üst ucu değiştiriyor. Her ne kadar klasik servo sinyali 1000 - 2000 µs arasında olsa da pratikte 800 ile 2200 arası kullanılıyor. Hatırlayın, kumanda EPA ayarları % 140'a kadar çıkar.
Biz alıcıdan gelen servo sinyalini okuyoruz ve bundan 1500 çıkarıyoruz. Elimizde full skalada - 700 ile + 700 arası bir değer kalıyor. Bu değer eksi ise EPA1 ile artı ise EPA2 ile ölçeklendiriliyor. Sonra 1500 ve CNT değeri buna eklenerek servo sinyal değeri (µs olarak) bulunmuş oluyor.

Örneğin EPA1 500 olsun EPA2 400 olsun. 500 ne demek? 700 tam adıma oranla 500 demek. Yani 500 değeri % 71 EPA'ya denk geliyor. 400 değeri % 57 EPA demek.

Şimdi burada en önemli sorum şu:
Şu komutta
x = x * servo1epa1 / 700;
istediğim ölçeklendirme mümkün mü yoksa x değişkenini ya da tüm değişkenleri "float" olarak mı deklare etmeliyim?




Kod:
servoinPWM = pulseIn(servoin, HIGH, 21000); // Alıcıdan gelen sinyali okuyoruz (µS)
x = servoinPWM – 1500; // x – 700 ile + 700 arasında bir değer alıyor
if(x < 0)
{
x = x * servo1epa1 / 700; // Önceden ayarlı alt EPA (EPA1)değerine göre ölçekleniyor
servo1PWM = x + 1500 + servo1cnt; //Servo1 için çıkış değeri oluşturuluyor
x = x * servo2epa1 / 700; // Önceden ayarlı alt EPA (EPA1)değerine göre ölçekleniyor
servo2PWM = x + 1500 + servo2cnt; //Servo2 için çıkış değeri oluşturuluyor
x = x * servo3epa1 / 700; // Önceden ayarlı alt EPA (EPA1)değerine göre ölçekleniyor
servo3PWM = x + 1500 + servo3cnt; //Servo1 için çıkış değeri oluşturuluyor
}
else
{
x = x * servo1epa2 / 700; // Önceden ayarlı üst EPA (EPA2)değerine göre ölçekleniyor
servo1PWM = x + 1500 + servo1cnt; //Servo1 için çıkış değeri oluşturuluyor
x = x * servo2epa2 / 700; // Önceden ayarlı üst EPA (EPA2)değerine göre ölçekleniyor
servo2PWM = x + 1500 + servo2cnt; //Servo2 için çıkış değeri oluşturuluyor
x = x * servo3epa2 / 700; // Önceden ayarlı üst EPA (EPA2)değerine göre ölçekleniyor
servo3PWM = x + 1500 + servo3cnt; //Servo1 için çıkış değeri oluşturuluyor
}
 
Somut örnekle gidelim.

x = x * servo1epa1 / 700;

x = 100 olsun
servo1epa1 = 500 olsun

500 / 700 işleminin sonucu normalde 0.71429...
Burada ise hep tamsayılar kullandığımız için "0" mı olur?
Öyle olursa 100 * 0 sonuçta 0 eder!!!
Ya da x * servo1epa1 işlemi önce yapılırsa şöyle oluyor:
100 * 500 = 50000
50000 / 700 = 71.42, tamsayı yaparsak 71


Arduino IDE aritmetiğini biraz kurcalamam gerekecek.
 
Kod satırını ikiye bölerek bu riski ortadan kaldırabilirim sanıyorum.

x = x * servo1epa2;
x = x / 700;

NOT: x LONG olarak tanımlı.
 
Servo senkronizasyon modülü

Sümer abi, aynı "x" değerini 3 defa iterasyona sokmuşsun. Bu durumda x'e göre değil, hep bir önceki servoya bağımlı olarak ölçeklenecek.

servoinPWM = pulseIn(servoin, HIGH, 21000); // Alıcıdan gelen sinyali okuyoruz (µS)
x = servoinPWM – 1500; // x – 700 ile + 700 arasında bir değer alıyor
if(x < 0) {
servo1PWM = ((x * servo1epa1) / 700) + 1500 + servo1cnt; //Önceden ayarlı alt EPA (EPA1)değerine göre ölçekleniyor ve servo1 için çıkış değeri oluşturuluyor
servo2PWM = ((x * servo2epa1) / 700) + 1500 + servo2cnt; //Önceden ayarlı alt EPA (EPA1)değerine göre ölçekleniyor ve servo2 için çıkış değeri oluşturuluyor
servo3PWM = ((x * servo3epa1) / 700) + 1500 + servo3cnt; //Önceden ayarlı alt EPA (EPA1)değerine göre ölçekleniyor ve servo3 için çıkış değeri oluşturuluyor
} else {
servo1PWM = ((x * servo1epa2) / 700) + 1500 + servo1cnt; //Önceden ayarlı üst EPA (EPA2)değerine göre ölçekleniyor ve servo1 için çıkış değeri oluşturuluyor
servo2PWM = ((x * servo2epa2) / 700) + 1500 + servo2cnt; //Önceden ayarlı üst EPA (EPA2)değerine göre ölçekleniyor ve servo2 için çıkış değeri oluşturuluyor
servo3PWM = ((x * servo3epa2) / 700) + 1500 + servo3cnt; //Önceden ayarlı üst EPA (EPA2)değerine göre ölçekleniyor ve servo3 için çıkış değeri oluşturuluyor
}

int ve float konusunda durum şöyle. void'leri es geçiyorum.

Serial.begin(9600);
int x=44;
float y=0;
y = x / 33;
Serial.print(y);


yukarıdaki işlemin sonucunu okuduğunuzda, y bir float olmasına rağmen y=1 olarak görürsünüz. y'nin float olabilmesi için sağ taraftaki tüm elemanların da float olması gerekiyor.

Serial.begin(9600);
int x=44;
float y=0;
y = (float)x / 33;
Serial.print(y)


Yukarıda y=1.333... olarak okursunuz.

x = x * servo1epa1 / 700; örneğinde de her zaman virgülün solundaki tamsayıyı elde edersiniz. yani normal aritmetiğe göre x, 1.999 çıksa bile arduino'da 1 okursunuz.

DÜZELTME : Kodu Düzelttim....
DÜZELTME2 : Kodu Daha da düzelttim....
 
Servo senkronizasyon modülü

Zafer SAHIN' Alıntı:
Sümer abi, aynı "x" değerini 3 defa iterasyona sokmuşsun. Bu durumda x'e göre değil, hep bir önceki servoya bağımlı olarak ölçeklenecek.


Uyyyy doğruuuu! :) Bir de y kullanayım. :)

Diğer konuda sanırım çarpmayı öne alarak sorunu çözebileceğim.
 
Yani...

Kod:
servoinPWM = pulseIn(servoin, HIGH, 21000); // Alıcıdan gelen sinyali okuyoruz (µS)
y = servoinPWM – 1500; // x – 700 ile + 700 arasında bir değer alıyor
if(x < 0)
{
x = y;
x = x * servo1epa1;
x = x / 700; // Önceden ayarlı alt EPA (EPA1)değerine göre ölçekleniyor
servo1PWM = x + 1500 + servo1cnt; //Servo1 için çıkış değeri oluşturuluyor
x = y;
x = x * servo2epa1;
x = x / 700; // Önceden ayarlı alt EPA (EPA1)değerine göre ölçekleniyor
servo2PWM = x + 1500 + servo2cnt; //Servo2 için çıkış değeri oluşturuluyor
x = y;
x = x * servo3epa1;
x = x / 700; // Önceden ayarlı alt EPA (EPA1)değerine göre ölçekleniyor
servo3PWM = x + 1500 + servo3cnt; //Servo1 için çıkış değeri oluşturuluyor
}
else
{
x = y;
x = x * servo1epa2;
x = x / 700; // Önceden ayarlı üst EPA (EPA2)değerine göre ölçekleniyor
servo1PWM = x + 1500 + servo1cnt; //Servo1 için çıkış değeri oluşturuluyor
x = y;
x = x * servo2epa2;
x = x / 700; // Önceden ayarlı üst EPA (EPA2)değerine göre ölçekleniyor
servo2PWM = x + 1500 + servo2cnt; //Servo2 için çıkış değeri oluşturuluyor
x = y;
x = x * servo3epa2;
x = x / 700; // Önceden ayarlı üst EPA (EPA2)değerine göre ölçekleniyor
servo3PWM = x + 1500 + servo3cnt; //Servo1 için çıkış değeri oluşturuluyor
}
 
Servo senkronizasyon modülü

Sümer abi, ayıptır sorması niye tek satırda yapmıyorsun, koddan tasarruf, tam tembel işi :).
 
Servo senkronizasyon modülü

Zafer SAHIN' Alıntı:
Sümer abi ,ayıptır sorması niye tek satırda yapmıyorsun, koddan tasarruf, tam tembel işi :)

İki sebebi var. Birincisi daha önceki uygulamalarda görüp teyid ettim ki burada yazdığın kod uzunluğu compiler çıkışı ile doğru orantılı olmuyor. :)
İkinci ve önemli sebep ise yukarıdaki tartışma. Matematik kuralları gereği çarpma ve bölme işlemlerinde sıra önemli değildir. Ama tamsayı aritmetiği uygulandığında;

x = x * servo1epa1 / 700 işleminin sonucu hangi işlemin önce yapıldığına göre ciddi oranda değişir. Yani sistem önce bölmeyi yapacak olursa her durumda 0 çıkar. :) Bu riski ortadan kaldırmak için önce çarpma işlemini ayrı olarak yapmak bana mantıklı geldi.

Ama seni kırmamak adına bir ara çözüm buldum. :D :D :D

x = y * servo1epa1;
x = x / 700;
 
servo1PWM = ((x * servo1epa1) / 700) + 1500 + servo1cnt;

Yukarıdaki olmaz mı ? :p