Commit 6c42ee9f authored by GUILLOU Perceval's avatar GUILLOU Perceval Committed by Perceval Guillou
Browse files

fix soft axis and add output safe mode

parent 84d05d37
......@@ -39,7 +39,7 @@ This module implements the classes allowing the control of regulation processes
---------------------------------------------- YML file example ------------------------------------------------------------------------
-
class: Mockup # <== the controller class inheriting from 'bliss.controllers.regulator.Controller'
class: Mockup # <-- the controller class inheriting from 'bliss.controllers.regulator.Controller'
module: mockup
host: lid42
inputs:
......@@ -57,9 +57,9 @@ This module implements the classes allowing the control of regulation processes
name: heater
channel: A
unit: Volt
low_limit: 0.0 # <== minimum device value [unit]
high_limit: 100.0 # <== maximum device value [unit]
ramprate: 0.0 # <== ramprate to reach the output value [unit/s]
low_limit: 0.0 # <-- minimum device value [unit]
high_limit: 100.0 # <-- maximum device value [unit]
ramprate: 0.0 # <-- ramprate to reach the output value [unit/s]
ctrl_loops:
-
......@@ -69,12 +69,12 @@ This module implements the classes allowing the control of regulation processes
P: 0.5
I: 0.2
D: 0.0
low_limit: 0.0 # <== low limit of the PID output value. Usaually equal to 0 or -1.
high_limit: 1.0 # <== high limit of the PID output value. Usaually equal to 1.
low_limit: 0.0 # <-- low limit of the PID output value. Usaually equal to 0 or -1.
high_limit: 1.0 # <-- high limit of the PID output value. Usaually equal to 1.
frequency: 10.0
deadband: 0.05
deadband_time: 1.5
ramprate: 1.0 # <== ramprate to reach the setpoint value [input_unit/s]
ramprate: 1.0 # <-- ramprate to reach the setpoint value [input_unit/s]
wait_mode: deadband
----------------------------------------------------------------------------------------------------------------------------------------
......@@ -93,51 +93,51 @@ This module implements the classes allowing the control of regulation processes
---------------------------------------------- YML file example ------------------------------------------------------------------------
-
class: MyCustomInput # <== a custom input defined by the user and inheriting from the Input class
package: bliss.controllers.temperature.mockup # <== the module where the custom class is defined
class: MyCustomInput # <-- a custom input defined by the user and inheriting from the Input class
package: bliss.controllers.temperature.mockup # <-- the module where the custom class is defined
plugin: bliss
name: custom_input
unit: eV
-
class: MyCustomOutput # <== a custom output defined by the user and inheriting from the Output class
package: bliss.controllers.temperature.mockup # <== the module where the custom class is defined
class: MyCustomOutput # <-- a custom output defined by the user and inheriting from the Output class
package: bliss.controllers.temperature.mockup # <-- the module where the custom class is defined
plugin: bliss
name: custom_output
unit: eV
low_limit: 0.0 # <== minimum device value [unit]
high_limit: 100.0 # <== maximum device value [unit]
ramprate: 0.0 # <== ramprate to reach the output value [unit/s]
low_limit: 0.0 # <-- minimum device value [unit]
high_limit: 100.0 # <-- maximum device value [unit]
ramprate: 0.0 # <-- ramprate to reach the output value [unit/s]
-
class: Input # <== value of key 'class' could be 'Input' or 'ExternalInput', the object will be an ExternalInput
class: Input # <-- value of key 'class' could be 'Input' or 'ExternalInput', the object will be an ExternalInput
name: diode_input
device: $diode # <== a SamplingCounter
device: $diode # <-- a SamplingCounter
unit: mm
-
class: Output # <== value of key 'class' could be 'Output' or 'ExternalOutput', the object will be an ExternalOutput
class: Output # <-- value of key 'class' could be 'Output' or 'ExternalOutput', the object will be an ExternalOutput
name: robz_output
device: $robz # <== an axis
device: $robz # <-- an axis
unit: mm
low_limit: 0.0 # <== minimum device value [unit]
high_limit: 100.0 # <== minimum device value [unit]
ramprate: 0.0 # <== ramprate to reach the output value [unit/s]
low_limit: 0.0 # <-- minimum device value [unit]
high_limit: 100.0 # <-- minimum device value [unit]
ramprate: 0.0 # <-- ramprate to reach the output value [unit/s]
-
class: Loop # <== value of key 'class' could be 'Loop' or 'SoftLoop', the object will be a SoftLoop
class: Loop # <-- value of key 'class' could be 'Loop' or 'SoftLoop', the object will be a SoftLoop
name: soft_regul
input: $custom_input
output: $robz_output
P: 0.5
I: 0.2
D: 0.0
low_limit: 0.0 # <== low limit of the PID output value. Usaually equal to 0 or -1.
high_limit: 1.0 # <== high limit of the PID output value. Usaually equal to 1.
low_limit: 0.0 # <-- low limit of the PID output value. Usaually equal to 0 or -1.
high_limit: 1.0 # <-- high limit of the PID output value. Usaually equal to 1.
frequency: 10.0
deadband: 0.05
deadband_time: 1.5
......@@ -398,13 +398,6 @@ class Output:
self._start_ramping(value)
def set_min_value(self):
if self.limits[0] is not None:
self.set_value(self.limits[0])
else:
self.set_value(0)
# ----------- METHODS THAT A CHILD CLASS COULD CUSTOMIZE ------------------
def state(self):
......@@ -461,6 +454,19 @@ class Output:
else:
return self._controller.is_output_ramping(self)
def set_in_safe_mode(self):
try:
return self._controller.set_in_safe_mode(self)
except NotImplementedError:
# if self.limits[0] is not None:
# self.set_value(self.limits[0])
# else:
# self.set_value(0)
pass
# ---------------- PRIVATE METHODS -----------------------------------------------
def _set_value(self, value):
......@@ -566,6 +572,13 @@ class ExternalOutput(Output):
return self._ramp.is_ramping()
def set_in_safe_mode(self):
# if self.limits[0] is not None:
# self.set_value(self.limits[0])
# else:
# self.set_value(0)
pass
# ---------------- PRIVATE METHODS -----------------------------------------------
def _set_value(self, value):
......@@ -891,14 +904,14 @@ class Loop:
self._stop_ramping()
self._stop_regulation()
time.sleep(0.5) # wait for the regulation to be stopped
self.output.set_min_value()
self.output.set_in_safe_mode()
##--- SOFT AXIS METHODS: makes the Loop object scannable (ex: ascan(loop, ...) )
def get_axis(self):
""" Return a SoftAxis object that makes the Loop scanable """
sa = SoftAxis(
self.name,
self.input.name,
self,
position="axis_position",
move="axis_move",
......
......@@ -16,6 +16,7 @@ def SoftAxis(
position="position",
move="position",
stop=None,
state=None,
low_limit=float("-inf"),
high_limit=float("+inf"),
):
......@@ -34,6 +35,7 @@ def SoftAxis(
"position": position,
"move": move,
"stop": stop,
"state": state,
"limits": (low_limit, high_limit),
"name": name,
},
......
......@@ -90,6 +90,13 @@ class MyCustomOutput(Output):
self.device.set_value(value)
def set_in_safe_mode(self):
# if self.limits[0] is not None:
# self.set_value(self.limits[0])
# else:
# self.set_value(0)
pass
class Mockup(Controller):
""" Simulate a regulation controller.
......
......@@ -31,9 +31,9 @@ with the mandatory fields:
name: heater
channel: A
unit: Volt
low_limit: 0.0 # <== minimum device value [unit]
high_limit: 100.0 # <== maximum device value [unit]
ramprate: 0.0 # <== ramprate to reach the output value [unit/s].
low_limit: 0.0 # <-- minimum device value [unit]
high_limit: 100.0 # <-- maximum device value [unit]
ramprate: 0.0 # <-- ramprate to reach the output value [unit/s].
ctrl_loops:
-
......@@ -43,12 +43,12 @@ with the mandatory fields:
P: 0.5
I: 0.3
D: 0.0
low_limit: 0.0 # <== low limit of the PID output value. Usaually equal to 0 or -1.
high_limit: 1.0 # <== high limit of the PID output value. Usaually equal to 1.
low_limit: 0.0 # <-- low limit of the PID output value. Usaually equal to 0 or -1.
high_limit: 1.0 # <-- high limit of the PID output value. Usaually equal to 1.
frequency: 10.0
deadband: 0.4
deadband_time: 1.5
ramprate: 4.0 # <== ramprate to reach the setpoint value [input_unit/s]
ramprate: 4.0 # <-- ramprate to reach the setpoint value [input_unit/s]
"""
......@@ -122,7 +122,7 @@ class Controller:
log_info(self, "Controller:get_object: %s" % (name))
return self._objects.get(name)
# ====== init methods =========================
# ------ init methods ------------------------
def initialize(self):
"""
......@@ -157,7 +157,7 @@ class Controller:
"""
pass
# ====== get methods =========================
# ------ get methods ------------------------
def read_input(self, tinput):
"""
......@@ -215,21 +215,7 @@ class Controller:
log_info(self, "Controller:state_output: %s" % (toutput))
raise NotImplementedError
# ====== set methods =========================
def set_output_value(self, toutput, value):
"""
Set the value on the Output device.
Raises NotImplementedError if not defined by inheriting class
Args:
toutput: Output class type object
value: value for the output device (in output unit)
"""
log_info(self, "Controller:set_output_value: %s %s" % (toutput, value))
raise NotImplementedError
# ====== raw methods =========================
# ------ raw methods ------------------------
def Wraw(self, str):
"""
......@@ -266,7 +252,7 @@ class Controller:
log_info(self, "Controller:WRraw:")
raise NotImplementedError
# ====== PID methods =========================
# ------ PID methods ------------------------
def set_kp(self, tloop, kp):
"""
......@@ -346,47 +332,10 @@ class Controller:
log_info(self, "Controller:get_kd: %s" % (tloop))
raise NotImplementedError
def get_sampling_frequency(self, tloop):
"""
Get the sampling frequency (PID)
Raises NotImplementedError if not defined by inheriting class
Args:
tloop: Loop class type object
"""
log_info(self, "Controller:get_sampling_frequency: %s" % (tloop))
raise NotImplementedError
def set_sampling_frequency(self, tloop, value):
"""
Set the sampling frequency (PID)
Raises NotImplementedError if not defined by inheriting class
Args:
tloop: Loop class type object
value: the sampling frequency [Hz]
"""
log_info(self, "Controller:set_sampling_frequency: %s %s" % (tloop, value))
raise NotImplementedError
def get_pid_range(self, tloop):
"""
Get the PID range (PID output value limits)
"""
log_info(self, "Controller:get_pid_range: %s %s" % (tloop))
raise NotImplementedError
def set_pid_range(self, tloop, pid_range):
"""
Set the PID range (PID output value limits)
"""
log_info(self, "Controller:set_pid_range: %s %s" % (tloop, pid_range))
raise NotImplementedError
def start_regulation(self, tloop):
"""
Starts the regulation process.
Does NOT start the ramp, use 'start_ramp' to do so.
It must NOT start the ramp, use 'start_ramp' to do so.
Raises NotImplementedError if not defined by inheriting class
Args:
......@@ -398,7 +347,7 @@ class Controller:
def stop_regulation(self, tloop):
"""
Stops the regulation process.
Does NOT stop the ramp, use 'stop_ramp' to do so.
It must NOT stop the ramp, use 'stop_ramp' to do so.
Raises NotImplementedError if not defined by inheriting class
Args:
......@@ -407,12 +356,12 @@ class Controller:
log_info(self, "Controller:stop_regulation: %s" % (tloop))
raise NotImplementedError
# ====== setpoint methods =========================
# ------ setpoint methods ------------------------
def set_setpoint(self, tloop, sp, **kwargs):
"""
Set the current setpoint (target value).
Does NOT start the PID process, use 'start_regulation' to do so.
It must NOT start the PID process, use 'start_regulation' to do so.
Raises NotImplementedError if not defined by inheriting class
Args:
......@@ -437,14 +386,17 @@ class Controller:
log_info(self, "Controller:get_setpoint: %s" % (tloop))
raise NotImplementedError
# ====== setpoint ramping methods =========================
# ------ setpoint ramping methods ------------------------
def start_ramp(self, tloop, sp, **kwargs):
"""
Start ramping to a setpoint
Does NOT start the PID process, use 'start_regulation' to do so.
It must NOT start the PID process, use 'start_regulation' to do so.
Raises NotImplementedError if not defined by inheriting class
Replace 'Raises NotImplementedError' by 'pass' if the controller has ramping but doesn't have a method to explicitly starts the ramping.
Else if this function returns 'NotImplementedError', then the Loop 'tloop' will use a SoftRamp instead.
Args:
tloop: Loop class type object
sp: setpoint (in tloop.input unit)
......@@ -456,7 +408,7 @@ class Controller:
def stop_ramp(self, tloop):
"""
Stop the current ramping to a setpoint
Does NOT stop the PID process, use 'stop_regulation' to do so.
It must NOT stop the PID process, use 'stop_regulation' to do so.
Raises NotImplementedError if not defined by inheriting class
Args:
......@@ -557,13 +509,81 @@ class Controller:
log_info(self, "Controller:get_step: %s" % (tloop))
raise NotImplementedError
# ====== output ramping methods =========================
# ------ others ------------------------------
def _f(self):
pass
def set_in_safe_mode(self, toutput):
"""
Set the output in a safe mode (like stop heating)
Raises NotImplementedError if not defined by inheriting class
Args:
toutput: Output class type object
"""
log_info(self, "Controller:set_in_safe_mode: %s" % (toutput))
raise NotImplementedError
# ------ soft regulation only ??? ------------------------
def get_sampling_frequency(self, tloop):
"""
Get the sampling frequency (PID)
Raises NotImplementedError if not defined by inheriting class
Args:
tloop: Loop class type object
"""
log_info(self, "Controller:get_sampling_frequency: %s" % (tloop))
raise NotImplementedError
def set_sampling_frequency(self, tloop, value):
"""
Set the sampling frequency (PID)
Raises NotImplementedError if not defined by inheriting class
Args:
tloop: Loop class type object
value: the sampling frequency [Hz]
"""
log_info(self, "Controller:set_sampling_frequency: %s %s" % (tloop, value))
raise NotImplementedError
def get_pid_range(self, tloop):
"""
Get the PID range (PID output value limits)
"""
log_info(self, "Controller:get_pid_range: %s" % (tloop))
raise NotImplementedError
def set_pid_range(self, tloop, pid_range):
"""
Set the PID range (PID output value limits)
"""
log_info(self, "Controller:set_pid_range: %s %s" % (tloop, pid_range))
raise NotImplementedError
def set_output_value(self, toutput, value):
"""
Set the value on the Output device.
Raises NotImplementedError if not defined by inheriting class
Args:
toutput: Output class type object
value: value for the output device (in output unit)
"""
log_info(self, "Controller:set_output_value: %s %s" % (toutput, value))
raise NotImplementedError
def start_output_ramp(self, toutput, value, **kwargs):
"""
Start ramping on the output
Raises NotImplementedError if not defined by inheriting class
Replace 'Raises NotImplementedError' by 'pass' if the controller has output ramping but doesn't have a method to explicitly starts the output ramping.
Else if this function returns 'NotImplementedError', then the output 'toutput' will use a SoftRamp instead.
Args:
toutput: Output class type object
value: target value for the output ( in output unit )
......@@ -622,8 +642,3 @@ class Controller:
"""
log_info(self, "Controller:get_output_ramprate: %s" % (toutput))
raise NotImplementedError
# ====== others ===================================
def _f(self):
pass
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment