Skip to main content
Glama
Alonbbar6

robot-runtime

by Alonbbar6

Eine Control-Runtime für entfernte Roboter-Policies

Ein simulierter Franka Panda führt Pick-and-Place aus, gesteuert von einer Policy, die hinter einer HTTP-Grenze lebt – und weiterarbeitet, wenn diese Grenze sich fehlverhält.

die Runtime, die einen Serverausfall durchhält und wieder aufnimmt

Das Interessante ist nicht der Arm. Es ist alles zwischen dem Arm und dem Modell: Action-Chunk-Planung, Staleness-Ablehnung, Retries mit Backoff, ein Circuit Breaker, ein schützender Halt, der sich selbst aufhebt, und eine MCP-Tool-Oberfläche, damit ein Agent die Zelle steuern kann, ohne sie beschädigen zu können.

Läuft vollständig auf einem Laptop. Keine GPU, keine ROS-Installation, keine Hardware.


Warum das Netzwerk der schwierige Teil ist

Manipulations-Policies wollen eine GPU. Roboter wollen eine Echtzeit-Regelschleife. Das sind selten dieselbe Maschine, also sitzt das Modell in der Praxis hinter einem Netzwerk-Hop – weshalb Policies Action-Chunks ausgeben statt einzelner Schritte. Man kann nicht bei 50 Hz zu einem Inferenz-Server hin- und herpendeln, aber man kann 400 ms an Aktionen auf einmal anfordern und weiter ausführen, während der nächste Chunk unterwegs ist.

Jedes schwierige Problem in diesem Repository folgt aus diesem einen Hop:

  • Ein Chunk beschreibt eine Welt, die existierte, als die Beobachtung aufgenommen wurde. Wenn er ankommt, ist er bereits veraltet. Wie veraltet ist zu veraltet?

  • Die Regelschleife muss den Arm alle 20 ms befehligen, ob der Server nun geantwortet hat oder nicht. Was tut sie, wenn nichts Gültiges auszuführen ist?

  • Anfragen schlagen fehl, werden wiederholt und kommen in falscher Reihenfolge an. Was verhindert, dass eine ältere Antwort eine neuere überschreibt?

  • Ein Modell kann NaNs ausgeben; ein falsch versionierter Server kann Ziele für einen anderen Roboter senden. Was weigert sich, das an die Aktuatoren weiterzugeben?

Related MCP server: omni-kit-mcp

Ergebnisse

25 Seeds pro Bedingung, echtes HTTP, Fehler injiziert aus einem geseedeten RNG. python experiments/latency_sweep.py --seeds 25 --ablations

Bedingung

Aufgaben-Erfolg

sicher beendet

Median-Zeit

gehalten

Wiederaufnahmen

p50-Latenz

Stale-Ablehnungen

Retries

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 % Verlust

100%

100%

12,6 s

0,36 s

68

280 ms

222

64

lossy – 20 % Verlust

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 – Server 3 s weg

100%

100%

13,9 s

6,2 s

25

60 ms

0

24

Aufgaben-Erfolg bedeutet, dass der Würfel auf dem Ziel liegt. Sicher beendet ist bewusst eine eigene Spalte: Ein Lauf kann die Aufgabe verfehlen und trotzdem korrekt sein, denn Anhalten ist manchmal die richtige Antwort. Beides zusammenzufassen würde den Unterschied zwischen das Netzwerk war schlecht und der Roboter hat etwas getan, was er nicht hätte tun sollen verbergen.

Das Muster über die Tabelle hinweg ist das Designziel: Wenn die Verbindung schlechter wird, wird der Roboter langsamer, nicht falsch. Eine überlastete 250-ms-Verbindung verdoppelt die Zykluszeit und lehnt 222 veraltete Chunks ab; sie lässt den Würfel nicht fallen und greift nicht dorthin, wo sie nicht hingreifen sollte.

Ablationen – jede Absicherung, entfernt

Eine Sicherheitsprüfung, die man noch nie hat fehlschlagen sehen, ist eine Sicherheitsprüfung, von der man nicht behaupten kann, dass sie funktioniert.

entfernt

Aufgaben-Erfolg

Median-Zeit

Anmerkung

(nichts – Baseline congested)

100%

12,6 s

Wiederaufnahme aus dem Halt (outage)

0 %

0,5 s

verriegelnder Stopp, nimmt nie wieder auf

Staleness-Prüfung (congested)

88 %

23,7 s

führt Pläne für eine Welt aus, die sich bewegt hat

Retries (congested)

96 %

17,5 s

Adaptiver Vorlauf (congested)

100%

12,4 s

aber 1,10 s gehalten statt 0,36 s

Retries (lossy)

100%

7,9 s

ohne sie schneller – siehe unten

Was der Fehler-Sweep tatsächlich gefunden hat

Beides waren echte Defekte. Keiner war gegen einen gesunden Localhost-Server sichtbar; beide zeigten sich beim ersten Lauf des Sweeps.

1. Der Schutzstopp hatte keinen Weg zurück. Beim outage-Profil erkannte die Runtime korrekt den toten Server, hielt die Position und verriegelte einen E-Stop – und saß dann da, während der Server drei Sekunden später zurückkam. Korrekt und nutzlos. Ein Roboter, der nach jedem Netzwerk-Aussetzer einen Menschen braucht, der hinübergeht und ihn wieder scharf schaltet, wird in Woche zwei ausgesteckt.

Die Korrektur teilt ein Konzept in zwei: einen Schutzhalt, der sich in dem Moment selbst aufhebt, in dem ein gültiger Chunk ankommt, und einen verriegelten E-Stop acht Sekunden später, falls er nie ankommt. outage ging von 0 % auf 100 %, und dieselbe Änderung korrigierte congested. Die Abbildung oben ist genau diese Korrektur in Aktion.

2. Die Anforderungs-Vorlaufzeit war kürzer als die Latenz. Die Runtime forderte den nächsten Chunk an, wenn noch 120 ms an Aktionen übrig waren. Auf der überlasteten Verbindung betrug der Roundtrip 280 ms. Jede Anfrage wurde 140 ms zu spät gestellt, um nützlich zu sein, also verhungerte der Arm an fast jeder Chunk-Grenze. Kein noch so häufiges Retrying behebt eine Anfrage, die zu spät gesendet wurde – man muss früher fragen.

Die Runtime misst nun ihre eigene p95-Latenz und skaliert den Vorlauf darauf. Die gehaltene Zeit bei congested sank von 1,10 s auf 0,36 s.

3. Eine Absicherung, die sich nicht auszahlt. Beim lossy-Profil machte das Ausschalten von Retries die Sache schneller (7,9 s statt 9,8 s) ohne Verlust an Erfolgsrate und eliminierte 197 Stale-Ablehnungen. Auf einer Verbindung mit niedriger Latenz liefert das Chunking bereits die Redundanz: Wenn ein Retry ankommt, wäre eine frische Anfrage nützlicher gewesen. Retries verdienen ihren Platz bei congested (96 % → 100 %) und nicht bei lossy. Es steht in der Tabelle, weil man nur über die Absicherungen zu berichten, die funktioniert haben, genau der Weg ist, auf dem man am Ende diejenigen ausliefert, die es nicht tun.

Wie es funktioniert

        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                │

Modul

eine Aufgabe

contracts.py

jeder Typ, der über die Leitung geht, einmal definiert

clock.py

Zeit, injizierbar – real oder virtuell

sim.py

MuJoCo hinter sechs Methoden; hier gegen Hardware tauschen

policies/scripted.py

steht für ein VLA: zustandslos, gechunkt, reaktiv

server.py

die Policy, hinter HTTP

client.py

submit/poll, Deadlines, Retries, Backoff, Circuit Breaker

scheduler.py

welchen Chunks zu trauen ist, welche Aktionen auszuführen sind

safety.py

nimmt an, dass die Policy falsch liegt

runtime.py

die 50-Hz-Schleife

recording.py

MCAP-Logging

mcp_server.py

die Zelle als MCP-Tools

Drei Entscheidungen, die erwähnenswert sind:

Die Schleife blockiert nie auf dem Netzwerk. Schritt 2 sendet ab, Schritt 1 pollt, nichts wartet. Eine Regelschleife, die ein langsamer Server anhalten kann, ist keine Regelschleife.

Staleness wird ab observed_at gemessen, nicht ab Ankunft. Ein Chunk, der 300 ms zur Rückkehr gebraucht hat, ist in dem Moment, in dem er landet, 300 ms veraltet.

Sicherheitsprüfungen laufen mit zwei verschiedenen Raten. Chunk-Validierung ist teuer (Vorwärtskinematik für jede Aktion) und läuft einmal pro Chunk an der Vertrauensgrenze. Ratenbegrenzung ist billig und läuft jeden Takt. Einen schlechten Plan im Ganzen abzulehnen ist besser, als ihn in etwas subtil Falsches zu klemmen.

Der Uhr-Trick

Virtuelle Zeit läuft ~100× schneller als reale Zeit, also vergehen 400 ms Roboterzeit in 4 ms Wanduhrzeit – schneller als ein HTTP-Roundtrip zu localhost. Ohne Sorgfalt wirkt jede Antwort verspätet und das Experiment misst die Testumgebung statt der Runtime.

Deshalb blockiert SimClock.settle() in realen Sekunden, ohne virtuelle voranzutreiben. Die einzige Verzögerung, die die Runtime je beobachtet, ist die Verzögerung, die das Fehlerprofil verlangt hat. Derselbe Client-Code, dieselben Retry-Pfade, dieselbe Staleness-Logik – unter WallClock auf Hardware ist settle() ein No-op. Das ist es, was jede Zahl oben bis auf das Bit reproduzierbar macht.

Steuerung durch einen Agenten (MCP)

python -m robot_runtime.mcp_server

Zwölf Tools. Sechs schreibgeschützt (Zustand, Kameras, Fehlerprofile, Aufzeichnungen, Audit- Log), sechs, die den Roboter bewegen. Die Abschaltung ist serverseitiger Zustand, keine Aufforderung im Prompt:

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"}
  • Bewegung ist abgeschaltet; Lesen nicht; der Stopp-Knopf nie. Ein Sicherheits- kontrollelement, das man erst erreichen muss, indem man sich authentifiziert, ist kein Sicherheitskontrollelement.

  • Scharfschalten braucht einen Grund und läuft ab, und der Grund wird protokolliert.

  • Fehler sind strukturierte Ergebnisse mit einem hint, niemals Exceptions. Ein Agent, der hint: start the policy server liest, kann das Problem beheben. Ein Stacktrace lässt ihn raten.

  • Jeder Aufruf wird an ein Audit-Log angehängt, das über dieselbe Schnittstelle lesbar ist, sodass „was genau hat es aufgerufen?“ immer eine Antwort hat.

Beobachtbarkeit und Wiedergabe

Jede Episode zeichnet in MCAP auf – dem Container, in den ROS 2 loggt – auf vier Topics: /observation, /action_chunk, /command, /event. Das Event-Topic ist das, was zählt, denn es zeichnet Entscheidungen auf, nicht nur Daten:

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

Neun Zeilen, nicht die 128, die die erste Version schrieb – wiederholte Ereignisse kollabieren. Der Breaker lehnt eine Anfrage bei jedem der 50 Ticks pro Sekunde ab, in denen er offen ist, und alle fünfzig aufzuschreiben sagt nichts, was das erste nicht schon gesagt hätte.

Das Abspielen einer Aufzeichnung führt die exakten Befehle in einen frisch geseedeten Simulator aus:

$ 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

Bit-exakt. Das war es zunächst nicht: /command wurde auf sechs Dezimalstellen gerundet geloggt, was einen Mikrometer Drift zwischen einem Lauf und seiner eigenen Wiedergabe brachte. Klein – und es machte „reproduziert exakt“ falsch, was der ganze Sinn der Aufzeichnung ist.

So wird auch ein Feld-Fehler behoben: die MCAP-Datei vom Standort zurückschicken, abspielen, zusehen, wie der Arm auf dem eigenen Laptop wieder das Falsche tut.

Ausführen

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

Das venv liegt bewusst auf dem internen Laufwerk – dieses Repo sitzt auf einem exFAT- Volume, wo macOS AppleDouble-._-Dateien verstreut, die MuJoCos Plugin-Loader per dlopen laden will und daran stirbt, und die git nicht durch einen Pack-Index aufrechterhalten kann.

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 statt python für alles mit einem Viewer – auf macOS muss das Fenster den Haupt-Thread besitzen.

Tests

38 Tests, etwa fünf Sekunden, keine Mocks des zu testenden Objekts. Die Client-Tests nutzen einen Fake-Transport, aber den echten Fehler-Injektor; die Runtime-Tests laufen über echtes HTTP zu einem echten Server in einem Thread.

Drei davon sind die obigen Defekte, als Regressionen behalten: test_server_outage_holds_then_recovers, test_adaptive_lead_reduces_time_spent_holding und test_the_stage_machine_does_not_oscillate – eine frühere Policy wechselte lift→carry→lift→carry, weil sie die Höhe vor der Position prüfte.

Was das hier nicht ist

Um es klar zu sagen: Übertriebene Behauptungen gegenüber Robotik-Ingenieuren scheitern im Interview, nicht beim Screening.

  • Nur Simulation. Keine Hardware, kein Sim-to-Real-Transfer, keine Kontaktmodell-Kalibrierung gegen einen echten Panda.

  • Die Policy ist handgeschrieben, nicht gelernt. Sie ist bewusst wie eine VLA geformt — zustandslos, in Chunks aufgeteilt, sprachkonditioniert, reaktiv — damit die Laufzeit so beansprucht wird, wie sie es durch ein echtes Modell würde. Aber hier ist nichts trainiert, und es wird keine Aussage über die Modellqualität gemacht.

  • Objektposen kommen aus dem Simulator, nicht aus der Wahrnehmung. Die Observation trägt ein Kamerabild und der Contract unterstützt das; die skriptbasierte Policy ignoriert die Pixel. Eine echte Bereitstellung braucht einen Perception-Stack, und diese Lücke ist die größte hier.

  • Ein Arm, ein einzelnes starres Objekt, eine Aufgabe.

  • Kein ROS. MCAP wird verwendet, weil es der richtige Container ist und das Ökosystem es liest, aber es gibt keine Nodes, keinen TF-Baum, keine Launch-Dateien.

  • In etwa einem Tag gebaut, als fokussierte Demonstration der Laufzeitschicht.

Wie es weitergeht

Grob nach Wert geordnet:

  1. Perception in the Loop — Pose aus dem Kamerabild statt aus dem Simulator. Schließt die größte Lücke auf dieser Liste.

  2. Die Policy trainieren. Demonstrationen mit dem skriptbasierten Controller erzeugen, ein Action-Chunking-Behavior-Cloning-Modell fitten, es über denselben /predict-Contract ausliefern. Die Laufzeit sollte keine einzige geänderte Zeile benötigen — das ist die Behauptung, die das Policy-Interface aufstellt, und sie ist derzeit ungetestet.

  3. Zwei Arme, was das Chunk-Scheduling zu einem echten Koordinationsproblem macht statt zu einem Buchhaltungsproblem.

  4. Ein echter Panda, wo settle() zu einem No-op wird und jede Latenzzahl in dieser README wirklich neu gemessen wird.

Danksagungen

Panda-Modell aus MuJoCo Menagerie (Apache 2.0). Physik: MuJoCo. Logging: 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