Skip to content

Step 2 - Build Gateway Subsystem

The cleaner robot tutorial provides a 2D arena simulator. The simulator is not the robot gateway that users should model. It is the environment that the robot runs against.

The Librux-facing lower boundary is a simulator-backed gateway subsystem named gateway.device_gateway.

gateway.device_gateway owns the runtime bridge to the provided simulator.

  • drive commands for the mobile base
  • arm extension commands
  • digital I/O commands for gripper and disposal outputs
  • scan requests for the tutorial radar

It does not own simulator administration. Reset, trash spawn, and browser world state come from the provided simulator support API, not from the robot gateway.

The tutorial uses one compact gateway so the concept stays visible. A real robot could use one servo gateway for all motors, separate actuator and sensor gateways, or a vendor gateway that exposes several standard device API contracts.

The simulator process is separate.

tutorials/simulator/arena_server.py

It is not a Librux subsystem. run_sim_world.py starts only the simulator and browser. This step starts gateway.device_gateway as one managed package with librux launch run. Full deployment orchestration comes later, after the platform and application exist.

Run This Stage

From the installed root.

cd /opt/librux
librux launch run tutorials/subsystems/gateway.device_gateway \
  --instance gateway.device_gateway \
  --set simulator.url=http://127.0.0.1:8092 \
  --detach

Keep the simulator world from Step 1 running while this command starts. The gateway waits for the simulator API during startup because it is the robot-facing adapter over that already-running world.

Expected terminal output shape.

Launched package tutorial.robot_cleaner.device_gateway
  mode: detached
  instance: gateway.device_gateway

Open the browser with the same host rule from Step 1. For a local browser and runtime, use the following.

http://127.0.0.1:8091/

For a remote runtime host, use the following.

http://<runtime-host>:8091/

The robot still does not move from the browser. That is correct. This stage adds the gateway boundary only; there is no controller or application yet.

1. Open The Gateway Manifest

nano tutorials/subsystems/gateway.device_gateway/subsystem.yaml

The manifest declares robot-facing standard interfaces.

subsystem:
  name: gateway.device_gateway
  role: gateway

provides:
  actuator_servo:
    contract: api.actuator.servo.v1
  digital_io:
    contract: api.io.digital.output.v1
  perception_query:
    contract: api.perception.query.v1

These are public Librux contracts. The simulator remains an implementation detail behind them. A real gateway would translate the same public surfaces to EtherCAT, CAN, serial, a vendor SDK, or a simulator API. The endpoint names come from the referenced specs; the manifest does not repeat them.

2. Read The Gateway Code

nano tutorials/subsystems/gateway.device_gateway/device_gateway.py

Focus on on_initialize().

self.register_control_endpoint("servo_joint", self._servo_joint)
self.register_procedure("set_digital_output", self._set_digital_output)
self.register_procedure("get_digital_output", self._get_digital_output)
self.register_procedure("scan", self._scan)
self.register_procedure("front", self._front)
self.register_procedure("nearest", self._nearest)

The manifest and code must agree. The manifest says which contracts the gateway claims to provide; the code registers the runtime endpoints required by those contracts. servo_joint is the actuator-servo Control surface from api.actuator.servo.v1. It is intentionally registered only as a Control endpoint. Librux rejects a subsystem that exposes the same spec endpoint as both Control and Procedure because that hides timing mistakes.

The 2D arena server and state logic live in the provided support modules.

nano tutorials/simulator/arena_server.py
nano tutorials/simulator/arena.py

You normally do not modify this simulator while learning Librux. Treat it like a small IsaacSim, Gazebo, vendor SDK, or hardware environment that already exists.

3. Understand Simulator State

The browser reads simulator state directly from the provided simulator API. That API is tutorial infrastructure, not a robot gateway contract. It carries.

robot pose
trash list
scan result
score
world size

This gives the cleaner UI a single source of truth for drawing the arena.

4. Understand The Gateway Endpoints

Components never edit simulator state directly. They call robot-facing gateway endpoints.

Endpoint Called by Effect
servo_joint control timing-aware actuator clients sends base or arm actuator commands through the servo gateway surface
set_digital_output procedure gripper component and compound subsystem toggles gripper/disposal outputs
get_digital_output procedure gripper component reads a digital output state
scan procedure perception component requests a bounded object scan
front procedure perception component requests a forward field-of-view scan
nearest procedure perception component requests the nearest visible object

Reset, spawn, and world-state sync are not listed because they belong to the provided simulator API. The world is visible, but it is not the robot-facing gateway contract.

5. Validate The Manifest Shape

Deployment validation will later validate this gateway as part of the whole robot. For now, read the file and check the registered endpoint names against the contracts.

rg -n "register_control_endpoint|register_procedure" tutorials/subsystems/gateway.device_gateway/device_gateway.py

The names should match subsystem.yaml.

Cleaner Robot Graph After This Step

flowchart LR SimulatorProcess["arena_server.py<br/>provided simulator process"] Gateway["gateway.device_gateway<br/>gateway"] Browser["Browser arena"] Gateway -->|"HTTP simulator API"| SimulatorProcess Browser -->|"HTTP simulator API"| SimulatorProcess

The simulator can exist before the gateway starts. The Librux gateway subsystem is the adapter that exposes robot-facing procedures to future controls.

Verify

Inspect this stage.

librux subsystem status gateway.device_gateway

Then inspect the platform plan that will later assign the same gateway package to three robot slots.

librux deploy plan tutorials/deployments/stages/robot.deployment.yaml

Look for the following.

gateway.device_gateway [gateway] slots=actuator_gateway:actuator_servo,digital_output_gateway:digital_io,perception_gateway:perception_query

Continue to Step 3 - Add Component Subsystems.