Skip to content

Introduction

This document provides an overview of the Ground Station system, detailing its components, functionalities, and how it integrates with other systems. The Ground Station is a critical part of the overall architecture, enabling communication with the telemetry server and facilitating the management of boat operations. Link to PyQt documentation: PyQt Documentation

Components Overview

Note about exceptions in the groundstation

Exceptions thrown in the groundstation do not behave like exceptions thrown in regular Python code. The reason for the exception will not be printed to the console and must be handled in order for the application to continue running. If you have code that you suspect may throw an exception, please enclose it in a try/except block and handle the exception appropriately (ask Barrett if you are unsure how to handle it).

All data that persists between runs of the Ground Station and its assets are stored in the app_data directory. I have tried to split up the code in the Ground Station into logical components to make it easier to understand and modify. The Ground Station is divided into the following main components:

base components

constants.py

We will begin with the constants.py file, which defines objects that are used throughout the entire codebase. In addition, this file checks for the presence of configuration files and assets that are essential for the Ground Station's operation. The code in this file is the first to be run and is run before the actual application is registered with PyQt. If you have code that will cause the application to crash or not behave correctly when missing assets, it is best to place that code in this file. Additionally, code in this file cannot access properties of the application object created by PyQt. The icons used in the Ground Station are defined in this file, but are not able to be used until the application is registered with PyQt, which happens in the main.py file.

thread_classes.py

The thread_classes.py file contains classes that are used to manage threads within the Ground Station application. I decided to places these classes in a seperate file since they don't really feel like widgets, but may be hard to find in the constants.py file if you didn't know they were there. These classes are essential for handling asynchronous operations and ensuring that the Ground Station can perform tasks without blocking the main application thread. I highly recommend reading the code in this file to understand how threads are managed and how they interact with the rest of the application. Online resources on threads and how they work in PyQt may also be helpful if you are trying to work with the code in this file.

main.py

This file is the main entry point for the Ground Station application. The code in this file is pretty self-explanatory and will probably only need to be modified if you are adding entirely new functionality to the Ground Station. If you need to know the specifics of what happens in this file, I recommend reading the code itself.

syntax_highlighters

base_highlighter.py

The base_highlighter.py file contains the base class for syntax highlighters used in the Ground Station. I wanted to take the QSyntaxHighlighter class and write some methods that would make it easier to write syntax highlighters for whatever I needed. The methods in this class are meant to guide the implementation of syntax highlighters so that time is not wasted trying to understand each individual method in the QSyntaxHighlighter class. The methods in this class are not meant to be used directly, but rather to be overridden in subclasses that implement specific syntax highlighting functionality. If you are writing a syntax highlighter for the Ground Station, you should start by subclassing this class and implementing the methods that are relevant to your use case.

json.py

The json.py file contains a syntax highlighter specifically designed for JSON files. It extends the base highlighter class and implements the necessary methods to provide syntax highlighting for JSON syntax. This highlighter is used to enhance the readability of JSON files within the Ground Station, making it easier to work with configuration files and other JSON data.

console.py

The console.py file contains a syntax highlighter for the console output within the Ground Station. This highlighter is designed to improve the readability of console messages, making it easier to identify important information, warnings, and errors. It uses the base highlighter class to implement specific highlighting rules for console output, ensuring that messages are displayed in a clear and organized manner.

widgets

groundstation.py

This is the magnum opus of the Ground Station application. It was the first widget I wrote for the Ground Station and is first widget that you see when you open the application. It serves as the main interface for interacting with the Ground Station and allows users to add and remove waypoints and buoys, view telemetry data, and shows popups that that are used to modify the state of the Ground Station. This file also uses some of the classes in the thread_classes.py file to manage asynchronous operations, such as fetching telemetry data and updating the interface without blocking the main thread. If you are looking to understand how the Ground Station works, this is a great place to start.

This widget is used to create 'windows' that make it easier to modify text in the Ground Station. It takes highligther (such as one of the syntax highlighters defined in the syntax_highlighters directory), some initial text, a tab width, and font size as arguments and uses a QSignal to return the modified text when the user clicks the "Save" button or closes the window. This widget is used in the Ground Station to edit buoy data, some data types in the autopilot parameter editor, and the telemetry data 'limits' that are used to determine when a warning or error should be displayed.

console_output.py

This widget is used to display the console output of the Ground Station. It uses a QPlainTextEdit to display the output and the console.py syntax highlighter to provide syntax highlighting for the output. It also contains the code that makes it possible to have the console output displayed in the terminal and in the Ground Station at the same time. This is done by using a QThread and some redirection of the standard output streams to capture the console output and display it in the widget.

map_widget

This directory contains the code that is used to make displaying the waypoints and buoys on a interactive map possible. It contains a Go server that is used to manage the transfer of waypoints and buoys between the Python code and the JavaScript code running in the HTML file in this directory. The Go server exposes a get and set endpoint that modifies an array containing the latitude and longitude of the waypoints and buoys which takes the form:

[
    [1.0, 1.0],
    [2.0, 2.0],
    [3.0, 3.0],
    ...
]

Where latitude is the first element of each array and longitude is the second element. The JavaScript code in this directory uses the Leaflet library to display the waypoints and buoys on a map.

camera_widget

This widget is used to display the camera feed from the boat. It uses a QThread from the thread_classes.py file to fetch the camera feed and then runs some JavaScript code to display the feed in a HTML file. We are using an HTML file to display the camera feed because of its abibility to natively show base64 encoded images, saving us the trouble of having to do the decoding ourselves. The widget has buttons that allow you to start and stop the camera feed in order to save bandwidth and processing power when the camera feed is not needed.

autopilot_param_editor

This widget is used to manage the autopilot parameters of the boat. It provides a scrollable table that features a search bar to filter the parameters by name. The widget uses a json file located in the app_data/autopilot_params/params_default.jsonc file to manage the default configuration for each of the parameters. This json file takes the form:

{
    "param_name": {
        "type": "example_type",
        "default": "example_default_value",
        "description": "This is a description of the parameter.",
    },
    ...
}

Where param_name is the name of the parameter, type is the type of the parameter, default is the default value of the parameter, and description is a description of the parameter. The parameter type must be one of the built-in types (i.e int, float, str, bool, list, dict, or set) in order for the parameter to be usable in the widget. Additional types should be defined in the constants.py file and properly handled in the code for the widget.

When the application is started, it copies the contents of the params_default.jsonc file to a new file in the autopilot_param_editor directory called params_temp.json (all comments are stripped). This file is used to store the current values of the parameters and is updated whenever the user modifies a parameter in the widget. When the user clicks the "Save" button, a dialog allows the user to save the current parameters to a new file. If no file is selected, the parameters are not saved and the application continues on.

In addition, the widget allows you to send, recieve, and reset each parameter to the value defined in the app_data/autopilot_params/params_default.jsonc file.