Files
argo/README.md
T
2026-08-27 18:24:22 +02:00

174 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.
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.