Skip to content

Spatial Model And Frame Graph

R2Kernel treats spatial composition as part of the robot architecture, not as an application-specific Event topic. A subsystem can participate in a frame graph without exposing transforms as a public communication contract.

The model has four layers.

component spec = which spatial ports a compatible component must expose
subsystem manifest = which local frames implement those ports
compound manifest = how bound subsystem ports are mounted together
runtime frame graph = live static and dynamic transforms for this deployment

Spatial Ports Are Not Communication Interfaces

provides and requires declare communication contracts. Spatial ports declare physical attachment and reference-frame boundaries. A spatial port does not create an Event, Control, Procedure, or Operation endpoint.

Every public component spec explicitly declares whether it participates.

spatial:
  participation: required
  ports:
    base:
      direction: import
      semantic: mounting_frame
    tool:
      direction: export
      semantic: tool_frame

Use participation: none when spatial topology is not meaningful for that component. This is explicit so a provider cannot silently omit required frame semantics.

Concrete Frame Mapping

A subsystem maps the component ports to names local to its own process.

spatial:
  participation: required
  ports:
    base:
      direction: import
      frame: arm_base
    tool:
      direction: export
      frame: tool0

Local names do not need to be globally unique. The runtime qualifies them as <subsystem>/<frame>, for example component.arm/tool0.

An alias can also resolve a port through a required binding. This is useful when a compound subsystem re-exports the frame of a bound component.

spatial:
  participation: required
  ports:
    body:
      direction: export
      source:
        requirement: mobility
        port: body

Compound Mounts

A compound subsystem owns the static topology between the subsystems that form its body. Mount endpoints refer to logical requirements, so the topology remains valid when deployment chooses a different compatible provider.

spatial:
  participation: required
  mounts:
    - name: arm_on_body
      parent:
        requirement: mobility
        port: body
      child:
        requirement: manipulation
        port: base
      transform:
        translation: [0.18, 0.0, 0.12]
        rotation_xyzw: [0.0, 0.0, 0.0, 1.0]

The parent port must export a frame and the child port must import one. The deployment validator resolves both through current bindings and rejects missing ports, invalid directions, cycles, and multiple parents.

Dynamic Transform Ownership

The subsystem that computes a changing relationship owns that transform. A localizer can report world -> base, while a manipulator component can report arm_base -> tool0. The compound declares only the static mount between the mobile body and the arm base.

Python example.

self.set_frame_transform(
    parent_frame="world",
    child_frame="base_link",
    translation=(x, y, 0.0),
    rotation_xyzw=(0.0, 0.0, qz, qw),
    observed_at_sync_ns=self.now_ns(),
    stale_after_ms=500,
)

C++ uses r2kernel::FrameTransform with Subsystem::set_frame_transform(). Updates use a lightweight runtime path. The regular heartbeat still carries a complete snapshot so the graph recovers after a control-backend restart.

Runtime Lookup And Diagnostics

Inspect the current graph.

r2kernel frame graph

Resolve one frame into another.

r2kernel frame lookup component.mobile/world component.manipulation/tool0

The same data is available through Host Control REST.

GET /api/v1/control/frames
GET /api/v1/control/frames/lookup?source=<frame>&target=<frame>

Dynamic edges have a stale deadline. Stale edges remain visible for diagnosis but are excluded from lookup. The graph also reports unresolved ports, invalid mounts, cycles, and frames with multiple parents.

What The Robot Manifest Owns

The robot manifest still names the reusable platform, slots, and application-facing capabilities. It does not duplicate concrete frame topology. Runtime topology is owned by subsystem spatial declarations and the compound subsystem that connects them.