Skip to content

portal: live lateral steering graph for phones (/lateral) - #164

Closed
ghbarker wants to merge 2 commits into
BluePilotDev:bp-devfrom
ghbarker:portal-lateral-graph
Closed

portal: live lateral steering graph for phones (/lateral)#164
ghbarker wants to merge 2 commits into
BluePilotDev:bp-devfrom
ghbarker:portal-lateral-graph

Conversation

@ghbarker

Copy link
Copy Markdown
Contributor

Standalone — no dependency on the other open Ford branches (cross-branch telemetry fields are read defensively).

The evidence that motivated this

  • Tuning angle-mode steering means watching desired vs actual curvature converge — "the tops and bottoms of the graphs." The comma four's lateral debug screen shows exactly the right signals on a display that is honestly too small for more than a gut feeling; the 3X has the nice screen but not everyone drives one.
  • Meanwhile every BluePilot device already runs a capable HTTP server (bp_portal, the Web Routes Server) that phones on the hotspot reach today for route browsing and video — long-lived streaming connections included. The gap wasn't infrastructure; it was one page and one endpoint.

Why the fix is shaped this way

  • A page and a feed on the existing portal, nothing new to deploy. /lateral is a single self-contained HTML file (no SPA build, no external assets — the device is offline); /api/lateral/stream is Server-Sent Events, which needs no client library and reconnects natively.
  • Zero cost while nobody watches. A singleton reader owns one SubMaster (carState, carControl, controllerStateBP); it starts on the first connected phone and shuts down 10 s after the last one leaves. Messaging is imported lazily, same pattern as the portal's log streamer.
  • View-only, by decision. No control on the page changes anything on the device — adjustments stay on the on-device menus. A phone in a cupholder should never be a steering-settings surface.
  • Onroad is the use case, so it's allowed onroad: /api/lateral joins the GET allowlist alongside status/params. It's a read-only telemetry stream.
  • Defensive about fields it doesn't own: the auto-cal status string ships with a different branch; on a schema without it the page shows a dash instead of the stream dying. Verified by running the branch against the current bp-dev schema.
  • Robust to garbage: samples beyond ±600° (past any physical wheel) are dropped at ingest, and the axis uses a 1-2-5 grid ladder so a full-lock parking maneuver rescales gracefully instead of wallpapering the axis with labels.

The evidence afterwards

  • Measured on a replay-fed rig (real portal, real messages): metronomic 20 fps — 50 ± 1 ms frame gaps, zero drops over 500+ frames — and 12 ms median capture-to-client (p95 21 ms). With the WiFi hop and a 60 fps paint, wheel-moves-to-pixel-moves lands around 50 ms: one tick of the graph, the same effective liveness as the on-device screen.
  • ~4% of one CPU core while streaming, zero while idle; ~6 KB/s on the wire.
  • Confirmed working in the car from a phone over the device hotspot.

What each change is

  • bluepilot/backend/realtime/lateral_stream.py: the singleton reader + SSE writer (start-on-demand, idle stop, keepalive frames, per-client threads on the portal's existing ThreadingHTTPServer).
  • bluepilot/web/public/lateral.html: the page — rolling 12 s canvas of desired vs actual steering angle, autoscaled symmetric about zero; mph / lateral-active / live-error / factors readouts and the auto-cal status line; tap-anywhere pause; screen wake-lock; auto-reconnect with an explicit "waiting for data…" veil so a stale trace is never presented as live.
  • bluepilot/backend/bp_portal.py: two GET routes and one onroad-allowlist entry.
  • docs/lateral-phone-graph.md: driver-facing guide (enable the toggle, join the hotspot, open http://192.168.43.1:8088/lateral).

Test it yourself

  • Enable Web Routes Server, put a phone on the device hotspot, open http://192.168.43.1:8088/lateral. The graph should be live within a couple of seconds of the first frame.
  • Tap the graph: the trace freezes with a PAUSED badge; tap again to resume.
  • Turn the wheel at standstill: the trace follows and the scale steps up its ladder cleanly.
  • Close the page and check /tmp/bp_portal.log: "lateral feed: reader stopped (idle)" ~10 s later.

Risks / limits

  • Read-only endpoint on an opt-in server that already runs on these devices; no control path, no params writes, no new process.
  • Each watching phone holds one server thread (SSE); realistic usage is one or two viewers, and the portal already serves heavier per-connection work for video.
  • Wake-lock needs a modern phone browser (iOS 16.4+ / current Android); elsewhere it silently no-ops and the screen may sleep — the page reconnects on wake.
  • The stream reports whatever the sockets carry; if lateral is disengaged the traces sit at the driver's actual wheel angle, which is correct but worth knowing when reading it.

🤖 Generated with Claude Code

ghbarker and others added 2 commits July 22, 2026 18:28
The MICI lateral debug screen is too small for more than a gut feeling. The
portal now serves the same signals to any phone on the device hotspot/LAN:

- /lateral — self-contained page: desired vs actual steering angle on a rolling
  12 s canvas (autoscaled symmetric about zero, 1-2-5 grid ladder at any scale),
  mph / lateral-active / live error / factors readouts, tap-anywhere pause, and
  a screen wake-lock. View-only by design — adjustments stay on device menus.
  Samples beyond +/-600 degrees (past any physical wheel) are dropped at ingest
  so a CAN glitch or replay seam can never blow the scale.
- /api/lateral/stream — 20 Hz SSE. A singleton reader (realtime/lateral_stream)
  owns a SubMaster on carState/carControl/controllerStateBP, starts on the
  first watcher and stops after 10 s idle, so the portal costs nothing while
  nobody is looking. Messaging imports lazily, matching log_streamer. Fields
  owned by other branches (the auto-cal status string) are read defensively —
  a dash on the page instead of a dead stream on schemas without them.
- /api/lateral joins the onroad allowlist — watching while driving is the point.

Measured on a replay-fed rig: metronomic 20 fps (50 +/- 1 ms gaps, zero drops
over 500+ frames), 12 ms median capture-to-client, ~4% of one CPU core while
streaming and zero while idle. Confirmed working on-car from a phone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ghbarker

Copy link
Copy Markdown
Contributor Author

Closing — the /lateral phone graph never became reliable on-car (repeated disengages traced to portal spawn CPU spikes) and has been removed entirely. The on-device battery gauges in #161 cover the same need without a network path.

@ghbarker ghbarker closed this Jul 26, 2026
@ghbarker
ghbarker deleted the portal-lateral-graph branch July 27, 2026 00:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant