503 lines
29 KiB
Markdown
503 lines
29 KiB
Markdown
# Argonaut 3 — UI Design Specification
|
||
**Version:** 2.0
|
||
**Date:** 9 July 2026
|
||
**Status:** ⚠ **SAFETY-CRITICAL FINDING — W1 does not see the vehicle.** With the flight controller
|
||
unreachable, W1 displayed GREEN / "Systems nominal". Every widget reflects the **RPi5 autonomy
|
||
stack**, not the vehicle. In AUV mode W1 is the pre-dive GO/NO-GO gate (`health_role: gate`) — as
|
||
built it would pass a dive with a dead FC. See §W1 and DIR-7 / DIR-12. **OPEN.**
|
||
|
||
**This session:** `rov_api` `/mode` endpoints (GET/POST) built, deployed, tested (`9109439`).
|
||
**W8 Mode Indicator built and validated live — render + data** (`87000e6`) — the first widget
|
||
beyond W0/W1 confirmed with real data. Chronic "widgets show no data" fault root-caused:
|
||
`cockpit_bridge` had no `respawn`, so a boot-time race left the data-lake feed permanently dead
|
||
(`c099c00`); fixed and verified across a cold stack restart.
|
||
|
||
**Prior status (v1.9):** FastAPI backend (`rov_api`) core deployed and verified on RPi5:8081. W3 backend
|
||
(`/abort`) now LIVE and confirmed end-to-end (button path → failsafe_monitor FSM). Mission
|
||
start/stop endpoints available. W3 widget label decision "RETURN TO SAFE" stands; widget code
|
||
update + `FASTAPI_HOST` config still pending. W6 committed as `w6_altitude.json`. Stage 2b
|
||
endpoints (return budget, backup, mission upload) deferred. Production data path confirmed as
|
||
cockpit_bridge WebSocket.
|
||
|
||
---
|
||
|
||
## Version History
|
||
|
||
| Version | Date | Changes |
|
||
|---|---|---|
|
||
| 2.0 | 9 Jul 2026 | **⚠ SAFETY-CRITICAL: W1 does not see the vehicle.** With the FC unreachable, W1 showed GREEN / "Systems nominal". `failsafe_monitor` does not gate on FC connectivity; absence of data is being read as good data. In AUV mode W1 is the pre-dive GO/NO-GO gate — as built it would pass a dive with a dead flight controller. W1 spec rewritten with required fixes; status line promoted from debug affordance to operational element carrying cause text. See DIR-7, DIR-12. **OPEN.** **W8 Mode Indicator added** — read-only active-profile display, colour-coded by base mode; validated live (render + data), the first widget beyond W0/W1 so confirmed (`87000e6`). Mode *switching* explicitly excluded from W8 (belongs to the setup wizard, `POST /mode`); ArduSub arm/vehicle mode excluded (Cockpit shows it natively). **Widget testing status corrected** — "renders" and "works" are now explicitly distinguished throughout: validated with live data = W0, W1, W8; render-only = W2–W6; not built = W7. Prior wording conflated the two. **`rov_api` `/mode` endpoints** (GET/POST) built, deployed, tested incl. rejection path (`9109439`). **Chronic "widgets show no data" root-caused:** `cockpit_bridge` was launched but had no `respawn`; a boot-time race left it permanently dead, killing the whole data-lake feed. Fixed (`c099c00`), verified across a cold stack restart. This — not the widgets — was why W1 "sometimes" worked. |
|
||
| 1.9 | July 2026 | FastAPI backend (`rov_api`) core deployed on RPi5:8081 (commit 66a18ef). W3 backend `/abort` now LIVE — verified end-to-end (POST /abort → Bool /rov/mission/abort → failsafe_monitor flag_manual_abort → FSM NORMAL→HOLD_AND_RECOVER). Mission endpoints `/mission/start` and `/mission/stop` available and tested. `/health` returns live mission/recording/failsafe. W6 committed to Gitea as `w6_altitude.json` (underscore convention); probe widget removed. W3 widget code update (label + FASTAPI_HOST) still pending. Stage 2b deferred: `/return_budget` (W5), `/backup/*` (W7), `/mission/upload`. FastAPI runs as argonaut-api.service (manual-start). |
|
||
| 1.8 | July 2026 | W6 Altitude Widget built and deployed (`w6_altitude.json`). NO SONAR state confirmed — correct baseline with no Ping2. cockpit_bridge updated to 8 variables: `rov-recording` and `rov-altitude` added. W3 button label decided: "RETURN TO SAFE" (assessed vehicle return-to-safe per DIR-5, not emergency hard-stop; widget code update pending). Widget testing status clarified: W0 confirmed live, W1–W5 visual confirmed only, W7 not built. Production data path: cockpit_bridge WebSocket is confirmed production path — NAMED_VALUE bridge node not required. |
|
||
| 1.7 | June 2026 | W7 (Backup Due Notice) added to widget scope — operator-facing reminder that a device backup is due, with delay options. Depends on RPi5:8081 FastAPI backend. See W7 spec and DIR-11. |
|
||
| 1.6 | June 2026 | Cockpit v1.18.2 DIY widget API confirmed via probe widget. Full `window.cockpit` surface (17 keys) enumerated. Confirmed: `getDataLakeVariableData(id)` returns live value. W1–W5 can now be built. |
|
||
| 1.5 | June 2026 | Production data path confirmed as `cockpit_bridge` ROS2 node (port 9001, in rov_mission, commit 12b5161) — all 6 vars live in data lake as `external/rov-*`. W0 working with scroll fix. |
|
||
| 1.4 | May 2026 | Data injection architecture fully documented with confirmed working path (Generic WebSocket) and all failed approaches. Widget variable names corrected. |
|
||
| 1.3 | May 2026 | Cockpit native app confirmed required. JSON import format confirmed. CSS rules established. All 6 widgets complete and committed to Gitea. |
|
||
| 1.2 | May 2026 | Confirmed DIY widget approach, Data Lake Inspector as W0, build status added. |
|
||
| 1.1 | May 2026 | Added Mission Setup button widget. |
|
||
| 1.0 | May 2026 | Initial UI design specification. |
|
||
|
||
---
|
||
|
||
## 1. Approach — Cockpit DIY Widgets (Confirmed)
|
||
|
||
Widgets are Cockpit **DIY widgets** — JSON files containing `html`, `css`, `js`, and
|
||
`inheritCockpitStyles` fields, imported via the gear icon on a placed DIY widget panel.
|
||
|
||
> **Cockpit native desktop app v1.18.2 is required.**
|
||
> The BlueOS browser extension version is "Lite" and does not support DIY widgets.
|
||
> DIY widget support was added in v1.9.0.
|
||
> Generic WebSocket data injection was added in v1.18.0.
|
||
> Download: https://github.com/bluerobotics/cockpit/releases
|
||
|
||
### Import Format
|
||
|
||
Each widget is a `.json` file with this exact structure:
|
||
```json
|
||
{
|
||
"html": "...",
|
||
"css": "...",
|
||
"js": "...",
|
||
"inheritCockpitStyles": false
|
||
}
|
||
```
|
||
|
||
### CSS Rules — Hard Constraints (Do Not Break)
|
||
|
||
These were discovered through testing. Violating any of them crashes or corrupts
|
||
the Cockpit renderer:
|
||
|
||
| Rule | Reason |
|
||
|---|---|
|
||
| No `body {}` or `:root {}` blocks | Bleed into Cockpit's own styles — causes renderer crash |
|
||
| No `@keyframes` animations | Cause renderer instability |
|
||
| No unicode characters in JS strings | Use plain ASCII only (-- not —, ... not …) |
|
||
| No `position: fixed` elements | Use `display: block/none` toggling instead |
|
||
| No `async/await` | Use `.then()/.catch()` for all fetch calls |
|
||
| No global tag selectors (e.g. `div {}`) | Use ID and class selectors only, scoped to widget root |
|
||
|
||
### What DIY Widgets Can Do
|
||
|
||
| Capability | Mechanism |
|
||
|---|---|
|
||
| Read all variable metadata | `window.cockpit.getAllDataLakeVariablesInfo()` — returns array of {id, name, type, description} ONLY, not values |
|
||
| **Read a single live value** | **`window.cockpit.getDataLakeVariableData(variableId)` — CONFIRMED working in v1.18.2. Returns live numeric/string value. Use this in all widgets.** |
|
||
| Read single variable metadata | `window.cockpit.getDataLakeVariableInfo(variableId)` |
|
||
| Set a variable | `window.cockpit.setDataLakeVariableData(variableId, value)` — available (not tested) |
|
||
| Call external REST endpoints | `fetch()` with `.then()/.catch()` |
|
||
| Open a new browser tab | `window.open('URL', '_blank')` |
|
||
|
||
**NOT available in DIY widget scope (confirmed absent by probe):**
|
||
- `getDataLakeValue()` — undefined in v1.18.2
|
||
- `listenToDatalakeVariable()` — undefined (postMessage iframe External API only)
|
||
|
||
**Full window.cockpit surface (17 keys, confirmed v1.18.2):**
|
||
`dataLakeVariableData [object]`, `getDataLakeVariableData [function]`, `listenDataLakeVariable [function]`, `unlistenDataLakeVariable [function]`, `getAllDataLakeVariablesInfo [function]`, `getDataLakeVariableInfo [function]`, `setDataLakeVariableData [function]`, `createDataLakeVariable [function]`, `updateDataLakeVariableInfo [function]`, `deleteDataLakeVariable [function]`, `getDataLakeVariableLastUpdateTimestamp [function]`, `availableCockpitActions [object]`, `registerNewAction [function]`, `deleteAction [function]`, `registerActionCallback [function]`, `unregisterActionCallback [function]`, `executeActionCallback [function]`
|
||
|
||
---
|
||
|
||
## 2. Data Injection Architecture — CONFIRMED FACTS
|
||
|
||
### Production Path (Confirmed) — cockpit_bridge WebSocket
|
||
|
||
```
|
||
cockpit_bridge (ROS2 node on RPi5, rov_mission package, port 9001)
|
||
WebSocket server :9001
|
||
<-- Cockpit connects as client (Settings -> Generic WebSocket Connections)
|
||
--> Sends 'variable-name=value' text messages at 2Hz
|
||
--> Data lake key: external/{variable-name}
|
||
--> DIY widget reads: getDataLakeVariableData('external/{variable-name}')
|
||
```
|
||
|
||
**Message format:** Plain text, one variable per message:
|
||
```
|
||
variable-name=value
|
||
```
|
||
|
||
**Data lake key format:** `external/{variable-name}`
|
||
|
||
> CRITICAL: Cockpit normalises variable names when creating data lake IDs.
|
||
> Underscores become hyphens in the data lake ID.
|
||
> ALWAYS USE HYPHENS in WebSocket variable names.
|
||
|
||
**Cockpit one-time configuration:**
|
||
```
|
||
Cockpit -> Menu -> Settings -> Generic WebSocket Connections
|
||
Enter: ws://192.168.1.101:9001
|
||
Click: ADD CONNECTION
|
||
```
|
||
|
||
This configuration persists between Cockpit restarts.
|
||
|
||
### Failed Injection Approaches (Do Not Retry)
|
||
|
||
| Approach | Why it failed |
|
||
|---|---|
|
||
| HTTP POST to mavlink2rest /mavlink | Stored in REST only — not broadcast to Cockpit |
|
||
| UDP to MAVLink ports from external scripts | Does not route to mavlink2rest WebSocket |
|
||
| NAMED_VALUE with sysid=1, compid=1 | ArduSub detects heartbeat conflict — do not impersonate |
|
||
|
||
### Data Lake Variables (8 total, published by cockpit_bridge)
|
||
|
||
| Variable | Source topic | Notes |
|
||
|---|---|---|
|
||
| `external/rov-failsafe` | `/rov/failsafe` | 0=GREEN, 1=AMBER, 2=RED; -1=no data |
|
||
| `external/rov-depth` | `/rov/depth` | Metres (3 dp) |
|
||
| `external/rov-voltage` | `/mavros/battery` | Battery volts (2 dp) |
|
||
| `external/rov-heading` | `/mavros/mavros/compass_hdg` | Compass degrees (1 dp) |
|
||
| `external/rov-ms` | `/rov/mission/status` | 0=IDLE…4=ABORTED; -1=no data |
|
||
| `external/rov-mp` | `/rov/mission/status` | Progress 0-100% |
|
||
| `external/rov-recording` | `/rov/recording/active` | 1=recording, 0=not recording |
|
||
| `external/rov-altitude` | `/ping2/altitude` | Ping2 metres; -1.0=NO SONAR |
|
||
|
||
---
|
||
|
||
## 3. Widget Palette — Overview
|
||
|
||
Argonaut 3 uses Cockpit as the operator hub. **No more than 8 widgets are in scope.**
|
||
Cockpit is NOT a container for everything — only the specific operator-facing information
|
||
and controls needed for field operations.
|
||
|
||
| # | Widget | Purpose | Status |
|
||
|---|---|---|---|
|
||
| W0 | Data Lake Inspector | Dev diagnostic — shows all 706 data lake variables live | **Confirmed working** |
|
||
| W1 | System Health Indicator | DP-style GREEN/AMBER/RED traffic light showing mission capability | **Visual confirmed** |
|
||
| W2 | Mission Status | Mission state, progress, current task | **Visual confirmed** |
|
||
| W3 | Return To Safe Button | Operator-initiated vehicle return-to-safe (DIR-5) | **UI confirmed; backend LIVE; label update pending** |
|
||
| W4 | Mission Setup Button | Opens mission configuration page in new tab | **Visual confirmed** |
|
||
| W5 | Return Budget | Battery % and dynamic return budget with headroom | **Visual confirmed** |
|
||
| W6 | Altitude | Ping2 downward sonar altitude with colour-banded bar | **NO SONAR confirmed** |
|
||
| W7 | Backup Due Notice | Operator-aware backup reminder with delay control | **Not built** |
|
||
| W8 | Mode Indicator | Read-only active mode profile name, colour-coded by base mode | **Validated live (render + data)** |
|
||
|
||
> **Widget testing status (corrected 9 Jul 2026).** There is a hard distinction between a widget
|
||
> that **renders** and a widget that **works**. "Renders" means it draws in Cockpit. "Works" means
|
||
> it has been validated end-to-end with live data. Do not conflate them.
|
||
>
|
||
> - **Validated with live data:** W0, W1, **W8**.
|
||
> - **Render-confirmed only, never validated with data:** W2, W3, W4, W5, W6.
|
||
> - **Not built:** W7.
|
||
>
|
||
> W6 shows a correct NO SONAR state, which is its *no-data* state — that is not data validation.
|
||
> Full testing requires a live mission, FastAPI backend, and/or Ping2 hardware.
|
||
|
||
> **All widgets read the RPi5 autonomy stack, not the vehicle.** For vehicle state (FC present,
|
||
> armed/disarmed, board running) the operator currently must use BlueOS/Cockpit-native surfaces.
|
||
> This is a defect, not a design — see W1 below and DIR-12. In AUV mode there is no operator and
|
||
> no second tool, so the gate must become self-sufficient.
|
||
|
||
> **Widget consolidation:** Grant may consolidate W0–W7 into a single unified widget
|
||
> as development progresses and the full operational picture is clearer. Not yet designed.
|
||
|
||
---
|
||
|
||
## 4. Widget Specs
|
||
|
||
---
|
||
|
||
### W0 — Data Lake Inspector
|
||
**File:** `w0_data_lake_inspector.json`
|
||
**Status:** **Confirmed working** — 706/706 vars live.
|
||
**Purpose:** Dev diagnostic tool. Renders a scrollable table of all Cockpit data lake
|
||
variables with live values. Used to confirm data is reaching the data lake from
|
||
cockpit_bridge, MAVROS, and other sources.
|
||
**Data source:** `window.cockpit.getAllDataLakeVariablesInfo()` for enumeration,
|
||
`getDataLakeVariableData(id)` for values.
|
||
**Notes:** Production use is optional — this is a dev/debug tool, not an operational widget.
|
||
|
||
---
|
||
|
||
### W1 — System Health Indicator
|
||
**File:** `w1_system_health_indicator.json`
|
||
**Status:** **Validated with live data** (GREEN/RED observed). ⚠ **But the assessment behind it is
|
||
incomplete and unsafe — see below.**
|
||
**Purpose:** Primary mission-capability indicator. DP-style traffic light showing
|
||
whether the vehicle is ready to conduct a mission (GREEN), degraded but proceeding
|
||
(AMBER), or in a critical state (RED).
|
||
**Data lake variable:** `external/rov-failsafe` (0=GREEN, 1=AMBER, 2=RED; -1=no data)
|
||
|
||
**Mode-dependent role (`external/rov-health-role`):**
|
||
- **ROV (`advisory`, 0)** — display only; the pilot decides.
|
||
- **AUV (`gate`, 1)** — **pre-dive GO/NO-GO gate.** RED blocks mission start. Last human-visible
|
||
decision point before the vehicle goes dark.
|
||
|
||
**Behaviour:**
|
||
- GREEN: "Systems nominal" — all parameters within limits
|
||
- AMBER: Named degraded parameter — mission continues with reduced confidence
|
||
- RED: Critical failure — return-to-safe active
|
||
- Initial / no data: grey / loading state
|
||
|
||
> ⚠ **OPEN, SAFETY-CRITICAL (9 Jul 2026).** On 9 July, with the Pixhawk unreachable and BlueOS
|
||
> reporting "No board running", **W1 displayed GREEN / "Systems nominal"**.
|
||
>
|
||
> **Cause:** `failsafe_monitor` does not gate on flight-controller connectivity. It assesses the
|
||
> autonomy stack's own view of health. With no FC data arriving it has no *bad* data, so it reports
|
||
> nominal. Absence of data is being treated as good data.
|
||
>
|
||
> **Consequence:** in AUV mode (`health_role: gate`) W1 would pass a pre-dive gate with a dead
|
||
> flight controller — on a vehicle that will have no operator once submerged.
|
||
>
|
||
> **Required (not built):**
|
||
> 1. `failsafe_monitor` MUST subscribe to `/mavros/state` and assess FC connection + heartbeat age,
|
||
> driving AMBER/RED on comms loss. (This was in the node's *original* design intent —
|
||
> `comms_timeout_sec`, `comms_lost` — but is not effective in the implemented node.)
|
||
> 2. A monitor with no input MUST NOT report GREEN. "No data" and "good data" must be distinct
|
||
> states, distinctly displayed.
|
||
> 3. W1's status line MUST carry cause text — `"Vehicle Disconnected"`, `"Heartbeat Lost"`,
|
||
> `"No Board Running"`, `"Systems nominal"` — not a bare colour. The status line was previously
|
||
> treated as a debug affordance; it is promoted to an operational element.
|
||
> 4. Consider a pre-dive FD-headroom check on BlueOS `ardupilot_manager` (handover §15a) as part of
|
||
> the same gate — same question, different failure mode.
|
||
>
|
||
> See **DIR-7** (health MUSTs) and **DIR-12** (vehicle health ≠ autonomy health).
|
||
|
||
**Test required:** Confirm GREEN/AMBER/RED transitions by triggering failsafe monitor
|
||
state changes with live data. **Additionally: confirm RED on FC disconnect** once (1) above is built.
|
||
|
||
---
|
||
|
||
### W2 — Mission Status
|
||
**File:** `w2_mission_status.json`
|
||
**Status:** **Visual confirmed** — IDLE state and progress bar display correctly. Untested with live mission.
|
||
**Purpose:** Show current mission state (IDLE/RUNNING/PAUSED/COMPLETE/ABORTED) and
|
||
progress as a percentage progress bar.
|
||
**Data lake variables:**
|
||
- `external/rov-ms` (0=IDLE, 1=RUNNING, 2=PAUSED, 3=COMPLETE, 4=ABORTED; -1=no data)
|
||
- `external/rov-mp` (0-100 percent)
|
||
**Test required:** Start a mission with waypoints, observe state transitions and progress bar advancing.
|
||
|
||
---
|
||
|
||
### W3 — Return To Safe Button
|
||
**File:** `w3_abort_button.json`
|
||
**Status:** **UI confirmed** — confirm dialog, 10s auto-cancel countdown, clean network-error
|
||
handling. Label in widget code still reads "ABORT MISSION" — **update to "RETURN TO SAFE" pending.**
|
||
**Purpose:** Operator-initiated vehicle return-to-safe action (DIR-5). This is a
|
||
**vehicle-layer action** — it moves the vehicle. It is NOT the mission start/stop button.
|
||
**Button label:** "RETURN TO SAFE" (decided July 2026 per DIR-5)
|
||
- Not "ABORT MISSION" — that implies emergency hard-stop
|
||
- Not "STOP MISSION" — that is a mission-layer action (DIR-4), not vehicle layer
|
||
- "RETURN TO SAFE" correctly states what the vehicle does: follow breadcrumb path
|
||
back to the closest designated safe place
|
||
**Mechanism:** Confirm dialog (10s auto-dismiss) → `fetch()` POST to FastAPI `/abort`
|
||
**Config:** `FASTAPI_HOST` constant in JS must be set to `http://192.168.1.101:8081`
|
||
**Dependency:** FastAPI backend at RPi5:8081 — **LIVE** (commit 66a18ef). `/abort` verified
|
||
end-to-end server-side: POST → Bool `/rov/mission/abort` → failsafe_monitor FSM
|
||
NORMAL→HOLD_AND_RECOVER.
|
||
**Remaining:** update widget code label ("ABORT MISSION" → "RETURN TO SAFE") and set
|
||
`FASTAPI_HOST`, then test the full button→backend path from Cockpit.
|
||
|
||
---
|
||
|
||
### W4 — Mission Setup Button
|
||
**File:** `w4_mission_setup_button.json`
|
||
**Status:** **Visual confirmed** — cyan button renders, "Configure before diving" status shown.
|
||
Opens 404 until setup page exists.
|
||
**Purpose:** Open mission setup page in a new browser tab without leaving Cockpit.
|
||
**Behaviour:**
|
||
- IDLE: Full brightness, "Configure before diving" label — button enabled
|
||
- RUNNING/PAUSED: Dimmed — button disabled (mission already in progress)
|
||
**Config:** `SETUP_URL` constant in JS must be set to the FastAPI setup page URL
|
||
**Dependency:** FastAPI backend serving the setup page — not yet built.
|
||
**Test required:** Open setup page successfully with live FastAPI backend.
|
||
|
||
---
|
||
|
||
### W5 — Return Budget
|
||
**File:** `w5_battery_return_budget.json`
|
||
**Status:** **Visual confirmed** — battery % shows pending. Return budget pending
|
||
until `external/rov-return-budget` is published.
|
||
**Purpose:** Show battery percentage alongside dynamic return budget and headroom warning.
|
||
**Data lake variables:**
|
||
- `external/rov-voltage` — battery voltage from cockpit_bridge
|
||
- `external/rov-return-budget` — return budget % (not yet published by cockpit_bridge)
|
||
**Headroom thresholds:**
|
||
- Headroom < 15%: AMBER warning
|
||
- Headroom < 5%: RED critical
|
||
**Dependency:** FastAPI backend for return budget calculation; cockpit_bridge must be
|
||
updated to publish `external/rov-return-budget`.
|
||
**Test required:** Full test with live voltage and return budget data.
|
||
|
||
---
|
||
|
||
### W6 — Altitude
|
||
**File:** `w6_altitude.json`
|
||
**Status:** **Built and deployed** (July 2026). **NO SONAR** state confirmed — correct
|
||
baseline with no Ping2 connected. Full test hardware-gated on Ping2 sonar purchase.
|
||
**Purpose:** Display downward Ping2 sonar altitude above hull or seafloor with
|
||
colour-coded status and vertical bar gauge.
|
||
**Data lake variable:** `external/rov-altitude` (metres float; -1.0 = NO SONAR sentinel)
|
||
**Source topic:** `/ping2/altitude` (sensor_msgs/Range) — published by Ping2 driver node
|
||
(hardware-gated; driver not yet built)
|
||
**Colour thresholds:**
|
||
- GREEN (GOOD): > 1.5m
|
||
- AMBER (CAUTION): 0.5–1.5m
|
||
- RED (CRITICAL): < 0.5m
|
||
- GREY (NO SONAR): sentinel value -1.0 (no Ping2 connected or no echo)
|
||
**Bar scale:** Linear, 0m (bottom) to 5m (top). Values above 5m fill bar to 100%.
|
||
**No hardware default:** Shows "NO SONAR" when altitude value is ≤ -1.0 (sentinel).
|
||
The sentinel is published by `cockpit_bridge` when no `/ping2/altitude` messages have
|
||
been received — meaning no Ping2 driver is running.
|
||
**Notes:**
|
||
- `sensor_msgs/Range` field `range_max` (100m for Ping2) is treated as "no return"
|
||
and also maps to the -1.0 sentinel in cockpit_bridge.
|
||
- Widget layout uses a vertical bar to the left of the numeric readout. The bar background
|
||
shows faint colour zone tints at the threshold boundaries even when reading is live.
|
||
**Pending:** Ping2 ROS2 driver node (wraps ping-python library). Interface defined:
|
||
topic `/ping2/altitude`, type `sensor_msgs/Range`, field `range` in metres.
|
||
Write driver when Ping2 hardware arrives — cockpit_bridge and widget are ready.
|
||
|
||
---
|
||
|
||
### W7 — Backup Due Notice (ops-facing)
|
||
**File:** `w7_backup_due_notice.json` — **NOT YET BUILT**
|
||
**Status:** Scoped, not built. Depends on RPi5:8081 FastAPI backend (shared with W3/W4).
|
||
**Purpose:** Surface to the operator that a device backup is due, and let the operator
|
||
delay it, rather than allowing an unattended backup to start during operations.
|
||
See DIR-11 for intent.
|
||
|
||
**Why this exists:** The automated Pi backup system (built 30 Jun 2026) runs each Pi's
|
||
self-backup via root cron — RPi4 at 00:00, RPi5 at 00:30 — unattended, which is correct
|
||
for dev. In the field this is the wrong default: an SD image is a multi-GB `dd` stream
|
||
that must NOT begin mid-dive. The ops model inverts the dev model — the operator is made
|
||
aware a backup is due and chooses when it runs, with the option to delay.
|
||
|
||
**Behaviour:**
|
||
- Hidden/dormant when no backup is due.
|
||
- When a backup is due, show a small unobtrusive notice: which device(s), how overdue.
|
||
- Offer delay options (e.g. delay 1h / 4h / until end of session). Delay is operator-chosen, never automatic.
|
||
- "Run now" option only enabled when vehicle is not in a mission (ties to `external/rov-ms`).
|
||
|
||
**Data sources (planned):**
|
||
- `FastAPI /backup/status` — backup-due state and overdue age per device
|
||
- `external/rov-ms` — mission state (to gate "run now")
|
||
|
||
**Delay mechanism (planned):** operator selection POSTs to `FastAPI /backup/delay`
|
||
|
||
**Dependency:** FastAPI backend on RPi5:8081 — not yet built.
|
||
**Open / TBC with Grant:** exact delay options; whether "run now" is exposed in field;
|
||
whether notice appears for all operators or pilot-only.
|
||
|
||
---
|
||
|
||
### W8 — Mode Indicator
|
||
**File:** `w8_mode_indicator.json`
|
||
**Status:** **Validated live** — render + data confirmed 9 Jul 2026 (commit `87000e6`).
|
||
**Purpose:** Read-only indicator of the **active operating-mode profile**. Answers one question:
|
||
"what mode am I in?" Nothing else.
|
||
**Data lake variables:**
|
||
- `external/rov-mode` (string) — active profile name: `ROV`, `AUV`, or a saved hybrid name
|
||
- `external/rov-mode-base` (number) — 0 = ROV, 1 = AUV; anything else treated as hybrid
|
||
|
||
**Behaviour:**
|
||
- Displays the profile name large and prominent, under a small `MODE` header
|
||
- Colour-coded by base mode: **cyan `#38bdf8`** = ROV, **green `#00e5a0`** = AUV,
|
||
**amber `#f59e0b`** = hybrid / unrecognised base
|
||
- No-data state: `--` in grey `#484f58` with a `NO DATA` / `NO API` status line
|
||
- 2 Hz poll, matching `cockpit_bridge` broadcast rate
|
||
|
||
**Explicitly NOT in scope:**
|
||
- **Read-only.** W8 never writes to the data lake and never calls `rov_api`. **Mode switching lives
|
||
in the setup wizard** (`POST /mode`), not here. An indicator indicates.
|
||
- **Does not show ArduSub arm state or vehicle mode.** Cockpit's native UI already surfaces
|
||
ARMED/DISARMED and flight mode; duplicating it here would add clutter, not information.
|
||
|
||
> **Note (DIR-12):** W8 reads a resolved profile that originates from `mode_profiles.yaml` on the
|
||
> RPi5. It reflects **configuration**, not vehicle state — it would display `AUV` with the Pixhawk
|
||
> disconnected. This is correct for what W8 is, but it is another reason W1 must carry the vehicle
|
||
> health picture.
|
||
|
||
---
|
||
|
||
## 5. Widget File Locations
|
||
|
||
**Gitea repo:** `rov-autonomy/widgets/`
|
||
**Laptop local:** `C:\Users\grant\Desktop\Autonomous ROV System\rov-autonomy\widgets\`
|
||
|
||
> **Widget JSON → Gitea:** W6 widget JSON (`w6_altitude.json`) and any updated W0–W5
|
||
> files need to be re-imported from the laptop and pushed to Gitea. Do NOT overwrite
|
||
> from chat history — the laptop files are the source of truth.
|
||
|
||
---
|
||
|
||
## 6. Production Data Path — Confirmed
|
||
|
||
The production data path is **cockpit_bridge WebSocket** (confirmed working, commit 12b5161
|
||
onwards). The NAMED_VALUE bridge node previously considered is not required — the WebSocket
|
||
path has no 10-char name limit, simpler implementation, and is already deployed.
|
||
|
||
**NAMED_VALUE is not needed for production.** Do not build a NAMED_VALUE bridge node.
|
||
|
||
The one case where native ArduSub NAMED_VALUE messages matter is data that ArduSub
|
||
itself publishes (e.g. attitude data) — these flow automatically through mavlink2rest to
|
||
Cockpit's data lake without any bridge. Custom ROS2 data goes exclusively through
|
||
cockpit_bridge.
|
||
|
||
---
|
||
|
||
## 7. FastAPI Backend (`rov_api`)
|
||
|
||
Runs as `argonaut-api.service` on RPi5:8081 (manual-start in dev). **Core deployed and
|
||
verified end-to-end (commit 66a18ef).** Architecture: uvicorn/FastAPI in the main thread,
|
||
embedded rclpy node (`RovApiNode`) in a daemon background thread. CORS enabled for Cockpit.
|
||
|
||
### Endpoints
|
||
|
||
| Endpoint | Method | Action | Status |
|
||
|---|---|---|---|
|
||
| `/health` | GET | Returns mission state, recording active, failsafe state | DONE — verified |
|
||
| `/abort` | POST | W3 RETURN TO SAFE — publishes Bool to `/rov/mission/abort` (vehicle-layer, DIR-5) | DONE — verified end-to-end |
|
||
| `/mission/start` | POST | MissionCommand START (recording no-go gate enforced by mission_executor) | DONE — verified |
|
||
| `/mission/stop` | POST | MissionCommand ABORT | DONE — verified |
|
||
| `/mission/upload` | POST | Accepts YAML file, saves to RPi5 | DEFERRED — Stage 2b |
|
||
| `/return_budget` | GET | Returns current calculated return budget % (feeds W5) | DEFERRED — Stage 2b |
|
||
| `/backup/status` | GET | Per-device backup-due state and overdue age (feeds W7) | DEFERRED — Stage 2b (Option A) |
|
||
| `/backup/delay` | POST | Records operator-chosen backup delay window (feeds W7) | DEFERRED — Stage 2b (Option A) |
|
||
|
||
**W3 abort path detail:** `/abort` publishes `Bool(true)` to `/rov/mission/abort`. The
|
||
failsafe_monitor latches this as `flag_manual_abort` → FSM transitions NORMAL → HOLD_AND_RECOVER.
|
||
This is the DIR-5 vehicle-layer return-to-safe, NOT the mission ABORT service. Verified live.
|
||
|
||
**W3 widget wiring (pending):** update `w3_abort_button.json` label to "RETURN TO SAFE" and
|
||
set the `FASTAPI_HOST` constant to `http://192.168.1.101:8081`.
|
||
|
||
**Stage 2b design notes:**
|
||
- `/return_budget`: return budget calculation approach under discussion ("shortest path to
|
||
safety" concept). Without a DVL, position is unreliable — approach TBD with Grant.
|
||
- `/backup/*`: Option A chosen — server exposes read-only JSON backup status, RPi5 FastAPI
|
||
polls outbound (most secure: no credentials on the field-exposed RPi5, read-only, outbound only).
|
||
|
||
---
|
||
|
||
## 8. Development Sequence
|
||
|
||
| Order | Task | Status |
|
||
|---|---|---|
|
||
| 1 | Confirm Cockpit native app required | DONE |
|
||
| 2 | Confirm JSON import format | DONE |
|
||
| 3 | Establish CSS rules for DIY widgets | DONE |
|
||
| 4 | W0 Data Lake Inspector | DONE — confirmed working (706 vars live) |
|
||
| 5 | W1 System Health Indicator | DONE — visual confirmed; full test pending |
|
||
| 6 | W2 Mission Status | DONE — visual confirmed; full test pending |
|
||
| 7 | W3 Return To Safe Button | DONE (UI); backend LIVE; label + FASTAPI_HOST update pending |
|
||
| 8 | W4 Mission Setup Button | DONE — visual confirmed; needs setup page (Stage 2b/Phase 6) |
|
||
| 9 | W5 Return Budget | DONE — visual confirmed; needs /return_budget (Stage 2b) |
|
||
| 10 | Commit W0–W5 to Gitea | DONE — `rov-autonomy/widgets/` |
|
||
| 11 | cockpit_bridge node (WebSocket production path) | DONE — 8 variables, commits 12b5161, 5d75a9d, 0640353 |
|
||
| 12 | Probe widget (API discovery tool) | DONE and DELETED — dev tool only, not part of W0–W7 |
|
||
| 13 | W6 Altitude Widget | DONE — `w6_altitude.json`, committed (commit 785ec56) |
|
||
| 14 | FastAPI backend core (RPi5:8081) | DONE — commit 66a18ef, verified end-to-end |
|
||
| 15 | W3 label update to "RETURN TO SAFE" + FASTAPI_HOST | PENDING — widget code update required |
|
||
| 16 | W3 backend `/abort` POST confirmed end-to-end | DONE — FSM NORMAL→HOLD_AND_RECOVER verified |
|
||
| 17 | W5 `/return_budget` + `rov-return-budget` publishing | DEFERRED — Stage 2b (approach TBD) |
|
||
| 18 | W7 Backup Due Notice + FastAPI `/backup/*` | DEFERRED — Stage 2b (Option A) |
|
||
| 19 | W6 full end-to-end test | HARDWARE-GATED — requires Ping2 sonar (Phase 3 purchase) |
|
||
| 20 | W2 full test with live mission | READY — backend available; needs loaded plan + `POST /mission/start` |
|
||
| 21 | Mission Setup View (full page, W4 target) | Phase 6 / Stage 2b |
|
||
| 22 | Viewer Page | Phase 6 |
|
||
|
||
---
|
||
|
||
*End of document — Argonaut 3 UI Design v1.9 — July 2026*
|
||
*Next revision triggered by: FastAPI backend built, W3 label updated, W7 built, Ping2 purchased.*
|