Mirrors

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