Dimos supports three visualization backends: rerun (default), foxglove, and none.
Choose your viewer via the CLI:
# Rerun native viewer (default) - dimos-viewer with built-in teleop + click-to-navigate
dimos run unitree-go2
# Explicitly select the viewer backend:
dimos --viewer rerun run unitree-go2
dimos --viewer foxglove run unitree-go2
dimos --viewer none run unitree-go2Control how the Rerun viewer opens with --rerun-open and --rerun-web:
# Open native desktop viewer (default)
dimos --rerun-open native run unitree-go2
# Open web viewer in browser
dimos --rerun-open web run unitree-go2
# Open both native and web
dimos --rerun-open both run unitree-go2
# No viewer (headless) — data still accessible via gRPC
dimos --rerun-open none run unitree-go2
# Serve the web viewer without auto-opening a browser
dimos --rerun-web --rerun-open native run unitree-go2What you get:
- dimos-viewer, a custom Dimensional fork of Rerun with built-in keyboard teleop and click-to-navigate
- Native desktop application (opens automatically)
- Better performance with larger maps/higher resolution
- No browser or web server required
What you get:
- Browser-based dashboard at http://localhost:7779
- Rerun 3D viewer + command center sidebar in one page
- Teleop controls and goal setting via the web UI
- Works headless (no display required)
What you get:
- Foxglove bridge on ws://localhost:8765
- No Rerun (saves resources)
- Better performance with larger maps/higher resolution
- Open layout:
assets/foxglove_dashboards/old/foxglove_unitree_lcm_dashboard.json
To enable visualization in your own blueprint, use vis_module:
from dimos.core.coordination.blueprints import autoconnect
from dimos.hardware.sensors.camera.module import CameraModule
from dimos.visualization.vis_module import vis_module
camera_demo = autoconnect(
CameraModule.blueprint(),
vis_module(viewer_backend=global_config.viewer),
)Run the stack locally (this blocks until you stop the process):
from dimos.core.coordination.module_coordinator import ModuleCoordinator
if __name__ == "__main__":
ModuleCoordinator.build(camera_demo).loop()Every LCM stream, such as color_image (output by CameraModule), that uses a data type (like Image) that has a .to_rerun method will get rendered (rr.log) using the LCM topic as the rerun entity path. In other words: to render something, simply log it to a stream and it will automatically be available in rerun.
If you notice:
- Robot appears to "walk across empty space"
- Costmap updates lag behind the robot
- Visualization stutters or freezes
This happens on lower-end hardware (NUC, older laptops) with large maps.
Edit dimos/robot/unitree/go2/blueprints/smart/unitree_go2.py:
# Before (high detail, slower on large maps)
voxel_mapper(voxel_size=0.05), # 5cm voxels
# After (lower detail, 8x faster)
voxel_mapper(voxel_size=0.1), # 10cm voxelsTrade-off:
- Larger voxels = fewer voxels = faster updates
- But slightly less detail in the map
If you want to log data to Rerun directly from inside a module (e.g. for debugging or one-off visualizations), use rerun_init instead of calling rr.init() yourself. It handles colormap registration and can optionally start a gRPC server so a viewer can connect.
import rerun as rr
from dimos.visualization.rerun.init import rerun_init
# Basic init (no gRPC server — use when RerunBridgeModule is already running)
rerun_init()
rr.log("debug/my_points", rr.Points3D(positions=[[1, 2, 3]]))
# Start a gRPC server so you can connect a viewer
rerun_init(start_grpc=True)
# Then connect with: dimos-viewer --connect rerun+http://127.0.0.1:9877/proxy
# Custom gRPC config
rerun_init(
start_grpc=True,
grpc_config={
"connect_url": "rerun+http://127.0.0.1:9999/proxy",
"server_memory_limit": "4GB",
},
)When a RerunBridgeModule is already part of your blueprint, you typically don't need start_grpc — just call rerun_init() and log directly with rr.log(). The data will appear in the existing viewer.
Rerun on dev is module-driven: modules decide what to log, and Blueprint.build() sets up the shared viewer + default layout.