# 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. ![SUB Control interface](docs/sub-control-interface.png) 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. Binary and ASCII STL faces are preserved in full; large assemblies are not rendered by skipping triangles. Imports are limited to 30 MB to keep startup and interactive orbiting responsive. ## 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 1. Install Python 3.11 or newer. A virtual environment installs packages, but it does not install Python itself. 2. Open PowerShell in this folder and run `./run.ps1` (or right-click it and choose **Run with PowerShell**). 3. 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). 4. Confirm `ArduSub` and a live heartbeat are shown. 5. Click **Set MANUAL**, then **ARM** only when the bench is safe. 6. 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_STATUS` at 1 Hz and `SERVO_OUTPUT_RAW` / `RC_CHANNELS` at 2 Hz are requested, in addition to the normal heartbeat and event-driven status text. - Arm/disarm uses `MAV_CMD_COMPONENT_ARM_DISARM` and displays `COMMAND_ACK` - Link health is based on received autopilot heartbeats - Battery voltage is read from `SYS_STATUS` at 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 in `battery_settings.json`. Capacity consumed cannot be measured without a current sensor. - Servo configuration scans `SERVO1_FUNCTION` through `SERVO16_FUNCTION` and ArduSub's `MOT_1_DIRECTION` through `MOT_12_DIRECTION` one 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 corresponding `MOT_n_DIRECTION` value while disarmed; `SERVOx_REVERSED` is intentionally not used for Motor functions. It never downloads the full parameter list. The diagnostic scan also reads `SERVO1`–`SERVO3` MIN/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.