Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
006bbf5
Add normalized diagnostics contract for ground station UI.
khuzaymahbinharis-jpg Jun 6, 2026
0c48fa5
Add mock diagnostics source with normal and fault demo modes.
khuzaymahbinharis-jpg Jun 6, 2026
58a7694
Add dark engineering dashboard theme and status colors.
khuzaymahbinharis-jpg Jun 6, 2026
7e6f30d
Add PySide6 main window for ground station monitoring dashboard.
khuzaymahbinharis-jpg Jun 6, 2026
4887781
Add app entry point, dependencies, and prototype documentation.
khuzaymahbinharis-jpg Jun 6, 2026
1295e1c
Document languages and frameworks used by the ground station UI.
khuzaymahbinharis-jpg Jun 6, 2026
0671fe8
Add waybionic_rviz_plugins ROS 2 package scaffold.
khuzaymahbinharis-jpg Jun 6, 2026
4b781f7
Add normalized diagnostics contract and mock data source.
khuzaymahbinharis-jpg Jun 6, 2026
abd8231
Add RViz2 diagnostics panel plugin for engineer monitoring.
khuzaymahbinharis-jpg Jun 6, 2026
fff8fd2
Add doctor and engineer RViz layouts with launch files.
khuzaymahbinharis-jpg Jun 6, 2026
80f9f05
Document RViz ground station setup, run steps, and live integration.
khuzaymahbinharis-jpg Jun 6, 2026
c972b34
Archive standalone PySide6 prototype folder after RViz2 pivot.
khuzaymahbinharis-jpg Jun 6, 2026
1bf970b
Decouple Annin/AR4 from core waybionic_rviz_plugins launch path.
khuzaymahbinharis-jpg Jun 13, 2026
e9a0e65
Add mock/live diagnostics source switching for the engineer panel.
khuzaymahbinharis-jpg Jun 13, 2026
1eeaf9a
Add SurgeonCameraPanel placeholder for doctor/surgeon camera layout.
khuzaymahbinharis-jpg Jun 13, 2026
9992aca
Document generic launch flow, mock/live diagnostics, and review notes.
khuzaymahbinharis-jpg Jun 13, 2026
aa50ab9
Add PR review screenshots for engineer and surgeon views.
khuzaymahbinharis-jpg Jun 13, 2026
d47fee9
Note opened PR link in PR_NOTES.
khuzaymahbinharis-jpg Jun 13, 2026
773ae3b
Focus PR on RViz diagnostics only and add local test publisher.
khuzaymahbinharis-jpg Jun 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions ground_station_monitoring_ui_archived/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# WayBionic Ground Station Monitoring Interface (Archived)

> **Archived:** This standalone PySide6 prototype has been superseded by the RViz2-native ground station UI in `waybionic_rviz_plugins/`. Kept for reference only.

This folder contains a first desktop UI proof of concept for the WayBionic engineering and operations ground station. It is a standalone Python + PySide6/Qt dashboard focused on monitoring diagnostic health and live values.

The prototype uses locally generated mock diagnostic data immediately. It does not depend on robot hardware, sensors, ROS topics, PCBs, cameras, or the doctor/surgeon controller.

## Languages and Frameworks

This prototype is built as a standalone desktop app using:

- **Python 3**: core application language for the entry point, dashboard logic, mock diagnostics, and normalized diagnostic contract.
- **PySide6**: official Qt for Python bindings used to render the desktop UI.
- **Qt Widgets**: window layout, panels, tables, buttons, timers, and Qt Style Sheets for the dark engineering dashboard theme.

Current Python dependencies are listed in `requirements.txt`. The only required package today is `PySide6`.

This sprint does not use ROS 2, rclpy, or web frameworks in the UI layer. Future live integration is expected to add a backend diagnostics subscriber (for example via ROS 2), but the dashboard should continue consuming the same normalized `DiagnosticMessage` format rather than depending directly on ROS message types.

## Scope

This app is monitoring-only.

- It does not send motor commands.
- It does not participate in the real-time safety-critical control loop.
- It does not implement video streaming.
- It does not implement robot control or arm simulation.

The interface is intended to give operators and engineers an early ground station layout while the live robotics integrations are still being built.

## UI Regions

- Top bar: demo state controls, current NORMAL/FAULT state, title, and last-updated indicator.
- System Status: diagnostic source, future ROS 2 connection status, backend heartbeat, UI mode, and safety note.
- Telemetry + Live Values: compact diagnostic table for current readings.
- Current Alerts: derived from any diagnostic signal whose status is not `OK`.
- Surgeon Camera View: reserved placeholder; no video streaming in this sprint.
- Robot / Arm Visualization: reserved placeholder; monitoring-only for now.

## Install

From this folder:

```powershell
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -r requirements.txt
```

On Linux/macOS:

```bash
python -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
```

## Run

```powershell
python app.py
```

## Demo Modes

Use the top-left buttons to switch states:

- `Normal Demo`: all mock diagnostic signals report `OK`, and the alerts panel shows `No active alerts`.
- `Fault Demo`: board temperature reports a high-temperature `FAULT`, IMU heartbeat reports `STALE`, and alerts become visually urgent.

The dashboard refreshes roughly once per second and updates the telemetry table, alert panel, backend heartbeat, state indicator, and last-updated text from the current diagnostic source.

## Future ROS 2 Integration

The UI depends on normalized `DiagnosticMessage` objects, not on mock internals. A future `ROS2DiagnosticsSubscriber` should replace `MockDiagnosticsSource` and convert live ROS 2 diagnostics into the same normalized contract before the data reaches the UI.

See `docs/DIAGNOSTICS_CONTRACT.md` for the expected data shape and backend integration notes.
20 changes: 20 additions & 0 deletions ground_station_monitoring_ui_archived/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""Entry point for the WayBionic ground station monitoring prototype."""

from __future__ import annotations

import sys

from PySide6.QtWidgets import QApplication

from src.main_window import GroundStationMainWindow


def main() -> int:
app = QApplication(sys.argv)
window = GroundStationMainWindow()
window.show()
return app.exec()


if __name__ == "__main__":
raise SystemExit(main())
89 changes: 89 additions & 0 deletions ground_station_monitoring_ui_archived/docs/DIAGNOSTICS_CONTRACT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Diagnostics Contract

The ground station UI consumes normalized diagnostic messages. Mock data uses this contract today, and future ROS 2 data should be converted into the same shape before reaching the UI.

## Internal Format

```python
DiagnosticMessage:
signal_name: str
status: "OK" | "WARN" | "FAULT" | "STALE"
timestamp: str
value: float | str | None
unit: str | None
alert_message: str | None
```

## Fields

- `signal_name`: stable name of the monitored topic or signal, such as `board.temperature`, `motor.current`, `imu.roll`, `imu.pitch`, `imu.yaw`, or `imu.heartbeat`.
- `status`: current health state of the signal. It must map cleanly to `OK`, `WARN`, `FAULT`, or `STALE`.
- `timestamp`: time the diagnostic was generated or last updated. ISO-8601 UTC strings are preferred.
- `value`: current reading, if applicable.
- `unit`: unit for the value, such as `°C`, `A`, `deg`, `V`, or empty/null.
- `alert_message`: human-readable message shown in the alerts panel when status is not `OK`.

## Example Normal Diagnostics

```python
[
DiagnosticMessage("board.temperature", "OK", "2026-06-06T18:30:00.400000+00:00", 42, "°C", None),
DiagnosticMessage("motor.current", "OK", "2026-06-06T18:30:00.500000+00:00", 0.8, "A", None),
DiagnosticMessage("imu.roll", "OK", "2026-06-06T18:30:00.200000+00:00", 1.2, "deg", None),
DiagnosticMessage("imu.pitch", "OK", "2026-06-06T18:30:00.200000+00:00", -0.4, "deg", None),
DiagnosticMessage("imu.yaw", "OK", "2026-06-06T18:30:00.200000+00:00", 12.9, "deg", None),
]
```

## Example Fault Diagnostics

```python
[
DiagnosticMessage(
"board.temperature",
"FAULT",
"2026-06-06T18:30:00.200000+00:00",
82,
"°C",
"High temperature detected",
),
DiagnosticMessage("motor.current", "OK", "2026-06-06T18:30:00.500000+00:00", 0.8, "A", None),
DiagnosticMessage("imu.roll", "OK", "2026-06-06T18:30:00.200000+00:00", 1.2, "deg", None),
DiagnosticMessage("imu.pitch", "OK", "2026-06-06T18:30:00.200000+00:00", -0.4, "deg", None),
DiagnosticMessage("imu.yaw", "OK", "2026-06-06T18:30:00.200000+00:00", 12.9, "deg", None),
DiagnosticMessage(
"imu.heartbeat",
"STALE",
"2026-06-06T18:29:55.200000+00:00",
None,
None,
"Sensor timeout",
),
]
```

## Future ROS 2 Integration

The current flow is:

```text
MockDiagnosticsSource -> normalized DiagnosticMessage objects -> UI
```

The future flow should be:

```text
ROS2DiagnosticsSubscriber -> normalized DiagnosticMessage objects -> same UI
```

The preferred future topic is `/diagnostics`. The backend may publish diagnostics using ROS 2 diagnostic-style messages, such as diagnostic array/status messages, or another agreed format.

Whatever live ROS 2 source is used, it should be converted into the normalized `DiagnosticMessage` format before reaching the UI. The UI should not directly depend on ROS message internals.

## Integration Note For Korede / Backend

Please publish each monitored signal with a stable signal name, status level, timestamp, current value if applicable, unit, and alert message if applicable.

The UI expects statuses to map cleanly to `OK`, `WARN`, `FAULT`, or `STALE`. Faults and stale signals should generate visible alerts.

The UI can initially be tested using mock messages, then connected to live ROS 2 diagnostics once available.
1 change: 1 addition & 0 deletions ground_station_monitoring_ui_archived/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
PySide6
1 change: 1 addition & 0 deletions ground_station_monitoring_ui_archived/src/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""WayBionic ground station monitoring prototype package."""
48 changes: 48 additions & 0 deletions ground_station_monitoring_ui_archived/src/diagnostics_contract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"""Normalized diagnostics contract used by the monitoring UI.

The UI consumes these objects only. A future ROS 2 subscriber should convert
live diagnostics into this shape before handing them to the dashboard.
"""

from __future__ import annotations

from dataclasses import dataclass
from datetime import datetime, timedelta, timezone
from typing import Literal


DiagnosticStatus = Literal["OK", "WARN", "FAULT", "STALE"]


@dataclass(frozen=True)
class DiagnosticMessage:
signal_name: str
status: DiagnosticStatus
timestamp: str
value: float | str | None
unit: str | None
alert_message: str | None = None


def utc_timestamp(seconds_ago: float = 0.0) -> str:
"""Return an ISO-8601 UTC timestamp offset from the current time."""
now = datetime.now(timezone.utc)
if seconds_ago:
now = now - timedelta(seconds=seconds_ago)
return now.isoformat()


def seconds_since(timestamp: str) -> float:
"""Return age in seconds for an ISO-8601 timestamp."""
try:
parsed = datetime.fromisoformat(timestamp)
except ValueError:
return 0.0

if parsed.tzinfo is None:
parsed = parsed.replace(tzinfo=timezone.utc)
return max(0.0, (datetime.now(timezone.utc) - parsed).total_seconds())


def format_age(timestamp: str) -> str:
return f"{seconds_since(timestamp):.1f}s ago"
Loading