Main Page   Data Structures   File List   Data Fields   Globals  

motion.c

Go to the documentation of this file.
00001 #include "motion.h"
00002 #include "bppio.h"
00003 #include "bppimpl.h"
00004 
00005 
00006 #ifdef DEBUG
00007 const static int debuglevel =
00008 #ifdef DEBUGLEVEL
00009 DEBUGLEVEL;
00010 #else
00011 1;
00012 #endif
00013 #define DBUGMESS(N, PRINTARGS) if ((N) >= debuglevel) fprintf PRINTARGS
00014 #else
00015 #define DBUGMESS(N, PRINTARGS) /* sfa */
00016 #define DBUGPERR(ERR, MESS) if (ERR) perror(MESS)
00017 #endif
00018 
00019 static const char* xlabel = "X";
00020 static const char* ylabel = "Y";
00021 
00022 static const int deltamag = 1;       /* nominal step size magnitude */
00023 static const velocity_t basespeed = 50.0;
00024 static const velocity_t vslow = 1.0 / 128;  /* speeds < vslow steps/s set to 0 */
00025 static const velocity_t minturn = 5.0;   /* minimum speed when changing direction */
00026 static const velocity_t mincoast = 0.5;  /* minimum speed when coasting */
00027 
00028 static void* track (void* arg);
00029 static int xstep(int fd, int incr);
00030 static int ystep(int fd, int incr);
00031 static int nextwake (const velocity_t vs, const velocity_t minspeed, struct timespec* thewake);
00032 static double findattract (const double qn, const velocity_t pn,
00033                            const double qg, const velocity_t pg);
00034 static velocity_t nextvel (const double qn, const velocity_t pn,
00035                            const double qg, const velocity_t pg,
00036                            const double qc, coord_t* delta);
00037 
00038 
00039 
00040 
00041 void showreg (int fd)
00042 {
00043    struct bpp_reg reg_dump;
00044    int err;
00045 
00046    err = ioctl(fd, BPPIOC_GETREGS, &reg_dump);
00047    fprintf(stderr, "Status code (register dump) %d.\n", err);
00048    fprintf(stderr, "dma_csr     = %x\n", reg_dump.dma_csr);
00049    fprintf(stderr, "dma_addr    = %x\n", reg_dump.dma_addr);
00050    fprintf(stderr, "dma_bcnt    = %d\n", reg_dump.dma_bcnt);
00051    fprintf(stderr, "dma_tst_csr = %x\n", reg_dump.dma_tst_csr);
00052    fprintf(stderr, "hw_config   = %x\n", reg_dump.hw_config);
00053    fprintf(stderr, "op_config   = %x\n", reg_dump.op_config);
00054    fprintf(stderr, "data        = %x\n", reg_dump.data);
00055    fprintf(stderr, "trans_cntl  = %x\n", reg_dump.trans_cntl);
00056    fprintf(stderr, "out_pins    = %x\n", reg_dump.out_pins);
00057    fprintf(stderr, "in_pins     = %x\n", reg_dump.in_pins);
00058    fprintf(stderr, "int_cntl    = %x\n", reg_dump.int_cntl);
00059 }
00060    
00061 int openstage (ptraject stage, const char* path)
00062 {
00063    int err = 0;
00064 
00065    stage->filedescr = open(path, O_WRONLY);
00066    if (stage->filedescr < 0) {
00067       err = stage->filedescr;
00068       perror("Couldn't open");
00069    } else {
00070       int ax  = stage->naxes;
00071       ptranslation trans = stage->axis;
00072       while (!err && ax-- && (trans != NULL)) {
00073          err = start(stage->filedescr, trans, &stage->tattr);
00074          trans++;
00075       }
00076       if (!err && !ax) {
00077          err = -1;
00078          DBUGMESS(1, (stderr, "openstage: undefined axis\n"));
00079       }
00080    }
00081    return err;
00082 }
00083 
00084 int closestage (ptraject stage)
00085 {
00086    int ax  = stage->naxes;
00087    ptranslation trans = stage->axis;
00088    int err = 0;
00089 
00090    while (!err && ax-- && (trans != NULL)) {
00091       err = stop(trans);
00092       trans++;
00093    }
00094    if (!err && !ax) {
00095       err = -1;
00096       DBUGMESS(1, (stderr, "closestage: undefined axis\n"));
00097    }
00098    if (!err) {
00099       err = close(stage->filedescr);
00100       if (err)
00101          perror("Closestage couldn't close");
00102    }
00103    return err;
00104 }
00105 
00106 void disposestage (ptraject stage)
00107 {
00108    free(stage->axis);
00109    pthread_attr_destroy(&stage->tattr);
00110    free(stage);
00111 }
00112 
00113 int movestage (ptraject stage, pmotion motn)
00114 {
00115    int err = 0;
00116    int ax  = stage->naxes;
00117 
00118    ptranslation trans = stage->axis;
00119    while (!err && ax-- && (trans != NULL) && (motn != NULL)) {
00120       DBUGMESS(1, (stderr, "Movestage: starting %s axis\n", trans->label));
00121       err = moveto(trans, motn);
00122       trans++;
00123       motn++;
00124    }
00125    if (err) DBUGMESS(1, (stderr, "Movestage: error on axis %d, code %d\n", ax, err));
00126    if (!err && !ax) {
00127       err = -1;
00128       if (trans == NULL)
00129          DBUGMESS(1, (stderr, "movestage: undefined axis\n"));
00130       if (motn == NULL)
00131          DBUGMESS(1, (stderr, "movestage: undefined motion\n"));
00132    }
00133    return err;
00134 }
00135 
00136 int findstage (ptraject stage, pmotion motn)
00137 {
00138    int err = 0;
00139    int ax  = stage->naxes;
00140 
00141    ptranslation trans = stage->axis;
00142    while (!err && ax-- && (trans != NULL) && (motn != NULL)) {
00143       DBUGMESS(1, (stderr, "Findstage: looking at %s axis\n", trans->label));
00144       err = where(trans, motn);
00145       trans++;
00146       motn++;
00147    }
00148    if (err) DBUGMESS(1, (stderr, "Findstage: error on axis %d, code %d\n", ax, err));
00149    if (!err && !ax) {
00150       err = -1;
00151       if (trans == NULL)
00152          DBUGMESS(1, (stderr, "Findstage: undefined axis\n"));
00153       if (motn == NULL)
00154          DBUGMESS(1, (stderr, "Findstage: undefined motion\n"));
00155    }
00156    return err;
00157 }
00158 
00159 ptraject newxystage (void)
00160 {
00161    ptraject stage;
00162 
00163    stage = (ptraject)malloc(sizeof(struct Traject));
00164    if (stage != NULL) {
00165      int err = pthread_attr_init(&stage->tattr);
00166      if (!err) {
00167         if (err = pthread_attr_setdetachstate(&stage->tattr, PTHREAD_CREATE_DETACHED))
00168            pthread_attr_destroy(&stage->tattr);
00169      }
00170      if (err) {
00171         free(stage);
00172         stage == NULL;
00173      }
00174    }
00175    if (stage != NULL) {
00176       stage->naxes = 2;
00177       stage->axis = (ptranslation)calloc(2, sizeof(struct Translation));
00178       if (stage->axis == NULL) {
00179          free(stage);
00180          stage = NULL;
00181       } else {
00182          stage->axis[0].label   = xlabel;
00183          stage->axis[0].step    = xstep;
00184          stage->axis[0].pos     = 0;
00185          stage->axis[0].goalpos = 0;
00186          stage->axis[0].backlash= 0;
00187          stage->axis[0].maxlash = 13;
00188          stage->axis[0].vel     = 0;
00189          stage->axis[0].goalvel = 0;
00190          stage->axis[1].label   = ylabel;
00191          stage->axis[1].step    = ystep;
00192          stage->axis[1].pos     = 0;
00193          stage->axis[1].goalpos = 0;
00194          stage->axis[1].backlash= 0;
00195          stage->axis[1].maxlash = 2;
00196          stage->axis[1].vel     = 0;
00197          stage->axis[1].goalvel = 0;
00198       }
00199    }
00200    return (stage);
00201 }
00202 
00203 static double findattract (const double qn, const velocity_t pn,
00204                            const double qg, const velocity_t pg)
00205 {
00206    double qc;
00207 
00208    if (fabs(qn - qg) < deltamag/2.0) {
00209       qc = (fabs(pn - pg) <= fabs(pg)) ? qn : qn + pg;
00210    } else if ((fabs((pg + pn)/2) < deltamag/100.0) || (fabs(qn - qg) < deltamag/2.0)) {   /* colinear cases */
00211       qc = (qn + qg)/2;
00212    } else {
00213       qc = (pow(pn,2) - pow(pg,2) + pow(qn,2) - pow(qg,2)) / (2*(qn - qg));
00214    }
00215    return (qc);
00216 }
00217 
00218 static velocity_t nextvel (const double qn, const velocity_t pn,
00219                        const double qg, const velocity_t pg,
00220                        const double qc, coord_t* delta)
00221 {
00222    double r, r2;
00223    velocity_t v;
00224 
00225    if ((fabs(qn - qg) < deltamag/2.0) &&
00226        ((fabs(pn - pg) < vslow) || (fabs(pn - pg) < (fabs(pn) + fabs(pg))))){
00227       DBUGMESS(1, (stderr, "*"));
00228       *delta = 0;
00229       v = pg;
00230       DBUGMESS(1, (stderr, "--->\n"));
00231       return (v);
00232    }
00233    r2 = pow(qc - qg, 2) + pow(pg, 2);
00234    r  = sqrt(r2);
00235    if ((pn > 0) && (qn > (qc + r - (1 - 1E-4L)*deltamag))) {
00236       *delta = 0;
00237       v = -fabs(pn);
00238    } else if ((pn < 0) && (qn < (qc - r + (1 - 1E-4L)*deltamag))) {
00239       *delta = 0;
00240       v = fabs(pn);
00241    } else {
00242       *delta = ((pn < 0) || (pn == 0 && (qn > qc))) ? -deltamag : deltamag;
00243       v = sqrt(fabs(r2 - pow((qc - qn - *delta), 2)));
00244       if (*delta < 0)
00245          v = -v;
00246    }
00247    DBUGMESS(1, (stderr, "r=%10.4f qc=%10.4f qn=%10.4f qg=%10.4f pn=%10.4f pg=%10.4f v=%10.4f\n",
00248                    r, qc, qn, qg, pn, pg, v));
00249    return v;
00250 }
00251 
00252 static int nextwake (const velocity_t vs, const velocity_t minspeed, struct timespec* thewake)
00253 {
00254    long  tick;
00255    time_t sec;
00256    int err = 0;
00257    velocity_t v = fabs(vs);
00258 
00259    if (v < fabs(minspeed))
00260       v = fabs(minspeed);
00261    sec = (time_t)floor(1.0 / v);
00262    tick = (long)((double)NANOSEC * (1.0/v - sec));
00263    err = clock_gettime(CLOCK_REALTIME, thewake);
00264    if (err) {
00265       perror("Couldn't get time");
00266    } else {
00267       thewake->tv_sec += sec;
00268       if ((thewake->tv_nsec += tick) >= NANOSEC) {
00269          thewake->tv_nsec -= NANOSEC;
00270          thewake->tv_sec++;
00271       }
00272    }
00273    return (err);
00274 }
00275 
00276 static int xstep(int fd, int incr)
00277 {  
00278    struct bpp_delta move;
00279    
00280    move.x = 0;
00281    move.y = incr;
00282    return ioctl(fd, BPPIOC_STEP, &move);
00283 }
00284 
00285 static int ystep(int fd, int incr)
00286 {
00287    struct bpp_delta move;
00288    
00289    move.x = incr;
00290    move.y = 0;
00291    return ioctl(fd, BPPIOC_STEP, &move);
00292 }
00293 
00294 int moveto (ptranslation state, pmotion goal)
00295 {
00296    int err = 0;
00297 
00298    err = pthread_mutex_lock(&state->modlock);
00299    if (err) {
00300       DBUGMESS(1, (stderr, "moveto (%s axis): couldn't acquire lock, error %d\n",
00301                       state->label, err));
00302       return (err);
00303    }
00304    DBUGMESS(1, (stderr, "moveto (%s axis): going to %d, target speed %10.4f waiting....\n",
00305                    state->label, goal->pos, goal->vel));
00306    while (!err && ((state->pos != state->goalpos) ||
00307                    (fabs(state->vel - state->goalvel) >= vslow))) {
00308       err = pthread_cond_wait(&state->ontrack, &state->modlock);
00309    }
00310    if (err) {
00311       DBUGMESS(1, (stderr, "moveto (waiting on cv): invalid value\n"));
00312    } else {
00313       if (goal->relative) {
00314          state->goalpos = state->pos + goal->pos;
00315          state->goalvel = state->vel + goal->vel;
00316       } else {
00317          state->goalpos = goal->pos;
00318          state->goalvel = goal->vel;
00319       }
00320       state->scale = sqrt(120*(1 - (1/(1 + pow(state->vel - state->goalvel, 2) +
00321                                            pow(state->pos - state->goalpos, 2)))));
00322       if (state->scale < 0.25) state->scale = 0.25;
00323       state->attract = findattract(state->pos,     state->vel / state->scale, 
00324                                    state->goalpos, state->goalvel / state->scale);
00325       pthread_cond_signal(&state->offtrack);
00326       if (err)
00327          DBUGMESS(1, (stderr, "moveto (cv signal): invalid value\n"));
00328    }
00329    DBUGMESS(1, (stderr, "moveto (%s axis): going to %d, initial speed %10.4f\n",
00330                    state->label, state->goalpos, state->vel));
00331    pthread_mutex_unlock(&state->modlock);
00332    return (err);
00333 }
00334 
00335 int where (ptranslation state, pmotion here)
00336 {
00337    int err = 0;
00338 
00339    err = pthread_mutex_lock(&state->modlock);
00340    if (err) {
00341       DBUGMESS(1, (stderr, "where (%s axis): couldn't acquire lock, error %d\n",
00342                       state->label, err));
00343       return (err);
00344    }
00345    while (!err && (state->pos != state->goalpos)
00346                && (fabs(state->vel - state->goalvel) < vslow)) {
00347       err = pthread_cond_wait(&state->ontrack, &state->modlock);
00348    }
00349    if (err) {
00350       DBUGMESS(1, (stderr, "where: invalid value\n"));
00351    } else {
00352       here->pos = state->pos;
00353       here->vel = state->vel;
00354    }
00355    pthread_mutex_unlock(&state->modlock);
00356    return (err);
00357 }
00358 
00359 static void* track (void* arg)
00360 {
00361    ptranslation state = (ptranslation)arg;
00362    struct timespec wakeup;
00363    int delta;
00364    int err = 0;
00365 
00366    err = pthread_mutex_lock(&state->modlock);
00367    if (err)
00368       DBUGMESS(1, (stderr, "track (%s axis): couldn't acquire lock, error %d\n", state->label, err));
00369    while (!err) {
00370       /* Simple case: at rest . . . . */
00371       while (!err && (state->pos == state->goalpos)
00372                   && (fabs(state->vel) < vslow) && (fabs(state->goalvel) < vslow)) {
00373          DBUGMESS(1, (stderr, "%s resting\n", state->label));
00374          err = pthread_cond_wait(&state->offtrack, &state->modlock);
00375       }
00376       /* In motion . . . . */
00377       delta = ((state->vel > 0) ||
00378                ((state->vel == 0) && (state->pos < state->goalpos))) ? deltamag : -deltamag;
00379       err = nextwake(state->vel, mincoast, &wakeup);
00380       /* Coasting . . . . */
00381       while (!err && (state->pos == state->goalpos)
00382                   && (fabs(state->vel - state->goalvel) < vslow)) {
00383          DBUGMESS(1, (stderr, "%s coasting pos = %d vel = %10.4f\n",
00384                          state->label, state->pos, state->vel));
00385          err = pthread_cond_timedwait(&state->offtrack, &state->modlock, &wakeup);
00386          if (err == ETIMEDOUT) {
00387             err = (*(state->step))(state->device, delta);
00388             if (!err) {
00389                err = nextwake(state->vel, mincoast, &wakeup);
00390                if (abs(state->backlash + delta) < state->maxlash) {
00391                   state->backlash += delta;
00392                } else {
00393                   state->pos += delta;
00394                   state->goalpos += delta;
00395                }
00396             }
00397          }
00398       }
00399       /* Moving to goal . . . . */
00400       delta = ((state->vel > 0) ||
00401                ((state->vel == 0) && (state->pos < state->goalpos))) ? deltamag : -deltamag;
00402       err = nextwake(state->vel, minturn, &wakeup);
00403       while (!err && ((state->pos != state->goalpos) ||
00404                       (fabs(state->vel - state->goalvel) >= vslow))) {
00405          DBUGMESS(1, (stderr, ">>> %s moving pos = %d vel = %10.4f\n",
00406                          state->label, state->pos, state->vel));
00407          err = pthread_cond_timedwait(&state->ontrack, &state->modlock, &wakeup);
00408          if (err == ETIMEDOUT) {
00409             if (delta) {
00410                err = (*(state->step))(state->device, delta);
00411                if (err)
00412                   perror("driving motor");
00413                if (abs(state->backlash + delta) < state->maxlash) {
00414                   state->backlash += delta;
00415                } else {
00416                   state->pos += delta;
00417                }
00418             } else {
00419                err = 0;
00420             }
00421             if (!err) {
00422                state->vel = nextvel(state->pos,     state->vel / state->scale, 
00423                                     state->goalpos, state->goalvel / state->scale,
00424                                     state->attract, &delta) * state->scale;
00425                err = nextwake(state->vel, minturn, &wakeup);
00426             }
00427          }
00428       }
00429       if (!err && (state->pos == state->goalpos)) {
00430          DBUGMESS(1, (stderr, "*** %s reached goal pos = %d vel = %10.4f\n",
00431                          state->label, state->pos, state->vel));
00432          
00433          pthread_cond_signal(&state->ontrack);
00434       }
00435    }
00436    DBUGMESS(1, (stderr, "Exiting on code %d\n", err));
00437    pthread_mutex_unlock(&state->modlock);
00438    return (NULL);
00439 } 
00440 
00441 int start (int fd, ptranslation state, pthread_attr_t* ptattr)
00442 {
00443    int err = 0;
00444 
00445    state->device = fd;
00446    if (err = pthread_mutex_init(&state->modlock, NULL)) {
00447       DBUGMESS(1, (stderr, "start (%s mutex init): ", state->label));
00448    } else if (err = pthread_cond_init(&state->offtrack, NULL)) {
00449       DBUGMESS(1, (stderr, "start (%s offtrack init): ", state->label));
00450    } else if (err = pthread_cond_init(&state->ontrack, NULL)) {
00451       DBUGMESS(1, (stderr, "start (%s ontrack init): ", state->label));
00452    } else if (err = pthread_create(&state->tid, ptattr, track, (void*)state)) {
00453       DBUGMESS(1, (stderr, "start (%s thread creation): ", state->label));
00454    }
00455    switch (err) {
00456    case ENOMEM:
00457       DBUGMESS(1, (stderr, "not enough memory.\n"));
00458       break;
00459    case EAGAIN:
00460       DBUGMESS(1, (stderr, "system limit reached.\n"));
00461       break;
00462    case EINVAL:
00463       DBUGMESS(1, (stderr, "invalid attribute.\n"));
00464       break;
00465    case ESRCH:
00466       DBUGMESS(1, (stderr, "invalid thread ID.\n"));
00467       break;
00468    default:
00469       if (err)
00470          DBUGMESS(1, (stderr, "error %d.\n", err));
00471    }
00472    return (err);
00473 }
00474 
00475 int stop (ptranslation state)
00476 {
00477    int err = 0;
00478 
00479    DBUGMESS(1, (stderr, "stop (%s axis): waiting . . . .\n", state->label));
00480    pthread_mutex_lock(&state->modlock);
00481    if (err) {
00482       DBUGMESS(1, (stderr, "stop (%s axis): couldn't acquire lock, error %d\n",
00483                       state->label, err));
00484       return (err);
00485    }
00486    while (!err && ((state->pos != state->goalpos)  ||
00487                    (fabs(state->vel - state->goalvel) >= vslow))) {
00488       err = pthread_cond_wait(&state->ontrack, &state->modlock);
00489    }
00490    DBUGMESS(1, (stderr, "stop (%s axis): starting cleanup\n", state->label));
00491    if (err) {
00492       DBUGMESS(1, (stderr, "stop (%s waiting for move to complete): ", state->label));
00493    } else if (err = pthread_cancel(state->tid)) {
00494       DBUGMESS(1, (stderr, "stop (%s cancelling thread): ", state->label));
00495    }
00496    pthread_mutex_unlock(&state->modlock);
00497    if (!err) {
00498       if (err = pthread_cond_destroy(&state->offtrack)) {
00499          DBUGMESS(1, (stderr, "stop (%s offtrack destroy): ", state->label));
00500       } else if (err = pthread_cond_destroy(&state->ontrack)) {
00501          DBUGMESS(1, (stderr, "stop (%s ontrack destroy): ", state->label));
00502       } else if (err = pthread_mutex_destroy(&state->modlock)) {
00503          DBUGMESS(1, (stderr, "stop (%s mutex destroy): ", state->label));
00504       }
00505    }
00506    switch (err) {
00507    case ESRCH:
00508       DBUGMESS(1, (stderr, "invalid thread ID.\n"));
00509       break;
00510    case EINVAL:
00511       DBUGMESS(1, (stderr, "invalid attribute.\n"));
00512       break;
00513    default:
00514       if (err)
00515          DBUGMESS(1, (stderr, "error %d.\n", err));
00516    }
00517    return (err);
00518 }

Generated on Wed Apr 9 08:56:09 2003 for TREES by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002