Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

segmentqueue.c

Go to the documentation of this file.
00001 /*
00002 
00003   segmentqueue.c
00004 
00005   Modification history
00006   30-Jun-1999 RSB changed the calculation of the maximum tangential
00007   acceleration for circles (in sqAddCircle)
00008    8-Jun-1999 RSB added sqSetMaxFeedOverride to set a maximum value for
00009    the maximum feed override at start-up. This value is used for to determine
00010    if a segment needs to be linked when it's added to the queue. This way feed
00011    overrides larger than one are possible. Also added a line in sqPlanSegment
00012    to make sure that the maxInc*feedOverrideFactor never exceeds maxV, the
00013    system's maximum feed, times the cycleTime
00014    8-Jun-1999 RSB changed arguments of sqInitQueue: it now requires a valid
00015    pointer to an address where the segmentqueue should start. Symbols
00016    SQ_STATIC_LINKED_QUEUE and SQ_USE_SHARED_MEM are no longer needed and
00017    therefore deleted. Including of rtmalloc.h is needed anymore either
00018    7-Jun-1999 RSB implemented sqGetVel
00019    1-Jun-1999 RSB created sqLinkCriterion, sqForwardLinking and
00020    sqBackWardLinking. There used to be many places in the code where criterion
00021    checking and linking was done.
00022   25-May-1999 RSB added two other ways of allocating the memory for the
00023   segmentqueue: static (linked in) memory and in the memory that is not used
00024   by linux ("shared memory"). At compile time the preferred way can be selected
00025   by defining either SQ_STATIC_LINKED_QUEUE or SQ_USE_SHARED_MEM
00026   21-May-1999 RSB added a third parameter to sqLinkSegments that indicates
00027   the priority of the linking. Added two #define's as well:
00028   SQ_LOW_LINKING_PRIORITY and SQ_HIGH_LINKING_PRIORITY
00029   20-May-1999 RSB added a check on sq->numSegments==0 in sqSetFeedOverride
00030   sqPause and sqResume (bug fix).
00031   18-May-1999 RSB added helixRadius to segment, which is used instead
00032   of radius when doing length-related calculations with circles, so
00033   that helices can be executed as well. Also made some modifications
00034   to sqGiveCornerInc for the same reason.
00035   14-May-1999  RSB modified the code such that a feedOverride of zero is
00036   dealt with correctly: it will pause the system until a new, non-zero value
00037   for the feed override will be given.
00038   14-May-1999  RSB added a 'sq' prefix to all local functions. All functions
00039   in segmentqueue now begin with sq.
00040   14-May-1999  RSB made code more clean: every time a function returns -1
00041   this is catched by the routine that calls the function. Besides, every time
00042   a 'return -1' is executed, a diagnostic message is printed. The printing of
00043   these messages can be switched of by defining SQ_NO_DEBUG_PRINTING.
00044   To disable just one message,  replace 'diagnostics' with 'diagnostics off'.
00045   13-May-1999  RSB added a couple checks to barf when sq->numSegments gets
00046   negative somehow
00047   10-May-1999  RSB made code more clean: added lots of nullpointer checks
00048   10-May-1999  RSB changed giveCornerVelocity to return DBL_MAX when two
00049   segments align perfectly.
00050   24-Mar-1999  RSB changed the giveCornerVelocity implementation. The corner
00051   velocity is now calculated by selecting the axis with the largest
00052   'velocity jump', and using that to determine the maximum velocity.
00053   11-Mar-1999  RSB added more switches throughout the code to distinguish
00054   between linear and circular movements
00055   11-Mar-1999  RSB removed sqAppendMotion, added sqAddLine and sqAddCircle
00056   10-Mar-1999  RSB replaced as many pose related calcutions as possible with
00057   the corresponding functions from the posemath library
00058   10-Mar-1999  RSB removed the slopes[3], changed to PmLine
00059    9-Mar-1999  RSB changed to PmPose
00060    6-Mar-1999  RSB added a test every time before the sq->full is reset
00061    6-Mar-1999  RSB removed the functions unlinkSegments and givePrevSeg, since
00062    they were never used
00063    6-Mar-1999  RSB removed some diagnostics printing
00064    3-Mar-1999  RSB added a safety margin in the queue, such that after a
00065    the threshold is exceeded, sq->full flag will be set. The size of the
00066    margin is a variable named SQ_SAFETY_MARGIN
00067    3-Mar-1999  RSB added handling of aborting flag, so that after an abort the
00068    segmentqueue is cleared
00069    2-Mar-1999  RSB added a macro for diagnostics printing
00070   18-Feb-1999  RSB changed sqSetFeedOverride(): when the given factor is out
00071                of the valid range, it doesn't return -1 anymore, but clamps
00072                the value.
00073   28-Jan-1999  RSB added giveMaxInc()
00074   26-Jan-1999  RSB added plInitInc and plFinalInc to SEGMENT
00075                planSegment and other functions were modified
00076   26-Jan-1999  RSB changed arguments of planSegment (now includes sq)
00077   25-Jan-1999  RSB added sqSetFeedOverride() (many modifications needed)
00078   25-Jan-1999  RSB added sqIsStepping()
00079   22-Jan-1999  RSB added sqStep() (modifications elsewhere needed too)
00080   21-Jan-1999  RSB added sqResume() (modification needed for runCycle)
00081   20-Jan-1999  RSB added sqPause() (slight modification needed for runCycle)
00082   05-Jan-1999  RSB changed queue structure to ring buffer
00083   07-Dec-1998  RSB created
00084 
00085 
00086 */
00087 # include "segmentqueue.h"
00088 
00089 # ifdef rtlinux
00090 # include <linux/kernel.h>
00091 # else
00092 # include <stdio.h>
00093 # endif
00094 
00095 #include <float.h>   /* for DBL_MAX */
00096 
00097 /* sq->full will be set 1 when the number of segments exceeds the size
00098    of the queue minus the safety margin. This safety margin is created
00099    because it might happen that the task will send another motion (or more)
00100    before it gets the signal that the queue is full. Without a safety margin,
00101    this would result in a queue overflow
00102 */
00103 #define SQ_SAFETY_MARGIN 10
00104 
00105 /* if linking is possible, it will generally do it. With certain program
00106    this could result in a completely linked segment queue. When the chain is
00107    done, it will be deleted from the queue, that will be completely empty then.
00108    This variable can be used to set an upper limit for the number of linked
00109    segments */
00110 #define SQ_MAX_NUM_LINKED_SEGS 500
00111 
00112 #define SQ_LOW_LINKING_PRIORITY 1
00113 #define SQ_HIGH_LINKING_PRIORITY 2
00114 
00115 #define SQ_LINKING_NEEDED 2
00116 #define SQ_LINKING_NOT_NEEDED 1
00117 
00118 /* diagnostics printing */
00119 #if !defined(SQ_NO_DEBUG_PRINTING)
00120 #   undef diagnostics
00121 #   ifdef rtlinux
00122 #     define diagnostics(fmt, args...) printk(KERN_CRIT fmt, ## args)
00123 #   else
00124 #     define diagnostics(fmt,args...) fprintf(stderr, fmt, ## args )
00125 #   endif
00126 #else
00127 #   define diagnostics(fmt, args...) /* not debugging: nothing */
00128 #endif
00129 
00130 /* the next define can be used to turn off printing of individual messages */
00131 #define diagnosticsOff(fmt, args...) /* nothing: it's a placeholder */
00132 
00133 /* some static variables for debugging */
00134 static EmcPose oldPos, oldVel, newVel, newAcc;
00135 static double oldDist;
00136 
00137 /* functions for 'internal' use */
00138 /* ---------------------------- */
00139 
00140 static double sqGiveLength(EmcPose p1, EmcPose p2)
00141 {
00142   PmCartesian disp;
00143   double mag;
00144 
00145   pmCartCartSub(p1.tran, p2.tran, &disp);
00146   pmCartMag(disp, &mag);
00147 
00148   return mag;
00149 };
00150 
00151 
00152 static double sqGiveCornerVelocity(SEGMENT *s1, SEGMENT *s2, double amax, \
00153                                  double cycleTime )
00154 {
00155   /* s1 and s2 must have been initialized correctly and must have a nonzero
00156      lenght in order to get a valid corner */
00157 
00158   PmCartesian v1;
00159   PmCartesian v2;
00160   PmCartesian me;
00161   PmCartesian diff;
00162   PmCartesian helix;
00163 
00164   double maxdiff;
00165 
00166   if ( s1 == 0 || s2 == 0 )
00167     {
00168       diagnostics("Error in sqGiveCornerVelocity()\n");
00169       return -1;
00170     }
00171 
00172   /* check if s1 or s2 has a zero length or amax or cycleTime is zero */
00173   if ( s1->length == 0 || s2->length == 0 || amax==0 || cycleTime==0 )
00174     {
00175       /* of course this shouldn't happen */
00176       diagnostics("Error in sqGiveCornerVelocity()\n");
00177       return -1;
00178     }
00179 
00180   if (s1->type == SQ_LINEAR)
00181     {
00182         v1=s1->line.uVec;
00183     }
00184   else
00185     {
00186       pmCartCartSub( s1->end.tran , s1->circle.center, &me );
00187       pmCartCartCross( s1->circle.normal, me, &v1 );
00188       pmCartScalDiv ( s1->circle.rHelix, s1->circle.angle, &helix);
00189       pmCartCartAdd ( v1, helix, &v1);
00190       pmCartNorm ( v1, &v1 );
00191 
00192     }
00193 
00194   if (s2->type == SQ_LINEAR)
00195     {
00196       v2=s2->line.uVec;
00197     }
00198   else
00199     {
00200       pmCartScalDiv ( s2->circle.rHelix, s2->circle.angle, &helix);
00201       pmCartCartAdd ( s2->circle.rPerp, helix, &v2);
00202       pmCartNorm ( v2, &v2 );
00203     }
00204 
00205   /* calculate the difference between v1 and v2 */
00206   pmCartCartSub ( v2,v1, &diff );
00207 
00208   /* select the largest element in diff */
00209   maxdiff = max ( fabs(diff.x), fabs(diff.y) );
00210   maxdiff = max ( maxdiff , fabs(diff.z) );
00211 
00212   /* return cornerVelocity */
00213   if ( maxdiff <= 0 )
00214     return DBL_MAX;
00215   else
00216     return ( amax * cycleTime / maxdiff );
00217 
00218 };
00219 
00220 static double sqGiveMinAmaxTan(SEGMENT *s)
00221 {
00222   /* give the minimum tangential acceleration for the chain of linked
00223      that starts with s. */
00224   SEGMENT *cursor;
00225   double minAmax;
00226 
00227   if (s == 0)
00228     {
00229       diagnostics("Error in sqGiveMinAmaxTan()\n");
00230       return -1;
00231     }
00232 
00233   if ( s->numLinkedSegs == 0 )
00234     return s->amaxTan;
00235 
00236   minAmax = s->amaxTan;
00237   cursor = s;
00238 
00239   while (cursor->nextSegment!=0 && cursor->nextSegment->linkedToPrevSeg==1)
00240     {
00241       cursor = cursor->nextSegment;
00242       if (cursor->amaxTan < minAmax )
00243         {
00244           minAmax = cursor->amaxTan;
00245         }
00246     }
00247   return minAmax;
00248 }
00249 
00250 static double sqGiveMaxInc(SEGMENTQUEUE *sq, SEGMENT *s)
00251      /* give the right maxInc from the chain of linked segments that start
00252         with s. */
00253 {
00254   int done=0;
00255   int minNumSteps;
00256   double startInc,finalInc;
00257   SEGMENT *cursor;
00258   double l;
00259   double maxAccTan;
00260 
00261   if (sq == 0 || s == 0)
00262     {
00263       diagnostics("Error in sqGiveMaxInc()\n");
00264       return -1;
00265     }
00266 
00267   if ( s->numLinkedSegs == 0 )
00268     return s->maxInc;
00269 
00270   maxAccTan = sqGiveMinAmaxTan(s);
00271 
00272   startInc=s->plInitInc;
00273   cursor=s;
00274   l=s->length;
00275   while (!done)
00276     {
00277       if ( cursor->nextSegment==0 )
00278         {
00279           return cursor->maxInc;
00280         }
00281       if ( cursor->nextSegment!=0 && cursor->nextSegment->maxInc < \
00282            cursor->maxInc)
00283         finalInc=min(cursor->finalInc,\
00284                      cursor->nextSegment->maxInc*sq->feedOverrideFactor);
00285 
00286       else
00287         finalInc=min(cursor->finalInc,\
00288                      cursor->maxInc*sq->feedOverrideFactor);
00289       minNumSteps = ceil ( 3 *fabs(finalInc-startInc) / \
00290                            ( 2 * maxAccTan * sq->ctPow2 ));
00291 
00292       if ((minNumSteps+1)* (startInc+finalInc)/2 -startInc > \
00293           l - 5 * max(finalInc,startInc) )
00294         {
00295           /* this segment was too short and therefore linked to the next
00296              one */
00297           cursor=cursor->nextSegment;
00298           l+=cursor->length;
00299         }
00300       else
00301         done=1;
00302     }
00303 
00304   return cursor->maxInc;
00305 }
00306 int sqLinkCriterion(SEGMENTQUEUE *sq, SEGMENT *s, double feedOverride)
00307 {
00308   /* this function returns SQ_LINKING_NEEDED if the chain of segments starting
00309      with s is not long enough to accelerate or decelerate from the initial
00310      increment of the first segment in the chain to the final increment of the
00311      last segment in the chain
00312   */
00313 
00314   double amaxTan;
00315   double initInc, finalInc;
00316   int minNumSteps, i;
00317   SEGMENT *lastSeg;
00318 
00319   if ( sq == 0 || s == 0 )
00320     {
00321       diagnostics("Error in sqLinkCriterion\n");
00322       return -1;
00323     }
00324 
00325   if ( s->linkedToPrevSeg == 1 )
00326     {
00327       diagnostics("Segment s is linked to it's preceding segment in sqLinkCriterion\n");
00328       return -1;
00329     }
00330 
00331   /* find the last segment of the chain */
00332   lastSeg = s;
00333   for ( i=0 ; i<s->numLinkedSegs; i++)
00334     {
00335       lastSeg=lastSeg->nextSegment;
00336       if (lastSeg == 0 )
00337         {
00338           diagnostics("Panic: NULL pointer in sqLinkCriterion\n");
00339           return -1;
00340         }
00341     }
00342 
00343   /* find the minimum boundary for the acceleration in tangential
00344      direction */
00345   /* FIXME: this can be combined with the previous for statement that
00346      looks up the last segment of the chain */
00347   amaxTan = sqGiveMinAmaxTan(s);
00348 
00349   /* find the correct value for the initial increment: when s->plInitInc is
00350      non zero, this means that the segment has been processed before, and that
00351      value should be used */
00352   if ( 0 != s->plInitInc )
00353     initInc = s->plInitInc;
00354   else
00355     initInc = s->initInc;
00356 
00357   /* find the correct value of the final increment (with taking a feedoverride
00358      into account).*/
00359   if ( feedOverride >= 1.0)
00360     {
00361       finalInc=lastSeg->finalInc;
00362     }
00363   else
00364     {
00365       if ( lastSeg->nextSegment!=0 && lastSeg->nextSegment->maxInc < \
00366            lastSeg->maxInc)
00367         finalInc=min(lastSeg->finalInc,\
00368                      lastSeg->nextSegment->maxInc*feedOverride);
00369       else
00370         finalInc=min(lastSeg->finalInc,\
00371                      lastSeg->maxInc*feedOverride);
00372     }
00373   minNumSteps=ceil(3* fabs(initInc - finalInc ) / (2*amaxTan*sq->ctPow2));
00374   if ((minNumSteps+1)*(initInc + finalInc)/2 - initInc >  \
00375       s->totLength - 2*initInc - finalInc -  5*max(initInc,finalInc) )
00376     {
00377       return SQ_LINKING_NEEDED;
00378     }
00379   else
00380     {
00381       return SQ_LINKING_NOT_NEEDED;
00382     }
00383 }
00384 
00385 static int sqPlanSegment(SEGMENTQUEUE *sq, SEGMENT *s)
00386 {
00387   /* variable declaration */
00388   double length;
00389   double maxInc;
00390   double amaxTan;
00391 
00392   SEGMENT *cursor;
00393 
00394   int validSolutionFound;
00395 
00396   if (sq==0)
00397     {
00398       diagnostics("Error in sqPlanSegment()\n");
00399       return -1;
00400     }
00401 
00402 
00403   /* check is s is a valid pointer */
00404   if (s==0)
00405     {
00406       diagnostics("Error in sqPlanSegment()\n");
00407       return -1;
00408     }
00409 
00410 
00411   /* check if this segment is linked to its predecessor (which should never
00412      happen!) */
00413   if ( s->linkedToPrevSeg == 1 )
00414     {
00415       diagnostics("Error in sqPlanSegment()\n");
00416       return -1;
00417     }
00418 
00419 
00420   length=s->length;
00421   cursor=s;
00422 
00423   /* check if there are any segments linked to s, find the total length of the
00424      linked segments and find the finalInc of the last segment in the chain */
00425   while (cursor->nextSegment!=0 && cursor->nextSegment->linkedToPrevSeg)
00426     {
00427       cursor = cursor->nextSegment;
00428     }
00429 
00430   if ( SQ_LINKING_NEEDED == sqLinkCriterion(sq,s,1.0) )
00431     {
00432       diagnostics("Error in sqPlanSegment(), chain too short\n");
00433       if (s->initInc > cursor->finalInc )
00434         diagnostics("InitInc > finalInc \n");
00435       else
00436         diagnostics("InitInc < finalInc \n");
00437 
00438       diagnostics("ID = %d\n", s->ID );
00439       diagnostics("Startpt: x=%d, y=%d, z=%d\n",(int)(1000.0*s->start.tran.x),(int)(1000.0*s->start.tran.y),(int)(1000.0*s->start.tran.z));
00440     }
00441 
00442 
00443   if (-1 == (maxInc=sqGiveMaxInc(sq,s)*sq->feedOverrideFactor))
00444     {
00445       diagnostics("Error in sqPlanSegment()\n");
00446       return -1;
00447     }
00448 
00449   /* maxInc should never exceed the the system's maximum increment
00450      (maxV*cycleTime) */
00451   maxInc = min(maxInc, sq->maxV*sq->cycleTime);
00452 
00453   /* find the minimum value for the maximum tangential acceleration for this
00454      chain of segments beginning with s*/
00455   amaxTan = sqGiveMinAmaxTan(s);
00456   diagnosticsOff("AmaxTan in sqplansegment  = %d \n",(int)(ceil(amaxTan)));
00457   /* finalInc ( = initInc of nextSegment) should never be larger than
00458      the maxInc * feedOveride of this segment and the next segment */
00459 
00460   if ( cursor->finalInc!=0)     /* if true: this is not the last segment */
00461     {
00462       if ( cursor->nextSegment->maxInc < cursor->maxInc)
00463         s->plFinalInc=min(cursor->finalInc,\
00464                           cursor->nextSegment->maxInc*sq->feedOverrideFactor);
00465 
00466       else
00467         s->plFinalInc=min(cursor->finalInc,maxInc);
00468 
00469       cursor->nextSegment->plInitInc=s->plFinalInc;
00470     }
00471   else
00472     s->plFinalInc=0;
00473 
00474 
00475   /* the first two steps and the last step are already defined */
00476   length = s->totLength - 2* s->plInitInc - s->plFinalInc;
00477 
00478 
00479   /* calculate minimal number of steps for the first phase (acc) */
00480   if (s->plInitInc == maxInc)
00481     s->m=0;
00482   else
00483     /* m should be always be two steps or more */
00484     s->m=max(2,ceil ( 3*fabs(maxInc-s->plInitInc)/(2*amaxTan*sq->ctPow2)));
00485 
00486   /* calulate minimal number of steps for the third phase (dec) */
00487   if (s->plFinalInc == maxInc)
00488     s->q=0;
00489   else
00490     s->q=max(2,ceil(3*fabs(maxInc-s->plFinalInc)/(2*amaxTan*sq->ctPow2)));
00491 
00492   /* calculate the minimal number of steps needed for the cruising phase */
00493   if (length - ((s->m+1)*(s->plInitInc+maxInc)/2 - s->plInitInc)*(s->m!=0)   \
00494              - ((s->q+1)*(maxInc+s->plFinalInc)/2 - maxInc)*(s->q!=0) < 0 )
00495     {
00496       /* true: there is no cruising phase */
00497        s->p=3;
00498       validSolutionFound=0;
00499       if (s->ID==474) diagnostics("0: maxInc = %d, initInc = %d, finalInc = %d\n",(int)(100000.0*maxInc), (int)(100000.0*s->plInitInc),(int)(100000.0*s->plFinalInc));
00500       if ( maxInc > s->plInitInc && maxInc > s->plFinalInc )
00501         {
00502           maxInc = -s->p*amaxTan*sq->ctPow2/3 + sqrt ( 4*s->p*s->p*amaxTan*amaxTan*sq->ctPow2*sq->ctPow2 + 18*(s->plInitInc*s->plInitInc+s->plFinalInc*s->plFinalInc) + 12*amaxTan*sq->ctPow2*(s->plInitInc-s->plFinalInc+2*length))/6;
00503           diagnosticsOff("1: maxInc = %d\n",(int)(100000.0*maxInc));
00504           if ( maxInc > s->plInitInc && maxInc > s->plFinalInc )
00505             {
00506               validSolutionFound=1;
00507             }
00508         }
00509 
00510       if ( (s->plInitInc >= maxInc && maxInc > s->plFinalInc) || !validSolutionFound )
00511         {
00512           maxInc = 3*((s->plFinalInc*s->plFinalInc - s->plInitInc*s->plInitInc) + 2*amaxTan*sq->ctPow2*(s->plInitInc-s->plFinalInc+2*length))/(4 * s->p * amaxTan * sq->ctPow2 );
00513           diagnosticsOff("2: maxInc = %d\n",(int)(100000.0*maxInc));
00514           if ( s->plInitInc >= maxInc && maxInc > s->plFinalInc )
00515             {
00516               validSolutionFound=1;
00517             }
00518         }
00519       if ( (s->plInitInc < maxInc && maxInc <= s->plFinalInc) || !validSolutionFound )
00520         {
00521           maxInc = ( 3*( s->plInitInc*s->plInitInc - s->plFinalInc*s->plFinalInc) + 2*amaxTan*sq->ctPow2*(s->plInitInc-s->plFinalInc+2*length))/(4 * s->p * amaxTan * sq->ctPow2 );
00522           diagnosticsOff("3: maxInc = %d\n",(int)(100000.0*maxInc));
00523           if ( s->plInitInc < maxInc && maxInc <= s->plFinalInc )
00524             {
00525               validSolutionFound=1;
00526             }
00527         }
00528       if ( ( maxInc <= s->plInitInc && maxInc <= s->plFinalInc) || !validSolutionFound )
00529         {
00530           maxInc = s->p*amaxTan*sq->ctPow2/3 + sqrt ( 4*s->p*s->p*amaxTan*amaxTan*sq->ctPow2*sq->ctPow2 + 18*(s->plInitInc*s->plInitInc+s->plFinalInc*s->plFinalInc) + 12*amaxTan*sq->ctPow2*(-s->plInitInc+s->plFinalInc-2*length))/6;
00531           diagnosticsOff("4: maxInc = %d\n",(int)(100000.0*maxInc));
00532           if ( maxInc <= s->plInitInc && maxInc <= s->plFinalInc )
00533             {
00534               validSolutionFound=1;
00535             }
00536         }
00537       if ( !validSolutionFound )
00538         {
00539           diagnostics("No solution found in sqPlanSegment\n");
00540           return -1;
00541         }
00542 
00543       /* recalculate m and q */
00544       s->m=ceil(3*fabs(maxInc-s->plInitInc)/(2*amaxTan*sq->ctPow2));
00545       s->q=ceil(3*fabs(maxInc-s->plFinalInc)/(2*amaxTan*sq->ctPow2));
00546       s->p=ceil((length-(s->m!=0)*((s->m+1)*(s->plInitInc+maxInc)/2-\
00547                  s->plInitInc)-(s->q!=0)*((s->q+1)*(s->plFinalInc+maxInc)/2\
00548                  -maxInc))/maxInc );
00549    }
00550   else
00551       s->p=ceil((length-(s->m!=0)*((s->m+1)*(s->plInitInc+maxInc)/2-\
00552                  s->plInitInc)-(s->q!=0)*((s->q+1)*(s->plFinalInc+maxInc)/2\
00553                  -maxInc))/maxInc );
00554 
00555   /* adjust maxInc a little */
00556   maxInc= (2*length-(s->m!=0)*(s->m-1)*s->plInitInc\
00557            -(s->q!=0)*(s->q+1)*s->plFinalInc) \
00558            / ( (s->m!=0)*(s->m+1) + 2 * s->p + (s->q!=0)*(s->q-1) );
00559 
00560 /*    if ((s->m<=1) && (fabs(s->plInitInc - maxInc) > 0.3*amaxTan*sq->ctPow2)) */
00561 /*      { */
00562 /*        s->m=2; */
00563 /*        maxInc = (2*length - (s->m!=0) * (s->m-1) * s->initInc */
00564 /*              - (s->q!=0) * (s->q+1) * s->plFinalInc) \ */
00565 /*         / ( (s->m!=0) * (s->m+1) + 2 * s->p + (s->q!=0)*(s->q-1) ); */
00566 /*      } */
00567 /*    if ((s->q<=1) && (fabs(s->plFinalInc-maxInc)> 0.3 * amaxTan*sq->ctPow2))     */
00568 /*      { */
00569 /*        s->q=2; */
00570 /*        maxInc= (2*length - (s->m!=0)*(s->m-1)*s->plInitInc  */
00571 /*             - (s->q!=0) * (s->q+1) * s->plFinalInc) \ */
00572 /*         / ( (s->m!=0)*(s->m+1) + 2 * s->p + (s->q!=0)*(s->q-1) ); */
00573 /*      } */
00574   s->totNumPoints= s->m + s->p + s->q + 3;
00575   s->cruiseInc=maxInc;
00576 
00577   /* ok, we've found (sub)-optimal values for m, p and q. Let's go on
00578      with the actual planning */
00579 
00580   if (s->m!=0)
00581     {
00582       s->b1 = 3 * (maxInc-s->plInitInc ) / ( (s->m*s->m*sq->ctPow2) );
00583       s->a1 = -2 * s->b1 / ( 3 * s->m * sq->cycleTime) ;
00584       s->c1 = 0;
00585       s->d1 = s->plInitInc;
00586     }
00587 
00588   else s->a1 = s->b1 = s->c1 = s->d1 = 0;
00589 
00590   if (s->q!=0)
00591     {
00592       s->b3 = 3 * ( s->plFinalInc - maxInc ) / ( (s->q*s->q*sq->ctPow2) );
00593       s->a3 = -2 * s->b3 / ( 3 * s->q * sq->cycleTime) ;
00594       s->c3 = 0;
00595       s->d3 = maxInc;
00596     }
00597   else s->a3 = s->b3 = s->c3 = s->d3 = 0;
00598 
00599   s->planningDone=1;
00600 
00601   return 0;
00602 };
00603 
00604 /* function to link s2 to s1
00605    Here it is assumed that s1 and s2 are indeed successive segments */
00606 static int sqLinkSegments(SEGMENT *s1, SEGMENT *s2, int priority)
00607 {
00608   if (s1==0)
00609     {
00610       diagnostics("Error 1a in sqLinkSegments() \n");
00611       return -1;
00612     }
00613   if (s2==0)
00614     {
00615       diagnostics("Error 1b in sqLinkSegments() \n");
00616       return -1;
00617     }
00618 
00619 
00620   /* if s2 is not the segment that immediately follows s1, then linking
00621      can not be done */
00622 
00623   if ( s1->nextSegment != s2 )
00624     {
00625       diagnostics("Error 2 in sqLinkSegments()\n");
00626       return -1;
00627     }
00628 
00629   /* if s1 is active, linking should not be done */
00630   if (s1->active == 1)
00631     {
00632 /*        diagnostics("Error in sqLinkSegments()\n"); */
00633 /*        return -1; */
00634       return 0;
00635     }
00636 
00637   /* find the first element in the series of linked segments of which s1 is
00638      the last one */
00639   while (s1->linkedToPrevSeg)
00640     {
00641       if (s1==0)
00642         {
00643           diagnostics("Panic: NULL pointer in sqLinkSegments\n");
00644           return -1;
00645         }
00646       s1=s1->prevSegment;
00647     }
00648 
00649   if ( s1->numLinkedSegs > SQ_MAX_NUM_LINKED_SEGS && priority==SQ_LOW_LINKING_PRIORITY)
00650     return 0;
00651 
00652   s1->numLinkedSegs += s2->numLinkedSegs + 1;
00653   s1->totLength += s2->totLength;
00654   s2->linkedToPrevSeg = 1;
00655   s2->numLinkedSegs = 0;
00656 
00657 /*    if (priority==SQ_HIGH_LINKING_PRIORITY) */
00658 /*      {   */
00659 /*        s2->amaxTan = s2->amaxTan * 0.50; */
00660 /*      } */
00661 
00662   return 0;
00663 }
00664 
00665 int sqForwardLinkSegment(SEGMENTQUEUE *sq, SEGMENT *s, double feedOverride)
00666 {
00667   /* function that checks whether segment s needs to be linked to its
00668      successor(s) based upon its initial increment. It is possible that
00669      this requires linking of a set of succeding segments to make sure that
00670      the final increment can be reached. */
00671 
00672   SEGMENT *cursor;
00673   int done, counter;
00674   int linkcrit;
00675 
00676   if ( sq == 0 || s == 0 )
00677     {
00678       diagnostics("Error in sqForwardLinkSegment\n");
00679       return -1;
00680     }
00681 
00682   if ( s->initInc > s->finalInc )
00683     {
00684       diagnostics("sqForwardlinkSegment called while initInc is larger than finalInc\n");
00685       /* not critical, so we don't return -1, but it's not good....*/
00686          return 0;
00687     }
00688 
00689   cursor=s;
00690   done=0;
00691   counter=0;
00692 
00693   while (!done)
00694     {
00695       counter++;
00696       if ( counter > sq->size )
00697         {
00698           /* we have browsed through the whole queue and can't
00699              get out of the loop.... */
00700           diagnostics("Can't get out of the loop in sqForwardLinkSegment\n");
00701           return -1;
00702         }
00703       if (cursor->nextSegment == 0 )
00704         {
00705           /* then this is the last segment in the queue, which always has
00706              a final velocity of zero that can always be reached. Ergo: we're
00707              done */
00708           done = 1;
00709         }
00710       else if (cursor->nextSegment->linkedToPrevSeg==1)
00711         /* the next segment is already linked to cursor, so let's go on */
00712         {
00713           cursor=cursor->nextSegment;
00714           if (cursor == 0 )
00715             {
00716               /* this is VERY unlikely to happen, since we already checked
00717                  that a few lines before, but just in case...... */
00718               diagnostics("Panic: cursor = NULL in sqForwardLinkSegment\n");
00719               return -1;
00720             }
00721         }
00722       else if (s->initInc > cursor->finalInc )
00723         /* then we're done. This is always true as long as the set of
00724          segments that succeed s is correctly processed: if the
00725          succeeding segments are correctly processed, then
00726          cursor->finalInc can be reached from s->finalInc
00727          (= s->nextSegment->initInc) over the distance of the segments
00728          s->nextSegment to cursor. The final increment of s is larger
00729          than the initial increment (otherwise this function wouldn't
00730          have been called), so the distance of the segments s to cursor is
00731          of course large enough too to decelerate from s->initInc to
00732          cursor->finalInc */
00733         done=1;
00734       else
00735         {
00736           if ( -1 == (linkcrit = sqLinkCriterion(sq,s,feedOverride)))
00737             {
00738               diagnostics("Error in sqForwardLinkSegment\n");
00739               return -1;
00740             }
00741           else if ( linkcrit == SQ_LINKING_NEEDED )
00742             {
00743               cursor=cursor->nextSegment;
00744               if (cursor == 0 )
00745                 {
00746                   /* again, this is very unlikely to happen */
00747                   diagnostics("Panic: cursor = NULL in sqForwardLinkSegment\n");
00748                   return -1;
00749                 }
00750               if (-1 == sqLinkSegments(cursor->prevSegment,cursor,SQ_HIGH_LINKING_PRIORITY))
00751                 {
00752                   diagnostics("Error in sqForwardLinkSegment\n");
00753                   return -1;
00754                 }
00755             }
00756           else
00757             /* linkcrit==SQ_NO_LINKING_NEEDED */
00758             done=1; /* no further linking needed */
00759         }
00760       if ( cursor == sq->queue + sq->end )
00761         {
00762           /* sq->end points to the first free position in the ring buffer
00763              so there's no segment at that position. So if cursor points to
00764              that position, something is very wrong */
00765           diagnostics("End of queue reached, no further linking possible\n");
00766           done =1;
00767         }
00768     }
00769   return 0;
00770 }
00771 
00772 int sqBackwardLinkSegment(SEGMENTQUEUE *sq, SEGMENT *s, double feedOverride)
00773 {
00774   /* function that checks whether segment s needs to be linked to its
00775      predecessor(s) based upon the finalInc. It is possible that
00776      this requires linking of a set of preceding segments to make sure that
00777      the final increment can be reached. */
00778 
00779   SEGMENT *cursor;
00780   int done, counter;
00781   int linkcrit;
00782 
00783   if ( sq == 0 || s == 0 )
00784     {
00785       diagnostics("Error in sqBackwardLinkSegment\n");
00786       return -1;
00787     }
00788 
00789   if ( s->initInc < s->finalInc )
00790     {
00791       diagnostics("sqBackwardlinkSegment called while initInc is smaller than finalInc\n");
00792       /* not critical, so we don't return -1, but it's not good....*/
00793          return 0;
00794     }
00795 
00796   cursor=s;
00797   done=0;
00798   counter=0;
00799 
00800   while (!done)
00801     {
00802       counter++;
00803       if ( counter > sq->size )
00804         {
00805           /* we have browsed through the whole queue and can't
00806              get out of the loop.... */
00807           diagnostics("Can't get out of the loop in sqBackwardLinkSegment\n");
00808           return -1;
00809         }
00810 
00811       if (cursor->linkedToPrevSeg==1)
00812         /* it is already linked */
00813         {
00814           cursor=cursor->prevSegment;
00815           if (cursor == 0 )
00816             {
00817               diagnostics("Panic: cursor = NULL in sqBackwardLinkSegment\n");
00818               return -1;
00819             }
00820         }
00821       else if (cursor->initInc < s->finalInc )
00822         /* then we're done. This is always true as long as the set of
00823          segments that precede s is correctly processed, since the
00824          total length of the segments from cursor to the last segment
00825          before s is large enough to reach s's initial increment. This
00826          length is of course large enough too to reach s->finalInc
00827          because that is smaller than s->initInc (otherwise this
00828          function wouldn't have called). */
00829         done=1;
00830 
00831       else
00832         {
00833           if ( -1 == (linkcrit = sqLinkCriterion(sq,cursor,feedOverride)))
00834             {
00835               diagnostics("Error in sqBackWardLinkSegment\n");
00836               return -1;
00837             }
00838           else if ( linkcrit == SQ_LINKING_NEEDED )
00839             {
00840               cursor=cursor->prevSegment;
00841               if (cursor == 0 )
00842                 {
00843                   diagnostics("Panic: cursor = NULL in sqBackwardLinkSegment\n");
00844                   return -1;
00845                 }
00846               if (-1 == sqLinkSegments(cursor,cursor->nextSegment,SQ_HIGH_LINKING_PRIORITY))
00847                 {
00848                   diagnostics("Error in sqBackwardLinkSegment\n");
00849                   return -1;
00850                 }
00851             }
00852           else
00853             done=1; /* no further linking needed */
00854         }
00855       if ( cursor == sq->queue + sq->start )
00856         {
00857           diagnostics("Beginning of queue reached, no further linking possible\n");
00858           done =1;
00859         }
00860     }
00861   return 0;
00862 }
00863 
00864 int sqPreprocessSegment(SEGMENTQUEUE *sq, SEGMENT *newseg)
00865 {
00866 
00867   /* this is the stuff that's needs to be done for both linear and
00868      circular motions. Only sqAddLine and sqAddCircle should call this
00869      function.
00870   */
00871 
00872   double cornerInc;
00873 
00874   SEGMENT *prevseg;
00875   SEGMENT * cursor;
00876 
00877   /* check if segment queue has been initialized and if newseg is valid */
00878   if ( sq == 0 || sq->queue == 0 || newseg == 0 )
00879     {
00880       diagnostics("Error 1 in sqPreprocessSegment()\n");
00881       return -1;
00882     }
00883 
00884 
00885   /* if this is the first segment.... */
00886   if  ( sq->numSegments == 1 )
00887     {
00888       newseg->initInc=0;
00889       newseg->start=sq->lastPoint;
00890       newseg->prevSegment=0;
00891       if (sq->paused != 1 && sq->stepping != 1 )
00892         sq->done=0;
00893     }
00894   /* if not ... */
00895   else
00896     {
00897       prevseg = sq->queue + ( ( sq->end+sq->size-2) % sq->size );
00898       newseg->start   = prevseg->end;
00899       prevseg->nextSegment=newseg;
00900       newseg->prevSegment=prevseg;
00901 
00902       if ( prevseg->active == 1 )
00903         /* we can't change anything of the active segment */
00904         {
00905           newseg->initInc=prevseg->finalInc;
00906         }
00907       else
00908         {
00909 
00910           /* calculate the corner velocity for the corner between prevSegment
00911              and newseg */
00912 
00913           if ( -1 == (cornerInc = sqGiveCornerVelocity( prevseg, newseg ,\
00914                           sq->maxAcc,sq->cycleTime) * sq->cycleTime ))
00915             {
00916               diagnostics("Error 2 in sqPreprocessSegment()\n");
00917               return -1;
00918             }
00919 
00920 
00921           /* if the maximum speeds of the new and the previous segment
00922           are the same and the corner speed is larger than this
00923           maximum speed, the segments can be linked */
00924 
00925           if ( (prevseg->maxInc == newseg->maxInc ) && \
00926                (cornerInc > newseg->maxInc) )
00927             {
00928               if (-1 == sqLinkSegments(prevseg,newseg,SQ_LOW_LINKING_PRIORITY))
00929                 {
00930                   diagnostics("Error 3 in sqPreprocessSegment()\n");
00931                   return -1;
00932                 }
00933               cornerInc = prevseg->maxInc;
00934               newseg->initInc = cornerInc;
00935               prevseg->finalInc = cornerInc;
00936             }
00937 
00938           else
00939             {
00940               /* the corner velocity shouldn't exceed the maximum
00941                  speeds of both segments */
00942 
00943               if ( (cornerInc>prevseg->maxInc) || (cornerInc>newseg->maxInc) )
00944                 cornerInc = min( prevseg->maxInc, newseg->maxInc );
00945 
00946               newseg->initInc = cornerInc;
00947               prevseg->finalInc = cornerInc;
00948 
00949               /* is prevseg long enough to acc/dec from initInc to finalInc
00950                  (=cornerInc)? */
00951               cursor=prevseg;
00952               /* check if prevseg is linked to its predecessor and
00953                  if so, find the first segment in the linked
00954                  series of segments */
00955 
00956               if (prevseg->linkedToPrevSeg == 1)
00957                 {
00958                   while (cursor->linkedToPrevSeg )
00959                     {
00960                       cursor=cursor->prevSegment;
00961                       if (cursor == 0 )
00962                         {
00963                           diagnostics("Panic: cursor = NULL in sqPreprocessSegment\n");
00964                           return -1;
00965                         }
00966                     }
00967                 }
00968               if (cursor->initInc < cornerInc)
00969                 {
00970                   /* check if prevseg needs to be linked to it's next
00971                      segment(s), which in this case only the newseg
00972                      can be. The feedoverride factor is set to the
00973                      maximum feedoverride to ensure correct linking
00974                      for every possible feed */
00975                   if ( -1 == sqForwardLinkSegment(sq,cursor,sq->maxFeedOverrideFactor) )
00976                     {
00977                       diagnostics("Error 4 in sqPreprocessSegment()\n");
00978                       return -1;
00979                     }
00980                 }
00981               else /* cursor->initInc > cornerInc */
00982                 /* check if the prevseg needs to be linked to its
00983                    predecessor(s). The feedoverride factor is set to
00984                    the maximum feedoverride to ensure correct linking
00985                    for every possible feed */
00986                 {
00987                   if ( -1 == sqBackwardLinkSegment(sq,prevseg,sq->maxFeedOverrideFactor) )
00988                     {
00989                       diagnostics("Error 5 in sqPreprocessSegment()\n");
00990                       return -1;
00991                     }
00992                 }
00993             }
00994         }
00995     }
00996 
00997   return 0;
00998 }
00999 
01000 /* interface functions */
01001 /* ------------------- */
01002 
01003 int sqInitQueue(SEGMENTQUEUE *sq, SEGMENT *first, int size)
01004 {
01005   if (size <= 0 || sq == 0 || first == 0 )
01006     {
01007       diagnostics("Error in sqInitQueue()\n");
01008       return -1;
01009     }
01010 
01011   sq->queue = first;
01012 
01013   /* FIXME: third argument (size) is ignored, since the queue size for
01014      the coordinated mode queue can not be set seperately from the
01015      free mode queues */
01016   sq->size = 2000;
01017 
01018   sq->start = sq->end = 0;
01019   sq->full = 0;
01020   sq->numSegments=0;
01021 
01022   sq->initXYZ.tran.x=0;
01023   sq->initXYZ.tran.y=0;
01024   sq->initXYZ.tran.z=0;
01025   sq->lastPoint=sq->initXYZ;
01026   sq->n=0;
01027   sq->maxFeedOverrideFactor = 1.0;   /* this has to be set at start-up using
01028                                         sqSetMaxFeedOverride() */
01029   sq->feedOverrideFactor=1.0;
01030   sq->cycleTime=0;
01031   sq->maxAcc=0;
01032   sq->maxV=0;
01033   sq->currentID=0;
01034 
01035   sq->done=1;      /* the queue is empty, so by definition we're done */
01036   sq->paused=0;
01037   sq->stepping=0;
01038   sq->feedAdjusting=0;
01039   sq->aborting=0;
01040 
01041 
01042   /* initializing debug variables */
01043   oldPos = sq->lastPoint;
01044   oldVel.tran.x=0;
01045   oldVel.tran.y=0;
01046   oldVel.tran.z=0;
01047   oldDist = 0;
01048   return 0;
01049 };
01050 
01051 int sqSetMaxAcc(SEGMENTQUEUE *sq, double amax)
01052 {
01053   if (sq==0 || amax <=0 )
01054     {
01055       diagnostics("Error in SetMaxAcc!!!\n");
01056       return -1;
01057     }
01058   sq->maxAcc=amax/2;
01059   return 0;
01060 };
01061 
01062 int sqSetVmax(SEGMENTQUEUE *sq, double vmax)
01063 {
01064   if (sq==0 || vmax <= 0 )
01065     {
01066       diagnostics("Error in SetVmax!!!\n");
01067       return -1;
01068     }
01069   sq->maxV=vmax;
01070   return 0;
01071 };
01072 
01073 int sqSetCycleTime(SEGMENTQUEUE *sq, double secs)
01074 {
01075   if (sq==0 || secs==0 )
01076     {
01077       diagnostics("Cycletime is zero!!!\n");
01078       return -1;
01079     }
01080   sq->cycleTime=secs;
01081   sq->ctPow2=secs *secs;
01082   sq->ctPow3=sq->ctPow2 * secs;
01083   return 0;
01084 };
01085 
01086 int sqSetMaxFeedOverride(SEGMENTQUEUE *sq, double mfo)
01087 {
01088   if (sq==0 || mfo<=0 )
01089     {
01090       diagnostics("Error in sqSetMaxFeedOverride()\n");
01091       return -1;
01092     }
01093   sq->maxFeedOverrideFactor = mfo;
01094   return 0;
01095 }
01096 
01097 
01098 int sqSetPos(SEGMENTQUEUE *sq, EmcPose pos)
01099 {
01100   if (sq==0)
01101     {
01102       diagnostics("Error in sqSetPos()\n");
01103       return -1;
01104     }
01105   sq->initXYZ=pos;
01106   sq->lastPoint=sq->initXYZ;
01107   return 0;
01108 }
01109 
01110 int sqClearQueue(SEGMENTQUEUE *sq)
01111 {
01112   if (sq==0)
01113     {
01114       diagnostics("Error in sqClearQueue(): sq == 0 \n");
01115       return -1;
01116     }
01117   sq->numSegments=0;
01118   sq->start = sq->end = 0;
01119   sq->full = 0;
01120   sq->n=0;
01121   sq->feedOverrideFactor=1.0;
01122   sq->currentID=0;
01123 
01124   sq->done=1;      /* the queue is empty, so by definition we're done */
01125   sq->paused=0;
01126   sq->stepping=0;
01127   sq->feedAdjusting=0;
01128   sq->aborting=0;
01129 
01130   sq->currentVel=0;
01131   oldDist=0;
01132   oldPos = sq->lastPoint;
01133   oldVel.tran.x=0;
01134   oldVel.tran.y=0;
01135   oldVel.tran.z=0;
01136 
01137   return 0;
01138 }
01139 
01140 int sqTrashQueue(SEGMENTQUEUE *sq)
01141 {
01142   if ( sq == 0 || sq->queue == 0 )
01143     {
01144       diagnostics("Error in sqTrashQueue()\n");
01145       return -1;
01146     }
01147   sqClearQueue(sq);
01148   sq->queue=0;
01149   return 0;
01150 };
01151 
01152 /* function to set the feed rate for the motions appended after this command */
01153 int sqSetFeed(SEGMENTQUEUE *sq, double feed)
01154 {
01155   if (sq==0 || feed<=0)
01156     {
01157       diagnostics("Error in sqSetFeed()\n");
01158       return -1;
01159     }
01160 
01161   if (feed > sq->maxV)
01162     sq->feed = sq->maxV;
01163   else
01164     sq->feed=feed;
01165   return 0;
01166 }
01167 
01168 int sqAddLine(SEGMENTQUEUE  *sq, EmcPose end, int ID)
01169 {
01170   double length, maxUVec;
01171   SEGMENT *newseg;
01172   EmcPose start;
01173 
01174 
01175   /* check if segment queue has been initialized */
01176   if ( sq == 0 || sq->queue == 0 )
01177     {
01178       diagnostics("Error in sqAddLine()\n");
01179       return -1;
01180     }
01181 
01182   /* check for full */
01183   if ( sq->numSegments == sq->size )
01184     {
01185       diagnostics("Panic!!!!, segmentqueue overflows!!!\n");
01186       return -1;
01187     }
01188 
01189   /* check if new motion has zero length */
01190   if ( sq->numSegments==0 )
01191     start=sq->lastPoint;
01192   else
01193     start=sq->queue[(sq->end+sq->size-1)%sq->size].end;
01194 
01195   length = sqGiveLength(start,end);
01196 
01197   if (length==0)
01198     {
01199       /* only set ID of last appended motion */
01200       sq->lastAppMotionID=ID;
01201       return 0;
01202     }
01203 
01204   /* let newseg point to the first empty place in the ring buffer... */
01205   newseg= sq->queue+sq->end;
01206   /* ...and update the ring buffer properties */
01207   sq->end = (sq->end+1) % sq->size;
01208   sq->numSegments++;
01209   if ( sq->numSegments >= sq->size - SQ_SAFETY_MARGIN )
01210     {
01211       sq->full=1;
01212     }
01213 
01214   /* fill segment parameter fields */
01215   newseg->ID             = ID;
01216   newseg->type           = SQ_LINEAR;
01217   newseg->length         = length;
01218   newseg->totLength      = length;
01219   newseg->start          = start;
01220   newseg->end            = end;
01221   newseg->maxInc         = sq->feed*sq->cycleTime;
01222   newseg->finalInc       = 0;
01223   newseg->plInitInc      = 0;
01224   newseg->plFinalInc     = 0;
01225   newseg->cruiseInc      = 0;
01226   newseg->planningDone   = 0;
01227   newseg->active         = 0;
01228   newseg->numLinkedSegs  = 0;
01229   newseg->linkedToPrevSeg= 0;
01230   newseg->totNumPoints   = 0;
01231   newseg->nextSegment    = 0;
01232 
01233   /* initialize line */
01234   pmLineInit( &newseg->line, newseg->start, newseg->end);
01235 
01236   /* set the maximum tangential acceleration for this line */
01237   maxUVec = max ( fabs(newseg->line.uVec.x) , fabs(newseg->line.uVec.y) );
01238   maxUVec = max ( fabs(newseg->line.uVec.z) , maxUVec );
01239   newseg->amaxTan = sq->maxAcc/maxUVec;
01240 
01241   diagnosticsOff("Amax tan = %d\n",(int)newseg->amaxTan);
01242 
01243   if (-1 == sqPreprocessSegment(sq, newseg))
01244     {
01245       diagnostics("Error in sqAddLine()\n");
01246       return -1;
01247     }
01248 
01249   /* set last Appended Motion ID */
01250   sq->lastAppMotionID=ID;
01251 
01252   return 0;
01253 }
01254 
01255 int sqAddCircle(SEGMENTQUEUE *sq, EmcPose end, PmCartesian center, \
01256                 PmCartesian normal, int turn, int ID)
01257 {
01258   SEGMENT * newseg;
01259   PmCircle circle;
01260   EmcPose start;
01261   PmCartesian helix;
01262   double absHelix;
01263 
01264   /* used to calculate the maximum tangential acceleration */
01265   double rpow2,A,topIncPow2;
01266 
01267 /* check if segment queue has been initialized */
01268   if ( sq == 0 || sq->queue == 0 )
01269     {
01270       diagnostics("Error in sqAddCircle()\n");
01271       return -1;
01272     }
01273 
01274   /* check for full */
01275   if ( sq->numSegments == sq->size )
01276     {
01277       diagnostics("Panic!!!!, segmentqueue overflows!!!\n");
01278       return -1;
01279     }
01280 
01281   if ( sq->numSegments==0 )
01282     start=sq->lastPoint;
01283   else
01284     start=sq->queue[(sq->end+sq->size-1)%sq->size].end;
01285 
01286   pmCircleInit(&circle, start, end, center, normal, turn);
01287 
01288   if (circle.angle==0)
01289     {
01290       /* only set ID of last appended motion */
01291       sq->lastAppMotionID=ID;
01292       return 0;
01293     }
01294 
01295   /* Calculate the helix gradient in normal direction */
01296   pmCartScalDiv( circle.rHelix, circle.angle, &helix );
01297   pmCartMag( helix, &absHelix);
01298 
01299   /* let newseg point to the first empty place in the ring buffer... */
01300   newseg= sq->queue+sq->end;
01301   /* ...and update the ring buffer properties */
01302   sq->end = (sq->end+1) % sq->size;
01303   sq->numSegments++;
01304   if ( sq->numSegments >= sq->size - SQ_SAFETY_MARGIN )
01305     {
01306       sq->full=1;
01307     }
01308 
01309   /* fill segment parameter fields */
01310   newseg->ID             = ID;
01311   newseg->type           = SQ_CIRCULAR;
01312   newseg->circle         = circle;
01313 
01314   newseg->helixRadius    = sqrt(circle.radius*circle.radius\
01315                                 + absHelix*absHelix);
01316   newseg->length         = circle.angle * newseg->helixRadius;
01317 
01318   newseg->totLength      = newseg->length;
01319   newseg->start          = start;
01320   newseg->end            = end;
01321   newseg->maxInc         = min (sq->feed*sq->cycleTime, sqrt( sq->maxAcc * \
01322                                 circle.radius ) * sq->cycleTime );
01323   if ( absHelix != 0 )
01324     newseg->maxInc = min ( newseg->maxInc, sq->feed * sq->cycleTime / absHelix );
01325 
01326   newseg->finalInc       = 0;
01327   newseg->plInitInc      = 0;
01328   newseg->plFinalInc     = 0;
01329   newseg->cruiseInc      = 0;
01330   newseg->planningDone   = 0;
01331   newseg->active         = 0;
01332   newseg->numLinkedSegs  = 0;
01333   newseg->linkedToPrevSeg= 0;
01334   newseg->totNumPoints   = 0;
01335   newseg->nextSegment    = 0;
01336 
01337   /* calculate the maximum tangential acceleration for this circle */
01338   rpow2 = circle.radius*circle.radius;
01339   topIncPow2 = newseg->maxInc * newseg->maxInc;
01340   A = max (sq->maxAcc*sq->maxAcc*sq->ctPow2*sq->ctPow2*rpow2 \
01341        - topIncPow2*topIncPow2 ,\
01342        3.0/4.0 * topIncPow2*topIncPow2 );
01343 
01344   newseg->amaxTan = sqrt( A / ( rpow2 * (rpow2* + topIncPow2 )))/sq->ctPow2;
01345 
01346   if ( absHelix != 0 )
01347     {
01348       newseg->amaxTan= min (newseg->amaxTan, \
01349                             sq->maxAcc*newseg->helixRadius/absHelix );
01350     }
01351 
01352   if (-1 == sqPreprocessSegment(sq, newseg))
01353     {
01354       diagnostics("Error in sqAddCircle()\n");
01355       return -1;
01356     }
01357 
01358   /* set last Appended Motion ID */
01359   sq->lastAppMotionID=ID;
01360 
01361   return 0;
01362 }
01363 
01364 int sqGetPosition(SEGMENTQUEUE *sq, EmcPose *p)
01365 {
01366   if ( (sq == 0) || (p == 0) )
01367     {
01368       diagnostics("Error in sqGetPosition()\n");
01369       return -1;
01370     }
01371 
01372   *p = sq->lastPoint;
01373   return 0;
01374 };
01375 
01376 int sqRunCycle(SEGMENTQUEUE *sq)
01377 {
01378   SEGMENT *as;             /* to use instead of sq->queue[sq->start],
01379                               stands for Active Segment */
01380   int i;
01381   SEGMENT *cursor;
01382   double finalInc;
01383   int done;
01384   int minNumSteps;
01385   double angleToGo;
01386   double amaxTan;
01387   int turn;
01388   PmCartesian normal, center;
01389 
01390   int npow1, npow2, npow3; /* to speed up cubic calculations */
01391 
01392   if (sq==0 )
01393     {
01394       diagnostics("Error in sqRunCycle(): Segmentqueue doesn't exist!\n");
01395       return -1;
01396     }
01397 
01398   if ( sq->full == 1 && sq->numSegments < sq->size - SQ_SAFETY_MARGIN )
01399     diagnostics("sq->full == 1 although queue's not full!!!!\n");
01400 
01401   if ( sq->done==1 )
01402     {
01403       /* do nothing */
01404       return 0;
01405     }
01406   /* if buffer is empty give last point (i.e. do nothing) */
01407   if ( sq->numSegments==0 )
01408     {
01409       /* set the 'done' flag ..... */
01410       sq->done=1;
01411 
01412       /* check if currentID is the same as the ID of the last appended motion.
01413          The only case in which this will not be true is when the last motion
01414          has a zero length */
01415       if (sq->currentID != sq->lastAppMotionID )
01416         sq->currentID=  sq->lastAppMotionID;
01417       return 0;
01418     }
01419   as=sq->queue+sq->start;   /* much shorter ..... */
01420   if (as == 0 )
01421     {
01422       diagnostics("Panic: as = NULL in sqRunCycle\n");
01423       return -1;
01424     }
01425 
01426   if (as->active==0)
01427     /* we're about to start with a new segment */
01428     {
01429       if (-1 == sqPlanSegment(sq, as))
01430         {
01431           diagnostics("Error in sqRunCycle\n");
01432           return -1;
01433         }
01434       /* mark the whole chain as active */
01435       cursor=as;
01436       for (i=0;i<=as->numLinkedSegs;i++)
01437         {
01438           if (cursor == 0 )
01439             {
01440               diagnostics("Panic: cursor = NULL in sqRunCycle\n");
01441               return -1;
01442             }
01443           cursor->active=1;
01444           cursor=cursor->nextSegment;
01445         }
01446       oldDist=0;
01447       sq->dist=0;
01448 
01449       /* reset base, cursor, offset and cumlength and n */
01450       sq->base = as->start;
01451       sq->cursor=as;
01452       sq->offset=0;
01453       sq->cumLength=as->length;
01454       sq->n=1;
01455       sq->currentID=as->ID;
01456 
01457     }
01458   /* else: planning has been done before and the parameters are correctly
01459      initialized, unless someone deliberately changed planningDone to 1.
01460      Let's trust our user and not check for that here. */
01461 
01462   /* depending of in what phase of the motion we are, determine the new
01463      distance */
01464   if ( sq->n==1 || sq->n==2 )
01465     {
01466       sq->dist += as->plInitInc;
01467     }
01468   else if ( sq->n <= as->m +2 )
01469     /* acceleration phase */
01470     {
01471       npow1 = sq->n - 2;
01472       npow2 = npow1 * npow1;
01473       npow3 = npow2 * npow1;
01474       sq->dist += as->a1 * npow3 *sq->ctPow3 \
01475                   + as->b1 * npow2 * sq->ctPow2 \
01476                   + as->c1 * npow1 * sq->cycleTime \
01477                   + as->d1;
01478     }
01479   else if ( sq->n <= as->m + as->p + 2 )
01480     /* cruising phase */
01481     {
01482       sq->dist += as->cruiseInc;
01483     }
01484   else if ( sq->n <= as->m + as->p + as->q +2 )
01485     /* deceleration phase */
01486     {
01487       npow1 = sq->n - as->m - as->p - 2;
01488       npow2 = npow1 * npow1;
01489       npow3 = npow2 * npow1;
01490       sq->dist += as->a3 * npow3 *sq->ctPow3 \
01491                   + as->b3 * npow2 * sq->ctPow2 \
01492                   + as->c3 * npow1 * sq->cycleTime \
01493                   + as->d3;
01494 
01495     }
01496   else if ( sq->n == as->m + as->p + as->q + 3 )
01497     /* last step */
01498     {
01499       sq->dist+= as->plFinalInc;
01500     }
01501   else
01502     /* we have a problem, because this should never happen */
01503     {
01504       diagnostics("Error in sqRunCycle\n");
01505       return -1;
01506     }
01507 
01508   /* transform the dist scalar into a XYZ triplet */
01509   if (as->nextSegment !=0 && ( as->nextSegment->linkedToPrevSeg ==1 ||
01510                                sq->paused == 1))
01511     /* the active segment is the first segment of a chain */
01512     /* the sq->paused == 1 test is added to make sure that if a pause
01513        command is given just before the end of the segment, that the
01514        following segment is used to finish decelerating to zero */
01515     {
01516       while ( (sq->dist > sq->cumLength)
01517               && ( sq->cursor->nextSegment!=0 )
01518               && ( (sq->cursor->nextSegment->linkedToPrevSeg==1 ) ||
01519                    sq->paused==1 ) )
01520         {
01521           sq->offset  = sq->cumLength;
01522           sq->base    = sq->cursor->end;
01523           sq->cursor  = sq->cursor->nextSegment;
01524           sq->cumLength += sq->cursor->length;
01525 
01526         }
01527       /* set currentID */
01528       sq->currentID=sq->cursor->ID;
01529 
01530       if ( sq->cursor->type == SQ_LINEAR )
01531         pmLinePoint( &sq->cursor->line, sq->dist - sq->offset, &sq->lastPoint);
01532       else
01533         pmCirclePoint( &sq->cursor->circle, \
01534                        (sq->dist - sq->offset)/sq->cursor->helixRadius,\
01535                        &sq->lastPoint );
01536     }
01537 
01538   else
01539     /* the active segment has no other segments linked to it, which makes
01540        things much easier... */
01541     {
01542       if ( sq->cursor->type == SQ_LINEAR )
01543         pmLinePoint(&as->line, sq->dist, &sq->lastPoint);
01544       else
01545         pmCirclePoint(&as->circle, sq->dist/as->helixRadius, &sq->lastPoint);
01546     }
01547 
01548   sq->n++;
01549 
01550   if (sq->n > as->totNumPoints )
01551     {
01552       if (sq->aborting == 1)
01553         {
01554           if (-1 == sqClearQueue(sq))
01555             {
01556               diagnostics("Error in sqRunCycle\n");
01557               return -1;
01558             }
01559         }
01560 
01561       else if (sq->paused == 1 || sq->feedAdjusting == 1)
01562         {
01563 
01564           if (sq->paused==1)
01565             {
01566               sq->done=1;
01567               finalInc=0;
01568             }
01569           else
01570             {
01571               sq->feedAdjusting=0;
01572               finalInc=as->plFinalInc;
01573             }
01574 
01575           /* remove all segments preceding the current segment */
01576           cursor=as;
01577           while ( cursor!=sq->cursor )
01578             {
01579               cursor=cursor->nextSegment;
01580               if (cursor == 0 )
01581                 {
01582                   diagnostics("Panic: cursor = NULL in sqRunCycle\n");
01583                   return -1;
01584                 }
01585               sq->numSegments--;
01586             }
01587           if ( sq->numSegments < sq->size - SQ_SAFETY_MARGIN )
01588             sq->full = 0;
01589           if ( sq->numSegments < 0 )
01590             {
01591               diagnostics("Panic: sq->numSegments <0  in sqRunCycle\n");
01592               return -1;
01593             }
01594 
01595           cursor->prevSegment=0;
01596           cursor->linkedToPrevSeg=0;
01597           sq->start= sq->cursor - sq->queue;
01598           as=cursor;
01599 
01600           as->planningDone=0;
01601           as->plInitInc=finalInc;
01602           as->start=sq->lastPoint;
01603 
01604           if ( as->type == SQ_LINEAR)
01605             {
01606               as->length=sqGiveLength(as->start,as->end);
01607               as->totLength=as->length;
01608               pmLineInit(&as->line,as->start,as->end);
01609             }
01610           else
01611             {
01612               angleToGo= as->circle.angle-\
01613                          (sq->dist-sq->offset)/as->helixRadius;
01614               turn = floor(angleToGo / ( 2 * PM_PI ));
01615               normal = as->circle.normal;
01616               center = as->circle.center;
01617               pmCircleInit( &as->circle, as->start, as->end, \
01618                             center, normal, turn);
01619               as->length=as->circle.angle* as->helixRadius;
01620               as->totLength= as->length;
01621             }
01622 
01623 
01624           as->active=0;         /* mark the first segment of the chain
01625                                    as not active */
01626 
01627           /* determine how many segments are linked to as */
01628           as->numLinkedSegs=0;
01629           while (cursor->nextSegment!=0 &&
01630                  cursor->nextSegment->linkedToPrevSeg==1 )
01631             {
01632               cursor=cursor->nextSegment;
01633               as->numLinkedSegs++;
01634               as->totLength+=cursor->length;
01635             }
01636           /* find the minimum of the amax's of the segments in the chain */
01637           amaxTan=sqGiveMinAmaxTan(as);
01638 
01639           done=0;
01640           /* keep linking segments until the chain is long enough */
01641           while (!done)
01642             {
01643               if ( cursor->nextSegment!=0 && cursor->nextSegment->maxInc < \
01644                    cursor->maxInc)
01645                 finalInc=min(cursor->finalInc,\
01646                         cursor->nextSegment->maxInc*sq->feedOverrideFactor);
01647 
01648               else
01649                 finalInc=min(cursor->finalInc,\
01650                         cursor->maxInc*sq->feedOverrideFactor);
01651 
01652               amaxTan= min(amaxTan, cursor->amaxTan);
01653               minNumSteps = ceil ( 3 * fabs(finalInc-as->plInitInc) / \
01654                                    ( 2 * amaxTan * sq->ctPow2 ));
01655               if ((minNumSteps+1)* (as->plInitInc+finalInc)/2-as->plInitInc >\
01656                   as->totLength - 5 * max(as->plInitInc,finalInc ))
01657 
01658                 {
01659                   if (-1 ==sqLinkSegments(cursor,cursor->nextSegment,SQ_HIGH_LINKING_PRIORITY))
01660                     {
01661                       diagnostics("Error in sqRunCycle\n");
01662                       return -1;
01663                     }
01664                   cursor=cursor->nextSegment;
01665                   if (cursor == 0 )
01666                     {
01667                       diagnostics("Panic: cursor = NULL in sqRunCycle\n");
01668                       return -1;
01669                     }
01670 
01671                 }
01672               else
01673                 done=1;
01674             }
01675 
01676         }
01677       else if ( sq->stepping == 1)
01678         /* we are at the end of the segment, but shouldn't go on
01679            with the next one */
01680         {
01681           sq->numSegments--;
01682           sq->start = (sq->start + 1 ) % sq->size;
01683           if ( sq->numSegments < sq->size - SQ_SAFETY_MARGIN )
01684             sq->full = 0;
01685           if ( sq->numSegments < 0 )
01686             {
01687               diagnostics("Panic: sq->numSegments < 0  in sqRunCycle\n");
01688               return -1;
01689             }
01690 
01691           as= sq->queue+sq->start;
01692           as->plInitInc=0;
01693           as->active=0;
01694           sq->done=1;
01695         }
01696 
01697       else
01698         {
01699           /* end of segment reached */
01700           sq->numSegments -= 1 + as->numLinkedSegs;
01701           sq->start = ( sq->start + as->numLinkedSegs + 1 ) % sq->size;
01702           if ( sq->numSegments < sq->size - SQ_SAFETY_MARGIN )
01703             sq->full = 0;   /* we just removed some segments ... */
01704           if ( sq->numSegments < 0 )
01705             {
01706               diagnostics("Panic: sq->numSegments <0  in sqRunCycle\n");
01707               return -1;
01708             }
01709 
01710         }
01711     }
01712 
01713   /* for debugging */
01714 
01715   oldVel=newVel;
01716   newVel.tran.x= sq->lastPoint.tran.x - oldPos.tran.x;
01717   newVel.tran.y= sq->lastPoint.tran.y - oldPos.tran.y;
01718   newVel.tran.z= sq->lastPoint.tran.z - oldPos.tran.z;
01719 
01720   oldPos=sq->lastPoint;
01721 
01722   newAcc.tran.x= newVel.tran.x - oldVel.tran.x;
01723   newAcc.tran.y= newVel.tran.y - oldVel.tran.y;
01724   newAcc.tran.z= newVel.tran.z - oldVel.tran.z;
01725 
01726   if (fabs(newAcc.tran.x) > sq->maxAcc*sq->ctPow2 || \
01727       fabs(newAcc.tran.y) > sq->maxAcc*sq->ctPow2 || \
01728       fabs(newAcc.tran.z) > sq->maxAcc*sq->ctPow2 )
01729     {
01730       diagnosticsOff("MaxAcc limited violated on motion %d\n",sq->currentID);
01731       diagnosticsOff("ddx=%d ddy=%d ddz=%d\n",(int)(newAcc.tran.x*1000000.0),(int)(newAcc.tran.y*1000000.0),(int)(newAcc.tran.z*1000000.0 ));
01732     }
01733 
01734   sq->currentVel = sq->dist - oldDist;
01735   oldDist = sq->dist;
01736 
01737   return 0;
01738 }
01739 
01740 /* function to change the feed overide */
01741 int sqSetFeedOverride(SEGMENTQUEUE *sq, double fo)
01742 {
01743 
01744   SEGMENT *as, *cursor;   /* as = Active Segment */
01745   double startInc,finalInc,startAcc=0;
01746   double prevInc;
01747   int npow1,npow2,npow3;
01748   double angleToGo;
01749   int turn;
01750   PmCartesian normal, center;
01751 
01752   if ( sq==0 || sq->queue==0 )
01753     {
01754       diagnostics("Error in sqSetFeedOverride\n");
01755       return -1;
01756     }
01757 
01758   /* if fo is out of the valid range: clamp it */
01759   if ( fo < 0 )
01760     fo=0;
01761   else if ( fo > sq->maxFeedOverrideFactor )
01762     fo=sq->maxFeedOverrideFactor;
01763 
01764   if ( sq->feedOverrideFactor==fo )
01765     /* don't do anything, just return */
01766     return 0;
01767 
01768   if ( fo == 0 )
01769     {
01770       /* then this is actually a pause action */
01771       if ( -1 == sqPause(sq) )
01772         {
01773           diagnostics("Error in sqSetFeedOverride\n");
01774           return -1;
01775         }
01776       else
01777         {
01778           sq->feedOverrideFactor=0;
01779           return 0;
01780         }
01781     }
01782 
01783   if ( sq->numSegments==0 )
01784     {
01785       /* the queue is empty */
01786       sq->feedOverrideFactor=fo;
01787       return 0;
01788     }
01789 
01790   as=sq->queue+sq->start;
01791 
01792   if ( sq->paused==1 )
01793     {
01794       if ( sq->feedOverrideFactor == 0 )
01795         {
01796           /* If the previous feed override factor equals zero, then the
01797              pause action was actually done by setting the feed
01798              override to zero */
01799           sq->feedOverrideFactor=fo;
01800           if ( -1 == sqResume(sq) )
01801             {
01802               diagnostics("Error in sqSetFeedOverride\n");
01803               return -1;
01804             }
01805           else
01806             return 0;
01807         }
01808       else
01809         {
01810           /* else: don't do anything else*/
01811           sq->feedOverrideFactor=fo;
01812           return 0;
01813         }
01814     }
01815 
01816   sq->feedOverrideFactor=fo;
01817   if ( as->active==0 )
01818     {
01819       /* the previous segment has just been finished. as still needs to
01820          be planned. So: don't do anything */
01821     }
01822 
01823   else if ( sq->n < as->m + 2 || sq->feedAdjusting==1 )
01824     {
01825       /* we are accelerating to (macInc * 'previous fo'). We need to adjust
01826          this phase in order get to the desired cruising feed */
01827 
01828       if ( sq->feedAdjusting!=1 && as->p==0 && as->maxInc*fo > as->cruiseInc )
01829         /* the the segment is too short to reach the current maxInc and it
01830            will be too short too to reach the new feed */
01831         return 0;
01832 
01833       if (sq->feedAdjusting==1)
01834         {
01835           /* copy the phase 3 params to the phase 1 params, since these will
01836              be used to find estimates for the current velocity and
01837              acceleration */
01838           as->a1=as->a3;
01839           as->b1=as->b3;
01840           as->c1=as->c3;
01841           as->d1=as->d3;
01842         }
01843 
01844       finalInc=as->maxInc*fo;
01845 
01846       /* recalculate the last two dist values to find startInc and to use
01847          for making an estimation of startAcc */
01848       if (sq->n==1 || sq->n==2 || sq->n==3)
01849         {
01850           startInc=as->plInitInc;
01851           startAcc=0;
01852         }
01853       else if ( sq->n==3)
01854         {
01855           npow1 = 1;
01856           npow2 = 1;
01857           npow3 = 1;
01858           startInc = as->a1 * npow3 *sq->ctPow3 \
01859             + as->b1 * npow2 * sq->ctPow2 \
01860             + as->c1 * npow1 * sq->cycleTime \
01861             + as->d1;
01862           startAcc = (startInc - as->plInitInc );
01863         }
01864       else
01865         {
01866           npow1 = sq->n - 3;            /* sq->n-2-1 */
01867           npow2 = npow1 * npow1;
01868           npow3 = npow2 * npow1;
01869           startInc = as->a1 * npow3 *sq->ctPow3 \
01870             + as->b1 * npow2 * sq->ctPow2 \
01871             + as->c1 * npow1 * sq->cycleTime \
01872             + as->d1;
01873           npow1 = sq->n - 4;            /* sq->n-2-2 */
01874           npow2 = npow1 * npow1;
01875           npow3 = npow2 * npow1;
01876           prevInc = (as->a1 * npow3 *sq->ctPow3 \
01877                                  + as->b1 * npow2 * sq->ctPow2 \
01878                                  + as->c1 * npow1 * sq->cycleTime \
01879                                  + as->d1);
01880           startAcc = startInc - prevInc;
01881         }
01882       as->q= ceil ( 1.7393877* fabs(startInc-finalInc) / \
01883                     ( sq->maxAcc * sq->ctPow2 ) +
01884                     0.5967755904 * fabs(startInc-finalInc) / \
01885                     ( sq->maxAcc * sq->maxAcc * sq->ctPow2 * sq->ctPow2) *\
01886                     startAcc-(sq->maxAcc * sq->ctPow2)/2);
01887       as->m=0;
01888       as->p=0;
01889       as->totNumPoints = as->q + 1;
01890       sq->n=3;          /* start all over, but skip the first initInc steps */
01891 
01892       as->b3 = - ( 3 * (startInc-finalInc) + 2 * as->q* startAcc ) \
01893         / ( as->q * as->q * sq->ctPow2 ) ;
01894       as->a3 = ( 2 * (startInc-finalInc) + as->q* startAcc ) \
01895         / ( as->q * as->q * as->q * sq->ctPow3 ) ;
01896       as->c3 = startAcc/sq->cycleTime;
01897       as->d3 = startInc;
01898 
01899       as->plFinalInc=finalInc;
01900       /* when the desired feed is reached, some things off this segment
01901          will have to be recalculated, which is done by runCycle. By setting
01902          this flag, runCycle will know that it needs to do this
01903       */
01904       sq->feedAdjusting=1;
01905 
01906     }
01907   else if ( sq->n < as->m + as->p + 2 )
01908     {
01909 
01910     /* change the active segment such that it looks like we are starting
01911        with a new segment */
01912 
01913       startInc=as->cruiseInc;
01914 
01915       /* delete all previous segments */
01916       cursor=as;
01917       while ( cursor!=sq->cursor )
01918         {
01919           cursor=cursor->nextSegment;
01920           if (cursor == 0 )
01921             {
01922               diagnostics("Panic 1: cursor = NULL in sqSetFeedOverride\n");
01923               return -1;
01924             }
01925           sq->numSegments--;
01926         }
01927       if ( sq->numSegments < sq->size - SQ_SAFETY_MARGIN )
01928         sq->full = 0;
01929       if ( sq->numSegments < 0 )
01930         {
01931           diagnostics("Panic: sq->numSegments <0  in sqSetFeedOverride\n");
01932           return -1;
01933         }
01934 
01935 
01936       cursor->prevSegment=0;
01937       cursor->linkedToPrevSeg=0;
01938       sq->start= sq->cursor - sq->queue;
01939       as=cursor;
01940 
01941       as->planningDone=0;
01942       as->plInitInc=startInc;
01943       as->start=sq->lastPoint;
01944       if ( as->type == SQ_LINEAR)
01945         {
01946           as->length=sqGiveLength(as->start,as->end);
01947           as->totLength=as->length;
01948           pmLineInit(&as->line,as->start,as->end);
01949         }
01950       else
01951         {
01952           angleToGo= as->circle.angle-(sq->dist-sq->offset)/as->helixRadius;
01953           turn = floor(angleToGo / ( 2 * PM_PI ));
01954           normal = as->circle.normal;
01955           center = as->circle.center;
01956           pmCircleInit( &as->circle, as->start, as->end, center, normal, turn);
01957           as->length=as->circle.angle* as->helixRadius;
01958           as->totLength= as->length;
01959         }
01960 
01961 
01962       as->active=0;     /* mark the first segment of the chain
01963                            as not active */
01964 
01965       /* determine how many segments are linked to as */
01966       as->numLinkedSegs=0;
01967       while (cursor->nextSegment!=0 &&
01968              cursor->nextSegment->linkedToPrevSeg==1 )
01969         {
01970           cursor=cursor->nextSegment;
01971           as->numLinkedSegs++;
01972           as->totLength+=cursor->length;
01973         }
01974 
01975       /* keep linking successive segments to as until the chain is
01976          long enough */
01977       if ( -1 == sqForwardLinkSegment(sq,as,sq->feedOverrideFactor))
01978         {
01979           diagnostics("Error in sqSetFeedOverride\n");
01980           return -1;
01981         }
01982     }
01983   else
01984     {
01985       /* we are already decelerating, which is in most cases
01986          necessary.  Therefore, let's not interrupt this and finish
01987          the current segment first. The new segment will be planned
01988          with the new feedOverrideFactor.*/
01989     }
01990 
01991   return 0;
01992 }
01993 
01994 /* function to pause the system (decelerate to zero velocity) */
01995 int sqPause(SEGMENTQUEUE *sq)
01996 {
01997   SEGMENT *as;          /* as = Active Segment */
01998   double startInc;      /* the incrediment at the time the pause command
01999                            was given */
02000   double startAcc;      /* the derivate of the inc at that time */
02001   int npow1,npow2,npow3;
02002   double amaxTan;
02003 
02004   if (sq==0 || sq->queue==0 )
02005     {
02006       diagnostics("Error in sqPause\n");
02007       return -1;
02008     }
02009 
02010   if (sq->paused == 1)
02011     /* don't do anything, system is already paused */
02012     return 0;
02013 
02014   /* set paused flag */
02015   sq->paused=1;
02016 
02017   if ( sq->numSegments==0)
02018     {
02019       /* the queue is empty */
02020       sq->done = 1; /* propably redundant */
02021       return 0;
02022     }
02023 
02024   as=sq->queue+sq->start;
02025 
02026   if ( as->active==0 && as->initInc==0 )
02027     /* then this is the very first segment and we have not started yet.
02028        So let's set the done flag and return */
02029     {
02030       sq->done=1;
02031       return 0;
02032     }
02033 
02034   sq->feedAdjusting=0;  /* if we were adjusting the speed, ignore that too */
02035 
02036   amaxTan= sqGiveMinAmaxTan(as);
02037 
02038   if ( as->active==0 || sq->n<=3)
02039     {
02040       startInc = as->plInitInc;
02041       startAcc = 0;
02042       as->active=1;
02043       as->planningDone=1; /* the planning will be done in this function */
02044 
02045       as->q= ceil ( 3 * startInc / ( 2 * amaxTan * sq->ctPow2 ) );
02046       as->m=0;
02047       as->p=0;
02048       as->totNumPoints = as->q + 3;
02049       sq->n=3;          /* start allover, but skip the first initInc steps */
02050 
02051     }
02052   else if ( sq->n < as->m + 2 )
02053     {
02054       /* recalculate the last two dist values */
02055       npow1 = sq->n - 3;                /* sq->n-2-1 */
02056       npow2 = npow1 * npow1;
02057       npow3 = npow2 * npow1;
02058       startInc = as->a1 * npow3 *sq->ctPow3 \
02059                   + as->b1 * npow2 * sq->ctPow2 \
02060                   + as->c1 * npow1 * sq->cycleTime \
02061                   + as->d1;
02062       npow1 = sq->n - 4;                /* sq->n-2-2 */
02063       npow2 = npow1 * npow1;
02064       npow3 = npow2 * npow1;
02065       startAcc = startInc - (as->a1 * npow3 *sq->ctPow3 \
02066                   + as->b1 * npow2 * sq->ctPow2 \
02067                   + as->c1 * npow1 * sq->cycleTime \
02068                   + as->d1);
02069       as->q= ceil ( 2.12* startInc / ( amaxTan * sq->ctPow2 ) );
02070       as->m=0;
02071       as->p=0;
02072       as->totNumPoints = as->q + 3;
02073       sq->n=3;          /* start allover, but skip the first initInc steps */
02074     }
02075   else if ( sq->n < as->m + as->p + 2 )
02076     {
02077       startInc = as->cruiseInc;
02078       startAcc = 0;
02079       as->q= ceil ( 3 * startInc / ( 2 * amaxTan * sq->ctPow2 ) );
02080       as->m=0;
02081       as->p=0;
02082       as->totNumPoints = as->q + 3;
02083       sq->n=3;          /* start allover, but skip the first initInc steps */
02084     }
02085   else
02086     {
02087       /* we are already decelerating, so it would be best to finish that
02088          first. After we're done with that, we can decelerate to zero */
02089 
02090       /* before messing the whole thing up, let's see if we are already
02091          decelerating to zero */
02092       if (as->plFinalInc==0)
02093         {
02094           /* Then we'll reach the end of the segment with a zero velocity.
02095              This means that we don't have to do anything but waiting at the
02096              end of the segment. This is basically the same thing that
02097              happens at the end of a step-motion. This is exactly what
02098              we will tell the system: that we're stepping, so that all of
02099              the extra things needed for a pause within a segment are skipped.
02100           */
02101           sq->paused=0;
02102           sq->stepping=1;
02103           return 0;
02104         }
02105       else
02106         {
02107 
02108           /* let's do a little trick: we copy the deceleration parameters
02109              of the current motion to the acceleration phase parameter
02110              fields in the current segment and calculate a new
02111              deceleration action from finalInc to 0. We'll decrease sq->n
02112              with a number such of steps, such that it will look like
02113              nothing has happened. sqRunCycle won't notice this, and will
02114              think it's (again) in phase 1. We know better.... */
02115 
02116           as->a1=as->a3;
02117           as->b1=as->b3;
02118           as->c1=as->c3;
02119           as->d1=as->d3;
02120 
02121           sq->n -= as->m + as->p;
02122 
02123           as->m =as->q;
02124           as->p=1 ;        /* the cruising phase now becomes the
02125                               usual final step of a segment */
02126 
02127           /* find the finalInc */
02128           startInc = as->plFinalInc;
02129           startAcc = 0;
02130           as->cruiseInc = startInc;
02131 
02132           as->q= ceil ( 3 * startInc / ( 2 * amaxTan * sq->ctPow2 ) );
02133           as->totNumPoints = as->m + as->q + as->p + 2;
02134 
02135         }
02136     }
02137   as->b3 = - ( 3 * startInc + 2 * as->q* startAcc ) \
02138     / ( as->q * as->q * sq->ctPow2 ) ;
02139   as->a3 = ( 2 * startInc + as->q* startAcc ) \
02140     / ( as->q * as->q * as->q * sq->ctPow3 ) ;
02141   as->c3 = startAcc/sq->cycleTime;
02142   as->d3 = startInc;
02143 
02144   as->plFinalInc=0;
02145 
02146   return 0;
02147 }
02148 
02149 /* function to resume with a paused segmentqueue */
02150 int sqResume(SEGMENTQUEUE *sq)
02151 {
02152   SEGMENT *as;                  /* as = Active Segment */
02153   SEGMENT *cursor;
02154 
02155   if (sq==0 || sq->queue==0 )
02156     {
02157       diagnostics("Error in sqResume\n");
02158       return -1;
02159     }
02160 
02161   if ( sq->done!=1)
02162 
02163     /* we can't resume if the systems is not done yet with a step or pause
02164        action */
02165     {
02166       diagnosticsOff("Can't resume if not done with pause or step action\n");
02167       /* this is not a critical error, so we'll just ignore the command */
02168       return 0;
02169     }
02170 
02171   if ( sq->feedOverrideFactor == 0 )
02172     {
02173       /* we can't resume if the feed override factor is zero. To resume
02174          the user should set a new non-zero value for this factor first.
02175          This will immediately result in a resume action. */
02176       diagnostics("Can't resume if feed override is zero\n");
02177       /* not a critical error, so ignore it */
02178       return 0;
02179     }
02180 
02181   if ( sq->numSegments == 0)
02182     {
02183       /* there's not much to do */
02184       sq->paused = 0;
02185       return 0;
02186     }
02187 
02188   /* let's see if the length of the segment(chain) is large enough to
02189      accelerate from zero to finalInc */
02190   as=sq->queue+sq->start;
02191   cursor=as;
02192   /* first find the last segment in the chain */
02193   while ( cursor->nextSegment!=0 && cursor->nextSegment->linkedToPrevSeg==1)
02194     cursor=cursor->nextSegment;
02195 
02196   /* keep linking successive segments to as until the chain is long
02197      enough */
02198 
02199   if ( -1 == sqForwardLinkSegment(sq, as, sq->feedOverrideFactor ))
02200     {
02201       diagnostics("Error in sqResume \n ");
02202       return -1;
02203     }
02204 
02205   if (sq->paused == 1 && sq->stepping == 1 )
02206     sq->stepping=1;
02207   else
02208     sq->stepping=0;
02209 
02210   sq->paused=0;
02211   sq->done=0;
02212 
02213   return 0;
02214 }
02215 
02216 /* function to abort */
02217 int sqAbort(SEGMENTQUEUE *sq)
02218 {
02219   if (1 == sq->aborting)
02220     /* we are already aborting, so let's just ignore it */
02221     return 0;
02222 
02223   if (sq==0)
02224     {
02225       diagnostics("Error in sqAbort\n");
02226       return -1;
02227     }
02228 
02229   if ( sq->paused == 1 || sq->done == 1 )
02230     {
02231       if (-1 == sqClearQueue(sq))
02232         {
02233           diagnostics("Error in sqAbort\n");
02234           return -1;
02235         }
02236     }
02237   else
02238     {
02239       sq->aborting=1;
02240       sqPause(sq);
02241     }
02242   return 0;
02243 }
02244 
02245 /* function to do execute one motion from a stop and stop again */
02246 int sqStep(SEGMENTQUEUE *sq)
02247 {
02248   SEGMENT *as;                  /* as = Active Segment */
02249   if (sq==0)
02250     {
02251       diagnostics("Error in sqStep\n");
02252       return -1;
02253     }
02254 
02255   if (sq->done!=1 || sq->numSegments==0 )
02256     /* step should only be used when system is paused and waiting... */
02257     {
02258       diagnostics("Stepping can only be done when system is paused and waiting\n");
02259       /* not a critical error, let's ignore it */
02260       return 0;;
02261     }
02262 
02263   if ( sq->feedOverrideFactor == 0 )
02264     {
02265       /* we can't step if the feed override factor is zero. To step
02266          the user should set a new non-zero value for this factor first.
02267          This will immediately result in a resume action. */
02268       diagnostics("Can't resume if feed override is zero\n");
02269       /* not a critical error, so ignore it */
02270       return 0;
02271     }
02272 
02273 
02274   /* make finalInc of the current segment 0, set sq->stepping and resume.
02275      This means that after this is segment is done, it will
02276      wait for the next step or resume command */
02277 
02278   as=sq->queue+sq->start;
02279   as->finalInc=0;
02280 
02281   /* if the next segment is linked to the current one, unlink it */
02282   if (as->nextSegment!=0 && as->nextSegment->linkedToPrevSeg==1)
02283     {
02284       as->nextSegment->linkedToPrevSeg=0;
02285       as->nextSegment->numLinkedSegs=as->numLinkedSegs-1;
02286       as->nextSegment->totLength=as->totLength - as->length;
02287       as->numLinkedSegs=0;
02288       as->totLength=as->length;
02289     }
02290   sq->done=0;
02291   sq->stepping=1;
02292   sq->paused=0;
02293   return 0;
02294 }
02295 
02296 int sqIsStepping(SEGMENTQUEUE *sq)
02297 {
02298   if (sq==0)
02299     {
02300       diagnostics("Error in sqIsStepping\n");
02301       return -1;
02302     }
02303   return sq->stepping;
02304 }
02305 
02306 int sqIsDone(SEGMENTQUEUE *sq)
02307 {
02308   if (sq==0)
02309     {
02310       diagnostics("Error in sqIsStepping\n");
02311       return -1;
02312     }
02313   return sq->done;
02314 }
02315 
02316 int sqIsPaused(SEGMENTQUEUE *sq)
02317 {
02318   if (sq==0)
02319     {
02320       diagnostics("Error in sqIsPaused\n");
02321       return -1;
02322     }
02323   return sq->paused;
02324 }
02325 
02326 double sqGetVel(SEGMENTQUEUE *sq)
02327 {
02328   if (sq==0)
02329     {
02330       diagnostics("Error in sqGetVel\n");
02331       return -1;
02332     }
02333 
02334   return sq->currentVel;
02335 }
02336 
02337 double sqGetMaxAcc(SEGMENTQUEUE *sq)
02338 {
02339   if (sq==0)
02340     {
02341       diagnostics("Error in sqGetMaxAcc\n");
02342       return -1;
02343     }
02344   return sq->maxAcc;
02345 }
02346 
02347 int sqGetDepth(SEGMENTQUEUE *sq)
02348 {
02349   if (sq==0)
02350     {
02351       diagnostics("Error in sqGetDepth\n");
02352       return -1;
02353     }
02354   return sq->numSegments;
02355 }
02356 
02357 int sqIsQueueFull(SEGMENTQUEUE *sq)
02358 {
02359   if (sq==0)
02360     {
02361       diagnostics("Error in sqIsQueueFull\n");
02362       return -1;
02363     }
02364   return sq->full;
02365 }
02366 
02367 int sqGetID(SEGMENTQUEUE *sq)
02368 {
02369   if (sq==0)
02370     {
02371       diagnostics("Error in sqGetID\n");
02372       return -1;
02373     }
02374   return sq->currentID;
02375 }
02376 
02377 /* trash */
02378 
02379 # ifdef trash
02380 
02381 /* from sqPreprocessSegment */
02382 
02383                 {
02384                   cursor=prevseg;
02385                   done=0;
02386                   counter=0;
02387                   while (!done)
02388                     {
02389                       counter++;
02390                       if ( counter > sq->size )
02391                         {
02392                           /* we have browsed through the whole queue and can't
02393                              get out of the loop.... */
02394                           diagnostics("Can't get out of the loop\n");
02395                           return -1;
02396                         }
02397 
02398                       if (cursor->initInc < cornerInc )
02399                         /* then we're done (never true for the first
02400                            iteration of course) */
02401 
02402                         done=1;
02403                       else if (cursor->linkedToPrevSeg==1)
02404                         /* it is already linked */
02405                         {
02406                           cursor=cursor->prevSegment;
02407                           if (cursor == 0 )
02408                             {
02409                               diagnostics("Panic: cursor = NULL in sqPreprocessSegment\n");
02410                               return -1;
02411                             }
02412                         }
02413                       else
02414                         {
02415                           amaxTan = sqGiveMinAmaxTan(cursor);
02416                           minNumSteps=ceil(3*( cursor->initInc-cornerInc ) / \
02417                                     (2*amaxTan*sq->ctPow2));
02418                           if ((minNumSteps+1)*(cursor->initInc+cornerInc)/2 \
02419                              - cursor->initInc >  \
02420                              cursor->length-5*max(cursor->initInc,cornerInc) )
02421                             {
02422                               /* then it needs to be linked */
02423 
02424                               cursor=cursor->prevSegment;
02425                               if (cursor == 0 )
02426                                 {
02427                                   diagnostics("Panic: cursor = NULL in sqPreprocessSegment\n");
02428                                   return -1;
02429                                 }
02430                               if (-1 == sqLinkSegments(cursor,cursor->nextSegment,SQ_HIGH_LINKING_PRIORITY))
02431                                 {
02432                                   diagnostics("Error 5 in sqPreprocessSegment()\n");
02433                                   return -1;
02434                                 }
02435 
02436                             }
02437                           else
02438                             done=1; /* no further linking needed */
02439                         }
02440                       if ( cursor == sq->queue + sq->start )
02441                         {
02442                           diagnostics("Beginning of queue reached, no further linking possible\n");
02443                           done =1;
02444                         }
02445                     }
02446 
02447                   /* another part from sqPreprocessSegment */
02448                   /* find the minimum maximum acceleration for this chain */
02449 
02450                   amaxTan = sqGiveMinAmaxTan(cursor);
02451                   minNumSteps = ceil ( 3 * (cornerInc-cursor->initInc ) / \
02452                                ( 2 * amaxTan * sq->ctPow2 ));
02453                   if ((minNumSteps+1)*(cursor->initInc+cornerInc)/2 - \
02454                       cursor->initInc >
02455                       cursor->totLength - 5*max( cursor->initInc,cornerInc ) )
02456                     /* link the new segment to the previous segment */
02457                     if ( -1 == sqLinkSegments(prevseg,newseg,SQ_HIGH_LINKING_PRIORITY))
02458                       {
02459                         diagnostics("Error 4 in sqPreprocessSegment()\n");
02460                         return -1;
02461                       }
02462 
02463                   /* from sqSetFeedOverride */
02464       amaxTan = sqGiveMinAmaxTan(as);
02465       while (!done)
02466         {
02467           if ( cursor->nextSegment!=0 && cursor->nextSegment->maxInc < \
02468                cursor->maxInc)
02469               finalInc=min(cursor->finalInc,\
02470                           cursor->nextSegment->maxInc*sq->feedOverrideFactor);
02471 
02472             else
02473               finalInc=min(cursor->finalInc,\
02474                            cursor->maxInc*sq->feedOverrideFactor);
02475           amaxTan = min ( amaxTan, cursor->amaxTan);
02476           minNumSteps = ceil ( 3 *fabs(finalInc-startInc) / \
02477                                ( 2 * amaxTan * sq->ctPow2 ));
02478           if ((minNumSteps+1)* (startInc+finalInc)/2  > \
02479               as->totLength - 1 * finalInc )
02480             /* link the new segment to the next segment */
02481             {
02482               if (-1 ==sqLinkSegments(cursor,cursor->nextSegment,SQ_HIGH_LINKING_PRIORITY))
02483                 {
02484                   diagnostics("Error in sqSetFeedOverride\n");
02485                   return -1;
02486                 }
02487               cursor=cursor->nextSegment;
02488               if (cursor == 0 )
02489                 {
02490                   diagnostics("Panic 2: cursor = NULL in sqSetFeedOverride\n");
02491                   return -1;
02492                 }
02493 
02494             }
02495           else
02496             done=1;
02497         }
02498 
02499       /* from sqResume */
02500   amaxTan = sqGiveMinAmaxTan(as);
02501 
02502   /* keep linking segments until the chain is long enough */
02503   while (!done)
02504     {
02505       if ( cursor->nextSegment!=0 && cursor->nextSegment->maxInc < \
02506            cursor->maxInc)
02507         finalInc=min(cursor->finalInc,\
02508                      cursor->nextSegment->maxInc*sq->feedOverrideFactor);
02509 
02510       else
02511         finalInc=min(cursor->finalInc,\
02512                      cursor->maxInc*sq->feedOverrideFactor);
02513 
02514       amaxTan = min ( amaxTan, cursor->amaxTan);
02515       minNumSteps = ceil ( 3 * finalInc / \
02516                            ( 2 * amaxTan * sq->ctPow2 ));
02517       if ((minNumSteps+1)* finalInc/2  > \
02518           as->totLength - 2 * finalInc )
02519         /* link the new segment to the next segment */
02520         {
02521           if (-1 == sqLinkSegments(cursor,cursor->nextSegment,SQ_HIGH_LINKING_PRIORITY))
02522             {
02523               diagnostics("Error in sqResume \n");
02524               return -1;
02525             }
02526           cursor=cursor->nextSegment;
02527           if (cursor == 0 )
02528             {
02529               diagnostics("Panic: cursor = NULL in sqResume\n");
02530               return -1;
02531             }
02532 
02533         }
02534       else
02535         done=1;
02536     }
02537 
02538 
02539 #endif

Generated on Sun Dec 2 15:27:43 2001 for EMC by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001