feat: add live K1 Foxglove console
This commit is contained in:
@@ -16,11 +16,17 @@ Each gate produces evidence and an explicit GO, PAUSE or BLOCKED result.
|
||||
| Stage 5 point cloud | GO — raw-LZ4 protobuf, 1,140 live frames decoded |
|
||||
| Stage 5 pose | GO — 1,215 live frames decoded and motion-correlated |
|
||||
| Stage 5 camera | PAUSE — no independent frame/video stream observed |
|
||||
| Stage 6 live viewer | GO — React console, Foxglove cloud/path and Mac latency metrics |
|
||||
|
||||
USB project copying remains optional ground truth rather than a blocker for the
|
||||
now-verified network path. MQTT control publishing remains deliberately deferred
|
||||
because the physical button is a known-safe start/stop mechanism.
|
||||
|
||||
The Stage 6 alpha uses a bounded raw-first bridge: loss in the visualization
|
||||
queue cannot discard MQTT evidence. Acceptance is replay of the full captured
|
||||
scan followed by a live ideal-LAN run with measured host pipeline latency.
|
||||
Sensor-to-display latency remains a separate clock-correlation test.
|
||||
|
||||
## Stage 0 — repository and host baseline
|
||||
|
||||
Deliverables:
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
# K1 live console and Foxglove bridge
|
||||
|
||||
Status: alpha implementation for the verified firmware-3 MQTT streams. It uses
|
||||
real K1 data and does not generate a placeholder cloud, pose or latency value.
|
||||
|
||||
## Architecture
|
||||
|
||||
```text
|
||||
K1 lio_pcl / lio_pose
|
||||
|
|
||||
v
|
||||
read-only MQTT subscription on TCP 1883
|
||||
|
|
||||
+--> raw .k1mqtt + JSONL + SHA-256 summary (first)
|
||||
|
|
||||
v
|
||||
bounded latest-wins preview queue (32 messages)
|
||||
|
|
||||
v
|
||||
raw-LZ4/protobuf decoder --> foxglove.PointCloud / Pose / SceneUpdate
|
||||
|
|
||||
v
|
||||
ws://127.0.0.1:8765 --> Foxglove 3D
|
||||
|
||||
React console <-- REST + WebSocket state --> FastAPI on 127.0.0.1:8000
|
||||
```
|
||||
|
||||
The Paho MQTT callback never decodes the point cloud. It writes and flushes the
|
||||
raw frame and metadata, then enqueues a preview reference. If visualization cannot
|
||||
keep up, the oldest queued preview is discarded while the raw capture continues.
|
||||
|
||||
## Start the local application
|
||||
|
||||
Prerequisites are the repository-local Python environment and Node.js 20 or
|
||||
newer. No global Python package or system component is installed.
|
||||
|
||||
```bash
|
||||
uv sync --group dev
|
||||
cd apps/k1-viewer
|
||||
npm install
|
||||
npm run build
|
||||
cd ../..
|
||||
uv run k1link serve
|
||||
```
|
||||
|
||||
Open `http://127.0.0.1:8000`. `k1link serve` intentionally exposes no LAN bind
|
||||
option because its provisioning endpoint temporarily receives a Wi-Fi password.
|
||||
The password is accepted only in the POST body, is never logged or persisted by
|
||||
the connector, and is cleared from the React form after success.
|
||||
|
||||
## Replay the captured proof
|
||||
|
||||
1. In **Session**, select **Replay capture**.
|
||||
2. Enter the repository-relative path:
|
||||
|
||||
```text
|
||||
sessions/20260715T122850Z_live_power_cycle/captures/mqtt_scan_full_payloads_03.tsv
|
||||
```
|
||||
|
||||
3. Use speed `1` and enable loop for initial viewer setup.
|
||||
4. Start replay, then select **Open Foxglove 3D**.
|
||||
5. In a Foxglove 3D panel, enable `/k1/points`, `/k1/pose` and
|
||||
`/k1/trajectory`.
|
||||
6. For the cloud, choose `intensity` as the color field and a Turbo/Rainbow
|
||||
colormap or custom two-color gradient. Foxglove can also color by `x`, `y`,
|
||||
`z` and its derived `<distance>`.
|
||||
|
||||
The reviewed TSV reader accepts exactly four columns: receive timestamp, topic,
|
||||
declared payload length and hex payload. It verifies timestamp, UTF-8 topic,
|
||||
declared length, hex encoding and allocation bounds. Native
|
||||
`mqtt.raw.k1mqtt` captures are supported directly and use their sibling metadata
|
||||
timestamps when present.
|
||||
|
||||
## Connect and stream live
|
||||
|
||||
1. Power K1 to its normal steady-green standby state.
|
||||
2. Confirm the manual power checklist in **Connect**.
|
||||
3. Run the real six-second BLE scan and select the K1 candidate.
|
||||
4. Enter the existing router SSID/password and press **Provision Wi-Fi &
|
||||
connect**. That button is the explicit authorization for one reviewed 99-byte
|
||||
provisioning write; the backend never retries automatically.
|
||||
5. When K1 reports a non-AP private address, press **Start live stream**.
|
||||
6. Open Foxglove before scanning if convenient.
|
||||
7. Double-click the physical K1 button to start scanning. Double-click again to
|
||||
stop, wait for the LED to return to steady green, then stop the local session.
|
||||
|
||||
Each live run creates an ignored `sessions/<UTC>_viewer_live/` directory with a
|
||||
redacted manifest, operator notes, raw MQTT frames, per-message metadata and a
|
||||
hash summary. No application request topic is published.
|
||||
|
||||
## Published topics
|
||||
|
||||
| Topic | Foxglove schema | Meaning |
|
||||
| --- | --- | --- |
|
||||
| `/k1/points` | `foxglove.PointCloud` | metric XYZ float32 + uint8 intensity, stride 16 |
|
||||
| `/k1/pose` | `foxglove.PoseInFrame` | current decoded K1 pose in the `map` frame |
|
||||
| `/k1/trajectory` | `foxglove.SceneUpdate` | bounded cyan line strip, throttled while growing |
|
||||
| `/k1/metrics` | JSON schema | latency, decode/publish time, FPS, points and drops |
|
||||
|
||||
Point coordinates remain `(x/scaler, y/scaler, z/scaler)` exactly as verified.
|
||||
No axis swap, quaternion normalization or vehicle extrinsic is silently applied.
|
||||
Only the low byte of `rgbi` is labeled intensity; interpreting the upper bytes
|
||||
as RGB remains unverified.
|
||||
|
||||
## Latency semantics
|
||||
|
||||
`pipeline_ms` / `mqtt_to_publish_ms` is measured with the host monotonic clock
|
||||
from MQTT callback receipt through raw disk write, bounded queue wait, decode,
|
||||
packing and Foxglove channel publish. Rolling p50/p95 values use the last 512
|
||||
published decoded messages.
|
||||
|
||||
This is the exact Mac pipeline latency, not yet sensor-photon-to-screen latency.
|
||||
The K1 header timestamp epoch has not been proven, Foxglove rendering time is
|
||||
outside the Python publisher, and display latency is not observable without a
|
||||
clock-correlated device timestamp or high-speed-camera experiment. Foxglove
|
||||
message time therefore uses host receive Unix time while durations use
|
||||
`monotonic_ns`.
|
||||
|
||||
## Current boundaries
|
||||
|
||||
- Raw panoramic camera frames were not present on the observed MQTT report
|
||||
topics; this milestone intentionally ships point cloud plus trajectory only.
|
||||
- Physical double-click remains the start/stop control. A future MQTT modeling
|
||||
publisher needs a separately reviewed state-changing profile.
|
||||
- The React application opens the official Foxglove viewer over a local
|
||||
WebSocket. It does not embed or fork the proprietary modern viewer; Foxglove
|
||||
account/seat terms apply to that viewer independently of this connector.
|
||||
- Exact path axes and a scanner-to-vehicle transform must be calibrated before
|
||||
mounting on the unmanned platform.
|
||||
|
||||
## Verification checkpoint — 2026-07-15
|
||||
|
||||
The full captured 180-second scan was passed through the production Foxglove
|
||||
bridge without a viewer-side substitute:
|
||||
|
||||
| Check | Result |
|
||||
| --- | ---: |
|
||||
| MQTT messages read | 2,836 |
|
||||
| `lio_pcl` frames published | 1,140 |
|
||||
| `lio_pose` frames published | 1,215 |
|
||||
| points packed and published | 4,165,862 |
|
||||
| decoder errors | 0 |
|
||||
| final trajectory poses | 1,215 |
|
||||
|
||||
The same replay was then started through the FastAPI/React contract at `10x`.
|
||||
The API exposed the loopback Foxglove URL, live point/pose metrics and non-zero
|
||||
preview-drop accounting under deliberate acceleration, and released TCP 8765
|
||||
after the stop request. This validates replay, overload behavior and lifecycle;
|
||||
the next checkpoint is the powered K1 ideal-LAN live run.
|
||||
Reference in New Issue
Block a user