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