A high-performance, real-time embedded telemetry system and ground station desktop software engineered for aerospace and defense benchmark requirements. The project features a deterministic firmware architecture implemented on an ARM Cortex-M4 microcontroller and a high-throughput Ground Station GUI written in Python.
-
Deterministic Non-Blocking Architecture: Hardware Timer (
TIM2) drives a strict 50 Hz ($20\text{ ms}$ ) base sampling and transmission tick. Zero blocking delays (HAL_Delayor blocking I2C/UART transactions) inside Interrupt Service Routines to guarantee interrupt safety. -
Timer-Driven IMU & Baro Sampling: Replaced EXTI line polling with a deterministic
$50\text{ Hz}$ Hardware Timer flag mechanism (mpu_data_ready_flagandbmp_read_flag) to avoid pin noise and enforce synchronized frame generation. -
Hybrid Firmware Driver Model: Utilizes STM32 HAL for system clock tree initialization alongside optimized bitwise shift (
high << 8 | low) register extraction for raw sensor payloads. -
Robust 40-Byte Fixed Binary Frame Protocol: Custom telemetry packet structure featuring a 2-byte frame synchronization header (
0xAA 0x55), rolling sequence counter, payload identifier, and 16-bit CRC-CCITT verification. - Attitude & Environmental Estimation: Real-time Roll and Pitch calculation using a Complementary Filter fusing 6-DOF IMU data (MPU6050), alongside barometric pressure and temperature acquisition (BMP280).
- High-FPS Desktop Ground Station: Built with PyQt6 and PyQtGraph to ensure sub-1% CPU usage at 50 FPS telemetry rates, integrated with an OpenGL 3D aircraft visualization view and automatic CSV data logging.
graph TD
subgraph SENSORS ["Hardware Layer (I2C Bus @ 100 kHz)"]
MPU["MPU6050 (6-DOF IMU)"]
BMP["BMP280 (Baro & Temp)"]
end
subgraph MCU ["STM32F446RE Firmware Architecture"]
ISR["TIM2 Hardware Timer ISR (50 Hz / 20 ms)<br/>• Sets volatile flags: mpu_read, bmp_read, send_telemetry"]
subgraph MAIN_LOOP ["Deterministic Main Loop Priorities"]
P1["1. Read MPU6050 Raw Payload"]
P2["2. Read BMP280 Raw Payload (10 Hz)"]
P3["3. Build Telemetry Packet & Calculate CRC-16"]
end
UART_TX["UART2 Peripheral (115200 Baud / 8N1)"]
end
subgraph GUI ["Python Ground Station (Desktop App)"]
PARSER["Non-Blocking State Machine Parser<br/>• Header Check (0xAA 0x55)<br/>• Sequence Counter Verification<br/>• CRC-16 Validation"]
subgraph DISP ["Real-Time Display & Storage"]
G3D["3D Orientation View (OpenGL)"]
G2D["2D Live Graphs (PyQtGraph)"]
LOG["Automated CSV Logging"]
end
end
MPU -->|Raw I2C Payload| P1
BMP -->|Raw I2C Payload| P2
ISR -->|Trigger Flags| MAIN_LOOP
P1 --> P3
P2 --> P3
P3 -->|40-Byte Binary Frame| UART_TX
UART_TX -->|Serial Data Stream| PARSER
PARSER -->|Validated Data| G3D
PARSER -->|Validated Data| G2D
PARSER -->|Timestamped Data| LOG
style SENSORS fill:#1f2937,stroke:#3b82f6,stroke-width:2px,color:#fff
style MCU fill:#111827,stroke:#10b981,stroke-width:2px,color:#fff
style GUI fill:#1e1b4b,stroke:#8b5cf6,stroke-width:2px,color:#fff
| Microcontroller Pin | Peripheral / Module | Signal Line | Functional Description |
|---|---|---|---|
| PB6 | I2C1 | I2C1_SCL |
Serial Clock Line ( |
| PB7 | I2C1 | I2C1_SDA |
Serial Data Line |
| PA2 | USART2 | USART2_TX |
Telemetry Transmit Line ( |
| PA3 | USART2 | USART2_RX |
Telemetry Receive Line (Reserved for V2.0) |
| +3.3V / GND | Power Bus | VCC / GND | Common Power and Ground Rail |
To guarantee zero frame desynchronization and immediate packet loss detection, the network protocol enforces 1-byte struct alignment (#pragma pack(push, 1)):
0x00 0x01 0x02 0x04 0x05 0x06 0x26 0x28
+---------+---------+---------+---------+---------+--------------------------+---------+
| 0xAA | 0x55 | SEQ_NUM | LENGTH | TYPE | PAYLOAD (32-Byte Floats) | CRC16 |
| Header1 | Header2 | (uint16)| (0x20) | (0x01) | Accel, Gyro, Temp, Press | (uint16)|
+---------+---------+---------+---------+---------+--------------------------+---------+
Click the thumbnail below to watch the full system demonstration, featuring real-time 50 Hz telemetry streaming, 3D aircraft attitude synchronization, and zero-packet-loss verification:
📌 Note: If the video thumbnail does not load, you can watch the demonstration directly on YouTube via this link.
Hardware signal integrity was verified on the physical I2C bus using a Saleae Logic Analyzer at a
-
I2C Clock Verification: Stable
$100\text{ kHz}$ SCL frequency validated. -
Bus Protocol Integrity: Validated Start/Stop bit conditions, 7-bit slave addressing (
0x68for MPU6050,0x76for BMP280), and slave ACK responses without clock stretching or timeout bus lockups.
To verify long-term stability and zero packet loss under continuous streaming, a 30-minute stress test was executed. The results were logged directly to telemetry_data_log.csv.
| Test Benchmark ( |
Test Benchmark ( |
|---|---|
![]() |
![]() |
| Timestamp: 09:35:43 | Lost Packets: 0 | Timestamp: 10:05:43 | Lost Packets: 0 |
| Test Parameter | Targeted Value | Measured / Verified Value | Status | Verification Method |
|---|---|---|---|---|
| I2C SCL Frequency | PASSED | Saleae Logic Analyzer Waveform | ||
| I2C Bus ACK/NACK | Hardware ACK | PASSED | Saleae Protocol Decoder | |
| Telemetry Rate | PASSED | Hardware TIM2 ISR & GUI FPS Counter | ||
| Stress Test Duration | PASSED | System Clock & CSV Timestamp Delta | ||
| Total Transmitted Packets | PASSED | Continuous SEQ_NUM Counter |
||
| Packet Loss Rate | 0 Lost Packets | PASSED | Parser State Machine Tracking | |
| CRC-16 Checksum Errors | 0 Errors | PASSED | Software CRC-CCITT Verification |
├── firmware/
│ ├── Core/
│ │ ├── Inc/
│ │ │ ├── config.h # Global defines, Telemetry struct, CRC-16 inline utility
│ │ │ ├── mpu6050.h # MPU6050 driver header & raw data structures
│ │ │ ├── bmp280.h # BMP280 driver header & trimming parameters
│ │ │ └── main.h # HAL imports and system function prototypes
│ │ └── Src/
│ │ ├── main.c # Entry point, TIM2 ISR flag handling, while(1) scheduling
│ │ ├── mpu6050.c # MPU6050 I2C burst read & register bit-shift extraction
│ │ └── bmp280.c # BMP280 trimming math & compensation implementation
│ └── Firmware.ioc # STM32CubeMX Project Configuration File
├── ground_station/
│ ├── ground_station.py # PyQt6 Desktop GUI & Serial State Machine Parser
│ └── baykar_bayraktar_tb2.glb # 3D CAD Aircraft Model
├── docs/
│ ├── i2c_saleae_verification.png
│ ├── ground_station_gui_t0.png
│ └── ground_station_gui_t30.png
├── telemetry_data_log.csv # 30-minute validation CSV log
└── README.md # System Engineering Documentation
- Open STM32CubeIDE and import the
firmware/directory. - Ensure compiler flags include
-O2optimization and Hardware FPU enabled (-mfpu=fpv4-sp-d16 -mfloat-abi=hard). - Compile and flash the binary to the STM32F446RE Nucleo via ST-LINK.
- Install Python dependencies:
pip install PyQt6 pyqtgraph PyOpenGL pyserial trimesh numpy
- Run the Ground Station application:
python ground_station/ground_station.py
- Select the active ST-LINK COM port, set Baud Rate to
115200, and click Start Telemetry.
- UART RX Ring Buffer: Circular buffer implementation for non-blocking ground-to-air command parsing.
- UART TX DMA Integration: Offload UART frame serialization to DMA channels to reduce CPU usage.
- Independent Watchdog (IWDG): Hardware fault recovery and dynamic I2C bus-reset sequences on bus lockup.
- Sensor Fusion Upgrade: Extended Kalman Filter (EKF) integration for noise-immune attitude estimation.
- RF Wireless Link: Replace wired UART link with SPI-based NRF24L01 or LoRa modules.


