Servo senkronizasyon modülü

Servo senkronizasyon modülü

Sümer Yamaner' Alıntı:
Ben "senin yüzünden" ne durumdayım bir de ona baksan!!! :lol:
O zaman Sümer abi, ben de bir hayra vesile olayım :lollol: :lol: Microsoft Visual Studio Professional Edition artık kişisel kullanım için(aslında ticari bile olsa 5 kişilik gruplara kadar) lisans gerektirmiyor. Microsoft Visual Studio Community edition adı altında sunuluyor. Tek gereken bir "LIVE" ya da Hotmail hesabı.


Bu aşağıdaki de bilgisayar üzerindeki COM portları(Arduino'nun takıldığı nı seçebiliyoruz böylece) okuyup, onlara abuk subuk mesajlar göndermek için kullandığım bir test programı. PC kontrollü bir Arduino-araba yapmak için başlamıştım ama henüz aşağıdakinden ileri gitme fırsatım olmadı :D.

Kod:
Public Class Form1
    Dim SerialPortName As String
    Dim charsToTrim() As Char = {" "c, vbCr, vbLf}
    '_serialPort = New SerialPort()

    Sub GetSerialPortNames()
        ListBox1.Items.Clear()
        For Each sp As String In My.Computer.Ports.SerialPortNames
            ListBox1.Items.Add(sp)
        Next
    End Sub

    Function SendSerialData(ByVal data As String, ByVal SerialPortName As String) As String()
        Dim returnVal(1) As String
        Dim iCnt As Integer = 0
        Dim intSleepTimer As Integer = 117
        'Dim COMPortNewLine As String
        Dim COMPort As IO.Ports.SerialPort = Nothing
        MsgBox(SerialPortName)
        COMPort = My.Computer.Ports.OpenSerialPort(SerialPortName)
        'COMPortNewLine = COMPort.NewLine.ToString
        'MsgBox(Asc(COMPortNewLine))
        Do While iCnt <= 100
            COMPort.Write(data + vbCrLf)
            System.Threading.Thread.Sleep(intSleepTimer)
            iCnt += 1
        Loop
        If COMPort IsNot Nothing Then COMPort.Close()
        Return returnVal
    End Function

    Function ReceiveSerialData(ByVal data As String, ByVal SerialPortName As String) As String()
        Dim returnVal(1) As String
        Dim iCnt As Integer = 0
        Dim intSleepTimer As Integer = 200
        Dim intReadTimout As Integer = 5000
        'Dim COMPortNewLine As String
        Dim COMPort As IO.Ports.SerialPort = Nothing
        MsgBox(SerialPortName)
        Try
            COMPort = My.Computer.Ports.OpenSerialPort(SerialPortName)
            COMPort.ReadTimeout = intReadTimout
            'COMPortNewLine = COMPort.NewLine.ToString
            'MsgBox(Asc(COMPortNewLine))
            'COMPort.NewLine = vbLf 'Default end of line character to detect. LineFeed or Char10 or \n
            'COMPort.NewLine = vbCr 'Alternative end of line character. Carriage return or Char13 or \r
            'COMPort.NewLine = vbCrLf 'Non working end of line character. Char10+Char13 or \r\n
            Do While iCnt <= 10
                Dim Incoming As String = COMPort.ReadLine
                If Incoming Is Nothing Then
                    Exit Do
                Else
                    returnVal(0) &= Incoming & vbCrLf
                End If
                iCnt += 1
            Loop
        Catch ex As TimeoutException
            returnVal(1) = "Error: Serial Port read timed out : " + CStr(intReadTimout) + "ms"
        Finally
            If COMPort IsNot Nothing Then COMPort.Close()
        End Try

        Return returnVal
    End Function

    Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedIndexChanged

    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Label1.Text = Date.Now
        GetSerialPortNames()

    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Dim SerialPortMessage As String()
        If (ListBox1.SelectedIndex >= 0) Then
            SerialPortName = ListBox1.SelectedItem.ToString
            SerialPortMessage = SendSerialData("Working...!", SerialPortName)
        End If
    End Sub

    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        Dim SerialPortMessage As String()
        If (ListBox1.SelectedIndex >= 0) Then
            SerialPortName = ListBox1.SelectedItem.ToString
            SerialPortMessage = ReceiveSerialData("Working...!", SerialPortName)
            MsgBox("--- MESSAGE ---" + vbCrLf + SerialPortMessage(0).Trim(charsToTrim) + vbCrLf + "--- --- --- ---" + vbCrLf + "--- ERROR ---" + vbCrLf + SerialPortMessage(1) + vbCrLf + "--- --- --- ---")
        End If
    End Sub
End Class
 
Servo senkronizasyon modülü

Kullanılacak plaketin fiziksel koşulları nedeniyle programlama için kullanılacak dört butonu analog girişlere bağlamıştım (A0, A1, A2, A3). Tek tek "digitalRead()" yapmak yerine tek komutla dört butonun durumunu okumak istedim. Bu amaçla şöyle bir kod oluşturdum:

Kod:
int buttonbas()
{
  keypress = PINC & B00001111;
  if (keypress == B00001110) return 1;
  if (keypress == B00001101) return 2;
  if (keypress == B00001011) return 3;
  if (keypress == B00000111) return 4;
  if (keypress == B00001100) return 5;
  return 0;
}

Daha önceden "keypress" değişkeni de "byte" olarak tanımlanıyor tabii.
Dört buton şöyle: Mode1 Mode2 Decrease(-) Increase(+)
Butonlara tek tek basılması durumunda 1, 2, 3 ve 4 sonucu döndürülüyor. Mode1 ve Mode2 butonuna birlikte basıldıysa 5 sonucu döndürülüyor. Herhangi bir butona basılmadı ya da birden çok butona aynı anda basıldı ise (Mode1 Mode2 hariç) o zaman 0 döndürülüyor.
 
Servo senkronizasyon modülü

Butonları okumak kolay. Ama iki sorun var. Biri "debounce" diğeri "hızlı tekrarı önlemek".
Debounce için butonları belirli bir süre okuyup sonucun hep aynı kaldığını görmek bir yöntem. Arada farklı bir sonuç gelirse de "0" döndürülecek.
Hızlı tekrarı önlemek için ise bir butona basıldığında herhangi bir işlem yapmadan önce butonun bırakılmasını beklemek bir çözüm olabilir.

Kod:
int debouncebutton() //Buraya gelirken key1 değişkeni basıldığı belirlenen butonu içeriyor. Yani 0 - 5 arası bir değer.
{
  if(key1 == 0) return key1; //Tuşa basılmamış ise hiçbir şey yapmadan geri dön
  b = 0; //Sayaç sıfırlanıyor
  for (int n = 0; n < 50; n++) //Buradaki 50 rakamı ve ilerideki 40 rakamı hassas ayar için değiştirilecek
  {
    key = buttonbas(); //Butonlar 50 kez okunuyor
    if(key == key1)
    {
      b++; //Eğer okunan değer ilk okunan değer ile aynı ise b sayacı bir artırılıyor
    }
    else if(key != 0) //Farklı bir değer okunduysa ve bu değer 0 değil ise bu durum bounce nedeniyle değil başka butona basma nedeniyle olmuştur. 0 döndürüyoruz.
    {
      return 0;
    }
    if(b < 40) //Okunan değerlerin en az % 80'i key1 ile aynı olmalı. Yoksa 0 döndürüyoruz
    {
      return 0;
    }
  }
  while (buttonbas() != 0) //Buraya geldiğimize göre 50 test okumasındaki değerlerin en az 40'ı orijinal key1 değeri ile aynı demektir. Artık butonun bırakılmasını bekliyor ve key1 değerini döndürüyoruz
  {
  }
  return key1;
}

Önümüzdeki birkaç gün buton okuma kodunu test edip hassas ayarlarını tamamlayıp rahat kullanılabilir hale getirmek ve bu kodu da standart kodlar klasörüne atmak istiyorum.
 
Servo senkronizasyon modülü

Sümer Yamaner' Alıntı:
...Önümüzdeki birkaç gün buton okuma kodunu test edip hassas ayarlarını tamamlayıp rahat kullanılabilir hale getirmek ve bu kodu da standart kodlar klasörüne atmak istiyorum.
Ama olmaz ki abi, hem library kullanımına karşısın yani en azından tercih etmiyorsun, hem de kendi library kuruyorsun yavaştan yavaştan :lol: :lollol:
 
Servo senkronizasyon modülü

Mehmet Kucuksari' Alıntı:
Ama olmaz ki abi, hem library kullanımına karşısın yani en azından tercih etmiyorsun, hem de kendi library kuruyorsun yavaştan yavaştan :lol: :lollol:

Aynen. "Paralel library lobisi"! :D :p Ruhum anarşist demek ki! :lol:
 
Sisteme dört buton dört de LED bağladım. Yukarıdaki kodlarda küçük değişiklikler yaptım. Şu anda aşağıdaki kod ile "decrease" ve "increase" tuşları takılmadan ve tekrarlamadan LED'leri sıra ile yakıp söndürüyorlar. Yani ya ileri ya da geri doğru sıra ile LED yakılıyor. Gerçek kodda LED yakma yerine değer değiştirme işlevi olacak. Ayrıca mode1 ve mode2 olarak ifade edilen iki tuşa birden basıldığında dört LED birden yanıyor. Yani bunu da güvenli olarak ayırdedebiliyoruz. Buna karşılık gelen buton kodu "5". Gerçek kodda üç saniye boyunca sürekli "5" kodu gelirse ayarlanmış değerler EEPROM'a yazılacak ve LED'ler hızlı hızlı yakılıp söndürülerek reset beklenecek.

Kod:
byte keypress = B00111111;
int key = 0;
int key1 = 0;
int key2 = 0;
int prevkey = 0;
int LED[4] = {2, 3, 4, 5};
int b = 0;
int debounce = 200;
int bounce = 160;

int sira = 1;

void setup()
{
  pinMode(A0, INPUT_PULLUP);
  pinMode(A1, INPUT_PULLUP);
  pinMode(A2, INPUT_PULLUP);
  pinMode(A3, INPUT_PULLUP);
  for (int n = 0; n < 4; n++)
  {
    pinMode(LED[n], OUTPUT);
    digitalWrite(LED[n], LOW);
  }
}

void loop()
{
  key1 = buttonbas();
  key2 = debouncebutton();
  if ((key1 == key2) && ((key1 * key2) != 0))
  {
    dosomething();
  }
  prevkey = key2;
}

int buttonbas()
{
  keypress = PINC & B00001111;
  for (int n = 0; n < 1000; n++)
  {
    keypress &= PINC;
  }
  if (keypress == B00001110) return 1;
  if (keypress == B00001101) return 2;
  if (keypress == B00001011) return 3;
  if (keypress == B00000111) return 4;
  if (keypress == B00001100) return 5;
  return 0;
}

int debouncebutton() //Buraya gelirken key1 değişkeni basıldığı belirlenen butonu içeriyor. Yani 0 - 5 arası bir değer.
{
  if (key1 == 0) return key1; //Tuşa basılmamış ise hiçbir şey yapmadan geri dön
  b = 0; //Sayaç sıfırlanıyor
  for (int n = 0; n < debounce; n++)
  {
    key = buttonbas(); //Butonlar "debounce" kez okunuyor
    if (key == key1) b++; //Eğer okunan değer ilk okunan değer ile aynı ise b sayacı bir artırılıyor
    else if (key != 0) return 0; //Farklı bir değer okunduysa ve bu değer 0 değil ise bu durum bounce nedeniyle değil başka butona basma nedeniyle olmuştur. 0 döndürüyoruz.
  }
  if (b < bounce) return 0; //Okunan değerlerin en az % 80'i key1 ile aynı olmalı. Yoksa 0 döndürüyoruz
  while (buttonbas() != 0) //Buraya geldiğimize göre "debounce" test okumasındaki değerlerin en az "bounce"'ı orijinal key1 değeri ile aynı demektir. Artık butonun bırakılmasını bekliyor ve key1 değerini döndürüyoruz
  {
  }
  return key1;
}

void dosomething()
{

  //  if (prevkey == key1) return;
  for (int n = 0; n < 4; n++)
  {
    digitalWrite(LED[n], LOW);
  }
  if (key1 == 5)
  {
    for (int n = 0; n < 4; n++)
    {
      digitalWrite(LED[n], HIGH);
    }
  }
  switch (key1)
  {
    case 1:

      break;
    case 2:

      break;
    case 3:
      sira--;
      if (sira < 1) sira = 4;
      break;
    case 4:
      sira++;
      if (sira > 4) sira = 1;
      break;
  }
  digitalWrite(LED[sira - 1], HIGH);
}
 
Kodun ana modülleri şunlar:

Pin giriş değerlerini okuyan işlev. Her bir buton için 1'den 4'e kadar bir integer, Mode1 ve Mode2 butonlarına birlikte basıldıysa 5, başka buton kombinasyonu ya da herhangi bir butona basılmamışsa 0 döndürüyor.

Kod:
int buttonbas()
{
  keypress = PINC & B00001111;
  for (int n = 0; n < 1000; n++)
  {
    keypress &= PINC;
  }
  if (keypress == B00001110) return 1;
  if (keypress == B00001101) return 2;
  if (keypress == B00001011) return 3;
  if (keypress == B00000111) return 4;
  if (keypress == B00001100) return 5;
  return 0;
}

Bu da debounce işlevi için:

Bu işlev de benzer formatta bir integer döndürüyor. Ana program gövdesinde bu iki değer karşılaştırılıyor. Sıfır değil ve eşit ise değerlendirmeye alınıyor.

Kod:
int debouncebutton() //Buraya gelirken key1 değişkeni basıldığı belirlenen butonu içeriyor. Yani 0 - 5 arası bir değer.
{
  if (key1 == 0) return key1; //Tuşa basılmamış ise hiçbir şey yapmadan geri dön
  b = 0; //Sayaç sıfırlanıyor
  for (int n = 0; n < debounce; n++)
  {
    key = buttonbas(); //Butonlar "debounce" kez okunuyor
    if (key == key1) b++; //Eğer okunan değer ilk okunan değer ile aynı ise b sayacı bir artırılıyor
    else if (key != 0) return 0; //Farklı bir değer okunduysa ve bu değer 0 değil ise bu durum bounce nedeniyle değil başka butona basma nedeniyle olmuştur. 0 döndürüyoruz.
  }
  if (b < bounce) return 0; //Okunan değerlerin en az % 80'i key1 ile aynı olmalı. Yoksa 0 döndürüyoruz
  while (buttonbas() != 0) //Buraya geldiğimize göre "debounce" test okumasındaki değerlerin en az "bounce"'ı orijinal key1 değeri ile aynı demektir. Artık butonun bırakılmasını bekliyor ve key1 değerini döndürüyoruz
  {
  }
  return key1;
}
 
Interrupt'lara alt seviyeden müdahale etmek büyük bir güç sağlıyor. Ancak bunu yaparken datasheetleri de iyi okumak gerekiyor. Bugün ATmega328 datasheet'i okurken farkettim ki interrupt geldiğinde status register kaydedilmiyormuş. Yani bir işin ortasında interrupt geldiğinde interrupt işi bitip normal program akışına döndüğümüzde status register interrupt service routine'deki olaylara göre şekilleniyor. Bu da pekala olmadık bir yerde saçma sapan bir dallanma sorunu yaratabilir. Çözüm çok basit. Bir adet volatile byte değişken tanımlıyoruz. Örneğin sregvalue gibi. Interrupt service routine başında sregvalue = SREG; diyoruz. Interrupttan çıkarken de SREG = sregvalue; diyoruz.
Yukarıda interrupt kullanan tüm kodlara bu ekleme yapılacak doğal olarak. Bu bilgi notunu da burada paylaşayım dedim.
 
Servo senkronizasyon modülü

Sümer Yamaner' Alıntı:
Interrupt'lara alt seviyeden müdahale etmek büyük bir güç sağlıyor. Ancak bunu yaparken datasheetleri de iyi okumak gerekiyor. Bugün ATmega328 datasheet'i okurken farkettim ki interrupt geldiğinde status register kaydedilmiyormuş. Yani bir işin ortasında interrupt geldiğinde interrupt işi bitip normal program akışına döndüğümüzde status register interrupt service routine'deki olaylara göre şekilleniyor. Bu da pekala olmadık bir yerde saçma sapan bir dallanma sorunu yaratabilir. Çözüm çok basit. Bir adet volatile byte değişken tanımlıyoruz. Örneğin sregvalue gibi. Interrupt service routine başında sregvalue = SREG; diyoruz. Interrupttan çıkarken de SREG = sregvalue; diyoruz.
Yukarıda interrupt kullanan tüm kodlara bu ekleme yapılacak doğal olarak. Bu bilgi notunu da burada paylaşayım dedim.
Sümer abi , harikasın , ancak bu işe sardın saralı iletişim problemi yaşamaya başladık farkındasın değil mi ...Çünkü bu yazdıklarından birşey anladıysam ne olayım :D :lollol:.
Yok canım , bir altı ay sonra , artık teknik ingilizce sözlükle falan çözebiliriz bu yazdıklarını Sümer abi... :p :saygilar:
 
Servo senkronizasyon modülü

Yahu mesele anlamak değil ki. Ben arşiv amaçlı paylaşoyorum. :) Birkaç gün yoğun olarak bu işle ilgilenirsen her şey değişir.
 
Servo senkronizasyon modülü

Senkronizasyon modülünde oldukça ilerledik. Saklanması gereken sabit parametrelerin işlemci üzerindeki EEPROM'a yazılması ve okunması, EEPROM'un test edilmesi, butonlarla değerlerin ayarlanması gibi işlemler tamamlandı. Servo çıkış sinyalleri osiloskopla doğrulandı. Servo takarak denendi. Bu kadar iş iyi gidince tabii bazı şeyler unutuluyor. Örneğin programlama modu ile çok ilgilenince normal çalışma modunu test etmeyi unutmuşum. Bu akşam da bunu test ettiğimde ve olası sorunları çözdüğümde modül üretime hazır hale gelmiş olacak. İki farklı modül planladım. Birisi butonlarla programlanabilir olacak. Diğerini bu ilki ile yapılan ayar sonrası sabit değerlerle uçağa has şekilde programlayıp sadece normal modda çalışacak şekilde planladım. Biri muhtemelen 6 * 6 cm diğeri ise muhtemelen 6 * 3 cm gibi bir boyutta olacak. Gerçi kontrol yüzeyi başına 2 ya da 3 servo içeren bir uçak zaten en az 50 cc olur ve 6 * 6 cm çok da rahatsız etmez ama olsun...

You must be registered for see images attach
 

Ekli dosyalar

  • Servo Sync.png
    Servo Sync.png
    15.8 KB · Görülme: 9
Son olarak da Servo Sync Lite modülümüz hazırlandı. Bunda EPA senkronizasyonu yok. Sadece center senkronizasyonu ile idare ediyor ki piyasadaki ucuz istemler böyle çalışıyor zate.

[attachimg=1]
 

Ekli dosyalar

  • Servo Sync Lite.jpg
    Servo Sync Lite.jpg
    35.4 KB · Görülme: 26