Public: anyone can read this; the crew can change it.

Migrated from github.com/Trevato/SO-ARM100

workbenchthis machine

TOP: smooth driving and a camera that never freezes, through the public URL - one WebSocket, measured end to end #54

Closed opened this has it
opened this

Owner, 2026-10-20 21:10Z: "the movement is really buggy and not really working as well. on both mobile and mac", "the camera keeps freezing too on the mac", "definitely instrument with metrics to iterate on". This comes before the mobile pieces (#49-#53).

Probes (steward, 21:10Z):

  • Public round trip: GET https://arm--forge-trevato-apps.open-platform.sh/status takes 0.37-0.46 s (browser → Cloudflare → forge → app); the app to the Pi is 17-66 ms (forge pod → 100.89.95.68:8101). The cost is the public leg: anything done per HTTP request (a command, a status poll) pays ~0.4 s.
  • The public camera path does not stream: GET /camera answered first byte at 0.36 s and only 25 bytes in 6 s. Meanwhile the owner's Mac browser holds direct connections to 100.89.95.68:8080 - the page reaches the Pi camera directly, which only works on the owner's tailnet and is what freezes. Through Cloudflare a long MJPEG response is buffered and cut at ~100 s.
  • The Pi's arm server logged nothing in 15 min; its only :8101 client was the owner's Mac.

Done:

  1. ONE WebSocket per viewer to the app (Cloudflare passes WebSockets) carries: driver commands (binary or compact JSON, coalesced to 30 Hz, latest-wins - never queued), pose updates from the app (30 Hz), queue/chat events, and camera frames. The app holds ONE persistent connection to the Pi (#48) and fans pose out.
  2. Camera: the app reads the Pi's MJPEG once and sends JPEG frames over the WebSocket (latest-frame-wins per viewer, drop frames for slow viewers, never buffer); the browser draws them to a canvas/img. No browser ever connects to 100.89.95.68. Fallback: if a viewer's socket stalls > 2 s, reconnect and resume.
  3. Driving feel: client-side prediction (move the 3D model immediately), reconcile with the arm's pose; commands are targets with a max step; on reconnect, hold.
  4. Metrics (the owner wants to iterate on numbers): per viewer - command round-trip (send → pose reflects it) p50/p95, commands/s sent and dropped, camera fps received and frame age (capture → shown) p50/p95, stalls and reconnects; on the app - Pi round-trip, Pi frame rate in, viewers, bytes out. Expose /metrics (Prometheus text) and an Admin → Health panel with live sparklines; log a one-line summary every minute.
  5. Targets to report in the pull (Mac on home wifi and a phone on 4G): command→pose p95 < 250 ms, camera frame age p95 < 400 ms, 0 freezes over 10 min, ≥ 10 fps on 4G.

Tests: a fake Pi (pose + MJPEG) - a slow viewer drops frames without slowing others; commands are latest-wins; metrics report the injected delays.

the crew's run was interrupted: restart, resumes on the next pass — cancelled
commented

Owner, 22:40Z: "maybe whats happening with the arm is the camera is laggy. we really need this app to be SUPER fast. snappy. smart caching. etc"

Priority inside this issue: the CAMERA first - frame age p95 < 400 ms on the owner's Mac and phone, measured and shown live in the metrics; then commands. Speed rules for the whole app: static assets content-hashed and cached immutable for a year (HTML no-cache), the shell < 50 KB first load, the 3D model and its meshes cached (Cache-Control immutable + a service worker cache), no work on the main thread during drags (move pose maths off the render path), pose and frames over the one WebSocket with latest-wins and frame dropping for slow viewers. Report before/after numbers in the pull.

the crew's run was interrupted: restart, resumes on the next pass — cancelled
commented

Steward, 23:05Z — FOCUS: Quill works only on this until it lands; the mobile issues moved to Vesper. Owner: "its still not responsive. i need you to be getting good metrics and drive this down."

Today /metrics on the app has only event counters (since 22:36: block 83, jam 2, stream 229, move 8, stall 0) — no latency numbers, so nobody can measure the lag. Ship in this order, each its own small pull:

  1. MEASURE first: /metrics gains latency histograms (p50/p95/p99) — command sent → pose reflects it, camera capture → shown (frame age), Pi round-trip, viewer WebSocket round-trip, frames/s in and out per camera, dropped frames; plus the meaning of block and jam named in a doc line. A tiny client beacon reports the viewer-side numbers. Land this within the hour.
  2. Then the one-WebSocket path (pose, commands latest-wins, frames) and drive the numbers down; every pull states before/after p95s.

The steward reads these numbers every tick and reports them to the owner.

commented

Split into #87 (camera frames over a WebSocket, latest-wins per viewer, so Cloudflare stops freezing it), #88 (server-side counters at /metrics.prom and a per-minute log line) and #89 (each viewer reports round trip, fps and frame age; Admin -> Health shows them). The original was five deliverables in one run and was left without a pull; driving over one /follow WebSocket, the single arm link and the dead-man already landed (#59, #72, #78, #79). #87 and #88 can start now; #89 waits on both. The on-device targets (Mac + 4G phone) are for the owner to read off #89's numbers.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs