-
Notifications
You must be signed in to change notification settings - Fork 8
Systems
Systems are an essential part of the simulator, as they are essentially responsible for making the simulation happen. Systems are also very versatile and can be used not only to represent a part of the simulation, but also to extract information from it.
There are 2 different types of systems that can be used:
- systems compatible with
esper
library systems, referred to as esper systems - systems compatible with
simpy
library, referred to as DES systems.
Both are optional and the use of one or the other depends on what will be simulated by the system.
The central concept of HMR Sim is that systems are built to use a set of components in order to represent a part of the simulation. Each set of related systems (and their components) gives new capabilities to the simulator, and therefore the simulation being made. For example systems can represent sensors, movement, communication between robots, etc. Much of the flexibility that the simulator provides is in the relative ease of creating and using systems. If any system is not suitable for your needs, just replace it with another one, or modify it, without having to change other parts of the simulation. For example, if the purpose of a simulation is to compare robot management algorithms, 2 different systems (using the same components) will be created, one for each algorithm. Testing algorithm A or B becomes a simple matter of adding system A or B to the simulation.
Esper systems are those that are stored within the esper World
. They are defined as classes that extend esper.Processor
class. Every esper system must implement 2 functions: __ init__
and process
. The process function receives two arguments, self
(the World instance) and kwargs
passed by the Simulator (detailed here).
❗
To use esper systems you must define the FPS config option
These systems are managed by the World instance. They are executed every 1 / FPS simulation seconds. ALL esper systems are executed at every step. This kind of system is ideal to simulate frequent and repetitive behaviors, such as collision checks or moving entities through the simulation. The general shape of such a system is displayed below.
# ...
from simulator.components.MyComponent impor tMyComponent
from simulator.components.MyOtherComponent import MyOtherComponent
# ...
class MySystem(esper.Processor ):
def __init__(self, args):
super().__init__ ()
# initialize system
def process(self, kwargs: SystemArgs) -> None:
# Iterate over components the system is interested in
for ent, (my_comp, my_other_comp) in self.world.get_components(MyComponent, MyOtherComponent ):
# Does stuff
# ...
DES systems are managed by simpy
. They are defined as simpy processes (i.e. any generator function). It is suggested, as a convention, to use a function called process
. Optionally, they can also define a clean-up function, which will be executed at the end of the simulation. This clean-up function is used to close files that have been opened, for example. These systems "live" all within the same simpy environment, which is stored as one of the attributes of the simulation (Simulator.ENV
).
The communication between this type of system takes advantage of the events supported by simpy, using the resource EVENT_STORE
, available through kwargs. Only events (EVENT or ERROR, check the typehints) should be used within the EVENT_STORE
. Each system can export its own payload tag for events. Thus, any other system that wants to send a message to the system in question just needs to create a new event with the appropriate payload and tag and add it to EVENT_STORE
. This communication system allows the creation of reactive systems, which only process events expected by them, and the rest of the time they are disabled. Systems may create and emply their own communication schemes as well.
This type of systems are indicated to simulate inconstant or unpredictable behaviors, reactive systems or even plugins, extending the simulator. The general shape of a reactive DES system is displayed below.
# Example of custom event
MyEventPayload = NamedTuple('myPayload', [('ent',int), ('info',str)])
MyEventTag = 'MyEvent'
def process(kwargs: SystemArgs):
event_store: FilterStore = kwargs.get('EVENT_STORE', None)
# Initialize other variables
while True:
# Activates process when event arrives
ev = yield event_store.get(lambda e: e.type == MyEventTag)
# Do stuff# ...
SystemArgs
is defined as a typehint. It provides:
- ENV: simpy.Environment
- WORLD: esper.World
- _KILL_SWITCH: the event that ends the simulation when triggered
- EVENT_STORE: The event store, for communication between systems
- WINDOW_OPTIONS: width and height of the simulation, and the default line width.
Some essential systems are available, with their components as part of the simulation core. These are completely optional as you can implement your own systems and components. You can also create only new systems that reuse the provided components as well.
- Movement and Collision - 2D movement and collision checks.
- Navigation - Provides navigation capabilities to entities
- Script (or Control) - Provides automated control to entities
- Seer - Provides visualization for the simulation