Ground Control System
Installation
The SteelEagle GCS is comprised of two components: a frontend browser application written in React (JSX) and a FastAPI backend (python) that acts returns data to the frontend by interfacing with the other backend components.
In the SteelEagle repo, the frontend code resides at: ~/steeleagle/gcs/react/prime.
The FastAPI backend resides at: ~/steeleagle/gcs/react/backend.
In order to quickly build the GCS, an installation shell script exists. This script will install nvm (used to manage versions of npm), npm (package manager), and build the frontend React application into a set of static files. It will also install uv, and use it to install the dependencies required by the FastAPI backend.
cd ~/steeleagle/gcs/react
sh -x install.sh
Configuration
There are two configuration files related to the GCS. These configuration files will be generated by the backend setup wizard during initial setup, but can be modified as necessary.
~/steeleagle/gcs/react/prime/src/config.js
- Contains the Mapbox token that is required to load map tiles. A free Mapbox account is required to generate the token. The following guide from Mapbox explains how to get started generating an access token
~/steeleagle/gcs/react/backend/config.toml
- The FastAPI .toml manages two primary sets of configuration: backends and vehicles. The GCS can either get data directly from local vehicles (the [vehicles] stanza) or by talking to a backend server ([backend] stanza). A sample config.toml is displayed below that defines two different backends and two local vehicles. The GCS can connect to multiple local vehicles simultaneously, but can only be connected to a single backend at runtime. Which backend to use from the config.toml can be controlled by passing the BACKEND environment variable when launching the GCS.
- For local vehicles, a [vehicle.name] stanza needs to be created that defines the local socket endpoints for that vehicle.
- For backends, a [backend.name] stanza needs to be created that defines where the various backend components can be found (swarm controller, redis db, etc).
[cors]
origins = [
"*"
]
[backend]
[backend.machine1]
swarm-controller = "machine1.address:5004"
redis_host = "machine1.address"
redis_port = 6379
redis_username = "steeleagle"
redis_password = "<password here>"
webserver = "http://machine1.address:8080"
[backend.machine2]
swarm-controller = "some.other.address:5004"
redis_host = "some.other.address"
redis_port = 6379
redis_username = "steeleagle"
redis_password = "<password here>"
webserver = "http://some.other.address:8080"
[vehicle]
[vehicle.test1]
address = 'unix:///tmp/test1-kernel.sock'
tel_endpoint = 'ipc:///tmp/test1-driver_telem.sock'
img_endpoint = 'ipc:///tmp/test1-imagery.sock'
res_endpoint = 'ipc:///tmp/test1-results.sock'
[vehicle.test2]
address = 'unix:///tmp/test2-kernel.sock'
tel_endpoint = 'ipc:///tmp/test2-driver_telem.sock'
img_endpoint = 'ipc:///tmp/test2-imagery.sock'
res_endpoint = 'ipc:///tmp/test2-results.sock'
cd ~/steeleagle/gcs/react/backend/
BACKEND=machine2 uv run main.py
Usage
The GCS can be launched by using uv:
cd ~/steeleagle/gcs/react/backend/
uv run main.py
This will launch using the default host (127.0.0.1) and port (8002). The host and port can be overridden by using the --host and --port command line parameters respectively. Once launched, the GCS can be reached in the browser at the host/port specified.
GCS Anatomy

By default, the control page is shown. Below is an explanation of each numbered part of the image.
- Page Selection - Navigate between monitor, control, and plan pages.
- The monitor page displays a large map which tracks the position of all vehicles and detected objects. It also lists the status cards for all connected vehicles.
- The control page allows the user to view a particular vehicle. It also allows both manual and autonomous control of a squadron of vehicles.
- The plan page is currently a WIP and is non-functional.
-
Global Settings Panel - This settings panel allows toggling between two modes: Swarm Controller where it talks to a backend server (this is the default), and Local Vehicles where it will communicate directly with any locally running vehicles.
-
Vehicle Details Selector - This dropdown controls which vehicle is currently being displayed. All connected vehicles will be listed and switching the selection will update the image stream (#6) and the vehicle status (#7).
This is distinct from the Squad Selection dropdown (#8). Changing the Vehicle Details selection will not change which vehicles (if any), are sent control messages. An error message will be generated in a toast popup if control messages are attempted to be sent when no vehicles have been selected.
- Control Settings Panel - The control settings panel displays a number of knobs and buttons that affect the behavior of the GCS. The image below shows these settings; explanations of each follow.

- Base Planar Velocity - The maximum velocity at which the vehicle moves in the planar dimensions (roll, pitch, elevation).
- Base Angular Velocity - The maximum velocity at which the vehicle rotates (yaw).
- Gimbal Velocity - The rate at which the gimbal pitches.
- Takeoff Altitude -The altitude to elevate to upon takeoff.
- Gamepad Deadzone - The percentage of joystick axis inputs are ignored before movement. Useful for gamepads that have some stick drift.
- Tracking Button - Whether or not to have the map snap to the currently selected vehicle so that it is always centered.
- Show Detections - Whether or not to show bounding boxes for detected objects overlaid on the image stream.
-
Map View - The map will display the location of all vehicles, but will snap to the currently selected vehicle when the value of the selector (#3) changes. If tracking is enabled (the default), the map will continuously snap to keep the vehicle centered. The zoom depth can still be changed whether or not tracking is enabled (by using the mouse wheel when focused on the map). Clicking and dragging the left mouse button on the map will pan (only works when tracking is disabled, otherwise it will just snap back to center). Clicking and dragging the right mouse button will pitch and rotate the map.
-
Image Stream - The image stream from the currently selected vehicle. If show detections are enabled (the default), bounding boxes will be overlaid onto the image stream when detections are made.
-
Vehicle Status - The vehicle status card will be displayed for the currently selected vehicle. It contains information such as the current battery level, number of satellites, compass heading, and currently velocities.
-
Squad Selection - This multi-select dropdown allows for one or more vehicles to be selected for control. Only the vehicles selected here can be controlled manually or autonomously (by uploading and starting missions; see #10). To the left of this dropdown is also the Manual Control indicator, which changes depending on whether or not manual control is currently possible.
-
Manual Control Buttons - These buttons issue a number of manual commands to the selected vehicles.
- Arm/Disarm
- Takeoff/Land
- RTH (return to home)/Hold(stop mission and hover)
- Autonomous Control Buttons - These buttons allow a user to select a mission (comprised of both a .kml and .json file), upload it (blue button), and then start the mission (green button). The red X button will remove the currently selected files to allow for a new mission to be uploaded.
Autonomous missions are a two stage process. First, the mission must be uploaded. Then a start mission command must be sent. As long as the mission doesn't change (and the vehicle is not restarted), subsequent calls to start the mission will execute the same mission. If the mission is changed, new files must be selected and uploaded before executing the mission using the mission start button.
Controlling Vehicles Manually
The GCS supports two methods for manual control: keyboard and gamepad. Gamepads can be connected using USB-A/C. When the Manual Control Indicator is disabled, no manual commands will be sent to the vehicles in the squad. Using one of the manual control buttons (#9 above) other than 'Hold' will disable manual control, as will starting an autonomous mission. Manual control can be enabled at any time using the Escape key on the keyboard or the 'Options' button on the gamepad. Below is a list of keyboard and gamepad axis/button mappings.
Currently only PS4/PS5 controllers have been tested. Other gamepads should work in theory, though button mappings may be different.
Keyboard Controls:
- T - Takeoff
- L - Land
- R/F - Pitch Gimbal Up/Down
- W/A/S/D - Planar movement
- I/K - Elevation
- J/L - Rotation
- Escape - Cancel Mission/Enable Manual Control
Gamepad Controls (PS4/PS5):
- Left Stick Up/Down - Elevation
- Left Stick Left/Right - Rotation
- Right Stick Up/Down - Pitch
- Right Stick Left/Right - Roll
- Triangle - Takeoff
- X - Land
- D-Pad Up/Down - Pitch Gimbal
- L1 - Return to Home
- Options Button - Cancel Mission/Enable Manual Control
- Share Button - Disable Manual Control
Running Autonomous Missions
Please see the guide on writing DSL missions for more information on how to craft a mission and compile it. Once a mission is compiled (into a .json file), it can be selected and uploaded to all the vehicles in a squad and executed. The autonomous missions controls in the bottom right of the Control page allow the user to select a set of waypoints (.kml) and a compiled mission (.json) file. After being selected, the files MUST be uploaded to the vehicles participating in the mission, by hitting the blue button with the up arrow. Once the mission files have been uploaded, the mission can be started at any time by pressing the green 'Start Mission' button.
Once a mission has started, it will run to completion unless it is canceled. Canceling a mission can be achieved by enabling manual control on either the keyboard (Escape key) or gamepad (Options button), or by hitting the 'Hold button in the bottom left corner of the GCS. Depending on the behavior of a vehicle's driver, some other actions may be blocking and also interrupt an autonomous mission, such as RTH and Land, though this is not recommended.
Please keep in mind that due to the nature of the control loop in SteelEagle, there is a fair amount of latency between commands issued at the GCS and their execution on the vehicle. The control plane is separate from the data plane, however real networks still have congestion and variability. Furthermore, when autonomous missions are running, actuation of the vehicle naturally builds momentum and even when a Hold command is received by a vehicle, it can take time to decelerate and come to a complete stop.
Utmost caution should be taken when executing autonomous missions and when unsure, missions should be interrupted using the above mechanisms.