SUB Control
A deliberately small, low-bandwidth MAVLink controller for bench-testing an ArduSub vehicle over a USB serial connection. It sends no parameter-list request and no telemetry-stream request.
The desktop window uses a local HTML/CSS/JavaScript interface rendered by the Windows WebView. Python remains the only launcher and owns the MAVLink worker, arming, logging, output limiting, and parameter writes. It does not run a web server, open a browser tab, or require an internet connection.
The WebView is frameless and uses the compact title bar drawn by the interface.
The vehicle rail includes a local STL viewer: choose Load STL to start with
an orthographic top-view silhouette, then drag to orbit or use the mouse wheel
to zoom. A cached STL copy is stored locally under the ignored runtime/
directory so the model can be restored on the next launch.
STEP/STP CAD solids must first be tessellated/exported as STL because the
embedded renderer intentionally does not include a full CAD kernel.
Safety first
- Remove propellers for initial tests and restrain the vehicle.
- Verify the ArduSub frame and
SERVOx_FUNCTION, motor direction, ESC range, leak/failsafe, and emergency-stop arrangements before arming. - The application starts disarmed and limits pilot demand to 20% by default. Once armed, control movement is sent directly with no additional gate.
- Closing or disconnecting sends neutral controls and a disarm request, but a physical power cutoff is still required.
The controls are pilot-demand axes, not direct PWM values. ArduSub performs
the frame mixing and generates the configured ESC outputs. For ArduSub,
MANUAL_CONTROL.z = 500 is neutral vertical thrust.
Run on Windows
- Install Python 3.11 or newer. A virtual environment installs packages, but it does not install Python itself.
- Open PowerShell in this folder and run
./run.ps1(or right-click it and choose Run with PowerShell). - Select the autopilot's COM port, then click Connect. Baud and control-rate
settings are under the small
•••link button (normally 57600 baud / 20 Hz). - Confirm
ArduSuband a live heartbeat are shown. - Click Set MANUAL, then ARM only when the bench is safe.
- Move the controls. Once armed, no additional enable button is needed.
run.ps1 automatically creates a private .venv on the first run, installs
the versions declared in requirements.txt, and starts SUB Control. Later runs
reuse the same environment and update missing dependencies when necessary.
The .venv directory is intentionally ignored by Git: virtual environments
contain machine-specific executables and can be recreated from
requirements.txt.
Repository layout
The Gitea repository is named argo. SUB Control is a normal directory inside
that repository containing this application. A Gitea Project is a planning
board for issues and tasks; source code is not attached to a Project board.
Git tracks the folder automatically because its files are committed on the
repository's main branch.
Keyboard controls for SimpleROV-3: W/S forward/back, A/D yaw left/right, Q/E alternative yaw control, and R/F rise/dive. Releasing movement keys eases their controls back to neutral.
Three-thruster limitation
The common ArduSub SimpleROV-3 arrangement controls forward, yaw, and depth.
It cannot independently control lateral, roll, or pitch. Accordingly, the main
pad is mapped to forward/yaw, while the vertical slider controls depth thrust.
Link behavior
- MAVLink GCS heartbeat: 1 Hz
MANUAL_CONTROL: selectable 10 or 20 Hz (default 20 Hz). Lower rates are intentionally excluded because they make short return ramps become abrupt steps at the flight controller.- No full parameter download
- On connection, inherited bulk telemetry streams are stopped. Only
SYS_STATUSat 1 Hz andSERVO_OUTPUT_RAW/RC_CHANNELSat 2 Hz are requested, in addition to the normal heartbeat and event-driven status text. - Arm/disarm uses
MAV_CMD_COMPONENT_ARM_DISARMand displaysCOMMAND_ACK - Link health is based on received autopilot heartbeats
- Battery voltage is read from
SYS_STATUSat 1 Hz and shown as pack voltage, estimated per-cell voltage, and a voltage-only percentage. Cell count, capacity, C rating, full/empty cell voltages, and warning percentage are configurable and saved locally inbattery_settings.json. Capacity consumed cannot be measured without a current sensor. - Servo configuration scans
SERVO1_FUNCTIONthroughSERVO16_FUNCTIONand ArduSub'sMOT_1_DIRECTIONthroughMOT_12_DIRECTIONone at a time, waiting for each response and retrying missed replies. A selected output can be assigned to Motor 1–12 or set unassigned. Motor direction is toggled with the correspondingMOT_n_DIRECTIONvalue while disarmed;SERVOx_REVERSEDis intentionally not used for Motor functions. It never downloads the full parameter list. The diagnostic scan also readsSERVO1–SERVO3MIN/TRIM/MAX and ArduSub's joystick gain values into the local session log; these values remain read-only in the application. - Every session creates a local text log under
logs/, including operator actions, outgoing manual-control values and commands, acknowledgements, status text, and all received MAVLink messages. This does not use ArduPilot's onboard logger or add any link traffic.
The car-style virtual joystick maps only to forward/reverse and continuous differential turning; it never sends lateral motion. The joystick and vertical slider ease back to center over 400 ms after mouse/key release, so neither can be left commanding motion. Heartbeat loss, disconnect, and disarm remain immediate safety stops and are intentionally not eased.
In addition, transmitted pilot demands have a small 4% input deadband and a 0.8-second full-range slew limit. This makes both acceleration and deceleration arrive at the flight controller as a sequence of stable intermediate values. Forward and yaw are normalized as a SimpleROV-3 motor pair before the output limit is applied, preventing their mixer contributions from adding beyond the selected horizontal limit.
ArduPilot may ignore manual input when MAV_GCS_SYSID does not match this
application's system ID (default 255), or when MAV_OPTIONS does not allow
MAVLink input. Those parameters must already be correctly configured.