Add motor tracking on/off/clear/stats/save commands
This commit is contained in:
@@ -11,6 +11,7 @@
|
|||||||
* - check for motors enabled on plc
|
* - check for motors enabled on plc
|
||||||
* - Check error bit, see Dan's email
|
* - Check error bit, see Dan's email
|
||||||
*/
|
*/
|
||||||
|
#include <limits.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
/* ISO C Standard: 7.16 Boolean type and values <stdbool.h> */
|
/* ISO C Standard: 7.16 Boolean type and values <stdbool.h> */
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -103,6 +104,19 @@ struct EvtEvent_s {
|
|||||||
} event;
|
} event;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct TrackEntry_s {
|
||||||
|
double Timestamp;
|
||||||
|
double Position;
|
||||||
|
int Steps;
|
||||||
|
int Counts;
|
||||||
|
} TrackEntry;
|
||||||
|
#define TrackEntryCount 100
|
||||||
|
typedef struct TrackEntryBuffer_s {
|
||||||
|
struct TrackEntryBuffer_s* nextBuff;
|
||||||
|
int index;
|
||||||
|
TrackEntry buff[TrackEntryCount];
|
||||||
|
} TrackEntryBuffer;
|
||||||
|
|
||||||
#define VAR_REQ (1<<0)
|
#define VAR_REQ (1<<0)
|
||||||
#define VAR_RSP (1<<1)
|
#define VAR_RSP (1<<1)
|
||||||
#define VAR_RUN (1<<2)
|
#define VAR_RUN (1<<2)
|
||||||
@@ -255,6 +269,8 @@ struct __MoDriv {
|
|||||||
double S_m;
|
double S_m;
|
||||||
double S_b;
|
double S_b;
|
||||||
double S_r;
|
double S_r;
|
||||||
|
bool doTracking;
|
||||||
|
TrackEntryBuffer *trackHead, *trackTail;
|
||||||
};
|
};
|
||||||
|
|
||||||
int DMC2280MotionControl = 1; /* defaults to enabled */
|
int DMC2280MotionControl = 1; /* defaults to enabled */
|
||||||
@@ -345,6 +361,48 @@ static double getMotorParam(pDMC2280Driv self, char *param) {
|
|||||||
return fParam;
|
return fParam;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void TrackingRelease(pDMC2280Driv self) {
|
||||||
|
while (self->trackHead) {
|
||||||
|
TrackEntryBuffer *victim;
|
||||||
|
victim = self->trackHead;
|
||||||
|
self->trackHead = self->trackHead->nextBuff;
|
||||||
|
free(victim);
|
||||||
|
}
|
||||||
|
self->trackTail = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static TrackEntryBuffer* TrackingBufferAllocate(pDMC2280Driv self) {
|
||||||
|
/* give the last one if still space available */
|
||||||
|
if (self->trackTail)
|
||||||
|
if (self->trackTail->index < TrackEntryCount)
|
||||||
|
return self->trackTail;
|
||||||
|
/* allocate and chain in a new one */
|
||||||
|
if (NULL == self->trackHead) {
|
||||||
|
self->trackHead = (TrackEntryBuffer *) malloc(sizeof(TrackEntryBuffer));
|
||||||
|
self->trackTail = self->trackHead;
|
||||||
|
if (NULL == self->trackTail) {
|
||||||
|
SICSLogPrintf(eLogError, "Out of memory in TrackingAllocate");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self->trackTail->nextBuff = (TrackEntryBuffer *) malloc(sizeof(TrackEntryBuffer));
|
||||||
|
if (NULL == self->trackTail->nextBuff) {
|
||||||
|
SICSLogPrintf(eLogError, "Out of memory in TrackingAllocate");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
self->trackTail = self->trackTail->nextBuff;
|
||||||
|
}
|
||||||
|
memset(self->trackTail, 0, sizeof(TrackEntryBuffer));
|
||||||
|
return self->trackTail;
|
||||||
|
}
|
||||||
|
|
||||||
|
static TrackEntry *TrackEntryAllocate(pDMC2280Driv self) {
|
||||||
|
TrackEntryBuffer *bp = TrackingBufferAllocate(self);
|
||||||
|
if (NULL == bp)
|
||||||
|
return NULL;
|
||||||
|
return &bp->buff[bp->index++];
|
||||||
|
}
|
||||||
|
|
||||||
static bool check_positions(pDMC2280Driv self) {
|
static bool check_positions(pDMC2280Driv self) {
|
||||||
char line[CMDLEN];
|
char line[CMDLEN];
|
||||||
int missing = 0;
|
int missing = 0;
|
||||||
@@ -2450,6 +2508,8 @@ static void DMCState_MotorOn(pDMC2280Driv self, pEvtEvent event) {
|
|||||||
self->stepCount = 0;
|
self->stepCount = 0;
|
||||||
self->moveStartTime = DoubleTime();
|
self->moveStartTime = DoubleTime();
|
||||||
if (!self->legacy_fsm) {
|
if (!self->legacy_fsm) {
|
||||||
|
if (self->trackHead)
|
||||||
|
TrackingRelease(self);
|
||||||
self->myNextState = NULL;
|
self->myNextState = NULL;
|
||||||
if (self->backlash_offset != 0) {
|
if (self->backlash_offset != 0) {
|
||||||
change_state(self, DMCState_BacklashStart);
|
change_state(self, DMCState_BacklashStart);
|
||||||
@@ -3020,6 +3080,18 @@ static void DMCState_StepMove(pDMC2280Driv self, pEvtEvent event) {
|
|||||||
self->origSteps = self->currSteps;
|
self->origSteps = self->currSteps;
|
||||||
self->minRatio = 0.0;
|
self->minRatio = 0.0;
|
||||||
self->maxRatio = 0.0;
|
self->maxRatio = 0.0;
|
||||||
|
/*
|
||||||
|
* Record how the motor is tracking
|
||||||
|
*/
|
||||||
|
if (self->doTracking) {
|
||||||
|
TrackEntry *ent = TrackEntryAllocate(self);
|
||||||
|
if (ent) {
|
||||||
|
ent->Timestamp = DoubleTime();
|
||||||
|
ent->Position = self->currPosition;
|
||||||
|
ent->Steps = self->currSteps;
|
||||||
|
ent->Counts = self->currCounts;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* begin moving */
|
/* begin moving */
|
||||||
cmdBegin(self);
|
cmdBegin(self);
|
||||||
self->stepCount++;
|
self->stepCount++;
|
||||||
@@ -3053,6 +3125,7 @@ static void DMCState_StepMove(pDMC2280Driv self, pEvtEvent event) {
|
|||||||
return;
|
return;
|
||||||
} else if (self->subState == 2) { /* Status */
|
} else if (self->subState == 2) { /* Status */
|
||||||
int iRet;
|
int iRet;
|
||||||
|
|
||||||
/* update the stop time now in case of error exit */
|
/* update the stop time now in case of error exit */
|
||||||
self->moveStopTime = DoubleTime();
|
self->moveStopTime = DoubleTime();
|
||||||
/* parse the status response and set error codes */
|
/* parse the status response and set error codes */
|
||||||
@@ -3060,6 +3133,18 @@ static void DMCState_StepMove(pDMC2280Driv self, pEvtEvent event) {
|
|||||||
/* if the parse failed break out of here */
|
/* if the parse failed break out of here */
|
||||||
if (iRet == 0)
|
if (iRet == 0)
|
||||||
break;
|
break;
|
||||||
|
/*
|
||||||
|
* Record how the motor is tracking
|
||||||
|
*/
|
||||||
|
if (self->doTracking) {
|
||||||
|
TrackEntry *ent = TrackEntryAllocate(self);
|
||||||
|
if (ent) {
|
||||||
|
ent->Timestamp = DoubleTime();
|
||||||
|
ent->Position = self->currPosition;
|
||||||
|
ent->Steps = self->currSteps;
|
||||||
|
ent->Counts = self->currCounts;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* if the status response can be handled here, return */
|
/* if the status response can be handled here, return */
|
||||||
if (motorHandleStatus(self))
|
if (motorHandleStatus(self))
|
||||||
return;
|
return;
|
||||||
@@ -5262,8 +5347,92 @@ int DMC2280Action(SConnection *pCon, SicsInterp *pSics, void *pData,
|
|||||||
else if(strcasecmp("halt", argv[1]) == 0) {
|
else if(strcasecmp("halt", argv[1]) == 0) {
|
||||||
state_cmd_execute(self, CMD_HALT);
|
state_cmd_execute(self, CMD_HALT);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
} else if(self->abs_encoder && strcasecmp("tracking", argv[1]) == 0) {
|
||||||
else if(self->abs_encoder && strcasecmp("stats", argv[1]) == 0) {
|
if (argc < 3) {
|
||||||
|
SCPrintf(pCon, eValue, "%s.tracking %s", self->name, self->doTracking ? "ON" : "OFF");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (strcasecmp(argv[2], "on") == 0) {
|
||||||
|
self->doTracking = true;
|
||||||
|
SCPrintf(pCon, eValue, "%s.tracking %s", self->name, self->doTracking ? "ON" : "OFF");
|
||||||
|
} else if (strcasecmp(argv[2], "off") == 0) {
|
||||||
|
self->doTracking = false;
|
||||||
|
SCPrintf(pCon, eValue, "%s.tracking %s", self->name, self->doTracking ? "ON" : "OFF");
|
||||||
|
} else if (strcasecmp(argv[2], "clear") == 0) {
|
||||||
|
TrackingRelease(self);
|
||||||
|
SCSendOK(pCon);
|
||||||
|
} else if (strcasecmp(argv[2], "stats") == 0) {
|
||||||
|
TrackEntryBuffer *bp;
|
||||||
|
TrackEntry *ep;
|
||||||
|
int i;
|
||||||
|
double S_x = 0.0;
|
||||||
|
double S_y = 0.0;
|
||||||
|
double S_xx = 0.0;
|
||||||
|
double S_yy = 0.0;
|
||||||
|
double S_xy = 0.0;
|
||||||
|
double S_n = 0.0;
|
||||||
|
double S_m = 0.0;
|
||||||
|
double S_b = 0.0;
|
||||||
|
double S_r = 0.0;
|
||||||
|
for (bp = self->trackHead; bp; bp = bp->nextBuff) {
|
||||||
|
for (i = 0; i < bp->index; i++) {
|
||||||
|
ep = &bp->buff[i];
|
||||||
|
/* TODO */
|
||||||
|
S_x += (double) ep->Counts;
|
||||||
|
S_y += (double) ep->Steps;
|
||||||
|
S_xy += (double) ep->Counts * (double) ep->Steps;
|
||||||
|
S_xx += (double) ep->Counts * (double) ep->Counts;
|
||||||
|
S_yy += (double) ep->Steps * (double) ep->Steps;
|
||||||
|
S_n += (double) 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
S_m = S_n * S_xy - S_x * S_y;
|
||||||
|
S_m /= S_n * S_xx - S_x * S_x;
|
||||||
|
S_b = S_y / S_n - S_m * S_x / S_n;
|
||||||
|
S_r = S_n * S_xy - S_x * S_y;
|
||||||
|
S_r /= sqrt((S_n * S_xx - S_x * S_x)
|
||||||
|
* (S_n * S_yy - S_y * S_y));
|
||||||
|
SCPrintf(pCon, eValue, "Motor=%s stats: n=%.0f, m=%f, b=%f, r=%f, stepsPerX=%f",
|
||||||
|
self->name, S_n, S_m, S_b, S_r, self->cntsPerX * S_m);
|
||||||
|
} else if (strcasecmp(argv[2], "save") == 0) {
|
||||||
|
TrackEntryBuffer *bp;
|
||||||
|
TrackEntry *ep;
|
||||||
|
int i;
|
||||||
|
FILE *fp;
|
||||||
|
char *rp;
|
||||||
|
if (argc < 4) {
|
||||||
|
SCPrintf(pCon, eError, "Motor %s, %s subcommand %s needs filename",
|
||||||
|
argv[0], argv[1], argv[2]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
rp = realpath(argv[3], NULL);
|
||||||
|
fp = fopen(argv[3], "w");
|
||||||
|
if (NULL == fp) {
|
||||||
|
SCPrintf(pCon, eError, "Motor %s, %s subcommand %s failed to open %s",
|
||||||
|
argv[0], argv[1], argv[2], rp ? rp : argv[3]);
|
||||||
|
if (rp)
|
||||||
|
free(rp);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fprintf(fp, "Timestamp,MotorPosition,MotorSteps,EncoderCounts\n");
|
||||||
|
for (bp = self->trackHead; bp; bp = bp->nextBuff) {
|
||||||
|
for (i = 0; i < bp->index; i++) {
|
||||||
|
ep = &bp->buff[i];
|
||||||
|
/* TODO timestamp in HH:MM:SS.cc, softPosition maybe ??*/
|
||||||
|
fprintf(fp, "%.6f,%.6f,%d,%d\n", ep->Timestamp, ep->Position, ep->Steps, ep->Counts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
SCPrintf(pCon, eStatus, "Motor %s, tracking data saved to %s",
|
||||||
|
argv[0], rp ? rp : argv[3]);
|
||||||
|
if (rp)
|
||||||
|
free(rp);
|
||||||
|
} else {
|
||||||
|
SCPrintf(pCon, eError, "Motor %s, %s subcommand %s not recognized",
|
||||||
|
argv[0], argv[1], argv[2]);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
} else if(self->abs_encoder && strcasecmp("stats", argv[1]) == 0) {
|
||||||
char line[132];
|
char line[132];
|
||||||
snprintf(line, CMDLEN, "%s.stats=%s samples=%.0f, slope=%f, intercept=%f, r=%f, stepsPerX=%f",
|
snprintf(line, CMDLEN, "%s.stats=%s samples=%.0f, slope=%f, intercept=%f, r=%f, stepsPerX=%f",
|
||||||
self->name,
|
self->name,
|
||||||
|
|||||||
Reference in New Issue
Block a user