esrf

Beamline Instrument Software Support
SPEC Macro documentation: [ Macro Index | BCU Home ]

#%TITLE% KB_MIRROR.MAC 
#%NAME%
#  Define height and tilt pseudomotors for KB mirror
#
#%CATEGORY% Positioning
#
#%DESCRIPTION%
"""
  A kb mirror is controlled typically by two rotation motors. 
  One, main rotation, is located at the middle of the mirror
  while a second one is set in an eccentric point. The
  combination of both allows to drive the mirror (the center
  of it) to a certain 'tilt' angle and 'height' (for vertically
  positioned mirrors, but we will use the 'height' term for 
  all mirrors). 

  This macro set supports both pseudo motor style definition
  or macro motors directly in spec.

  Rotation angles are in milli-radians, distance in millimeters

  For pseudo motors:
  ------------------
     Define tilt and height motors as controller NONE in spec config

     In setup, for each mirror, add a line like:
          mirrorsetup kbrot kbecrot kbtilt kbhgt 85 

     (in the example 85 is the distance between the two rotation points)

  For macro motors:
  ----------------- 
     Add a MAC_MOT motor controller in spec config. 
             Device field = "kb"

     Add motors tilt and height in config with controller pointing to
        MAC_MOT "kb" controller

     Set channels as: 
        channel 0 = tilt
        channel 1 = height

     Add !! manually !! in config files MOT_PAR lines to the
        tilt (channel 0) motor. (Just add lines after MOTXXX line
        correspoding to tilt motor

     MOTPAR:distance = 85 
     MOTPAR:kbrot = kbrot  
     MOTPAR:kbecrot = kbecrot  

     (in the example kbrot and kbecrot are the mnemonics for
      real motors (rotation and eccentric rotation). 85 is the
      distance between the two rotation points )
     
     Remember that one single kb motor controller is needed for
     several mirrors.  In that case it is necessary to define the
     module field in the unit/mod/chan parameter in the motor
     configuration in spec config. 
"""
#%END%

global MIRROR_MNAME MIRROR_OLDPOS 
global MIRROR_LEN

#%UU%  <motor1> <motor2> <tilt> <offset> <distance>
#%MDESC%
# This macro allow to configure pseudo motors to control a KB-Mirror. %BR%
# A Kb_mirror is made with 2 motors mounted in leving-arm mode, one in the middle
# position of the mirror and one at the left side of the mirror: %BR%
# motor1 does a pure rotation of the mirror and motor2 does a kind of translation.%BR%
# So the mirror is rotated by moving m1 and tilt position = m2+m1.%BR%
# So the mirror is translated by moving first m1 of +delta and m2 of -delta and
# offset position  = - m2 . %BR%
# %BR%
# m2 and m1 have to be configured in mradian unit and with a clokwise rotation.%BR%
#%PRE%
#              X-Ray             
#    <-------------------------- 
#        <-  d   ->               
#       o=========o==========     
#       |         |               
#       |         |               
#       | <==     |<==           
#       | m2        m1            
#     ==== base                   
#%PRE%
#
# Note: with small mirror check how the motor m1 is mounted and its position motion direction.
# on BM05 m1 moves the mirror in the opposite direction of m2. So the SPEC sign into the config is -1.
# long mirror is "correctly" mounted.
def mirrorsetup '{

  #
  # Store motor mnemonics used
  #

  if ($# != 5){
    print "Usage:mirrorsetup <motor1> <motor2> <tilt> <offset> <distance>"
    exit
  }

  MIRROR_MNAME[0]="$1"  # Motor1
  MIRROR_MNAME[1]="$2"  # Motor2 
  MIRROR_MNAME[2]="$3"  # Tilt
  MIRROR_MNAME[3]="$4"  # Offset
  MIRROR_LEN=$5       # Distance on mirror

  #
  # register hooks for SPEC
  #

  mirror_pdef

}'

#%UU%  <tilt> <offset>
#%MDESC%
def mirrorunsetup '{
  MIRROR_MNAME[2]="$1"  # Tilt
  MIRROR_MNAME[3]="$2"  # Offset

  cdef ("","",MIRROR_MNAME[2],"delete")
  cdef ("","",MIRROR_MNAME[3],"delete")
}'

#%IU%
#%MDESC%
def mirror_getangle '{
    local _position _sign

    _position = A[$2] + A[$3]
    _sign     = user($1, 2) - user ($1, 1)
    A[$1]     = _position * _sign

    MIRROR_OLDPOS[$1]=A[$1]
}'

#%IU%
#%MDESC%
def mirror_getheight '{
    local _multi _position _sign

    _multi = $4
    _position = A[$3] * (-1.0) * _multi / 1000.0
    _sign     = user($1, 2) - user ($1, 1)
    A[$1]     = _position * _sign

    MIRROR_OLDPOS[$1]=A[$1]
}'

#%IU%
#%MDESC%
def mirror_moveangle '{
    local _sign

    if (A[$1]!=MIRROR_OLDPOS[$1]) {
       _sign   = user($1, 2) - user ($1, 1)
       A[$2] += (A[$1] - MIRROR_OLDPOS[$1]) * _sign
    }
}'

#%IU%
#%MDESC%
def mirror_moveheight '{
    local _multi _sign _pos 

    if (A[$1]!=MIRROR_OLDPOS[$1]) {
       _multi = 1000.0 / $4
       _sign  = user($1, 2) - user ($1, 1)

      #
      # check first the limits of the second motor 
      # before moving the first one.
      #
      _pos = (A[$1] - MIRROR_OLDPOS[$1]) * _multi * _sign

      _m2pos = A[$3] - _pos  
      _bad_lim=0
      _chk_lim $3 _m2pos

      if (_bad_lim) exit

      A[$2] += _pos
      move_all;waitmove;
      A[$3] -= _pos
   }
}'

#%IU%
#%MDESC%
def mirror_setuser '{
    local delta _multi _sign _pos

    delta = position2set - A[motor2set]

    if (motor2set == $2) {
         # height
         _multi = 1 / $5
         _multi = _multi * 1000.0
         _sign  = user($2, 2) - user ($2, 1)

         chg_offset($3,A[$3]+ delta *_multi *_sign)
         chg_offset($4,A[$4]- delta *_multi *_sign)

    } else if (motor2set == $1) {
        # angle
         chg_offset($3,A[$3]+delta)
    } 
}'

#%IU%
#%MDESC%
def mirror_pdef '{
  cdef("user_checkall",sprintf("mirror_moveheight %s %s %s %f;"\
	,MIRROR_MNAME[3],MIRROR_MNAME[0],MIRROR_MNAME[1], MIRROR_LEN),MIRROR_MNAME[3],0x21)
  cdef("user_getpangles",sprintf("mirror_getheight %s %s %s %f;"\
	,MIRROR_MNAME[3],MIRROR_MNAME[0],MIRROR_MNAME[1], MIRROR_LEN),MIRROR_MNAME[3],0x11)
  cdef("user_checkall",sprintf("mirror_moveangle %s %s %s ;"\
	,MIRROR_MNAME[2],MIRROR_MNAME[0],MIRROR_MNAME[1]),MIRROR_MNAME[2],0x21)
  cdef("user_getpangles",sprintf("mirror_getangle %s %s %s ;"\
	,MIRROR_MNAME[2],MIRROR_MNAME[0],MIRROR_MNAME[1]),MIRROR_MNAME[2],0x11)
#LC 10/06/2004
  cdef("user_set",sprintf("mirror_setuser %s %s %s %s %f;"\
        ,MIRROR_MNAME[2],MIRROR_MNAME[3],MIRROR_MNAME[0],MIRROR_MNAME[1], MIRROR_LEN)\
        ,MIRROR_MNAME[3],0x1)
}'

#
#  Macros to support macro motor funcitonality
#
def kb_config(mne,type,unit,module,chan) '{

     local _master, _kbrot, _kbecrot, _distance

     if ( type == "ctrl") return

     _master   = motor_par(mne,    "chan0")
  
     _kbrot    = motor_par(_master,"kbrot")
     _kbecrot  = motor_par(_master,"kbecrot")
     _distance = motor_par(_master,"distance")

     if (motor_num(_kbrot) == -1  || motor_num(_kbecrot) == -1) {
          return ".error."
     }

     motor_par(mne,     "master",    _master,  "add")

     if (chan == 0) {  #  Tilt

        #  save my role and inform the master
        motor_par(mne,     "role",  "tilt",  "add")
        motor_par(_master, "tilt",  motor_mne(mne),  "add")

        #
        # save interesting motor_par for real motors
        #    master, distance and role
        # they will be needed later in kb_calc
        #
        motor_par(_kbrot,   "master", mne, "add")
        motor_par(_kbecrot, "master", mne, "add")
        
        motor_par(_kbrot,   "distance", distance, "add")
        motor_par(_kbecrot, "distance", distance, "add")

        motor_par(_kbrot,    "role",  "kbrot", "add") 
        motor_par(_kbecrot,  "role",  "kbecrot", "add") 
     } else if (chan == 1) {  # Height
        #  save my role and inform the master
        motor_par(mne,    "role",    "height",  "add")
        motor_par(_master, "height",  motor_mne(mne),  "add")
     } else {
        print "Wrong channel assignment for kb_mirror macro motors. Only 0 or 1"
        return ".error."
     } 

     # return dependency on real motors

     return sprintf("%s %s", _kbrot, _kbecrot)
}'

def kb_calc(mne,mode) '{

   local  _motnum,  _role, _master, _distance
   local  _kbrot,  _kbecrot, _kbrotnum, _kbecrotnum 
   local  _tilt, _hgt, _tiltnum, _hgtnum

   _motnum = motor_num(mne)

   if (mne == "..") return

   #
   # role and master have been set on kb_config for all motors,
   # both real and macro motors
   #
   _role     = motor_par(mne, "role")
   _master   = motor_par(mne, "master")

   if ( mode == 0 ) {  # getangles... calculate macro mot positions

       _distance   = motor_par(_master, "distance")
       _kbrot      = motor_par(_master,"kbrot")
       _kbecrot    = motor_par(_master,"kbecrot")
       _kbrotnum   = motor_num(_kbrot)
       _kbecrotnum = motor_num(_kbecrot)

       if ( _role == "tilt") {
           A[_motnum] = A[_kbrotnum] + A[_kbecrotnum]
       } else if ( _role == "height") {
           A[_motnum] = - A[_kbecrotnum]  * _distance / 1000.0
       }
   } else {  # mode = 1. calculate real positions from macro motors

       _tilt     = motor_par(_master,"tilt")
       _hgt      = motor_par(_master,"height")
       _distance = motor_par(_master, "distance")

       _tiltnum  = motor_num(_tilt)
       _hgtnum   = motor_num(_hgt)

       if ( _role == "kbrot") {
            A[_motnum] = A[_tiltnum] +  A[_hgtnum] * 1000.0 / _distance
       } else if ( _role == "kbecrot") {
            A[_motnum] = - A[_hgtnum] * 1000.0 / _distance
       }  
   }
}'

#%MACROS%
#%IMACROS%
#%DEPENDENCIES%
#  The file kb_mirror.mac has to be loaded      ! done in idxxsetup.mac
#  (This file needs pseudo.mac stlocal.mac)
#%AUTHOR%
#  KB_MIRROR.MAC 
#%TOC%