它是可选的官方接口插件,但以 fastsim-tui 启动独立 companion 进程,不是
Runtime 托管插件,也不注册 fastsim.components 或 fastsim.plugins entry
point。TUI 不导入 FastSim Core 或任何仿真器 SDK。没有启动 TUI 时,FastSim
不会创建相关对象、回调、线程或网络任务。
fastsim-tui fastsim-server FastSim Run
┌──────────────────────┐ HTTP/WS ┌──────────────────────┐ API ┌──────────────┐
│ Textual 终端工作站 │◄─────────►│ 公共控制面 │◄───────►│ UniRoboSim │
│ 独立进程 │ v1 │ Run generation 权威 │ │ 仿真后端 │
└──────────────────────┘ └──────────────────────┘ └──────────────┘
安装与连接
TUI 可安装在任意能够访问 Server 的 Python 3.11 或 3.12 环境中,不要求与 仿真器共用环境。
python -m pip install ./packages/fastsim-plugin-tui
fastsim-tui --version
fastsim-tui --url http://127.0.0.1:8000 --connect
认证部署建议使用环境变量或受保护的 token 文件:
FASTSIM_SERVER_TOKEN='...' fastsim-tui --url https://sim.example.com --connect
fastsim-tui --url https://sim.example.com --token-file /run/secrets/fastsim-token --connect
默认传输是带认证的增量 WebSocket。远程部署可指定 Server 允许的精确 Origin:
fastsim-tui \
--url https://sim-api.example.com \
--realtime-origin https://console.example.com \
--connect
轮询只是显式兼容模式,不会在 WebSocket 失败后静默降级:
fastsim-tui --url http://127.0.0.1:8000 --transport compatibility-poll --connect
工作站页面
| 页面 | 功能 |
|---|---|
| Dashboard | Run generation、生命周期、tick、仿真时间、Server FPS、实测 tick 速率和当前订阅 |
| Launch | 从 Server root 或本地 YAML/JSON/TOML 启动,并指定 open、prepared 或 running |
| Scene | 按 generation 缓存、支持分页的实体目录,以及 latest-wins 实体状态 |
| Camera | 按需读取 Server JPEG/PNG;离开页面立即停止相机请求 |
| Control | 控制目标、joint path、物理 Track、抢占、超时和 applied-control 审计 |
| Plugins | 插件实例状态和可靠插件事件 |
| Operations | 进度、精确详情、已接受 operation ID 和取消操作 |
| Logs | 可靠 Server 日志,以及客户端传输/协议错误 |
| Metrics | 仅在页面可见时读取进程 CPU、内存和可选 GPU 显存 |
工作站采用克制的高对比度配色,并在紧凑、标准和宽屏终端宽度下自动重排。 Overview 会直接展示生命周期、仿真时间、tick、FPS、实测 tick rate、generation、 Run 身份和当前 realtime demand,不要求操作者先阅读原始 JSON。常驻活动栏会在 toast 消失后继续保留最近一次成功信息或准确错误。
按 1 至 9 可直接切换页面,也可按 Ctrl+P 搜索工作站命令。生命周期快捷键
与可见按钮经过同一套 Server admission gate,不会绕过当前 Run 的允许操作。
终端窄于 124 列时,横向标签会替换为一个紧凑的页面按钮。按钮始终显示当前 页面,并可打开包含全部 9 个页面的可滚动列表,不会因标签裁切导致功能不可发现。 Help 和确认对话框也会随终端自适应,空间不足时可滚动。
连接颜色具有明确语义:绿色仅表示 realtime 或显式 poll 会话已建立;黄色表示
connecting、reconnecting 或 degraded;红色表示 failed。首次连接失败会恢复可操作的
Connect 状态,不会停留在 CONNECTING。
生命周期按钮同时服从 Server capability 与当前 Run 的
allowed_lifecycle_actions。例如运行状态下 Step 不可按,只有 Server 明确允许
时才启用。Step 数量显式可配并有上限。所有 Run 级 mutation 都携带当前 slot
generation。
所有 mutation 进入同一条串行客户端通道;响应不明确时不会盲目重试。Server 返回的 operation ID 会保留在界面中,可继续查看进度或请求取消。
Joint path
选择控制目标或填写 actor 和 resource group,设置 dt、是否抢占及可选超时,
再输入矩形 JSON 轨迹:
[
[0.0, -0.4, 0.2],
[0.1, -0.3, 0.3]
]
物理 Track
物理 Track 对应完整 Server 多资源控制契约。每条 Track 明确版本化 controller、 command space、固定 axes/units 以及时间线:
{
"tracks": [
{
"entity_id": "robots.droid",
"resource_group": "arm",
"controller": "joint.passthrough@1",
"command_space": "joint.position@1",
"interpolation": "linear",
"frames": [
{
"time_from_start_s": 0.0,
"axes": ["joint1", "joint2"],
"values": [0.0, 0.0],
"units": ["rad", "rad"]
},
{
"time_from_start_s": 1.0,
"axes": ["joint1", "joint2"],
"values": [0.2, -0.2],
"units": ["rad", "rad"]
}
]
}
]
}
提交前会校验有限数值、标识符、版本 ID、axes/units 稳定性、资源不重叠以及帧数 和传输上限。
传输与性能边界
- REST 只用于发现、ticket、mutation、相机快照、目录分页和用户主动请求的详情。
- 当前可见页面决定一组有界 realtime 订阅;隐藏页面不会产生 state、scene、 plugin、log、metrics、operation 或 applied-control 采样需求。
- Realtime 支持 snapshot + JSON Patch delta、heartbeat ack、generation 感知重订阅、 cursor resume 和有界指数退避重连。
- Scene catalog 按 slot generation 缓存;状态 latest-wins,事件、日志和 applied control 使用固定容量历史。
- JSON 响应在解析前有字节上限,且只解析一次。解析阶段会拒绝非标准的非有限 JSON 常量;类型和有限值检查只作用于 TUI 实际消费的 metrics、相机时间、仿真时间、 FPS 和控制值,不再递归复查响应里每一个值。
- 相机默认读取 JPEG(PNG 需显式
--camera-format png),只保留一个 worker 和 当前帧,不形成帧积压。 - 断开或退出会关闭 timer、订阅、相机 worker、HTTP 连接池和 WebSocket 任务。
快捷键
| 按键 | 功能 |
|---|---|
1–9 |
依次打开 Overview 到 Metrics |
Ctrl+P |
搜索页面与工作站命令 |
C |
连接或断开 |
Space |
在 Server 允许时暂停或继续 |
N |
在 Server 允许时执行指定 tick 数 |
R |
确认后 reset |
S |
确认后 stop |
F5 |
在兼容轮询模式显式刷新 |
? |
帮助 |
Q |
退出并清理客户端资源 |
开发验证
python -m pytest -q
python -m ruff check src tests
python -m ruff format --check src tests
python -m mypy src
python -m build
测试 extra 包含官方 pytest-textual-snapshot 插件。已接受的 SVG 快照覆盖
80x24、88x32、160x50 终端以及紧凑导航、Help、连接/错误状态和长确认内容。只能在人工检查生成的视觉差异后
执行 pytest --snapshot-update;这是人工验收操作,不是格式化命令。
包内测试覆盖有界 HTTP、结构化错误、generation/idempotency header、按需 realtime
订阅、heartbeat、generation 变化、delta、断线重连与 resume、Textual 交互和干净
退出。包发布门禁还包括以 Server 0.7.6 作为已验证版本的 HTTP/WebSocket、installed Wheel、
Textual 重复卸载和有界资源 soak。可见的 Isaac DROID Run 属于单独的后端验收门禁,
不作为这个无仿真器依赖包已经完成的测试来宣称。