[MLZ] fix entangle integration
handling of mappings for NamedDigital*put needs to be improved! Change-Id: I015cb1d26d049d3caecc0e03baa9f523951f004c Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/22932 Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de> Tested-by: JenkinsCodeReview <bjoern_pedersen@frm2.tum.de>
This commit is contained in:
parent
ac03f5333f
commit
bccfe6109b
@ -1,5 +1,5 @@
|
|||||||
[node MLZ_ccr12]
|
[node MLZ_ccr12]
|
||||||
description = CCR12 box of MLZ Sample environment group
|
description = CCR box of MLZ Sample environment group
|
||||||
.
|
.
|
||||||
Contains a Lakeshore 336 and an PLC controlling the compressor
|
Contains a Lakeshore 336 and an PLC controlling the compressor
|
||||||
and some valves.
|
and some valves.
|
||||||
@ -14,58 +14,86 @@ bindport=10767
|
|||||||
class=secop_mlz.entangle.NamedDigitalOutput
|
class=secop_mlz.entangle.NamedDigitalOutput
|
||||||
tangodevice=tango://localhost:10000/box/plc/_automatik
|
tangodevice=tango://localhost:10000/box/plc/_automatik
|
||||||
mapping=dict(Off=0,p1=1,p2=2)
|
mapping=dict(Off=0,p1=1,p2=2)
|
||||||
|
description="controls the (simple) pressure regulation
|
||||||
|
.
|
||||||
|
selects between off, regulate on p1 or regulate on p2 sensor"
|
||||||
|
|
||||||
[module compressor]
|
[module compressor]
|
||||||
class=secop_mlz.entangle.NamedDigitalOutput
|
class=secop_mlz.entangle.NamedDigitalOutput
|
||||||
tangodevice=tango://localhost:10000/box/plc/_cooler_onoff
|
tangodevice=tango://localhost:10000/box/plc/_cooler_onoff
|
||||||
mapping=dict(Off=0,On=1)
|
mapping=dict(Off=0,On=1)
|
||||||
|
description=control the compressor (on/off)
|
||||||
|
|
||||||
[module gas]
|
[module gas]
|
||||||
class=secop_mlz.entangle.NamedDigitalOutput
|
class=secop_mlz.entangle.NamedDigitalOutput
|
||||||
tangodevice=tango://localhost:10000/box/plc/_gas_onoff
|
tangodevice=tango://localhost:10000/box/plc/_gas_onoff
|
||||||
mapping=dict(Off=0,On=1)
|
mapping=dict(Off=0,On=1)
|
||||||
|
description=control the gas inlet into the ccr (on/off)
|
||||||
|
.
|
||||||
|
note: this switches off automatically after 15 min.
|
||||||
|
note: activation de-activates the vacuum inlet
|
||||||
|
note: if the pressure regulation is active, it enslave this device
|
||||||
|
|
||||||
[module vacuum]
|
[module vacuum]
|
||||||
class=secop_mlz.entangle.NamedDigitalOutput
|
class=secop_mlz.entangle.NamedDigitalOutput
|
||||||
tangodevice=tango://localhost:10000/box/plc/_vacuum_Onoff
|
tangodevice=tango://localhost:10000/box/plc/_vacuum_Onoff
|
||||||
mapping=dict(Off=0,On=1)
|
mapping=dict(Off=0,On=1)
|
||||||
|
description=control the vacuum inlet into the ccr (on/off)
|
||||||
|
.
|
||||||
|
note: activation de-activates the gas inlet
|
||||||
|
note: if the pressure regulation is active, it enslave this device
|
||||||
|
|
||||||
[module p1]
|
[module p1]
|
||||||
class=secop_mlz.entangle.AnalogInput
|
class=secop_mlz.entangle.AnalogInput
|
||||||
tangodevice=tango://localhost:10000/box/plc/_p1
|
tangodevice=tango://localhost:10000/box/plc/_p1
|
||||||
value.unit='mbar'
|
value.unit='mbar'
|
||||||
|
description=pressure sensor 1 (linear scale)
|
||||||
|
|
||||||
[module p2]
|
[module p2]
|
||||||
class=secop_mlz.entangle.AnalogInput
|
class=secop_mlz.entangle.AnalogInput
|
||||||
tangodevice=tango://localhost:10000/box/plc/_p2
|
tangodevice=tango://localhost:10000/box/plc/_p2
|
||||||
value.unit='mbar'
|
value.unit='mbar'
|
||||||
|
description=pressure sensor 2 (selectable curve)
|
||||||
|
|
||||||
[module curve_p2]
|
[module curve_p2]
|
||||||
class=secop_mlz.entangle.NamedDigitalInput
|
class=secop_mlz.entangle.NamedDigitalInput
|
||||||
tangodevice=tango://localhost:10000/box/plc/_curve
|
tangodevice=tango://localhost:10000/box/plc/_curve
|
||||||
value.default='undefined'
|
value.default=0
|
||||||
mapping=dict(curve1=1,curve2=2,curve3=3)
|
description=calibration curve for pressure sensor 2
|
||||||
|
mapping="{'0-10V':0, '0-1000mbar':1, '1-9V to 0-1 mbar':2,
|
||||||
|
'DI200':3, 'DI2000':4, 'TTR100':7, 'PTR90':8,
|
||||||
|
'PTR225/237':9, 'ITR90':10, 'ITR100-D':11,
|
||||||
|
'ITR100-2':12, 'ITR100-3':13, 'ITR100-4':14,
|
||||||
|
'ITR100-5':15, 'ITR100-6':16, 'ITR100-7':17,
|
||||||
|
'ITR100-8':18, 'ITR100-9':19, 'ITR100-A':20,
|
||||||
|
'CMR361':21, 'CMR362':22, 'CMR363':23,
|
||||||
|
'CMR364':24, 'CMR365':25}"
|
||||||
|
|
||||||
# sensors
|
# sensors
|
||||||
[module T_sample]
|
[module T_sample]
|
||||||
class=secop_mlz.entangle.Sensor
|
class=secop_mlz.entangle.Sensor
|
||||||
tangodevice=tango://localhost:10000/box/sample/sensora
|
tangodevice=tango://localhost:10000/box/sample/sensora
|
||||||
value.unit='K'
|
value.unit='K'
|
||||||
|
description=sample temperature
|
||||||
|
|
||||||
[module T_stick]
|
[module T_stick]
|
||||||
class=secop_mlz.entangle.Sensor
|
class=secop_mlz.entangle.Sensor
|
||||||
tangodevice=tango://localhost:10000/box/stick/sensorb
|
tangodevice=tango://localhost:10000/box/stick/sensorb
|
||||||
value.unit='K'
|
value.unit='K'
|
||||||
|
description=temperature at bottom of sample stick
|
||||||
|
|
||||||
[module T_coldhead]
|
[module T_coldhead]
|
||||||
class=secop_mlz.entangle.Sensor
|
class=secop_mlz.entangle.Sensor
|
||||||
tangodevice=tango://localhost:10000/box/coldhead/sensorc
|
tangodevice=tango://localhost:10000/box/coldhead/sensorc
|
||||||
value.unit='K'
|
value.unit='K'
|
||||||
|
description=temperature at coldhead
|
||||||
|
|
||||||
[module T_tube]
|
[module T_tube]
|
||||||
class=secop_mlz.entangle.Sensor
|
class=secop_mlz.entangle.Sensor
|
||||||
tangodevice=tango://localhost:10000/box/tube/sensord
|
tangodevice=tango://localhost:10000/box/tube/sensord
|
||||||
value.unit='K'
|
value.unit='K'
|
||||||
|
description=temperature at thermal coupling tube <-> stick
|
||||||
|
|
||||||
|
|
||||||
# regulations
|
# regulations
|
||||||
|
|
||||||
@ -73,6 +101,7 @@ value.unit='K'
|
|||||||
class=secop_mlz.entangle.TemperatureController
|
class=secop_mlz.entangle.TemperatureController
|
||||||
tangodevice=tango://localhost:10000/box/stick/control2
|
tangodevice=tango://localhost:10000/box/stick/control2
|
||||||
heateroutput.default=0
|
heateroutput.default=0
|
||||||
|
description=regulation of stick temperature
|
||||||
ramp.default=6
|
ramp.default=6
|
||||||
speed.default=0.1
|
speed.default=0.1
|
||||||
setpoint.default=0
|
setpoint.default=0
|
||||||
@ -89,11 +118,13 @@ class=secop_mlz.entangle.AnalogOutput
|
|||||||
tangodevice=tango://localhost:10000/box/stick/range2
|
tangodevice=tango://localhost:10000/box/stick/range2
|
||||||
precision.default=1
|
precision.default=1
|
||||||
abslimits=(0,3)
|
abslimits=(0,3)
|
||||||
|
description=heaterrange for stick regulation
|
||||||
|
|
||||||
|
|
||||||
[module T_tube_regulation]
|
[module T_tube_regulation]
|
||||||
class=secop_mlz.entangle.TemperatureController
|
class=secop_mlz.entangle.TemperatureController
|
||||||
tangodevice=tango://localhost:10000/box/tube/control1
|
tangodevice=tango://localhost:10000/box/tube/control1
|
||||||
|
description=regulation of tube temperature
|
||||||
heateroutput.default=0
|
heateroutput.default=0
|
||||||
ramp.default=6
|
ramp.default=6
|
||||||
speed.default=0.1
|
speed.default=0.1
|
||||||
@ -116,4 +147,4 @@ value.unit='K'
|
|||||||
class=secop_mlz.entangle.NamedDigitalOutput
|
class=secop_mlz.entangle.NamedDigitalOutput
|
||||||
tangodevice=tango://localhost:10000/box/tube/range1
|
tangodevice=tango://localhost:10000/box/tube/range1
|
||||||
mapping=dict(Off=0, Low=1, Medium=2, High=3)
|
mapping=dict(Off=0, Low=1, Medium=2, High=3)
|
||||||
|
description=heaterrange for tube regulation
|
@ -26,10 +26,10 @@
|
|||||||
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import math
|
|
||||||
from base64 import b64decode, b64encode
|
from base64 import b64decode, b64encode
|
||||||
|
|
||||||
from secop.errors import ProgrammingError, ProtocolError, BadValueError, ConfigError
|
from secop.errors import ProgrammingError, ProtocolError, BadValueError, ConfigError
|
||||||
|
from secop.lib import clamp
|
||||||
from secop.lib.enum import Enum
|
from secop.lib.enum import Enum
|
||||||
from secop.parse import Parser
|
from secop.parse import Parser
|
||||||
from secop.properties import HasProperties, Property
|
from secop.properties import HasProperties, Property
|
||||||
@ -160,8 +160,8 @@ class Stub(DataType):
|
|||||||
class FloatRange(DataType):
|
class FloatRange(DataType):
|
||||||
"""Restricted float type"""
|
"""Restricted float type"""
|
||||||
properties = {
|
properties = {
|
||||||
'min': Property('low limit', Stub('FloatRange'), extname='min', default=float('-inf')),
|
'min': Property('low limit', Stub('FloatRange'), extname='min', default=-sys.float_info.max),
|
||||||
'max': Property('high limit', Stub('FloatRange'), extname='max', default=float('+inf')),
|
'max': Property('high limit', Stub('FloatRange'), extname='max', default=sys.float_info.max),
|
||||||
'unit': Property('physical unit', Stub('StringType'), extname='unit', default=''),
|
'unit': Property('physical unit', Stub('StringType'), extname='unit', default=''),
|
||||||
'fmtstr': Property('format string', Stub('StringType'), extname='fmtstr', default='%g'),
|
'fmtstr': Property('format string', Stub('StringType'), extname='fmtstr', default='%g'),
|
||||||
'absolute_resolution': Property('absolute resolution', Stub('FloatRange', 0),
|
'absolute_resolution': Property('absolute resolution', Stub('FloatRange', 0),
|
||||||
@ -172,10 +172,8 @@ class FloatRange(DataType):
|
|||||||
|
|
||||||
def __init__(self, minval=None, maxval=None, **kwds):
|
def __init__(self, minval=None, maxval=None, **kwds):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
if minval is not None:
|
kwds['min'] = minval if minval is not None else -sys.float_info.max
|
||||||
kwds['min'] = minval
|
kwds['max'] = maxval if maxval is not None else sys.float_info.max
|
||||||
if maxval is not None:
|
|
||||||
kwds['max'] = maxval
|
|
||||||
self.set_properties(**kwds)
|
self.set_properties(**kwds)
|
||||||
|
|
||||||
def checkProperties(self):
|
def checkProperties(self):
|
||||||
@ -192,9 +190,10 @@ class FloatRange(DataType):
|
|||||||
value = float(value)
|
value = float(value)
|
||||||
except Exception:
|
except Exception:
|
||||||
raise BadValueError('Can not __call__ %r to float' % value)
|
raise BadValueError('Can not __call__ %r to float' % value)
|
||||||
if math.isinf(value):
|
# map +/-infty to +/-max possible number
|
||||||
raise BadValueError('FloatRange does not accept infinity')
|
value = clamp(-sys.float_info.max, value, sys.float_info.max)
|
||||||
|
|
||||||
|
# now check the limits
|
||||||
prec = max(abs(value * self.relative_resolution), self.absolute_resolution)
|
prec = max(abs(value * self.relative_resolution), self.absolute_resolution)
|
||||||
if self.min - prec <= value <= self.max + prec:
|
if self.min - prec <= value <= self.max + prec:
|
||||||
return min(max(value, self.min), self.max)
|
return min(max(value, self.min), self.max)
|
||||||
|
@ -36,7 +36,7 @@ from time import sleep
|
|||||||
import PyTango
|
import PyTango
|
||||||
|
|
||||||
from secop.datatypes import ArrayOf, EnumType, \
|
from secop.datatypes import ArrayOf, EnumType, \
|
||||||
FloatRange, IntRange, StringType, TupleOf
|
FloatRange, IntRange, StringType, TupleOf, LimitsType
|
||||||
from secop.errors import CommunicationFailedError, \
|
from secop.errors import CommunicationFailedError, \
|
||||||
ConfigError, HardwareError, ProgrammingError
|
ConfigError, HardwareError, ProgrammingError
|
||||||
from secop.lib import lazy_property
|
from secop.lib import lazy_property
|
||||||
@ -429,30 +429,26 @@ class AnalogOutput(PyTangoDevice, Drivable):
|
|||||||
|
|
||||||
parameters = {
|
parameters = {
|
||||||
'userlimits': Parameter('User defined limits of device value',
|
'userlimits': Parameter('User defined limits of device value',
|
||||||
datatype=TupleOf(FloatRange(), FloatRange()),
|
datatype=LimitsType(FloatRange(unit='$')),
|
||||||
default=(float('-Inf'), float('+Inf')),
|
default=(float('-Inf'), float('+Inf')),
|
||||||
unit='main', readonly=False, poll=10,
|
readonly=False, poll=10,
|
||||||
),
|
),
|
||||||
'abslimits': Parameter('Absolute limits of device value',
|
'abslimits': Parameter('Absolute limits of device value',
|
||||||
datatype=TupleOf(FloatRange(), FloatRange()),
|
datatype=LimitsType(FloatRange(unit='$')),
|
||||||
unit='main',
|
|
||||||
),
|
),
|
||||||
'precision': Parameter('Precision of the device value (allowed deviation '
|
'precision': Parameter('Precision of the device value (allowed deviation '
|
||||||
'of stable values from target)',
|
'of stable values from target)',
|
||||||
unit='main', datatype=FloatRange(1e-38),
|
datatype=FloatRange(1e-38, unit='$'),
|
||||||
readonly=False, group='stability',
|
readonly=False, group='stability',
|
||||||
),
|
),
|
||||||
'window': Parameter('Time window for checking stabilization if > 0',
|
'window': Parameter('Time window for checking stabilization if > 0',
|
||||||
unit='s', default=60.0, readonly=False,
|
default=60.0, readonly=False,
|
||||||
datatype=FloatRange(0, 900), group='stability',
|
datatype=FloatRange(0, 900, unit='s'), group='stability',
|
||||||
),
|
),
|
||||||
'timeout': Parameter('Timeout for waiting for a stable value (if > 0)',
|
'timeout': Parameter('Timeout for waiting for a stable value (if > 0)',
|
||||||
unit='s', default=60.0, readonly=False,
|
default=60.0, readonly=False,
|
||||||
datatype=FloatRange(0, 900), group='stability',
|
datatype=FloatRange(0, 900, unit='s'), group='stability',
|
||||||
),
|
),
|
||||||
}
|
|
||||||
commands = {
|
|
||||||
'stop': Command('Stops current movement.', argument=None, result=None),
|
|
||||||
}
|
}
|
||||||
_history = ()
|
_history = ()
|
||||||
_timeout = None
|
_timeout = None
|
||||||
@ -607,12 +603,12 @@ class Actuator(AnalogOutput):
|
|||||||
|
|
||||||
parameters = {
|
parameters = {
|
||||||
'speed': Parameter('The speed of changing the value',
|
'speed': Parameter('The speed of changing the value',
|
||||||
unit='main/s', readonly=False, datatype=FloatRange(0),
|
readonly=False, datatype=FloatRange(0, unit='$/s'),
|
||||||
),
|
),
|
||||||
'ramp': Parameter('The speed of changing the value',
|
'ramp': Parameter('The speed of changing the value',
|
||||||
unit='main/min', readonly=False, datatype=FloatRange(0),
|
readonly=False, datatype=FloatRange(0, unit='$/s'),
|
||||||
poll=30,
|
poll=30,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
commands = {
|
commands = {
|
||||||
@ -647,13 +643,13 @@ class Motor(Actuator):
|
|||||||
|
|
||||||
parameters = {
|
parameters = {
|
||||||
'refpos': Parameter('Reference position',
|
'refpos': Parameter('Reference position',
|
||||||
datatype=FloatRange(), unit='main',
|
datatype=FloatRange(unit='$'),
|
||||||
),
|
),
|
||||||
'accel': Parameter('Acceleration',
|
'accel': Parameter('Acceleration',
|
||||||
datatype=FloatRange(), readonly=False, unit='main/s^2',
|
datatype=FloatRange(unit='$/s^2'), readonly=False,
|
||||||
),
|
),
|
||||||
'decel': Parameter('Deceleration',
|
'decel': Parameter('Deceleration',
|
||||||
datatype=FloatRange(), readonly=False, unit='main/s^2',
|
datatype=FloatRange(unit='$/s^2'), readonly=False,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -699,18 +695,17 @@ class TemperatureController(Actuator):
|
|||||||
datatype=TupleOf(FloatRange(), FloatRange(), FloatRange()),
|
datatype=TupleOf(FloatRange(), FloatRange(), FloatRange()),
|
||||||
readonly=False, group='pid', poll=30,
|
readonly=False, group='pid', poll=30,
|
||||||
),
|
),
|
||||||
'setpoint': Parameter('Current setpoint', datatype=FloatRange(), poll=1,
|
'setpoint': Parameter('Current setpoint', datatype=FloatRange(unit='$'), poll=1,
|
||||||
),
|
),
|
||||||
'heateroutput': Parameter('Heater output', datatype=FloatRange(), poll=1,
|
'heateroutput': Parameter('Heater output', datatype=FloatRange(), poll=1,
|
||||||
),
|
),
|
||||||
'ramp': Parameter('Temperature ramp', unit='main/min',
|
|
||||||
datatype=FloatRange(), readonly=False, poll=30),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
overrides = {
|
overrides = {
|
||||||
# We want this to be freely user-settable, and not produce a warning
|
# We want this to be freely user-settable, and not produce a warning
|
||||||
# on startup, so select a usually sensible default.
|
# on startup, so select a usually sensible default.
|
||||||
'precision': Override(default=0.1),
|
'precision': Override(default=0.1),
|
||||||
|
'ramp': Override(description='Temperature ramp'),
|
||||||
}
|
}
|
||||||
|
|
||||||
def read_ramp(self):
|
def read_ramp(self):
|
||||||
@ -761,12 +756,13 @@ class PowerSupply(Actuator):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
parameters = {
|
parameters = {
|
||||||
'ramp': Parameter('Current/voltage ramp', unit='main/min',
|
'voltage': Parameter('Actual voltage',
|
||||||
datatype=FloatRange(), readonly=False, poll=30,),
|
datatype=FloatRange(unit='V'), poll=-5),
|
||||||
'voltage': Parameter('Actual voltage', unit='V',
|
'current': Parameter('Actual current',
|
||||||
datatype=FloatRange(), poll=-5),
|
datatype=FloatRange(unit='A'), poll=-5),
|
||||||
'current': Parameter('Actual current', unit='A',
|
}
|
||||||
datatype=FloatRange(), poll=-5),
|
overrides = {
|
||||||
|
'ramp': Override(description='Current/voltage ramp'),
|
||||||
}
|
}
|
||||||
|
|
||||||
def read_ramp(self):
|
def read_ramp(self):
|
||||||
@ -807,7 +803,11 @@ class NamedDigitalInput(DigitalInput):
|
|||||||
super(NamedDigitalInput, self).initModule()
|
super(NamedDigitalInput, self).initModule()
|
||||||
try:
|
try:
|
||||||
# pylint: disable=eval-used
|
# pylint: disable=eval-used
|
||||||
self.accessibles['value'].datatype = EnumType('value', **eval(self.mapping))
|
mapping = eval(self.mapping.replace('\n', ' '))
|
||||||
|
if isinstance(mapping, str):
|
||||||
|
# pylint: disable=eval-used
|
||||||
|
mapping = eval(mapping)
|
||||||
|
self.accessibles['value'].setProperty('datatype', EnumType('value', **mapping))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise ValueError('Illegal Value for mapping: %r' % e)
|
raise ValueError('Illegal Value for mapping: %r' % e)
|
||||||
|
|
||||||
@ -874,9 +874,12 @@ class NamedDigitalOutput(DigitalOutput):
|
|||||||
super(NamedDigitalOutput, self).initModule()
|
super(NamedDigitalOutput, self).initModule()
|
||||||
try:
|
try:
|
||||||
# pylint: disable=eval-used
|
# pylint: disable=eval-used
|
||||||
self.accessibles['value'].datatype = EnumType('value', **eval(self.mapping))
|
mapping = eval(self.mapping.replace('\n', ' '))
|
||||||
# pylint: disable=eval-used
|
if isinstance(mapping, str):
|
||||||
self.accessibles['target'].datatype = EnumType('target', **eval(self.mapping))
|
# pylint: disable=eval-used
|
||||||
|
mapping = eval(mapping)
|
||||||
|
self.accessibles['value'].setProperty('datatype', EnumType('value', **mapping))
|
||||||
|
self.accessibles['target'].setProperty('datatype', EnumType('target', **mapping))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise ValueError('Illegal Value for mapping: %r' % e)
|
raise ValueError('Illegal Value for mapping: %r' % e)
|
||||||
|
|
||||||
@ -924,8 +927,8 @@ class StringIO(PyTangoDevice, Module):
|
|||||||
|
|
||||||
parameters = {
|
parameters = {
|
||||||
'bustimeout': Parameter('Communication timeout',
|
'bustimeout': Parameter('Communication timeout',
|
||||||
datatype=FloatRange(), readonly=False,
|
datatype=FloatRange(unit='s'), readonly=False,
|
||||||
unit='s', group='communication'),
|
group='communication'),
|
||||||
'endofline': Parameter('End of line',
|
'endofline': Parameter('End of line',
|
||||||
datatype=StringType(), readonly=False,
|
datatype=StringType(), readonly=False,
|
||||||
group='communication'),
|
group='communication'),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user