Welcome | spec | C-PLOT | Support | Users | Contact
 
Contents -> STANDARD MACRO GUIDE -> Motor Macros
spec Manual


3.5. - Motor Macros



    mv motor pos            # Move a motor
    mvr motor pos           # Move a motor, relatively
    mvd motor dial_pos      # Move a motor to a dial position
    tw motor inc            # Tweak a motor, interactively
    
    umv motor pos           # Move while updating screen
    umvr motor pos          # Move while updating screen
    
    wa                      # Show positions of all motors
    lm                      # Show limits of all motors
    wm m1 m2 ...            # Show positions and limits of motors
    uwm m1 m2 ...           # Show positions while motors are moving
    
    set motor pos           # Set user angle for a motor
    set_dial motor pos      # Set dial angle for a motor
    set_lm motor low high   # Set user limits for a motor
    
    an tth_pos th_pos       # Move two theta and theta
    pl chi_pos phi_pos      # Move chi and phi (four-circle)
    uan tth_pos th_pos      # Move while updating screen
    upl chi_pos phi_pos     # Move while updating screen
    


The following macro moves a single motor, adding a comment to the printer that the motor was moved:
    # Move a single motor
    def mv  '_mv $*; move_poll'
    def umv '_mv $*; _update1 $1'   # "update" version of mv
    def _mv '
          if ($# != 2) {
                  print "Usage:  mv motor position"
                  exit
          }
          _check0 "$1"
          waitmove; getangles; A[$1]=$2
          if (PRINTER != ")
                  fprintf(PRINTER,"\nmv $1 %g\n", A[$1])
          move_em
    '
    


In mv, as in all the macros that move motors, the move_em macro is invoked, rather than the move_all command. Normally, move_em is defined as
    def move_em '
          user_premove
          move_all
          user_postmove
    '
    
One can define the user_premove and/or user_postmove macros to take into account special conditions. For example, to check for limits that depend on the relative position of motors, one could define user_premove as
    def user_premove '
          if (fabs(A[tth] - A[th]) > 10) {
                  print "Move exceeds Theta - Two Theta relative limit."
                  exit
          }
          move_all
    '
    



The set macro changes the offset between user and dial units.
    # Define a new motor position
    def set '
          if ($# != 2) {
                  print "Usage:  set motor new_user_value"
                  exit
          }
          {
            local old
            _check0 "$1"
            waitmove; getangles
            old = A[$1]
            if (chg_offset($1, $2))
              exit
            getangles
            if (old != A[$1]) {
              comment "%s reset from %g to %g" "motor_name($1), old, A[$1]"
            } else
              print "No change."
          }
    '
    


The set_dial macro changes the dial position of the motor, which means a change to the contents of the motor controller register. set_dial refuses to set the dial beyond the current software limits for the motor. set_dial also changes the offset to maintain the prior value of the user angle. These two macros document the change in the data file and on the printer.

The set_lm macro converts the user-unit arguments to dial units for the call to set_lim().
    Change a motor limit
    def set_lm '
          if ($# != 3) {
                  print "Usage:  set_lm motor low high"
                  exit
          }
          {
              _check0 "$1"
              if (!set_lim($1, dial($1, $2), dial($1, $3))) {
                  onp
                  printf("\n%s limits set to %g %g (dial units).\n",\
                          motor_name($1), get_lim($1, -1), get_lim($1, +1))
                  offp
              }
          }
    '
    



The macros in the above list that begin with a u continuously read motor positions from the controller and show the positions on the screen. The frequency of screen updates is set by the global variable UPDATE, which is used as an argument to the sleep() function. Setting UPDATE=.25 places a 1/4 second pause between updates. The umv macro first calls _mv and then calls the internal _update1 macro. The other updated-move macros are defined similarly.
    def umv _'mv $*; _update1 $1 '   # "update" version of mv
    
    # Displays updated position of 1 motor while it is moving
    def _update1 '
          if (chk_move)) {
                  printf("\n%10.9s\n", motor_name($1))
                  while (wait(0x22)) {
                          getangles
                          printf("%10.4f\r", A[$1])
                          sleep(UPDATE)
                  }
                  getangles
                  printf("%10.4f\n", A[$1])
          }
    '
    


The technique for displaying status information about all the motors is a little complicated. spec places no restriction on what order the motors are assigned to the controller, but does recognize that there is a preferred order for displaying motor information. To this end, the macros use an array mA[] which contains reordered motor numbers. The four-circle macro source file contains the following code, which is executed when the command file is read and when the config macro is run.
    # Conventionally, the first four motors are tth, th, chi, phi.
    # The following code guarantees this.
    def _assign '{
          local   i j
          mA[0]=tth
          mA[1]=th
          mA[2]=chi
          mA[3]=phi
          for (i = 4, j = 0; i < MOTORS; j++) {
                  if (j == tth || j == th || j == chi || j == phi)
                          continue
                  mA[i++] = j
          }
    }'
    
Similar code is contained in the macro source files for the other geometries.


An internal macro named _mo_loop exists to loop through all the motors printing selected fields. Its use is best illustrated by example. First here is its definition:
    # Looping routine used in many macros.
    # Normally k is set to MOTORS, but can be set to something else, e.g., 4
    # (Kludge with printf(" ") avoids auto linefeed on 80th column.)
    def _mo_loop '{
          local s
          for (j = i; j < i + 8 && j < k; j++)
                  if (motor_name(mA[j]) != "unused") {
                          s = s sprintf("%$1", $2)
                          if (j < i + 7)
                                  s = s " "
                  }
          print s
    }'
    
It is within this macro that motors named unused are not used in printing motor information.

The wa macro that displays information for all motors is typical of a macro that calls the _mo_loop macro.
    # Where - all motors
    def wa '
          waitmove; get_angles
          onp
          printf("\nCurrent Positions  (user, dial)\n")
          {
                  local i j k
                  for (i = 0, k = MOTORS; i < k; i += 8) {
                          _mo_loop 9.9s "motor_name(mA[j])"
                          _mo_loop 9.9s "motor_mne(mA[j])"
                          _mo_loop 9.4f "A[mA[j]]"
                          _mo_loop 9.4f "dial(mA[j], A[mA[j]])"
                  }
          }
          offp
    '
    
The first argument for _mo_loop is a printf() field specification, the second argument is the field value. The field values use the mA[] array to reorder the motor numbers.


  Top
  Prev | Next