herostools.actor.control_loop
=============================

.. py:module:: herostools.actor.control_loop

.. autoapi-nested-parse::

   Control loop implementations.



Classes
-------

.. autoapisummary::

   herostools.actor.control_loop.ControlLoop
   herostools.actor.control_loop.PIDControlLoop


Module Contents
---------------

.. py:class:: ControlLoop(sensor: object | heros.RemoteHERO, actor: object | heros.RemoteHERO, actor_parameter: str, initial_set_value: float, actor_min: float | None = None, actor_max: float | None = None, loop: asyncio.AbstractEventLoop | None = None, update_rate: float = 1.0, autostart: bool = True)

   Base class for (slow) control loops.

   It measures the value of a sensor that implements the atomiq `Measurable` interface and and acts on an actor that
   implements the atomiq `Parametrizable` interface. This makes it a versatile tool that can be used for a large
   number of slow control tasks.

   This class provides a basic structure for implementing control loops. Subclasses should implement the
   `_next_control_value` method to define the specific control logic. See `PIDControlLoop` for an example.

   :param sensor: object that measures the value to be controlled. Must implement the `Measurable` interface
   :param actor: object that can act on the value to be controlled. Must implement the `Parametrizable` interface
   :param actor_parameter: name of the parameter to act on in the actor.
   :param initial_set_value: set value when the control loop starts. Can be changed during operation.
   :param actor_min: minimum value to set for the control parameter on the actor.
   :param actor_max: maximum value to set for the control parameter on the actor.
   :param loop: asyncio loop to be used for control loop
   :param update_rate: rate at which values should be measured and the actor should be updated in Hz (default 1Hz).
   :param autostart: whether to close the control loop upon startup.


   .. py:attribute:: set_value
      :type:  float
      :value: 0.0



   .. py:attribute:: sensor


   .. py:attribute:: actor


   .. py:attribute:: actor_parameter


   .. py:attribute:: _loop


   .. py:attribute:: update_rate
      :value: 1.0



   .. py:attribute:: _running
      :value: False



   .. py:attribute:: actor_min
      :value: None



   .. py:attribute:: actor_max
      :value: None



   .. py:attribute:: _run_flag


   .. py:attribute:: _stop_flag


   .. py:attribute:: _loop_task


   .. py:property:: running


   .. py:method:: start_loop() -> None

      Close the control loop.



   .. py:method:: stop_loop() -> None

      Open the control loop.



   .. py:method:: _destroy_hero()


   .. py:method:: _next_control_value(input_value: float) -> float
      :abstractmethod:



   .. py:method:: _actor_value_bounded(value) -> float


   .. py:method:: _mainloop()
      :async:



   .. py:method:: _emit_observable_data(input_value: float, output_value: float) -> None


.. py:class:: PIDControlLoop(sensor: object | heros.RemoteHERO, actor: object | heros.RemoteHERO, actor_parameter: str, initial_set_value: float, actor_min: float | None = None, actor_max: float | None = None, loop: asyncio.AbstractEventLoop | None = None, update_rate: float = 1.0, autostart: bool = True, default_p: float = 1.0, default_i: float = 0.0, default_d: float = 0.0, integral_limit: float | None = None)

   Bases: :py:obj:`ControlLoop`


   PID (Proportional-Integral-Derivative) control loop.

       This class implements a PID control loop, which is a common control loop
       feedback mechanism widely used in industrial control systems. The PID
       controller calculates an "error" value as the difference between a desired
       setpoint and a measured process variable and attempts to minimize the error
       by adjusting the process control inputs.

       The PID formula is given by:

       .. math :: u(t) = K_p e(t) + K_i \int_{0}^{t} e(    au) \, d        au + K_d
   rac{de(t)}{dt}

       where:
       - ( u(t) ) is the control signal,
       - ( e(t) ) is the error (difference between the setpoint and the measured value),
       - ( K_p ) is the proportional gain,
       - ( K_i ) is the integral gain,
       - ( K_d ) is the derivative gain.

       Args:
           sensor: object that measures the value to be controlled. Must implement the `Measurable` interface
           actor: object that can act on the value to be controlled. Must implement the `Parametrizable` interface
           actor_parameter: name of the parameter to act on in the actor.
           initial_set_value: set value when the control loop starts. Can be changed during operation.
           actor_min: minimum value to set for the control parameter on the actor.
           actor_max: maximum value to set for the control parameter on the actor.
           loop: asyncio loop to be used for control loop
           update_rate: rate at which values should be measured and the actor should be updated in Hz (default 1Hz).
           autostart: whether to close the control loop upon startup.
           default_p: initial value to set for the proportional gain. Can be changed during operation.
           default_i: initial value to set for the integral gain. Can be changed during operation.
           default_d: initial value to set for the differential gain. Can be changed during operation.



   .. py:attribute:: p
      :type:  float


   .. py:attribute:: i
      :type:  float


   .. py:attribute:: d
      :type:  float


   .. py:attribute:: integral
      :type:  float


   .. py:attribute:: last_value
      :value: 0.0



   .. py:attribute:: integral_limit
      :value: None



   .. py:method:: reset_integral()

      Reset the time integral of the error to zero.



   .. py:method:: _next_control_value(input_value: float) -> float

      Calculate the next value to set on the actor with the PID formula.



   .. py:method:: _emit_observable_data(input_value: float, output_value: float) -> None


