174 lines
9.4 KiB
Markdown
174 lines
9.4 KiB
Markdown
# 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.
|
||
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.
|
||
Focus loss, stale telemetry, disconnect, and disarm clear commanded inputs
|
||
without easing. This is a neutral-command request, **not proof that motors have
|
||
stopped** when the communication link is unavailable.
|
||
|
||
In addition, transmitted pilot demands have a small 4% input deadband and a
|
||
0.25-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.
|
||
|
||
## Engage, confirmation, and interruption handling
|
||
|
||
The compact window opens at 1100 × 650. Empty sidebar areas drag the window;
|
||
the STL viewer, buttons, and sliders are separate interactive regions. Output
|
||
limit and Motor setup sit below the main controls. Recent activity retains the
|
||
last three events, oldest at the top and newest emphasized at the bottom.
|
||
Routine hold instructions are kept in tooltips;
|
||
pending confirmations and safety warnings still appear above the controls.
|
||
The full-width text control displays `engage` / `disengage`; disengage sends the
|
||
same immediate disarm request described below.
|
||
|
||
- Hold **ENGAGE** for 1.4 seconds (or hold F2). Early release, leaving the
|
||
button, interrupted touch, and focus loss cancel the hold without sending arm.
|
||
- **ENGAGING…** means a request is pending. A send result or accepted command
|
||
ACK alone does not prove that the vehicle armed: a fresh autopilot heartbeat
|
||
reporting the requested state is the final confirmation. A heartbeat can
|
||
confirm state even if the ACK packet was lost.
|
||
- **DISARM** is one tap or F3, with no long hold. While confirmation is pending,
|
||
**DISARMING…** stays red and driving is disabled. Disarm can also interrupt a
|
||
pending Engage request. No forced-arm/disarm bypass is used.
|
||
- Confirmation timeout: 5 seconds in the backend (6-second UI fallback).
|
||
Rejection and timeout remain visible. Late heartbeat updates still determine
|
||
the displayed state; the UI never substitutes an animation state for telemetry.
|
||
- A heartbeat older than 3 seconds is stale. A missing bridge reply after
|
||
1.5 seconds shows **STATE UNKNOWN**, preserving the last-known state without
|
||
claiming disarm. Battery readings older than 5 seconds are marked stale.
|
||
- The web frontend renews an input lease locally every 250 ms. If it stops for
|
||
1 second, the worker clears stored demands and sends neutral at its configured
|
||
control rate. This adds no MAVLink stream or parameter download. Focus loss
|
||
clears both captured touch pointers and queued input; reconnect never replays
|
||
the old joystick position. Normal release still eases back to center.
|
||
- Link loss cannot deliver a stop over a broken tether. Verify the vehicle's
|
||
own failsafe and use independent physical power isolation for bench tests.
|
||
|
||
### Regression checks (no hardware)
|
||
|
||
Run from this project folder after setting up the Python environment:
|
||
|
||
```powershell
|
||
.venv\Scripts\python.exe -m unittest discover -s tests -v
|
||
node --test tests/control_ui.test.cjs
|
||
```
|
||
|
||
Node is needed only for the frontend regression tests, not to run the app.
|
||
The tests use mocked transport and synthetic pointer events, including independent
|
||
joystick/vertical pointers. Validate physical multi-touch on the intended screen
|
||
and FC failsafes on a restrained, propeller-free setup before powered operation.
|