From 554843dd8c65a76ad7f3488c0ad111ae7d0ae40e Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Fri, 20 Dec 2019 09:55:48 +0100 Subject: [PATCH 1/4] add limit switch functionality --- sardana_tango/ctrl/TangoAttrMotorCtrl.py | 48 ++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/sardana_tango/ctrl/TangoAttrMotorCtrl.py b/sardana_tango/ctrl/TangoAttrMotorCtrl.py index 172fc4f..d9bdfb7 100755 --- a/sardana_tango/ctrl/TangoAttrMotorCtrl.py +++ b/sardana_tango/ctrl/TangoAttrMotorCtrl.py @@ -1,4 +1,3 @@ -import math import time from tango import AttrQuality, AttributeProxy, DevFailed @@ -8,6 +7,8 @@ TANGO_ATTR = 'TangoAttribute' +TANGO_LIMIT_PLUS = 'TangoLimitPlus' +TANGO_LIMIT_MINUS = 'TangoLimitMinus' FORMULA_READ = 'FormulaRead' FORMULA_WRITE = 'FormulaWrite' TANGO_ATTR_ENC = 'TangoAttributeEncoder' @@ -16,6 +17,8 @@ TAU_ATTR = 'TauAttribute' TAU_ATTR_ENC = 'TauAttributeEnc' +TAU_LIMIT_PLUS = 'TauLimitPlus' +TAU_LIMIT_MINUS = 'TauLimitMinus' MOVE_TO = 'MoveTo' MOVE_TIMEOUT = 'MoveTimeout' @@ -39,6 +42,8 @@ class TangoAttrMotorController(MotorController): ch2.FormulaWrite = 'math.pow(VALUE,2)' Each motor could use the following optional extra attributes: + +) TangoLimitPlus/Minus - Used to set the boolean attributes for limit + switches. +) TangoAttributeEncoder - Used in case you want to use another attribute (different than the TangoAttribute) when the motor's position is to be read. @@ -63,6 +68,18 @@ class TangoAttrMotorController(MotorController): ' (e.g. my/tango/dev/attr)', Access: DataAccess.ReadWrite }, + TANGO_LIMIT_PLUS: { + Type: str, + Description: 'The Tango Attribute indicating positive limit'\ + ' (e.g. my/tango/dev/limit_plus)', + Access: DataAccess.ReadWrite + }, + TANGO_LIMIT_MINUS: { + Type: str, + Description: 'The Tango Attribute indicating negative limit'\ + ' (e.g. my/tango/dev/limit_minus)', + Access: DataAccess.ReadWrite + }, FORMULA_READ: { Type: str, Description: 'The Formula to get the desired position from'\ @@ -101,6 +118,8 @@ def __init__(self, inst, props, *args, **kwargs): def AddDevice(self, axis): self.axisAttributes[axis] = {} self.axisAttributes[axis][TAU_ATTR] = None + self.axisAttributes[axis][TAU_LIMIT_PLUS] = None + self.axisAttributes[axis][TAU_LIMIT_MINUS] = None self.axisAttributes[axis][FORMULA_READ] = 'VALUE' self.axisAttributes[axis][FORMULA_WRITE] = 'VALUE' self.axisAttributes[axis][TAU_ATTR_ENC] = None @@ -118,6 +137,8 @@ def StateOne(self, axis): status = 'ok' switch_state = 0 tau_attr = self.axisAttributes[axis][TAU_ATTR] + tau_limit_plus = self.axisAttributes[axis][TAU_LIMIT_PLUS] + tau_limit_minus = self.axisAttributes[axis][TAU_LIMIT_MINUS] if tau_attr is None: return (State.Alarm, "attribute proxy is None", 0) @@ -147,8 +168,22 @@ def StateOne(self, axis): move_to - enc_threshold, move_to + enc_threshold)) - # SHOULD DEAL ALSO ABOUT LIMITS - switch_state = 0 + limit_plus = 0 + limit_minus = 0 + switch_state = MotorController.NoLimitSwitch + if tau_limit_plus: + limit_plus = tau_limit_plus.read().value + if tau_limit_minus: + limit_minus = tau_limit_minus.read().value + + if limit_plus: + switch_state |= MotorController.UpperLimitSwitch + state = State.Alarm + elif limit_minus: + switch_state |= MotorController.LowerLimitSwitch + + if (state != State.Moving) & (limit_plus | limit_minus): + state = State.Alarm return (state, status, switch_state) except Exception as e: self._log.error(" (%d) error getting state: %s" % (axis, str(e))) @@ -239,10 +274,15 @@ def SetAxisExtraPar(self, axis, name, value): self._log.debug( "SetExtraAttributePar [%d] %s = %s" % (axis, name, value)) self.axisAttributes[axis][name] = value - if name in [TANGO_ATTR, TANGO_ATTR_ENC]: + if name in [TANGO_ATTR, TANGO_ATTR_ENC, TANGO_LIMIT_PLUS, + TANGO_LIMIT_MINUS]: key = TAU_ATTR if name == TANGO_ATTR_ENC: key = TAU_ATTR_ENC + elif name == TANGO_LIMIT_PLUS: + key = TAU_LIMIT_PLUS + elif name == TANGO_LIMIT_MINUS: + key = TAU_LIMIT_MINUS try: self.axisAttributes[axis][key] = AttributeProxy(value) except Exception as e: From 5a0a003cb9dbb76249de53bc198f5174a721b401 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Mon, 14 Sep 2020 10:47:43 +0200 Subject: [PATCH 2/4] adapt tangoAttrZeroDController for Sardana v3.03 --- sardana_tango/ctrl/TangoAttrZeroDCtrl.py | 89 ++++++++++++++++-------- 1 file changed, 60 insertions(+), 29 deletions(-) diff --git a/sardana_tango/ctrl/TangoAttrZeroDCtrl.py b/sardana_tango/ctrl/TangoAttrZeroDCtrl.py index 47f5354..4b695dc 100644 --- a/sardana_tango/ctrl/TangoAttrZeroDCtrl.py +++ b/sardana_tango/ctrl/TangoAttrZeroDCtrl.py @@ -68,32 +68,48 @@ def pre_read_one(self, axis): self.devsExtraAttributes[axis][INDEX_READ_ALL] = index def read_all(self): - for dev in list(self.devices_to_read.keys()): - attributes = self.devices_to_read[dev] - dev_proxy = PoolUtil().get_device(self.inst_name, dev) - try: - values = dev_proxy.read_attributes(attributes) - except tango.DevFailed as e: - for attr in attributes: - axis = self.axis_by_tango_attribute[dev + '/' + attr] - self.devsExtraAttributes[axis][EVALUATED_VALUE] = e - except Exception as e: - self._log.error('Exception reading attributes:%s.%s' % - (dev, str(attributes))) + try: + for dev in list(self.devices_to_read.keys()): + attributes = self.devices_to_read[dev] + values = {} + try: + dev_proxy = PoolUtil().get_device(self.GetName(), dev) + # Set the list to prevent duplicated attr names + # Tango raise exception on read_attributes if there are + # duplicated attributes + attrs = list(set(attributes)) + r_values = dev_proxy.read_attributes(attrs) + values = dict(list(zip(attrs, r_values))) + except tango.DevFailed as e: + # In case of DeviceServer error + for attr in attributes: + axis = self.axis_by_tango_attribute[dev + '/' + attr] + self.devsExtraAttributes[axis][EVALUATED_VALUE] = e + self._log.debug("Exception on read the attribute:%r"%e) + except Exception as e: + self._log.error('Exception reading attributes:%s.%s' % + (dev, str(attributes))) + for attr in attributes: - axis = self.axis_by_tango_attribute[dev + '/' + attr] - formula = self.devsExtraAttributes[axis][FORMULA] - index = attributes.index(attr) - dev_attr_value = values[index] - if dev_attr_value.has_failed: - VALUE = tango.DevFailed(*dev_attr_value.get_err_stack()) - self.devsExtraAttributes[axis][EVALUATED_VALUE] = VALUE - else: - VALUE = float(dev_attr_value.value) - # just in case 'VALUE' has been written in lowercase... - value = VALUE - self.devsExtraAttributes[axis][ - EVALUATED_VALUE] = eval(formula) + axies = [] + for axis, dic in self.devsExtraAttributes.items(): + if dic[TANGO_ATTR] == dev+'/'+attr: + axies.append(axis) + for axis in axies: + if len(values) > 0: + dev_attr_value = values[attr] + if dev_attr_value.has_failed: + # In case of Attribute error + VALUE = tango.DevFailed(*dev_attr_value.get_err_stack()) + self.devsExtraAttributes[axis][EVALUATED_VALUE] = VALUE + else: + formula = self.devsExtraAttributes[axis][FORMULA] + VALUE = float(dev_attr_value.value) + value = VALUE # just in case 'VALUE' has been written in lowercase... + v = eval(formula) + self.devsExtraAttributes[axis][EVALUATED_VALUE] = v + except Exception as e: + self._log.error('Exception on read_all: %r'%e) def read_one(self, axis): value = self.devsExtraAttributes[axis][EVALUATED_VALUE] @@ -105,6 +121,7 @@ def get_axis_extra_par(self, axis, name): return self.devsExtraAttributes[axis][name] def set_axis_extra_par(self, axis, name, value): + value = value.lower() self._log.debug( 'set_axis_extra_par [%d] %s = %s' % (axis, name, value)) self.devsExtraAttributes[axis][name] = value @@ -115,9 +132,10 @@ def set_axis_extra_par(self, axis, name, value): self.devsExtraAttributes[axis][DEVICE] = dev self.devsExtraAttributes[axis][ATTRIBUTE] = attr self.axis_by_tango_attribute[value] = axis + -class TangoAttrZeroDController(ZeroDController, ReadTangoAttributes): +class TangoAttrZeroDController(ReadTangoAttributes, ZeroDController): """This controller offers as many channels as the user wants. Each channel has two _MUST_HAVE_ extra attributes: @@ -142,11 +160,9 @@ class TangoAttrZeroDController(ZeroDController, ReadTangoAttributes): MaxDevice = 1024 - axis_attributes = ReadTangoAttributes.axis_attributes - def __init__(self, inst, props, *args, **kwargs): - ZeroDController.__init__(self, inst, props, *args, **kwargs) ReadTangoAttributes.__init__(self) + ZeroDController.__init__(self, inst, props, *args, **kwargs) def AddDevice(self, axis): self.add_device(axis) @@ -177,3 +193,18 @@ def SetAxisExtraPar(self, axis, name, value): def SendToCtrl(self, in_data): return "" + + def AbortOne(self, axis): + pass + + def PreStartAll(self): + pass + + def StartOne(self, axis): + pass + + def StartAll(self): + pass + + def LoadOne(self, axis, value, repetitions, latency): + pass From 4c90ddd555d5e7a0c9ff0a301bcbf399a60e7485 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Tue, 22 Jun 2021 09:18:05 +0200 Subject: [PATCH 3/4] read state of attribute --- sardana_tango/ctrl/TangoAttrMotorCtrl.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sardana_tango/ctrl/TangoAttrMotorCtrl.py b/sardana_tango/ctrl/TangoAttrMotorCtrl.py index d9bdfb7..28cdc74 100755 --- a/sardana_tango/ctrl/TangoAttrMotorCtrl.py +++ b/sardana_tango/ctrl/TangoAttrMotorCtrl.py @@ -1,6 +1,6 @@ import time -from tango import AttrQuality, AttributeProxy, DevFailed +from tango import AttrQuality, AttributeProxy, DevFailed, DevState from sardana import State, DataAccess from sardana.pool.controller import MotorController from sardana.pool.controller import Type, Access, Description @@ -139,16 +139,16 @@ def StateOne(self, axis): tau_attr = self.axisAttributes[axis][TAU_ATTR] tau_limit_plus = self.axisAttributes[axis][TAU_LIMIT_PLUS] tau_limit_minus = self.axisAttributes[axis][TAU_LIMIT_MINUS] + enc_threshold = self.axisAttributes[axis][TANGO_ATTR_ENC_THRESHOLD] if tau_attr is None: return (State.Alarm, "attribute proxy is None", 0) if tau_attr.read().quality == AttrQuality.ATTR_CHANGING: state = State.Moving - elif self.axisAttributes[axis][MOVE_TIMEOUT] != None: + elif (self.axisAttributes[axis][MOVE_TIMEOUT] != None) and (enc_threshold > 0): tau_attr_enc = self.axisAttributes[axis][TAU_ATTR_ENC] - enc_threshold = self.axisAttributes[ - axis][TANGO_ATTR_ENC_THRESHOLD] + move_to = self.axisAttributes[axis][MOVE_TO] move_timeout = self.axisAttributes[axis][MOVE_TIMEOUT] @@ -167,6 +167,8 @@ def StateOne(self, axis): ' in [%f,%f]' % (current_pos, move_to - enc_threshold, move_to + enc_threshold)) + else: + state = tau_attr.state() limit_plus = 0 limit_minus = 0 From b1c0dfeba2ee477d775736f802e4dedd26013fa1 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Tue, 22 Jun 2021 09:44:32 +0200 Subject: [PATCH 4/4] reapply changes after pull upstream --- sardana_tango/ctrl/TangoAttrMotorCtrl.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sardana_tango/ctrl/TangoAttrMotorCtrl.py b/sardana_tango/ctrl/TangoAttrMotorCtrl.py index 3234189..deda333 100755 --- a/sardana_tango/ctrl/TangoAttrMotorCtrl.py +++ b/sardana_tango/ctrl/TangoAttrMotorCtrl.py @@ -148,10 +148,8 @@ def StateOne(self, axis): if tau_attr.read().quality == AttrQuality.ATTR_CHANGING: state = State.Moving - elif self.axisAttributes[axis][MOVE_TIMEOUT] is not None: + elif (self.axisAttributes[axis][MOVE_TIMEOUT] != None) and (enc_threshold > 0): # tau_attr_enc = self.axisAttributes[axis][TAU_ATTR_ENC] - enc_threshold = self.axisAttributes[ - axis][TANGO_ATTR_ENC_THRESHOLD] move_to = self.axisAttributes[axis][MOVE_TO] move_timeout = self.axisAttributes[axis][MOVE_TIMEOUT] @@ -171,6 +169,8 @@ def StateOne(self, axis): ' in [%f,%f]' % (current_pos, move_to - enc_threshold, move_to + enc_threshold)) + else: + state = tau_attr.state() limit_plus = 0 limit_minus = 0