NODEDC_MISSION_CORE/docs/06_K1_LIVE_VIEWER.md

6.1 KiB

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

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.

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:

    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.