K. Isom 54a01625ce Initial commit: CloudView generic networked point-cloud viewer
Standalone Open3D viewer that listens on a TCP/Unix socket and renders NDJSON point-cloud streams from any producer. Decoupled server/protocol/store layers (no Open3D dependency, testable headless) plus a lazy Open3D render loop.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 14:09:11 -07:00

CloudView

A small, generic point-cloud viewer. It listens on a socket, accepts newline-delimited JSON (NDJSON) from any number of producers, and renders the combined cloud in an interactive Open3D window. It is not tied to any one robot: anything that can write JSON lines to a socket — a Crazyflie, a rover, a LIDAR rig, a log replay — gets live 3D visualization for free.

RangeView is the first producer (its 2D map stays the at-a-glance live diagnostic; the full 3D cloud is streamed here), but the wire format is the only contract, so other systems can feed the same viewer.

   producers (any language)                    viewer
  ┌───────────────────────┐   NDJSON over    ┌──────────────────────┐
  │ rangeview  ───────────┼── tcp:// ────────▶ CloudView (Open3D)   │
  │ rover-2    ───────────┼── unix:// ───────▶  - merges all sources │
  │ lidar-rig  ───────────┼──────────────────▶  - colour by height   │
  └───────────────────────┘                  └──────────────────────┘

Install & run

# with uv (resolves from the committed uv.lock)
uv run main.py                             # listen on tcp://127.0.0.1:9870
uv run main.py -l tcp://0.0.0.0:9870       # accept from other machines

# or a plain venv
python -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt            # open3d + numpy
python -m cloudview

Listen addresses (repeatable, TCP and/or Unix):

uv run main.py -l tcp://0.0.0.0:9870 -l unix:///tmp/cloud.sock

Viewer keys: C toggle colour (by height / per-source), R refit the camera, B cycle background, mouse to orbit/zoom/pan.

Wire protocol (NDJSON)

One JSON object per line over a stream socket. source keys a distinct cloud, so one viewer shows several robots at once. Coordinates are floats in whatever frame the producer uses.

message fields effect
hello source, name announce/label a stream
points source, points ([[x,y,z],...]), frame, color (optional [r,g,b] 0..1) append a batch
clear source drop that source's cloud
pose source, position [x,y,z], yaw (deg) record robot pose

Points are batched per message to keep overhead low. If a source supplies no color, the viewer colours its points by height; otherwise the given colour is used as a solid.

Producing from any language

It is just JSON lines — test it with nc:

printf '%s\n' \
  '{"type":"hello","source":"demo","name":"nc test"}' \
  '{"type":"points","source":"demo","points":[[0,0,0],[1,0,0.5],[0,1,1]]}' \
  | nc 127.0.0.1 9870

Python producers can reuse RangeView's cloud_publisher.CloudPublisher (a non-blocking client with auto-reconnect and full-cloud replay), or just write json.dumps(msg) + "\n" to a socket.

Layout

  • cloudview/protocol.py - NDJSON encode/decode + address parsing.
  • cloudview/store.py - thread-safe per-source cloud store.
  • cloudview/server.py - TCP/Unix socket server; one reader thread per producer.
  • cloudview/viewer.py - Open3D render loop (height/per-source colouring).
  • cloudview/app.py - CLI entry point.

Networking and rendering are decoupled: the server fills the store from any producer; the viewer polls the store and rebuilds geometry only when it changes. The server/protocol layers have no Open3D dependency, so they are testable headless.

Description
Visualize LIDAR/ranging sensor data.
Readme 232 KiB
Languages
Python 100%