Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
9306b43
Alpha 0.1.9/518 add altitude warnings (#585)
bensgilbert Jun 22, 2025
9ff87d6
Alpha 0.1.10/569 write missions to drone (#589)
1Blademaster Jul 29, 2025
539a6cd
alpha-0.1.10/575-add-improvements-to-mission-items-on-missions-page (…
1Blademaster Jul 30, 2025
ed4b4fc
Bump electron from 26.6.10 to 37.1.0 in /gcs in the npm_and_yarn grou…
dependabot[bot] Jul 30, 2025
cc43160
Alpha 0.1.10/571 read mission from file (#594)
1Blademaster Aug 1, 2025
ae630bf
Add exporting waypoints to file functionality (#596)
1Blademaster Aug 2, 2025
ab35bef
Revert "Bump electron from 26.6.10 to 37.1.0 in /gcs in the npm_and_y…
1Blademaster Aug 2, 2025
89c23bd
Alpha 0.1.10/573 add moveable home location (#597)
1Blademaster Aug 3, 2025
bffd8a5
Alpha 0.1.10/592 add rally point functionality to missions (#599)
1Blademaster Aug 3, 2025
8c4e9d1
Add clear mission button to context menu (#603)
1Blademaster Aug 6, 2025
e0c48fa
Add check and error message for mission item and mission type (#601)
1Blademaster Aug 6, 2025
c3aee87
alpha-0.1.10/Linux maptiler error #604 (#605)
NexInfinite Aug 6, 2025
7ff8947
Add progress modal for reading and writing mission to drone (#606)
1Blademaster Aug 7, 2025
fa581ed
Alpha 0.1.10/574 add fence functionality to missions (#607)
1Blademaster Aug 16, 2025
2ba3f85
Add mission statistics (#609)
1Blademaster Aug 16, 2025
d51c43c
Adding Redux base files (#614)
NexInfinite Aug 17, 2025
98df64e
Add mission tests (#616)
1Blademaster Aug 18, 2025
6e2434f
Dashboard.jsx change for redux (#617)
NexInfinite Aug 18, 2025
8efec3b
Fix activeTab state not updating bug (#625)
1Blademaster Aug 19, 2025
5511e89
Alpha 0.1.10/621 show a warning if changes were made to the mission b…
1Blademaster Aug 19, 2025
4e7d39c
Convert navbar to redux (#627)
NexInfinite Aug 19, 2025
bb35bc8
redux fix for alerts (#632)
bensgilbert Aug 20, 2025
19dc960
Conditionally render navbar based on pathname (#640)
Jopat2409 Aug 22, 2025
07b829a
Alpha 0.1.10/641 spotlight commands for connection to drone isnt work…
Jopat2409 Aug 22, 2025
21a9822
Add mission import and export tests (#630)
1Blademaster Aug 22, 2025
b4a66ff
Add zoom buttons to missions context menu (#633)
1Blademaster Aug 22, 2025
a21bc38
Add hideable mission warning banner (#637)
1Blademaster Aug 22, 2025
2274cf6
Fix bugs with home location and waypoints not being displayed correct…
1Blademaster Aug 22, 2025
59a830e
Move AddCommand to empty useEffect (#644)
Jopat2409 Aug 23, 2025
8898254
Python workflows only run on change in radio/ directory (#646)
Jopat2409 Aug 23, 2025
0ef2a13
Alpha 0.1.10/628 convert missions to redux (#647)
NexInfinite Aug 24, 2025
c49b807
Alpha 0.1.10/648 webcam duplicate connection issue (#649)
Jopat2409 Aug 25, 2025
e3e6ba2
Alpha 0.1.10/650 convert mission components to redux (#651)
1Blademaster Aug 31, 2025
ac6923e
Move all emitters to the socketMiddleware #654 (#660)
NexInfinite Sep 5, 2025
12917a9
remove connectionType attribute from drone class as its unused (#663)
1Blademaster Sep 5, 2025
b27eb47
Add context menu to waypoint markers (#661)
1Blademaster Sep 5, 2025
72165dd
Increase z height of context menu (#665)
1Blademaster Sep 7, 2025
758ac24
Make tabs list sticky (#667)
1Blademaster Sep 7, 2025
84ed918
Update fence styling and fix draggable marker bug (#669)
1Blademaster Sep 7, 2025
f079626
Add max telem distance stat (#671)
1Blademaster Sep 7, 2025
d7c4b13
Add custom about window (#673)
1Blademaster Sep 7, 2025
fc24298
Alpha 0.1.10/655 convert graphs to redux (#676)
NexInfinite Sep 7, 2025
ef79251
Add link stats popout window (#675)
1Blademaster Sep 7, 2025
1e49445
Add input to set loiter radius (#678)
1Blademaster Sep 9, 2025
ccffd5a
add battery alerts (#680)
bensgilbert Sep 10, 2025
f943e08
Fetch and build param definitions during build (#685)
1Blademaster Sep 10, 2025
5808ba4
Fix parameters and commands uplink from drone (#682)
1Blademaster Sep 10, 2025
033d8d2
Separate home position and planned home position, fix updating planne…
1Blademaster Sep 11, 2025
dcf6eac
Add number inputs for setting planned home position (#689)
1Blademaster Sep 13, 2025
61203e3
Add modal to select whether to update planned home position on missio…
1Blademaster Sep 14, 2025
54f0e57
Publish heartbeat message every second (#693)
1Blademaster Sep 14, 2025
eb6835a
Add context menu item to reset home position to drones home position …
1Blademaster Sep 14, 2025
5434170
Convert params to redux (#677)
NexInfinite Sep 14, 2025
6e4a727
Alpha 0.1.10/696 add options to add new waypoints via context menu (#…
1Blademaster Sep 18, 2025
084a88a
Alpha 0.1.10/699 all popout windows broken in build (#700)
1Blademaster Sep 19, 2025
3ed9c76
Alpha 0.1.10/701 fix reboot functionality (#702)
1Blademaster Sep 19, 2025
1991e94
Fix guided mode bug and convert to redux (#704)
1Blademaster Sep 19, 2025
f4a305e
Join all threads except current (#710)
1Blademaster Sep 23, 2025
2db1e32
Fix line display from home to first waypoint if no takeoff point (#708)
1Blademaster Sep 23, 2025
7ff5176
Add streamlined technical documentation for new developers (#705)
Copilot Sep 23, 2025
0c4a019
Alpha 0.1.10/659 move all other components missed into redux (#706)
1Blademaster Sep 23, 2025
3861968
Fix duplicate mission fetching, show loading notification when fetchi…
1Blademaster Sep 23, 2025
b2fb77f
Remove notificationSlice (#715)
1Blademaster Sep 23, 2025
3cfea16
Alpha 0.1.10/485 fla refactor (#698)
Kwash67 Sep 25, 2025
5b98a48
Add connection stats button to mac menu (#718)
1Blademaster Sep 26, 2025
379a1a6
Convert config to redux (#719)
NexInfinite Sep 26, 2025
d97964c
Add progress bar when connecting to drone (#722)
1Blademaster Sep 27, 2025
8ad61fc
Alpha 0.1.10/724 fix caching in paramscontroller (#725)
1Blademaster Sep 28, 2025
2f103bb
Add motor test warning modal (#727)
1Blademaster Sep 28, 2025
dbff5c4
Refactor outside visibility management to use Redux, optimise redux s…
1Blademaster Sep 28, 2025
85d2dad
Alpha 0.1.10/716 fla optimisation (#720)
1Blademaster Sep 28, 2025
708008f
Add Inter font (#730)
1Blademaster Sep 28, 2025
756b783
Fix pre-release bugs found (#732)
1Blademaster Sep 28, 2025
8e046c4
Merge branch 'main' into release-alpha-0.1.10
1Blademaster Sep 28, 2025
e16c844
Fix font not styling as bold
1Blademaster Sep 28, 2025
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
5 changes: 4 additions & 1 deletion .github/workflows/python_code_quality.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
name: Python Code Quality
on: [pull_request]
on:
pull_request:
paths:
- radio/**

jobs:
build:
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/python_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@ on:
branches:
- main
- release-*
paths:
- radio/**
pull_request:
branches:
- main
- release-*
paths:
- radio/**

jobs:
build:
Expand Down
11 changes: 11 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"configurations": [
{
"name": "Python Debugger: Backend",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/radio/app.py",
"console": "integratedTerminal"
}
]
}
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
{
"cSpell.words": [
"ardupilot",
"ARSP",
"centered",
"chancount",
"Crosshair",
"falcongrey",
"falconred",
"frametype",
"frametypename",
"maplibre",
"maptilers",
"mavutil",
"Motortestpanel",
"pymavlink",
"PYQT",
"RSSI",
Expand Down
152 changes: 9 additions & 143 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# FGCS

Falcon Ground Control Station.
# FGCS - Falcon Ground Control Station

> Learn more on our [website](https://fgcs.projectfalcon.uk)!

Expand All @@ -10,152 +8,20 @@ Falcon Ground Control Station.

## How to run

<details><summary>Windows - Installation</summary>

1. Go to [releases](https://github.com/Avis-Drone-Labs/FGCS/releases) and download the most recent versions `.exe` file
2. Run the downloaded file, you may have to click "more" then "run anyway" if windows defender blocks it
1. Go to [releases](https://github.com/Avis-Drone-Labs/FGCS/releases) and download the latest installer for your system
2. Run the downloaded installer, you may have to click "more" then "run anyway" if windows defender or any other firewall blocks it
3. Once installed it should be accessible via the start menu as "FGCS"

</details>

<details><summary>Windows - Manually</summary>

### Prerequisites

1. Ensure npm is installed, to do so follow [this guide](https://kinsta.com/blog/how-to-install-node-js/). Note: node version must be >= v20.10.0
2. Ensure yarn is installed, to do so run `npm install --global yarn` or follow [this guide](https://classic.yarnpkg.com/lang/en/docs/install/#windows-stable)
3. Install `python 3.11.9` (this can be found [here](https://www.python.org/downloads/release/python-3119/)) then create a virtual environment for it (see [Creating a virtual environment](#creating-a-virtual-environment) for help)

#### Creating a virtual environment

Create a new Python virtual environment using `python -m venv venv`. This can then be activated using `./venv/scripts/activate`.

> NOTE: To enter the virtual environment you will need to run `venv/Scripts/activate` on windows, to learn more please read: [how to make venv for linux and windows](https://www.geeksforgeeks.org/creating-python-virtual-environment-windows-linux/) or [what is a virtual environment?](https://docs.python.org/3/library/venv.html)


<details><summary>Running with bat file</summary>

1. If this is your first time running, please create a venv (see [Creating a virtual environment](#creating-a-virtual-environment)) and then run `./run.bat /path/to/venv update`
2. After this you can run `./run.bat /path/to/venv` (without the word update after)

</details>

<details><summary>Running independently</summary>

### Frontend

1. `cd gcs`
2. `yarn` (to install dependencies)
3. Create a `.env` file and add these two entries or rename `.env_sample` and populate the values:
- `VITE_MAPTILER_API_KEY=` + Your maptiler API key (can be generated [on maptilers website](https://cloud.maptiler.com/account/keys))
- `VITE_BACKEND_URL=http://127.0.0.1:4237` (if you want to change the port and host see: [Configuration > Changing Ports](#Configuration))
5. `yarn dev`

### Backend

1. `cd radio`
2. Make sure you're in a virtual environment (see [Creating a virtual environment](#creating-a-virtual-environment))
3. Install requirements `pip install -r requirements.txt`
4. `python app.py`

</details>

---

</details>

<details><summary>Mac/Linux</summary>

We currently don't have instructions or releases for mac or linux, we will in future releases. It does run on ubuntu and mac as members of the team use it, but we want to test the instructions before releasing them. However, you can still run both the frontend and backend individually by following the windows version with slight alterations to the commands.

</details>

---

## Development Info

<details><summary>Stack</summary>

- GUI
- Electron + Vite + React (JavaScript)
- Backend
- Flask + Pymavlink (Python)

</details>

<details><summary>Running tests</summary>

## Backend

For running Python tests, first make sure you're in the `radio` directory. By default the tests will attempt to connect to the simulator running within Docker. To run the tests simply run `pytest`. To use a physical device connected to your computer, you can use `pytest --fc -s` and a prompt will display to select the correct COM port for the device.

</details>

<details><summary>SITL with Docker</summary>

To run the SITL simulator within Docker, first pull the docker image with `docker pull kushmakkapati/ardupilot_sitl`. Once pulled, you can start the container with `docker run -it --rm -p 5760:5760 kushmakkapati/ardupilot_sitl`. This will expose port 5760 for you to connect to over TCP on 127.0.0.1 (the connection string is `tcp:127.0.0.1:5760`). You can also open up port 5763 for running other scripts on the simulator whilst a GCS is connected.

By default the vehicle type will be ArduCopter, however you can tell the SITL to use a custom vehicle by providing it as a named argument at the end of the run command, e.g. `docker run -it --rm -p 5760:5760 kushmakkapati/ardupilot_sitl VEHICLE=ArduPlane`. You can also set the starting LAT, LON, ALT and DIR using the named arguments.

If you want to upload a custom parameter file or custom mission waypoint to the simulator then you must have a `custom_params.parm` or `mission.txt` file in your current working directory. These can then be uploaded to the simulator on run by specifying a bind mount with `-v .:/sitl_setup/custom` (note that the destination path must be `sitl_setup/custom`). E.g. `docker run -it --rm -p 5760:5760 -p 5763:5763 -v .:/sitl_setup/custom ardupilot_sitl VEHICLE=ArduPlane`.

Note: Steps to push an updated image to docker hub:

```plaintext
docker build . -t ardupilot_sitl
docker tag ardupilot_sitl:latest kushmakkapati/ardupilot_sitl:latest
docker push kushmakkapati/ardupilot_sitl:latest
```

</details>

<details><summary>Python</summary>

## Version

We are going to be using **python 3.11.x** so please install that on your computer from [Python's website](https://www.python.org/downloads/). Please try to use a virtual environment when programming, if you don't know how to do this please message me (Julian)! Name the folder either "env" or "venv" so its in the .gitignore as we don't want to be uploading that to github.

## Code Style

We will be using `ruff` as the code style for python, please look at the documentation found [here](https://docs.astral.sh/ruff/). When pushing code we have an action to check if it is in the correct code style, if it is not in the correct style it will fail the run and you will need to fix it by running `python -m ruff format .` in your virtual environment (or something `ruff format .` works on different systems); this should automatically reformat everything so you can push it again!

</details>

<details><summary>Pre-Commit</summary>

When cloning the repo for the first time, please install `pre-commit`. This can be done with a simple `pip install pre-commit` and then `pre-commit install`. Our pre-commit hooks will run every time you try to push something, if any of the checks fail then you will not be able to push that commit and receive an error message, often the files will be fixed but not staged, so make sure to re-stage and retry the with pushing commit.

</details>

<details><summary>Packaging</summary>

## Backend

From within the `radio` folder run `pyinstaller --paths .\venv\Lib\site-packages\ --add-data=".\venv\Lib\site-packages\pymavlink\message_definitions\:message_definitions" --add-data=".\venv\Lib\site-packages\pymavlink\:pymavlink" --hidden-import pymavlink --hidden-import engineio.async_drivers.threading .\app.py -n fgcs_backend`. This will create an exe and folder within the `dist/fgcs_backend/` folder.

On Mac:
From within the `radio` folder run
`pyinstaller --paths ./venv/lib/python3.11/site-packages/ --add-data="./venv/lib/python*/site-packages/pymavlink/message_definitions:message_definitions" --add-data="./venv/lib/python*/site-packages/pymavlink:pymavlink" --hidden-import pymavlink --hidden-import engineio.async_drivers.threading --windowed --name fgcs_backend ./app.py`.
This will create the `dist/fgcs_backend.app/` folder.

## Frontend

After compiling the backend, place the contents of `radio/dist/fgcs_backend` into a folder in `gcs/extras`. Then from within the `gcs` folder run `yarn build`.

On Mac:
After compiling the backend, copy the `radio/dist/fgcs_backend.app` directory and move it to `gcs/extras`. Then from within the `gcs` folder run `yarn build`. Install from the .dmg file.

</details>

### Configuration

<details><summary>Changing Ports</summary>

We have an `.env` file located in `gcs/.env`. To change the host and port for the backend, please edit `VITE_BACKEND_URL`.
## 📚 Documentation

> Note: The default host and port is `http://127.0.0.1:4237`.
For developers and advanced users, some technical documentation is available:

</details>
- **[📖 Complete Documentation Index](docs/README.md)** - Overview of all documentation
- **[🚀 Development Guide](docs/DEVELOPMENT_GUIDE.md)** - Complete setup, testing, and best practices
- **[🔧 Backend Architecture](docs/BACKEND_ARCHITECTURE.md)** - Controllers and system design
- **[🖥️ Frontend Architecture](docs/FRONTEND_ARCHITECTURE.md)** - Project structure, Redux state management

---

Expand Down
7 changes: 5 additions & 2 deletions building/windows/build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ if (Test-Path ..\gcs\extras) {
Move-Item .\dist\fgcs_backend\ ..\gcs\extras

Write-Output "Building frontend"
Set-Location ../gcs
Set-Location ../gcs/data
python generate_param_definitions.py
Write-Output "Generated param definitions"

Set-Location ../
yarn
yarn version --new-version $Version --no-git-tag-version --no-commit-hooks
yarn build
Expand All @@ -40,4 +44,3 @@ Write-Output "Going back to building\windows from gcs"
Set-Location ..\building\windows

Write-Output "Done!"

135 changes: 135 additions & 0 deletions docs/BACKEND_ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# Backend Architecture Guide

The FGCS backend is a Python Flask application that handles communication between the frontend and the drone via the MAVLink protocol.

## Overview

```bash
Frontend (React/Electron)
↕ (Socket.IO/HTTP)
Backend (Flask/Socket.IO)
↕ (MAVLink/Serial/TCP)
Drone (ArduPilot/PX4)
```

## Core Components

### 1. Main Application (`app.py`)

- Flask application with Socket.IO integration
- Handles drone connection management
- Routes HTTP requests and Socket.IO events
- Manages application state and logging

### 2. Drone Class (`app/drone.py`)

The central class that manages drone communication and state:

```python
class Drone:
def __init__(self, port, baud=57600, wireless=False, ...):
# Core MAVLink connection
self.master = mavutil.mavlink_connection(...)

# Controller instances
self.paramsController = ParamsController(self)
self.armController = ArmController(self)
self.flightModesController = FlightModesController(self)
# ... other controllers
```

**Key Responsibilities:**

- Establish and maintain MAVLink connection
- Initialize all controller instances
- Handle data stream management
- Process incoming MAVLink messages
- Manage connection state and error handling

### 3. Data Streams

The drone class sets up various MAVLink data streams to receive telemetry:

```python
DATASTREAM_RATES_WIRED = {
mavutil.mavlink.MAV_DATA_STREAM_RAW_SENSORS: 2,
mavutil.mavlink.MAV_DATA_STREAM_EXTENDED_STATUS: 2,
mavutil.mavlink.MAV_DATA_STREAM_RC_CHANNELS: 2,
mavutil.mavlink.MAV_DATA_STREAM_POSITION: 3,
mavutil.mavlink.MAV_DATA_STREAM_EXTRA1: 10,
mavutil.mavlink.MAV_DATA_STREAM_EXTRA2: 10,
mavutil.mavlink.MAV_DATA_STREAM_EXTRA3: 2,
}
```

**Stream Types and Messages:**

- **RAW_SENSORS**: IMU data, pressure sensors
- **EXTENDED_STATUS**: System status, GPS, mission info
- **RC_CHANNELS**: Radio control inputs and servo outputs
- **POSITION**: Local and global position data
- **EXTRA1**: Attitude data (roll, pitch, yaw)
- **EXTRA2**: VFR HUD data (airspeed, groundspeed, etc.)
- **EXTRA3**: Battery status, system time, vibration

### 4. The Command Lock

The command lock is a thread synchronization mechanism (typically implemented using Python’s `threading.Lock`) that ensures only one command is sent to the drone at a time. This is crucial because the MAVLink protocol and ArduPilot expect commands to be sent and acknowledged sequentially. Sending multiple commands simultaneously can lead to race conditions, command collisions, or unexpected drone behavior.

**In practice:**
Whenever a controller needs to send a command to the drone (e.g., change mode, set a parameter, arm/disarm), it acquires the command lock, sends the command, waits for a response, and then releases the lock. This guarantees orderly and reliable communication with the drone. This can be achieved either manually by acquiring and releasing the lock, or by using the `sendingCommandLock` decorator.

**Note:**
If you acquire a lock inside a function which then uses another function which acquires the lock as well this will lead to the program halting. Ensure that the lock is released before any other function acquires it.

## Controllers Architecture

Controllers encapsulate specific drone functionality and handle related MAVLink commands:

### Parameters Controller (`paramsController.py`)

Manages drone parameter operations and provides methods for:

- Retrieving individual parameters
- Fetching all parameters from drone
- Setting single or multiple parameter values

### Arm Controller (`armController.py`)

Handles drone arming and disarming operations.

### Flight Modes Controller (`flightModesController.py`)

Provides functionality for setting flight modes, retrieving current mode, and listing available modes for the connected vehicle type.

### Mission Controller (`missionController.py`)

Handles mission planning and execution with features including:

- Mission upload/download with progress tracking
- Saving and importing missions to/from files
- Starting, stopping and restarting missions

### Motor Test Controller (`motorTestController.py`)

Provides motor testing capabilities.

### Navigation Controller (`navController.py`)

Handles guided mode navigation including:

- Waypoint navigation commands
- Takeoff and landing commands
- Home position related operations

### RC Controller (`rcController.py`)

Manages radio control inputs and channel mapping including.

### Frame Controller (`frameController.py`)

Handles vehicle frame type detection.

### Gripper Controller (`gripperController.py`)

Controls a gripper/payload release mechanism.
Loading
Loading