Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Supervisor actions #628

Merged
merged 11 commits into from
Feb 20, 2024
110 changes: 103 additions & 7 deletions docs/agents/hwp_supervisor_agent.rst
Original file line number Diff line number Diff line change
Expand Up @@ -67,17 +67,113 @@ This agent has two main purposes:
- Serve as a host for high-level HWP operations that require coordinated control
of various HWP subsystems, such as "Begin rotating at 2 Hz"

Right now only the first point is implemented, but operations can be added here
as we need them.

HWP subsystems should implement a ``monitor_shutdown`` process that uses the
``get_op_data`` function to get the hwp-supervisor's session data, and check
the ``action`` field to determine if shutdown should be initiated.

For the first point, the supervisor agent implements the ``monitor`` process,
which monitors HWP-related processes to compile full state info for the HWP, and uses
that to make a determination if the HWP should be shutdown.

For high-level control, the HWP supervisor implements a state machine that
is used to perform complex operations with HWP agents that depend on the global
state of the HWP and related hardware.

Control States and Actions
`````````````````````````````
In the context of the HWP supervisor state machine, a *Control State* is a python
dataclass that contains data to dictate what the supervisor will do on each
update call. For example, while in the ``WaitForTargetFreq`` state, the
supervisor will do nothing until the HWP frequency is within tolerance of a
specified freq for a specified period of time, at which point it will transition
into the Done state.

A *Control Action* is a user-requested operation, where a starting state can
transition through any number of states before completing. The action object
BrianJKoopman marked this conversation as resolved.
Show resolved Hide resolved
contains its current state, state history, completion status, and whether it
considers itself successful. The action is considered "complete" when it
transitions into a "completion state", which can be ``Done``, ``Error``,
``Abort``, or ``Idle``, at which point no more state transitions will occur.
In between update calls, a control action may be aborted by the state-machine,
where the action will transition into the completed "Abort" state, and no further
action will be taken.

OCS agent operations are generally one-to-one with control actions, where each
operation begins a new action, and sleeps until that action is complete.
If an operation is started while there is already an action is in progress, the
current action will be aborted at the next opportunity and replaced with the new
requested action. The ``abort_action`` task can be used to abort the current
action without beginning a new one.

Examples
```````````
Below is an example client script that runs the PID to freq operation, and waits
until the target freq has been reached.

.. code-block:: python

supervisor = OCSClient("hwp-supervisor")

result = supervisor.pid_to_freq(target_freq=2.0)
print(result.session['data']['action'])

>> {'action_id': 6,
'completed': True,
'cur_state': {'class': 'Done', 'msg': None, 'success': True},
'state_history': [{'class': 'PIDToFreq',
'direction': '0',
'freq_tol': 0.05,
'freq_tol_duration': 10.0,
'target_freq': 2.0},
{'class': 'WaitForTargetFreq',
'freq_tol': 0.05,
'freq_tol_duration': 10.0,
'freq_within_tol_start': 1706829677.7613404,
'target_freq': 2.0},
{'class': 'Done', 'msg': None, 'success': True}],
'success': True}

Below is an example of a client script that starts to PID the HWP to 2 Hz, then
aborts the PID action, and shuts off the PMX power supply. Note that the
``abort_action`` here is technically redundant, since starting the new action
would abort the active action in the same manner.

.. code-block:: python

supervisor = OCSClient("hwp-supervisor")

supervisor.pid_to_freq.start(target_freq=2.0)
supervisor.abort_action()
res1 = supervisor.pid_to_freq.wait()
res2 = supervisor.pmx_off()

print("Result 1:")
print(res1.session['data']['action'])
print("Result 2: ")
print(res2.session['data']['action'])

>>
Result 1:
{'action_id': 1,
'completed': True,
'cur_state': {'class': 'Abort'},
'state_history': [{'class': 'PIDToFreq',
'direction': '0',
'freq_tol': 0.05,
'freq_tol_duration': 10.0,
'target_freq': 2.0},
{'class': 'Abort'}],
'success': False}
Result 2:
{'action_id': 3,
'completed': True,
'cur_state': {'class': 'Done', 'msg': None, 'success': True},
'state_history': [{'class': 'PmxOff', 'success': True},
{'class': 'Done', 'msg': None, 'success': True}],
'success': True}

Agent API
-----------

.. autoclass:: socs.agents.hwp_supervisor.agent.ControlAction
:members:

.. autoclass:: socs.agents.hwp_supervisor.agent.HWPSupervisor
:members:

Expand Down
Loading
Loading