Watchdog
Interrupt Watchdog (IWDT) RTC Watchdog Timer (RTC_WDT)
ESP32 mimarisinde iki önemli sistem watchdog’u olan Interrupt Watchdog (IWDT) ve RTC Watchdog Timer (RTC_WDT), uygulama koduna herhangi bir müdahaleye gerek kalmadan sistem seviyesinde otomatik olarak çalışmaktadır. IWDT, FreeRTOS işletim sistemi tarafından her tick’te beslenerek, ISR’ların veya kritik bölümlerin sistemin kilitlenmesine neden olup olmadığını denetler. RTC_WDT ise, sistem açıldığında (boot aşamasında) devreye girerek, main() fonksiyonuna zamanında ulaşılamazsa otomatik reset işlemi gerçekleştirir. Bu iki watchdog, ESP32 sisteminin kararlı çalışmasını sağlamakta, olası kilitlenmelerde sistemin kendi kendine toparlanmasına imkân tanımaktadır.
Task Watchdog Timer (TWDT)
ESP32 platformunda kullanılan Task Watchdog Timer (TWDT), belirli görevlerin (task'ların) belirli bir süre içerisinde düzgün şekilde çalışıp çalışmadığını denetlemek amacıyla kullanılan bir yazılımsal koruma mekanizmasıdır. Kullanıcı tarafından başlatılarak aktif hâle getirilen TWDT’ye, izlenmesi istenen görevler abone edilir. Bu görevler, belirlenen zaman aralığında esp_task_wdt_reset() fonksiyonu ile watchdog'u “beslemeli”; aksi takdirde TWDT bu görevin kilitlendiğini varsayarak sistemin hata mesajı üretmesini (panic) ya da resetlenmesini sağlar. Güvenlik-kritik uygulamalarda TWDT, sistemin ana görevlerinin donması, veri akışının kesilmesi veya infinite loop gibi yazılım hatalarının oluşması durumunda müdahale ederek sistemin kendi kendini kurtarabilmesini sağlar.
#include "esp_task_wdt.h"
void setup() {
// ... mevcut kurulumlar ...
esp_task_wdt_config_t twdt_config = {
.timeout_ms = 3000, // 3 saniye içinde resetlenmeli
.idle_core_mask = 0, // idle task izlenmiyor
.trigger_panic = true
};
esp_task_wdt_init(&twdt_config); // Watchdog’u başlat
esp_task_wdt_add(NULL); // Mevcut görev (loop task) TWDT’ye abone edildi
}
void loop() {
// Uçuş kontrol fonksiyonlarını çağır
kalkis();
burnout();
apogee();
parasut();
alcalma();
call_lora();
esp_task_wdt_reset(); // 🔁 watchdog'u besle
delay(200);
}old
-
Özgün UKB’lerin algoritmaları açık ve net bir şekilde açıklanmalıdır. Algoritma açıklanırken karmaşık ve uzun cümleler kullanılmamalı, akış şemaları kullanılmalıdır. Kullanılan algoritmaya ilişkin akış şemasında; algoritmada kullanılan parametrelerin hangi sensörden geldiği açık ve net bir şekilde anlatılmalıdır. Kurtarma sistemini tetikleyecek parametreler listelenmeli ve neden seçildiği belirtilmelidir (kullandığı parametreleri doğru sensörlerden almayan veya eksik olarak açıklayan takımlar diskalifiye edilecektir). Algoritma içerisinde haberleşme ve yer istasyonu ile ilgili adımlar var ise bunlar paylaşılmamalıdır. (besma // görselleştirerek yap)
-
Özgün UKB’lerin test edilmesi kapsamında test cihazı ile Ö-UKB arasında çalışacak olan yazılımın UKB ana algoritması ile nasıl entegre edildiği ve çalışma yapısı açık şekilde algoritma şeması olarak paylaşılmalıdır. (semih/enes/besma)
Deney videosu (Semih) https://drive.google.com/drive/folders/1odC9xmdg6W0WZIL8I4gqv5UqY6kFndTy?usp=sharing
🌟 Özet Strateji:
🧠 Sensör Füzyonlama (Sensor Fusion) + 📉 Kalman Filtresi
Bu iki yöntem, farklı sensörlerden gelen verileri birleştirerek daha doğru ve güvenilir ölçümler sağlar.
⸻
💡 Elimizdeki Üç Faktör: 1. İvme (Accelerometer) • Başlangıç ve motor bitimi (burn-out) sırasında yüksek titreşim nedeniyle barometre bozulabilir. • Bunu kontrol etmek için ivmeölçer (accelerometer) kullanılır. • Kalman filtresi ile filtrelenerek anlık ivme patlamalarına karşı önlem alınır. 2. Dikey Hız (Vertical Speed) • Barometre verisinden veya ivme verisinin integralinden hesaplanabilir. • Özellikle motor kapanışından sonra roketin apogee noktasına ulaşıp ulaşmadığı burada anlaşılır. 3. Yükseklik (Altitude) • Barometrik sensör (BMP280 gibi) ile ölçülür ama burn-out ve ani basınç değişimlerinde güvenilirliği düşer. • Bu nedenle ivme ve dikey hız verisiyle çapraz kontrol yapılır.
⸻
🔍 Neden Kalman Filtresi?
Kalman filtresi, sistemdeki gürültülü sensör verilerini birleştirerek en iyi tahmini yapar. Yani: • Barometre + ivmeölçer verisi → Yükseklik ve dikey hızın en güvenilir hali elde edilir. • Başlangıçta barometredeki hataları ivme ile check edersiniz. • Hata varsa Kalman filtresi bunu “güvenilir olmayan veri” olarak değerlendirip tahminini düzeltir.
⸻
🔄 Sensör Füzyonlama • Sensör füzyonlama, farklı kaynaklardan gelen verileri birleştirerek tek bir anlamlı veri seti üretir. • Örneğin: • BMP280 (yükseklik) • MPU6050 (ivme ve gyro) • Kalman filtresi ile bu sensörlerin birleşimi yapılır.
⸻
📌 Uygulamada Ne Yapılmalı? 1. MPU6050 → ivme ve gyro verisini oku. 2. BMP280 → basınca dayalı yükseklik verisini al. 3. Tüm bu verileri Kalman filtresi ile işleyerek: • Gerçek yükseklik • Dikey hız • Apogee tespiti gibi önemli bilgileri güvenilir şekilde elde et.
📌 KTR Raporunda Algoritma’dan Ne Bekleniyor?
- 📄 “Özgün UKB’lerin algoritmaları açık ve net bir şekilde açıklanmalıdır.”
- 📄 “Algoritma açıklanırken karmaşık ve uzun cümleler kullanılmamalı, akış şemaları kullanılmalıdır.”
- 📄 “Algoritmada kullanılan parametrelerin hangi sensörden geldiği açık ve net bir şekilde anlatılmalıdır.”
- 📄 “Kurtarma sistemini tetikleyecek parametreler listelenmeli ve neden seçildiği belirtilmelidir.”
- 📄 “Algoritma içerisinde haberleşme ve yer istasyonu ile ilgili adımlar var ise bunlar paylaşılmamalıdır.”
2025.04.20 / Algoritma Deney Testi / Asansör Kullanıldı hızın değişimi gözlemlendi. ( Erenle birlikte yaptık )
-
Algoritma Testleri: Bu test ile takimlar özgün UKB'leri ile aym sensör mimarisine sahip bir prototip olusturmalidir. Prototip için devre kartinin üretilmis olmasi gerekmemektedir. Sensörler modül olarak breadboard üzerinde bir araya getirilebilir. Devre kartini üretmis olan takimlar nihai devre kartlari ile bu testi gerçeklestirebilirler. Testin amaci ayrilma sistemini aktiflestirecek olan algoritmanin çalisma prensibinin kontrolüdür. Takimlar gerekirse algoritmalari için belirledikleri esik degerleri degistirerek ancak algoritma mantigini degistirmeden algoritmalarin1 test etmelidirler. Yapilan test sonucunda ayrilma sisteminin aktiflestirildigi görsel veya isitsel bir çikti ile gösterilmelidir. Ornek bir test senaryosu olarak, ayrilma algoritmasinda roketin yer normali ile yaptigi açi ve irtifa degerini kullanan bir sistem için breadboard üzerine yerlestirilen bir prototip aviyonik sistemin yer ile yaptigi açi el ile degistirilebilir. Sonrasinda ise sistem bir emis sistemi (örnegin elektrik süpürgesi) yardimiyla vakumlama yapip irtifa degisimi saglanabilir. Yapilan degisiklikler sonucun kurtarma sisteminin aktivasyonunu modellemek için bir LED lambas1 yakilabilir ya da bir ses sistemi (örnegin buzzer) aktive edilebilir. Yapilan bu adimlar en fazla 30 saniyelik bir video ile gösterilmelidir.
WhatsApp.Video.2025-04-20.at.15.08.31.mp4
- BUNUN SESLENDİRİLMESİ YAPILMASI GEREKİYOR ASANSÖRDE ÇIKILDIĞINI VE ŞU AMAÇLA YAPILMASI GEREKTİĞİNİ SÖYLEYEN BİR MONTAJ
- Kodlanış şekilleri, i2c mi SPI mı UART mı ?
- Hazır kütüphane var mı yoksa driver mı yazılacak ?
Alternatif Modül
2025_01_25/27GPS için araştırma sürecine girdim ancak araştırırken birkez daha aldığım GPS modülunu denemeye karar verdim, başka bir kodla EKTEDİR, Cerendeydi GPS getirdi bende test için eve getirdim. Pazartesi günü Yusuf ve Şenol hocalarla konuşmak için gideceğim Ömer de eşlik edecek inşallah o güne kadar detaylı bir GPS modül araştırma raporlamasını yapmış olur test etmiş olurum yeni kodu umarım lock olur.
- NEO-6M GPS MODÜL ile konum, hız, irtifa, tarih bilgisi alma | ESP VE ARDUİNO | TİNYGPS++ LİBRARY
- Videodaki verilen kod
- TinyGPS++ Library
-- {Elimizdeki GY-NEO6MV2 GPS Modülü} Roket takımları genelde Adafruit Ultimate GPS Modülü veya elimizdeki GY-NEO6MV2 GPS Modülünü kullanmış benim beğendiğim u-blox NEO-M8N-0
Adafruit Ultimate GPS
Ublox GYGPSV1 NEO-8M GPS Modülü:
Beitian BN-220 GPS Modülü
-
AddictiveRC $20
-
AMAZON 845 ₺
-
Beitian Dual BN-220 GPS GLONASS Anten Modülü TTL Seviye RC Drone Uçak$17,59
-
Tyro119 RC Drone FPV Yarışı için Beitian BN-220T GPS Modülü Çift Modülü $14,32
Ublox ZED-F9P RTK GPS Modülü
başka gps modüllerine burdan bakabiliriz : https://www.mouser.com.tr/c/embedded-solutions/wireless-rf-modules/gnss-gps-modules/
| GPS Modülü | Kullanılan Protokoller | Hazır Kütüphane | Yazılım Platformu | Driver Gereksinimi |
|---|---|---|---|---|
| Adafruit Ultimate GPS Breakout | UART | Adafruit GPS Kütüphanesi (GitHub) | Arduino, Python | Hayır, kütüphane mevcut. |
| TinyGPS++ Kütüphanesi (GitHub) | Arduino, ESP32, ESP8266 | Hayır, kütüphane mevcut. | ||
| Adafruit Ultimate GPS + GLONASS (PA1616D) | UART | Adafruit GPS Kütüphanesi (GitHub) | Arduino, Python | Hayır, kütüphane mevcut. |
| TinyGPS++ Kütüphanesi (GitHub) | Arduino, ESP32, ESP8266 | Hayır, kütüphane mevcut. | ||
| Ublox GY-GPSV3 NEO-8M | UART | u-blox C++/Python API (u-blox Docs) | Arduino, STM32, Raspberry Pi, Python | Hayır, kütüphane mevcut. |
| TinyGPS++ Kütüphanesi (GitHub) | Arduino, ESP32, ESP8266 | Hayır, kütüphane mevcut. | ||
| NeoGPS Kütüphanesi (GitHub) | Arduino, AVR, ESP8266 | Hayır, kütüphane mevcut. | ||
| Ublox NEO-6M GPS Modülü | UART | TinyGPS++ Kütüphanesi (GitHub) | Arduino, ESP32, ESP8266, STM32 | Hayır, kütüphane mevcut. |
| NeoGPS Kütüphanesi (GitHub) | Arduino, AVR, ESP8266 | Hayır, kütüphane mevcut. | ||
| u-blox C++/Python API (u-blox Docs) | Arduino, Raspberry Pi, STM32, Python | Hayır, kütüphane mevcut. | ||
| Beitian BN-220 GPS Modülü | UART | TinyGPS++ Kütüphanesi (GitHub) | Arduino, ESP32, ESP8266 | Hayır, kütüphane mevcut. |
| NeoGPS Kütüphanesi (GitHub) | Arduino, AVR, ESP8266 | Hayır, kütüphane mevcut. | ||
| Ublox ZED-F9P RTK GPS Modülü | UART, I2C, SPI | u-blox F9P RTK Kütüphanesi (u-blox Docs) | Arduino, Raspberry Pi, STM32, Python | Hayır, kütüphane mevcut. |
| TinyGPS++ Kütüphanesi (GitHub) | Arduino, ESP32, ESP8266 | Hayır, kütüphane mevcut. |
| Kütüphane | Platformlar | Avantajlar | Olası Sorunlar |
|---|---|---|---|
| TinyGPS++ | Arduino, ESP32, ESP8266 | Basit ve hızlı kullanım. Hızlı entegrasyon sağlar. | Bellek kısıtlaması olan projelerde yetersiz olabilir, örneğin düşük bellekli cihazlarda. |
| NeoGPS | Arduino, AVR, ESP8266 | Düşük bellek kullanımı, hızlı veri işleme. Gerçek zamanlı verileri işlemek için optimize edilmiştir. | Yapılandırması daha karmaşık olabilir, başlangıç seviyesindeki kullanıcılar için zorlayıcı olabilir. |
| u-blox API | Arduino, STM32, Raspberry Pi | Gelişmiş veri işleme, GNSS desteği, yüksek doğruluklu veriler sağlar. | Basit projelerde fazla karmaşık ve donanım gereksinimleri yüksek olabilir. Ayrıca, API'yi kullanmak için biraz daha fazla öğrenme süresi gerekebilir. |
| u-blox F9P RTK | Arduino, STM32, Raspberry Pi | RTK (Real-Time Kinematic) desteği, çoklu GNSS Global Navigation Satellite System) sistemlerini destekler, yüksek doğruluk sağlar (santimetre seviyesinde). | Yüksek maliyet, karmaşık yapılandırma, yüksek donanım gereksinimi. |
- Geçen sene finalist olan takım gps için bunu kullanmışlar güç tüketimi bakımından daha az olduğu ve daha hızlı güncelleme hızı için bunu kullandıklarını düşünüyordum Mete başkan " Fazla profesyonel bir ürün , Bunu kullanmamız zor olur. Önce elimizdekiyle işi bitirelim sonra geçmeyi deneriz" dedi.
- İrtifa
- Enlem
- Boylam
bilgisi olmak zorunda.
- Jireskoptan gelen verinin birinimi dps mi ?
- Ivmenin birimi g-force mudur ?
yoksa başka bir şey olup onu dönüştürmemiz mi gerekir ?
-
USB -TTL olan bağlantı nasıl yapacağız onunla ilgili bir araştırma yapılmalı ?
-
yaptığımız form uygulamasını nasıl export edip onu desktop app yapmamız gerekiyor?
-
HYI denilen sistemin com bağlantı ayarları ile ilgili birkaç madde var onu anlamadık.
bu kodu denedik ve çalıştı. Veri aldık ancak şöyle bir durum var , NMEA DECODER da çevirmemiz ve o şekilde Latitude, Longitude, Time çıktılarını anlamamız gerekti.
Plan Algoritması: GPS Verisinin Alınması, Decode Edilmesi ve Gösterimi
- Arduino'dan NMEA verisi alınması için gerekli seri port ayarlarını yap.
- COM port ve baud rate değerlerini belirle.
- Seri portu açarak Arduino'dan veri okumayı başlat.
-
Arduino'dan gelen veriyi seri port üzerinden oku.
- Her satırın bir NMEA cümlesi olduğunu varsay.
- NMEA cümlelerini satır bazında al (ör.
$GPGLL,$GPRMC).
-
NMEA cümlelerini bir buffer içine kaydet.
- Cümle tamamlandığında (satır sonu
\ngörüldüğünde), decode işlemine geç.
- Cümle tamamlandığında (satır sonu
-
Filtreleme:
- Gelen veriyi kontrol et.
- Yalnızca
$GPGLLveya$GPRMCcümlelerini işle.
-
Veri Ayrıştırma:
NmeaParserkullanarak cümleleri otomatik decode et.$GPGLL: Latitude, Longitude, UTC Time.$GPRMC: Latitude, Longitude, UTC Time ve ek olarak hız/yön bilgisi.
- Ayrıştırılan değerleri geçerli formatta (ondalık derece) hesapla.
-
Koordinatları Ondalık Dereceye Dönüştür:
- Latitude ve Longitude değerlerini derece/dakika formatından ondalık dereceye çevir.
-
Enlem, boylam ve zamanı arayüzde göster:
- Latitude, Longitude ve Time bilgilerini bir
TextBoxveyaLabeliçinde güncelle.
- Latitude, Longitude ve Time bilgilerini bir
-
Harita Güncellemesi:
- Harita üzerindeki mevcut marker'ı temizle.
- Yeni Latitude ve Longitude değerleriyle bir marker ekle.
- Haritayı marker’ın bulunduğu konuma merkezle.
-
Ayrıştırılan tüm verileri bir CSV dosyasına yaz.
- Dosya mevcut değilse, başlık satırı ekle:
Latitude,Longitude,Time. - Yeni bir veri alındığında, bu veriyi dosyaya ekle:
Latitude, Longitude, Time 39.968672, 32.743390, 13:45:16
- Dosya mevcut değilse, başlık satırı ekle:
-
Veri güvenliği için dosya işlemlerini doğru yönet:
- Dosya açıkken hatalardan korunmak için try-catch bloğu kullan.
-
Yeni veri geldiğinde mevcut veriyi geçersiz kıl:
- Haritada yalnızca en güncel veriyi göster.
- Haritayı sürekli yeni gelen veriyle güncelle.
-
Daha önce gelen tüm verileri CSV dosyasına sakla:
- Harita güncellenirken eski veriler kaybolmaz, yalnızca yedeklenir.
-
Seri Port:
- Port açık değilse kullanıcıyı uyar ve programı durdur.
- Hatalı port seçimi yapılırsa, kullanıcıya uygun mesaj göster.
-
Decode İşlemi:
- Geçersiz bir NMEA cümlesi gelirse, işlemi atla ve bir sonraki satıra geç.
-
Dosya İşlemleri:
- CSV dosyasına yazarken oluşabilecek hataları yönet.
- Seri port bağlantısını kapat.
- Haritayı son gösterilen konumda bırak.
- Yedeklenen veriler CSV dosyasında eksiksiz bir şekilde bulunmalı.
Başla
↓
Seri portu aç ve GPS modülünden veri al
↓
Her satırı oku:
Eğer `$GPGLL` veya `$GPRMC` ile başlıyorsa:
→ NmeaParser kullanarak veriyi ayrıştır
→ Latitude, Longitude ve UTC Time bilgilerini çıkar
→ Koordinatları ondalık dereceye dönüştür
→ Arayüzü güncelle: Enlem, Boylam ve Zaman bilgilerini göster
→ Haritada konumu güncelle: Marker ekle ve haritayı merkeze al
→ Veriyi `gps_data.csv` dosyasına yedekle
Değilse:
→ Bir sonraki satıra geç
↓
Yeni veri geldikçe işlemi tekrarla
↓
Hata varsa kullanıcıyı bilgilendir
↓
Program sonlandırıldığında:
→ Seri portu kapat
→ Haritayı ve CSV dosyasını kaydet
Bitti
Plan: Seri Porttan Gelen NMEA Verisini Otomatik Decode Etme ve İşleme
-
Kütüphaneler:
- NmeaParser:
- NMEA verilerini otomatik olarak ayrıştırmak için kullanılır.
$GPGLL,$GPRMC,$GPGGAgibi standart NMEA cümlelerini destekler.- Yükleme:
Install-Package NmeaParser
- GMap.NET:
- Harita üzerinde konum göstermek için kullanılır.
- Google Maps, OpenStreetMap gibi sağlayıcılardan veri alır.
- NmeaParser:
-
Donanım:
- Arduino + GPS modülü
- Bilgisayara USB ile bağlı Arduino cihazı
-
Seri Porttan Veri Alımı:
- Arduino, GPS modülünden aldığı NMEA cümlelerini seri port üzerinden bilgisayara gönderir.
- C# uygulaması, bu verileri seri port dinleyicisiyle alır.
-
NMEA Verisinin Decode Edilmesi:
- Tüm NMEA cümleleri
NmeaParserile işlenir. $GPGLLveya$GPRMCcümlelerinden:- Latitude (Enlem),
- Longitude (Boylam),
- UTC Time bilgileri ayrıştırılır.
- Tüm NMEA cümleleri
-
Harita Üzerinde Gösterim:
- Ayrıştırılan Latitude ve Longitude bilgileri, GMap.NET kullanılarak harita üzerinde marker (işaretleyici) olarak gösterilir.
- Harita, yeni konuma göre merkezlenir.
-
Verilerin Yedeklenmesi:
- Decode edilen tüm veriler, bir CSV dosyasına şu formatta kaydedilir:
Latitude, Longitude, Time
- Decode edilen tüm veriler, bir CSV dosyasına şu formatta kaydedilir:
-
$GPGLL Cümlesi:
- Format:
$GPGLL,<latitude>,<N/S>,<longitude>,<E/W>,<UTC time>,<status>,<checksum> - Örnek:
$GPGLL,3958.12035,N,03244.60339,E,134516.00,A*61 - Ayrıştırılacak Değerler:
Latitude: 39°58.12035' N → 39.96867267Longitude: 32°44.60339' E → 32.74339065UTC Time: 13:45:16
- Format:
-
$GPRMC Cümlesi:
- Format:
$GPRMC,<UTC time>,<status>,<latitude>,<N/S>,<longitude>,<E/W>,<speed>,<course>,<date>,... - Örnek:
$GPRMC,134517.00,A,3958.12036,N,03244.60344,E,0.601,,270125,,,A*74 - Ek olarak:
- Hız bilgisi
speedve yön bilgisicourseayrıştırılabilir.
- Hız bilgisi
- Format:
-
Ondalık Dereceye Dönüştürme:
- Derece/Dakika formatını ondalık dereceye dönüştürmek için:
private double ConvertToDecimal(string degreeString, string direction) { double degrees = double.Parse(degreeString.Substring(0, 2)); double minutes = double.Parse(degreeString.Substring(2)); double decimalDegrees = degrees + (minutes / 60); if (direction == "S" || direction == "W") decimalDegrees *= -1; return decimalDegrees; }
- Derece/Dakika formatını ondalık dereceye dönüştürmek için:
-
GMap.NET Harita Ayarları:
private void InitializeMap() { gMapControl1.MapProvider = GMapProviders.GoogleMap; // Harita sağlayıcı GMaps.Instance.Mode = AccessMode.ServerOnly; gMapControl1.Position = new PointLatLng(39.92077, 32.85411); // Başlangıç pozisyonu gMapControl1.MinZoom = 1; gMapControl1.MaxZoom = 20; gMapControl1.Zoom = 15; markersOverlay = new GMapOverlay("markers"); gMapControl1.Overlays.Add(markersOverlay); } private void UpdateMap(double latitude, double longitude) { markersOverlay.Markers.Clear(); // Eski markerları temizle PointLatLng point = new PointLatLng(latitude, longitude); GMarkerGoogle marker = new GMarkerGoogle(point, GMarkerGoogleType.red_dot); markersOverlay.Markers.Add(marker); gMapControl1.Position = point; }
-
Marker Güncelleme:
- Yeni konum geldiğinde marker haritada güncellenir ve harita otomatik olarak merkezlenir.
-
CSV Formatında Kaydetme:
private void SaveToCsv(double latitude, double longitude, string utcTime) { string filePath = "gps_data.csv"; if (!File.Exists(filePath)) { File.WriteAllText(filePath, "Latitude,Longitude,Time\n"); // Başlık satırı } File.AppendAllText(filePath, $"{latitude},{longitude},{utcTime}\n"); }
-
Her Yeni Veri Geldiğinde Kaydetme:
$GPGLLveya$GPRMCcümlesi decode edildikten sonra, bu fonksiyon çağrılır.
-
Kütüphaneler:
NmeaParser: NMEA cümlelerini decode etmek için.GMap.NET: Harita üzerinde konum göstermek için.
-
Uygulama Akışı:
- Arduino’dan seri port üzerinden NMEA verileri alınır.
$GPGLLveya$GPRMCcümleleri filtrelenir.- Latitude, Longitude ve Time bilgileri ayrıştırılır.
- Decode edilen veriler:
- Harita üzerinde marker olarak gösterilir.
gps_data.csvdosyasına kaydedilir.
Örnek kod GPT:
using System; using System.IO.Ports; using System.Windows.Forms; using GMap.NET; using GMap.NET.MapProviders; using GMap.NET.WindowsForms; using GMap.NET.WindowsForms.Markers; using System.IO; using NmeaParser; using NmeaParser.Messages; public partial class MainForm : Form { private SerialPort serialPort; private GMapOverlay markersOverlay;
public MainForm()
{
InitializeComponent();
InitializeMap();
}
// 1. Harita Başlangıç Ayarları
private void InitializeMap()
{
gMapControl1.MapProvider = GMapProviders.GoogleMap; // Google Maps sağlayıcı
GMaps.Instance.Mode = AccessMode.ServerOnly;
gMapControl1.Position = new PointLatLng(39.92077, 32.85411); // Ankara başlangıç pozisyonu
gMapControl1.MinZoom = 1;
gMapControl1.MaxZoom = 20;
gMapControl1.Zoom = 15;
markersOverlay = new GMapOverlay("markers");
gMapControl1.Overlays.Add(markersOverlay);
}
// 2. Seri Port Bağlantısını Aç
private void btnConnect_Click(object sender, EventArgs e)
{
serialPort = new SerialPort
{
PortName = cmbPorts.Text, // Kullanıcıdan seçilen COM port
BaudRate = 9600,
DataBits = 8,
Parity = Parity.None,
StopBits = StopBits.One
};
serialPort.DataReceived += SerialPort_DataReceived; // Veri geldiğinde tetiklenecek
serialPort.Open();
MessageBox.Show("Bağlantı Başarılı!");
}
// 3. Seri Port Bağlantısını Kapat
private void btnDisconnect_Click(object sender, EventArgs e)
{
if (serialPort != null && serialPort.IsOpen)
{
serialPort.Close();
MessageBox.Show("Bağlantı Kapatıldı!");
}
}
// 4. Seri Port Üzerinden Veri Al
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string nmeaData = serialPort.ReadLine();
try
{
var message = NmeaMessage.Parse(nmeaData); // NmeaParser ile ayrıştırma
if (message is Gll gll) // Eğer $GPGLL mesajı geldiyse
{
ProcessGllMessage(gll);
}
else if (message is Rmc rmc) // Eğer $GPRMC mesajı geldiyse
{
ProcessRmcMessage(rmc);
}
}
catch (Exception ex)
{
Console.WriteLine($"Decode hatası: {ex.Message}");
}
}
// 5. GPGLL Mesajını İşle
private void ProcessGllMessage(Gll gll)
{
double latitude = gll.Latitude;
double longitude = gll.Longitude;
string time = gll.Time.ToString();
// Arayüz Güncelle
UpdateUI(latitude, longitude, time);
// Haritada Göster
UpdateMap(latitude, longitude);
// CSV'ye Kaydet
SaveToCsv(latitude, longitude, time);
}
// 6. GPRMC Mesajını İşle
private void ProcessRmcMessage(Rmc rmc)
{
double latitude = rmc.Latitude;
double longitude = rmc.Longitude;
string time = rmc.FixTime.ToString();
// Arayüz Güncelle
UpdateUI(latitude, longitude, time);
// Haritada Göster
UpdateMap(latitude, longitude);
// CSV'ye Kaydet
SaveToCsv(latitude, longitude, time);
}
// 7. Arayüzü Güncelle
private void UpdateUI(double latitude, double longitude, string time)
{
this.Invoke((MethodInvoker)delegate
{
txtLatitude.Text = latitude.ToString("F6");
txtLongitude.Text = longitude.ToString("F6");
txtTime.Text = time;
});
}
// 8. Haritayı Güncelle
private void UpdateMap(double latitude, double longitude)
{
markersOverlay.Markers.Clear(); // Önceki markerları temizle
PointLatLng point = new PointLatLng(latitude, longitude);
GMarkerGoogle marker = new GMarkerGoogle(point, GMarkerGoogleType.red_dot);
markersOverlay.Markers.Add(marker);
gMapControl1.Position = point;
}
// 9. CSV Dosyasına Kaydet
private void SaveToCsv(double latitude, double longitude, string utcTime)
{
string filePath = "gps_data.csv";
if (!File.Exists(filePath))
{
File.WriteAllText(filePath, "Latitude,Longitude,Time\n"); // Başlık satırı
}
File.AppendAllText(filePath, $"{latitude},{longitude},{utcTime}\n");
}
}
Yazılım ve Donanım Arasındaki Haberleşme Mantığını anlamak için yaptığım deneylerin döküman repoları :
(about one month ago)2025_01_07 / versiyon hatası ve çalışmayan GPS
🕙09:00-15:28
groundStation.cs 26th line there is "private GMapControl gmapcontrol = new ; " line getting unhendeled exception error aldığımız hatayı bir türlü çözemedik versiyon hatasından kaynaklı bir exception error alıyoruz gpt sorduk araştırdık diğer insanların yaptığı repoları inceledim lakin işe yarar bir çıktı alamadık.
-
Alınan Hata : Could not load type 'GMap.NET.Singleton`1' from assembly 'GMap.NET.Core, Version=2.1.6.0, Culture=neutral, PublicKeyToken=b85b9027b614afef' NOT : Hata .Net uzantılı bir proje oluşturduğumuzda giderildi. Ceren Hanıma sevgilerimizle :)
Gps satın almıştım onu denemeye çalıştık ama açık havada olması gerektiğinden olumlu bir çıktı alamadık, çalışıp çalışmadığını bilmiyoruz.
🕞 15:30-18:28
Yanıp sönmeye başladı ama hiç bir şey yazdırmıyo Sinyal kontolü için bunu denedim Rx Tx değiştirip 10 11 yaptım. Rx Tx 10 (eskiden 3 yaptim calismadi port okuyor ama yok ) Tx Rx 11 (eskiden 4 yaptim calismadi port okuyor ama yok) Gnd Gnd Vcc 5v
dışarda çok beklememe rağmen çalışmadı, bir yerlerim dondu :/ sağlık olsun ne yapalım efenim.. yarın terasta deneyeceğiz cerenle :) umarım olur.
Kodda kullanılan temel kütüphaneler şunlardır:
Adafruit_MPU6050.h: MPU6050 ivmeölçer ve jiroskop sensörü için Adafruit kütüphanesi.Adafruit_BMP280.h: BMP280 barometrik basınç sensörü için Adafruit kütüphanesi.Adafruit_Sensor.h: Adafruit'in sensör arabirimi.Wire.h: I2C haberleşme için kullanılan kütüphane.SPI.h: SPI haberleşme kütüphanesi.
Değişkenler
float Q = 0.001; // Süreç gürültü kovaryansı
float R = 0.03; // Ölçüm gürültü kovaryansı
float P = 1; // Hata kovaryansı
float K; // Kalman kazancı
float filteredX = 0, filteredY = 0, filteredZ = 0;
float axOffset = 0, ayOffset = 0, azOffset = 0;
float gxOffset = 0, gyOffset = 0, gzOffset = 0;
float baseAltitude = 0;
float h = bmp.readAltitude(1030.9);
float a = sqrt(pow(axOffset, 2) + pow(ayOffset, 2) + pow(azOffset, 2));- Kalman Filtresi kullanılarak sensör verileri gürültüden arındırılır.
- Kovaryans, iki değişkenin birbirleriyle nasıl değiştiğini ölçen bir istatistiksel değerdir; pozitifse aynı yönde, negatifse ters yönde değiştiklerini gösterir.
Kalman Filtre Fonksiyonu
float applyKalmanFilter(float measurement, float &estimate) {
P += Q;
K = P / (P + R);
estimate = estimate + K * (measurement - estimate);
P *= (1 - K);
return estimate;
}applyKalmanFilterfonksiyonu, ölçülen veriyi süzerek daha doğru bir tahmin üretir.
Sensör Kalibrasyon Kodu
void sensorKalibrasyonu() {
Serial.println("Sensör kalibrasyonu başlatılıyor");
sensors_event_t a, g, temp;
int calibrationLoops = 1000;
for (int i = 0; i < calibrationLoops; i++) {
mpu.getEvent(&a, &g, &temp);
axOffset += a.acceleration.x;
ayOffset += a.acceleration.y;
azOffset += a.acceleration.z;
gxOffset += g.gyro.x;
gyOffset += g.gyro.y;
gzOffset += g.gyro.z;
delay(5);
}
axOffset /= calibrationLoops;
ayOffset /= calibrationLoops;
azOffset /= calibrationLoops;
gxOffset /= calibrationLoops;
gyOffset /= calibrationLoops;
gzOffset /= calibrationLoops;
baseAltitude = bmp.readAltitude(1030.9);
Serial.println("Kalibrasyon tamamlandı.");
}- Sensör verilerinin ortalaması alınarak gürültü azaltılır.
- MPU6050 ve BMP280 için referans değerler belirlenir.
MPU ve BMP Kontrol Fonksiyon Kodu
Bu fonksiyonlar MPU6050 ve BMP280 sensörlerinin çalışıp çalışmadığını kontrol eder.
void MPU() {
for (int i=0; i<3; i++) {
if (!mpu.begin()) {
Serial.println("Failed to find MPU6050 chip");
MPU(); // Çalışmazsa tekrar başlat
}
}
Serial.println("MPU çalışmaya hazır");
}void BMP() {
unsigned status = bmp.begin(0x76);
for (int i=0; i<3; i++) {
if (!status) {
Serial.println(F("BMP280 sensörü bulunamadı!"));
while (1) delay(10);
}
}
}roketHareketEtmiyor, LiffOff , Apogee , Paraşüt Açılma Kontrolü , Roket Yere İndiğinde Kontrol
void roketHareketEtmiyor() {
if(h==){
axOffset = sensor.acceleration.x;//offsetleri sabitliyoruz değer alınmıyo
ayOffset = sensor.acceleration.y;
azOffset = sensor.acceleration.z;
gxOffset = sensor.gyro.x;
gyOffset = sensor.gyro.y;
gzOffset = sensor.gyro.z;
}
else{ // uçmaya başlarsa kalibrasyondaki ofsetleri bir kere alıp devam ediyoruz sensor kalibrasyonundaki kod
mpu.getEvent(&a, &g, &temp);
axOffset += a.acceleration.x;
ayOffset += a.acceleration.y;
azOffset += a.acceleration.z;
gxOffset += g.gyro.x;
gyOffset += g.gyro.y;
gzOffset += g.gyro.z;
delay(500);
axOffset /= calibrationLoops;
ayOffset /= calibrationLoops;
azOffset /= calibrationLoops;
gxOffset /= calibrationLoops;
gyOffset /= calibrationLoops;
gzOffset /= calibrationLoops;
referansYukseklik = bmp.readAltitude(1030.9); // Referans yükseklik alınması
}Eğer roket kalibrasyonu tamamladıktan sonra uçuşa geçmezse uygulanacak tarife
void LiffOff(){// Başlangıç noktası
for (int i=0; i<3; i++){
if (h>referansYukseklik && a> kalibrasyondan alınan ivme){// ivmeyi bilemedik
delay(100);
}
else {
roketHareketEtmiyor();
delay(10000);
LiffOff();
}
}
Serial.println("ucus saglandi");
}
}Roketin belirli bir yükseklik ve ivme eşiğini geçtiğinde uçuş moduna geçtiğini belirler.
void apogee() {
for (int i=0; i<3; i++) {
if (pitch < 0 && dikey hız <= 0 && h1 < h2) {
delay(500);
} else {
delay(500);
apogee();
}
}
Serial.println("Apogee ulaşıldı");
}Roketin apogee'ye ulaşıp ulaşmadığını kontrol eder.
void parasut2() {
for (int i=0; i<3; i++) {
if (400 < h && h < 600) {
delay(500);
} else {
delay(500);
parasut2();
}
}
Serial.println("İkinci paraşüt açılabilir");
}400m ile 600m arasında ikinci paraşütün açılmasına izin verir.
void alcalmaKontrol() {
for (int i=0; i<3; i++) {
if (h1 == h2 && dikey hız == 0 && a == 0) {
delay(500);
} else {
delay(500);
alcalmaKontrol();
}
}
Serial.println("Roket yerde, GPS verisi alın");
}- Sensörleri başlatır.
- Kalibrasyon işlemlerini gerçekleştirir.
MPU,BMP,GPSveloramodüllerini kontrol eder.
- MPU6050 ve BMP280'den verileri okur ve Kalman filtresi uygular.
- Uçuşun her aşamasını denetleyerek uçuş kontrolü, apogee, paraşüt açılma ve iniş kontrolü fonksiyonlarını çalıştırır.
- Roketin yere indiğinde GPS verisini kaydeder.



