Simple mirrors have a height and an angle. These degrees of freedom can be implemented as VmExecutors, as described in the following. The height is called m3x, the angle m3pitch.
The Tango configuration:
VmExecutor M3 VmExecutor p29/vmexecutor/m3pitch Property MOTOR_BACK: p29/motor/eh.06 MOTOR_FRONT: p29/motor/eh.05 USE_DEGREES: True or False BASE_LENGTH: 850. VmCode: /usr/local/experiment/Tango/VmCode/mirrorAngle.py p29/vmexecutor/m3x Property MOTOR_BACK: p29/motor/eh.06 MOTOR_FRONT: p29/motor/eh.05 USE_DEGREES: True or False VmCode: /usr/local/experiment/Tango/VmCode/mirrorHeight.py
Notice that the motors belonging to the mirror M3 are operated by the VmExecutor instance named M3.
The entries in /online_dir/online.xml are:
<device> <name>m3pitch</name> <type>type_tango</type> <module>motor_tango</module> <device>p29/vmexecutor/m3pitch</device> <control>tango</control> <hostname>hasep29oh:10000</hostname> </device> <device> <name>m3x</name> <type>type_tango</type> <module>motor_tango</module> <device>p29/vmexecutor/m3x</device> <control>tango</control> <hostname>hasep29oh:10000</hostname> </device>
After SardanaAIO.py is executed, the motors m3pitch and m3x are available.
The mirrorHeight.py code creates a GenericMirrorHeight object using the properties: MOTOR_BACK, MOTOR_FRONT and USE_DEGREES.
#!/bin/env python ”' file name: /usr/local/experiment/Tango/VmCode/mirrorHeight.py This VmExecutor instantiates an object of the GenericMirrorHeight class. The parameters MOTOR_FRONT MOTOR_BACK USE_DEGREES are supplied as properties. ”' import GenericMirror import PyTango import inspect import HasyUtils class VM: # # init_device # def __init__( self): self.parent = inspect.currentframe().f_back.f_locals['self'] self.parentProxy = PyTango.DeviceProxy( self.parent.get_name()) frontName = HasyUtils.getDeviceProperty( self.parent.get_name(), "MOTOR_FRONT")[0] backName = HasyUtils.getDeviceProperty( self.parent.get_name(), "MOTOR_BACK")[0] useDegrees = bool(HasyUtils.getDeviceProperty( self.parent.get_name(), "USE_DEGREES")[0]) self.genericMirrorHeight = GenericMirror.GenericMirrorHeight( motorFront = frontName, motorBack = backName, useDegrees = useDegrees) return # # dev_state # def dev_state( self): return self.genericMirrorHeight.dev_state() # # Position # def read_Position( self): return self.genericMirrorHeight.read_Position() def write_Position( self, argin): return self.genericMirrorHeight.write_Position( argin) # # UnitLimitMax # def read_UnitLimitMax( self): return self.genericMirrorHeight.read_UnitLimitMax() def write_UnitLimitMax( self, argin): return self.genericMirrorHeight.write_UnitLimitMax( argin) # # UnitLimitMin # def read_UnitLimitMin( self): return self.genericMirrorHeight.read_UnitLimitMin() def write_UnitLimitMin( self, argin): return self.genericMirrorHeight.write_UnitLimitMin( argin) # # CwLimit, CcwLimit # def read_CwLimit( self): return self.genericMirrorHeight.read_CwLimit() def read_CcwLimit( self): return self.genericMirrorHeight.read_CcwLimit() def StopMove( self): return self.genericMirrorHeight.StopMove() def Calibrate(self, argin): return self.genericMirrorHeight.Calibrate( argin) # # PositionSim # def read_PositionSim( self): return self.genericMirrorHeight.read_PositionSim() def write_PositionSim( self, argin): return self.genericMirrorHeight.write_PositionSim( argin) def read_ResultSim( self): return self.genericMirrorHeight.read_ResultSim()
The mirrorAngle.py code creates a GenericMirrorAngle object using the properties: MOTOR_BACK, MOTOR_FRONT, BASE_LENGTH and USE_DEGREES.
#!/bin/env python ”' file name: /usr/local/experiment/Tango/VmCode/mirrorAngle.py This VmExecutor instantiates an object of the GenericMirrorAngle class. The parameters MOTOR_FRONT MOTOR_BACK BASE_LENGTH USE_DEGREES are supplied as properties. ”' import PyTango import GenericMirror import inspect import HasyUtils class VM: # # init_device # def __init__( self): self.parent = inspect.currentframe().f_back.f_locals['self'] frontName = HasyUtils.getDeviceProperty( self.parent.get_name(), "MOTOR_FRONT")[0] backName = HasyUtils.getDeviceProperty( self.parent.get_name(), "MOTOR_BACK")[0] baseLength = float( HasyUtils.getDeviceProperty( self.parent.get_name(), "BASE_LENGTH")[0]) useDegrees = bool(HasyUtils.getDeviceProperty( self.parent.get_name(), "USE_DEGREES")[0]) self.genericMirrorAngle = GenericMirror.GenericMirrorAngle( motorFront = frontName, motorBack = backName, base = baseLength, useDegrees = useDegrees) return # # dev_state # def dev_state( self): return self.genericMirrorAngle.dev_state() # # Position # def read_Position( self): return self.genericMirrorAngle.read_Position() def write_Position( self, argin): return self.genericMirrorAngle.write_Position( argin) # # UnitLimitMax # def read_UnitLimitMax( self): return self.genericMirrorAngle.read_UnitLimitMax() def write_UnitLimitMax( self, argin): return self.genericMirrorAngle.write_UnitLimitMax( argin) # # UnitLimitMin # def read_UnitLimitMin( self): return self.genericMirrorAngle.read_UnitLimitMin() def write_UnitLimitMin( self, argin): return self.genericMirrorAngle.write_UnitLimitMin( argin) # # CwLimit, CcwLimit # def read_CwLimit( self): return self.genericMirrorAngle.read_CwLimit() def read_CcwLimit( self): return self.genericMirrorAngle.read_CcwLimit() def StopMove( self): return self.genericMirrorAngle.StopMove() def Calibrate(self, argin): return self.genericMirrorAngle.Calibrate( argin) # # PositionSim # def read_PositionSim( self): return self.genericMirrorAngle.read_PositionSim() def write_PositionSim( self, argin): return self.genericMirrorAngle.write_PositionSim( argin) def read_ResultSim( self): return self.genericMirrorAngle.read_ResultSim()
The scripts mirrorHeight.py and mirrorAngle.py make use of the GenericMirror module:
#!/bin/env python # # file name: /usr/local/experiment/Tango/VmCode/GenericMirror.py # import PyTango import math class GenericMirror( object): def __init__( self, motorFront = None, motorBack = None): self.PositionSim = 0 self.ResultSim = [] self.ResultSim.append("Horizontal Centering: PositionSim not set") self.ResultSim.append("mirror_front: PositionSim not set") self.ResultSim.append("mirror_back: PositionSim not set") self.motorFront = motorFront self.motorBack = motorBack self.proxyFront = PyTango.DeviceProxy( motorFront) self.proxyBack = PyTango.DeviceProxy( motorBack) # # need a list for certain actions # self.proxies = [] self.proxies.append( self.proxyFront) self.proxies.append( self.proxyBack) # # dev_state # def dev_state( self): argout = PyTango.DevState.ON # # if one device is in FAULT the VM is in FAULT too # for proxy in self.proxies: if proxy.state() == PyTango.DevState.FAULT: argout = PyTango.DevState.FAULT return argout # # if one device is MOVING the VM is MOVING too # for proxy in self.proxies: if proxy.state() == PyTango.DevState.MOVING: argout = PyTango.DevState.MOVING return argout return argout # # CwLimit, CcwLimit # def read_CwLimit( self): argout = 0 # # if one of the motors is in the limit return 1 # for proxy in self.proxies: if proxy.CwLimit == 1: argout = 1 break return argout def read_CcwLimit( self): argout = 0 # # if one of the motors is in the limit return 1 # for proxy in self.proxies: if proxy.CcwLimit == 1: argout = 1 break return argout def StopMove( self): for proxy in self.proxies: proxy.StopMove() return 1 def Calibrate(self, argin): PyTango.Except.throw_exception( "genericMirror.calibrate", "calibrate motors individually", "VmExecutor") class GenericMirrorHeight( GenericMirror): # # init_device # def __init__( self, motorFront = None, motorBack = None, useDegrees = True): super( GenericMirrorHeight, self).__init__( motorFront = motorFront, motorBack = motorBack) self.useDegrees = useDegrees return # # Position # def read_Position( self): position = (self.proxyFront.Position + self.proxyBack.Position)/2. return position def write_Position( self, argin): pos_front = self.proxyFront.position pos_back = self.proxyBack.position center = (pos_back + pos_front)/2. diff = argin - center self.proxyFront.Position = pos_front + diff self.proxyBack.Position = pos_back + diff return 1 # # UnitLimitMax # def read_UnitLimitMax( self): pos_back = self.proxyBack.position pos_front = self.proxyFront.position center = (pos_back + pos_front)/2. # # to preserve the angle, the difference between the motors # has to stay constant # diff = abs(pos_back - pos_front) # # calculate the free space for the front and the back motor # diff_front = self.proxyFront.UnitLimitMax - pos_front diff_back = self.proxyBack.UnitLimitMax - pos_back if diff_back < diff_front: unitLimitMax = center + diff_back else: unitLimitMax = center + diff_front if center > unitLimitMax: PyTango.Except.throw_exception( "m3y.read_unitLimitMax", "UnitLimitMax %g is below position %g" % (unitLimitMax, center), "VmExecutor") return unitLimitMax def write_UnitLimitMax( self, argin): PyTango.Except.throw_exception( "GenericMirrorHeight", "UnitLimitMax can not be written", "VmExecutor") # # UnitLimitMin # def read_UnitLimitMin( self): pos_back = self.proxyBack.position pos_front = self.proxyFront.position center = (pos_back + pos_front)/2. diff = abs(pos_back - pos_front) diff_front = pos_front - self.proxyFront.UnitLimitMin diff_back = pos_back - self.proxyBack.UnitLimitMin if diff_back < diff_front: unitLimitMin = center - diff_back else: unitLimitMin = center - diff_front if center < unitLimitMin: PyTango.Except.throw_exception( "m3y.read_unitLimitMin", "UnitLimitMin %g is above position %g" % (unitLimitMin, center), "VmExecutor") return unitLimitMin def write_UnitLimitMin( self, argin): PyTango.Except.throw_exception( "GenericMirrorHeight", "UnitLimitMin can not be written", "VmExecutor") # # PositionSim # def read_PositionSim( self): return self.PositionSim def write_PositionSim( self, argin): pos_front = self.proxyFront.position pos_back = self.proxyBack.position center = (pos_back + pos_front)/2. diff = argin - center self.ResultSim[0] = "center: %g " % argin self.ResultSim[1] = "front: %g " % (pos_front + diff) self.ResultSim[2] = "back: %g " % (pos_back + diff) def read_ResultSim( self): return self.ResultSim # # # class GenericMirrorAngle( GenericMirror): # # init_device # def __init__( self, motorFront = None, motorBack = None, base = None, useDegrees = True): super( GenericMirrorAngle, self).__init__( motorFront = motorFront, motorBack = motorBack) self.base = base self.useDegrees = useDegrees return # # Position # def read_Position( self): diff = self.proxyBack.Position - self.proxyFront.Position if self.useDegrees: argout = math.degrees(math.atan( diff/self.base)) else: argout = math.atan( diff/self.base) return argout def write_Position( self, argin): if self.useDegrees: diff = math.tan( math.radians(argin))*self.base else: diff = math.tan( argin)*self.base center = (self.proxyFront.Position + self.proxyBack.Position)/2. self.proxyFront.Position = center - diff/2. self.proxyBack.Position = center + diff/2. return 1 # # UnitLimitMax # def read_UnitLimitMax( self): center = (self.proxyFront.Position + self.proxyBack.Position)/2. # # diff_front, diff_back are the avaible space for the # front and the back motor. # diff_front = center - self.proxyFront.UnitLimitMin diff_back = self.proxyBack.UnitLimitMax - center diff = min( diff_front, diff_back) if self.proxyFront.UnitLimitMin > self.proxyBack.UnitLimitMax: diff = -diff # # factor 2.: self.base/2. is the adjacent side w.r.t. diff # delta = self.proxyBack.UnitLimitMax - self.proxyFront.UnitLimitMin mean = (self.proxyBack.UnitLimitMax + self.proxyFront.UnitLimitMin)/2. diff1 = delta - center + mean if self.useDegrees: argout = math.degrees(math.atan( 2.*diff/self.base)) else: argout = math.atan( 2.*diff/self.base) return argout def write_UnitLimitMax( self, argin): PyTango.Except.throw_exception( "GenericMirrorAngle", "UnitLimitMax can not be written", "VmExecutor") # # UnitLimitMin # def read_UnitLimitMin( self): center = (self.proxyFront.Position + self.proxyBack.Position)/2. diff_front = self.proxyFront.UnitLimitMax - center diff_back = center - self.proxyBack.UnitLimitMin diff = min( diff_front, diff_back) if self.proxyFront.UnitLimitMax > self.proxyBack.UnitLimitMin: diff = -diff if self.useDegrees: argout = math.degrees(math.atan( 2.*diff/self.base)) else: argout = math.atan( 2.*diff/self.base) return argout def write_UnitLimitMin( self, argin): PyTango.Except.throw_exception( "GenericMirrorAngle", "UnitLimitMin can not be written", "VmExecutor") # # PositionSim # def read_PositionSim( self): return self.PositionSim def write_PositionSim( self, argin): self.PositionSim = argin if self.useDegrees: diff = math.tan( math.radians(argin))*self.base else: diff = math.tan( argin)*self.base center = (self.proxyFront.Position + self.proxyBack.Position)/2. self.ResultSim[0] = "angle: %g " % argin self.ResultSim[1] = "front: %g " % (center - diff/2.) self.ResultSim[2] = "back: %g " % (center + diff/2.) def read_ResultSim( self): return self.ResultSim