Introduction to Guardian ======================== Guardian is an automation platform based on `python `_ and `EPICS `_. It was designed to meet the automation needs of the `Advanced LIGO project `_, but it should have usage in any environment where state machine automation is relevant. .. _sec_overview: Overview -------- Guardian is designed as a **hierarchical, distributed, state machine**. * Separate individual :program:`guardian` processes (*nodes*) each oversee a particular domain of the overall system. These individual domains are known in guardian as :ref:`systems `. They are represented by the blue circles in :ref:`fig_overview`. * Each system is described by a directed graph of :ref:`states `. Each state consists of code that describes a particular action on the domain, such as a change to the plant and/or verification of configuration. The states are joined together in a *directed graph* which describes the allowable transitions between states. * The guardian node processes load their state graphs and execute the state code. Commands are issued in the form of state requests. The node then determines that path from the current state to the requested state from the state graph, and executes the states on the path in sequence. * A hierarchy of nodes can be used to control a larger system. The low level nodes that talk to the plant itself are known as *device* nodes, and upper level nodes that control other lower level *subordinate* nodes are known as *manager** nodes. In :ref:`fig_overview` below, the dark blue *manager* nodes control other nodes, while the light blue *device* nodes at the bottom directly control the "front-end" hardware of the plant. This is not a strict distinction, as nodes can be *mixed*, talking both to the plant as well as directing other nodes. .. _fig_overview: .. figure:: _static/overview-full.png :width: 500px :figwidth: 600px Figure: Overview Each system is represented by a *state graph*. The state graph represents the full automation logic of the system. .. _fig_overview_graph: .. figure:: _static/overview-graph.png :width: 600px :figwidth: 700px Figure: Overview - state graph Guardian structure: state graphs -------------------------------- A guardian :ref:`system ` (i.e. an individual node in :ref:`fig_overview`) is essentially a `finite state machine `_ description of the system to be controlled (which we will refer to as the "plant"). Each system consists of a set of :ref:`states` representing a block of automation logic. They are connected by directed :ref:`edges` that represent the set of allowable transitions between states. This is all naturally described by a **directed graph**, where states of the system are graph nodes, and the allowable transitions are graph edges. The state graph describes the dynamics of the system. The nodes in the graph represent the various **states** of the system, and the edges represent the allowable transitions between states. States of the system (which are really just are represented as nodes in the graph, each consisting of executable code. Graph edges represent allowable transitions between states in the system. Edges have zero content, representing only which states are accessible from each other. .. _fig_state_graph: .. figure:: _static/graph-example.png :width: 200px :figwidth: 600px Figure: State graph of an example guardian system. The ovals represent :ref:`states` of the system. .. [#f1] Specifically a `Moore finite-state machine `_, in that the action of the system is entirely a function of the state, and the edges have no content. Guardian behavior: graph traversal ---------------------------------- As mentioned above, guardian systems define state graphs that describe the dynamics of the system: .. figure:: _static/graph-traverse_0.png :width: 200px :figwidth: 600px At any point in time, the system occupies a specific *state* in the graph. In the example below the current state is "DOWN" (blue outline): .. figure:: _static/graph-traverse_1.png :width: 200px :figwidth: 600px The system is directed in the form of a *REQUEST* state ("LOCK_PRIMARY" in thise case, red outline): .. figure:: _static/graph-traverse_2.png :width: 200px :figwidth: 600px Once a REQUEST comes in, guardian calculates the :ref:`shortest path ` (measured in number of hops) between the current state and the request. This is known as the *path* (green arrows and outlines): .. figure:: _static/graph-traverse_3.png :width: 200px :figwidth: 600px Guardian then begins executing all states in the path in sequence. Each state is executed until it returns :py:obj:`bool` that evaluates as :py:obj:`True`. States can also return a :py:obj:`str` that is interpreted as the name of a different state in the graph. In this case, guardian will immediately *jump* to that state and start executing it. This is known as a *jump transition*. Below, the "ACQUIRE" state returns the string 'TRIPPED', which causes guardian to transition immediately to the "TRIPPED" state (orange edge): .. figure:: _static/graph-traverse_4.png :width: 200px :figwidth: 600px Jumps are ways for the system to bypass the basic dynamic constraints of the graph, and are intended for when the system under control is not behaving as expected. Links ----- * `awiki/guardian`_ * `guardian SVN`_ * `cdsutils SVN`_ .. _awiki/guardian: https://awiki.ligo-wa.caltech.edu/aLIGO/Guardian .. _guardian SVN: https://redoubt.ligo-wa.caltech.edu/svn/guardian/ .. _cdsutils SVN: https://redoubt.ligo-wa.caltech.edu/svn/cdsutils/ .. _requirements: https://dcc.ligo.org/LIGO-T1300884/public