C# arayüzünde Pixhawk verisi bozuk, önce baytları say

Kendi yer kontrol istasyonunu C# ile yazdın. Port açılıyor, ışık yanıyor, baytlar akıyor. Ama ekrandaki irtifa bir 12 metre, bir 3.400 metre. Yaw değeri arada bir çılgına dönüyor.
Hat bozuk değil. Okuma biçimi bozuk. Aynı bayt akışını iki farklı kurguyla okuduğumuzda biri 5.440 paket çıkardı, diğeri aynı akıştan 181 tane fazladan paket uydurdu.
Ekranda ne oluyor
Belirti hep aynı sırayla gelir. Önce her şey düzgün görünür, birkaç saniye sonra bir alan sıçrar, sonra düzelir, sonra yine sıçrar. Uygulamayı kapatıp açınca bir süre daha düzgün çalışır.
Bu desen, ayrıştırıcının akışın içinde yanlış bir yerden çerçeve başlatıp bir sonraki gerçek çerçevede kendini toparlamasından gelir.
Çerçevenin nerede bittiğini LEN söyler
Otopilottan gelen akış, arka arkaya dizilmiş MAVLink çerçevelerinden oluşur. Her çerçeve 0xFD baytıyla başlar, ama boyu sabit değildir.
Gövde uzunluğu başlığın ikinci baytında gelir. Toplam boyu, o baytı okumadan bilemezsin. Ölçtüğümüz akışta paket boyu 14 ile 56 bayt arasında değişti.
Buradan ilk kural çıkıyor: çerçeveyi ancak kendi uzunluğu kadar atlayabilirsin. Sabit boy varsayan bir okuma ikinci pakette kayar ve bir daha toparlanmaz.
Yük içindeki bayt da 0xFD olabilir
Yaygın kurgu şudur: tamponda 0xFD baytını ara, bulduğun yeri paket başı say. Oysa gövde ham ikili veri taşır; içinde 0xFD baytı geçmesini engelleyen hiçbir şey yoktur.
Ayrımı yapan tek şey CRC doğrulamasıdır. CRC tutuyorsa o gerçekten bir çerçeve başıdır; tutmuyorsa yük içindeki rastgele bir bayta denk gelmişsindir.
Read çağrısı istediğin kadar bayt döndürmez
İkinci tuzak okuma katmanında. C# tarafında hem SerialPort hem NetworkStream, tamponun tamamını doldurmadan da geri dönebilir.
Dönen değeri yok sayıp tamponun tamamını işleyen kod, okumaların dörtte birinde önceki turdan kalan baytları ikinci kez ayrıştırır. Ortaya çıkan tekrar paketleri hat gürültüsüne benzer, oysa kaynak kendi kodundur.
Okuma döngüsü
İki düzeltme yeter. Birincisi, Read çağrısının döndürdüğü sayıyı kullan.
İkincisi, gelen baytları biriktiren ve yalnızca CRC'si tutan çerçeveleri tüketen bir okuyucu koy. Yarım kalan kuyruk bir sonraki okumaya devredilir.
CrcEkstra tablosu her mesaj kimliği için bir bayt tutar ve MAVLink tanımlarından üretilir. Tabloyu elle yazma; üretilmiş bir tablo kullan, yoksa doğrulama her mesajda düşer.
Ölçüm
İki kurguyu, ArduPilot SITL'e bağlanan aynı C# programı içinde aynı bayt akışına uyguladık; akışı 20 saniye boyunca 256 baytlık tamponla okuduk.
toplam bayt : 190653Read cagrisi : 803tam 256 donen : 601 (%74,8)Read donusu min/ort/max : 25 / 237,4 / 256---A (magic ara, CRC yok) : gecerli 5440 | CRC tutmayan 181B (cerceveden ilerle) : gecerli 5440 | kaydirma 0İki kurgu da 5.440 gerçek çerçeveyi buldu. Fark, birincisinin bunlara ek olarak 181 tane daha paket çıkarmasında. O 181 kayıt uygulamanın ekranına düşer ve alanları rastgele değerler taşır.
Hata Mesajları ve Anlamları
Bu üç metin .NET tarafında birebir bu şekilde çıkar. Hangisini gördüğün, sorunun hangi katmanda olduğunu söyler.
System.UnauthorizedAccessException: Access to the port 'COM3' is denied.
Port başka bir program tarafından açık. Mission Planner ya da önceki koşudan kalmış bir örnek hattı tutuyordur. Aynı seri portu iki uygulama paylaşamaz.
System.IO.IOException: Unable to read data from the transport connection: Connection timed out.
Bağlantı kuruldu ama okuma süresi doldu. Baud eşleşmiyorsa ya da karşı taraf MAVLink konuşmuyorsa bu metni görürsün. Önce SERIALx_PROTOCOL değerine bak.
System.Net.Sockets.SocketException: Connection refused
TCP tarafında karşı uçta dinleyen yok. SITL kapanmıştır ya da port numarası yanlıştır. Bu mesajı gördüğünde ayrıştırıcıyı kurcalamanın anlamı yok, henüz bayt gelmiyor.
Simülasyonda ve sahada
Yukarıdaki ölçüm TCP üzerinden alındı. Çerçeveleme mantığı iki tarafta da aynıdır; değişen, baytların hatta nasıl geldiğidir.
TCP tarafında bayt kaybı olmaz, sıra bozulmaz. Gördüğün her senkron kaybı senin kodundandır.
Seri hatta gürültü, baud sapması ve akış kontrolü eksikliği baytları gerçekten düşürebilir. Orada CRC hem senin hatanı hem hattın hatasını yakalar.
SERIAL1_BAUD parametresi 57 yazıyorsa hat 57.600'de çalışıyor demektir; değer bine bölünmüş saklanır.
Bu konunun devamı
Yukarıdaki okuyucu, çalışan bir yer kontrol istasyonunun en alt katmanı. Üstüne arayüz, kayıt ve komut gönderme katmanı gelir.
Bunları uçtan uca kuran ders Sıfırdan İleri Seviyeye C# eğitimi içinde. Orada firmware'in karar sırası, log imzaları ve kart bazlı farklar da var.
İNDİRİM KUPONU Kupon kodu: SOFTIVATION15 Eğitimi alırken ödeme ekranındaki "Kupon kodu" kutusuna bu kodu yaz, %15 iner.




Yorumlar