Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
0e78627
feat: deag, click on enable
ruthwikdasyam Mar 14, 2026
117df64
feat: click anywhere else to disengage
ruthwikdasyam Mar 14, 2026
d57c63d
feat: click to navigate
ruthwikdasyam Mar 14, 2026
c1baf07
fix: remove logging
ruthwikdasyam Mar 14, 2026
a952495
fix: reposition default
ruthwikdasyam Mar 14, 2026
d221409
fix: default position
ruthwikdasyam Mar 14, 2026
88eda7d
feat: add --connect arg to dimos-viewer for connecting to existing gR…
jeff-hykin Mar 14, 2026
692954b
fix: resolve CI lint, formatting, and cargo-shear failures
jeff-hykin Mar 15, 2026
65fd6da
add websocket hack to make connect work
jeff-hykin Mar 18, 2026
3eb8b8b
feat: switch WS from server to client mode, drain stale commands on r…
jeff-hykin Mar 21, 2026
a377b48
fix: respond to server WebSocket pings to prevent disconnects
jeff-hykin Mar 22, 2026
07f64d1
refactor: remove LCM transport, use WebSocket only for viewer events
jeff-hykin Mar 23, 2026
c6346fe
merge: sync with main, keep WebSocket transport
jeff-hykin Mar 30, 2026
63a1ab1
fix: lint/spelling/shear CI failures
jeff-hykin Apr 1, 2026
004df28
restore arg parsing
jeff-hykin Apr 2, 2026
25a5ce5
add to --ws-url help properly
jeff-hykin Apr 2, 2026
da5ae96
restore logging
jeff-hykin Apr 2, 2026
7dee28c
restore logging
jeff-hykin Apr 3, 2026
21228ff
increment version
jeff-hykin Apr 3, 2026
12c9f1c
fix test
jeff-hykin Apr 3, 2026
df95b8c
undo
jeff-hykin Apr 3, 2026
9748088
restore error handling
jeff-hykin Apr 3, 2026
43c529a
clean
jeff-hykin Apr 3, 2026
081bb40
-
jeff-hykin Apr 3, 2026
85bead9
remove unused
jeff-hykin Apr 3, 2026
07339f0
move docs
jeff-hykin Apr 3, 2026
6abbd9e
-
jeff-hykin Apr 3, 2026
a29e336
version change back
jeff-hykin Apr 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 45 additions & 2 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2330,6 +2330,12 @@ dependencies = [
"parking_lot_core",
]

[[package]]
name = "data-encoding"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea"

[[package]]
name = "data-url"
version = "0.3.1"
Expand Down Expand Up @@ -3110,15 +3116,17 @@ dependencies = [

[[package]]
name = "dimos-viewer"
version = "0.30.0-alpha.5"
version = "0.30.0-alpha.6"
dependencies = [
"bincode",
"clap",
"futures-util",
"mimalloc",
"parking_lot",
"rerun",
"serde",
"serde_json",
"tokio",
"tokio-tungstenite",
]

[[package]]
Expand Down Expand Up @@ -12596,6 +12604,18 @@ dependencies = [
"tokio-util",
]

[[package]]
name = "tokio-tungstenite"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857"
dependencies = [
"futures-util",
"log",
"tokio",
"tungstenite",
]

[[package]]
name = "tokio-util"
version = "0.7.16"
Expand Down Expand Up @@ -13013,6 +13033,23 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78122066b0cb818b8afd08f7ed22f7fdbc3e90815035726f0840d0d26c0747a"

[[package]]
name = "tungstenite"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442"
dependencies = [
"bytes",
"data-encoding",
"http",
"httparse",
"log",
"rand 0.9.2",
"sha1",
"thiserror 2.0.17",
"utf-8",
]

[[package]]
name = "twox-hash"
version = "2.1.2"
Expand Down Expand Up @@ -13192,6 +13229,12 @@ dependencies = [
"xmlwriter",
]

[[package]]
name = "utf-8"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"

[[package]]
name = "utf8-ranges"
version = "1.0.5"
Expand Down
151 changes: 151 additions & 0 deletions WS_EVENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# dimos-viewer WebSocket Event Stream

When `dimos-viewer` is started with `--connect`, LCM multicast is not available
(LCM uses UDP multicast which is limited to the local machine or subnet). Instead,
the viewer starts a WebSocket server that broadcasts click and keyboard events as
JSON to any connected client.

## Starting the server

```sh
dimos-viewer --connect [<grpc-proxy-url>] [--ws-port <port>]
```

| Flag | Default | Description |
|------|---------|-------------|
| `--connect [url]` | — | Enable connect mode. Optionally specify the gRPC proxy URL (defaults to `rerun+http://127.0.0.1:9877/proxy`). |
| `--ws-port <port>` | `3030` | Port for the WebSocket event server. |

The WebSocket server listens on:

```
ws://0.0.0.0:<ws-port>/ws
```

Multiple clients can connect simultaneously. All connected clients receive every
message. The server does not accept any inbound messages from clients.

## Message format

All messages are UTF-8 JSON objects with a `"type"` string discriminant.

### `heartbeat`

Sent once per second regardless of viewer activity. Useful for connection health
checks and detecting viewer restarts.

```json
{
"type": "heartbeat",
"timestamp_ms": 1773869091428
}
```

| Field | Type | Description |
|-------|------|-------------|
| `timestamp_ms` | `u64` | Unix timestamp in milliseconds (from the viewer's system clock). |

### `click`

Sent when the user clicks a 3D point in the Rerun viewport. Corresponds to the
`/clicked_point` convention from RViz / `geometry_msgs/PointStamped`.

```json
{
"type": "click",
"x": 1.234,
"y": -0.567,
"z": 0.000,
"entity_path": "/world/ground_plane",
"timestamp_ms": 1773869091428
}
```

| Field | Type | Description |
|-------|------|-------------|
| `x` | `f64` | World-space X coordinate (metres). |
| `y` | `f64` | World-space Y coordinate (metres). |
| `z` | `f64` | World-space Z coordinate (metres). |
| `entity_path` | `string` | Rerun entity path of the clicked object. |
| `timestamp_ms` | `u64` | Unix timestamp in milliseconds at the moment of the click. |

Click events are debounced: a minimum of 100 ms must elapse between successive
published clicks. Rapid clicks within that window are silently dropped (with a
warning logged after 5 consecutive rapid clicks).

### `twist`

Sent every frame (~60 Hz) while movement keys are held on the keyboard teleop
overlay. Corresponds to `geometry_msgs/Twist` / `/cmd_vel` convention.

The keyboard overlay must first be **engaged** by clicking on it (green border =
active). Clicking anywhere outside the overlay disengages it and sends a `stop`.

```json
{
"type": "twist",
"linear_x": 0.5,
"linear_y": 0.0,
"linear_z": 0.0,
"angular_x": 0.0,
"angular_y": 0.0,
"angular_z": 0.8
}
```

| Field | Type | Description |
|-------|------|-------------|
| `linear_x` | `f64` | Forward (+) / backward (−) velocity in m/s. |
| `linear_y` | `f64` | Strafe left (+) / right (−) velocity in m/s. |
| `linear_z` | `f64` | Vertical velocity in m/s (always 0 for ground robots). |
| `angular_x` | `f64` | Roll rate in rad/s (always 0). |
| `angular_y` | `f64` | Pitch rate in rad/s (always 0). |
| `angular_z` | `f64` | Yaw left (+) / right (−) rate in rad/s. |

**Key bindings:**

| Key | Effect |
|-----|--------|
| `W` / `↑` | Forward (`linear_x = +0.5`) |
| `S` / `↓` | Backward (`linear_x = −0.5`) |
| `A` / `←` | Turn left (`angular_z = +0.8`) |
| `D` / `→` | Turn right (`angular_z = −0.8`) |
| `Q` | Strafe left (`linear_y = +0.5`) |
| `E` | Strafe right (`linear_y = −0.5`) |
| `Shift` | Speed multiplier ×2 |

Multiple keys can be held simultaneously; their effects are summed.

### `stop`

Sent when all movement keys are released, the overlay is disengaged, or `Space`
is pressed (emergency stop). Signals the robot to halt immediately.

```json
{
"type": "stop"
}
```

No additional fields. Semantically equivalent to a `twist` with all fields zero.

## Example client (Deno)

A reference test client is provided at `dimos/test_ws_client.ts`:

```sh
deno run --allow-net dimos/test_ws_client.ts
# or with a custom address:
deno run --allow-net dimos/test_ws_client.ts ws://192.168.1.10:3030/ws
```

## Local mode (no `--connect`)

Without `--connect`, the viewer uses LCM UDP multicast instead of WebSocket:

| Channel | Message type |
|---------|-------------|
| `/clicked_point#geometry_msgs.PointStamped` | Click events |
| `/cmd_vel#geometry_msgs.Twist` | Twist / stop commands |

The WebSocket server is **not** started in this mode.
7 changes: 6 additions & 1 deletion dimos/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ rerun = { path = "../crates/top/rerun", default-features = false, features = [

clap = { workspace = true, features = ["derive"] }
bincode.workspace = true
futures-util.workspace = true
mimalloc.workspace = true
parking_lot.workspace = true
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
tokio = { workspace = true, features = [
"io-util",
"macros",
Expand All @@ -40,3 +41,7 @@ tokio = { workspace = true, features = [
"sync",
"time",
] }
tokio-tungstenite = "0.28.0"

[lints]
workspace = true
22 changes: 11 additions & 11 deletions dimos/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@ version = "0.30.0a6"
description = "Interactive Rerun viewer for DimOS with click-to-navigate support"
readme = "README.md"
requires-python = ">=3.10"
license = {text = "MIT OR Apache-2.0"}
authors = [{name = "Dimensional Inc.", email = "engineering@dimensional.com"}]
license = { text = "MIT OR Apache-2.0" }
authors = [{ name = "Dimensional Inc.", email = "engineering@dimensional.com" }]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Topic :: Scientific/Engineering",
"Topic :: Scientific/Engineering :: Visualization",
"Programming Language :: Rust",
"License :: OSI Approved :: MIT License",
"License :: OSI Approved :: Apache Software License",
"Operating System :: POSIX :: Linux",
"Operating System :: MacOS",
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Topic :: Scientific/Engineering",
"Topic :: Scientific/Engineering :: Visualization",
"Programming Language :: Rust",
"License :: OSI Approved :: MIT License",
"License :: OSI Approved :: Apache Software License",
"Operating System :: POSIX :: Linux",
"Operating System :: MacOS",
]

[project.urls]
Expand Down
4 changes: 2 additions & 2 deletions dimos/src/interaction/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ impl InteractionHandle {
is_2d,
};

if let Err(e) = self.tx.send(event) {
eprintln!("Failed to send click event: {}", e);
if let Err(err) = self.tx.send(event) {
eprintln!("Failed to send click event: {}", err);
}
}
}
Expand Down
Loading
Loading