diff --git a/LocCorr/config.c b/LocCorr/config.c index 8a0d510..4590b46 100644 --- a/LocCorr/config.c +++ b/LocCorr/config.c @@ -33,6 +33,8 @@ configuration theconf = { .minFpos=0, .minarea=DEFAULT_MINAREA, .maxarea=DEFAULT_MAXAREA, + .maxwh = 1.1, + .minwh = 0.9, .Nerosions=DEFAULT_NEROSIONS, .Ndilations=DEFAULT_NDILATIONS, .xoff=0, @@ -53,6 +55,7 @@ configuration theconf = { .maxexp=EXPOS_MAX + DBL_EPSILON, .minexp=EXPOS_MIN - DBL_EPSILON, .fixedexp=EXPOS_MIN, + .gain = 20., .intensthres=DEFAULT_INTENSTHRES }; @@ -62,6 +65,10 @@ static confparam parvals[] = { "maximal area (in square pixels) of recognized star image"}, {"minarea", PAR_INT, (void*)&theconf.minarea, 0, MINAREA-DBL_EPSILON, MAXAREA+DBL_EPSILON, "minimal area (in square pixels) of recognized star image"}, + {"minwh", PAR_DOUBLE, (void*)&theconf.minwh, 0, MINWH-DBL_EPSILON, 1., + "minimal value of W/H roundness parameter"}, + {"maxwh", PAR_DOUBLE, (void*)&theconf.maxwh, 0, 1., MAXWH+DBL_EPSILON, + "maximal value of W/H roundness parameter"}, {"ndilat", PAR_INT, (void*)&theconf.Ndilations, 0, 1.-DBL_EPSILON, MAX_NDILAT+DBL_EPSILON, "amount of dilations on binarized image"}, {"neros", PAR_INT, (void*)&theconf.Nerosions, 0, 1.-DBL_EPSILON, MAX_NEROS+DBL_EPSILON, @@ -84,6 +91,10 @@ static confparam parvals[] = { "maximal value of steps on U semi-axe"}, {"vmax", PAR_INT, (void*)&theconf.maxVsteps, 0, MINSTEPS-DBL_EPSILON, MAXSTEPS+DBL_EPSILON, "maximal value of steps on V semi-axe"}, + {"focmax", PAR_INT, (void*)&theconf.maxFpos, 0, 0., Fmaxsteps, + "maximal focus position in microsteps"}, + {"focmin", PAR_INT, (void*)&theconf.minFpos, 0, -Fmaxsteps, 0., + "minimal focus position in microsteps"}, {"stpservport", PAR_INT, (void*)&theconf.stpserverport, 0, -DBL_EPSILON, 65536., "port number of steppers' server"}, {"Kxu", PAR_DOUBLE, (void*)&theconf.Kxu, 0, KUVMIN-DBL_EPSILON, KUVMAX+DBL_EPSILON, @@ -110,13 +121,10 @@ static confparam parvals[] = { "threshold by total object intensity when sorting = |I1-I2|/(I1+I2)"}, {"gain", PAR_DOUBLE, (void*)&theconf.gain, 0, GAIN_MIN-DBL_EPSILON, GAIN_MAX+DBL_EPSILON, "gain value in manual mode"}, + {"brightness", PAR_DOUBLE, (void*)&theconf.brightness, 0, BRIGHT_MIN-DBL_EPSILON, BRIGHT_MAX-DBL_EPSILON, + "brightness value"}, {"starssort", PAR_INT, (void*)&theconf.starssort, 0, -DBL_EPSILON, 1.+DBL_EPSILON, "stars sorting algorithm: by distance from target (0) or by intensity (1)"}, - // immutable parameters (max user can't change) - {"focmax", PAR_INT, (void*)&theconf.maxFpos, 0, 1., 0., - "maximal focus position in microsteps"}, - {"focmin", PAR_INT, (void*)&theconf.minFpos, 0, 1., 0., - "minimal focus position in microsteps"}, {NULL, 0, NULL, 0, 0., 0., NULL} }; diff --git a/LocCorr/config.h b/LocCorr/config.h index 99e20bc..765a28e 100644 --- a/LocCorr/config.h +++ b/LocCorr/config.h @@ -36,21 +36,27 @@ #define MAX_OFFSET (10000) // min/max exposition in ms #define EXPOS_MIN (0.1) -#define EXPOS_MAX (4000.) +#define EXPOS_MAX (4001.) #define GAIN_MIN (0.) -#define GAIN_MAX (20.) +#define GAIN_MAX (33.) +#define BRIGHT_MIN (0.) +#define BRIGHT_MAX (1000.) // max average images counter #define NAVER_MAX (50) // coefficients to convert dx,dy to du,dv #define KUVMIN (-5000.) #define KUVMAX (5000.) // default coefficient for corrections (move to Kdu, Kdv instead of du, dv) -#define KCORR (0.9) +#define KCORR (0.97) // exposition methods: 0 - auto, 1 - fixed #define EXPAUTO (0) #define EXPMANUAL (1) +// roundness parameter +#define MINWH (0.3) +#define MAXWH (3.) + // messageID field name #define MESSAGEID "messageid" @@ -75,6 +81,7 @@ typedef struct{ // dU = Kxu*dX + Kyu*dY; dV = Kxv*dX + Kyv*dY double Kxu; double Kyu; double Kxv; double Kyv; + double minwh; double maxwh; // roundness parameters double xtarget; // target (center) values (in absolute coordinates! screen coords = target - offset) double ytarget; double throwpart; // part of values to throw avay @ histogram equalisation @@ -82,6 +89,7 @@ typedef struct{ double minexp; double fixedexp; // exptime in manual mode double gain; // gain value in manual mode + double brightness; // brightness @camera double intensthres; // threshold for stars intensity comparison: fabs(Ia-Ib)/(Ia+Ib) > thres -> stars differs } configuration; diff --git a/LocCorr/grasshopper.c b/LocCorr/grasshopper.c index cf0b3e4..c4b53ae 100644 --- a/LocCorr/grasshopper.c +++ b/LocCorr/grasshopper.c @@ -34,7 +34,9 @@ static fc2Context context; static fc2PGRGuid guid; static fc2Error err = FC2_ERROR_OK; -static float gain = 0.; +static float gain = 20.; +static float exptime = 100.; +static float brightness = 0.; #define FC2FN(fn, ...) do{err = FC2_ERROR_OK; if(FC2_ERROR_OK != (err=fn(context __VA_OPT__(,) __VA_ARGS__))){ \ WARNX(#fn "(): %s", fc2ErrorToDescription(err)); return 0;}}while(0) @@ -186,7 +188,7 @@ static int connect(){ } static int GrabImage(fc2Image *convertedImage){ - FNAME(); + //FNAME(); int ret = 0; fc2Image rawImage; // start capture @@ -282,6 +284,7 @@ int capture_grasshopper(void (*process)(Image*)){ FNAME(); static float oldexptime = 0.; static float oldgain = -1.; + static float oldbrightness = -1.; Image *oIma = NULL; fc2Image convertedImage; err = fc2CreateImage(&convertedImage); @@ -300,24 +303,28 @@ int capture_grasshopper(void (*process)(Image*)){ sleep(1); continue; } + if(fabsf(oldbrightness - brightness) > FLT_EPSILON){ // new brightness + DBG("Change brightness to %g", brightness); + if(setbrightness(brightness)){ + oldbrightness = brightness; + }else{ + WARNX("Can't change brightness to %g", brightness); + } + } if(fabsf(oldexptime - exptime) > FLT_EPSILON){ // new exsposition value - red("Change exptime to %.2fms\n", exptime); + DBG("Change exptime to %.2fms\n", exptime); if(setexp(exptime)){ oldexptime = exptime; }else{ WARNX("Can't change exposition time to %gms", exptime); - //disconnectGrasshopper(); - //continue; } } - if(fabs(oldgain - gain) > FLT_EPSILON){ // change gain - red("Change gain to %g\n", gain); + if(fabsf(oldgain - gain) > FLT_EPSILON){ // change gain + DBG("Change gain to %g\n", gain); if(setgain(gain)){ oldgain = gain; }else{ WARNX("Can't change gain to %g", gain); - //disconnectGrasshopper(); - //continue; } } if(!GrabImage(&convertedImage)){ @@ -331,6 +338,8 @@ int capture_grasshopper(void (*process)(Image*)){ exptime = theconf.fixedexp; if(fabs(theconf.gain - gain) > FLT_EPSILON) gain = theconf.gain; + if(fabs(theconf.brightness - brightness) > FLT_EPSILON) + brightness = theconf.brightness; } if(!process){ continue; @@ -359,8 +368,8 @@ char *gsimagestatus(const char *messageid, char *buf, int buflen){ DBG("path: %s", impath); } snprintf(buf, buflen, "{ \"%s\": \"%s\", \"camstatus\": \"%sconnected\", \"impath\": \"%s\", \"imctr\": %llu, " - "\"fps\": %.3f, \"expmethod\": \"%s\", \"exposition\": %g, \"gain\": %g }\n", + "\"fps\": %.3f, \"expmethod\": \"%s\", \"exposition\": %g, \"gain\": %g, \"brightness\": %g }\n", MESSAGEID, messageid, connected ? "" : "dis", impath, ImNumber, getFramesPerS(), - (theconf.expmethod == EXPAUTO) ? "auto" : "manual", exptime, gain); + (theconf.expmethod == EXPAUTO) ? "auto" : "manual", exptime, gain, brightness); return buf; } diff --git a/LocCorr/imagefile.c b/LocCorr/imagefile.c index 782826b..8825ce6 100644 --- a/LocCorr/imagefile.c +++ b/LocCorr/imagefile.c @@ -135,7 +135,7 @@ Image *u8toImage(uint8_t *data, int width, int height, int stride){ } outp->minval = (Imtype) min; outp->maxval = (Imtype) max; - DBG("\nMAX=%g, MIN=%g\n", outp->maxval, outp->minval); + //DBG("\nMAX=%g, MIN=%g\n", outp->maxval, outp->minval); outp->data = MALLOC(Imtype, width*height); // flip image updown for FITS coordinate system OMP_FOR() @@ -277,7 +277,7 @@ uint8_t *equalize(const Image *I, int nchannels, double throwpart){ Nwhite += orig_hysto[stopidx]; if(Nwhite >= wpart) break; }*/ - DBG("Throw %d (real: %d black) pixels, startidx=%d", bpart, Nblack, startidx); + //DBG("Throw %d (real: %d black) pixels, startidx=%d", bpart, Nblack, startidx); /* double part = (double)(s + 1) / 256., N = 0.; for(int i = 0; i < 256; ++i){ @@ -332,7 +332,7 @@ int Image_write_jpg(const Image *I, const char *name, int eq){ outp = equalize(I, 1, theconf.throwpart); else outp = linear(I, 1); - DBG("Try to write %s", name); + //DBG("Try to write %s", name); char *tmpnm = MALLOC(char, strlen(name) + 5); sprintf(tmpnm, "%s-tmp", name); int r = stbi_write_jpg(tmpnm, I->width, I->height, 1, outp, 95); diff --git a/LocCorr/improc.c b/LocCorr/improc.c index 4f10e48..ac6b68d 100644 --- a/LocCorr/improc.c +++ b/LocCorr/improc.c @@ -34,7 +34,6 @@ #include "median.h" #include "pusirobo.h" -float exptime = 10.; // GLOBAL: exposition time in milliseconds volatile atomic_ullong ImNumber = 0; // GLOBAL: counter of processed images volatile atomic_bool stopwork = FALSE; // GLOBAL: suicide //int autoExposition = 1; // GLOBAL: ==1 if exposition calculation is auto @@ -47,6 +46,8 @@ char *(*setstepstatus)(const char *newstatus, char *buf, int buflen) = NULL; char *(*movefocus)(const char *newstatus, char *buf, int buflen) = NULL; // GLOBAL: get image information char *(*imagedata)(const char *messageid, char *buf, int buflen); +// GLOBAL: disconnect stepper server +void (*stepdisconnect)() = NULL; static FILE *fXYlog = NULL; static double tstart = 0.; // time of logging start @@ -54,7 +55,7 @@ static double FPS = 0.; // frames per second // function to process calculated corrections -static void (*proc_corr)(double, double, int) = NULL; +static void (*proc_corr)(double, double) = NULL; typedef struct{ uint32_t area; // object area in pixels @@ -152,11 +153,11 @@ static void getDeviation(object *curobj){ averflag = 1; if(fXYlog) fprintf(fXYlog, "%.1f\t%.1f\t%.1f\t%.1f", xx, yy, Sx, Sy); process_corrections: - if(proc_corr){ + if(proc_corr && averflag){ if(Sx > XY_TOLERANCE || Sy > XY_TOLERANCE){ LOGDBG("Bad value - not process"); // don't run processing for bad data }else - proc_corr(xx, yy, averflag); + proc_corr(xx, yy); } XYnewline(); } @@ -214,7 +215,7 @@ void process_file(Image *I){ double wh = ((double)b->xmax - b->xmin)/(b->ymax - b->ymin); //DBG("Obj# %zd: wh=%g, area=%d", i, wh, b->area); // TODO: change magick numbers to parameters - if(wh < MINWH || wh > MAXWH) continue; + if(wh < theconf.minwh || wh > theconf.maxwh) continue; if((int)b->area < theconf.minarea || (int)b->area > theconf.maxarea) continue; double xc = 0., yc = 0.; double x2c = 0., y2c = 0., Isum = 0.; @@ -266,12 +267,16 @@ void process_file(Image *I){ outp = equalize(I, 3, theconf.throwpart); else outp = linear(I, 3); + static Pattern *cross = NULL; + if(!cross) cross = Pattern_cross(33, 33); + Img3 i3 = {.data = outp, .w = I->width, .h = H}; + // draw fiber center position + Pattern_draw3(&i3, cross, theconf.xtarget-theconf.xoff, H-(theconf.ytarget-theconf.yoff), C_B); if(objctr){ // draw crosses @ objects' centers - static Pattern *cross = NULL; - if(!cross) cross = Pattern_cross(33, 33); int H = I->height; - Img3 i3 = {.data = outp, .w = I->width, .h = H}; + // draw current star centroid Pattern_draw3(&i3, cross, Objects[0].xc, H-Objects[0].yc, C_G); + // draw other centroids for(int i = 1; i < objctr; ++i) Pattern_draw3(&i3, cross, Objects[i].xc, H-Objects[i].yc, C_R); // Pattern_free(&cross); don't free - static variable! @@ -390,6 +395,7 @@ void setpostprocess(const char *name){ WARNX("Pusiserver unavailable, will check later"); LOGWARN("Pusiserver unavailable, will check later"); } + stepdisconnect = pusi_stop; proc_corr = pusi_process_corrections; stepstatus = pusi_status; setstepstatus = set_pusistatus; diff --git a/LocCorr/improc.h b/LocCorr/improc.h index 73dfcac..1c99563 100644 --- a/LocCorr/improc.h +++ b/LocCorr/improc.h @@ -25,23 +25,19 @@ // tolerance of deviations by X and Y axis (if sigmaX or sigmaY greater, values considered to be wrong) #define XY_TOLERANCE (1.) -// roundness parameter -#define MINWH (0.5) -#define MAXWH (2.) #define PUSIROBO_POSTPROC "pusirobo" // how many frames will be averaged to count image deviation #define MAX_AVERAGING_ARRAY_SIZE (25) extern volatile atomic_bool stopwork; -extern double Xtarget, Ytarget; extern volatile atomic_ullong ImNumber; -extern float exptime; //extern int autoExposition; extern char *(*stepstatus)(const char *messageid, char *buf, int buflen); extern char *(*setstepstatus)(const char *newstatus, char *buf, int buflen); extern char *(*movefocus)(const char *newstatus, char *buf, int buflen); extern char *(*imagedata)(const char *messageid, char *buf, int buflen); +extern void (*stepdisconnect)(); void process_file(Image *I); int process_input(InputType tp, char *name); diff --git a/LocCorr/loccorr.conf b/LocCorr/loccorr.conf new file mode 100644 index 0000000..ac323a5 --- /dev/null +++ b/LocCorr/loccorr.conf @@ -0,0 +1,32 @@ +maxarea = 10000 +minarea = 100 +minwh = 0.800 +maxwh = 1.300 +ndilat = 4 +neros = 5 +xoffset = 0 +yoffset = 0 +width = 0 +height = 0 +equalize = 0 +expmethod = 1 +naverage = 5 +umax = 16000 +vmax = 16000 +focmax = 32000 +focmin = -32000 +stpservport = 4444 +Kxu = 28.047 +Kyu = 90.067 +Kxv = 69.539 +Kyv = -66.882 +xtarget = 810.335 +ytarget = 518.906 +eqthrowpart = 0.900 +minexp = 50.000 +maxexp = 3999.000 +fixedexp = 700.000 +intensthres = 0.010 +gain = 20.000 +brightness = 0.000 +starssort = 0 diff --git a/LocCorr/main.c b/LocCorr/main.c index 86bc0e7..9ea8e50 100644 --- a/LocCorr/main.c +++ b/LocCorr/main.c @@ -41,15 +41,16 @@ void signals(int sig){ } stopwork = TRUE; DBG("exit %d", sig); - LOGERR("Exit with status %d", sig); saveconf(NULL); if(GP && GP->pidfile){ // remove unnesessary PID file DBG("unlink(GP->pidfile)"); unlink(GP->pidfile); } + if(stepdisconnect) stepdisconnect(); DBG("closeXYlog()"); closeXYlog(); DBG("EXIT %d", sig); + LOGERR("Exit with status %d", sig); exit(sig); } diff --git a/LocCorr/pusirobo.c b/LocCorr/pusirobo.c index 7d08a6f..7768caa 100644 --- a/LocCorr/pusirobo.c +++ b/LocCorr/pusirobo.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include #include "config.h" +#include "improc.h" // global variable stopwork #include "pusirobo.h" #include "socket.h" @@ -37,14 +39,14 @@ // amount of consequent center coordinates coincidence in `process_targetstate` #define NCONSEQ (2) // tolerance of coordinates coincidence (pix) -#define COORDTOLERANCE (0.1) +#define COORDTOLERANCE (0.5) // messages for CAN server #define registerUaxe "register U 0x581 stepper" #define registerVaxe "register V 0x582 stepper" #define registerFocus "register F 0x583 stepper" -#define setUspeed "mesg U maxspeed 12800" -#define setVspeed "mesg V maxspeed 12800" +#define setUspeed "mesg U maxspeed 22400" +#define setVspeed "mesg V maxspeed 22400" #define setFspeed "mesg F maxspeed 12800" #define Urelsteps "mesg U relmove " #define Vrelsteps "mesg V relmove " @@ -62,16 +64,24 @@ #define ERRstatus "errstatus" #define CURPOSstatus "curpos" // max range of U and V motors (all in microsteps!) -#define UVmaxsteps (35200) +#define UVmaxsteps (96000) // steps to move from the edge -#define UVedgesteps (960) - +#define UVedgesteps (3200) #define moveU(s) move_motor(Urelsteps, s) #define moveV(s) move_motor(Vrelsteps, s) #define moveF(s) move_motor(Frelsteps, s) #define setF(s) move_motor(Fabssteps, s) -#define UVmoving_finished() (moving_finished(Ustatus, NULL) && moving_finished(Vstatus, NULL)) + +typedef enum{ + PUSI_DISCONN, + PUSI_RELAX, + PUSI_SETUP, + PUSI_GOTOTHEMIDDLE, + PUSI_FINDTARGET, + PUSI_FIX, + PUSI_UNDEFINED +} pusistate; typedef enum{ SETUP_NONE, // no setup @@ -84,9 +94,18 @@ typedef enum{ SETUP_WAITVMAX, // V->max SETUP_FINISH } setupstatus; -static setupstatus sstatus = SETUP_NONE; // setup state +static _Atomic setupstatus sstatus = SETUP_NONE; // setup state static pusistate state = PUSI_DISCONN; // server state +// the `ismoving` flag allows not to make corrections with bad images made when moving +static volatile atomic_bool ismoving = FALSE; // == TRUE if any of steppers @hanging part is moving +// this flag set to TRUE when next Xc,Yc available +static volatile atomic_bool coordsRdy = FALSE; +static double Xtarget = 0., Ytarget = 0.; + +// flag & new focus value +static volatile atomic_bool chfocus = FALSE; +static volatile atomic_int newfocpos = 0; static int sockfd = -1; // server file descriptor @@ -94,12 +113,14 @@ static int sockfd = -1; // server file descriptor static pthread_mutex_t sendmesg_mutex = PTHREAD_MUTEX_INITIALIZER; // current steps counters (zero at the middle) -static int Uposition = 0, Vposition = 0, Fposition = 0; +static volatile atomic_int Uposition = 0, Vposition = 0, Fposition = 0; +static volatile atomic_bool Umoving = FALSE, Vmoving = FALSE, Fmoving = FALSE; static uint8_t fixerr = 0; // ==1 if can't fixed -void pusi_disconnect(){ +static void pusi_disconnect(){ if(sockfd > -1) close(sockfd); sockfd = -1; + Umoving = Vmoving = Fmoving = ismoving = FALSE; state = PUSI_DISCONN; } @@ -209,7 +230,9 @@ static int waitOK(char **retval){ *retval = strdup(ok + sizeof(ANSOK)-1); //DBG("RETVAL: '%s'", *retval); } - }else LOGWARN("didn't get OK answer"); + }else{ + LOGWARN("didn't get OK answer"); + } #undef BUFFERSZ return ret; } @@ -230,7 +253,7 @@ static int send_message(const char *msg, char **ans){ LOGWARN("send_message(): send() failed"); return FALSE; } - DBG("Message '%s' sent", msg); + //DBG("Message '%s' sent", msg); int r = waitOK(ans); pthread_mutex_unlock(&sendmesg_mutex); return r; @@ -267,10 +290,11 @@ static int setSpeed(const char *mesg, const char *name){ } /** - * @brief pusi_connect - connect to a local steppers CAN server + * @brief pusi_connect_server - try connect to a local steppers CAN server * @return FALSE if failed */ -int pusi_connect(){ +static int pusi_connect_server(){ + Umoving = Fmoving = Vmoving = ismoving = FALSE; DBG("pusi_connect(%d)", theconf.stpserverport); char port[10]; snprintf(port, 10, "%d", theconf.stpserverport); @@ -318,15 +342,38 @@ int pusi_connect(){ return retval; } +static void *pusi_process_states(_U_ void *arg); +static pthread_t processingthread; +/** + * @brief pusi_connect - run a thread processed steppers status + * @return FALSE if failed to connect immediately + */ +int pusi_connect(){ + int c = pusi_connect_server(); + if(pthread_create(&processingthread, NULL, pusi_process_states, NULL)){ + LOGERR("pthread_create() for pusirobo server failed"); + ERR("pthread_create()"); + } + return c; +} + +// stop processing & disconnect +void pusi_stop(){ + pthread_join(processingthread, NULL); + pusi_disconnect(); +} + // return TRUE if motor is stopped -static int moving_finished(const char *mesgstatus, int *position){ +static int moving_finished(const char *mesgstatus, volatile atomic_int *position){ double val; char *ans = NULL; int ret = TRUE; if(send_message(mesgstatus, &ans) && getparval(PARstatus, ans, &val)){ - DBG("send(%s) true: %s %g\n", mesgstatus, ans, val); + //DBG("send(%s) true: %s %g\n", mesgstatus, ans, val); }else{ + WARNX("send(%s) false: %s %g\n", mesgstatus, ans, val); LOGDBG("send(%s) false: %s %g\n", mesgstatus, ans, val); + pusi_disconnect(); return FALSE; } int ival = (int)val; @@ -334,25 +381,31 @@ static int moving_finished(const char *mesgstatus, int *position){ if(position){ if(getparval(CURPOSstatus, ans, &val)){ *position = (int) val; - }else LOGDBG("%s not found in '%s'", CURPOSstatus, ans); + }else{ + WARNX("%s not found in '%s'", CURPOSstatus, ans); + LOGDBG("%s not found in '%s'", CURPOSstatus, ans); + } } FREE(ans); return ret; } // move motor to s steps, @return FALSE if failed -static int move_motor(const char *movecmd, int s/*, int *counter*/){ +static int move_motor(const char *movecmd, int s){ DBG("move %s -> %d", movecmd, s); LOGDBG("move %s -> %d", movecmd, s); char buf[256], *ans; snprintf(buf, 255, "%s %d", movecmd, s); if(!send_message(buf, &ans)){ + WARNX("can't send message"); LOGDBG("can't send message"); + pusi_disconnect(); return FALSE; } int ret = TRUE; if(!getOKval(STEPSstatus, ans)){ - LOGDBG("NO OK in %s", ans); + WARNX("NO OK in %s", ans); + LOGWARN("NO OK in %s", ans); ret = FALSE; } FREE(ans); @@ -362,27 +415,27 @@ static int move_motor(const char *movecmd, int s/*, int *counter*/){ static void process_movetomiddle_stage(){ switch(sstatus){ case SETUP_INIT: // initial moving - if(moveU(-UVmaxsteps) && moveV(-UVmaxsteps) && moveF(-Fmaxsteps)) + if(moveF(-Fmaxsteps) && moveU(-UVmaxsteps) && moveV(-UVmaxsteps)) sstatus = SETUP_WAITUV0; break; case SETUP_WAITUV0: // wait for both coordinates moving to zero - DBG("Moving to left border"); - if(!(UVmoving_finished() && moving_finished(Fstatus, NULL))) return; - DBG("Reached!"); - if(!send_message(Fsetzero, NULL)) return; - Fposition = 0; - if(moveU(theconf.maxUsteps+UVedgesteps) && moveV(theconf.maxUsteps+UVedgesteps) && moveF(Fmaxsteps/2)) + DBG("Reached UVF0!"); + if(moveF(Fmaxsteps/2) && moveU(theconf.maxUsteps+UVedgesteps) && moveV(theconf.maxVsteps+UVedgesteps)) sstatus = SETUP_WAITUVMID; + else{ + LOGWARN("GOTO middle: err in move command"); + sstatus = SETUP_INIT; + } break; case SETUP_WAITUVMID: // wait for the middle - DBG("Moving to the middle"); - if(!(UVmoving_finished() && moving_finished(Fstatus, NULL))) return; - DBG("Reached!"); - Uposition = 0; Vposition = 0; Fposition = Fmaxsteps/2; - if(!send_message(Usetzero, NULL) || !send_message(Vsetzero, NULL)) return; - sstatus = SETUP_NONE; - state = PUSI_RELAX; - break; + DBG("Reached middle position"); + if(!send_message(Fsetzero, NULL) || !send_message(Usetzero, NULL) || !send_message(Vsetzero, NULL)){ + LOGWARN("GOTO middle: err in set 0 command"); + sstatus = SETUP_INIT; + return; + } + Uposition = Vposition = Fposition = 0; + // fallthrough default: sstatus = SETUP_NONE; state = PUSI_RELAX; @@ -392,9 +445,8 @@ static void process_movetomiddle_stage(){ /** * @brief process_setup_stage - process all stages of axes setup */ -static void process_setup_stage(double x, double y, int aver){ +static void process_setup_stage(){ DBG("PROCESS: %d\n", sstatus); - static int ctr; // iterations counter // coordinates for corrections calculation static double X0U, Y0U, XmU, YmU; static double X0V, Y0V, XmV, YmV; @@ -404,54 +456,61 @@ static void process_setup_stage(double x, double y, int aver){ sstatus = SETUP_WAITUV0; break; case SETUP_WAITUV0: // wait for both coordinates moving to zero - DBG("Moving to left border"); - if(!UVmoving_finished()) return; - DBG("Reached!"); + DBG("Left border reached"); if(moveU(theconf.maxUsteps+UVedgesteps) && moveV(theconf.maxUsteps+UVedgesteps)) sstatus = SETUP_WAITUVMID; + else{ + LOGWARN("Can't move U/V -> 0"); + sstatus = SETUP_INIT; + } break; case SETUP_WAITUVMID: // wait for the middle - DBG("Moving to the middle"); - if(!UVmoving_finished()) return; - DBG("Reached!"); - Uposition = 0; Vposition = 0; + DBG("The middle reached"); if(moveU(-theconf.maxUsteps)) sstatus = SETUP_WAITU0; - ctr = 0; + else{ + LOGWARN("Can't move U -> middle"); + sstatus = SETUP_INIT; + } break; case SETUP_WAITU0: // wait while U moves to zero - if(!aver) return; - if(!moving_finished(Ustatus, NULL)) return; - if(++ctr < 2) return; // wait for next average coordinates - X0U = x; Y0U = y; - LOGDBG("got X0U=%.1f, Y0U=%.1f", x, y); + if(!coordsRdy) return; + coordsRdy = FALSE; + X0U = Xtarget; Y0U = Ytarget; + DBG("got X0U=%.1f, Y0U=%.1f", X0U, Y0U); + LOGDBG("got X0U=%.1f, Y0U=%.1f", X0U, Y0U); if(moveU(2*theconf.maxUsteps)) sstatus = SETUP_WAITUMAX; - ctr = 0; + else{ + LOGWARN("Can't move U -> max"); + sstatus = SETUP_INIT; + } break; case SETUP_WAITUMAX: // wait while U moves to UVworkrange - if(!aver) return; - if(!moving_finished(Ustatus, NULL)) return; - if(++ctr < 2) return; // wait for next average coordinates - XmU = x; YmU = y; - LOGDBG("got XmU=%.1f, YmU=%.1f", x, y); + if(!coordsRdy) return; + coordsRdy = FALSE; + XmU = Xtarget; YmU = Ytarget; + LOGDBG("got XmU=%.1f, YmU=%.1f", XmU, YmU); if(moveU(-theconf.maxUsteps) && moveV(-theconf.maxVsteps)) sstatus = SETUP_WAITV0; - ctr = 0; + else{ + LOGWARN("Can't move U -> mid OR/AND V -> min"); + sstatus = SETUP_INIT; + } break; case SETUP_WAITV0: // wait while V moves to 0 - if(!aver) return; - if(!moving_finished(Vstatus, NULL)) return; - if(++ctr < 2) return; // wait for next average coordinates - X0V = x; Y0V = y; - LOGDBG("got X0V=%.1f, Y0V=%.1f", x, y); + if(!coordsRdy) return; + coordsRdy = FALSE; + X0V = Xtarget; Y0V = Ytarget; + LOGDBG("got X0V=%.1f, Y0V=%.1f", X0V, Y0V); if(moveV(2*theconf.maxVsteps)) sstatus = SETUP_WAITVMAX; - ctr = 0; + else{ + LOGWARN("Can't move V -> max"); + sstatus = SETUP_INIT; + } break; case SETUP_WAITVMAX: // wait while V moves to UVworkrange - if(!aver) return; - if(!moving_finished(Vstatus, NULL)) return; - if(++ctr < 2) return; // wait for next average coordinates - ctr = 0; - XmV = x; YmV = y; - LOGDBG("got XmV=%.1f, YmV=%.1f", x, y); + if(!coordsRdy) return; + coordsRdy = FALSE; + XmV = Xtarget; YmV = Ytarget; + LOGDBG("got XmV=%.1f, YmV=%.1f", XmV, YmV); // calculate double dxU = XmU - X0U, dyU = YmU - Y0U, dxV = XmV - X0V, dyV = YmV - Y0V; LOGDBG("dxU=%.1f, dyU=%.1f, dxV=%.1f, dyV=%.1f", dxU, dyU, dxV, dyV); @@ -463,29 +522,27 @@ static void process_setup_stage(double x, double y, int aver){ double KU = 2 * theconf.maxUsteps / sqU; double KV = 2 * theconf.maxVsteps / sqV; double sa = dyU/sqU, ca = dxU/sqU, sb = dyV/sqV, cb = dxV/sqV; // sin(alpha) etc - // ctg(beta-alpha)=cos(b-a)/sin(b-a)=[cos(b)cos(a)+sin(b)sin(a)]/[sin(b)cos(a)-cos(b)sin(a)] - double sba = sb*ca - cb*sa; // sin(beta-alpha) - double ctba = (cb*ca + sb*sa) / sba; - if(fabs(ctba) < DBL_EPSILON || fabs(sba) < DBL_EPSILON) goto endmoving; - LOGDBG("KU=%.4f, KV=%.4f, sa=%.4f, ca=%.4f, sb=%.4f, cb=%.4f, ctba=%.5f, 1/sba=%.5f", - KU, KV, sa, ca, sb, cb, ctba, 1./sba); + LOGDBG("KU=%.4f, KV=%.4f, sa=%.4f, ca=%.4f, sb=%.4f, cb=%.4f", + KU, KV, sa, ca, sb, cb); /* - * U = x*(cos(alpha) - sin(alpha)*ctg(beta-alpha)) + y*(-sin(alpha)-cos(alpha)*ctg(beta-alpha)) - * V = x*sin(alpha)/sin(beta-alpha) + y*cos(alpha)/sin(beta-alpha) + * [dX dY] = M*[dU dV], M = [ca/KU cb/KV; sa/KU sb/KV] ===> + * [dU dV] = inv(M)*[dX dY], + * inv(M) = 1/(ca/KU*sb/KV - sa/KU*cb/KV)*[sb/KV -cb/KV; -sa/KU ca/KU] */ - theconf.Kxu = KU*(ca - sa*ctba); - theconf.Kyu = KU*(-sa - ca*ctba); - theconf.Kxv = KV*sa/sba; - theconf.Kyv = KV*ca/sba; + double mul = 1/(ca/KU*sb/KV - sa/KU*cb/KV); + theconf.Kxu = mul*sb/KV; + theconf.Kyu = -mul*cb/KV; + theconf.Kxv = -mul*sa/KU; + theconf.Kyv = mul*ca/KU; LOGDBG("Kxu=%g, Kyu=%g; Kxv=%g, Kyv=%g", theconf.Kxu, theconf.Kyu, theconf.Kxv, theconf.Kyv); DBG("Now save new configuration"); saveconf(NULL); // try to store configuration + // fallthrough endmoving: moveV(-theconf.maxVsteps); sstatus = SETUP_FINISH; break; case SETUP_FINISH: // reset current coordinates - if(!UVmoving_finished()) return; if(!send_message(Usetzero, NULL) || !send_message(Vsetzero, NULL)) return; // now inner steppers' counters are in zero position -> set to zero local Uposition = Vposition = 0; @@ -513,7 +570,8 @@ static int process_targetstage(double X, double Y){ theconf.xtarget = X + theconf.xoff; theconf.ytarget = Y + theconf.yoff; DBG("Got target coordinates: (%.1f, %.1f)", X, Y); - saveconf(FALSE); + LOGMSG("Got target coordinates: (%.1f, %.1f)", X, Y); + saveconf(NULL); nhit = 0; xprev = 0.; yprev = 0.; return TRUE; } @@ -530,9 +588,10 @@ static int try2correct(double dX, double dY){ dU = KCORR*(theconf.Kxu * dX + theconf.Kyu * dY); dV = KCORR*(theconf.Kxv * dX + theconf.Kyv * dY); int Unew = Uposition + (int)dU, Vnew = Vposition + (int)dV; - if(Unew > theconf.maxUsteps || Unew < -theconf.maxUsteps || - Vnew > theconf.maxVsteps || Vnew < -theconf.maxVsteps){ - // TODO: here we should signal the interface that limit reaced + int Unfixed = Unew + Fposition, Vnfixed = Vnew + Fposition; // fixed by focus position + if(Unfixed > theconf.maxUsteps || Unfixed < -theconf.maxUsteps || + Vnfixed > theconf.maxVsteps || Vnfixed < -theconf.maxVsteps){ + // TODO: here we should signal that the limit reached LOGWARN("Correction failed, curpos: %d, %d, should move to %d, %d", Uposition, Vposition, Unew, Vnew); return FALSE; @@ -543,79 +602,38 @@ static int try2correct(double dX, double dY){ return (moveU((int)dU) && moveV((int)dV)); } -#if 0 -mesg U relmove -35200 -mesg V relmove -35200 -mesg U relmove 16960 -mesg V relmove 16960 -mesg U relmove -500000 -mesg U relmove 100000 -mesg F relmove 32000 -#endif +// global variable proc_corr /** * @brief pusi_process_corrections - get XY corrections (in pixels) and move motors to fix them * @param X, Y - centroid (x,y) in screen coordinate system - * @param aver ==1 if X and Y are averaged * This function called from improc.c each time the corrections calculated (ONLY IF Xtarget/Ytarget > -1) */ -void pusi_process_corrections(double X, double Y, int aver){ - //DBG("got centroid data: %g, %g", X, Y); - static int first = TRUE; - double xtg = theconf.xtarget - theconf.xoff, ytg = theconf.ytarget - theconf.yoff; - double xdev = X - xtg, ydev = Y - ytg; - if(state != PUSI_DISCONN) first = TRUE; - switch(state){ - case PUSI_DISCONN: - if(!pusi_connect()){ - WARN("Can't reconnect"); - } - if(first){ - LOGWARN("Can't reconnect"); - first = FALSE; - } - break; - case PUSI_SETUP: // setup axes (before this state set Xtarget/Ytarget in improc.c) - process_setup_stage(X, Y, aver); - break; - case PUSI_GOTOTHEMIDDLE: - process_movetomiddle_stage(); - break; - case PUSI_FINDTARGET: // calculate target coordinates - if(aver && process_targetstage(X, Y)) - state = PUSI_RELAX; - break; - case PUSI_FIX: // process corrections - if(aver){ - red("GET AVERAGE -> correct\n"); - if(theconf.xtarget < 1. || theconf.ytarget < 1. || fabs(xdev) < COORDTOLERANCE || fabs(ydev) < COORDTOLERANCE){ - DBG("Target coordinates not defined or correction too small"); - return; - } - if(!moving_finished(Ustatus, &Uposition) || !moving_finished(Vstatus, &Vposition)) return; - LOGDBG("Current position: U=%d, V=%d, deviations: dX=%.1f, dy=%.1f", - Uposition, Vposition, xdev, ydev); - if(!try2correct(xdev, ydev)){ - LOGWARN("failed to correct"); - fixerr = 1; - // TODO: do something here - DBG("FAILED"); - } else fixerr = 0; - } - break; - default: // PUSI_RELAX - return; +void pusi_process_corrections(double X, double Y){ + static bool coordstrusted = TRUE; + if(ismoving){ // don't process coordinates when moving + coordstrusted = FALSE; + coordsRdy = FALSE; + return; } + if(!coordstrusted){ // don't trust first coordinates after moving finished + coordstrusted = TRUE; + coordsRdy = FALSE; + return; + } + //DBG("got centroid data: %g, %g", X, Y); + Xtarget = X; Ytarget = Y; + coordsRdy = TRUE; } // try to change state; @return TRUE if OK -int pusi_setstate(pusistate newstate){ +static int pusi_setstate(pusistate newstate){ if(newstate == state) return TRUE; if(newstate == PUSI_DISCONN){ pusi_disconnect(); return TRUE; } if(state == PUSI_DISCONN){ - if(!pusi_connect()) return FALSE; + if(!pusi_connect_server()) return FALSE; } if(newstate == PUSI_SETUP || newstate == PUSI_GOTOTHEMIDDLE){ sstatus = SETUP_INIT; @@ -624,11 +642,7 @@ int pusi_setstate(pusistate newstate){ return TRUE; } -pusistate pusi_getstate(){ - return state; -} - -// get current status +// get current status (global variable stepstatus) // return JSON string with different parameters char *pusi_status(const char *messageid, char *buf, int buflen){ int l; @@ -690,11 +704,11 @@ char *pusi_status(const char *messageid, char *buf, int buflen){ l = snprintf(bptr, buflen, ", "); buflen -= l; bptr += l; const char *motors[] = {"Umotor", "Vmotor", "Fmotor"}; - const char *statuses[] = {Ustatus, Vstatus, Fstatus}; - int *pos[] = {&Uposition, &Vposition, &Fposition}; + volatile atomic_bool *mv[] = {&Umoving, &Vmoving, &Fmoving}; + volatile atomic_int *pos[] = {&Uposition, &Vposition, &Fposition}; for(int i = 0; i < 3; ++i){ - const char *stat = "moving"; - if(moving_finished(statuses[i], pos[i])) stat = "stopping"; + const char *stat = "stopping"; + if(*mv[i]) stat = "moving"; l = snprintf(bptr, buflen, "\"%s\": { \"status\": \"%s\", \"position\": %d }%s", motors[i], stat, *pos[i], (i==2)?"":", "); buflen -= l; bptr += l; @@ -708,7 +722,7 @@ typedef struct{ const char *str; pusistate state; } strstate; - +// commands from client to change status strstate stringstatuses[] = { {"disconnect", PUSI_DISCONN}, {"relax", PUSI_RELAX}, @@ -718,7 +732,8 @@ strstate stringstatuses[] = { {"fix", PUSI_FIX}, {NULL, 0} }; -// try to set new status + +// try to set new status (global variable stepstatus) char *set_pusistatus(const char *newstatus, char *buf, int buflen){ strstate *s = stringstatuses; pusistate newstate = PUSI_UNDEFINED; @@ -750,18 +765,109 @@ char *set_pusistatus(const char *newstatus, char *buf, int buflen){ ptr[L-1] = '\n'; return buf; } -// change focus + +// change focus (global variable movefocus) char *set_pfocus(const char *newstatus, char *buf, int buflen){ - if(!moving_finished(Fstatus, &Fposition)){ - snprintf(buf, buflen, FAIL); - return buf; - } int newval = atoi(newstatus); if(newval < theconf.minFpos || newval > theconf.maxFpos){ snprintf(buf, buflen, FAIL); }else{ - if(!setF(newval)) snprintf(buf, buflen, FAIL); - else snprintf(buf, buflen, OK); + snprintf(buf, buflen, OK); + newfocpos = newval; + chfocus = TRUE; } return buf; } + +// MAIN THREAD +static void *pusi_process_states(_U_ void *arg){ + FNAME(); + static bool first = TRUE; // flag for logging when can't reconnect + while(!stopwork){ + usleep(10000); + // check for moving + switch(state){ + case PUSI_SETUP: + case PUSI_GOTOTHEMIDDLE: + case PUSI_FIX: + if(moving_finished(Ustatus, &Uposition)) Umoving = FALSE; + else Umoving = TRUE; + if(moving_finished(Vstatus, &Vposition)) Vmoving = FALSE; + else Vmoving = TRUE; + if(moving_finished(Fstatus, &Fposition)) Fmoving = FALSE; + else Fmoving = TRUE; + if(Umoving || Vmoving || Fmoving) ismoving = TRUE; + else ismoving = FALSE; + break; + case PUSI_DISCONN: + sleep(1); + pusi_connect_server(); + break; + default: + break; + } + if(ismoving){ + coordsRdy = FALSE; + continue; + } + // check request to change focus + if(chfocus){ + chfocus = FALSE; + int delta = newfocpos - Fposition; + moveF(delta); moveU(delta); moveV(delta); + continue; + } + // if we are here, all U/V/F moving is finished + if(state != PUSI_DISCONN) first = TRUE; + switch(state){ // pusirobo state machine + case PUSI_DISCONN: + if(!pusi_connect_server()){ + WARNX("Can't reconnect"); + if(first){ + LOGWARN("Can't reconnect"); + first = FALSE; + } + sleep(5); + } + break; + case PUSI_SETUP: // setup axes (before this state set Xtarget/Ytarget in improc.c) + process_setup_stage(); + break; + case PUSI_GOTOTHEMIDDLE: + process_movetomiddle_stage(); + break; + case PUSI_FINDTARGET: // calculate target coordinates + if(coordsRdy){ + coordsRdy = FALSE; + if(process_targetstage(Xtarget, Ytarget)) + state = PUSI_RELAX; + } + break; + case PUSI_FIX: // process corrections + if(coordsRdy){ + coordsRdy = FALSE; + red("GET AVERAGE -> correct\n"); + double xtg = theconf.xtarget - theconf.xoff, ytg = theconf.ytarget - theconf.yoff; + double xdev = xtg - Xtarget, ydev = ytg - Ytarget; + double corr = sqrt(xdev*xdev + ydev*ydev); + if(theconf.xtarget < 1. || theconf.ytarget < 1. || corr < COORDTOLERANCE){ + DBG("Target coordinates not defined or correction too small, targ: (%.1f, %.1f); corr: %.1f, %.1f (abs: %.1f)", + theconf.xtarget, theconf.ytarget, xdev, ydev, corr); + break; + } + LOGDBG("Current position: U=%d, V=%d, deviations: dX=%.1f, dy=%.1f", + Uposition, Vposition, xdev, ydev); + if(!try2correct(xdev, ydev)){ + LOGWARN("failed to correct"); + fixerr = 1; + // TODO: do something here + DBG("FAILED"); + }else fixerr = 0; + } + break; + default: // PUSI_RELAX + break; + } + } + return NULL; +} diff --git a/LocCorr/pusirobo.h b/LocCorr/pusirobo.h index 436d43e..036db52 100644 --- a/LocCorr/pusirobo.h +++ b/LocCorr/pusirobo.h @@ -19,26 +19,17 @@ #ifndef PUSIROBO_H__ #define PUSIROBO_H__ -typedef enum{ - PUSI_DISCONN, - PUSI_RELAX, - PUSI_SETUP, - PUSI_GOTOTHEMIDDLE, - PUSI_FINDTARGET, - PUSI_FIX, - PUSI_UNDEFINED -} pusistate; - // try to connect to local pusirobo server int pusi_connect(); -int pusi_setstate(pusistate newstate); -pusistate pusi_getstate(); -void pusi_disconnect(); -void pusi_process_corrections(double X, double Y, int corrflag); +// disconnect +void pusi_stop(); +// global variable proc_corr +void pusi_process_corrections(double X, double Y); +// global variable stepstatus char *pusi_status(const char *messageid, char *buf, int buflen); +// global variable setstepstatus char *set_pusistatus(const char *newstatus, char *buf, int buflen); +// global variable movefocus char *set_pfocus(const char *newstatus, char *buf, int buflen); -char *get_JSON_status(char *buf, int buflen); -// ADD global SEND #endif // PUSIROBO_H__ diff --git a/LocCorr/socket.c b/LocCorr/socket.c index cad2e72..8086509 100644 --- a/LocCorr/socket.c +++ b/LocCorr/socket.c @@ -79,8 +79,6 @@ static char *setfocusstate(const char *state, char *buf, int buflen); static setter setterHandlers[] = { {"stpstate", setstepperstate, "Set given steppers' server state"}, {"focus", setfocusstate, "Move focus to given value"}, -// {"exptime", setexposition, "Set exposition to new value (s)"}, -// {"expmethod", setexposmethod, "Set exposition method (\"manual\"/\"auto\")"}, {NULL, NULL, NULL} }; @@ -132,35 +130,6 @@ static char *setfocusstate(const char *state, char *buf, int buflen){ snprintf(buf, buflen, FAIL); return buf; } -/* -static char *setexposition(const char *expos, char *buf, int buflen){ - DBG("Set exp to %s ms", expos); - float e = atof(expos); - if(e < EXPOS_MIN || e > EXPOS_MAX){ - snprintf(buf, buflen, "bad value"); - }else{ - exptime = (float) e; - LOGMSG("Set exposition time to %gms", e); - snprintf(buf, buflen, OK); - } - return buf; -} -static char *setexposmethod(const char *expos, char *buf, int buflen){ - int good = 0; - if(strncasecmp(expos, "auto", 4) == 0){ - autoExposition = TRUE; - LOGMSG("Set exposition method to \"auto\""); - good = 1; - }else if(strncasecmp(expos, "manual", 6) == 0){ - autoExposition = FALSE; - LOGMSG("Set exposition method to \"manual\""); - good = 1; - } - if(good) snprintf(buf, buflen, OK); - else snprintf(buf, buflen, "wrong method: \"%s\"", expos); - return buf; -} -*/ /* static char *rmnl(const char *msg, char *buf, int buflen){