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
-
In Session, select Replay capture.
-
Enter the repository-relative path:
sessions/20260715T122850Z_live_power_cycle/captures/mqtt_scan_full_payloads_03.tsv -
Use speed
1and enable loop for initial viewer setup. -
Start replay, then select Open Foxglove 3D.
-
In a Foxglove 3D panel, enable
/k1/points,/k1/poseand/k1/trajectory. -
For the cloud, choose
intensityas the color field and a Turbo/Rainbow colormap or custom two-color gradient. Foxglove can also color byx,y,zand 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
- Power K1 to its normal steady-green standby state.
- Confirm the manual power checklist in Connect.
- Run the real six-second BLE scan and select the K1 candidate.
- 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.
- When K1 reports a non-AP private address, press Start live stream.
- Open Foxglove before scanning if convenient.
- 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.