Files
sics/doc/programmer/motor.tex
Douglas Clowes ef68c15345 fix some typos
2012-11-28 16:26:52 +11:00

210 lines
11 KiB
TeX

\subsection{Motors}
Most neutron scattering instruments have lots of motors to drive
monochromators, samples and detectors through space.This module implements
support for them. As usual for hardware objects in SICS motors are
subdivided into a driver and the logical object.
\subsubsection{The Motor Driver}
There is a problem here. There are some data fields and functions
which must be present for any motor driver. Then there are fields
which are specific just to a special implementation of a mot
driver. There are several ways to deal with this. The way chosen for
the motor driver is a kind of overlay. The first few fields of a valid
motor driver structure MUST be specified in the same order as given
below. A special motor driver can add additional fields at the end of
the standard list. As an example for this scheme compare the
AbstractMoDriv structure with the one for the EL734 motor driver.
\begin{verbatim}
typedef struct __AbstractMoDriv {
/* general motor driver interface
fields. REQUIRED!
*/
float fUpper; /* upper limit */
float fLower; /* lower limit */
char *name;
int (*GetPosition)(void *self, float *fPos);
int (*RunTo)(void *self,float fNewVal);
int (*GetStatus)(void *self);
void (*GetError)(void *self, int *iCode, char *buffer, int iBufLen);
int (*TryAndFixIt)(void *self, int iError,float fNew);
int (*ContinueAfterWarn)(void *self);
int (*Halt)(void *self);
}
MotorDriver;
\end{verbatim}
All functions return 0 on failure or 1 on success, if not stated otherwise.
The first parameter is always a pointer to the motor driver structure.
The fields and their meanings: \begin{description}
\item[fUpper,fLower] The hardware upper and lower limits for the motor.
These are the real hardware limits as implemented by limit switches bolted
to the instrument.
\item[name] The real motor name.
\item[GetPosition] retrieves the current hardware position of the motor into
fPos.
\item[RunTo] starts the motor to run to fNewVal. This sends a command to the
motor and returns immediately.
\item[GetStatus] requests the status from the motor. Possible answers are:
\begin{description}
\item[HWIdle, OKOK] The motor has finished or is idle.
\item[HWFault] A fault has been found at the motor.
\item[HWBusy] The motor is busy moving.
\item[HWWarn] The motor hardware complained but managed to reach the
requested position.
\item[HWPosFault] The motor could not go where it should go for some reason.
However, the motor is intact and ready to move somewhere else. This can
happen when there is a concrete block in the instruments way which is not
accounted for by a limit switch. This can also happen when the motor hits a
limit switch. However, the general idea of SICS is that the limits will be
checked for before even starting to run the motor. In order for this to
work, the limits SICS knows about must macth those actually implemented.
\end{description}
\item[GetError] This gets called when an error has been detected during one
of the previous operations. The function has to return more information
about the error: iCode an driver dependent integer error code and maximum
iErrLen characters of problem description in error.
\item[TryAndFixIt] takes the integer error code returned in iCode from
GetError and tries to solve the problem with the hardware. This function can
either return MOTREDO which means the problem has been fixed and the
operation needs to be redone, MOTOK when the problem has been fixed and no
resending of a command is necessary or MOTFAIL which means that it is not
possible to resolve the problem in software.
\item[ContinueAfterWarn] will be called after a warning from the motor. This
function is supposed to do whatever is needed to clear the warning from the
motor and keep him going.
\item[Halt] emergency stop the motor, NOW.
\end{description}
As an example for a derived motor driver the SINQ EL734 motor driver is
shown below. It add to the general fields the special things for that motor:
host, port and channel number of the motor controller and a pointer to the
driver communications structure.
\begin{verbatim}
typedef struct __MoDriv {
/* general motor driver interface
fields. REQUIRED!
*/
float fUpper; /* upper limit */
float fLower; /* lower limit */
char *name;
int (*GetPosition)(void *self,float *fPos);
int (*RunTo)(void *self, float fNewVal);
int (*GetStatus)(void *self);
void (*GetError)(void *self, int *iCode, char *buffer, int iBufLen);
int (*TryAndFixIt)(void *self,int iError, float fNew);
int (*ContinueAfterWarn)(void *self);
int (*Halt)(void *self);
/* EL-734 specific fields */
int iPort;
char *hostname;
int iChannel;
int iMotor;
void *EL734struct;
int iMSR;
} EL734Driv;
\end{verbatim}
Most of the interaction with the motor driver happens through the functions
defined in its data structure. The rest is creation and deletion:
\begin{description}
\item[MotorDriver *CreateEL734(SConnection *pCon, int argc, char
*argv[])]
creates a EL734 motor driver. The argc, \verb+argv[]+ pair contains the
necessary drive parameters.
\item[MotorDriver *CreateEL734DC(SConnection *pCon, int argc, char
*argv[])]
created an EL734 DC motor driver.
\item[void KillEL734(void *pData)] deletes a EL734 motor driver.
\item[MotorDriver *CreateSIM(SConnection *pCon, int argc, char *argv[])]
creates a simulation motor driver.
\item[void KillSIM(void *pData)] deletes a simulated motor driver.
\end{description}
\subsubsection{The Motor Logical Object}
The motor object represents the motor to SICS. One of its responsibilities
is to drive motor operations and error checking. The scheme
implemented is that the motor object tries to bring the motor to its
position at least three times before a failure is recorded. Also the
motor object keeps track of a count of failed operations. If this
count gets too high an interrupt is issued to stop the instrument. This
was put in after Druechal tried to drive over a slab of concrete for a
whole night and subsequently broke a clutch.
Motors are represented by the
following data structure:
\begin{verbatim}
typedef struct __Motor {
pObjectDescriptor pDescriptor;
ObPar *ParArray;
pIDrivable pDrivInt;
pICallBack pCall;
char *drivername;
char *name;
MotorDriver *pDriver;
float fTarget;
float fPosition;
} Motor;
typedef Motor *pMotor;
\end{verbatim}
The fields: \begin{description}
\item[pDescriptor] The usual SICS object descriptor.
\item[ParArray] A dictionary of parameter names and float values. This array
holds all the different parameters used to operate the motor.
\item[pDrivInt] A pointer to the drivable interface implemented by the motor
object.
\item[pCall] A pointer to the callback interface implemented by the motor
object.
\item[drivername] The name of the motor driver.
\item[name] The name of the motor.
\item[pDriver] A pointer to the motor driver to use.
\item[fTarget] The target position for the motor.
\item[fPosition] The last known position of the motor.
\end{description}
Much of the action of the motor is hidden in the implementation of the
drivable interface to the motor. Additionally the functions as given below
are defined. All functions take a pointer to the motor object data structure
as a parameter. They return 0 on success or 1 on failure while not stated
otherwise.
\begin{description}
\item[int MotorGetPar(pMotor self, char *name, float *fVal)] retrieves the
value of the parameter name in fVal.
\item[int MotorSetPar(pMotor self, SConnection *pCon, char *name, float
fVal)] tries to write fVal to the parameter name. Errors are written to
the connection pCon.
\item[long MotorRun(void *self, SConnection *pCon, float fNew)] starts a
motor running to fNew. Does not wait for the motor to finish.
\item[int MotorCheckBoundary(pMotor self, float fVal, float *fHard,
char *error, int iErrLen)] checks if the position
fVal violates any of the motors software or hardware limits. In case of
success a new hardware position is returned in fHard. fHard is then
corrected for possible software zero points. In case of a limit violation
maximum iErrLen characters of error information are returned in error.
\item[int MotorCheckPosition(void *self, SConnection *pCon)] returns 1 if
the motor is at the target position, 0 else, or -1 if the motor could not be
read.
\item[int MotorGetSoftPosition(pMotor self,SConnection *pCon, float *fVal)]
reads the current motor position into fVal. This position is corrected for
software zero points.
\item[int MotorGetHardPosition(pMotor self,SConnection *pCon, float *fVal)]
reads the current position of the motor as returned from the hardware.
\item[int MakeMotor(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])] the motor factory function. To
be hacked when a new driver needs to be included.
\item[pMotor MotorInit(char *drivername,char *name, MotorDriver *pDriv)]
creates a new motor object with driver pDriv. Returns NULL on failure.
\item[void MotorKill(void *self)] deletes a motor object. Needs to be
modified for a new driver in order to clean out the new driver properly.
\item[int MotorAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])] the object wrapper function for
the motor. Implements the user interface.
\item[pMotor FindMotor(SicsInterp *pSics, char *name)] finds a motor name in
the interpreter pSics. This is a convenience function. Returns NULL if no
motor could be found, else a pointer to its data structure.
\end{description}