A Python-based application for real-time aircraft tracking using Software-Defined Radio (SDR). This tool receives, decodes, and visualizes ADS-B (Automatic Dependent Surveillance-Broadcast) signals transmitted by aircraft, displaying live flight information on an interactive map with enriched data from online sources.
-
Real-Time ADS-B Decoding: Tunes RTL-SDR dongle to 1090 MHz and decodes Mode-S/ADS-B messages in real-time
-
Live Aircraft Table: Displays comprehensive flight data including:
- ICAO 24-bit address (unique aircraft identifier)
- Callsign/flight number
- Altitude (feet)
- GPS coordinates (latitude/longitude)
- Ground speed (knots)
- Heading (degrees)
- Vertical rate (climb/descent rate)
- Squawk code (transponder code)
- Message count and last-seen timestamp
-
Interactive Map Visualization:
- OpenStreetMap integration with live positioning
- Rotating aircraft icons that align with actual heading
- Flight path trails (approximately 3 minutes of history)
- Clickable markers to select aircraft
- Hover tooltips showing detailed flight information
-
Detailed Aircraft Information Panel:
- Aircraft registration number
- Aircraft type and manufacturer
- Operator/airline information
- Flight route (origin β destination)
- High-resolution aircraft photos from planespotters.net
-
Online Data Enrichment:
- Background API calls to hexdb.io for aircraft metadata
- Automatic photo retrieval from planespotters.net
- No API keys required β all services are free
-
Demo Mode: If no SDR hardware is detected, the application runs with 5 simulated aircraft for testing and demonstration purposes
- Modern dark-themed GUI with color-coded information
- Intuitive controls: βΆ Start / βΉ Stop / π Clear
- Activity log showing status messages and aircraft state changes
- Responsive layout with synchronized table and map selection
Hardware:
- RTL-SDR dongle (RTL2832U + R820T/R820T2 tuner)
- Antenna suitable for 1090 MHz reception (ideally a dedicated ADS-B antenna)
Software:
- Python 3.10 or higher
Download and install Python 3.10+ from python.org
Using Zadig (Recommended):
- Download Zadig from zadig.akeo.ie
- Plug in your RTL-SDR dongle
- Launch Zadig
- Go to Options β List All Devices
- Select Bulk-In, Interface (Interface 0) from the dropdown
- You may see it as "RTL2838UHIDIR" or similar
- In the target driver box (right side with green arrow), select WinUSB
- Click Replace Driver or Install Driver
- Wait for completion (may take 1-2 minutes)
- Restart your computer
Required DLL Files:
The pyrtlsdr library requires three DLL files. Place them in the same directory as the script or ensure they're in your system PATH:
librtlsdr.dlllibusb-1.0.dlllibwinpthread-1.dll
You can download pre-compiled Windows binaries from:
- rtl-sdr.com releases
- Or compile from source: osmocom/rtl-sdr
To add DLLs to PATH temporarily:
set PATH=%CD%;%PATH%pip install pyrtlsdr==0.2.91 numpy tkintermapview pillowpython adsb_decoder.pysudo apt update
sudo apt install python3 python3-pip rtl-sdr librtlsdr-dev libusb-1.0-0-devCreate a udev rule to allow non-root access to the RTL-SDR device:
sudo nano /etc/udev/rules.d/20-rtlsdr.rulesAdd the following line:
SUBSYSTEM=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2838", MODE="0666"
Save and reload udev rules:
sudo udevadm control --reload-rules
sudo udevadm triggerUnplug and replug your RTL-SDR dongle.
Prevent the DVB-T TV tuner drivers from claiming the device:
sudo nano /etc/modprobe.d/blacklist-rtl.confAdd these lines:
blacklist dvb_usb_rtl28xxu
blacklist rtl2832
blacklist rtl2830
Save and reboot:
sudo rebootpip3 install pyrtlsdr==0.2.91 numpy tkintermapview pillowrtl_test -tYou should see device information. Press Ctrl+C to exit.
python3 adsb_decoder.pyIf not already installed:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"brew install rtl-sdr libusbbrew install python@3.10pip3 install pyrtlsdr==0.2.91 numpy tkintermapview pillowpython3 adsb_decoder.pyNote: macOS may require granting terminal access to USB devices. Check System Preferences β Security & Privacy if the device isn't detected.
Automatic Dependent Surveillance-Broadcast (ADS-B) is a surveillance technology that allows aircraft to determine their position via satellite navigation (GPS) and periodically broadcast it, enabling them to be tracked. The system is "automatic" because it requires no pilot input, "dependent" because it relies on navigation systems, and "broadcast" because it transmits data to all receivers in range.
ADS-B is mandated in many airspaces worldwide (including US, Europe, Australia) and is a cornerstone of NextGen air traffic management.
- Position Determination: Aircraft GPS receiver calculates precise position (latitude, longitude, altitude)
- Data Encoding: Flight data is encoded into standardized message formats
- Transmission: Messages are broadcast on 1090 MHz (Mode-S Extended Squitter) or 978 MHz (UAT in the US)
- Reception: Ground stations, other aircraft, and hobbyist receivers decode the signals
- Tracking: Data is processed to track aircraft movements in real-time
ADS-B messages are transmitted using Mode-S Extended Squitter (1090ES) format. Each message is structured as follows:
Preamble (8 ΞΌs) + Data Block (56 or 112 bits) + Parity (24 bits)
Preamble:
- 8 microseconds
- Pulse pattern: 1-0-1-0-0-0-0-1-0-1-0-0-0-0 (allows receiver synchronization)
Data Block:
- Short messages: 56 bits (DF 0-15)
- Long messages: 112 bits (DF 16-24) β ADS-B uses DF 17 or 18
Parity/CRC:
- 24-bit CRC (Cyclic Redundancy Check) for error detection
- Generator polynomial: 0xFFFFFA (standard Mode-S)
112-bit Extended Squitter Message:
| Bits | Field | Description |
|---|---|---|
| 1-5 | Downlink Format (DF) | 17 = ADS-B, 18 = TIS-B/ADS-R |
| 6-8 | Capability (CA) | Transponder capability |
| 9-32 | ICAO Address | 24-bit unique aircraft identifier (hex) |
| 33-88 | ME (Message, Extended) | 56-bit payload β varies by Type Code |
| 89-112 | Parity (PI) | 24-bit CRC checksum |
The ME field's Type Code (TC) determines the message content:
| TC Range | Category | Data Provided |
|---|---|---|
| 1-4 | Aircraft Identification | Callsign (flight number) |
| 5-8 | Surface Position | Position on ground (airport surface) |
| 9-18 | Airborne Position (Barometric) | Latitude, longitude, altitude (barometric) |
| 19 | Airborne Velocity | Speed, heading, vertical rate |
| 20-22 | Airborne Position (GNSS) | Latitude, longitude, altitude (GNSS-derived) |
| 23-27 | Reserved / Test | β |
| 28 | Aircraft Status | Emergency codes, TCAS RAs |
| 29 | Target State and Status | Autopilot settings, target altitude |
| 31 | Operational Status | Capability, NIC/NAC codes |
ADS-B uses CPR encoding to reduce bandwidth while maintaining precision:
- Two message types: Even frame (CPR format 0) and Odd frame (CPR format 1)
- Each frame contains encoded latitude/longitude
- Decoding requires BOTH frames (received within ~10 seconds) to resolve global position
- Locally unambiguous: If receiver knows approximate position, single frame suffices
- 17-bit encoding: Achieves ~5-meter resolution globally
CPR Decoding Process:
- Receive Even frame β extract CPR latitude/longitude
- Receive Odd frame β extract CPR latitude/longitude
- Apply CPR NL (Number of Longitude zones) calculation
- Resolve global position using both frames
- Validate result (reject if aircraft jumped unrealistically)
Velocity messages provide:
- Subtype 1-2: Ground speed (East-West and North-South components)
- Subtype 3-4: Airspeed (heading and true airspeed)
- Vertical rate: Encoded in 64 ft/min increments, range Β±32,576 ft/min
- GNSS altitude difference: Difference between barometric and GNSS altitude
- Frequency: 1090 MHz (Mode-S)
- Modulation: Pulse Position Modulation (PPM)
- Power: ~51 dBm (125 watts) peak from commercial aircraft
- Range: Line-of-sight β typically 150-250 nautical miles depending on altitude
- Update rate:
- Position: Every 0.5 seconds (airborne)
- Velocity: Every 0.5 seconds
- Identification: Every 5 seconds
The RTL-SDR dongle is a low-cost SDR receiver originally designed for DVB-T TV tuners:
- Tuning range: 24 MHz β 1766 MHz (covers 1090 MHz perfectly)
- Sample rate: Up to 2.56 MS/s (sufficient for 1 MHz ADS-B bandwidth)
- Chipset: RTL2832U demodulator + R820T/R820T2 tuner
- Interface: USB 2.0
- Cost: $20-$40 USD
Decoding Process:
- Tune to 1090 MHz
- Capture IQ samples at 2 MS/s
- Demodulate PPM signal β extract bits
- Validate CRC checksum
- Parse message fields based on DF and TC
- Decode position (CPR), velocity, or identification
The application implements a complete ADS-B decoder pipeline:
Demodulation:
- Converts raw IQ samples from RTL-SDR to magnitude
- Detects Mode-S preamble pattern using peak detection
- Decodes Manchester-encoded bits (Pulse Position Modulation)
- Validates CRC-24 checksum
Message Parsing:
- Identifies Downlink Format (DF 17/18 for ADS-B, DF 5/21 for squawk)
- Extracts ICAO 24-bit address (unique aircraft ID)
- Decodes Type Code to determine message category
- Parses specific fields based on TC
Supported Message Types:
- TC 1-4: Callsign extraction (8-character alphanumeric)
- TC 9-18, 20-22: Airborne position with CPR decoding
- TC 19: Velocity (speed, heading, vertical rate)
- DF 5, 21: Squawk code (4-digit octal)
The table view updates in real-time and displays:
- ICAO: 24-bit address in hexadecimal (unique identifier)
- Callsign: Flight number or aircraft registration
- Altitude: Barometric altitude in feet
- Position: Decimal degrees latitude/longitude
- Speed: Ground speed in knots
- Heading: True heading in degrees (0-359Β°)
- V/R: Vertical rate (ft/min) β positive for climb, negative for descent
- Squawk: 4-digit transponder code
- Messages: Total message count received from this aircraft
- Last Seen: Local time of most recent message
Table Features:
- Click any row to view detailed information
- Alternating row colors for readability
- Automatic sorting by ICAO address
- Selection synchronizes with map markers
OpenStreetMap Integration:
- Live updating aircraft positions
- Pan and zoom controls
- Tile caching for performance
Aircraft Markers:
- White triangle icons representing aircraft
- Icons rotate to match actual heading (updated every 5Β°)
- Label shows callsign or ICAO
Flight Path Trails:
- Cyan polyline shows recent flight path
- Approximately 3 minutes of history (60 position updates)
- Trail fades as aircraft moves
Hover Tooltips:
- Move mouse over any marker to see:
- Callsign and aircraft type
- Altitude, speed, heading
- Operator and registration
- Route (origin β destination)
- Squawk code
Click Interaction:
- Click any map marker to select that aircraft
- Selection synchronized with table and detail panel
When an aircraft is selected (via table or map), the detail panel shows:
Static Information:
- Registration: Tail number (e.g., N12345, G-ABCD)
- Type: Aircraft model (e.g., Boeing 737-800, Airbus A320-214)
- Manufacturer: Boeing, Airbus, Bombardier, etc.
- Operator: Airline or owner
- Route: Departure β Arrival (e.g., KJFK β EGLL)
Dynamic Information:
- Real-time position, speed, altitude
- Current squawk code
- Message statistics
Aircraft Photo:
- High-resolution image fetched from planespotters.net
- Automatically matched by ICAO address or registration
- Cached for performance
- Fallback to placeholder if unavailable
Background Thread Architecture:
- Non-blocking API calls
- Queue-based processing
- One enrichment per aircraft
hexdb.io API:
- Free, no authentication required
- Returns: registration, type, manufacturer, operator, route
- Endpoint:
https://hexdb.io/api/v1/aircraft/<ICAO>
planespotters.net Photo API:
- Free, no authentication required
- Searches by ICAO or registration
- Returns highest-rated photos
- Thumbnail and full-size image URLs
Caching Strategy:
- Enrichment data cached per ICAO
- Photos cached as PhotoImage objects
- Prevents redundant API calls
Real-time log panel displays:
- Application start/stop events
- SDR initialization status
- Aircraft detection messages
- Enrichment API responses
- Selected aircraft state changes
- Error messages and warnings
Log Format:
[HH:MM:SS] Message text
Start Button (βΆ):
- Initializes RTL-SDR device
- Starts sample acquisition thread
- Begins decoding loop
- Updates UI at 1 Hz
Stop Button (βΉ):
- Stops sample acquisition
- Halts decoder thread
- Preserves aircraft data (not cleared)
- Closes RTL-SDR device
Clear Button (π):
- Removes all aircraft from table
- Clears map markers and trails
- Resets decoder state
- Preserves log history
If no RTL-SDR hardware is detected, the application automatically enters demo mode:
Features:
- Simulates 5 aircraft with realistic flight patterns
- Randomly generated positions within viewing area
- Simulated movement (speed, heading changes)
- Fake callsigns and ICAO addresses
- Useful for testing UI and understanding functionality
- No hardware required
Detection:
- Attempts to initialize RTL-SDR on startup
- Falls back gracefully if
RtlSdr()raises exception - Logs "No RTL-SDR detected β demo mode" message
- Height is key: Rooftop or high window placement dramatically improves range
- Line of sight: Aircraft must be above the radio horizon (β1.23 Γ βaltitude)
- Dedicated ADS-B antenna: 1090 MHz quarter-wave (6.9 cm) or commercial ADS-B antenna recommended
- Avoid obstructions: Metal, brick, and electronic devices reduce signal
- Gain setting: 49.6 dB is optimal for most RTL-SDR units (set in code)
- Filter interference: Use ADS-B bandpass filter to reduce out-of-band noise
- Powered USB hub: RTL-SDR can draw significant current; use powered hub if unstable
- Cooling: SDR dongles heat up during extended use; ensure ventilation
- Urban area, window-mounted antenna: 50-100 nautical miles
- Rooftop, dedicated antenna: 150-250+ nautical miles
- High altitude aircraft: Detectable at 250+ nm
- Low-flying aircraft: Limited to 20-50 nm depending on terrain
- Active aircraft: 10-50 messages per second
- Nearby aircraft: 50-200 messages per second
- Distant aircraft: 1-10 messages per second
- High message counts indicate strong signal and proximity
- Rate limits: Both hexdb.io and planespotters.net are free but rate-limited
- Cache hit: Enrichment data persists for session β restarting app clears cache
- No API key: No registration required
Windows:
- Verify WinUSB driver installed via Zadig
- Check Device Manager β Universal Serial Bus devices β Should see RTL-SDR
- Try different USB port (preferably USB 2.0, not 3.0)
- Ensure DLL files are present and PATH is set
Linux:
- Run
rtl_test -tto verify device detection - Check
lsusboutput for0bda:2838(Realtek RTL2838) - Verify udev rules:
ls -l /dev/bus/usb/...should show mode 0666 - Confirm blacklist:
lsmod | grep dvbshould return nothing
macOS:
- Run
rtl_test -tin terminal - Check USB system report: Apple menu β About This Mac β System Report β USB
- Reinstall librtlsdr:
brew reinstall rtl-sdr libusb
- Check antenna connection: Ensure SMA connector is tight
- Antenna placement: Move to window or outdoors
- Verify local traffic: Use online tracker (e.g., FlightRadar24) to confirm aircraft overhead
- Increase gain: Edit
GAIN = 49.6in code (try 40-50 range) - Check frequency: Aircraft use 1090 MHz (not 978 MHz UAT)
- Reduce sample rate: Lower
SAMPLES_PER_POLL(currently 256 * 1024) - Close other applications: Decoding is CPU-intensive
- Disable photo loading: Comment out photo enrichment calls
- Update NumPy:
pip install --upgrade numpy
ModuleNotFoundError: No module named 'rtlsdr'
Solution:
pip install pyrtlsdr==0.2.91ImportError: DLL load failed: The specified module could not be found.
Solution (Windows):
- Download
librtlsdr.dll,libusb-1.0.dll,libwinpthread-1.dll - Place in script directory or add to PATH
- Internet connection: OpenStreetMap requires active connection
- Firewall: Ensure Python allowed through firewall
- Reinstall tkintermapview:
pip install --upgrade tkintermapview
Edit constants at top of script:
ADSB_FREQ = 1_090_000_000 # Frequency (Hz)
SAMPLE_RATE = 2_000_000 # Sample rate (Hz)
GAIN = 49.6 # Gain (dB) β 0 to 49.6
SAMPLES_PER_POLL = 256 * 1024 # Buffer size# In App.__init__(), modify initial map position:
self.map_widget.set_position(45.50, -73.57) # Latitude, Longitude
self.map_widget.set_zoom(10) # Zoom level (1-19)# In App._update_markers():
trail = self._ac_trails.setdefault(icao, deque(maxlen=60))
# Change maxlen to adjust trail length (60 = ~3 min at 0.5s updates)pyrtlsdr==0.2.91β RTL-SDR interfacenumpyβ Signal processing
tkintermapviewβ Interactive mappillowβ Aircraft photo display
tkinterβ GUI framework (included with Python)threading,queueβ Concurrencyurllibβ HTTP requestsjsonβ API response parsing
- Main Thread: Tkinter GUI event loop
- SDR Thread: Continuous sample acquisition from RTL-SDR
- Enrichment Thread: Background API calls (non-blocking)
RTL-SDR Hardware
β
IQ Samples (USB)
β
Demodulation (magnitude, preamble detection)
β
Bit Extraction (PPM decoding)
β
CRC Validation
β
Message Parsing (DF, TC, ICAO, payload)
β
CPR Position Decoding
β
Aircraft Database Update
β
GUI Update (table, map, detail panel)
β
Enrichment Queue (background)
β
hexdb.io API β planespotters.net API
β
Aircraft Metadata & Photo Update
This project is provided as-is for educational and hobbyist purposes. ADS-B reception is legal in most jurisdictions, but verify local regulations. Do not use decoded ADS-B data for commercial air traffic control or safety-critical applications.
External APIs:
- hexdb.io β Aircraft database
- planespotters.net β Aircraft photos
- OpenStreetMap β Map tiles
Libraries:
- pyrtlsdr β Python wrapper for librtlsdr
- NumPy β Numerical computing
- tkintermapview β Tkinter map widget
- Pillow β Image processing
Hardware:
- RTL-SDR developers and community
- ADS-B on Wikipedia
- Mode S on Wikipedia
- ICAO Annex 10 β Official ADS-B specification
- The 1090 Megahertz Riddle (Online Book) β Comprehensive ADS-B decoding guide
- RTL-SDR Blog β SDR tutorials and news
- dump1090 Project β Popular ADS-B decoder
This is an educational project. Feel free to modify, extend, and experiment with the code. Suggestions for improvements:
- Add MLAT (multilateration) support
- Implement Mode-S Comm-B interrogation
- Database logging (SQLite, CSV export)
- Web-based dashboard
- Aircraft statistics and heatmaps
- Integration with virtual radar software
Happy tracking!
