Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ launch.json
# Assitnow token and files for test script
tokens.yaml
*.ubx
/testing/
/.idea/

# Local development files
.semgrepignore
Expand Down
82 changes: 82 additions & 0 deletions dev/adsb/adsb_uart_sender.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import json
import time
import argparse
import serial
from pymavlink.dialects.v20 import common as mavlink2

def load_aircraft(json_file):
with open(json_file, "r") as f:
return json.load(f)

def create_mavlink(serial_port):
mav = mavlink2.MAVLink(serial_port)
mav.srcSystem = 1
mav.srcComponent = mavlink2.MAV_COMP_ID_ADSB
return mav

def send_heartbeat(mav):
mav.heartbeat_send(
mavlink2.MAV_TYPE_ADSB,
mavlink2.MAV_AUTOPILOT_INVALID,
0,
0,
0
)

def send_adsb(mav, aircraft):
for ac in aircraft:
icao = int(ac["icao_address"])
lat = int(ac["lat"] * 1e7)
lon = int(ac["lon"] * 1e7)
alt_mm = int(ac["altitude"] * 1000)
heading_cdeg = int(ac["heading"] * 100)
hor_vel_cms = int(ac["hor_velocity"] * 100)
ver_vel_cms = int(ac["ver_velocity"] * 100)
callsign = ac["callsign"].encode("ascii").ljust(9, b'\x00')

Comment thread
error414 marked this conversation as resolved.
msg = mavlink2.MAVLink_adsb_vehicle_message(
ICAO_address=icao,
lat=lat,
lon=lon,
altitude_type=0,
altitude=alt_mm,
heading=heading_cdeg,
hor_velocity=hor_vel_cms,
ver_velocity=ver_vel_cms,
callsign=callsign,
emitter_type=0,
tslc=1,
flags=3,
squawk=0
)

mav.send(msg)

def main():
parser = argparse.ArgumentParser()
parser.add_argument("com_port")
parser.add_argument("json_file")
parser.add_argument("--baud", default=115200, type=int)
parser.add_argument("--rate", default=1.0, type=float)
args = parser.parse_args()

ser = serial.Serial(args.com_port, args.baud)
mav = create_mavlink(ser)

aircraft = load_aircraft(args.json_file)

period = 1.0 / args.rate
last_hb = 0
Comment thread
error414 marked this conversation as resolved.

while True:
now = time.time()

if now - last_hb >= 1.0:
send_heartbeat(mav)
last_hb = now

send_adsb(mav, aircraft)
time.sleep(period)

if __name__ == "__main__":
main()
52 changes: 52 additions & 0 deletions dev/adsb/aircraft.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
[
{
"icao_address": 1002,
"lat": 49.2341564,
"lon": 16.5505527,
"altitude": 300,
"heading": 275,
"hor_velocity": 30,
"ver_velocity": 0,
"callsign": "V550"
},
{
"icao_address": 1001,
"lat": 49.2344299,
"lon": 16.5610206,
"altitude": 300,
"heading": 237,
"hor_velocity": 30,
"ver_velocity": 0,
"callsign": "V250"
},
{
"icao_address": 1003,
"lat": 49.2422463,
"lon": 16.5645653,
"altitude": 300,
"heading": 29,
"hor_velocity": 30,
"ver_velocity": 0,
"callsign": "V1100"
},
{
"icao_address": 1004,
"lat": 49.2377083,
"lon": 16.5520834,
"altitude": 300,
"heading": 110,
"hor_velocity": 30,
"ver_velocity": 0,
"callsign": "V650X3"
},
{
"icao_address": 1005,
"lat": 49.2388158,
"lon": 16.5730266,
"altitude": 300,
"heading": 261,
"hor_velocity": 30,
"ver_velocity": 0,
"callsign": "V1250X4"
}
]
87 changes: 87 additions & 0 deletions dev/adsb/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# ADSB Vehicle MAVLink Simulator

A Python tool for simulating ADS-B aircraft traffic over a serial connection using the MAVLink protocol. Useful for testing ADS-B receivers, ground station software, or flight controller integrations without real aircraft.

---

## Requirements
```bash
pip install pymavlink pyserial
```

---

## Usage
```bash
python adsb_uart_sender.py <com_port> <json_file> [--baud BAUD] [--rate RATE]
```
Comment thread
error414 marked this conversation as resolved.

### Arguments

| Argument | Required | Default | Description |
|---|---|---|---|
| `com_port` | ✅ | — | Serial port (e.g. `COM3`, `/dev/ttyUSB0`) |
| `json_file` | ✅ | — | Path to JSON file with aircraft definitions |
| `--baud` | ❌ | `115200` | Serial baud rate |
| `--rate` | ❌ | `1.0` | Update rate in Hz |

### Examples
```bash
# Windows
python adsb_uart_sender.py COM3 aircraft.json

# Linux
python adsb_uart_sender.py /dev/ttyUSB0 aircraft.json --baud 57600 --rate 2.0
```

---

## Aircraft JSON Format

Each aircraft is defined as an object in a JSON array:
```json
[
{
"icao_address": 1001,
"lat": 49.2344299,
"lon": 16.5610206,
"altitude": 300,
"heading": 237,
"hor_velocity": 30,
"ver_velocity": 0,
"callsign": "V250"
}
]
```

| Field | Type | Unit | Description |
|---|---|---|---|
| `icao_address` | int | — | Unique ICAO identifier |
| `lat` | float | degrees | Latitude |
| `lon` | float | degrees | Longitude |
| `altitude` | float | meters ASL | Altitude above sea level |
| `heading` | float | degrees (0–360) | Track heading |
| `hor_velocity` | float | m/s | Horizontal speed |
| `ver_velocity` | float | m/s | Vertical speed (positive = climb) |
| `callsign` | string | — | Aircraft callsign (max 8 chars) |

---

## How It Works

The simulator connects to a serial port and continuously transmits two MAVLink message types:

- **HEARTBEAT** — sent once per second to identify the component as an ADS-B device
- **ADSB_VEHICLE** — sent for each aircraft at the configured rate, containing position, velocity, heading and identification data

All aircraft from the JSON file are broadcast in every update cycle. The positions are static — aircraft do not move between updates.

---

## Notes

- Altitude is transmitted in millimeters internally (`altitude * 1000`) as required by the MAVLink `ADSB_VEHICLE` message spec
- Heading is transmitted in centidegrees (`heading * 100`)
- Callsigns are ASCII-encoded and null-padded to 9 bytes
- `flags` is set to `3` (lat/lon and altitude valid)
- `tslc` (time since last communication) is hardcoded to `1` second
38 changes: 38 additions & 0 deletions docs/ADSB.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,41 @@ AT+SETTINGS=SAVE
* in INAV configurator ports TAB set telemetry MAVLINK, and baudrate 115200
* https://pantsforbirds.com/adsbee-1090/quick-start/

---

---

## Alert and Warning
The ADS-B warning/alert system supports two operating modes, controlled by the parameter osd_adsb_calculation_use_cpa (ON or OFF).

---

### ADS-B Warning and Alert Messages (CPA Mode OFF)
The ADS-B warning/alert system supports two operating modes, controlled by the parameter **osd_adsb_calculation_use_cpa** (ON or OFF).

When **osd_adsb_calculation_use_cpa = OFF**, the system evaluates only the **current distance between the aircraft and the UAV**. The aircraft with the **shortest distance** is always selected for monitoring.

- If the aircraft enters the **warning zone** (`adsb_distance_warning`), the corresponding **OSD element is displayed**.
- If the aircraft enters the **alert zone** (`adsb_distance_alert`), the **OSD element starts blinking**, indicating a higher-priority alert.

This mode therefore provides a simple proximity-based warning determined purely by real-time distance.

---

### ADS-B Warning and Alert Messages (CPA Mode ON)

When **osd_adsb_calculation_use_cpa = ON**, the system evaluates aircraft using the **Closest Point of Approach (CPA)** and predicted trajectories, not only the current distance.

1. **Aircraft already inside the alert zone**
If one or more aircraft are currently inside the **alert zone** (`adsb_distance_alert`), the **closest aircraft** to the UAV is selected and the **OSD element blinks**.

2. **Aircraft in the warning zone, none predicted to enter the alert zone**
If aircraft are present in the **warning zone** (`adsb_distance_warning`), but none of them are predicted to enter the **alert zone** (their CPA distance is greater than `adsb_distance_alert`), the **closest aircraft to the UAV** is selected and the **OSD element remains steady** (no blinking).

3. **Aircraft in the warning zone, one predicted to enter the alert zone**
If at least one aircraft in the **warning zone** is predicted to enter the **alert zone**, that aircraft is selected and the **OSD element blinks**.

4. **Aircraft in the warning zone, multiple predicted to enter the alert zone**
If multiple aircraft are predicted to enter the **alert zone**, the system selects the aircraft that will **reach the alert zone first**, and the **OSD element blinks**.

![ADSB CPA_ON](assets/images/adsb-CPA-on.png)
23 changes: 20 additions & 3 deletions docs/Settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,7 @@ ADC, VIRTUAL, FAKE, ESC, SMARTPORT, CAN, NONE. The virtual current sensor, once
| FAKE | |
| ESC | |
| SMARTPORT | |
| CAN | |

---

Expand Down Expand Up @@ -780,6 +781,7 @@ Defines debug values exposed in debug variables (developer / debugging setting)
| GPS | |
| LULU | |
| SBUS2 | |
| OSD_REFRESH | |

---

Expand Down Expand Up @@ -872,9 +874,12 @@ Re-purpose the craft name field for messages.

The speed of the CANbus network in kbps. Set all devices to the same speed.

| Default | Min | Max |
| --- | --- | --- |
| 1000 | | |
| Allowed Values | |
| --- | --- |
| 125 | |
| 250 | |
| 500 | |
| 1000 | Default |

---

Expand Down Expand Up @@ -1859,6 +1864,7 @@ Which GPS protocol to be used.
| UBLOX | Default |
| MSP | |
| FAKE | |
| DRONECAN | |

---

Expand Down Expand Up @@ -4705,6 +4711,16 @@ Optical flow module scale factor

---

### osd_adsb_calculation_use_cpa

Use CPA (Closest Point of Approach) method for ADS-B traffic distance and collision risk calculation instead of instantaneous distance.

| Default | Min | Max |
| --- | --- | --- |
| OFF | OFF | ON |

---

### osd_adsb_distance_alert

Distance inside which ADSB data flashes for proximity warning
Expand Down Expand Up @@ -6934,6 +6950,7 @@ Vbat voltage source. Possible values: `NONE`, `ADC`, `SMARTPORT`, `ESC`, 'CAN'.
| ESC | |
| FAKE | |
| SMARTPORT | |
| CAN | |

---

Expand Down
Binary file added docs/assets/images/adsb-CPA-on.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/main/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ main_sources(COMMON_SRC
flight/adaptive_filter.h

io/adsb.c
io/adsb.h
io/beeper.c
io/beeper.h
io/servo_sbus.c
Expand Down
43 changes: 43 additions & 0 deletions src/main/fc/fc_msp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1042,6 +1042,49 @@ static bool mspFcProcessOutCommand(uint16_t cmdMSP, sbuf_t *dst, mspPostProcessF
sbufWriteU8(dst, 0);
sbufWriteU32(dst, 0);
sbufWriteU32(dst, 0);
#endif
break;
case MSP2_ADSB_LIMITS:
#ifdef USE_ADSB
sbufWriteU16(dst, osdConfig()->adsb_distance_warning);
sbufWriteU16(dst, osdConfig()->adsb_distance_alert);
sbufWriteU16(dst, osdConfig()->adsb_ignore_plane_above_me_limit);
#else
sbufWriteU16(dst, 0);
sbufWriteU16(dst, 0);
sbufWriteU16(dst, 0);
#endif
break;
case MSP2_ADSB_WARNING_VEHICLE_ICAO:
#ifdef USE_ADSB
if(isEnvironmentOkForCalculatingADSBDistanceBearing()) {
adsbVehicle_t *vehicle = NULL;
bool isAlert = true;
vehicle = findVehicleForAlert(
METERS_TO_CENTIMETERS(osdConfig()->adsb_distance_alert),
METERS_TO_CENTIMETERS(osdConfig()->adsb_distance_warning),
METERS_TO_CENTIMETERS(osdConfig()->adsb_ignore_plane_above_me_limit)
);

if(vehicle == NULL) {
vehicle = findVehicleForWarning(METERS_TO_CENTIMETERS(osdConfig()->adsb_distance_warning), METERS_TO_CENTIMETERS(osdConfig()->adsb_ignore_plane_above_me_limit));
isAlert = false;
}

if(vehicle != NULL) {
sbufWriteU32(dst, vehicle->vehicleValues.icao);
sbufWriteU8(dst, isAlert ? 1 : 0);;
} else {
sbufWriteU32(dst, 0);
sbufWriteU8(dst, 0);;
}
} else {
sbufWriteU32(dst, 0);
sbufWriteU8(dst, 0);
}
#else
sbufWriteU32(dst, 0);
sbufWriteU8(dst, 0);
#endif
break;
case MSP_DEBUG:
Expand Down
Loading
Loading