Detect and Avoid
Detect and Avoid (DAA) runs in the navigator module. Its DetectAndAvoid component uses the adsb library for conflict evaluation, traffic identification, conflict tracking, and action policy (see Implementation Structure). It evaluates cooperative ("transponder-equipped") traffic, such as that from ADS-B, FLARM, or UTM integrations, that is reported through the transponder_report topic. DAA can warn the operator, request navigator actions, or block arming when a conflict requires an automatic response.
TIP
This page is the detailed technical reference for PX4 developers and advanced integrators looking to maintain and extend the DAA implementation.
For basic setup and configuration of an avoidance system, see ADS-B/FLARM/UTM Receivers: Air Traffic Avoidance.
Scope and Context
DAA is most relevant for operations in shared airspace, especially beyond visual line of sight (BVLOS), where an unmanned aircraft must help maintain safe separation from manned aviation without an onboard pilot performing see-and-avoid.
PX4 currently handles only cooperative traffic: aircraft that broadcast position and related state through ADS-B, FLARM, UTM, or another compatible integration. If you are not using one of those traffic sources, this page is mainly relevant only if you are developing or integrating DAA itself.
This page uses encounter for a received cooperative-traffic report and conflict when that traffic breaches a configured alert test.
Use this page for understanding:
- The detailed behavior of Conflict Standards
- Action selection and preflight behavior in Automated Actions and Arming, Preflight, and Ground Behavior
- Message, logging, and test details in Operator Messages, Analysing a Conflict Using the Logs, and Testing and Simulation
- Extension guidance in Adding a New Standard
Overview
DAA supports two conflict models:
Crosstrackmode raises one conflict level when ownship (the current vehicle) is close to the traffic's predicted track, vertically close, and within a configured collision-time threshold. Use it when you want one threshold driven byNAV_TRAFF_*.F3442mode evaluates four alert tests derived from concepts in ASTM F3442/F3442M-23. Use it when you want staged alerting and per-level actions.
CONFIG_NAVIGATOR_ADSB includes DAA in the firmware. When it is enabled, CONFIG_NAVIGATOR_ADSB_F3442 selects F3442 mode; otherwise Crosstrack mode is built.
WARNING
F3442 mode handles cooperative traffic only and implements selected alert concepts and thresholds. It does not by itself establish compliance with ASTM F3442/F3442M-23, which applies to a complete DAA system and its compliance evidence. The implementation references the 2023 edition and has not been evaluated against the later ASTM F3442-25 edition.
At runtime DAA can:
- Process queued traffic reports from
transponder_report. - Keep the most important active conflicts in a fixed-size buffer.
- Publish both per-traffic and most-urgent DAA status topics.
- Trigger configured navigator actions when a conflict requires more than a warning.
- Prevent arming if DAA is enabled and the current most urgent conflict requires an automatic action.
How It Works
Each navigator cycle, DAA:
- Reads all queued
transponder_reportmessages for that cycle.- Rejects invalid or stale traffic reports.
- Filters self-detections using ownship ICAO, ADS-B callsign, and UAS ID.
- Evaluates the conflict with the built DAA model.
- Publishes
detect_and_avoidfor reports that create or update a tracked conflict, including the sample that clears one. First-seen traffic evaluated at conflict levelNONEis not published.
- Publishes
- Applies the result to the active-conflict buffer (
ConflictTracker) and selects the most urgent conflict.- The tracker reports buffer changes (new, level changed, removed, ignored).
- Publishes the most urgent conflict summary on
detect_and_avoid_most_urgent.
- Hands the cycle's change records to the notifier (
ConflictNotifier), which decides all operator warnings for the cycle in one place, and, if configured, requests a navigator action.
Conflict priority is determined by:
- Higher conflict level first.
- Shorter aircraft distance when conflict levels are equal.
Conflict Standards
Crosstrack Mode
This mode is used by firmware built without CONFIG_NAVIGATOR_ADSB_F3442.
This mode provides a single actionable threshold for track-crossing traffic. It evaluates the traffic geometry using three gates. If all three conditions are met, DAA publishes a single conflict level: HIGH.
- The ownship must lie within
NAV_TRAFF_A_HORof the traffic's projected ground track. - Vertical separation must be below
NAV_TRAFF_A_VER. - Estimated time to collision must be below
NAV_TRAFF_COLL_T.
Metrics and Conflict Test
The crosstrack implementation publishes these geometry outputs in detect_and_avoid:
aircraft_dist: the current point-to-point 3D range.aircraft_dist_hor: the signed crosstrack distance to the projected traffic line when that line can be constructed.aircraft_dist_vert: the absolute vertical separation.expected_min_dist_time: a conservative collision-time estimate.
Click here to view how the crosstrack metrics and gates are computed
The crosstrack implementation computes them as follows:
It first computes the current point-to-point separations between the ownship and the traffic:
, . It projects a traffic ground-track line starting at the reported traffic position and extending in the reported traffic heading direction. Let
denote the fixed path-extension constant kTrafficToUavDistanceExtension. Heading is required for this step. The line length is:It then computes the signed crosstrack error
from ownship to that projected line. The horizontal gate is: The projected-line gate is only valid when the line solver succeeds and the ownship has not already passed the end of the projected segment.
Vertical separation is checked directly:
The time metric uses the current 3D separation and a conservative relative-speed assumption. This time calculation intentionally does not use heading to derive closure rate. It uses a worst-case head-on assumption and sums the ownship and traffic speed magnitudes:
The time gate is only valid when the summed speed is greater than zero:
A crosstrack conflict is raised only when all three gates are true. If the line projection is valid, aircraft_dist_hor publishes
Data Requirements
- Valid ownship and traffic coordinates, altitude, and velocity, plus a finite traffic heading.
Parameters
- NAV_TRAFF_AVOID: action requested when Crosstrack raises its single
HIGHconflict. - NAV_TRAFF_A_HOR: maximum absolute crosstrack distance from the projected traffic track for the horizontal gate.
- NAV_TRAFF_A_VER: maximum absolute vertical separation for the vertical gate.
- NAV_TRAFF_COLL_T: maximum conservative time-to-collision estimate for the time gate.
Actions
Action mapping is defined by NAV_TRAFF_AVOID:
0: Disabled,1: Warn only,2: Return,3: Land,4: Hold,5: Terminate
F3442 Mode
This mode is used by firmware built with CONFIG_NAVIGATOR_ADSB_F3442.
This mode uses selected alert concepts and default separation values associated with ASTM F3442/F3442M-23.
- NMAC is defined as coming within 100 ft (30 m) vertically and 500 ft (153 m) horizontally from other aircraft.
- Loss of Well Clear (LoWC) is defined more conservatively at 250 ft (76 m) vertically and 2000 ft (610 m) horizontally from other aircraft.
PX4 places one protective zone around the ownship and an identical zone around each detected aircraft, so the radius and height parameters below are defined per aircraft. A conflict is raised when the two zones touch, which means the separation that triggers it is the sum of both zones. For two identical aircraft that is simply twice the configured value, which is why the critical radius defaults to roughly half of the NMAC horizontal distance (DAA_LVL_CRIT_RAD = 77 m, giving 2 × 77 m ≈ 153 m).
Conflict Levels
F3442 is evaluated in four severity levels and returns the first breached level in this order: CRITICAL, HIGH, MEDIUM, LOW.
| Conflict level | Meaning in DAA | Zone | Action |
|---|---|---|---|
CRITICAL | Near Mid-Air Collision (NMAC) | DAA_LVL_CRIT_RAD, DAA_LVL_CRIT_HGT | DAA_LVL_CRIT_ACT |
HIGH | Loss of Well Clear (LoWC) | DAA_LVL_HIGH_RAD, DAA_LVL_HIGH_HGT | DAA_LVL_HIGH_ACT |
MEDIUM | Augmented NMAC | NMAC bounds expanded using DAA_LVL_MED_TIME | DAA_LVL_MED_ACT |
LOW | Augmented WC | WC bounds expanded using DAA_LVL_LOW_TIME | DAA_LVL_LOW_ACT |
The augmented MEDIUM and LOW tests enlarge each aircraft's bounds in proportion to its horizontal and vertical speed (scaled by DAA_LVL_MED_TIME and DAA_LVL_LOW_TIME). The four tests are evaluated in the priority order shown above. Validated parameter ordering guarantees that CRITICAL also breaches HIGH, MEDIUM, and LOW; HIGH also breaches LOW; and MEDIUM also breaches LOW. HIGH and MEDIUM are not ordered relative to each other.
Click here to view the F3442 zone computations
PX4 models F3442 using cylindrical horizontal and vertical bounds. A level is breached only when both the horizontal and vertical inequalities for that level are satisfied.
Use the following notation:
, : absolute horizontal and vertical separation between the aircraft. , : per-aircraft NMAC radius and height. , : per-aircraft WC radius and height. , : augmentation times for the MEDIUMandLOWlevels., : ownship absolute horizontal and vertical speed magnitudes. , : traffic absolute horizontal and vertical speed magnitudes.
Parameter mapping:
- DAA_LVL_CRIT_RAD =
- DAA_LVL_CRIT_HGT =
- DAA_LVL_HIGH_RAD =
- DAA_LVL_HIGH_HGT =
- DAA_LVL_MED_TIME =
- DAA_LVL_LOW_TIME =
CRITICAL: NMAC zone
Per-aircraft volume:
Combined breach condition:
HIGH: Loss of Well Clear (LoWC) zone
Per-aircraft volume:
Combined breach condition:
MEDIUM: Augmented NMAC
Each aircraft starts with the NMAC cylinder and expands it using
Combined breach condition:
LOW: Augmented WC
Each aircraft starts with the WC cylinder and expands it using
Combined breach condition:
PX4 validates that WC base bounds are not smaller than NMAC base bounds, both augmentation times are non-negative, and the LOW augmentation time is not shorter than the MEDIUM time. The conflict evaluation order remains CRITICAL, HIGH, MEDIUM, then LOW.
Data Requirements
- Mandatory: Valid coordinates and altitude.
- Optional: Traffic velocity.
- If missing, F3442 is evaluated assuming zero traffic horizontal/vertical speed.
- If DAA_EN_DFLT_VEL is enabled, the traffic vertical speed is replaced by DAA_DFLT_VEL (preserving the reported sign if known, otherwise assuming positive climb).
- Not required: Heading is not used. Each aircraft is wrapped in a symmetric zone, which is conservative and covers unexpected course changes.
Actions
Each level uses the action parameter listed in the table above. If that action is Disabled, the policy checks only levels whose bounds are guaranteed to have been breached:
CRITICAL:CRITICAL -> HIGH -> MEDIUM -> LOWHIGH:HIGH -> LOWMEDIUM:MEDIUM -> LOWLOW:LOW
The first action that is not Disabled is used.
Automated Actions
The action parameter depends on the DAA model selected at build time: NAV_TRAFF_AVOID for Crosstrack builds and DAA_LVL_*_ACT for F3442 builds.
The DAA action parameters use these values:
0: Disabled,1: Warn only,2: Return,3: Land,4: Hold,5: Terminate
WARNING
The parameter values are not in severity order. Internally, automatic-action severity is strictly ordered as:
INFO
Changing an action parameter does not immediately re-evaluate buffered conflicts. The updated setting is considered on a later change of the overall most-urgent conflict level, and automatic mode changes are only requested when that level increases.
Conflict-to-Action Mapping
Crosstrackonly publishesHIGHconflicts, so its requested action comes directly from NAV_TRAFF_AVOID.F3442maps each conflict level through its correspondingDAA_LVL_*_ACTparameter.- In
F3442, a disabled action falls back only to levels guaranteed to have been breached:CRITICAL -> HIGH -> MEDIUM -> LOW,HIGH -> LOW, orMEDIUM -> LOW.
Navigator-State Equivalence
Before sending a vehicle command, PX4 maps the current navigator state into the DAA_ACTION severity ladder and only triggers an automatic action when the requested action is to change to "a more severe mode" than the current navigator state:
Click here to view the full navigator-state to DAA-action mapping
| Current navigator state | Equivalent DAA action | Practical effect |
|---|---|---|
AUTO_MISSION, AUTO_TAKEOFF, AUTO_FOLLOW_TARGET, AUTO_VTOL_TAKEOFF, GUIDED_COURSE | DISABLED | Any automatic DAA action may still escalate |
ORBIT, AUTO_LOITER | POSITION_HOLD_MODE | Only Return, Land, or Terminate can escalate |
AUTO_RTL | RETURN_MODE | Only Land or Terminate can escalate |
AUTO_LAND, DESCEND, AUTO_PRECLAND, MANUAL, ALTCTL, ALTITUDE_CRUISE, POSCTL, POSITION_SLOW, ACRO, STAB | LAND_MODE | Only Terminate can escalate |
TERMINATION | TERMINATE | No stronger DAA action exists |
OFFBOARD, EXTERNAL1 through EXTERNAL8, and unknown states | MAX_ACTION_VALUE | PX4 will not inject an automatic DAA mode change |
Manual modes are intentionally treated as LAND_MODE. That means DAA will not automatically switch a manually flown vehicle into Hold, Return, or Land; only Terminate is considered a stronger action than those modes.
Action behavior:
- DAA only triggers an automatic action when the requested action is to change to "a more severe mode" than the current navigator state.
- Warnings are evaluated separately from automatic mode changes. A conflict configured as
Warn onlyor stronger can still emit operator warnings and status messages even when DAA does not request a mode change because the current navigator state is already equivalent or more severe. - DAA continues to publish status updates even when no automatic action is sent.
- Automatic actions are evaluated from changes in the overall most-urgent conflict level. DAA does not retry a command while that level remains unchanged, including when a different aircraft becomes most urgent at the same level.
- Conflict de-escalation is conservative. For example, DAA does not automatically resume the mission after a hold conflict is cleared.
OFFBOARDis handled conservatively: DAA does not inject an automatic mode change there, so arming and operating procedures need to account for that.- If the vehicle is landed, DAA warns instead of changing mode.
Arming, Preflight, and Ground Behavior
The commander health check reads detect_and_avoid_most_urgent and applies the result only while the vehicle is disarmed.
This section covers conflict-based DAA behavior when traffic is already present. The separate traffic-system-presence arming check is configured by COM_ARM_TRAFF and described in ADS-B/FLARM/UTM Receivers > Arming Check.
Preflight behavior:
- If DAA is enabled and the most urgent conflict requires an automatic action, arming is rejected until the conflict clears.
- If the most urgent conflict is configured as
Warn only, arming is not blocked. - Once the vehicle is armed, commander stops emitting the prearm DAA conflict warning. In-flight conflict handling continues through the navigator action logic and DAA status messages.
Ground behavior:
- If the vehicle is landed and a conflict requires an action, DAA reports a ground warning instead of changing flight mode.
- If the vehicle is disarmed, the operator is warned not to arm.
- If the vehicle is already armed on the ground, the operator is warned not to take off until the conflict is resolved.
This is especially important for:
- Ground operations with nearby traffic already inside an action-triggering volume.
OFFBOARDuse cases where arming protection may be the primary safeguard.
Traffic Inputs and Identification
DAA consumes the transponder_report topic, which can be populated by ADS-B, FLARM, UTM, or another integration. PX4 maps incoming MAVLink ADSB_VEHICLE messages to this topic. Other integrations must provide their own compatible transponder_report publisher.
INFO
PX4 does not currently map incoming MAVLink UTM_GLOBAL_POSITION messages to transponder_report. The similarly named MAVLink stream in PX4 sends ownship UTM state; it is not a traffic-input adapter.
Reports without a usable identifier are ignored before they enter the active-conflict buffer.
DAA chooses one identifier per traffic report in this order:
- ICAO address
- ADS-B callsign
- UAS ID
The selected identifier is published on both detect_and_avoid and detect_and_avoid_most_urgent as:
unique_id: the encoded 64-bit identifier valueunique_id_encoding:ICAO,ADSB_CALLSIGN, orUAS_ID
The encoding is part of the traffic key. That means an ICAO address and a callsign can encode to the same integer and still remain separate traffic entries. To decode a logged unique_id back into an ICAO address, callsign, or shortened UAS ID, see Identifying the aircraft, which includes a Python helper.
Click here to view how DAA accepts and encodes each identifier source
| Identifier source | Accepted if | Stored value |
|---|---|---|
| ICAO address | 0 < icao_address <= 0xFFFFFF | Stored directly in the low bits of unique_id with UNIQUE_ID_ENCODING_ICAO |
| ADS-B callsign | PX4_ADSB_FLAGS_VALID_CALLSIGN is set and the callsign[9] field is null-terminated | Packs up to 8 callsign characters into a uint64. Byte 0 is the first character. Bytes 0-3 correspond to ADSB_CALLSIGN_1 and bytes 4-7 correspond to ADSB_CALLSIGN_2. |
| UAS ID | At least one of the final 8 bytes in uas_id[18] is non-zero | Packs those final 8 bytes into a uint64 with UNIQUE_ID_ENCODING_UAS_ID |
Important implications of that priority order:
- DAA stops at the first usable identifier. It does not compare a later callsign or UAS ID once a non-zero ICAO address has been accepted.
- Callsign self-filtering only works if the incoming report either has no ICAO address or the ICAO address is also configured as ownship.
- UAS ID self-filtering is the last fallback. On boards that expose a PX4 UUID, DAA compares the reduced UAS ID against the reduced tail bytes of the board UUID.
Self-filtering uses:
- ADSB_ICAO_ID: primary ownship ICAO address.
- ADSB_ICAO_ID_2: optional second ownship ICAO address checked independently for self-filtering.
- ADSB_CALLSIGN_1: first 4 characters of the ownship ADS-B callsign.
- ADSB_CALLSIGN_2: last 4 characters of the same ownship ADS-B callsign.
ADSB_CALLSIGN_1 and ADSB_CALLSIGN_2 together define one 8-character callsign, and both halves must match for callsign-based self-filtering. By contrast, ADSB_ICAO_ID and ADSB_ICAO_ID_2 are two separate ICAO addresses that DAA checks independently.
WARNING
ADSB_ICAO_ID now defaults to -1, which leaves the primary self-filter unset and disables PX4-managed ADS-B Out. Older PX4 releases defaulted this parameter to 1194684; a vehicle that relied on that default rather than saving an explicitly assigned ICAO address will therefore stop PX4-managed ADS-B transmission after upgrading. Configure the aircraft's assigned ICAO address and reboot before relying on ADS-B Out.
The callsign parameters use the documented character order within each 32-bit word. For example, ADSB_CALLSIGN_1 = 0x50583420 ("PX4 ") and ADSB_CALLSIGN_2 = 0x54455354 ("TEST") identify the callsign "PX4 TEST"; DAA converts those words to its internal packed-ID byte order before comparing reports.
DAA also removes conflicts that stop receiving updates after DAA_TRAFF_TOUT.
Key Parameters
For the operator-facing setup flow, see ADS-B/FLARM/UTM Receivers > Configure Traffic Avoidance. On this page, parameters are described where their behavior matters: NAV_TRAFF_* in Crosstrack Mode, DAA_LVL_*, DAA_EN_DFLT_VEL, and DAA_DFLT_VEL in F3442 Mode, DAA_NOTIF_STATE in Operator Messages, DAA_TRAFF_TOUT in Traffic Inputs and Identification, and ownship ADS-B identification parameters in the same traffic-input section. F3442-specific parameters are only present in firmware built with CONFIG_NAVIGATOR_ADSB_F3442.
Telemetry and Logging
The main DAA topics are:
detect_and_avoid: per-traffic assessments for reports that create, update, or clear a tracked conflict. First-seen reports evaluated at conflict levelNONEare omitted.detect_and_avoid_most_urgent: the current most urgent active conflict.transponder_report: raw traffic input to DAA.
detect_and_avoid and detect_and_avoid_most_urgent are logged by default.
These topics are useful for:
- Flight review
- Integration testing
- Preflight debugging
- Verifying conflict escalation and action selection
Operator Messages
DAA talks to the operator on two channels at the same time:
- MAVLink STATUSTEXT is the short, human-readable line such as
DAA Main: 6E9F7B lvl UP 3. 199 m.. PX4 emits these asmavlink_logrecords, and the MAVLink module forwards them on itsSTATUSTEXTstream as MAVLinkSTATUSTEXTmessages to connected ground stations. The identifier is already decoded into a readable string here, so this is the easiest channel to read while flying. - PX4 Events carry the same information through the Events Interface, but as structured data: a fixed event ID plus numeric arguments (identifier, conflict level, distance, cause, notification kind).
For levels configured as Warn only or stronger, messages are emitted after the queue-processing cycle when a conflict level changes. The most urgent conflict is also reported periodically (the period is DAA_NOTIF_STATE).
Reading the message fields
Every conflict message refers to one traffic aircraft and reuses the same handful of fields.
Click here to view the fields used in events
<ID>: the traffic identifier
DAA tracks each aircraft by the identifier selected in Traffic Inputs and Identification. The two channels show that identifier differently:
- In STATUSTEXT it is already decoded to a readable string: a 6-character ICAO hex such as
6E9F7B, an up-to-8-character callsign such asLX00777A, or a shortened UAS-ID hex such aseaebecedee. - In events it is the raw 64-bit integer (
unique_id) that DAA stores internally. The same integer, together with itsunique_id_encoding, is also published on thedetect_and_avoidanddetect_and_avoid_most_urgenttopics.
To turn that integer back into a readable identifier (for example an ICAO address) you need the encoding and the matching decode rule. A worked example with code is in Identifying the aircraft.
<N>: the conflict level
The level is the same integer used on the uORB topics:
<N> | Level | F3442 meaning |
|---|---|---|
0 | NONE | no conflict or cleared |
1 | LOW | augmented Well Clear |
2 | MEDIUM | augmented NMAC |
3 | HIGH | Loss of Well Clear |
4 | CRITICAL | NMAC |
Crosstrack builds only ever publish HIGH (3). See Conflict Levels for the full F3442 definitions. In the main and secondary messages, the words UP and DOWN tell you whether the level just increased or decreased.
<dist>: distance to the traffic
The straight-line 3D range to that aircraft in meters, computed from the horizontal and vertical separation (
Notification kind (events only)
The navigator_traffic_conflict_update event carries a notification kind argument that says which conflict the update is about. It matches the prefix used in the STATUSTEXT line:
| Notification kind | STATUSTEXT prefix | Meaning |
|---|---|---|
0 | DAA Main: | update for the conflict that is already the most urgent |
1 | DAA New and Main: | a conflict that appeared this cycle and is also now the most urgent |
2 | DAA SEC: | a secondary (non-primary) tracked conflict that is not the most urgent |
Action code (events only)
The navigator_traffic_action event reports which automatic response was triggered, using the same numbering as the NAV_TRAFF_AVOID / DAA_LVL_*_ACT parameters:
| Action code | Action |
|---|---|
2 | Return |
3 | Land |
4 | Hold |
5 | Terminate |
0 (Disabled) and 1 (Warn only) do not generate an action event because no automatic action is requested. See Automated Actions for the full action parameter convention.
Click here to view the message families and notification timing
- New conflict:
DAA New <ID> lvl <N>. <dist> m.: emitted after the currentcheck_traffic()queue drain completes when a new warning-level conflict remains in the active buffer but is not the current most urgent conflict. - Main conflict:
DAA Main: <ID> lvl UP <N>. <dist> m.: emitted immediately when the most urgent conflict level increases.DAA Main: <ID> lvl DOWN <N>. <dist> m.: emitted immediately when the most urgent conflict level decreases but remains active.DAA Main: <ID> lvl <N>. <dist> m.: periodic message for the current most urgent conflict when its level stays unchanged. The message period is DAA_NOTIF_STATE; setting it to0disables this periodic message.
- New and Main conflict:
DAA New and Main: <ID> lvl <N>. <dist> m.,DAA New and Main: <ID> lvl UP <N>. <dist> m.,DAA New and Main: <ID> lvl DOWN <N>. <dist> m.: emitted after the currentcheck_traffic()queue drain completes when a new warning-level conflict is also the current most urgent conflict. - Secondary conflicts:
DAA SEC: <ID> lvl UP <N>. <dist> m.,DAA SEC: <ID> lvl DOWN <N>. <dist> m.,DAA SEC: <ID> solved. <dist> m.: emitted immediately for non-primary traffic whose level changes while another conflict remains most urgent. - Buffer handling:
DAA <ID> out (<cause>) lvl <N> (<age>s).: emitted immediately when a previously buffered conflict is removed because it became stale or because it was evicted to make room for a more urgent conflict. New conflicts that are inserted and then displaced within the same queue drain before anyDAA Newnotification are intentionally silent. The cause is mapped to:- STALE_CONFLICT = 0,
- BUFFER_FULL = 1
DAA <ID> ignored (<cause>) lvl <N>.: emitted when traffic could not be inserted or updated. This warning is rate-limited to once every2 s. The cause can be:- BUFFER_FULL = 0
- Actions:
DAA <ID>: Hold!,Return!,Land!,Terminate!, and the on-groundDAA do not arm until air conflict solved!/DAA do not takeoff until air conflict solved!warnings only appear when a conflict level is configured with an automatic action stronger thanWarn only. The default DAA parameters are warn-only so by default these action messages are not emitted. - No more conflicts:
DAA all conflicts solved.: emitted immediately when the most urgent conflict clears and no warning-level conflicts remain.
The shared fields <ID>, <N>, and <dist>, plus the cause numbers above, are explained in Reading the message fields. To turn a logged or event identifier back into an ICAO address, callsign, or UAS ID, see Analysing a Conflict Using the Logs.
Analysing a Conflict Using the Logs
After a flight you can reconstruct exactly what DAA saw and did from the default log. This is the recommended way to investigate a conflict, because the logged topics carry the full identifier, encoding, geometry, and timing that the short operator messages only summarize.
What to look at
detect_and_avoid_most_urgent: the single conflict that drove the DAA status and any automatic action or prearm block. Start here to find the worst moment of the encounter (highestconflict_level, smallestaircraft_dist) and whetherhas_actionwas set.detect_and_avoid: samples for traffic that creates, updates, or clears a tracked conflict, with the per-aircraftconflict_leveland the horizontal, vertical, and time geometry. Use it to follow one specific aircraft over time.transponder_report: the raw input. Match it by timestamp to see the traffic's reported position, altitude, velocity, heading, and validity flags, plus the originalicao_address,callsign, anduas_idfields before encoding.- Navigator state and commander messages: confirm whether a requested action actually changed the flight mode.
You can open the log in Flight Review or plot these topics directly. Live, the same topics can be inspected from the shell with listener detect_and_avoid and listener detect_and_avoid_most_urgent.
Identifying the aircraft
Both DAA topics publish unique_id (the 64-bit integer) and unique_id_encoding (the type of ID). Decode the integer according to the encoding:
unique_id_encoding | Source | How to decode |
|---|---|---|
0 (ICAO) | ICAO 24-bit address | low 24 bits formatted as 6 uppercase hex digits |
1 (ADSB_CALLSIGN) | ADS-B callsign | bytes little-endian, byte 0 is the first character, stop at first \0 |
2 (UAS_ID) | shortened UAS ID | low bytes as hex; the displayed string uses the low 5 bytes (10 hex chars) |
The selection and storage rules behind this table are described in Traffic Inputs and Identification.
Click here to view a Python script example on how to decode unique_id (the 64-bit integer)
The following helper applies the same conversion DAA uses to build the STATUSTEXT string, so its output matches what you saw live:
import argparse
def decode_daa_id(unique_id: int, encoding: int) -> str:
if encoding == 0: # ICAO
return f"{unique_id & 0xFFFFFF:06X}"
if encoding == 1: # ADS-B callsign
out = bytearray()
for i in range(8):
byte = (unique_id >> (8 * i)) & 0xFF
if byte == 0:
break
out.append(byte)
return out.decode("ascii", "replace")
if encoding == 2: # UAS ID (shortened, low 5 bytes shown)
return "".join(f"{(unique_id >> (8 * i)) & 0xFF:02x}" for i in range(5))
return "unknown"
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Decode a DAA ID based on its encoding type.")
parser.add_argument("unique_id", type=int, help="The 64-bit unique ID")
parser.add_argument(
"encoding",
type=int,
choices=[0, 1, 2],
help="Encoding type: 0 (ICAO), 1 (ADS-B), or 2 (UAS ID)",
)
args = parser.parse_args()
print(decode_daa_id(args.unique_id, args.encoding))Example 1: Decoding an ICAO address (encoding 0): the integer 7249787 decodes to the 6-character hex ICAO address 6E9F7B.
python3 decode_daa.py 7249787 0Example 2: Decoding an ADS-B callsign (encoding 1): the integer 827736405 is the packed ASCII representation of the callsign UAV1.
python3 decode_daa.py 827736405 1Example 3: Decoding a UAS ID (encoding 2): the integer 737869762868 is unpacked into the shortened 10-character hex string 341177ccab.
python3 decode_daa.py 737869762868 2Turning an ICAO address into a real aircraft
When the encoding is ICAO, the decoded 6-digit hex (for example 6E9F7B) is the 24-bit address reported over ADS-B or Mode S. When the address has been assigned and transmitted correctly, an aircraft registry may map it to a tail number, type, or operator.
This is how you confirm whether the intruder was, for instance, a helicopter, a general-aviation aircraft, or even your own second transponder. If it turns out to be ownship, update the self-filtering parameters described in Traffic Inputs and Identification.
Summary
A typical investigation:
- In
detect_and_avoid_most_urgent, find whenconflict_levelpeaked andaircraft_distwas smallest, and noteunique_idandunique_id_encoding. - Decode the identifier; if it is an ICAO address, look up the aircraft.
- In
detect_and_avoid, follow that identifier to see how the horizontal, vertical, and time separation evolved and how the level escalated. - Cross-check
transponder_reportat the same timestamps for the raw geometry and validity flags. Missing velocity or heading changes how the model evaluates the conflict (see the data requirements for F3442 Mode or Crosstrack Mode). - Confirm in the navigator and commander messages whether the configured action ran and whether the resulting mode change matched expectations.
Testing and Simulation
Synthetic traffic generation is available when the firmware is built with CONFIG_NAVIGATOR_ADSB_FAKE_TRAFFIC. This option is intended for simulation and dedicated test images; it should not be enabled in production flight firmware.
Use the navigator shell command:
navigator fake_trafficAvailable modes:
unique_ids,escalation,spam_same,spam_new,flags,queue_fill
Example:
navigator fake_traffic escalationUse navigator fake_traffic help for the short mode list and navigator fake_traffic stop to cancel a pending scripted run.
WARNING
navigator fake_traffic injects traffic into the normal DAA pipeline. If the configured action for the triggered conflict level is Hold, Return, Land, or Terminate, PX4 can request that action exactly as it would for real traffic.
Run these scenarios with a valid vehicle position, because the synthetic reports are generated around the current ownship latitude, longitude, and altitude.
The command schedules a deterministic synthetic traffic sequence and returns immediately. DAA then publishes the scripted transponder_report samples from its normal update loop around the current ownship latitude, longitude, and altitude.
Click here for more details on each fake traffic scenario
Scenario guide:
unique_ids: Publishes three isolated four-step approach sequences: about1500 m,800 m,200 m, then5000 mto clear the conflict. The first traffic uses a valid ICAO address, the second removes ICAO so DAA must fall back to the ADS-B callsign, and the third removes ICAO plus a valid callsign so DAA must fall back to UAS ID. Use this to verify identifier priority without overlap between the three identifier cases.escalation: Publishes one aircraft every2 swhile its range decreases from about3000 mto100 m. Use this to watch conflict levels rise, confirm when the most urgent conflict level changes, and verify that the configured action thresholds trigger at the expected ranges.spam_same: Publishes the same aircraft40times at10 Hzwhile keeping it at about200 m. Use this to confirm that repeated updates from one target are not generating excessive notifications (expect a period of DAA_NOTIF_STATE).spam_new: Publishes10different ICAO identities, one per second, with fixed distances chosen to fill the5-entry conflict buffer, evict the least urgent items deterministically, and exercise ignored-traffic throttling once the buffer is full.flags: Publishes one aircraft with valid position, altitude, heading, and callsign, but with the velocity-valid flag intentionally cleared. In F3442 builds the report is still accepted because only coordinates and altitude are mandatory; the missing traffic velocity is treated as zero, and if DAA_EN_DFLT_VEL is enabled the vertical speed is replaced by DAA_DFLT_VEL. In Crosstrack builds the same report is rejected because velocity is required there.queue_fill: Runs three consecutive batches ofORB_QUEUE_LENGTHreports. Batch 1 repeats the same close critical aircraft for the full queue length. Batch 2 publishes new lower-priority conflicts that get progressively closer so each one is accepted while the original aircraft remains the most urgent. Batch 3 starts even closer and then gets farther away so only the first4entries replace the existing lower-priority traffic and the rest are ignored. Use this to confirm DAA drains one full queuedtransponder_reportburst percheck_traffic()call and preserves the correct final priority order after each batch.
What to watch while running a scenario:
detect_and_avoid: per-traffic output for tracker-accepted reports that create, update, or clear a conflict.detect_and_avoid_most_urgent: the single conflict that currently drives the main DAA status and any automatic action decision.mavlink_log, MAVLinkSTATUSTEXT, and PX4 Events: new conflict, escalation, reduction, ignored traffic, and stale or evicted traffic messages.
Useful shell commands:
listener detect_and_avoid
listener detect_and_avoid_most_urgentExpected Behavior
Exact distances and message text depend on the selected parameters and vehicle state. With the default warn-only F3442 actions:
| Scenario | Expected behavior |
|---|---|
unique_ids | Three otherwise similar encounters are tracked by ICAO address, callsign, and UAS ID respectively. |
escalation | One aircraft progresses through increasing conflict levels, then becomes stale and is removed. |
spam_same | Repeated reports refresh one tracked conflict without producing a message for every sample. |
spam_new | Multiple aircraft fill the conflict buffer; less urgent reports are evicted or ignored according to buffer priority. |
flags | F3442 accepts missing traffic velocity and applies its configured defaults; Crosstrack rejects the report. |
queue_fill | DAA drains a full queued burst and retains the highest-priority conflicts. |
Use the uORB topics and operator messages above to verify the result. Automated-action testing should use a controlled simulation environment.
The sequences below assume the default F3442 configuration.
Click here to view default configuration
- Firmware built with
CONFIG_NAVIGATOR_ADSB_F3442 - DAA_LVL_LOW_ACT =
Warn only - DAA_LVL_MED_ACT =
Warn only - DAA_LVL_HIGH_ACT =
Warn only - DAA_LVL_CRIT_ACT =
Warn only - DAA_EN_DFLT_VEL =
1 - DAA_DFLT_VEL =
10 m/s - Ownship horizontal and vertical speed =
0 - Ownship and traffic altitude are equal
Under those assumptions, the expected operator-visible messages for each scenario are:
unique_ids: four-step process repeated for the three unique identifier cases.
Click here to view the expected results
- ICAO case
6E9F7B:- Step 1:
DAA New and Main: 6E9F7B lvl UP 2. 1499 m. - Step 2:
6E9F7Bat 800 m stays at the same conflict level (2), so it does not emit anotherDAA Mainline before DAA_NOTIF_STATE expires. - Step 3:
DAA Main: 6E9F7B lvl UP 3. 199 m. - Step 4: move conflict 5000m away and expect:
DAA all conflicts solved.
- Step 1:
- Callsign case
LX00777A: the same level sequence as above, but withLX00777Aas the identifier. - UAS ID fallback case: the same level sequence as above, but with the shortened board-dependent UAS ID string as the identifier e.g.,
eaebecedee.
escalation: thirty-step conflict with a single incoming aircraft flying towards the UAV.
Click here to view the expected results
- Example with default warn-only parameters:
- No DAA warning is expected from
3000 mdown to about2300 m. - At about
2200 m:DAA New and Main: 9F3FA3 lvl UP 1. 2200 m. - At about
1800 m:DAA Main: 9F3FA3 lvl UP 2. 1800 m. - At about
600 m:DAA Main: 9F3FA3 lvl UP 3. 600 m. - At about
100 m:DAA Main: 9F3FA3 lvl UP 4. 100 m. - After approximately DAA_TRAFF_TOUT:
DAA 9F3FA3 out (0) lvl 4 (<age>s).followed byDAA all conflicts solved. - No
DAA SECor automatic-action messages are expected with the default warn-only parameters.
- No DAA warning is expected from
- Example with actions defined as Hold, Return, Land, and Terminate:
DAA: Actions lvl: low: 4, med: 2, high: 3, crit: 5:DAA New and Main: 9F3FA3 lvl UP 1. 2366 m.- Hold triggered on augmented WC breach:
DAA 9F3FA3: Hold! lvl 1. 2366 m. DAA Main: 9F3FA3 lvl UP 2. 1773 m.- Return triggered on augmented NMAC breach:
DAA 9F3FA3: Return! lvl 2. 1773 m.[commander] Returning to launch[navigator] RTL: start return at 519 m (30 m above destination)
DAA Main: 9F3FA3 lvl 2. 849 m.(the periodic most-urgent status, emitted because the level held at 2 for DAA_NOTIF_STATE since the previous9F3FA3message)DAA Main: 9F3FA3 lvl UP 3. 527 m.- Land triggered on WC breach:
DAA 9F3FA3: Land! lvl 3. 527 m.[commander] Landing at current position
DAA Main: 9F3FA3 lvl UP 4. 124 m.- Terminate triggered on NMAC breach:
DAA 9F3FA3: Terminate! lvl 4. 124 m.[failsafe] Failsafe activated
spam_same: forty-step conflict with an aircraft spamming transponder reports from the same location.
Click here to view the expected results
- First sample only:
DAA New and Main: 61F77C lvl UP 3. 199 m. - The remaining
39updates refresh the same conflict entry but do not emit extra status lines because the level does not change and the whole scenario finishes before DAA_NOTIF_STATE elapses. Eventually the traffic becomes stale at approximately DAA_TRAFF_TOUT, followed byDAA all conflicts solved..
queue_fill: three-cycle queue-drain burst.
Click here to view the expected results
- Step 1: the first queue is filled with the same aircraft, expect a single message:
DAA New and Main: DDF0A1 lvl UP 4. 100 m. - Step 2: the second queue is filled with different aircraft getting closer and closer. DAA drains the full queue before it emits
DAA Newlines, so only the four entries that survive the batch are reported:DAA New 51000D lvl 2. 680 m.,DAA New 51000E lvl 2. 670 m.,DAA New 51000F lvl 2. 660 m.,DAA New 510010 lvl 2. 650 m.- Earlier step-2 candidates
510001through51000Care accepted provisionally and then replaced within the same drain, so they do not emitoutorignoredoperator messages.
- Step 3: the third queue is filled with different aircraft getting farther and farther. The first four entries are still more important than the surviving step-2 traffic, so expect:
DAA New 520001 lvl 3. 569 m.,DAA New 520002 lvl 3. 589 m.,DAA New 520003 lvl 3. 609 m.,DAA New 520004 lvl 2. 629 m.- Because those four replace already-known step-2 conflicts from the previous cycle, expect removals:
DAA 51000D out (1) lvl 2 (2s).,DAA 51000E out (1) lvl 2 (2s).,DAA 51000F out (1) lvl 2 (2s).,DAA 510010 out (1) lvl 2 (2s). - The remaining step-3 traffic is less important than the buffer contents, so it is ignored. Because ignored notifications are throttled, the first operator-visible message is typically
DAA 520005 ignored (0) lvl 2.
spam_new: ten-step multi-aircraft conflict that fills the buffer.
Click here to view the expected results
| Step | ICAO | Nominal range | Expected result |
|---|---|---|---|
| 1 | 380E97 | 1200 m | DAA New and Main: 380E97 lvl UP 1. 1200 m. |
| 2 | 67F621 | 900 m | DAA New and Main: 67F621 lvl 1. 899 m. |
| 3 | ACDE77 | 700 m | DAA New and Main: ACDE77 lvl UP 2. 700 m. |
| 4 | 45F276 | 500 m | DAA New and Main: 45F276 lvl UP 3. 500 m. |
| 5 | 34990F | 100 m | DAA New and Main: 34990F lvl UP 4. 100 m. The buffer is now full. |
| 6 | EB61D8 | 130 m | New entry on a full buffer, least urgent conflict is removed first for cause: BUFFER_FULL: DAA 380E97 out (1) lvl 1 (5s). and then we add the new traffic: DAA New EB61D8 lvl 4. 130 m. |
| 7 | A1EAB2 | 550 m | New entry on a full buffer, least urgent conflict is removed first for cause: BUFFER_FULL: DAA 67F621 out (1) lvl 1 (5s). then DAA New A1EAB2 lvl 3. 550 m. |
| 8 | C5ED22 | 1100 m | DAA C5ED22 ignored (0) lvl 1. ignored for cause BUFFER_FULL and all other conflicts are more important. |
| 9 | B2F854 | 750 m | No new operator message is expected, because the traffic is ignored again while ignored-traffic warnings are still inside the 2 s rate limit |
| 10 | E16498 | 140 m | New entry on a full buffer, least urgent conflict is removed first for cause: BUFFER_FULL: DAA ACDE77 out (1) lvl 2 (7s). then DAA New E16498 lvl 4. 140 m. and DAA Main: 34990F lvl 4. 100 m. |
Notes:
- The main conflict
DAA Main: 34990F lvl 4. 100 m.appears periodically during the scenario at the rate of DAA_NOTIF_STATE. - After the last step, all conflicts are eventually marked as stale and resolved:
DAA 34990F out (0) lvl 4 (20s).DAA 45F276 out (0) lvl 3 (21s).DAA A1EAB2 out (0) lvl 3 (20s).DAA EB61D8 out (0) lvl 4 (21s).DAA E16498 out (0) lvl 4 (21s).DAA all conflicts solved.
flags: one aircraft with the velocity-valid flag intentionally cleared.
Click here to view the expected results
- In
F3442:DAA New and Main: L07NOVEL lvl UP 4. 100 m.followed by the periodic notification:DAA Main: L07NOVEL lvl 4. 100 m.and finally:DAA L07NOVEL out (0) lvl 4 (20s).andDAA all conflicts solved.. - In
Crosstrack: no DAA conflict message is expected, because the same report is rejected when the velocity-valid flag is missing.
Current Limitations
- DAA handles cooperative traffic only.
- DAA does not generate lateral or vertical avoidance trajectories.
- DAA selects high-level navigator actions; it does not solve conflict geometry beyond the selected conflict model.
- Conflict handling is bounded by a fixed-size active-conflict buffer.
- Action selection and the commander arming check are driven by the single geometrically most urgent conflict. A lower-priority buffered conflict does not independently drive an action or arming block, even if its configured action is stronger.
- DAA compares ownship altitude directly with
transponder_report.altitudeand does not usealtitude_typeto normalize pressure and geometric altitude references. A datum mismatch can therefore bias vertical separation. - DAA quality depends on the quality and freshness of both traffic data and vehicle state.
Implementation Structure
The implementation is split between a shared PX4 library and the navigator integration:
src/lib/adsb: the DAA core, with no navigator dependency; uORB message structs and enums are only used for data types. It contains the conflict standards (DaaCrosstrack,DaaF3442, wrapped byAdsbConflict), the traffic identifier encoding and self-detection (DaaEncodedId), the active-conflict buffer (ConflictTracker), and the action policy (DaaActionPolicy).ConflictTrackerowns the fixed-size conflict buffer and the priority rules: it inserts, updates, and evicts conflicts, caches the most urgent one, and reports every change that may require a user-facing message as a change record (conflict_tracker_change_s), without sending any notification itself.DaaActionPolicyis a stateless decision function: given the most-urgent level transition, the navigation state, the landed/armed state, and the action parameter values, it returns which vehicle command to request and which action or ground message to send. It implements the level-to-action mapping (including the F3442 per-level action fallback described in Automated Actions) and the navigator-state escalation gate.src/modules/navigator/DetectAndAvoid: the navigator integration. It validates and identifies incomingtransponder_reportdata, runs the built standard, feeds the result to the tracker, publishes the DAA topics, and executes the policy's action decisions (vehicle commands and action messages). All operator messaging is concentrated in one class,ConflictNotifier: it turns the change records collected over one cycle into the messages described in Operator Messages in a single per-cycle call (report_cycle()), and also owns the message formatting, severity mapping, and rate-limit timers used by the action and ground warnings.
Adding a New Standard
At the library level, a DAA standard is a class that consumes one ownship state plus one traffic state and returns both a conflict level and reporting metrics.
Click here to view an in depth guide on how to add a new standard
class DaaNewStandard : public ModuleParams
{
public:
DaaNewStandard();
uint8_t calculate_daa_stats(const aircraft_state_s &uav_state,
const aircraft_state_s &traffic_state,
daa_stats_s &daa_stats);
bool try_setting_params();
};The shared input and output are:
aircraft_state_sinput fields:lat_lon: ownship or traffic latitude/longitude in degrees.altitude: ownship or traffic altitude in meters.velocity_ned: velocity in meters per second in north-east-down frame. In the wrapper path, traffic without a finite heading is converted to a due-north horizontal vector(hor_speed, 0, -ver_speed_up)so heading-agnostic standards can still use speed magnitude. A new standard that depends on the actual traffic track direction must reject missing heading explicitly.heading: course-over-ground or track heading in radians. A standard may ignore this field, but a standard that builds projected-track geometry must require it to be finite.
daa_stats_soutput fields:aircraft_dist_hor: the standard's reported horizontal-separation metric in meters. This may be direct range, signed crosstrack distance, or another horizontal metric defined by the standard.aircraft_dist_vert: the standard's reported vertical-separation metric in meters.expected_min_dist_time_sec: the standard's reported conservative time metric in seconds. This may be a worst-case closure-time estimate or another minimum-distance timing metric defined by the standard.
- Return value:
- one of
detect_and_avoid_s::DAA_CONFLICT_LVL_NONE,LOW,MEDIUM,HIGH, orCRITICAL
- one of
To add a new standard end-to-end:
- Implement a new class with
calculate_daa_stats()and define its runtime parameter validation. - Decide which
aircraft_state_sfields are mandatory for that standard and enforce those requirements in the wrapper path (AdsbConflict::calculate_daa_output()) and inside the standard itself if it can be called directly. In particular, decide whether the due-north fallback forvelocity_nedwithout traffic heading is acceptable, or whether the standard requires the true traffic track direction. - Add a build-time config and CMake selection for the standard, including any standard-specific parameter metadata only when that config is enabled.
- Add the class to
AdsbConflictand update the compile-time branches that validate inputs, runcalculate_daa_stats(), and refresh parameters. - Add unit tests for both the standard math and the outer
AdsbConflictvalidation path, then update this documentation with the standard-specific data requirements, parameters, and action semantics.