Configuration System#

This article will cover the config module and explain why it was created.

See also

See Config Registry for how to register your own classes with this system.

Why does the config system exist?#

RobotSwarmSimulator is designed for simulations to be definable with Python code, but also for simulation objects to be modified easily in an object-oriented way.

This is why world and agent must be created using dataclasses: it allows us to inherit properties from the base class in a much more manageable way. This also separates the configuration from the object itself, so the parameters of agent instance can be moved around, copied, or modified without needing to have an actual agent instance.

controllers and other simulation objects use dict s for configuration for the same reason.

However, sometimes this can be cumbersome.

Take this example from the Basic Usage guide:

Run a simulation purely using Python#
from swarmsim.world.RectangularWorld import RectangularWorld, RectangularWorldConfig
from swarmsim.agent.control.StaticController import StaticController
from swarmsim.world.spawners.AgentSpawner import PointAgentSpawner
from swarmsim.agent.MazeAgent import MazeAgent, MazeAgentConfig
from swarmsim.world.simulate import main as sim

world_config = RectangularWorldConfig(size=(10, 10), time_step=1 / 40)
world = RectangularWorld(world_config)
controller = StaticController(output=[0.01, 0])
agent = MazeAgent(MazeAgentConfig(position=(5, 5), agent_radius=0.1,
                                  controller=controller), world)
spawner = PointAgentSpawner(world, n=6, facing="away", avoid_overlap=True,
                            agent=agent, oneshot=True)
world.spawners.append(spawner)

sim(world)

This allows for you to have a lot of control over the simulated world and how the agents behave, but look at how messy it is to define the world and agents. It’s difficult to read, and you also have to remember what order to define the objects in.

And if you want to run the simulation with a different configuration, you have to make an entirely new Python file, even if most of the code is the same. That’s not so bad for a simple simulation like this, but when you start building training programs around these simulations, it can get very messy.

The config system is designed to make this easier by allowing you to define a lot of the simulation in a single file with easy-to-read YAML.

For example, the above simulation can be defined in a single file like this:

world.yaml#
type: "RectangularWorld"
size:  # in meters
  - 10
  - 10
time_step: !np 1 / 40
spawners:
  - type: PointAgentSpawner
    oneshot: true
    n: 6
    facing: away
    avoid_overlap: true
    agent:
      type: MazeAgent
      position: [5, 5]
      agent_radius: 0.1
      controller:
        type: StaticController
        output: [0.01, 0]

Then, we can run the simulation with:

Run a simulation using world.yaml#
from swarmsim.world.RectangularWorld import RectangularWorldConfig
from swarmsim.world.simulate import main as sim

world_config = RectangularWorldConfig.from_yaml('world.yaml')

sim(world_config)

Now, if we need to change the simulation, we only need to change the world.yaml file. And we can save different .yaml files for different simulations.

Our yaml module also provides a custom YAML loader that defines some nice tags, such as the !np tag for numpy objects and the !include tag for including other YAML files as a mapping.

This allows you to do cool things like:

world.yaml (example)#
type: "RectangularWorld"
size: [10, 10]  # yaml flow style
agents:
- !include robot1.yaml  # add robot1 agent
- !include robot2.yaml  # add robot2 agent
- &anchor003  # save this robot as an anchor
  type: MazeAgent
  name: robot3
  agent_radius: 0.1
  angle: !np radians(90 + 45)  # convert degrees to radians
  poly: !include body_shape.svg  # load an SVG file
  controller:
    type: StaticController
    output: !np [1e-2, pi / 2]  # pi constant from numpy
spawners:
- type: ExcelSpawner
  path: !relpath positions.xlsx  # path is relative to cwd or this YAML file
  agent: *anchor003  # use the robot3 agent from above