Build Argo V2 control mappings and telemetry dashboard
Add configurable Xbox motion and action bindings, frame-aware six-axis MAVLink controls, sensor logging, camera viewing and recording, and a faster startup path. Synchronize both app copies and document companion hardware setup and verification limits.
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
# V2 verification — 22 October 2026
|
||||
|
||||
## Passing checks
|
||||
|
||||
- 41 Python tests: vehicle-state confirmation, control leases/watchdogs, six-axis packet values, unsupported firmware/frame gating, endpoint handling, telemetry conversion/staleness, persisted names/profiles, recording chunks, and relay acknowledgement.
|
||||
- `node tests/controller_v2.cjs`: synthetic Xbox triggers, B/A direction, opposing input cancellation, six axes, custom buttons, limits, invalid/missing inputs, migration, and actions.
|
||||
- `node tests/controller_input.cjs`: existing stick conditioning and console parser checks.
|
||||
- Python compilation, JavaScript syntax checks, and `git diff --check`.
|
||||
|
||||
No tests opened a real COM port or armed a physical vehicle.
|
||||
|
||||
## Rendered browser checks
|
||||
|
||||
Used the supported local in-app browser with the real app assets in Demo Mode:
|
||||
|
||||
- Mapping dialog: three-axis and six-axis presets, saving, reopening after a full page reload, and retained LB/RB roll bindings.
|
||||
- Vehicle settings: saved BlueROV1 six-thruster preview, independent accessory relay selectors, and consistent FC/demo status.
|
||||
- Drive: all six command controls at 1024×768, 960×580 (the native window minimum), and 700×572; no overlap with the output toolbar.
|
||||
- Active-output list: six rows for the six-thruster preview, with scrolling and reversal buttons. General frames disable the SimpleROV-3-specific independent-scale mode.
|
||||
- Engagement: held F2 in Demo Mode, inspected rendered **engaging**, then **disengaging** and their settled states. Both words are spelled correctly, centered, and have no trailing dots.
|
||||
- Dashboard: camera-off state, active simulated inspection view, missing/offline readings, explicit Demo labeling, sensor values and video controls at desktop and compact sizes.
|
||||
- Recording: started/stopped a canvas preview recording; the browser produced a 1,386,065-byte WebM file.
|
||||
- Accessories: demo lights toggle, camera power toggle, and viewing stops after demo power-off.
|
||||
|
||||
Reduced-motion CSS is included. The connected browser offers viewport testing but no media-preference emulation, so a rendered reduced-motion override was not verified.
|
||||
|
||||
## Existing harness limitation
|
||||
|
||||
The older `tests/control_ui.test.cjs` fake-DOM harness is not passing. It reports 23 failures on the saved pre-V2 checkpoint and 21 on V2. Most fail before app initialization because the harness lacks `ResizeObserver`; it also has obsolete markup/animation assertions and omits browser dependencies. It is not counted as a passing check. Actual browser checks above establish the rendered behavior of this implementation.
|
||||
|
||||
## Startup measurement
|
||||
|
||||
Three fresh-process worker-module imports on this laptop:
|
||||
|
||||
| Build | Samples | Median |
|
||||
| --- | --- | --- |
|
||||
| Pre-V2 checkpoint | 781.8 / 616.3 / 655.3 ms | 655.3 ms |
|
||||
| V2 | 402.8 / 362.4 / 399.1 ms | 399.1 ms |
|
||||
|
||||
This measures the module import, not total app startup. The launcher also avoids pip on subsequent launches when requirements have not changed, and starts the web interface directly.
|
||||
|
||||
## Physical verification still required
|
||||
|
||||
Real Xbox hardware, live six-axis FC motor allocation, live sensor calibration, WHEP video from a Raspberry Pi, native WebView full-video recording, physical relay outputs, and tether/underwater behavior were not verified. The browser recording and native chunk-writing path were checked separately. BlueOS native camera discovery/signaling is not integrated; this release uses an explicit WHEP, HTTP video, or MJPEG URL.
|
||||
@@ -0,0 +1,127 @@
|
||||
# Argo V2
|
||||
|
||||
V2 separates controller mapping, vehicle motion, ArduSub motor allocation, and camera transport. The pre-V2 app is preserved in commit `5e91c28` on `main`; development is on `v2`. A portable Git bundle was also saved locally. The checkpoint is also uploaded as `checkpoint/pre-v2-20261022`.
|
||||
|
||||
## Try it
|
||||
|
||||
1. Run `run.ps1`, select **Demo Mode**, and connect.
|
||||
2. Open **Vehicle**, select a **Preview frame**, and save. This changes the demo, never the connected FC's `FRAME_TYPE`.
|
||||
3. Open **Mapping**, choose **Triggers · 3** or **Six axes**, and save.
|
||||
4. Open **Dashboard** and press **Start** to see the simulated inspection camera. **Record** produces a WebM clip. The camera badge and sensor status identify demo data.
|
||||
|
||||
No physical port is opened in Demo Mode. Real TCP and UDP endpoints now connect to MAVLink instead of silently entering the demo.
|
||||
|
||||
## Xbox controls
|
||||
|
||||
| Motion | Triggers · 3 | Six axes |
|
||||
| --- | --- | --- |
|
||||
| Forward / back | RT / LT | RT / LT |
|
||||
| Rise / dive | B / A | B / A |
|
||||
| Turn | Left stick X | Left stick X |
|
||||
| Sideways | Unassigned | Right stick X |
|
||||
| Pitch | Unassigned | Left stick Y |
|
||||
| Roll | Unassigned | RB / LB |
|
||||
| Lights | X | X |
|
||||
| View stream | Y | Y |
|
||||
| Record | View | View |
|
||||
|
||||
Each motion has separate negative and positive bindings. Either direction can use a stick half, an analog trigger, a D-pad direction, or a button. Opposite commands cancel. Each motion has a limit; the profile also has dead zone and exponential response. The reverse arrow swaps its bindings. The **Buttons** disclosure configures optional accessory and media actions. Buttons do not arm the ROV.
|
||||
|
||||
Profiles are stored by controller ID in `controller_profiles.json`; **Xbox · offline** supplies a default before connecting a controller. Browser preview uses local storage. Existing stick mappings are migrated. Configuration is locked while armed or while the FC state is uncertain. Controls must return to neutral after input mode changes, reconnects, focus changes, or interruption. Accessory buttons also have to be released before they can trigger again.
|
||||
|
||||
Keyboard movement remains W/S, A/D (or Q/E), R/F. Additional axes use J/L for strafe, I/K for pitch, U/O for roll. The extra on-screen sliders return to center when released. F2 retains the 0.6-second engage hold; F3 requests disarm.
|
||||
|
||||
## Six thrusters and six axes
|
||||
|
||||
Your proposed arrangement can provide full control when the paired thrusters have useful moment arms:
|
||||
|
||||
| Pair | Shared thrust | Differential thrust |
|
||||
| --- | --- | --- |
|
||||
| Port / starboard, pointing forward | Surge | Yaw |
|
||||
| Front / rear, pointing vertically | Heave | Pitch |
|
||||
| Top / bottom, pointing sideways | Sway | Roll |
|
||||
|
||||
Translation uses the pair in the same direction; rotation uses opposite directions. Thruster directions, lever arms, balance and saturation still determine the result. The allocation matrix, whose columns are force direction and its moment `r × f`, must have rank six. Motor count alone does not establish this.
|
||||
|
||||
V2 sends body-motion demands to the FC. The autopilot owns its mixer and stabilization. Select/configure a firmware frame that matches the physical vehicle before using it. The app reads `FRAME_TYPE`; it does not infer a mixer from connected outputs or write a new frame automatically. Your orthogonal-pair design may require a custom firmware mixer if no stock frame matches its geometry.
|
||||
|
||||
| ArduSub frame | Motors | Available motion |
|
||||
| --- | --- | --- |
|
||||
| SimpleROV-3 (4) | 3 | Forward, vertical, yaw |
|
||||
| SimpleROV-4 (5) | 4 | Forward, vertical, yaw, roll |
|
||||
| SimpleROV-5 (6) | 5 | Forward, lateral, vertical, yaw, roll |
|
||||
| BlueROV1 (0) | 6 | All six axes |
|
||||
| Vectored (1) | 6 | All except pitch |
|
||||
| Vectored 6DOF (2, 3) | 8 | All six axes |
|
||||
|
||||
The verified six-axis wire mapping is ArduSub's `MANUAL_CONTROL`: X forward, Y lateral, Z vertical (500 neutral), R yaw, S pitch, T roll. Some generic joystick documentation describes S/T differently; this implementation follows ArduSub source. Firmware version is requested at connection; pitch/roll remain unavailable until compatible firmware is identified. ArduSub 4.5 uses S/T as ±400 PWM offsets; the current 4.8 development implementation scales normalized S/T. These encodings have automated checks; physical behavior is unverified.
|
||||
|
||||
The shared output limit applies to all motion axes. Full-frame demands use a conservative shared envelope before the FC mixer. This is an input-demand limit, not a calibrated thrust or electrical-current limit. The earlier independent motor-scale reconstruction is specific to SimpleROV-3 and is unavailable on other frames; applying it to a general mixer would be incorrect. Motor names, assignments, and direction controls remain available for active outputs.
|
||||
|
||||
References: [ArduSub frame configurations](https://ardupilot.org/sub/docs/sub-frames.html), [ArduSub 4.5 joystick source](https://github.com/ArduPilot/ardupilot/blob/Sub-4.5/ArduSub/joystick.cpp), [current joystick source](https://github.com/ArduPilot/ardupilot/blob/master/ArduSub/joystick.cpp), [Cockpit mapping and vehicle-version support](https://blueos.cloud/cockpit/docs/latest/usage/advanced/).
|
||||
|
||||
## Companion computer and tether
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
PC[Argo V2 on Windows] <-- Ethernet --> TOP[Topside media converter]
|
||||
TOP <-- Fibre tether --> ROV[Onboard media converter]
|
||||
ROV <-- Ethernet --> PI[Raspberry Pi / BlueOS]
|
||||
PI <-- USB or UART / MAVLink --> FC[ArduSub FC]
|
||||
CAM[USB or CSI camera] --> PI
|
||||
SENSOR[Pressure and power sensors] --> FC
|
||||
FC --> ESC[ESCs / thrusters]
|
||||
```
|
||||
|
||||
This is a proposed architecture, not installed hardware. Use a compatible Ethernet-to-fibre interface at each end, with optics, cable, terminations and housings selected for the tether length and environment. Fibre carries the data link; onboard power or a separate power path is still required. Ethernet lets telemetry and compressed video share a network while remaining separate application streams.
|
||||
|
||||
BlueOS is the researched companion option. It routes the FC's MAVLink traffic and manages cameras on supported Raspberry Pi hardware. In BlueOS, configure a MAVLink UDP output to the topside computer's tether-interface IP on port 14550. In Argo, choose **Network · UDP 14550**, or enter an explicit endpoint in Link settings. The listener uses `udpin:0.0.0.0:14550`; choose an interface-specific address with a custom endpoint if needed. The PC and Pi must be reachable on the same tether network.
|
||||
|
||||
Video uses an independent browser media connection. This release accepts **WebRTC · WHEP**, a browser-playable **HTTP video** URL, or **MJPEG**. It does not directly decode RTSP or raw UDP H.264. BlueOS's camera service has its own signaling interface, so entering its normal web-dashboard address as a WHEP URL will not work. Use a compatible WHEP endpoint, such as MediaMTX connected to the Pi camera or an RTSP source. Integrating BlueOS's native camera discovery/signaling is a separate follow-up.
|
||||
|
||||
Example MediaMTX path for a supported Pi camera:
|
||||
|
||||
```yaml
|
||||
paths:
|
||||
cam:
|
||||
source: rpiCamera
|
||||
```
|
||||
|
||||
With the server configured on the tether network, a typical WHEP endpoint is `http://<pi-address>:8889/cam/whep`. Verify it against your MediaMTX configuration. The browser needs CORS permission for the local Argo origin, and the negotiated WebRTC media ports must be reachable. Use a browser-compatible codec. No firewall, authentication, or origin policy is changed automatically by Argo.
|
||||
|
||||
**Start/Stop** controls viewing. **Camera power** is a separate optional relay action. **Record** records the incoming browser video; desktop clips are written incrementally to `runtime/recordings/`, and browser-preview clips download as WebM. MJPEG playback has no video recording control. For recordings that must survive tether loss, configure recording on the Pi as well.
|
||||
|
||||
References: [BlueOS companion hardware](https://blueos.cloud/docs/latest/integrations/hardware/required/onboard-computer/), [tether overview](https://blueos.cloud/docs/latest/integrations/hardware/required/tether/), [BlueOS endpoints and video services](https://blueos.cloud/docs/latest/usage/advanced/), [MediaMTX Pi cameras](https://mediamtx.org/docs/static-sources/raspberry-pi-cameras), [browser playback](https://mediamtx.org/docs/read/web-browsers).
|
||||
|
||||
## Sensors and electricity
|
||||
|
||||
The dashboard displays FC telemetry only when its group is fresh. Missing or stale values show a dash. Demo values are explicitly marked.
|
||||
|
||||
| Reading | Source | Units |
|
||||
| --- | --- | --- |
|
||||
| Pitch, roll, heading and angular rates | ATTITUDE | degrees, degrees/s |
|
||||
| Depth estimate relative to surface/home | GLOBAL_POSITION_INT.relative_alt | m, positive down |
|
||||
| Acceleration, gyroscope, magnetic field | SCALED_IMU | m/s², rad/s, gauss |
|
||||
| External pressure / temperature | SCALED_PRESSURE2 | hPa, °C |
|
||||
| Battery voltage, current and charge | SYS_STATUS / battery 0 BATTERY_STATUS | V, A, mAh |
|
||||
|
||||
Depth needs a correctly configured and calibrated external pressure sensor. Raw accelerometer values include gravity; they are not speed or a gravity-compensated acceleration estimate. Heading is FC-estimated yaw, not a separately read compass bearing.
|
||||
|
||||
Current is measured in **amps (A)** at the present moment. Power is **watts (W) = V × A**. Consumption is charge integrated over time, displayed as **mAh**; it is not amps per second. Use a correctly sized, calibrated voltage/current power monitor connected to the FC. Voltage alone cannot measure current. The app prefers reported consumption and otherwise integrates fresh current as a session estimate; source information is in Battery settings. A voltage update does not make an old current reading fresh.
|
||||
|
||||
**Log data** writes received normalized sensor values to `logs/sensors_<timestamp>.csv`. Existing raw MAVLink session logs remain in `logs/`. Rates for attitude, depth, IMU and pressure are independently configurable. Begin with low rates on RS-485; use a higher-bandwidth tether for video and increased telemetry.
|
||||
|
||||
Lights and camera power require configured, separate FC relay outputs. Configure relay assignments on the FC, then select their zero-based relay numbers in **Vehicle**. Buttons wait for command acknowledgement and expose timeout/rejection status. An accepted command confirms FC acceptance, not measured physical illumination or camera power.
|
||||
|
||||
Reference: [ArduSub battery monitor calibration](https://ardupilot.org/sub/docs/common-power-module-configuration-in-mission-planner.html), [MAVLink message definitions](https://mavlink.io/en/messages/common.html).
|
||||
|
||||
## Performance and verification
|
||||
|
||||
- The launcher only installs dependencies when the requirements fingerprint changes.
|
||||
- The production path launches `web_ui.py` directly. The old Tk frontend is loaded lazily from `legacy_ui.py`.
|
||||
- The asset server is threaded. Video frames stay in the browser's media pipeline.
|
||||
- Network MAVLink skips the redundant packet-leading heartbeat needed by the existing serial modules.
|
||||
- V2 controller input has one command ramp in the worker, avoiding the previous additional browser smoothing delay.
|
||||
- V2 controller-profile and station files are validated and replaced atomically. Existing input sequence, stale-bridge and heartbeat watchdogs cover all six motion axes.
|
||||
|
||||
Automated checks use synthetic gamepads, mock MAVLink transports, temporary configuration files and telemetry fixtures. Browser checks use Demo Mode and the actual rendered app. No live vehicle has been armed or commanded during development. Real controller hardware, Pi streaming, FC accessories, sensor calibration and water performance still need physical verification.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
Reference in New Issue
Block a user