Skip to main content
Glama
Alonbbar6

robot-runtime

by Alonbbar6

远程机器人策略的控制运行时

一个模拟的 Franka Panda 执行抓取-放置任务,由位于 HTTP 边界之后的策略驱动——并且在该边界出现故障时仍能继续工作。

运行时在服务器中断期间保持运行并恢复

有趣的部分不是机械臂。而是机械臂与模型之间的一切:动作块调度、陈旧拒绝、带退避的重试、熔断器、可自行解除的保护性保持,以及一个 MCP 工具面,让智能体能够驱动工作单元而不至于造成伤害。

完全在笔记本电脑上运行。无需 GPU,无需安装 ROS,无需硬件。


为什么网络才是难点

操作策略需要 GPU。机器人需要实时控制回路。它们很少在同一台机器上,因此实际上模型位于一次网络跳转之后——这正是策略发出动作块而非单步动作的原因。你无法以 50 Hz 的频率往返访问推理服务器,但你可以一次请求 400 ms 的动作,并在下一个块在途时继续执行。

本仓库中的每一个难题都源于这一次跳转:

  • 一个块描述的是采集观测时存在的世界。等它到达时已经过时了。过时多少才算太多?

  • 控制回路必须每 20 ms 命令一次机械臂,无论服务器是否已应答。当没有有效动作可执行时,它该怎么办?

  • 请求会失败、重试,并且乱序到达。是什么阻止了较旧的答案覆盖较新的答案?

  • 模型可能输出 NaN;版本不匹配的服务器可能发送针对另一台机器人的目标。是什么拒绝将这些传给执行器?

Related MCP server: omni-kit-mcp

结果

每种条件 25 个种子,真实 HTTP,从带种子的 RNG 注入故障。 python experiments/latency_sweep.py --seeds 25 --ablations

条件

任务成功率

安全结束

中位时间

保持时间

恢复次数

p50 延迟

陈旧拒绝

重试次数

clean

100%

100%

6.4 s

0.0 s

0

20 ms

0

0

lan — 20 ms ± 5

100%

100%

6.7 s

0.0 s

0

40 ms

0

0

wan — 150 ms ± 40

100%

100%

11.1 s

0.0 s

0

160 ms

0

0

congested — 250 ms ± 150,5% 丢包

100%

100%

12.6 s

0.36 s

68

280 ms

222

64

lossy — 20% 丢包

100%

100%

9.8 s

0.26 s

50

60 ms

197

222

flaky_server — 20% 5xx

100%

100%

8.1 s

0.0 s

0

60 ms

0

248

outage — 服务器消失 3 秒

100%

100%

13.9 s

6.2 s

25

60 ms

0

24

任务成功率是立方体到达目标位置。安全结束是单独一列,这是有意的:一次运行可以任务失败但仍然正确,因为停止有时才是正确的答案。将两者合并会掩盖网络不好机器人做了不该做的事之间的区别。

表格中的规律就是设计目标:随着链路恶化,机器人变得更慢,而不是出错。250 ms 的拥塞链路使周期时间翻倍并拒绝 222 个陈旧块;它不会掉落立方体,也不会伸到不该伸的地方。

消融实验——移除每一项缓解措施

一个你从未见过它失效的安全检查,就不能声称它有效。

移除项

任务成功率

中位时间

备注

(无——基线 congested

100%

12.6 s

从保持中恢复outage

0%

0.5 s

锁存停止,永不恢复

陈旧检查congested

88%

23.7 s

执行针对已移动世界的计划

重试congested

96%

17.5 s

自适应提前量congested

100%

12.4 s

但保持 1.10 s 对比 0.36 s

重试lossy

100%

7.9 s

去掉反而更快——见下文

故障扫描实际发现了什么

这两个都是真实缺陷。在健康的 localhost 服务器上都不可见;两者都是在扫描第一次运行时才显现的。

1. 保护性停止没有返回路径。outage 配置下,运行时正确检测到服务器已死,保持位置,并锁存了急停——然后服务器三秒后恢复时它却坐在那里。正确,但毫无用处。一个每次网络抖动都需要人走过去重新布防的机器人,在第二周就会被拔掉插头。

修复将一个概念拆分为两个:一个保护性保持,在有效块到达的瞬间自动解除;以及一个八秒后仍未解除时的锁存急停outage 从 0% 变为 100%,同样的修改也修复了 congested。顶部的图就是该修复在起作用。

2. 请求提前量短于延迟。 运行时在剩余 120 ms 动作时请求下一个块。在拥塞链路上往返需要 280 ms。每个请求都晚了 140 ms 才发出,毫无用处,因此机械臂几乎在每个块边界都会饥饿。无论重试多少次都无法修复一个发送太晚的请求——你必须更早请求。

运行时现在测量自身的 p95 延迟并将提前量缩放到该值。congested 上的保持时间从 1.10 s 降至 0.36 s。

3. 一项不划算的缓解措施。lossy 配置下,关闭重试反而更快(7.9 s 对比 9.8 s),成功率没有损失,并且消除了 197 次陈旧拒绝。在低延迟链路上,分块本身已经提供了冗余:等重试到达时,一个新的请求本来会更有用。重试在 congested 上值得存在(96% → 100%),在 lossy 上则不然。它被列在表中,因为只报告有效的缓解措施,正是导致你上线那些无效措施的原因。

工作原理

        robot side                          │            policy side
                                            │
  ┌──────────────────────────────┐          │       ┌────────────────────┐
  │ runtime.py  50 Hz loop       │          │       │ server.py          │
  │   1 collect ── poll ─────────┼── HTTP ──┼──────▶│  POST /predict     │
  │   2 request ── submit        │          │       │  obs → 20 actions  │
  │   3 act                      │◀─────────┼───────│                    │
  │   4 check                    │          │       └────────────────────┘
  └──┬────────┬────────┬─────────┘          │        stateless; knows
     │        │        │                    │        nothing about episodes
     ▼        ▼        ▼                    │        or scheduling
  client   scheduler  safety                │
  retries  staleness  NaN/limits/workspace  │
  backoff  ordering   rate limit            │
  breaker  discards   e-stop                │

模块

单一职责

contracts.py

所有跨线传输的类型,只定义一次

clock.py

时间,可注入——真实或虚拟

sim.py

六个方法背后的 MuJoCo;在此处替换为硬件

policies/scripted.py

代替 VLA:无状态、分块、响应式

server.py

策略,位于 HTTP 之后

client.py

提交/轮询、截止时间、重试、退避、熔断器

scheduler.py

哪些块可信,哪些动作可执行

safety.py

假设策略是错的

runtime.py

50 Hz 循环

recording.py

MCAP 日志记录

mcp_server.py

作为 MCP 工具的工作单元

三个值得指出的决策:

循环从不阻塞在网络上。 第 2 步提交,第 1 步轮询,没有任何等待。一个会被慢服务器卡住的控制回路不是控制回路。

陈旧度从 observed_at 开始测量,而不是到达时间。 一个花了 300 ms 才返回的块,在它落地的那一刻就已经过时了 300 ms。

安全检查以两种不同的速率运行。 块验证很昂贵(对每个动作做正向运动学),在每个块的信任边界运行一次。速率限制很便宜,每个 tick 都运行。整体拒绝一个坏计划,好过把它钳制到某个微妙错误的东西上。

时钟技巧

虚拟时间以约 100 倍于真实时间的速度运行,因此 400 ms 的机器人时间在 4 ms 的墙钟时间内流逝——比到 localhost 的 HTTP 往返还快。如果不加小心,每个响应看起来都迟到了,实验测量的就是测试装置而不是运行时。

所以 SimClock.settle()真实秒阻塞,而不推进虚拟秒。运行时观察到的唯一延迟就是故障配置所要求的延迟。相同的客户端代码、相同的重试路径、相同的陈旧逻辑——在硬件上使用 WallClock 时,settle() 是空操作。这就是上面每个数字都能逐位复现的原因。

从智能体驱动它(MCP)

python -m robot_runtime.mcp_server

十二个工具。六个只读(状态、相机、故障配置、录制、审计日志),六个移动机器人。门控是服务器端状态,而不是提示中的请求:

run_pick_and_place  → {"ok": false, "error": "cell is not armed",
                       "hint": "call arm_cell with a reason before commanding motion"}
arm_cell("  ")      → {"ok": false, "error": "a reason is required"}
arm_cell("demo")    → {"ok": true, "armed": true, "expires_in_s": 120.0}
emergency_stop()    → {"ok": true, "estopped": true}
run_pick_and_place  → {"ok": false, "error": "cell is e-stopped"}
clear_estop()       → {"ok": false, "error": "confirmation required"}
  • 运动被门控;读取不受门控;停止按钮永远不受门控。 一个需要认证才能触达的安全控制不是安全控制。

  • 布防需要理由并且会过期,理由会被记录。

  • 错误是带有 hint 的结构化结果,绝不是异常。 一个读到 hint: start the policy server 的智能体可以修复问题。堆栈跟踪只会让它猜。

  • 每次调用都会追加到审计日志,可通过同一接口读取,因此"它到底调用了什么?"永远有答案。

可观测性与回放

每次试验都记录到 MCAP——ROS 2 所记录的容器格式——四个主题:/observation/action_chunk/command/event。事件主题才是关键,因为它记录的是决策,而不仅仅是数据:

3.28s  request_failed:     unreachable
3.52s  breaker_rejected:   circuit open, request not sent
3.80s  protective_hold:    no valid action for 0.50s
6.66s  hold_released:      resumed on chunk 136

九行,而不是第一版写的 128 行——重复事件被折叠。熔断器在打开的每一秒的 50 个 tick 中都会拒绝请求,写全部五十次并不会比第一次多传达任何信息。

回放录制会将完全相同的命令重新运行到新播种的模拟器中:

$ python experiments/replay.py recordings/outage-seed0.mcap
  commands_replayed: 533
  placement_error_m: 0.007850735794278705   # live run: 0.007850735794278705
  time drift: 0.000 ms

逐位精确。起初并非如此:/command 被四舍五入到六位小数记录,这给一次运行与其自身回放之间引入了微米级的漂移。很小——但它使"精确复现"为假,而这正是录制的全部意义。

这也是现场故障的修复方式:将 MCAP 从现场寄回,回放它,在你的笔记本电脑上再次看到机械臂做错事。

运行

python3 -m venv ~/.venvs/robotarm && ~/.venvs/robotarm/bin/pip install -r requirements.txt

虚拟环境特意放在内部磁盘上——本仓库位于 exFAT 卷上,macOS 会在其中散布 AppleDouble ._ 文件,MuJoCo 的插件加载器会尝试对其 dlopen 然后崩溃,而且 git 无法在其上维护包索引。

python experiments/latency_sweep.py --seeds 25 --ablations   # the results table
mjpython demos/run_with_viewer.py --profile outage           # watch it hold and recover
python experiments/replay.py recordings/outage-seed0.mcap    # replay a recording
python -m robot_runtime.mcp_server                           # agent-facing tools
mjpython demos/pick_and_place.py                             # the original scripted demo
pytest -q                                                    # 38 tests, ~5 s

任何带查看器的内容都用 mjpython 而不是 python——在 macOS 上窗口必须拥有主线程。

测试

38 个测试,约五秒,没有对被测对象的 mock。客户端测试使用假传输但使用真实的故障注入器;运行时测试通过真实 HTTP 访问线程中的真实服务器。

其中三个是上述缺陷,作为回归测试保留: test_server_outage_holds_then_recoverstest_adaptive_lead_reduces_time_spent_holding,以及 test_the_stage_machine_does_not_oscillate——一个早期策略因为先检查高度再检查位置而翻转了 lift→carry→lift→carry

这不是什么

直白地说,因为对机器人工程师过度吹嘘会在面试中被识破,而不是在筛选阶段。

  • 仅仿真。 没有硬件,没有 sim-to-real 迁移,没有针对真实 Panda 的接触模型标定。

  • 策略是手写的,而非学习得到的。 它刻意被塑造成 VLA 的样子——无状态、分块、语言条件化、反应式——以便运行时像被真实模型驱动一样被充分锻炼。但这里没有任何训练,也不对模型质量做任何声明。

  • 物体位姿来自仿真器,而非感知。 观测携带相机图像,契约也支持它;但脚本化策略忽略了像素。真实部署需要感知栈,而这是这里最大的差距。

  • 单机械臂、单个刚体、单一任务。

  • 不是 ROS。 使用 MCAP 是因为它是合适的容器且生态能读取它,但没有节点、没有 TF 树、没有 launch 文件。

  • 大约一天内构建完成,作为运行时层的聚焦演示。

后续方向

按价值粗略排序:

  1. 感知闭环——从相机图像而非仿真器获取位姿。弥补了这份清单上最大的差距。

  2. 训练策略。 用脚本化控制器生成演示数据,拟合一个动作分块的行为克隆模型,通过同一个 /predict 契约提供服务。运行时应该不需要改动一行代码——这就是 Policy 接口所做的声明,而目前它尚未经过测试。

  3. 双臂,这将分块调度变成一个真正的协调问题,而非簿记问题。

  4. 真实的 Panda,此时 settle() 变成空操作,本 README 中的每个延迟数字都将被重新真实测量。

致谢

Panda 模型来自 MuJoCo Menagerie(Apache 2.0)。物理引擎:MuJoCo。日志记录:MCAP

F
license - not found
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • Hosted MCP endpoint with realistic fake data for prototyping agents. 12 tools, no setup.

  • A comprehensive Model Context Protocol (MCP) server that enables AI assistants to control Unreal E…

  • Control plane for autonomous software labor. Agents claim objectives over MCP with audit trail.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Alonbbar6/robot-runtime'

If you have feedback or need assistance with the MCP directory API, please join our Discord server