[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:
Enrico Faulhaber 2020-04-09 11:32:28 +02:00
parent ac03f5333f
commit bccfe6109b
3 changed files with 83 additions and 50 deletions

View File

@ -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

View File

@ -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)

View File

@ -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,31 +429,27 @@ 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
_moving = False _moving = False
@ -607,10 +603,10 @@ 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,
), ),
} }
@ -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', ' '))
if isinstance(mapping, str):
# pylint: disable=eval-used # pylint: disable=eval-used
self.accessibles['target'].datatype = EnumType('target', **eval(self.mapping)) 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'),