EnsemblePSOFly.db supports fly scans of a single motor controlled by an Aerotech
Ensemble controller.  It uses the motor record to move the motor, and read
position, and to read control fields such as offset and direction.  It uses an
asyn port to talk to the controller about capabilities that the motor record
doesn't support, such as the control of PSO (position synchronized output)
pulses.

Commands to tell the Aerotech Ensemble to output pulses every scanDelta units,
beginning at startPos and ending at scan_end.  Note that the Ensemble fires
pulses at positions n*delta from the position at which the PSOCONTROL X ARM
command was invoked.  Thus, the pre-fly ("taxi") position of the motor must be
an integer multiple of scanDelta.

{start} = startPos - scanDelta
{end} = scan_end + scanDelta/2


PSOCONTROL X RESET                             ' Reset PSO.
PSOPULSE X TIME 50,25                          ' Define a pulse of width
                                               ' 50 usec, with 25 usec
                                               ' on time.

PSOOUTPUT X PULSE WINDOW MASK                  ' Set PSO output type to PULSE.
                                               ' PSO pulses are masked by
                                               ' the window.

PSOTRACK X INPUT 1                             ' Track primary encoder for
                                               ' axis.

PSODISTANCE X FIXED scanDelta UNITS              ' Set the incremental firing
                                               ' distance ((units).

PSOWINDOW X 1 INPUT 1                          ' Track primary encoder for
                                               ' Window 1.

PSOWINDOW X 1 RANGE {start},{end} UNITS        ' Set the fixed range (in units) for
                                               ' the window.

' Note that the following command establishes the origin for
' distance-based output pulses as the motor's current position.
' (i.e., it simply clears a counter that will be clocked by encoder pulses.)
PSOCONTROL X ARM                               ' Enable PSO and start tracking.

<user moves the motor from start to end>

PSOWINDOW X 1 OFF                              ' Turn off window.
PSOCONTROL X OFF                               ' Stop PSO tracking.



------------------------------------------------------------------------------
Start, end positions, etc.

Before the motor's fly motion begins, the motor is moved to the "taxi" position,
which is chosen so that the motor can accelerate to constant speed before data
acquisition begins.  For constant acceleration from a possibly nonzero base
speed, the acceleration distance is given by

	accelDist = accelTime * (baseSpeed + slewSpeed)/2

In EPICS motorRecord PVs, this is

	accelDist = motor.ACCL * (motor.VBAS + M.VELO)/2

Data acquisition occurs at N locations during the motor motion, where
	N = (endPos - startPos) / scanDelta
The locations are given by
	dataStart + i*scanDelta*dir
where i is an integer in the range [0, N-1], and
	dir = (endPos-startPos)>0 ? 1 : -1

Because of the way the Ensemble motor controller's position-synchronized output
is implemented, dataStart is determined by the taxi position and the
pulse-window open and close positions, such that the taxi position must be an
integer multiple, M, of scanDelta away from dataStart.

The taxi position must also be at least accelDist away from dataStart, giving a
lower limit on M:

	taxi = dataStart - M*scanDelta*dir <= dataStart - accelDist*dir
	M >= accelDist/scanDelta
	M = ceil(accelDist/scanDelta)


-------------------------------------------------------------------------------

The Ensemble PSO output is RS422, via an interface cable that ends with a female
DB9 connector with an entirely custom pinout that includes 5V power.  If
conversion to TTL is needed, the following chips and boards seem useful:

Analog Devices ADM483E chip

Linear Technology LTC485 chip

Microbotics SLC10422-TTL board

-------------------------------------------------------------------------------
