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.