spec

Software for Diffraction

1.3.10. - Moving Motors



A primary purpose of spec is to manipulate an X-ray diffractometer according to a calculated geometry. The automation of the angular settings is accomplished through the use of motor controllers interfaced to the computer. spec can be configured to control any number of motors.

As explained earlier, motor positions are referred to as dial positions and user positions. The diffractometer is operated in user positions. Dial positions are used to provide a stable point of reference. The two differ possibly by a sign and/or an offset. Dial positions should be set to always agree with the physical dials of the diffractometer motors. The user positions are then set in the line-up procedure of the diffractometer. For example, they may be set to zero at the direct beam. The relations between the two positions are:
dial = hardware_register / steps_per_unit
user = sign × dial + offset
The hardware_register contains the value maintained by the stepper motor controller. The value of steps_per_unit is assigned in the hardware configuration file, as is sign. The latter must be chosen to agree with the conventions of the built-in geometry calculations.

The motor positions are often placed in the A[] array. The array is built-in and its elements can be used like any other variables. What makes it special, however, are the commands that use the array to convey the positions of the diffractometer motors. For example, the command getangles sets all of the elements of the A[] array to the current motor positions in user angles, while the move_all command sends the motors to the positions contained in A[] (in user angles). Typical usage is,
1.FOURC> waitmove       # Make sure no motors are active.
2.FOURC> getangles # load A[] with user angles.
3.FOURC> A[0] = 3 # move motor #0 to 3.
4.FOURC> move_all # start the move.
5.FOURC>

(The # symbols introduce comments.) It is important to first wait for any previous motions to complete. Then getangles is used to load the angle array with the current positions. Only the values for the motors to be moved are reassigned before using move_all to set the motors in motion.

A macro that would list the user positions of all the configured motors might be:
1.FOURC> def wa '
2.quot>     getangles
3.quot>     for (i = 0; i < MOTORS; i++)
4.quot>         printf("%9.9s = %g\n", motor_name(i), A[i])
5.quot> '
6.FOURC> wa
Two Theta = 3 Theta = 1.5 Chi = 0 Phi = 0 7.FOURC>


The motor_name() function returns the motor name assigned in the configuration file.

The motor positions are stored in three locations: in program memory, on the computer's hard disk and in the hardware registers associated with the motor controller. The program manipulates the angles in its memory. The values on the hard disk are updated every time a motor is moved but are only read when the program is initialized, or after the reconfig command is invoked. The controller registers count the actual number of steps moved and should be the true positions of the motors (unless a motor was switched off). Before each motor is moved, the controller registers are compared with program memory. If there are discrepancies, you are notified and asked which value is correct. The sync command can also be used to synchronize the controller registers with program memory. The angles can get out-of-sync by moving the motors with manual controls, by turning off the power to motor controllers or perhaps by a computer crash.

Although the motor controllers work in steps, it is much more convenient to use real units such as degrees (or, for linear motion, millimeters). The user and dial angles are in these units, converted from steps by the step-size parameters that are read from the configuration file.

The chg_dial(motor, dial_angle) function sets the dial register to dial_angle for one motor. The chg_offset(motor, user_angle) function sets the offset used to convert from dial positions to user positions for one motor. Often during the line-up procedure you will want to zero a particular angle:
1.FOURC> chg_offset(th, 0)  # set motor theta to zero
2.FOURC>

The set macro includes the above and documents the change on the printer and in the data file.
1.FOURC> set th 0
Wed Aug 19 11:53:33 1987. Theta reset from 1.5 to 0 2.FOURC>



Dial and user settings may also be set by the spec administrator using the program edconf. See 5.5.2 in the Administrator's Guide for further details.

Usually, diffractometer motions have a limit of travel, beyond which physical damage may occur (or a hardware limit switch tripped). Software limits therefore exist to prevent you from accidentally moving a motor out of range. The lower and upper limits for each motor are contained in internal arrays accessed through the set_lim(motor_number, low, high) and get_lim(motor_number, flag) functions. With the latter, the lower limit is returned if flag is less than zero, otherwise the upper limit is returned.

If a move_all command would take any motor outside of its limits, an error message is printed and no motors are moved. The limit values are stored in dial angles since they correspond to physical limitations to the motion. The limit values are therefore preserved as the user-angle offsets are changed. The set_lm macro can be used to set a single motor's limits:
1.FOURC> set_lm tth 0 360
Two theta limits set to 0 360 (dial units). 2.FOURC>

The angle arguments to the macro set_lm are given in user angles. (In this example, dial and user angles are the same.)