[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]
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
and some valves.
@ -14,58 +14,86 @@ bindport=10767
class=secop_mlz.entangle.NamedDigitalOutput
tangodevice=tango://localhost:10000/box/plc/_automatik
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]
class=secop_mlz.entangle.NamedDigitalOutput
tangodevice=tango://localhost:10000/box/plc/_cooler_onoff
mapping=dict(Off=0,On=1)
description=control the compressor (on/off)
[module gas]
class=secop_mlz.entangle.NamedDigitalOutput
tangodevice=tango://localhost:10000/box/plc/_gas_onoff
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]
class=secop_mlz.entangle.NamedDigitalOutput
tangodevice=tango://localhost:10000/box/plc/_vacuum_Onoff
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]
class=secop_mlz.entangle.AnalogInput
tangodevice=tango://localhost:10000/box/plc/_p1
value.unit='mbar'
description=pressure sensor 1 (linear scale)
[module p2]
class=secop_mlz.entangle.AnalogInput
tangodevice=tango://localhost:10000/box/plc/_p2
value.unit='mbar'
description=pressure sensor 2 (selectable curve)
[module curve_p2]
class=secop_mlz.entangle.NamedDigitalInput
tangodevice=tango://localhost:10000/box/plc/_curve
value.default='undefined'
mapping=dict(curve1=1,curve2=2,curve3=3)
value.default=0
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
[module T_sample]
class=secop_mlz.entangle.Sensor
tangodevice=tango://localhost:10000/box/sample/sensora
value.unit='K'
description=sample temperature
[module T_stick]
class=secop_mlz.entangle.Sensor
tangodevice=tango://localhost:10000/box/stick/sensorb
value.unit='K'
description=temperature at bottom of sample stick
[module T_coldhead]
class=secop_mlz.entangle.Sensor
tangodevice=tango://localhost:10000/box/coldhead/sensorc
value.unit='K'
description=temperature at coldhead
[module T_tube]
class=secop_mlz.entangle.Sensor
tangodevice=tango://localhost:10000/box/tube/sensord
value.unit='K'
description=temperature at thermal coupling tube <-> stick
# regulations
@ -73,6 +101,7 @@ value.unit='K'
class=secop_mlz.entangle.TemperatureController
tangodevice=tango://localhost:10000/box/stick/control2
heateroutput.default=0
description=regulation of stick temperature
ramp.default=6
speed.default=0.1
setpoint.default=0
@ -89,11 +118,13 @@ class=secop_mlz.entangle.AnalogOutput
tangodevice=tango://localhost:10000/box/stick/range2
precision.default=1
abslimits=(0,3)
description=heaterrange for stick regulation
[module T_tube_regulation]
class=secop_mlz.entangle.TemperatureController
tangodevice=tango://localhost:10000/box/tube/control1
description=regulation of tube temperature
heateroutput.default=0
ramp.default=6
speed.default=0.1
@ -116,4 +147,4 @@ value.unit='K'
class=secop_mlz.entangle.NamedDigitalOutput
tangodevice=tango://localhost:10000/box/tube/range1
mapping=dict(Off=0, Low=1, Medium=2, High=3)
description=heaterrange for tube regulation

View File

@ -26,10 +26,10 @@
import sys
import math
from base64 import b64decode, b64encode
from secop.errors import ProgrammingError, ProtocolError, BadValueError, ConfigError
from secop.lib import clamp
from secop.lib.enum import Enum
from secop.parse import Parser
from secop.properties import HasProperties, Property
@ -160,8 +160,8 @@ class Stub(DataType):
class FloatRange(DataType):
"""Restricted float type"""
properties = {
'min': Property('low limit', Stub('FloatRange'), extname='min', default=float('-inf')),
'max': Property('high limit', Stub('FloatRange'), extname='max', 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=sys.float_info.max),
'unit': Property('physical unit', Stub('StringType'), extname='unit', default=''),
'fmtstr': Property('format string', Stub('StringType'), extname='fmtstr', default='%g'),
'absolute_resolution': Property('absolute resolution', Stub('FloatRange', 0),
@ -172,10 +172,8 @@ class FloatRange(DataType):
def __init__(self, minval=None, maxval=None, **kwds):
super().__init__()
if minval is not None:
kwds['min'] = minval
if maxval is not None:
kwds['max'] = maxval
kwds['min'] = minval if minval is not None else -sys.float_info.max
kwds['max'] = maxval if maxval is not None else sys.float_info.max
self.set_properties(**kwds)
def checkProperties(self):
@ -192,9 +190,10 @@ class FloatRange(DataType):
value = float(value)
except Exception:
raise BadValueError('Can not __call__ %r to float' % value)
if math.isinf(value):
raise BadValueError('FloatRange does not accept infinity')
# map +/-infty to +/-max possible number
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)
if self.min - prec <= value <= self.max + prec:
return min(max(value, self.min), self.max)

View File

@ -36,7 +36,7 @@ from time import sleep
import PyTango
from secop.datatypes import ArrayOf, EnumType, \
FloatRange, IntRange, StringType, TupleOf
FloatRange, IntRange, StringType, TupleOf, LimitsType
from secop.errors import CommunicationFailedError, \
ConfigError, HardwareError, ProgrammingError
from secop.lib import lazy_property
@ -429,30 +429,26 @@ class AnalogOutput(PyTangoDevice, Drivable):
parameters = {
'userlimits': Parameter('User defined limits of device value',
datatype=TupleOf(FloatRange(), FloatRange()),
datatype=LimitsType(FloatRange(unit='$')),
default=(float('-Inf'), float('+Inf')),
unit='main', readonly=False, poll=10,
readonly=False, poll=10,
),
'abslimits': Parameter('Absolute limits of device value',
datatype=TupleOf(FloatRange(), FloatRange()),
unit='main',
datatype=LimitsType(FloatRange(unit='$')),
),
'precision': Parameter('Precision of the device value (allowed deviation '
'of stable values from target)',
unit='main', datatype=FloatRange(1e-38),
datatype=FloatRange(1e-38, unit='$'),
readonly=False, group='stability',
),
'window': Parameter('Time window for checking stabilization if > 0',
unit='s', default=60.0, readonly=False,
datatype=FloatRange(0, 900), group='stability',
),
default=60.0, readonly=False,
datatype=FloatRange(0, 900, unit='s'), group='stability',
),
'timeout': Parameter('Timeout for waiting for a stable value (if > 0)',
unit='s', default=60.0, readonly=False,
datatype=FloatRange(0, 900), group='stability',
),
}
commands = {
'stop': Command('Stops current movement.', argument=None, result=None),
default=60.0, readonly=False,
datatype=FloatRange(0, 900, unit='s'), group='stability',
),
}
_history = ()
_timeout = None
@ -607,12 +603,12 @@ class Actuator(AnalogOutput):
parameters = {
'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',
unit='main/min', readonly=False, datatype=FloatRange(0),
poll=30,
),
readonly=False, datatype=FloatRange(0, unit='$/s'),
poll=30,
),
}
commands = {
@ -647,13 +643,13 @@ class Motor(Actuator):
parameters = {
'refpos': Parameter('Reference position',
datatype=FloatRange(), unit='main',
datatype=FloatRange(unit='$'),
),
'accel': Parameter('Acceleration',
datatype=FloatRange(), readonly=False, unit='main/s^2',
datatype=FloatRange(unit='$/s^2'), readonly=False,
),
'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()),
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,
),
'ramp': Parameter('Temperature ramp', unit='main/min',
datatype=FloatRange(), readonly=False, poll=30),
}
overrides = {
# We want this to be freely user-settable, and not produce a warning
# on startup, so select a usually sensible default.
'precision': Override(default=0.1),
'ramp': Override(description='Temperature ramp'),
}
def read_ramp(self):
@ -761,12 +756,13 @@ class PowerSupply(Actuator):
"""
parameters = {
'ramp': Parameter('Current/voltage ramp', unit='main/min',
datatype=FloatRange(), readonly=False, poll=30,),
'voltage': Parameter('Actual voltage', unit='V',
datatype=FloatRange(), poll=-5),
'current': Parameter('Actual current', unit='A',
datatype=FloatRange(), poll=-5),
'voltage': Parameter('Actual voltage',
datatype=FloatRange(unit='V'), poll=-5),
'current': Parameter('Actual current',
datatype=FloatRange(unit='A'), poll=-5),
}
overrides = {
'ramp': Override(description='Current/voltage ramp'),
}
def read_ramp(self):
@ -807,7 +803,11 @@ class NamedDigitalInput(DigitalInput):
super(NamedDigitalInput, self).initModule()
try:
# 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:
raise ValueError('Illegal Value for mapping: %r' % e)
@ -874,9 +874,12 @@ class NamedDigitalOutput(DigitalOutput):
super(NamedDigitalOutput, self).initModule()
try:
# pylint: disable=eval-used
self.accessibles['value'].datatype = EnumType('value', **eval(self.mapping))
# pylint: disable=eval-used
self.accessibles['target'].datatype = EnumType('target', **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))
self.accessibles['target'].setProperty('datatype', EnumType('target', **mapping))
except Exception as e:
raise ValueError('Illegal Value for mapping: %r' % e)
@ -924,8 +927,8 @@ class StringIO(PyTangoDevice, Module):
parameters = {
'bustimeout': Parameter('Communication timeout',
datatype=FloatRange(), readonly=False,
unit='s', group='communication'),
datatype=FloatRange(unit='s'), readonly=False,
group='communication'),
'endofline': Parameter('End of line',
datatype=StringType(), readonly=False,
group='communication'),