Rerun.io 核心概念中文指南

依據官方文件 https://rerun.io/docs/concepts 整理。適合初次使用 Rerun 的開發者快速建立心智模型。


一、Rerun 是什麼

Rerun 是一套多維感測資料的視覺化平台,特別適合機器人、電腦視覺、感測器融合等場景。你在程式中記錄資料(log),Rerun Viewer 就能即時或事後播放這些資料的時序變化。

核心工作流程:

你的程式 —rr.log()→ Recording → Viewer(即時或檔案)

二、Recording(記錄)

Recording 是 Rerun 中資料的基本容器,對應一個 .rrd 檔案或一條串流。

初始化方式(Python):

import rerun as rr
rr.init("my_app")         # 建立一個 recording,app ID 為 "my_app"
rr.connect_tcp()          # 串流到本地 Viewer
# 或
rr.save("output.rrd")     # 存成檔案,事後用 Viewer 開啟

關鍵概念:

  • application_id:決定哪個 Blueprint(版面配置)會被套用
  • recording_id:若多個 process 共用同一個 recording ID,它們的資料會合併成單一邏輯 recording,方便分散式記錄

三、Entity 與 Component(實體與元件)

這是 Rerun 資料模型的核心,類似遊戲 ECS 的前兩層。

Entity:具名容器,用路徑字串表示(例如 "robot/arm/gripper"Component:掛在 Entity 上的實際資料(例如位置、顏色、影像像素)

rr.log("camera/image", rr.Image(img))          # Entity 路徑 + Archetype
rr.log("robot/joints", rr.Points3D(positions)) # 一個 log 呼叫可掛多個 component

Archetype 是便利包裝:rr.Points3D(...) 會自動拆解成 Position3D + Color + Radius 等 component。


四、Entity Path 層級

路徑用 / 分隔,形成樹狀結構,類似檔案系統:

world/
  robot/
    base_link
    arm/
      joint1
      gripper
  camera/
    image
    detections/
      points

實用規則:

  • 不需要顯式建立父路徑,Rerun 自動處理
  • Transform(座標變換)、Annotation Context 會沿路徑繼承
  • Blueprint 可以選取某個路徑及其所有子孫一起顯示

五、Timelines(時間軸)

Rerun 支援多條時間軸,讓你從不同時間維度瀏覽資料。

預設時間軸(自動建立):

  • log_tick:log 呼叫的順序編號
  • log_time:系統時鐘時間

自訂時間軸:

rr.set_time("frame_idx", sequence=42)          # 序列型(frame 編號)
rr.set_time("sensor_time", timestamp=ts_ns)    # 時間戳(奈秒 Unix epoch)
rr.log("lidar/points", rr.Points3D(pts))       # 這筆資料同時掛在兩條時間軸

Static 資料:rr.log(..., static=True) 記錄的資料不屬於任何時間點,對所有時間軸都可見(適合場景 mesh、座標系定義等)。


六、Transforms(座標變換)

Rerun 原生支援 3D 座標系轉換,對機器人場景特別重要。

方法一:路徑層級隱含 transform(最常用)

rr.log("world/robot/camera",
       rr.Transform3D(translation=[0.1, 0, 0.5],
                      rotation=rr.RotationQuat([0,0,0,1])))
rr.log("world/robot/camera/image", rr.Image(img))

此時 camera 相對於 robot 的位姿由 Transform3D 定義,Viewer 會自動換算到 world frame。

方法二:Named Coordinate Frame(拓撲可隨時間變化)

rr.log("robot_base", rr.CoordinateFrame(frame="base_link"))
rr.log("camera_frame",
       rr.Transform3D(parent_frame="base_link",
                      child_frame="camera_link", ...))

Pinhole 相機模型(投影):

rr.log("camera", rr.Pinhole(focal_length=..., width=..., height=...))
rr.log("camera/image", rr.Image(img))

七、Blueprint(視覺化版面)

Blueprint 控制 Viewer 要顯示什麼、用什麼方式呈現,和 recording(資料)分開管理。

用 Python 程式生成 Blueprint:

import rerun.blueprint as rrb
 
blueprint = rrb.Blueprint(
    rrb.Horizontal(
        rrb.Spatial3DView(origin="world"),
        rrb.Vertical(
            rrb.Spatial2DView(origin="camera/image"),
            rrb.TimeSeriesView(origin="robot/joints"),
        )
    )
)
rr.send_blueprint(blueprint)

View 類型:

  • Spatial3DView:3D 場景
  • Spatial2DView:2D 影像/平面
  • TimeSeriesView:時序折線圖
  • BarChartViewTextLogViewMapView

八、常見應用模式

機器人感測器記錄

rr.init("robot_demo")
rr.connect_tcp()
 
for frame in sensor_stream:
    rr.set_time("frame", sequence=frame.idx)
    rr.log("lidar/points", rr.Points3D(frame.lidar))
    rr.log("camera/rgb", rr.Image(frame.rgb))
    rr.log("robot/pose", rr.Transform3D(translation=frame.pos,
                                         rotation=frame.quat))

離線分析(先存檔再看)

rr.init("analysis_run")
rr.save("/tmp/run_001.rrd")
# ... 跑完資料記錄 ...
# 之後用 `rerun /tmp/run_001.rrd` 開啟

多 process 分散式記錄

recording_id = "shared-run-001"
# process A
rr.init("robot_app", recording_id=recording_id)
# process B(另一台機器或另一個 node)
rr.init("robot_app", recording_id=recording_id)
# Viewer 會自動合併兩者的資料

九、Chunk 與 Apache Arrow 內部儲存機制

什麼是 Chunk?

Chunk 是 Rerun 資料架構的核心儲存單位(自 v0.18 起全面採用)。每一個 Chunk 是一張 Apache Arrow 編碼的行欄式(column-oriented)資料表,包含:

欄位類型說明
Control column全域唯一 Row ID
Time/index columns時間軸資料(如 log_ticklog_time、自訂 timeline)
Component columns各 component 的資料(如 Points3D:positionsPoints3D:colors

每個 component column cell 對應一個 Component Batch(Rerun 的原子資料單位),包含一或多個 instance。

Apache Arrow 扮演的角色

Rerun 在底層使用 Apache Arrow 作為資料序列化與記憶體格式:

  • Component 資料以 Arrow array 表示,跨語言(Python/C++/Rust)共享同一記憶體佈局
  • Chunk 從 SDK 一路傳到 data store,再到 visualizer 和 GPU,全程零複製(zero-copy)
  • 行欄式佈局讓高頻小訊號(tall column)和低頻大資料(如點雲 tensor,wide column)能混合在同一個 recording 中
# SDK 底層流程(自動發生):
# rr.log() → Arrow array → batcher 累積 → Chunk → 傳輸/儲存

兩種資料輸入路徑

路徑一:rr.log()(行導向,適合即時記錄)

for i, pts in enumerate(frames):
    rr.set_time("frame", sequence=i)
    rr.log("lidar/points", rr.Points3D(pts))
    # SDK 自動把每行資料打包成 Arrow array,累積後形成 Chunk
  • 自動加入 log_timelog_tick 兩條時間軸
  • Batcher 達到大小閾值或定期觸發才傳送

路徑二:rr.send_columns()(欄導向,適合批次/離線資料)

import numpy as np
import rerun as rr
 
times = np.arange(0, 64)
scalars = np.sin(times / 10.0)
 
rr.send_columns(
    "scalars",
    indexes=[rr.TimeColumn("step", sequence=times)],
    columns=rr.Scalars.columns(scalars=scalars),
)
  • 繞過 time context 和 micro-batcher,直接產生大 Chunk
  • 不會自動加 log_time/log_tick,只包含你明確指定的時間軸
  • 壓縮率更佳,ingestion 速度更快(benchmark: 比逐行 log 快 ~100x)

點雲序列(多時間步,不同點數):

rr.send_columns(
    "points",
    indexes=[rr.TimeColumn("time", duration=times)],
    columns=[
        *rr.Points3D.columns(positions=positions).partition(lengths=[2, 4, 4, 3, 4]),
        *rr.Points3D.columns(colors=colors, radii=radii),
    ],
)

partition(lengths=...) 告知 Rerun 每個時間步各自有幾個點,因為批次中點數不固定。

影像序列:

rr.send_columns(
    "images",
    indexes=[rr.TimeColumn("step", sequence=times)],
    columns=rr.Image.columns(
        buffer=images.view(np.uint8).reshape(len(times), -1)
    ),
)

Chunk Compaction(壓縮優化)

Rerun 在 ingestion 時會自動把小 Chunk 合併成目標大小範圍內的大 Chunk。記錄完成後也可以用 CLI 手動優化:

rerun rrd compact --max-rows 4096 --max-bytes=1048576 my_recording.rrd

效能數字參考(v0.18 benchmark)

  • 225 萬筆 scalar 資料點:ingestion 速度提升 ~100x,記憶體 overhead 降低 ~35x
  • v0.18 後,百萬時間點規模為「完整支援」等級

十、快速上手 Checklist

  1. pip install rerun-sdk
  2. rr.init("app_name") + rr.connect_tcp()rr.save("file.rrd")
  3. 設計你的 Entity Path 層級(建議對齊你的座標系樹)
  4. 在每個時間步呼叫 rr.set_time(...)rr.log(...)
  5. 若有座標系關係,用 rr.log(..., rr.Transform3D(...)) 定義
  6. 用 Blueprint API 或 Viewer GUI 調整版面

參考連結