Introduction¶

PAGS (Python-async Ground Station) is a ground station software suite for MAVLink-based autonomous vehicles, including Ardupilot based vehicles.
It is inspired by the MAVProxy GCS, and features a similar module-based architecture.
The “async” comes from PAGS being entirely based on the asyncio library in Python. This allows for efficient asynchonous processing between the modules and links.
It is designed from the ground up as modular and multi-vehicle.
General Features:
- Can run in a terminal or GUI
- Can be used as a GCS, or as the foundation of your own GCS
- Compatible with Python 3.5+ on Windows or Linux
- Any number of vehicles can be connected to a single PAGS instance
- Low number of dependencies
- Module can be quickly and easily developed for additional functionality
- Full CI testing with high test coverage
Note
PAGS is still an early work in progress. Many features expected of a GCS are not currently present.
Installation¶
PaGS is compatible with Python 3.6 - 3.7 on both Linux or Windows.
At the command line:
git clone https://github.com/stephendade/PaGS.git
cd ./PaGS
pip3 install -U -r requirements.txt -r requirements_gui.txt
python3 setup.py build install --user
Under Linux, libSDL may also need to be installed:
sudo apt-get install git libsdl2-2.0-0
If using a headless (no screen) system, omit the -r requirements_gui.txt
section in the above.
If installing for development, the test dependencies can be installed by:
pip3 install -U -r ./tests/requirements_test.txt
Usage¶
PaGS can be used in two ways: either as a standalone GCS or as part of a larger application.
Standalone¶
To run standalone:
pags.py
The following commandline arguments can be used:
--source=tcpclient:127.0.0.1:5760:1:0
Connection in format connectiontype:connectionstr:sys:comp--mav=2
Mavlink Version (1 or 2)--dialect=ardupilotmega
MAVLink dialect--source-system=255
MAVLink source system for this GCS--source-component=0
MAVLink source component for this GCS--multi
--nogui
Disable usage of a GUI--sitl=n
Connect to Ardupilot SITL instance, wheren
is the instance ID (ID is required).
(Default values of each argument are shown above).
For the connection sources (--source
), the connection types can be:
tcpclient
with the connectionstr beingremoteip:port
tcpserver
with the connectionstr beinglocalip:port
udpserver
with the connectionstr beinglocalip:port
udpclient
with the connectionstr beingremoteip:port
serial
with the connectionstr beingserialport:baud
, iesource=serial:COM17:115200:1:0
The sys
is the System ID of the remote vehicle and the comp
is the component ID of the vehicle.
These are typically 1 and 0 respectively for Ardupilot with the default parameters.
Multiple --source
can be used. Each system ID is assumed to be a different vehicle. Thus multiple connections
to a single vehicle can be used.
In the alternate case, where multiple vehicles (each with a different System ID) are on a single connection,
simply repeat the --source
with the same connectionstr and the relevent (differerent) source ID’s.
If using the --sitl
options, multiple connections to different APM SITL instances can be used. For example, to connect to 3 SITL instances: --sitl=0 --sitl=1 --sitl=2
If neither the --source
and --sitl
arguments are used, PaGS will first look for any USB-connected flight controllers and attempt to connect at a buad rate of 115200, otherwise it will connect to a UDP server on localhost, port 14550.
As an example:
- Vehicle 1 (System ID 1) and Vehicle 3 (System ID) are both on serial port COM17, baud 57600
- Vehicle 2 (System ID 22) is on tcpserver 192.168.0.1:14500 and a secondary link on udpclient 192.168.0.10:14600
Gives:
pags.py --source=serial:COM17:57600:1:0 --source=serial:COM17:57600:3:0 --source=tcpserver:192.168.0.1:14500:22:0 -source=udpclient:192.168.0.10:14600:22:0
As a Library¶
Modules¶
Modules are plugins for PaGS that can read and write packets to vehicles.
For example, a module might read the system status onto a GUI, or command the vehicle to change mode.
Modules can be loaded by module load xxx
, where xx is the module library path.
The current set of loaded modules can be listed via module list
.
Terminal Module¶
module load terminalModule
Summary¶
This module provides a terminal-based UI for displaying vehicle status and sending commands to vehicles.
Each vehicle has it’s own tab and command interpreter.
Use ctrl+right and ctrl+left to navigate through the vehicle tabs.
The prompt show the vehicle’s current mode and arming status. “D” for disarmed and “A” for armed.

Commands¶
N/A
Mode Module¶
module load modeModule
Commands¶
mode list
. List the valid modes for the vehicle
mode do <mode>
. Switch to mode <mode>. The <mode> is not case sensitive.
mode arm
. Send an arming command to the vehicle
mode disarm
. Send a disarm command to the vehicle.
mode reboot
. Reboot the Flight Controller.
Terminal Module¶
module load paramModule
Summary¶
This module provides commands an a GUI for reading and writing vehicle parameters.
Note that the parameters are not checked for correctness before being sent to the vehicle.

Commands¶
param download
. Download (or refresh) the parameters from the vehicle. Required before any other parameters commands can be used.
param show <param>
. Show a parameter’s current value. Wildcards can be used, for example param show RC1_*
param set <param>
. Set a new value for a parameter.
param load <filename>
. Load the parameters from file.
param save <filename>
. Save the parameters to file.
GUI¶
<screenshot>
The GUI will automatically populate after a param download
has been performed. Each vehicle will have it’s own tab in the window.
The text field at the top can be used to filter parameters.
When a parameter is edited, it will be highlighted until written to the vehicle.
Status Module¶
module load statusModule
Summary¶
The module displays the current sub-system status of the Vehicle, both in the console and in a GUI

In the GUI, the following colours are used for the subsystem status:
- Grey: System not present
- Black: Present, not enabled
- Red: Present, enabled, not healthy
- Green: Present, enabled, healthy
Commands¶
status status
. Show the current status of the vehicle.
Development¶
Installing¶
See the Installation section
Testing and CI¶
All tests are in the ./tests
folder.
Windows users will need the com0com software.
Linux users will need socat installed via sudo apt install socat`
Tests can be run via:
python3 setup.py build install --user
py.test --log-level DEBUG
The CI uses Appveyor to run a build matrix of Windows/Linux and Python 3.5/3.6/3.7. So 6 runs total.
Coveralls is used to check the test coverage. This can be run manually via the ./scripts/run_pytest_coverage.sh
script
All changes should be compliant with the PEP8 standard. This is checked as part of the CI processes.
The PEP8 checks can be run via the ./scripts/flake8check.sh
script.
Modules¶
Modules must be placed in the ./PaGS/PaGS/modules
folder
There is a template available at ./PaGS/PaGS/modules/blankModule.py
, or see below:
"""
<Module Description>
"""
class Module():
"""
<Module Description>
"""
def __init__(self, loop, txClbk, vehListClk, vehObjClk, cmdProcessClk, prntr, isGUI):
"""
Called by PaGS when a module is loaded 'module load xxx'
"""
# Call this to send out a MAVLink packet
self.txCallback = txClbk
# Call this to get a list of current vehicles
self.vehListCallback = vehListClk
# Call this to get a Vehicle object by name
self.vehObjCallback = vehObjClk
# Call this to print to the console(s)
self.printer = prntr
# true if we're running in a GUI environment
self.isGUI = isGUI
# The short name of the module.
self.shortName = ""
# A dict of user commands. Key is the string name, value is the function to run
self.commandDict = {}
def addVehicle(self, name: str):
"""
Called by PaGS when a new vehicle is added
"""
pass
def incomingPacket(self, vehname: str, pkt):
"""
Called by PaGS when a decoded valid MAVLink packet is recieved from a vehicle
"""
pass
def removeVehicle(self, name: str):
"""
Called by PaGS when a vehicle is removed
"""
pass
def closeModule(self):
"""
Called by PaGS when the module is shut down
"""
pass
If modules have a GUI, they should respect the isGUI parameter. They should use the wxPython (with wxAsync) GUI library for consistency. For saving/loading window position and sizes, use the wxPersisent class: <example of both>
Modules are free to set/get attributes in the vehicle classes, but they should not assume they are present.
Any commonly used vehicle attributes should be managed from within the vehicle class - parameters, waypoints, etc.
PAGS has a common cache/user setting directory at <>. It can be accessed from the <> attribute.
Each vehicle has it’s own directory <accessed via the .. attribute>, where per vehicle files go - logs, parameter and waypoint files.
Each module should, where practical, test it’s functionality within the unit test suite.