- First working version of the triple axis UB matrix code

This commit is contained in:
koennecke
2005-05-13 07:40:57 +00:00
parent d0a535faa3
commit 6145b513f8
16 changed files with 1681 additions and 527 deletions

644
tasdrive.c Normal file
View File

@@ -0,0 +1,644 @@
/*---------------------------------------------------------------------
SICS interface to the triple axis drivable motors.
copyright: see file COPYRIGHT
Mark Koennecke, May 2005
--------------------------------------------------------------------*/
#include <assert.h>
#include "sics.h"
#include "tasdrive.h"
#define ABS(x) (x < 0 ? -(x) : (x))
#define MOTPREC .01
/*------------------- motor indexes in motor data structure ---------
WARNING: have to match tasub.c !!!!!
--------------------------------------------------------------------*/
#define A1 0
#define A2 1
#define MCV 2
#define MCH 3
#define A3 4
#define A4 5
#define SGU 6
#define SGL 7
#define A5 8
#define A6 9
#define ACV 10
#define ACH 11
/*============== Drivable Interface functions =====================*/
static int TASSetValue(void *pData, SConnection *pCon,
float value){
ptasMot self = (ptasMot)pData;
assert(self);
setTasPar(&self->math->target,self->math->tasMode,self->code,value);
self->math->mustDrive = 1;
return OKOK;
}
/*----------------------------------------------------------------*/
static int readTASMotAngles(ptasUB self, SConnection *pCon,
ptasAngles ang){
int status;
float val, theta;
/*
Monochromator
*/
status = MotorGetSoftPosition(self->motors[A1],pCon,&val);
if(status == 0){
return status;
}
theta = val;
status = MotorGetSoftPosition(self->motors[A2],pCon,&val);
if(status == 0){
return status;
}
ang->monochromator_two_theta = val;
if(ABS(val/2. - theta) > .1){
SCWrite(pCon,"WARNING: theta monochromator not half of two theta",eWarning);
}
/*
Analyzer
*/
status = MotorGetSoftPosition(self->motors[A5],pCon,&val);
if(status == 0){
return status;
}
theta = val;
status = MotorGetSoftPosition(self->motors[A6],pCon,&val);
if(status == 0){
return status;
}
ang->analyzer_two_theta = val;
if(ABS(val/2. - theta) > .1){
SCWrite(pCon,"WARNING: theta analyzer not half of two theta",eWarning);
}
/*
crystal
*/
status = MotorGetSoftPosition(self->motors[A3],pCon,&val);
if(status == 0){
return status;
}
ang->a3 = val;
status = MotorGetSoftPosition(self->motors[A4],pCon,&val);
if(status == 0){
return status;
}
ang->sample_two_theta = val;
status = MotorGetSoftPosition(self->motors[SGU],pCon,&val);
if(status == 0){
return status;
}
ang->sgu = val;
status = MotorGetSoftPosition(self->motors[SGL],pCon,&val);
if(status == 0){
return status;
}
ang->sgl = val;
return 1;
}
/*-------------------------------------------------------------*/
static float TASGetValue(void *pData, SConnection *pCon){
ptasMot self = (ptasMot)pData;
int status;
tasAngles angles;
double val;
assert(self);
if(self->math->mustRecalculate == 1) {
status = readTASMotAngles(self->math, pCon, &angles);
if(status != 1){
return -999.99;
}
status = calcTasQEPosition(&self->math->machine, angles, &self->math->current);
if(status < 0){
SCWrite(pCon,"ERROR: out of memory calculating Q-E variables",eError);
return -999.99;
}
self->math->mustRecalculate = 0;
}
val = getTasPar(self->math->current,self->code);
return (float)val;
}
/*-----------------------------------------------------------------*/
static float TASQMGetValue(void *pData, SConnection *pCon){
ptasMot self = (ptasMot)pData;
int status;
tasAngles angles;
double val;
assert(self);
if(self->math->mustRecalculate == 1) {
status = readTASMotAngles(self->math, pCon, &angles);
if(status != 1){
return -999.99;
}
status = calcTasPowderPosition(&self->math->machine, angles, &self->math->current);
if(status < 0){
SCWrite(pCon,"ERROR: out of memory calculating Q-E variables",eError);
return -999.99;
}
self->math->mustRecalculate = 0;
}
val = getTasPar(self->math->current,self->code);
return (float)val;
}
/*---------------------------------------------------------------------------------*/
static int TASCheckLimits(void *pData, float fVal, char *error, int iErrLen){
/*
There is no meaningful implementation here. This gets called when starting the motor.
At that stage not all other values may be known. If the calculation fails,
this will die at status check time.
*/
return 1;
}
/*---------------------------------------------------------------------------------*/
static int TASHalt(void *pData){
ptasMot self = (ptasMot)pData;
int i;
assert(self);
for(i = 0; i < 12; i++){
if(self->math->motors[i] != NULL){
self->math->motors[i]->pDrivInt->Halt(self->math->motors[i]);
}
}
return 1;
}
/*---------------------------------------------------------------------------*/
static int startMotors(ptasMot self, tasAngles angles,
SConnection *pCon){
float val;
double curve;
int status;
/*
monochromator
*/
val = self->math->motors[A1]->pDrivInt->GetValue(self->math->motors[A1],pCon);
if(ABS(val - angles.monochromator_two_theta/2.) > MOTPREC){
status = self->math->motors[A1]->pDrivInt->SetValue(self->math->motors[A1],
pCon,
angles.monochromator_two_theta/2.);
if(status != OKOK){
return status;
}
}
val = self->math->motors[A2]->pDrivInt->GetValue(self->math->motors[A2],pCon);
if(ABS(val - angles.monochromator_two_theta) > MOTPREC){
status = self->math->motors[A2]->pDrivInt->SetValue(self->math->motors[A2],
pCon,
angles.monochromator_two_theta);
if(status != OKOK){
return status;
}
}
if(self->math->motors[MCV] != NULL){
curve = maCalcVerticalCurvature(self->math->machine.monochromator,
angles.monochromator_two_theta);
val = self->math->motors[MCV]->pDrivInt->GetValue(self->math->motors[MCV],pCon);
if(ABS(val - curve) > MOTPREC){
status = self->math->motors[MCV]->pDrivInt->SetValue(self->math->motors[MCV],
pCon,
curve);
if(status != OKOK){
return status;
}
}
}
if(self->math->motors[MCH] != NULL){
curve = maCalcHorizontalCurvature(self->math->machine.monochromator,
angles.monochromator_two_theta);
val = self->math->motors[MCH]->pDrivInt->GetValue(self->math->motors[MCH],pCon);
if(ABS(val - curve) > MOTPREC){
status = self->math->motors[MCH]->pDrivInt->SetValue(self->math->motors[MCH],
pCon,
curve);
if(status != OKOK){
return status;
}
}
}
/*
analyzer
*/
val = self->math->motors[A5]->pDrivInt->GetValue(self->math->motors[A5],pCon);
if(ABS(val - angles.analyzer_two_theta/2.) > MOTPREC){
status = self->math->motors[A5]->pDrivInt->SetValue(self->math->motors[A5],
pCon,
angles.analyzer_two_theta/2.);
if(status != OKOK){
return status;
}
}
val = self->math->motors[A6]->pDrivInt->GetValue(self->math->motors[A6],pCon);
if(ABS(val - angles.analyzer_two_theta) > MOTPREC){
status = self->math->motors[A6]->pDrivInt->SetValue(self->math->motors[A6],
pCon,
angles.analyzer_two_theta);
if(status != OKOK){
return status;
}
}
if(self->math->motors[ACV] != NULL){
curve = maCalcVerticalCurvature(self->math->machine.analyzer,
angles.analyzer_two_theta);
val = self->math->motors[ACV]->pDrivInt->GetValue(self->math->motors[ACV],pCon);
if(ABS(val - curve) > MOTPREC){
status = self->math->motors[ACV]->pDrivInt->SetValue(self->math->motors[ACV],
pCon,
curve);
if(status != OKOK){
return status;
}
}
}
if(self->math->motors[ACH] != NULL){
curve = maCalcHorizontalCurvature(self->math->machine.analyzer,
angles.analyzer_two_theta);
val = self->math->motors[ACH]->pDrivInt->GetValue(self->math->motors[ACH],pCon);
if(ABS(val - curve) > MOTPREC){
status = self->math->motors[ACH]->pDrivInt->SetValue(self->math->motors[ACH],
pCon,
curve);
if(status != OKOK){
return status;
}
}
}
/*
crystal
*/
val = self->math->motors[A3]->pDrivInt->GetValue(self->math->motors[A3],pCon);
if(ABS(val - angles.a3) > MOTPREC){
status = self->math->motors[A3]->pDrivInt->SetValue(self->math->motors[A3],
pCon,
angles.a3);
if(status != OKOK){
return status;
}
}
val = self->math->motors[A4]->pDrivInt->GetValue(self->math->motors[A4],pCon);
if(ABS(val - angles.sample_two_theta) > MOTPREC){
status = self->math->motors[A4]->pDrivInt->SetValue(self->math->motors[A4],
pCon,
angles.sample_two_theta);
if(status != OKOK){
return status;
}
}
val = self->math->motors[SGL]->pDrivInt->GetValue(self->math->motors[SGL],pCon);
if(ABS(val - angles.sgl) > MOTPREC){
status = self->math->motors[SGL]->pDrivInt->SetValue(self->math->motors[SGL],
pCon,
angles.sgl);
if(status != OKOK){
return status;
}
}
val = self->math->motors[SGU]->pDrivInt->GetValue(self->math->motors[SGU],pCon);
if(ABS(val - angles.sgu) > MOTPREC){
status = self->math->motors[SGU]->pDrivInt->SetValue(self->math->motors[SGU],
pCon,
angles.sgu);
if(status != OKOK){
return status;
}
}
self->math->mustDrive = 0;
return OKOK;
}
/*-----------------------------------------------------------------------------*/
static int calculateAndDrive(ptasMot self, SConnection *pCon){
tasAngles angles;
int status;
status = calcAllTasAngles(&self->math->machine, self->math->target,
&angles);
switch(status){
case ENERGYTOBIG:
SCWrite(pCon,"ERROR: desired energy to big",eError);
return HWFault;
break;
case UBNOMEMORY:
SCWrite(pCon,"ERROR: out of memory calculating angles",eError);
return HWFault;
break;
case BADRMATRIX:
SCWrite(pCon,"ERROR: bad crystallographic parameters or bad UB",eError);
return HWFault;
break;
case TRIANGLENOTCLOSED:
SCWrite(pCon,"ERROR: cannot close scattering triangle",eError);
return HWFault;
break;
default:
return startMotors(self,angles,pCon);
}
return HWFault;
}
/*-----------------------------------------------------------------------------*/
static int checkMotors(ptasMot self, SConnection *pCon){
int i, status;
self->math->mustRecalculate = 1;
for(i = 0; i < 12; i++){
if(self->math->motors[i] != NULL){
status = self->math->motors[i]->pDrivInt->CheckStatus(self->math->motors[i],pCon);
if(status != HWIdle && status != OKOK){
return status;
}
}
}
return HWIdle;
}
/*------------------------------------------------------------------------------*/
static int TASGetStatus(void *pData, SConnection *pCon){
ptasMot self = (ptasMot)pData;
int status;
assert(self);
if(self->math->mustDrive == 1){
status = calculateAndDrive(self,pCon);
if(status != OKOK){
return HWFault;
} else {
return HWBusy;
}
} else {
return checkMotors(self, pCon);
}
}
/*---------------------------------------------------------------------------*/
static int startQMMotors(ptasMot self, tasAngles angles,
SConnection *pCon){
float val;
double curve;
int status;
/*
monochromator
*/
val = self->math->motors[A1]->pDrivInt->GetValue(self->math->motors[A1],pCon);
if(ABS(val - angles.monochromator_two_theta/2.) > MOTPREC){
status = self->math->motors[A1]->pDrivInt->SetValue(self->math->motors[A1],
pCon,
angles.monochromator_two_theta/2.);
if(status != OKOK){
return status;
}
}
val = self->math->motors[A2]->pDrivInt->GetValue(self->math->motors[A2],pCon);
if(ABS(val - angles.monochromator_two_theta) > MOTPREC){
status = self->math->motors[A2]->pDrivInt->SetValue(self->math->motors[A2],
pCon,
angles.monochromator_two_theta);
if(status != OKOK){
return status;
}
}
if(self->math->motors[MCV] != NULL){
curve = maCalcVerticalCurvature(self->math->machine.monochromator,
angles.monochromator_two_theta);
val = self->math->motors[MCV]->pDrivInt->GetValue(self->math->motors[MCV],pCon);
if(ABS(val - curve) > MOTPREC){
status = self->math->motors[MCV]->pDrivInt->SetValue(self->math->motors[MCV],
pCon,
curve);
if(status != OKOK){
return status;
}
}
}
if(self->math->motors[MCH] != NULL){
curve = maCalcHorizontalCurvature(self->math->machine.monochromator,
angles.monochromator_two_theta);
val = self->math->motors[MCH]->pDrivInt->GetValue(self->math->motors[MCH],pCon);
if(ABS(val - curve) > MOTPREC){
status = self->math->motors[MCH]->pDrivInt->SetValue(self->math->motors[MCH],
pCon,
curve);
if(status != OKOK){
return status;
}
}
}
/*
analyzer
*/
val = self->math->motors[A5]->pDrivInt->GetValue(self->math->motors[A5],pCon);
if(ABS(val - angles.analyzer_two_theta/2.) > MOTPREC){
status = self->math->motors[A5]->pDrivInt->SetValue(self->math->motors[A5],
pCon,
angles.analyzer_two_theta/2.);
if(status != OKOK){
return status;
}
}
val = self->math->motors[A6]->pDrivInt->GetValue(self->math->motors[A6],pCon);
if(ABS(val - angles.analyzer_two_theta) > MOTPREC){
status = self->math->motors[A6]->pDrivInt->SetValue(self->math->motors[A6],
pCon,
angles.analyzer_two_theta);
if(status != OKOK){
return status;
}
}
if(self->math->motors[ACV] != NULL){
curve = maCalcVerticalCurvature(self->math->machine.analyzer,
angles.analyzer_two_theta);
val = self->math->motors[ACV]->pDrivInt->GetValue(self->math->motors[ACV],pCon);
if(ABS(val - curve) > MOTPREC){
status = self->math->motors[ACV]->pDrivInt->SetValue(self->math->motors[ACV],
pCon,
curve);
if(status != OKOK){
return status;
}
}
}
if(self->math->motors[ACH] != NULL){
curve = maCalcHorizontalCurvature(self->math->machine.analyzer,
angles.analyzer_two_theta);
val = self->math->motors[ACH]->pDrivInt->GetValue(self->math->motors[ACH],pCon);
if(ABS(val - curve) > MOTPREC){
status = self->math->motors[ACH]->pDrivInt->SetValue(self->math->motors[ACH],
pCon,
curve);
if(status != OKOK){
return status;
}
}
}
/*
crystal
*/
val = self->math->motors[A4]->pDrivInt->GetValue(self->math->motors[A4],pCon);
if(ABS(val - angles.sample_two_theta) > MOTPREC){
status = self->math->motors[A4]->pDrivInt->SetValue(self->math->motors[A4],
pCon,
angles.sample_two_theta);
if(status != OKOK){
return status;
}
}
self->math->mustDrive = 0;
return OKOK;
}
/*-----------------------------------------------------------------------------*/
static int calculateQMAndDrive(ptasMot self, SConnection *pCon){
tasAngles angles;
int status;
status = calcTasPowderAngles(&self->math->machine, self->math->target,
&angles);
switch(status){
case ENERGYTOBIG:
SCWrite(pCon,"ERROR: desired energy to big",eError);
return HWFault;
break;
case TRIANGLENOTCLOSED:
SCWrite(pCon,"ERROR: cannot close scattering triangle",eError);
return HWFault;
break;
default:
return startQMMotors(self,angles,pCon);
}
return HWFault;
}
/*------------------------------------------------------------------------------*/
static int TASQMGetStatus(void *pData, SConnection *pCon){
ptasMot self = (ptasMot)pData;
int status;
assert(self);
if(self->math->mustDrive == 1){
status = calculateQMAndDrive(self,pCon);
if(status != OKOK){
return HWFault;
} else {
return HWBusy;
}
} else {
return checkMotors(self, pCon);
}
}
/*================== Life and Death =========================================*/
static void KillTasMot(void *pData){
ptasMot self = (ptasMot)pData;
if(self == NULL){
return;
}
if(self->pDes != NULL){
DeleteDescriptor(self->pDes);
self->pDes == NULL;
}
if(self->pDriv != NULL){
free(self->pDriv);
self->pDriv = NULL;
}
free(self);
}
/*---------------------------------------------------------------------------*/
static void *GetTasInterface(void *pData, int interfaceID){
ptasMot self = (ptasMot)pData;
if(self != NULL && interfaceID == DRIVEID){
return self->pDriv;
} else {
return NULL;
}
}
/*-------------------------------------------------------------------------*/
int InstallTasMotor(SicsInterp *pSics, ptasUB self, int tasVar, char *name){
ptasMot pNew = NULL;
pNew = (ptasMot)malloc(sizeof(tasMot));
if(!pNew){
return 0;
}
memset(pNew,0,sizeof(tasMot));
pNew->pDes = CreateDescriptor("TasMot");
pNew->pDriv = CreateDrivableInterface();
if(!pNew->pDes || !pNew->pDriv) {
free(pNew);
return 0;
}
pNew->pDes->GetInterface = GetTasInterface;
pNew->pDriv->Halt = TASHalt;
pNew->pDriv->CheckLimits = TASCheckLimits;
pNew->pDriv->SetValue = TASSetValue;
pNew->pDriv->CheckStatus = TASGetStatus;
pNew->pDriv->GetValue = TASGetValue;
pNew->math = self;
pNew->code = tasVar;
return AddCommand(pSics,name, TasMot, KillTasMot,pNew);
}
/*-------------------------------------------------------------------------*/
int InstallTasQMMotor(SicsInterp *pSics, ptasUB self){
ptasMot pNew = NULL;
pNew = (ptasMot)malloc(sizeof(tasMot));
if(!pNew){
return 0;
}
memset(pNew,0,sizeof(tasMot));
pNew->pDes = CreateDescriptor("TasMot");
pNew->pDriv = CreateDrivableInterface();
if(!pNew->pDes || !pNew->pDriv) {
free(pNew);
return 0;
}
pNew->pDes->GetInterface = GetTasInterface;
pNew->pDriv->Halt = TASHalt;
pNew->pDriv->CheckLimits = TASCheckLimits;
pNew->pDriv->SetValue = TASSetValue;
pNew->pDriv->CheckStatus = TASQMGetStatus;
pNew->pDriv->GetValue = TASQMGetValue;
pNew->math = self;
pNew->code = QM;
return AddCommand(pSics,"qm", TasMot, KillTasMot,pNew);
}
/*------------------------------------------------------------------------*/
int TasMot(SConnection *pCon,SicsInterp *pSics, void *pData,
int argc, char *argv[]){
ptasMot self = (ptasMot)pData;
float value;
char pBueffel[132];
if(argc > 1){
strtolower(argv[1]);
if(strcmp(argv[1],"target") == 0){
snprintf(pBueffel,131,"%s.target = %f",
argv[0], getTasPar(self->math->target,self->code));
SCWrite(pCon,pBueffel,eValue);
return 1;
} else {
SCWrite(pCon,"ERROR: tasmot does not understand this subcommand",eError);
return 0;
}
}
value = self->pDriv->GetValue(self,pCon);
snprintf(pBueffel,131,"%s = %f", argv[0], value);
SCWrite(pCon,pBueffel,eValue);
return 1;
}