Air Traffic Control Project – A Real-Time System Implementation
In our COEN 320 course, we developed a simplified Air Traffic Monitoring and Control (ATC) system, focusing on the en-route airspace. This project was implemented in C/C++ and ran on the QNX real-time operating system, ensuring accurate timing constraints and efficient task scheduling.
Project Overview
Our ATC system simulates an en-route control center, responsible for tracking aircraft as they traverse a designated 3D airspace. The system continuously monitors aircraft positions, velocities, and separation distances, issuing alerts for potential collisions.
Implemented Modules
- Radar System: Detects and tracks aircraft, relaying their positions to the computer system.
- Computer System: Processes aircraft data, checks for safety violations, and issues alerts if a collision is predicted within 3 minutes.
- Data Display: Updates the airspace visualization every 5 seconds, ensuring controllers have real-time situational awareness.
- Operator Console: Allows manual intervention, enabling air traffic controllers to adjust aircraft altitude, speed, or trajectory.
- Communication System: Transmits control commands from operators to the aircraft.
Technical Highlights
- Aircraft are modeled as individual threads, periodically updating their position every second.
- Real-time constraints are maintained using QNX message passing, ensuring efficient inter-process communication.
- Collision detection is implemented using mathematical trajectory analysis, predicting conflicts based on aircraft movement.
- Logging system records airspace history every 30 seconds, allowing post-analysis of aircraft movement.
System Architecture
The system consists of five subsystems communicating through named QNX IPC channels. Each subsystem runs on its own thread(s) with explicit scheduling priorities under SCHED_SPORADIC. All inter-process communication uses QNX's synchronous message-passing (MsgSend/MsgReceive), ensuring deterministic, auditable data flow with no shared-memory race conditions. The simulated airspace is bounded at 100 km × 100 km × 25 km.
Plane
Each Plane object spawns two threads on construction:
- Telemetry thread (
routineToRadar) — runs on a 1-second timer. Each cycle updates position via Euler integration (posX += accX,posY += accY,posZ += accZ), checks out-of-bounds conditions, packages position/velocity/time into aplane_datastruct, and sends it to Radar viaMsgSend()on the sharedDA_RADAR_channel. Blocks until Radar replies. Priority: 1. - Command receiver thread (
fromCommSysRoutine) — listens on a unique per-plane channel (COMM_SYS_channel + plane ID) for operator commands routed through CommSys. Parses altitude and vector change commands and updates acceleration values. Priority: 1.
Radar
A single thread running a server loop at priority 2. Listens on DA_RADAR_channel for plane telemetry. On message arrival, Radar immediately forwards it to CompSys via MsgSend() on COMP_SYS_channel, waits for the reply, then replies back to the originating plane. Radar is a pure relay — it performs no computation, just routing. All N planes funnel through this single Radar thread.
Computer System (CompSys)
The brain of the system. Spawns two threads:
- Server thread (priority 5) — listens on
COMP_SYS_channelfor telemetry from Radar (message type0x00) and commands from Operator (message type0x01). Maintains the authoritative aircraft state table (planeList— a map of plane ID to position/velocity data). Routes operator commands to CommSys for delivery to target planes, and forwards plane data to Data Display viaATC_Server1. - Safety check thread (priority 7) — runs periodically (default 3 seconds, configurable by the operator). Iterates over all plane pairs and calls
safetyViolation(), which checks current proximity (3 km horizontal, 1 km vertical tolerance) and projects positions forward up to 180 seconds via linear extrapolation. Logs immediate crashes and predicted conflicts.
x_future = x_current + vx * t and checks whether horizontal and vertical separation fall below threshold. One execution of the safety check processes all pairs across all 180 time steps — a complete traversal.
Communication System (CommSys)
A single thread at priority 3. Listens on COMP_SYS_channel_for_COMM for command messages from CompSys. When a command arrives, CommSys constructs the target plane's channel name (COMM_SYS_channel + plane ID), opens a connection via the QNX name service, and forwards the command via MsgSend(). CommSys is event-driven — it consumes zero CPU while blocked on MsgReceive(), waking only when CompSys sends work.
Operator
A single thread at priority 6 running a command-line interface. Supports four commands:
- Change safety violation time — adjusts the prediction window (max 180 seconds).
- Focus on a plane — filters Data Display to show only one aircraft.
- Change altitude — sends an altitude acceleration change to a specific plane.
- Change velocity vector — sends
ax/ay/azacceleration changes to a specific plane.
All commands are logged to command_log.txt for auditing. Commands are sent to CompSys via MsgSend() on COMP_SYS_channel with message type 0x01.
Data Display
Spawns two threads:
- Server thread — listens on
ATC_Server1for messages from CompSys. Updates an internalplanePositionsmap with current aircraft coordinates. Handles "focus" commands to filter display to a single aircraft. Logs all received data to file. - Display thread — wakes every 5 seconds and renders two views:
- Planar view (x, y): a 33×33 grid representing the airspace from above, with plane IDs plotted at scaled positions.
- Height distribution (z): a 25-level histogram showing aircraft count and IDs at each altitude band.
Test Scenarios
Three traffic density levels are generated by TestCaseSetUp:
- Low: 60 aircraft with manually defined positions and velocities, designed to create specific collision scenarios.
- Medium: 240 aircraft distributed along airspace edges, moving inward with constrained velocities.
- High: 540 aircraft placed on a grid with randomized positions and velocities directed toward the airspace center.
Key Design Decisions
- Synchronous message-passing — every
MsgSend()blocks until the receiver replies, ensuring deterministic ordering and implicit acknowledgment. No shared memory, no locks, no data races between subsystems. - Priority-based preemptive scheduling — on a single core, the highest-priority runnable thread always gets CPU time. Collision detection at priority 7 preempts everything else when it has work to do.
- Event-driven threads — subsystems like CommSys consume zero CPU while waiting. Threads only execute when messages arrive, making the system efficient even with hundreds of concurrent threads.
- Per-plane command channels — each plane listens on its own uniquely named channel, enabling direct command routing without broadcast or demultiplexing logic.