- Katılım
- 17 Eyl 2013
- Mesajlar
- 8,789
- Tepkime puanı
- 23,175
- Yaş
- 61
- Konum
- İstanbul
- Web sitesi
- www.sumeryamaner.com
- İlgi Alanı
- Uçak
Lütfen yanlış anlaşılmasın. Bunu paylaşma nedenim ukalalık değil. Tamamen arşiv amacıyla buraya koyuyorum. İlgilenen arkadaşlar olursa üzerinde tartışırız.
Bildiğiniz gibi kullandığımız RC sistemlerinin bazı standartları var. Servolara giden sinyal 1000 ile 2000 (hatta 800 ile 2200) mikrosaniye uzunluğunda darbeler. Bu darbelerin genişliği servo pozisyonunu belirliyor. (Darbe genişliği modülasyonu, pulse width modulation, PWM).
Ancak iş bu kadar basit değil. Özellikle standart servolar için darbelerin 20 milisaniye ara ile yani saniyede 50 kez gelmesi de gerekli. Daha sık darbe gelirse bazı analog servolar saçmalıyor hatta yanabiliyorlar. Daha seyrek darbe gelirse bazı digital servolar fail safe konumuna geçebiliyorlar.
Mikrokontrolörlerle yapılacak uygulamalarda bu standardın tutturulması büyük önem taşıyor. Allah'tan 20 milisaniye süresi çok sıkı bir sınırlama değil. Yani 18 ya da 25 milisaniye olsa da zararı yok. Ama çok da fazla şaşmamak gerekli.
Mikrokontrolörlerde bu düzeni sağlamanın iki yolu var. Birisi servo reverser, v tail mikser ya da servo yavaşlatıcı örneğinde olduğu gibi bir giriş darbesine karşılık bir çıkış darbesi üretmek. Bu durumda zamanlama sorunu yaşanmıyor. Ancak çoklu servo çıkışı gerektiren kompleks uygulamalarda iş biraz karışabiliyor. İşte o zaman işlemcinin interrupt özelliklerinin kullanılması gerekiyor. Interrupt demek belirli aralıklarla işlemcinin yaptığı işi bir kenara bırakıp zamanlanmış görevi yapıp sonra bıraktığı işe kaldığı yerden geri dönmesi demek. Yani işlemcinin her 20 milisaniyede bir işi gücü bırakıp servolara gerekli sinyali göndermesini sağlamamız gerekiyor.
Bunu daha önce yapıp burada paylaşmıştım. Ancak şöyle bir sorun var:
Eğer birden fazla servoya farklı değerlerde çıkış verilecek ise bunları peş peşe yapyordum. Yani önce bir servoya 800 - 2200 mikrosaniye arasında darbe gönderip sonra ikinci servoya geçiyordum. Toplam dört servo olduğunu ve her birinin 2200 mikrosaniye değerde olduğunu varsayalım. En az 8800 mikrosaniye hatta biraz daha fazla yani kabaca 9000 mikrosaniye gerekli. Yani 9 milisaniye... Her 20 milisaniyede bir interrupta gidip burada 9 milisaniye geçirirsek işlemcinin vaktinin yaklaşık % 45'i sadece bununla geçer. Arada yapılacak kompleks hesaplamalar falan olursa kalan 11 milisaniye yetersiz kalabilir. İşler aksayabilir.
Gerçi şu ana kadarki uygulamalarda bunun herhangi bir soruna yol açtığını görmüş değilim. Ancak bir adım ileriye gidebilme adına bir algoritma oluşturup test etmeye karar verdim.
Toplam dört servo için bir planlama yaptım. Zafer Şahin'i mutlu etmek için de array kullandım. Deneme için hazırladığım programda her bir servo için kafadan sallama değerler yazdım.
2 x 4 boyutlu ilk array'in (endpwm) ilk satırı birden dörde (aslında sıfırdan üçe) kadar servo numarasını, ikinci satırı da o servoya gidecek darbe uzunluğunu içeriyor. Sonra bu değerleri darbe süresine göre küçükten büyüğe sıralıyoruz. Sıralarken tabii ki servo numaraları da yer değiştiriyor. Sonra bu array (endpwm) değişkenini tekrar ele alıyoruz. Darbe sürelerini içeren satırın ilk elemanı en düşük darbe süresini içeriyor ve öylece kalıyor. Ama sonraki elemanlar darbe süresi değil de bir önceki darbe süresinden fark şeklinde hesaplanıp kaydediliyor.
Tüm bunlar zaman alan işlemler. Ama interrupt sırasında kullanılacak değerler hesaplanırken arada interrupt gelmesi halinde bazen saçma rakamlar oluşabiliyor. O nedenle nihai rakamları oluştururken kısa süreliğine interruptları kapatmak gerekiyor. İşte tüm hesaplamalar yapıldıktan sonra interruptlar kapatılıp hesaplanan değerler ayrı bir array (servopwm) değişkenine kopyalanıyor. Sonra interruptlar tekrar serbest bırakılıyor.
Tüm bu laf kalabalığından sonra servopwm array değişkeninde şöyle bir örnek yapı var:
0: 4, 1, 3, 2
1: 912, 23, 312, 36
Bu ne demek? En kısa darbe süresi 912 mikrosaniye ve 4 numaralı servoya gidecek. Sonra bir numaralı servoya bundan 23 mikrosaniye daha uzun yani 935 mikrosaniyelik bir darbe gidecek...
Servo çıkış zamanı geldiğinde dört servoya birden logic HIGH sinyali veriliyor. delayMicroseconds() komutu ile ilk (ve en kısa) darbe süresi kadar bekleniyor ve ilk sıradaki servo (bu örnekte 4 numaralı olan) çıkışına logic LOW yazılıyor.
Sonra bir sonraki değere bakılıyor. Eğer sıfırdan (bunu dörtten büyük olarak değiştirebilirim ileride) büyük bir değer ise yine delayMicroseconds() ile beklenerek, sıfır ise hiç beklenmeden ikinci sıradaki servonun (bu örnekte 1 numaralı servo) çıkışına logic LOW yazılıyor.
Döngü bu şekilde dördüncü sıradaki servonun darbe süresi de tamamlanana kadar devam ediyor.
Standart yönteme göre ne fark var?
Tüm servolara darbe aynı anda başlayarak gidiyor. Her birinin darbe süresine göre darbe sonlandırılıyor. Böylece tüm işlem en fazla 2200 mikrosaniye + bir miktar idarî süre içinde gerçekleşiyor. Kısaca interrupt işlemcinin zamanından 9 milisaniye yerine yaklaşık 2.5 milisaniye çalmış oluyor.
Bakalım gerçek hayat uygulamasında beklediğim gibi çalışacak mı...
Bildiğiniz gibi kullandığımız RC sistemlerinin bazı standartları var. Servolara giden sinyal 1000 ile 2000 (hatta 800 ile 2200) mikrosaniye uzunluğunda darbeler. Bu darbelerin genişliği servo pozisyonunu belirliyor. (Darbe genişliği modülasyonu, pulse width modulation, PWM).
Ancak iş bu kadar basit değil. Özellikle standart servolar için darbelerin 20 milisaniye ara ile yani saniyede 50 kez gelmesi de gerekli. Daha sık darbe gelirse bazı analog servolar saçmalıyor hatta yanabiliyorlar. Daha seyrek darbe gelirse bazı digital servolar fail safe konumuna geçebiliyorlar.
Mikrokontrolörlerle yapılacak uygulamalarda bu standardın tutturulması büyük önem taşıyor. Allah'tan 20 milisaniye süresi çok sıkı bir sınırlama değil. Yani 18 ya da 25 milisaniye olsa da zararı yok. Ama çok da fazla şaşmamak gerekli.
Mikrokontrolörlerde bu düzeni sağlamanın iki yolu var. Birisi servo reverser, v tail mikser ya da servo yavaşlatıcı örneğinde olduğu gibi bir giriş darbesine karşılık bir çıkış darbesi üretmek. Bu durumda zamanlama sorunu yaşanmıyor. Ancak çoklu servo çıkışı gerektiren kompleks uygulamalarda iş biraz karışabiliyor. İşte o zaman işlemcinin interrupt özelliklerinin kullanılması gerekiyor. Interrupt demek belirli aralıklarla işlemcinin yaptığı işi bir kenara bırakıp zamanlanmış görevi yapıp sonra bıraktığı işe kaldığı yerden geri dönmesi demek. Yani işlemcinin her 20 milisaniyede bir işi gücü bırakıp servolara gerekli sinyali göndermesini sağlamamız gerekiyor.
Bunu daha önce yapıp burada paylaşmıştım. Ancak şöyle bir sorun var:
Eğer birden fazla servoya farklı değerlerde çıkış verilecek ise bunları peş peşe yapyordum. Yani önce bir servoya 800 - 2200 mikrosaniye arasında darbe gönderip sonra ikinci servoya geçiyordum. Toplam dört servo olduğunu ve her birinin 2200 mikrosaniye değerde olduğunu varsayalım. En az 8800 mikrosaniye hatta biraz daha fazla yani kabaca 9000 mikrosaniye gerekli. Yani 9 milisaniye... Her 20 milisaniyede bir interrupta gidip burada 9 milisaniye geçirirsek işlemcinin vaktinin yaklaşık % 45'i sadece bununla geçer. Arada yapılacak kompleks hesaplamalar falan olursa kalan 11 milisaniye yetersiz kalabilir. İşler aksayabilir.
Gerçi şu ana kadarki uygulamalarda bunun herhangi bir soruna yol açtığını görmüş değilim. Ancak bir adım ileriye gidebilme adına bir algoritma oluşturup test etmeye karar verdim.
Toplam dört servo için bir planlama yaptım. Zafer Şahin'i mutlu etmek için de array kullandım. Deneme için hazırladığım programda her bir servo için kafadan sallama değerler yazdım.
2 x 4 boyutlu ilk array'in (endpwm) ilk satırı birden dörde (aslında sıfırdan üçe) kadar servo numarasını, ikinci satırı da o servoya gidecek darbe uzunluğunu içeriyor. Sonra bu değerleri darbe süresine göre küçükten büyüğe sıralıyoruz. Sıralarken tabii ki servo numaraları da yer değiştiriyor. Sonra bu array (endpwm) değişkenini tekrar ele alıyoruz. Darbe sürelerini içeren satırın ilk elemanı en düşük darbe süresini içeriyor ve öylece kalıyor. Ama sonraki elemanlar darbe süresi değil de bir önceki darbe süresinden fark şeklinde hesaplanıp kaydediliyor.
Tüm bunlar zaman alan işlemler. Ama interrupt sırasında kullanılacak değerler hesaplanırken arada interrupt gelmesi halinde bazen saçma rakamlar oluşabiliyor. O nedenle nihai rakamları oluştururken kısa süreliğine interruptları kapatmak gerekiyor. İşte tüm hesaplamalar yapıldıktan sonra interruptlar kapatılıp hesaplanan değerler ayrı bir array (servopwm) değişkenine kopyalanıyor. Sonra interruptlar tekrar serbest bırakılıyor.
Tüm bu laf kalabalığından sonra servopwm array değişkeninde şöyle bir örnek yapı var:
0: 4, 1, 3, 2
1: 912, 23, 312, 36
Bu ne demek? En kısa darbe süresi 912 mikrosaniye ve 4 numaralı servoya gidecek. Sonra bir numaralı servoya bundan 23 mikrosaniye daha uzun yani 935 mikrosaniyelik bir darbe gidecek...
Servo çıkış zamanı geldiğinde dört servoya birden logic HIGH sinyali veriliyor. delayMicroseconds() komutu ile ilk (ve en kısa) darbe süresi kadar bekleniyor ve ilk sıradaki servo (bu örnekte 4 numaralı olan) çıkışına logic LOW yazılıyor.
Sonra bir sonraki değere bakılıyor. Eğer sıfırdan (bunu dörtten büyük olarak değiştirebilirim ileride) büyük bir değer ise yine delayMicroseconds() ile beklenerek, sıfır ise hiç beklenmeden ikinci sıradaki servonun (bu örnekte 1 numaralı servo) çıkışına logic LOW yazılıyor.
Döngü bu şekilde dördüncü sıradaki servonun darbe süresi de tamamlanana kadar devam ediyor.
Standart yönteme göre ne fark var?
Tüm servolara darbe aynı anda başlayarak gidiyor. Her birinin darbe süresine göre darbe sonlandırılıyor. Böylece tüm işlem en fazla 2200 mikrosaniye + bir miktar idarî süre içinde gerçekleşiyor. Kısaca interrupt işlemcinin zamanından 9 milisaniye yerine yaklaşık 2.5 milisaniye çalmış oluyor.
Bakalım gerçek hayat uygulamasında beklediğim gibi çalışacak mı...