00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "constraint_aware_spline_smoother/ParabolicPathSmooth/ParabolicRamp.h"
00032 #include "constraint_aware_spline_smoother/ParabolicPathSmooth/Config.h"
00033 #include <iostream>
00034 using namespace std;
00035
00036 namespace ParabolicRamp {
00037
00038
00039 static bool gSuppressSavingRamps = false;
00040
00041
00042 static bool gMinAccelQuiet = false;
00043
00044
00045 static bool gMinTime2Quiet = false;
00046
00047
00048 int quadratic(Real a, Real b, Real c, Real& x1, Real& x2)
00049 {
00050 if(a == 0)
00051 {
00052 if(b == 0)
00053 {
00054 if(c == 0)
00055 return -1;
00056 return 0;
00057 }
00058 x1=-c/b;
00059 return 1;
00060 }
00061 if(c == 0) {
00062 x1 = 0;
00063 x2 = -b/a;
00064 return 2;
00065 }
00066
00067 Real det = b*b-4.0*a*c;
00068 if(det < 0.0)
00069 return 0;
00070 if(det == 0.0) {
00071 x1 = -b/(2.0*a);
00072 return 1;
00073 }
00074 det = sqrt(det);
00075 if(Abs(-b - det) < Abs(a))
00076 x1 = 0.5 * (-b + det)/a;
00077 else
00078 x1 = 2.0 * c / (-b-det);
00079 if(Abs(-b + det) < Abs(a))
00080 x2 = 0.5 * (-b-det) / a;
00081 else
00082 x2 = 2.0 * c / (-b+det);
00083 return 2;
00084 }
00085
00086
00087
00088 bool SaveRamp(const char* fn,Real x0,Real dx0,Real x1,Real dx1,
00089 Real a,Real v,Real t)
00090 {
00091 if(gSuppressSavingRamps) return true;
00092 PARABOLIC_RAMP_PLOG("Saving ramp to %s\n",fn);
00093 FILE* f=fopen(fn,"ab");
00094 if(!f) {
00095 f = fopen(fn,"wb");
00096 if(!f) {
00097 PARABOLIC_RAMP_PLOG("Unable to open file %s for saving\n",fn);
00098 return false;
00099 }
00100 }
00101 double vals[7]={x0,dx0,x1,dx1,a,v,t};
00102 fwrite(vals,sizeof(double),7,f);
00103 fclose(f);
00104 return true;
00105 }
00106
00107
00108 bool LoadRamp(FILE* f,Real& x0,Real& dx0,Real& x1,Real& dx1,
00109 Real& a,Real& v,Real& t)
00110 {
00111 double vals[7];
00112 int size = fread(vals,sizeof(double),7,f);
00113 if(size != 7) return false;
00114 x0=vals[0]; dx0=vals[1];
00115 x1=vals[2]; dx1=vals[3];
00116 a=vals[4]; v=vals[5];
00117 t=vals[6];
00118 return true;
00119 }
00120
00121
00122 bool LoadRamp(const char* fn,Real& x0,Real& dx0,Real& x1,Real& dx1,
00123 Real& a,Real& v,Real& t)
00124 {
00125 FILE* f=fopen(fn,"rb");
00126 if(!f) return false;
00127 bool res=LoadRamp(f,x0,dx0,x1,dx1,a,v,t);
00128 fclose(f);
00129 return res;
00130 }
00131
00132 void TestRamps(const char* fn)
00133 {
00134 FILE* f=fopen(fn,"rb");
00135 if(!f) return;
00136
00137 gSuppressSavingRamps=true;
00138 ParabolicRamp1D ramp;
00139 Real a,v,t;
00140 int numRamps=0;
00141 while(LoadRamp(f,ramp.x0,ramp.dx0,ramp.x1,ramp.dx1,a,v,t)) {
00142 if(t < 0) {
00143 PARABOLIC_RAMP_ASSERT( a >= 0 && v >= 0);
00144 bool res=ramp.SolveMinTime(a,v);
00145 PARABOLIC_RAMP_PLOG("Result %d: t=%g\n",(int)res,ramp.ttotal);
00146 }
00147 else if(a < 0) {
00148 PARABOLIC_RAMP_ASSERT( t >= 0 && v >= 0);
00149 bool res=ramp.SolveMinAccel(t,v);
00150 PARABOLIC_RAMP_PLOG("Result %d: a=%g\n",(int)res,ramp.a1);
00151 }
00152 else {
00153 bool res=ramp.SolveMinTime2(a,v,t);
00154 PARABOLIC_RAMP_PLOG("Result %d: t=%g\n",(int)res,ramp.ttotal);
00155
00156 if(!res) {
00157 bool res=ramp.SolveMinAccel(t,v);
00158 PARABOLIC_RAMP_PLOG("SolveMinAccel result %d: a=%g\n",(int)res,ramp.a1);
00159 }
00160 }
00161 PARABOLIC_RAMP_PLOG("\n");
00162 numRamps++;
00163 }
00164 fclose(f);
00165 PARABOLIC_RAMP_PLOG("%d ramps loaded from file %s\n",numRamps,fn);
00166 gSuppressSavingRamps=false;
00167 }
00168
00169 class ParabolicRamp
00170 {
00171 public:
00172 Real Evaluate(Real t) const;
00173 Real Derivative(Real t) const;
00174 Real Accel(Real t) const;
00175 bool Solve(Real amax);
00176 bool SolveFixedTime(Real endTime);
00177 Real MaxVelocity() const;
00178
00179
00180 Real x0,dx0;
00181 Real x1,dx1;
00182
00183
00184 Real a;
00185 Real ttotal;
00186 };
00187
00188
00189 class PPRamp
00190 {
00191 public:
00192 Real Evaluate(Real t) const;
00193 Real Derivative(Real t) const;
00194 Real Accel(Real t) const;
00195 bool SolveMinTime(Real amax);
00196 bool SolveMinTime2(Real amax,Real timeLowerBound);
00197 bool SolveMinAccel(Real endTime);
00198 Real SolveMinAccel2(Real endTime);
00199 Real MaxVelocity() const;
00200
00201 Real CalcTotalTime(Real a) const;
00202 Real CalcSwitchTime(Real a) const;
00203 Real CalcMinAccel(Real endTime,Real sign,Real& switchTime) const;
00204 int CalcSwitchTimes(Real a,Real& t1,Real& t2) const;
00205 int CalcTotalTimes(Real a,Real& t1,Real& t2) const;
00206
00207
00208 Real x0,dx0;
00209 Real x1,dx1;
00210
00211
00212 Real a;
00213 Real tswitch,ttotal;
00214 };
00215
00216 class PLPRamp
00217 {
00218 public:
00219 Real Evaluate(Real t) const;
00220 Real Derivative(Real t) const;
00221 Real Accel(Real t) const;
00222 bool SolveMinTime(Real amax,Real vmax);
00223 bool SolveMinTime2(Real amax,Real vmax,Real timeLowerBound);
00224 bool SolveMinAccel(Real endTime,Real vmax);
00225 Real SolveMinAccel2(Real endTime,Real vmax);
00226
00227 Real CalcTotalTime(Real a,Real v) const;
00228 Real CalcSwitchTime1(Real a,Real v) const;
00229 Real CalcSwitchTime2(Real a,Real v) const;
00230 Real CalcMinAccel(Real endTime,Real v) const;
00231 Real CalcMinTime2(Real endTime,Real a,Real vmax) const;
00232
00233
00234 Real x0,dx0;
00235 Real x1,dx1;
00236
00237
00238 Real a,v;
00239 Real tswitch1,tswitch2,ttotal;
00240 };
00241
00242
00243
00244 Real ParabolicRamp::Evaluate(Real t) const
00245 {
00246 return x0 + t*dx0 + 0.5*a*Sqr(t);
00247 }
00248
00249 Real ParabolicRamp::Derivative(Real t) const
00250 {
00251 return dx0 + a*t;
00252 }
00253
00254 Real ParabolicRamp::Accel(Real t) const
00255 {
00256 return a;
00257 }
00258
00259 bool ParabolicRamp::Solve(Real amax)
00260 {
00261 if(FuzzyEquals(x0,x1,EpsilonX)) {
00262 if(FuzzyEquals(dx0,dx1,EpsilonV)) {
00263 a=0;
00264 ttotal = 0;
00265 return true;
00266 }
00267 else if(FuzzyEquals(dx0,-dx1,EpsilonV)) {
00268 a=amax*Sign(dx1);
00269 ttotal = (dx1-dx0)/a;
00270 return true;
00271 }
00272
00273 return false;
00274 }
00275 a = 0.5*(Sqr(dx0)-Sqr(dx1))/(x0-x1);
00276
00277 if(Abs(a) < Abs(dx0+dx1)) {
00278 if(Abs(dx0+dx1) < EpsilonV) {
00279
00280
00281
00282 return false;
00283 }
00284 else {
00285 ttotal = 2.0*(x1-x0)/(dx0+dx1);
00286 }
00287 }
00288 else {
00289 ttotal = (dx1-dx0)/a;
00290 }
00291 if(ttotal < 0 && ttotal > -EpsilonT) ttotal = 0;
00292 if(ttotal < 0) {
00293 ttotal = -1;
00294 a=0;
00295 return false;
00296 }
00297
00298
00299 if(Abs(a) > amax && Abs(a) <= amax+EpsilonA) {
00300
00301 a = Sign(a)*amax;
00302 }
00303 if(FuzzyEquals(Evaluate(ttotal),x1,EpsilonX) && FuzzyEquals(Derivative(ttotal),dx1,EpsilonV)) {
00304 return true;
00305 }
00306 return false;
00307 }
00308
00309 bool ParabolicRamp::SolveFixedTime(Real endTime)
00310 {
00311 ttotal = endTime;
00312 if(FuzzyEquals(x0,x1,EpsilonX)) {
00313 if(FuzzyEquals(dx0,dx1,EpsilonV)) {
00314 a = 0;
00315 return FuzzyEquals(endTime,0.0,EpsilonT);
00316 }
00317 else if(FuzzyEquals(dx0,-dx1,EpsilonV)) {
00318 a=(dx1-dx0)/endTime;
00319 return true;
00320 }
00321
00322 return false;
00323 }
00324 a = 0.5*(Sqr(dx0)-Sqr(dx1))/(x0-x1);
00325
00326 if(Abs(a) < Abs(dx0+dx1)) {
00327 if(Abs(dx0+dx1) < EpsilonV) {
00328
00329
00330
00331 return false;
00332 }
00333 else {
00334 ttotal = 2.0*(x1-x0)/(dx0+dx1);
00335 }
00336 }
00337 else {
00338 ttotal = (dx1-dx0)/a;
00339 }
00340 if(!FuzzyEquals(ttotal,endTime,EpsilonT)) return false;
00341 ttotal = endTime;
00342 if(FuzzyEquals(Evaluate(ttotal),x1,EpsilonX) && FuzzyEquals(Derivative(ttotal),dx1,EpsilonV)) {
00343 return true;
00344 }
00345 return false;
00346 }
00347
00348 Real ParabolicRamp::MaxVelocity() const
00349 {
00350 if(fabs(dx0) > fabs(dx1)) return dx0;
00351 else return dx1;
00352 }
00353
00354 Real PPRamp::Evaluate(Real t) const
00355 {
00356 if(t < tswitch) return x0 + 0.5*a*t*t + dx0*t;
00357 else {
00358 Real tmT = t - ttotal;
00359 return x1 - 0.5*a*tmT*tmT + dx1*tmT;
00360 }
00361 }
00362
00363 Real PPRamp::Derivative(Real t) const
00364 {
00365 if(t < tswitch) return a*t + dx0;
00366 else {
00367 Real tmT = t - ttotal;
00368 return -a*tmT + dx1;
00369 }
00370 }
00371
00372 Real PPRamp::Accel(Real t) const
00373 {
00374 if(t < tswitch) return a;
00375 else return -a;
00376 }
00377
00378 bool PPRamp::SolveMinTime(Real amax)
00379 {
00380 Real tpn = CalcTotalTime(amax), tnp = CalcTotalTime(-amax);
00381
00382 if(tpn >= 0) {
00383 if(tnp >= 0 && tnp < tpn) {
00384 a = -amax;
00385 ttotal = tnp;
00386 }
00387 else {
00388 a = amax;
00389 ttotal = tpn;
00390 }
00391 }
00392 else if(tnp >= 0) {
00393 a = -amax;
00394 ttotal = tnp;
00395 }
00396 else {
00397 tswitch = -1;
00398 ttotal = -1;
00399 a = 0;
00400 return false;
00401 }
00402 tswitch = CalcSwitchTime(a);
00403
00404
00405 if(gValidityCheckLevel >= 1) {
00406 if(!FuzzyEquals(x0 + 0.5*a*Sqr(tswitch) + dx0*tswitch,x1 - 0.5*a*Sqr(tswitch-ttotal) + dx1*(tswitch-ttotal),EpsilonX)) {
00407 if(gVerbose >= 1)
00408 PARABOLIC_RAMP_PERROR("Numerical error computing parabolic-parabolic min-time...\n");
00409 if(gVerbose >= 2) {
00410 PARABOLIC_RAMP_PERROR("x0=%g,%g, x1=%g,%g\n",x0,dx0,x1,dx1);
00411 PARABOLIC_RAMP_PERROR("a = %g, tswitch = %g, ttotal = %g\n",a,tswitch,ttotal);
00412 PARABOLIC_RAMP_PERROR("Forward %g, backward %g, diff %g\n",x0 + 0.5*a*Sqr(tswitch) + dx0*tswitch,x1 - 0.5*a*Sqr(tswitch-ttotal) + dx1*(tswitch-ttotal), x0 + 0.5*a*Sqr(tswitch) + dx0*tswitch - (x1 - 0.5*a*Sqr(tswitch-ttotal) + dx1*(tswitch-ttotal)));
00413
00414
00415 Real b = 2.0*a*dx0;
00416 Real c = (Sqr(dx0)-Sqr(dx1))*0.5+(x0-x1)*a;
00417 Real t1,t2;
00418 int res=quadratic(a*a,b,c,t1,t2);
00419 PARABOLIC_RAMP_PERROR("Quadratic equation %g x^2 + %g x + %g = 0\n",a*a,b,c);
00420 PARABOLIC_RAMP_PERROR("%d results, %g %g\n",res,t1,t2);
00421 if(gErrorGetchar) getchar();
00422 }
00423 if(gErrorSave) SaveRamp("PP_SolveMinTime_failure.dat",x0,dx0,x1,dx1,amax,Inf,-1);
00424 return false;
00425 }
00426 }
00427
00428 return true;
00429 }
00430
00431 bool PPRamp::SolveMinTime2(Real amax,Real timeLowerBound)
00432 {
00433 PARABOLIC_RAMP_ASSERT(timeLowerBound >= 0);
00434 Real t1pn,t1np,t2pn,t2np;
00435 int respn = CalcTotalTimes(amax,t1pn,t2pn);
00436 int resnp = CalcTotalTimes(-amax,t1np,t2np);
00437 ttotal = Inf;
00438 if(respn >= 1) {
00439 if(t1pn >= timeLowerBound && t1pn < ttotal) {
00440 ttotal = t1pn;
00441 a = amax;
00442 }
00443 }
00444 if(respn >= 2) {
00445 if(t2pn >= timeLowerBound && t2pn < ttotal) {
00446 ttotal = t2pn;
00447 a = amax;
00448 }
00449 }
00450 if(resnp >= 1) {
00451 if(t1np >= timeLowerBound && t1np < ttotal) {
00452 ttotal = t1np;
00453 a = -amax;
00454 }
00455 }
00456 if(resnp >= 2) {
00457 if(t2np >= timeLowerBound && t2np < ttotal) {
00458 ttotal = t2np;
00459 a = -amax;
00460 }
00461 }
00462 if(IsInf(ttotal)) {
00463 a = 0;
00464 tswitch = ttotal = -1;
00465 return false;
00466 }
00467
00468 Real ts1,ts2;
00469 int res = CalcSwitchTimes(a,ts1,ts2);
00470 PARABOLIC_RAMP_ASSERT(res > 0);
00471 if(res == 1) {
00472 tswitch = ts1;
00473 PARABOLIC_RAMP_ASSERT(FuzzyEquals(ttotal,ts1*2.0 - (dx1-dx0)/a,EpsilonT));
00474 }
00475 else {
00476 if(FuzzyEquals(ttotal,ts1*2.0 - (dx1-dx0)/a,EpsilonT))
00477 tswitch = ts1;
00478 else {
00479 PARABOLIC_RAMP_ASSERT(FuzzyEquals(ttotal,ts2*2.0 - (dx1-dx0)/a,EpsilonT));
00480 tswitch = ts2;
00481 }
00482 }
00483
00484
00485 if(gValidityCheckLevel >= 1) {
00486 Real eps = EpsilonX;
00487 if(!FuzzyEquals(x0 + 0.5*a*Sqr(tswitch) + dx0*tswitch,x1 - 0.5*a*Sqr(tswitch-ttotal) + dx1*(tswitch-ttotal),eps)) {
00488 if(gVerbose >= 1)
00489 PARABOLIC_RAMP_PERROR("Numerical error in PPRamp::SolveMinTime2...\n");
00490 if(gVerbose >= 2) {
00491 PARABOLIC_RAMP_PERROR("x0=%g,%g, x1=%g,%g\n",x0,dx0,x1,dx1);
00492 PARABOLIC_RAMP_PERROR("a = %g, tswitch = %g, ttotal = %g\n",a,tswitch,ttotal);
00493 PARABOLIC_RAMP_PERROR("Forward %g, backward %g, diff %g\n",x0 + 0.5*a*Sqr(tswitch) + dx0*tswitch,x1 - 0.5*a*Sqr(tswitch-ttotal) + dx1*(tswitch-ttotal), x0 + 0.5*a*Sqr(tswitch) + dx0*tswitch - (x1 - 0.5*a*Sqr(tswitch-ttotal) + dx1*(tswitch-ttotal)));
00494
00495
00496 Real b = 2.0*a*dx0;
00497 Real c = (Sqr(dx0)-Sqr(dx1))*0.5+(x0-x1)*a;
00498 Real t1,t2;
00499 int res=quadratic(a*a,b,c,t1,t2);
00500 PARABOLIC_RAMP_PERROR("Quadratic equation %g x^2 + %g x + %g = 0\n",a*a,b,c);
00501 PARABOLIC_RAMP_PERROR("%d results, %g %g\n",res,t1,t2);
00502 }
00503 if(gErrorGetchar) getchar();
00504 if(gErrorSave) SaveRamp("PP_SolveMinTime_failure.dat",x0,dx0,x1,dx1,amax,Inf,timeLowerBound);
00505 return false;
00506 }
00507 }
00508 return true;
00509 }
00510
00511 bool PPRamp::SolveMinAccel(Real endTime)
00512 {
00513 Real switch1,switch2;
00514 Real apn = CalcMinAccel(endTime,1.0,switch1);
00515 Real anp = CalcMinAccel(endTime,-1.0,switch2);
00516
00517 if(apn >= 0) {
00518 if(anp >= 0 && anp < apn) a = -anp;
00519 else a = apn;
00520 }
00521 else if(anp >= 0) a = -anp;
00522 else {
00523 a=0;
00524 tswitch = -1;
00525 ttotal = -1;
00526 return false;
00527 }
00528 ttotal = endTime;
00529 if(a == apn)
00530 tswitch = switch1;
00531 else
00532 tswitch = switch2;
00533
00534
00535 if(gValidityCheckLevel >= 1) {
00536 Real t2mT = tswitch-ttotal;
00537 if(!FuzzyEquals(x0 + tswitch*dx0 + 0.5*a*Sqr(tswitch),x1+t2mT*dx1-0.5*a*Sqr(t2mT),EpsilonX)) {
00538 if(gVerbose >= 1)
00539 PARABOLIC_RAMP_PERROR("PPRamp::SolveMinAccel: Numerical error, x mismatch!\n");
00540 if(gVerbose >= 2) {
00541 PARABOLIC_RAMP_PERROR("Forward ramp: %g, backward %g, diff %g\n",x0 + tswitch*dx0 + 0.5*a*Sqr(tswitch),x1+t2mT*dx1-0.5*a*Sqr(t2mT),x0 + tswitch*dx0 + 0.5*a*Sqr(tswitch)-(x1+t2mT*dx1-0.5*a*Sqr(t2mT)));
00542 PARABOLIC_RAMP_PERROR("A+ = %g, A- = %g\n",apn,anp);
00543 PARABOLIC_RAMP_PERROR("ramp %g,%g -> %g, %g\n",x0,dx0,x1,dx1);
00544 PARABOLIC_RAMP_PERROR("Switch 1 %g, switch 2 %g, total %g\n",switch1,switch2,ttotal);
00545
00546 {
00547 Real sign = 1.0;
00548 Real a=Sqr(endTime);
00549 Real b=sign*(2.0*(dx0+dx1)*endTime+4.0*(x0-x1));
00550 Real c=-Sqr(dx1-dx0);
00551 PARABOLIC_RAMP_PERROR("Quadratic %g x^2 + %g x + %g = 0\n",a,b,c);
00552 Real t1,t2;
00553 int res = quadratic(a,b,c,t1,t2);
00554 PARABOLIC_RAMP_PERROR("Solutions: %d, %g and %g\n",res,t1,t2);
00555 }
00556 {
00557 Real sign = -1.0;
00558 Real a=Sqr(endTime);
00559 Real b=sign*(2.0*(dx0+dx1)*endTime+4.0*(x0-x1));
00560 Real c=-Sqr(dx1-dx0);
00561 PARABOLIC_RAMP_PERROR("Quadratic %g x^2 + %g x + %g = 0\n",a,b,c);
00562 Real t1,t2;
00563 int res = quadratic(a,b,c,t1,t2);
00564 PARABOLIC_RAMP_PERROR("Solutions: %d, %g and %g\n",res,t1,t2);
00565 }
00566 }
00567 if(gErrorSave) SaveRamp("PP_SolveMinAccel_failure.dat",x0,dx0,x1,dx1,-1,Inf,endTime);
00568 if(gErrorGetchar) getchar();
00569 }
00570 if(!FuzzyEquals(dx0 + a*tswitch,dx1-a*t2mT,EpsilonV)) {
00571 if(gVerbose >= 1) PARABOLIC_RAMP_PERROR("PPRamp::SolveMinAccel: Numerical error, v mismatch!\n");
00572 if(gVerbose >= 2) {
00573 PARABOLIC_RAMP_PERROR("Velocity error %g vs %g, err %g\n",dx0+a*tswitch,dx1-a*t2mT,dx0+a*tswitch-(dx1-a*t2mT));
00574 PARABOLIC_RAMP_PERROR("ramp %g,%g -> %g, %g\n",x0,dx0,x1,dx1);
00575 PARABOLIC_RAMP_PERROR("Accel %g\n",a);
00576 PARABOLIC_RAMP_PERROR("Switch %g, total %g\n",tswitch,ttotal);
00577 }
00578 if(gErrorSave) SaveRamp("PP_SolveMinAccel_failure.dat",x0,dx0,x1,dx1,-1,Inf,endTime);
00579 if(gErrorGetchar) getchar();
00580 return false;
00581 }
00582 }
00583 return true;
00584 }
00585
00586 Real PPRamp::MaxVelocity() const
00587 {
00588 return tswitch*a+dx0;
00589 }
00590
00591 Real PPRamp::CalcTotalTime(Real a) const
00592 {
00593 Real tswitch = CalcSwitchTime(a);
00594
00595 if(tswitch < 0) return -1;
00596 if(tswitch < (dx1-dx0)/a) return -1;
00597 return tswitch*2.0 - (dx1-dx0)/a;
00598 }
00599
00600 int PPRamp::CalcTotalTimes(Real a,Real& t1,Real& t2) const
00601 {
00602 Real ts1,ts2;
00603 int res=CalcSwitchTimes(a,ts1,ts2);
00604 if(res == 0) return res;
00605 else if(res == 1) {
00606 if(ts1 < (dx1-dx0)/a) return 0;
00607 t1 = ts1*2.0 - (dx1-dx0)/a;
00608 return 1;
00609 }
00610 else {
00611
00612 if(ts1 < (dx1-dx0)/a) t1=-1;
00613 else t1 = ts1*2.0 - (dx1-dx0)/a;
00614 if(ts2 < (dx1-dx0)/a) t2=-1;
00615 else t2 = ts2*2.0 - (dx1-dx0)/a;
00616 if(t1 < 0) {
00617 if(t2 < 0) return 0;
00618 t1 = t2;
00619 return 1;
00620 }
00621 else {
00622 if(t2 < 0) return 1;
00623 else return 2;
00624 }
00625 }
00626 }
00627
00628 int PPRamp::CalcSwitchTimes(Real a,Real& t1,Real& t2) const
00629 {
00630 int res;
00631 if(Abs(a) > 1.0) {
00632
00633 Real b = 2.0*dx0;
00634 Real c = (Sqr(dx0)-Sqr(dx1))*0.5/a+x0-x1;
00635 res=quadratic(a,b,c,t1,t2);
00636 }
00637 else {
00638 Real b = 2.0*a*dx0;
00639 Real c = (Sqr(dx0)-Sqr(dx1))*0.5+(x0-x1)*a;
00640 res=quadratic(a*a,b,c,t1,t2);
00641 }
00642 if(res == 0) {
00643 return res;
00644 }
00645 else if(res == 2) {
00646 if(t1 < 0 && t1 > -EpsilonT*0.1) t1=0;
00647 if(t2 < 0 && t2 > -EpsilonT*0.1) t2=0;
00648 if(t1 < 0 || t1*Abs(a) < (dx1-dx0)*Sign(a)) {
00649 if(t2 < 0 || t2*Abs(a) < (dx1-dx0)*Sign(a)) return 0;
00650 t1 = t2;
00651 return 1;
00652 }
00653 else if(t2 < 0 || t2*Abs(a) < (dx1-dx0)*Sign(a)) {
00654 return 1;
00655 }
00656 else {
00657 return 2;
00658 }
00659 }
00660 else {
00661 if(t1 < 0 && t1 > -EpsilonT) t1=0;
00662 if(t1 < 0) return 0;
00663 return 1;
00664 }
00665 }
00666
00667 Real PPRamp::CalcSwitchTime(Real a) const
00668 {
00669 Real t1,t2;
00670 int res = CalcSwitchTimes(a,t1,t2);
00671 if(res == 0) {
00672 return -1;
00673 }
00674 else if(res == 2) {
00675
00676 if(t2*Abs(a) < (dx1-dx0)*Sign(a)) return t1;
00677 else if(t1*Abs(a) < (dx1-dx0)*Sign(a)) return t2;
00678 else return Min(t1,t2);
00679 }
00680 else return t1;
00681 }
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704 Real PPRamp::CalcMinAccel(Real endTime,Real sign,Real& switchTime) const
00705 {
00706 Real a = -(dx1 - dx0)/endTime;
00707 Real b = (2.0*(dx0+dx1)+4.0*(x0-x1)/endTime);
00708 Real c = (dx1 - dx0)*endTime;
00709 Real rat1,rat2;
00710 int res=quadratic(a,b,c,rat1,rat2);
00711 Real accel1 = (dx1-dx0)/rat1;
00712 Real accel2 = (dx1-dx0)/rat2;
00713 Real switchTime1 = endTime*0.5+0.5*rat1;
00714 Real switchTime2 = endTime*0.5+0.5*rat2;
00715
00716 if(switchTime1 > endTime && switchTime1 < endTime+EpsilonT*1e-1)
00717 switchTime1 = endTime;
00718 if(switchTime2 > endTime && switchTime2 < endTime+EpsilonT*1e-1)
00719 switchTime2 = endTime;
00720 if(switchTime1 < 0 && switchTime1 > EpsilonT*1e-1)
00721 switchTime1 = 0;
00722 if(switchTime2 < 0 && switchTime2 > EpsilonT*1e-1)
00723 switchTime2 = 0;
00724 if(res > 0 && FuzzyZero(rat1,EpsilonT)) {
00725
00726
00727 if(!FuzzyZero(endTime,EpsilonT)) {
00728 accel1=-2.0*(dx0+dx1)/endTime + 4.0*(x1-x0)/Sqr(endTime);
00729 }
00730 }
00731 if(res > 1 && FuzzyZero(rat2,EpsilonT)) {
00732 if(!FuzzyZero(endTime,EpsilonT)) {
00733 accel2=-2.0*(dx0+dx1)/endTime + 4.0*(x1-x0)/Sqr(endTime);
00734 }
00735 }
00736 bool firstInfeas = false;
00737 if(res > 0 && (FuzzyZero(accel1,EpsilonA) || FuzzyZero(endTime/rat1,EpsilonA))) {
00738 if(!FuzzyZero(dx0-dx1,EpsilonT)) {
00739 switchTime1 = endTime*0.5;
00740 }
00741 if(!FuzzyEquals(x0 + switchTime1*dx0 + 0.5*Sqr(switchTime1)*accel1,x1 - (endTime-switchTime1)*dx1 - 0.5*Sqr(endTime-switchTime1)*accel1,EpsilonX) ||
00742 !FuzzyEquals(dx0+switchTime1*accel1,dx1+(endTime-switchTime1)*accel1,EpsilonV)) {
00743 firstInfeas = true;
00744 }
00745 }
00746 if(res > 1 && (FuzzyZero(accel2,EpsilonA) || FuzzyZero(endTime/rat2,EpsilonA))) {
00747 if(!FuzzyZero(dx0-dx1,EpsilonT)) {
00748 switchTime2 = endTime*0.5;
00749 }
00750 if(!FuzzyEquals(x0 + switchTime2*dx0 + 0.5*Sqr(switchTime2)*accel2,x1 - (endTime-switchTime2)*dx1 - 0.5*Sqr(endTime-switchTime2)*accel2,EpsilonX) ||
00751 !FuzzyEquals(dx0+switchTime2*accel2,dx1+(endTime-switchTime2)*accel2,EpsilonV)) {
00752 res--;
00753 }
00754 }
00755 if(firstInfeas) {
00756 accel1 = accel2;
00757 rat1 = rat2;
00758 switchTime1 = switchTime2;
00759 res--;
00760 }
00761 if(res==0) return -1;
00762 else if(res==1) {
00763 if(switchTime1 >= 0 && switchTime1 <= endTime) { switchTime=switchTime1; return sign*accel1; }
00764 return -1.0;
00765 }
00766 else if(res==2) {
00767 if(switchTime1 >= 0 && switchTime1 <= endTime) {
00768 if(switchTime2 >= 0 && switchTime2 <= endTime) {
00769 if(accel1 < accel2) { switchTime=switchTime1; return sign*accel1; }
00770 else { switchTime=switchTime2; return sign*accel2; }
00771 }
00772 else { switchTime=switchTime1; return sign*accel1; }
00773 }
00774 else if(switchTime2 >= 0 && switchTime2 <= endTime) { switchTime=switchTime2; return sign*accel2; }
00775 return -1.0;
00776 }
00777 if(FuzzyZero(a,EpsilonT) && FuzzyZero(b,EpsilonT) && FuzzyZero(c,EpsilonT)) {
00778 switchTime = 0.5*endTime;
00779 return 0;
00780 }
00781 return -1.0;
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877 }
00878
00879
00880 Real PLPRamp::Evaluate(Real t) const
00881 {
00882 Real tmT = t - ttotal;
00883 if(t < tswitch1) return x0 + 0.5*a*Sqr(t) + dx0*t;
00884 else if(t < tswitch2) {
00885 Real xswitch = x0 + 0.5*a*Sqr(tswitch1) + dx0*tswitch1;
00886 return xswitch + (t-tswitch1)*v;
00887 }
00888 else return x1 - 0.5*a*Sqr(tmT) + dx1*tmT;
00889 }
00890
00891 Real PLPRamp::Derivative(Real t) const
00892 {
00893 Real tmT = t - ttotal;
00894 if(t < tswitch1) return a*t + dx0;
00895 else if(t < tswitch2) return v;
00896 else return -a*tmT + dx1;
00897 }
00898
00899 Real PLPRamp::Accel(Real t) const
00900 {
00901 if(t < tswitch1) return a;
00902 else if(t < tswitch2) return 0;
00903 else return -a;
00904 }
00905
00906 Real PLPRamp::CalcTotalTime(Real a,Real v) const
00907 {
00908 Real t1 = (v-dx0)/a;
00909 Real t2mT = (dx1-v)/a;
00910 Real y1 = 0.5*(Sqr(v) - Sqr(dx0))/a + x0;
00911 Real y2 = 0.5*(Sqr(dx1) - Sqr(v))/a + x1;
00912 Real t2mt1 = (y2-y1)/v;
00913
00914 if(t1 < 0 || t2mT > 0 || t2mt1 < 0) return -1;
00915 if(!IsFinite(t1) || !IsFinite(t2mT)) return -1;
00916 return t1 + t2mt1 - t2mT;
00917 }
00918
00919 Real PLPRamp::CalcSwitchTime1(Real a,Real v) const
00920 {
00921 Real t1 = (v-dx0)/a;
00922 if(t1 < 0) return -1;
00923 return t1;
00924 }
00925
00926 Real PLPRamp::CalcSwitchTime2(Real a,Real v) const
00927 {
00928 Real t1 = (v-dx0)/a;
00929 Real y1 = 0.5*(Sqr(v) - Sqr(dx0))/a + x0;
00930 Real y2 = 0.5*(Sqr(dx1) - Sqr(v))/a + x1;
00931 Real t2mt1 = (y2-y1)/v;
00932
00933
00934 if(t1 < 0 || t2mt1 < 0) return -1;
00935 return t1 + t2mt1;
00936 }
00937
00938 Real PLPRamp::CalcMinAccel(Real endTime,Real v) const
00939 {
00940 Real den=endTime*v - (x1-x0);
00941
00942 if(FuzzyZero(den,EpsilonX)) {
00943 if(FuzzyEquals(dx0,v,EpsilonV) && FuzzyEquals(dx1,v,EpsilonV)) return 0;
00944 return Inf;
00945 }
00946
00947
00948 Real a = (Sqr(v) - v*(dx0+dx1) + 0.5*(Sqr(dx0)+Sqr(dx1)))/den;
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962 if(!(CalcTotalTime(a,v) >= 0)) { return Inf; }
00963 return a;
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990 }
00991
00992
00993 bool PLPRamp::SolveMinTime(Real amax,Real vmax)
00994 {
00995 return SolveMinTime2(amax,vmax,0);
00996 }
00997
00998 bool PLPRamp::SolveMinTime2(Real amax,Real vmax,Real timeLowerBound)
00999 {
01000 Real t1 = CalcTotalTime(amax,vmax);
01001 Real t2 = CalcTotalTime(-amax,vmax);
01002 Real t3 = CalcTotalTime(amax,-vmax);
01003 Real t4 = CalcTotalTime(-amax,-vmax);
01004
01005 ttotal = Inf;
01006 if(t1 >= timeLowerBound && t1 < ttotal) {
01007 a = amax;
01008 v = vmax;
01009 ttotal = t1;
01010 }
01011 if(t2 >= timeLowerBound && t2 < ttotal) {
01012 a = -amax;
01013 v = vmax;
01014 ttotal = t2;
01015 }
01016 if(t3 >= timeLowerBound && t3 < ttotal) {
01017 a = amax;
01018 v = -vmax;
01019 ttotal = t3;
01020 }
01021 if(t4 >= timeLowerBound && t4 < ttotal) {
01022 a = -amax;
01023 v = -vmax;
01024 ttotal = t4;
01025 }
01026 if(IsInf(ttotal)) {
01027 a = v = 0;
01028 tswitch1 = tswitch2 = ttotal = -1;
01029
01030
01031
01032 Real v1 = CalcMinTime2(timeLowerBound,amax,vmax);
01033 Real v2 = CalcMinTime2(timeLowerBound,-amax,vmax);
01034 if(v1 > 0) {
01035 a = amax;
01036 v = v1;
01037 tswitch1 = (v1-dx0)/a;
01038 tswitch2 = timeLowerBound - (v1-dx1)/a;
01039 ttotal = timeLowerBound;
01040
01041
01042
01043
01044 return true;
01045 }
01046 if(v2 > 0) {
01047 a = -amax;
01048 v = v2;
01049 tswitch1 = (v2-dx0)/a;
01050 tswitch2 = timeLowerBound - (v2-dx1)/a;
01051 ttotal = timeLowerBound;
01052
01053
01054
01055
01056 return true;
01057 }
01058 return false;
01059 }
01060 tswitch1 = CalcSwitchTime1(a,v);
01061 tswitch2 = CalcSwitchTime2(a,v);
01062
01063 if(tswitch1 > tswitch2 && FuzzyEquals(tswitch1,tswitch2,EpsilonT)) {
01064 tswitch1 = tswitch2 = 0.5*(tswitch1+tswitch2);
01065 }
01066 if(tswitch2 > ttotal && FuzzyEquals(tswitch2,ttotal,EpsilonT)) {
01067 tswitch2 = ttotal;
01068 }
01069
01070 if(gValidityCheckLevel >= 1) {
01071 Real t2mT = tswitch2-ttotal;
01072 Real xswitch = x0 + 0.5*a*Sqr(tswitch1) + dx0*tswitch1;
01073 Real xswitch2 = xswitch + (tswitch2-tswitch1)*v;
01074 if(!FuzzyEquals(xswitch2,x1 - 0.5*a*Sqr(t2mT) + dx1*t2mT,EpsilonX)) {
01075 if(gVerbose >= 1)
01076 PARABOLIC_RAMP_PERROR("PLPRamp::SolveMinTime2: incorrect switch 2 position: %g vs %g\n",xswitch2,x1 - 0.5*a*Sqr(t2mT) + dx1*t2mT);
01077 if(gVerbose >= 2) {
01078 PARABOLIC_RAMP_PERROR("Ramp %g,%g -> %g,%g\n",x0,dx0,x1,dx1);
01079 PARABOLIC_RAMP_PERROR("Acceleration %g, vel %g, deceleration %g\n",a,v,-a);
01080 PARABOLIC_RAMP_PERROR("Switch times %g %g %g\n",tswitch1,tswitch2,ttotal);
01081 }
01082 if(gErrorSave) SaveRamp("PLP_SolveMinTime_failure.dat",x0,dx0,x1,dx1,amax,vmax,timeLowerBound);
01083 if(gErrorGetchar) getchar();
01084 return false;
01085 }
01086 }
01087 return true;
01088 }
01089
01090
01091 bool PLPRamp::SolveMinAccel(Real endTime,Real vmax)
01092 {
01093 Real a1 = CalcMinAccel(endTime,vmax);
01094 Real a2 = CalcMinAccel(endTime,-vmax);
01095 a = Inf;
01096 if(fabs(a1) < a) {
01097 a = a1;
01098 v = vmax;
01099 }
01100 if(fabs(a2) < a) {
01101 a = a2;
01102 v = -vmax;
01103 }
01104 if(IsInf(a)) {
01105 a = 0;
01106 tswitch1 = tswitch2 = ttotal = -1;
01107 return false;
01108 }
01109 if(fabs(a) == 0) {
01110 tswitch1 = 0;
01111 tswitch2 = endTime;
01112 ttotal = endTime;
01113 }
01114 else {
01115 ttotal = CalcTotalTime(a,v);
01116 tswitch1 = CalcSwitchTime1(a,v);
01117 tswitch2 = CalcSwitchTime2(a,v);
01118
01119 if(tswitch1 > tswitch2 && FuzzyEquals(tswitch1,tswitch2,EpsilonT)) {
01120 tswitch1 = tswitch2 = 0.5*(tswitch1+tswitch2);
01121 }
01122 if(tswitch2 > endTime && FuzzyEquals(tswitch2,endTime,EpsilonT)) {
01123 tswitch2 = endTime;
01124 }
01125 if(ttotal < 0) {
01126 if(gVerbose >= 1) PARABOLIC_RAMP_PERROR("PLPRamp::SolveMinAccel: some numerical error prevented computing total time\n");
01127 if(gVerbose >= 2) {
01128 PARABOLIC_RAMP_PERROR(" Ramp %g,%g -> %g,%g\n",x0,dx0,x1,dx1);
01129 PARABOLIC_RAMP_PERROR(" endTime %g, accel %g, vel %g, switch times %g %g, total time %g\n",endTime,a,v,tswitch1,tswitch2,ttotal);
01130 }
01131 if(gErrorSave) SaveRamp("PLP_SolveMinAccel_failure.dat",x0,dx0,x1,dx1,-1,vmax,endTime);
01132 if(gErrorGetchar) getchar();
01133 return false;
01134 }
01135 }
01136 if(gValidityCheckLevel >= 1) {
01137 if(ttotal > endTime + EpsilonT) {
01138 if(gVerbose >= 1)
01139 PARABOLIC_RAMP_PERROR("PLPRamp::SolveMinAccel: total time greater than endTime!\n");
01140 if(gVerbose >= 2)
01141 PARABOLIC_RAMP_PERROR(" endTime %g, accel %g, vel %g, switch times %g %g, total time %g\n",endTime,a,v,tswitch1,tswitch2,ttotal);
01142 if(gErrorSave) SaveRamp("PLP_SolveMinAccel_failure.dat",x0,dx0,x1,dx1,-1,vmax,endTime);
01143 if(gErrorGetchar) getchar();
01144 return false;
01145 }
01146 if(fabs(ttotal-endTime) >= EpsilonT) {
01147 if(gVerbose >= 1)
01148 PARABOLIC_RAMP_PERROR("PLPRamp::SolveMinAccel: total time and endTime are different!\n");
01149 if(gVerbose >= 2)
01150 PARABOLIC_RAMP_PERROR(" endTime %g, accel %g, vel %g, switch times %g %g, total time %g\n",endTime,a,v,tswitch1,tswitch2,ttotal);
01151 if(gErrorSave) SaveRamp("PLP_SolveMinAccel_failure.dat",x0,dx0,x1,dx1,-1,vmax,endTime);
01152 if(gErrorGetchar) getchar();
01153 }
01154 }
01155 PARABOLIC_RAMP_ASSERT(fabs(ttotal-endTime) < EpsilonT);
01156
01157 ttotal = endTime;
01158 if(tswitch2 > ttotal) tswitch2=ttotal;
01159 if(tswitch1 > ttotal) tswitch1=ttotal;
01160
01161 if(gValidityCheckLevel >= 1) {
01162 Real t2mT = tswitch2-ttotal;
01163 Real xswitch = x0 + 0.5*a*Sqr(tswitch1) + dx0*tswitch1;
01164 Real xswitch2 = xswitch + (tswitch2-tswitch1)*v;
01165 if(!FuzzyEquals(xswitch2,x1 - 0.5*a*Sqr(t2mT) + dx1*t2mT,EpsilonX)) {
01166 if(gVerbose >= 1) PARABOLIC_RAMP_PERROR("PLP Ramp has incorrect switch 2 position: %g vs %g\n",xswitch2,x1 - 0.5*a*Sqr(t2mT) + dx1*t2mT);
01167 if(gVerbose >= 2) {
01168 PARABOLIC_RAMP_PERROR("Ramp %g,%g -> %g,%g\n",x0,dx0,x1,dx1);
01169 PARABOLIC_RAMP_PERROR("Acceleration %g, vel %g, deceleration %g\n",a,v,-a);
01170 PARABOLIC_RAMP_PERROR("Switch times %g %g %g\n",tswitch1,tswitch2,ttotal);
01171 }
01172 if(gErrorSave) SaveRamp("PLP_SolveMinAccel_failure.dat",x0,dx0,x1,dx1,-1,vmax,endTime);
01173 if(gErrorGetchar) getchar();
01174 return false;
01175 }
01176 }
01177 return true;
01178 }
01179
01180 Real PLPRamp::CalcMinTime2(Real endTime,Real a,Real vmax) const
01181 {
01182
01183 Real b = -a*endTime - (dx1+dx0);
01184 Real c = a*(x1-x0) + (Sqr(dx0)+Sqr(dx1))*0.5;
01185 Real v1,v2;
01186
01187 int res=quadratic(1.0,b,c,v1,v2);
01188
01189 if(res >= 1) {
01190 Real ts1 = (v1-dx0)/a;
01191 Real ts2 = endTime - (v1-dx1)/a;
01192
01193 if(Abs(v1) <= vmax && ts1 >= 0 && ts2 >= ts1 && ts2 <= endTime) return v1;
01194 }
01195 if(res == 2) {
01196 Real ts1 = (v2-dx0)/a;
01197 Real ts2 = endTime - (v2-dx1)/a;
01198
01199 if(Abs(v2) <= vmax && ts1 >= 0 && ts2 >= ts1 && ts2 <= endTime) return v2;
01200 }
01201 return -1;
01202 }
01203
01204
01205
01206
01207
01208
01209 void ParabolicRamp1D::SetConstant(Real x,Real t)
01210 {
01211 x0 = x1 = x;
01212 dx0 = dx1 = 0;
01213 tswitch1=tswitch2=ttotal=t;
01214 v = a1 = a2 = 0;
01215 }
01216
01217 void ParabolicRamp1D::SetLinear(Real _x0,Real _x1,Real t)
01218 {
01219 PARABOLIC_RAMP_ASSERT(t > 0);
01220 x0 = _x0;
01221 x1 = _x1;
01222 v = dx0 = dx1 = (_x1-_x0)/t;
01223 a1 = a2 = 0;
01224 tswitch1 = 0;
01225 tswitch2 = t;
01226 ttotal = t;
01227 }
01228
01229 Real ParabolicRamp1D::Evaluate(Real t) const
01230 {
01231 Real tmT = t - ttotal;
01232 if(t < tswitch1) return x0 + 0.5*a1*t*t + dx0*t;
01233 else if(t < tswitch2) {
01234 Real xswitch = x0 + 0.5*a1*tswitch1*tswitch1 + dx0*tswitch1;
01235 return xswitch + (t-tswitch1)*v;
01236 }
01237 else return x1 + 0.5*a2*tmT*tmT + dx1*tmT;
01238 }
01239
01240 Real ParabolicRamp1D::Derivative(Real t) const
01241 {
01242 if(t < tswitch1) return a1*t + dx0;
01243 else if(t < tswitch2) return v;
01244 else {
01245 Real tmT = t - ttotal;
01246 return a2*tmT + dx1;
01247 }
01248 }
01249
01250 Real ParabolicRamp1D::Accel(Real t) const
01251 {
01252 if(t < tswitch1) return a1;
01253 else if(t < tswitch2) return 0;
01254 else return a2;
01255 }
01256
01257 bool ParabolicRamp1D::SolveMinAccel(Real endTime,Real vmax)
01258 {
01259 ParabolicRamp p;
01260 PPRamp pp;
01261 PLPRamp plp;
01262 p.x0 = pp.x0 = plp.x0 = x0;
01263 p.x1 = pp.x1 = plp.x1 = x1;
01264 p.dx0 = pp.dx0 = plp.dx0 = dx0;
01265 p.dx1 = pp.dx1 = plp.dx1 = dx1;
01266 bool pres = p.SolveFixedTime(endTime);
01267 bool ppres = pp.SolveMinAccel(endTime);
01268 bool plpres = false;
01269 if(!IsInf(vmax))
01270 plpres = plp.SolveMinAccel(endTime,vmax);
01271
01272
01273 a1 = Inf;
01274 if(pres && FuzzyEquals(endTime,p.ttotal,EpsilonT) && Abs(p.MaxVelocity()) <= vmax) {
01275 if(FuzzyEquals(p.Evaluate(endTime),x1,EpsilonX) && FuzzyEquals(p.Derivative(endTime),dx1,EpsilonV)) {
01276 a1 = p.a;
01277 v = 0;
01278
01279
01280 tswitch1 = tswitch2 = endTime;
01281 ttotal = endTime;
01282 }
01283 }
01284 if(ppres && Abs(pp.MaxVelocity()) <= vmax && Abs(pp.a) < Abs(a1)) {
01285 a1 = pp.a;
01286 v = 0;
01287 tswitch1 = tswitch2 = pp.tswitch;
01288 ttotal = pp.ttotal;
01289 }
01290 if(plpres && Abs(plp.v) <= vmax && Abs(plp.a) < Abs(a1)) {
01291 a1 = plp.a;
01292 v = plp.v;
01293 tswitch1 = plp.tswitch1;
01294 tswitch2 = plp.tswitch2;
01295 ttotal = plp.ttotal;
01296 }
01297 a2 = -a1;
01298
01299 if(IsInf(a1)) {
01300 if(vmax == 0) {
01301 if(FuzzyEquals(x0,x1,EpsilonX) && FuzzyEquals(dx0,dx1,EpsilonV)) {
01302 a1 = a2 = v = 0;
01303 tswitch1 = tswitch2 = ttotal = endTime;
01304 return true;
01305 }
01306 }
01307 if(ppres && Abs(pp.MaxVelocity()) <= vmax + EpsilonV) {
01308
01309 a1 = pp.a;
01310 a2 = -pp.a;
01311 v = 0;
01312 tswitch1 = tswitch2 = pp.tswitch;
01313 ttotal = pp.ttotal;
01314 if(IsValid()) return true;
01315 }
01316 a1 = a2 = v = 0;
01317 tswitch1 = tswitch2 = ttotal = -1;
01318 if(!gMinAccelQuiet) {
01319 if(gVerbose >= 1)
01320 PARABOLIC_RAMP_PERROR("ParabolicRamp1D::SolveMinAccel: No ramp equation was successful.\n");
01321 if(gVerbose >= 2) {
01322 PARABOLIC_RAMP_PERROR("x0=%g, x1=%g, dx0=%g, dx1=%g\n",x0,x1,dx0,dx1);
01323 PARABOLIC_RAMP_PERROR("end time %g, vmax = %g\n",endTime,vmax);
01324
01325 PARABOLIC_RAMP_PERROR("P=%d, PP=%d, PLP=%d\n",(int)pres,(int)ppres,(int)plpres);
01326 PARABOLIC_RAMP_PERROR("p.a = %g, max vel=%g, end x=%g, end dx=%g\n",p.a,p.MaxVelocity(),p.Evaluate(endTime),p.Derivative(endTime));
01327 PARABOLIC_RAMP_PERROR("pp.a = %g, max vel=%g\n",pp.a,pp.MaxVelocity());
01328 PARABOLIC_RAMP_PERROR("plp.a = %g, v=%g\n",plp.a,plp.v);
01329
01330 Real switch1,switch2;
01331 Real apn = pp.CalcMinAccel(endTime,1.0,switch1);
01332 Real anp = pp.CalcMinAccel(endTime,-1.0,switch2);
01333 PARABOLIC_RAMP_PERROR("PP Calcuations: +: %g %g, -: %g %g\n",apn,switch1,anp,switch2);
01334 }
01335 if(gErrorSave) SaveRamp("Ramp_SolveMinAccel_failure.dat",x0,dx0,x1,dx1,-1,vmax,endTime);
01336 if(gErrorGetchar) getchar();
01337 }
01338 return false;
01339 }
01340 if(gValidityCheckLevel >= 2) {
01341 PARABOLIC_RAMP_ASSERT(ttotal==endTime);
01342 if(!IsValid()) {
01343 if(gVerbose >= 1) {
01344 PARABOLIC_RAMP_PERROR("Invalid min-accel!\n");
01345 PARABOLIC_RAMP_PERROR("x0=%g, x1=%g, dx0=%g, dx1=%g\n",x0,x1,dx0,dx1);
01346 PARABOLIC_RAMP_PERROR("end time %g, vmax = %g\n",endTime,vmax);
01347
01348 PARABOLIC_RAMP_PERROR("P=%d, PP=%d, PLP=%d\n",(int)pres,(int)ppres,(int)plpres);
01349 PARABOLIC_RAMP_PERROR("p.a = %g, max vel=%g\n",p.a,p.MaxVelocity());
01350 PARABOLIC_RAMP_PERROR("pp.a = %g, max vel=%g\n",pp.a,pp.MaxVelocity());
01351 PARABOLIC_RAMP_PERROR("plp.a = %g, v=%g\n",plp.a,plp.v);
01352 }
01353 if(gErrorGetchar) getchar();
01354 return false;
01355 }
01356 }
01357 return true;
01358 }
01359
01360 bool ParabolicRamp1D::SolveMinTime(Real amax,Real vmax)
01361 {
01362 ParabolicRamp p;
01363 PPRamp pp;
01364 PLPRamp plp;
01365 p.x0 = pp.x0 = plp.x0 = x0;
01366 p.x1 = pp.x1 = plp.x1 = x1;
01367 p.dx0 = pp.dx0 = plp.dx0 = dx0;
01368 p.dx1 = pp.dx1 = plp.dx1 = dx1;
01369 bool pres = p.Solve(amax);
01370 bool ppres = pp.SolveMinTime(amax);
01371 bool plpres = false;
01372 if(!IsInf(vmax))
01373 plpres = plp.SolveMinTime(amax,vmax);
01374
01375
01376
01377 ttotal = Inf;
01378 if(pres && Abs(p.a) <= amax+EpsilonA && p.ttotal < ttotal) {
01379 if(Abs(p.a) <= amax) {
01380 a1 = p.a;
01381 v = 0;
01382 tswitch1 = tswitch2 = p.ttotal;
01383 ttotal = p.ttotal;
01384 }
01385 else {
01386
01387 p.a = Sign(p.a)*amax;
01388 if(FuzzyEquals(p.Evaluate(p.ttotal),x1,EpsilonX) && FuzzyEquals(p.Derivative(p.ttotal),dx1,EpsilonV)) {
01389 a1 = p.a;
01390 v = 0;
01391 tswitch1=tswitch2=p.ttotal;
01392 ttotal = p.ttotal;
01393 }
01394 }
01395 }
01396 if(ppres && Abs(pp.MaxVelocity()) <= vmax && pp.ttotal < ttotal) {
01397 a1 = pp.a;
01398 v = 0;
01399 tswitch1 = tswitch2 = pp.tswitch;
01400 ttotal = pp.ttotal;
01401 }
01402 if(plpres && plp.ttotal < ttotal) {
01403 a1 = plp.a;
01404 v = plp.v;
01405 tswitch1 = plp.tswitch1;
01406 tswitch2 = plp.tswitch2;
01407 ttotal = plp.ttotal;
01408 }
01409 if(IsInf(ttotal)) {
01410 if(gVerbose >= 1)
01411 PARABOLIC_RAMP_PERROR("ParabolicRamp1D::SolveMinTime: No solution found!\n");
01412 if(gVerbose >= 2) {
01413 PARABOLIC_RAMP_PERROR("x0=%g, x1=%g, dx0=%g, dx1=%g\n",x0,x1,dx0,dx1);
01414 PARABOLIC_RAMP_PERROR("vmax = %g, amax = %g\n",vmax,amax);
01415 PARABOLIC_RAMP_PERROR("P=%d, PP=%d, PLP=%d\n",(int)pres,(int)ppres,(int)plpres);
01416 if(pres)
01417 PARABOLIC_RAMP_PERROR(" P a=%g, ttotal=%g\n",p.a,p.ttotal);
01418 if(ppres)
01419 PARABOLIC_RAMP_PERROR(" PP a=%g, tswitch=%g, ttotal=%g\n",pp.a,pp.tswitch,pp.ttotal);
01420 if(plpres)
01421 PARABOLIC_RAMP_PERROR(" PLP a=%g, tswitch=%g, %g, ttotal=%g\n",pp.a,plp.tswitch1,plp.tswitch2,plp.ttotal);
01422 PARABOLIC_RAMP_PERROR("\n");
01423 }
01424 if(gErrorSave) SaveRamp("Ramp_SolveMinTime_failure.dat",x0,dx0,x1,dx1,amax,vmax,-1);
01425 a1 = a2 = v = 0;
01426 tswitch1 = tswitch2 = ttotal = -1;
01427 return false;
01428 }
01429 a2 = -a1;
01430
01431 if(gValidityCheckLevel >= 2) {
01432 if(!IsValid()) {
01433 if(gVerbose >= 1) {
01434 PARABOLIC_RAMP_PERROR("Solved for invalid min-time path!\n");
01435 PARABOLIC_RAMP_PERROR("x0=%g, x1=%g, dx0=%g, dx1=%g\n",x0,x1,dx0,dx1);
01436 PARABOLIC_RAMP_PERROR("vmax = %g, amax = %g\n",vmax,amax);
01437 PARABOLIC_RAMP_PERROR("P=%d, PP=%d, PLP=%d\n",(int)pres,(int)ppres,(int)plpres);
01438 }
01439 if(gErrorGetchar) getchar();
01440 return false;
01441 }
01442 }
01443 return true;
01444 }
01445
01446 bool ParabolicRamp1D::SolveMinTime2(Real amax,Real vmax,Real tLowerBound)
01447 {
01448 ParabolicRamp p;
01449 PPRamp pp;
01450 PLPRamp plp;
01451 p.x0 = pp.x0 = plp.x0 = x0;
01452 p.x1 = pp.x1 = plp.x1 = x1;
01453 p.dx0 = pp.dx0 = plp.dx0 = dx0;
01454 p.dx1 = pp.dx1 = plp.dx1 = dx1;
01455 bool pres = p.Solve(amax);
01456 bool ppres = pp.SolveMinTime2(amax,tLowerBound);
01457 bool plpres = false;
01458 if(!IsInf(vmax))
01459 plpres = plp.SolveMinTime2(amax,vmax,tLowerBound);
01460
01461
01462
01463 ttotal = Inf;
01464 if(pres && Abs(p.a) <= amax+EpsilonA && p.ttotal < ttotal && p.ttotal >= tLowerBound) {
01465 if(Abs(p.a) <= amax) {
01466 a1 = p.a;
01467 v = 0;
01468 tswitch1 = tswitch2 = p.ttotal;
01469 ttotal = p.ttotal;
01470 }
01471 else {
01472
01473 p.a = Sign(p.a)*amax;
01474 if(FuzzyEquals(p.Evaluate(p.ttotal),x1,EpsilonX) && FuzzyEquals(p.Derivative(p.ttotal),dx1,EpsilonV)) {
01475 a1 = p.a;
01476 v = 0;
01477 tswitch1=tswitch2=p.ttotal;
01478 ttotal = p.ttotal;
01479 }
01480 }
01481 }
01482 if(ppres && Abs(pp.MaxVelocity()) <= vmax && pp.ttotal < ttotal) {
01483 a1 = pp.a;
01484 v = 0;
01485 tswitch1 = tswitch2 = pp.tswitch;
01486 ttotal = pp.ttotal;
01487 }
01488 if(plpres && plp.ttotal < ttotal) {
01489 a1 = plp.a;
01490 v = plp.v;
01491 tswitch1 = plp.tswitch1;
01492 tswitch2 = plp.tswitch2;
01493 ttotal = plp.ttotal;
01494 }
01495 if(IsInf(ttotal)) {
01496 if(!gMinTime2Quiet) {
01497 if(gVerbose >= 1)
01498 PARABOLIC_RAMP_PERROR("ParabolicRamp1D::SolveMinTime2: No solution found!\n");
01499 if(gVerbose >= 2) {
01500 PARABOLIC_RAMP_PERROR("x0=%g, x1=%g, dx0=%g, dx1=%g\n",x0,x1,dx0,dx1);
01501 PARABOLIC_RAMP_PERROR("vmax = %g, amax = %g, tmax = %g\n",vmax,amax,tLowerBound);
01502 PARABOLIC_RAMP_PERROR("P=%d, PP=%d, PLP=%d\n",(int)pres,(int)ppres,(int)plpres);
01503 if(pres)
01504 PARABOLIC_RAMP_PERROR(" P a=%g, ttotal=%g\n",p.a,p.ttotal);
01505 if(ppres)
01506 PARABOLIC_RAMP_PERROR(" PP a=%g, tswitch=%g, ttotal=%g\n",pp.a,pp.tswitch,pp.ttotal);
01507 if(plpres)
01508 PARABOLIC_RAMP_PERROR(" PLP a=%g, tswitch=%g, %g, ttotal=%g\n",pp.a,plp.tswitch1,plp.tswitch2,plp.ttotal);
01509 ppres = pp.SolveMinTime(amax);
01510 plpres = plp.SolveMinTime(amax,vmax);
01511 PARABOLIC_RAMP_PERROR("unconstrained PP (%d): %g, PLP (%d): %g\n",(int)ppres,pp.ttotal,(int)plpres,plp.ttotal);
01512 PARABOLIC_RAMP_PERROR("\n");
01513 }
01514 if(gErrorSave) SaveRamp("Ramp_SolveMinTime_failure.dat",x0,dx0,x1,dx1,amax,vmax,tLowerBound);
01515 }
01516 a1 = a2 = v = 0;
01517 tswitch1 = tswitch2 = ttotal = -1;
01518 return false;
01519 }
01520 a2 = -a1;
01521
01522 if(gValidityCheckLevel >= 2) {
01523 if(!IsValid()) {
01524 if(gVerbose >= 1) {
01525 PARABOLIC_RAMP_PERROR("ParabolicRamp1D::SolveMinTime: Failure to find valid path!\n");
01526 PARABOLIC_RAMP_PERROR("x0=%g, x1=%g, dx0=%g, dx1=%g\n",x0,x1,dx0,dx1);
01527 PARABOLIC_RAMP_PERROR("vmax = %g, amax = %g\n",vmax,amax);
01528 PARABOLIC_RAMP_PERROR("P=%d, PP=%d, PLP=%d\n",(int)pres,(int)ppres,(int)plpres);
01529 if(gErrorSave) SaveRamp("Ramp_SolveMinTime_failure.dat",x0,dx0,x1,dx1,amax,vmax,tLowerBound);
01530 PARABOLIC_RAMP_PERROR("\n");
01531 if(gErrorGetchar) getchar();
01532 }
01533 return false;
01534 }
01535 PARABOLIC_RAMP_ASSERT(ttotal >= tLowerBound);
01536 }
01537 return true;
01538 }
01539
01540 void ParabolicRamp1D::SolveBraking(Real amax)
01541 {
01542 tswitch1 = 0;
01543 tswitch2 = 0;
01544 a1 = Sign(dx0)*amax;
01545 v = 0;
01546 a2 = -Sign(dx0)*amax;
01547 ttotal = Abs(dx0)/amax;
01548 x1 = x0 + dx0*ttotal + 0.5*Sqr(ttotal)*a2;
01549 dx1 = 0;
01550 if(gValidityCheckLevel >= 2)
01551 PARABOLIC_RAMP_ASSERT(IsValid());
01552 }
01553
01554 void ParabolicRamp1D::Dilate(Real timeScale)
01555 {
01556 tswitch1*=timeScale;
01557 tswitch2*=timeScale;
01558 ttotal*=timeScale;
01559 a1 *= 1.0/Sqr(timeScale);
01560 a2 *= 1.0/Sqr(timeScale);
01561 v *= 1.0/timeScale;
01562 }
01563
01564 void ParabolicRamp1D::TrimFront(Real tcut)
01565 {
01566 if(tcut > ttotal) {
01567 PARABOLIC_RAMP_PERROR("Hmm... want to trim front of curve at time %g, end time %g\n",tcut,ttotal);
01568 }
01569 PARABOLIC_RAMP_ASSERT(tcut <= ttotal);
01570 x0 = Evaluate(tcut);
01571 dx0 = Derivative(tcut);
01572 ttotal -= tcut;
01573 tswitch1 -= tcut;
01574 tswitch2 -= tcut;
01575 if(tswitch1 < 0) tswitch1=0;
01576 if(tswitch2 < 0) tswitch2=0;
01577 if(gValidityCheckLevel >= 2)
01578 PARABOLIC_RAMP_ASSERT(IsValid());
01579
01580 }
01581
01582 void ParabolicRamp1D::TrimBack(Real tcut)
01583 {
01584 x1 = Evaluate(ttotal-tcut);
01585 dx1 = Derivative(ttotal-tcut);
01586 ttotal -= tcut;
01587 tswitch1 = Min(tswitch1,ttotal);
01588 tswitch2 = Min(tswitch2,ttotal);
01589 if(gValidityCheckLevel >= 2)
01590 PARABOLIC_RAMP_ASSERT(IsValid());
01591 }
01592
01593 void ParabolicRamp1D::Bounds(Real& xmin,Real& xmax) const
01594 {
01595 Bounds(0,ttotal,xmin,xmax);
01596 }
01597
01598 void ParabolicRamp1D::Bounds(Real ta,Real tb,Real& xmin,Real& xmax) const
01599 {
01600 if(ta > tb) {
01601 return Bounds(tb,ta,xmin,xmax);
01602 }
01603 if(ta < 0) ta = 0;
01604 if(tb <= 0) {
01605 xmin = xmax = x0;
01606 return;
01607 }
01608 if(tb > ttotal) tb=ttotal;
01609 if(ta >= ttotal) {
01610 xmin = xmax = x1;
01611 return;
01612 }
01613
01614 xmin = Evaluate(ta);
01615 xmax = Evaluate(tb);
01616
01617 if(xmin > xmax) Swap(xmin,xmax);
01618
01619 Real tflip1=0,tflip2=0;
01620 if(ta < tswitch1) {
01621
01622 tflip1 = -dx0/a1;
01623 if(tflip1 > tswitch1) tflip1 = 0;
01624 }
01625 if(tb > tswitch2) {
01626
01627 tflip2 = ttotal-dx1/a2;
01628 if(tflip2 < tswitch2) tflip2 = 0;
01629 }
01630 if(ta < tflip1 && tb > tflip1) {
01631 Real xflip = Evaluate(tflip1);
01632 if(xflip < xmin) xmin = xflip;
01633 else if(xflip > xmax) xmax = xflip;
01634 }
01635 if(ta < tflip2 && tb > tflip2) {
01636 Real xflip = Evaluate(tflip2);
01637 if(xflip < xmin) xmin = xflip;
01638 else if(xflip > xmax) xmax = xflip;
01639 }
01640 }
01641
01642 void ParabolicRamp1D::DerivBounds(Real& vmin,Real& vmax) const
01643 {
01644 DerivBounds(0,ttotal,vmin,vmax);
01645 }
01646
01647 void ParabolicRamp1D::DerivBounds(Real ta,Real tb,Real& vmin,Real& vmax) const
01648 {
01649 if(ta > tb) {
01650 return DerivBounds(tb,ta,vmin,vmax);
01651 }
01652 if(ta < 0) ta = 0;
01653 if(tb <= 0) {
01654 vmin = vmax = dx0;
01655 return;
01656 }
01657 if(tb > ttotal) tb=ttotal;
01658 if(ta >= ttotal) {
01659 vmin = vmax = dx1;
01660 return;
01661 }
01662
01663 vmin = Derivative(ta);
01664 vmax = Derivative(tb);
01665 if(vmin > vmax) Swap(vmin,vmax);
01666
01667 if(tswitch2 > tswitch1) {
01668 if(ta < tswitch2 && tb > tswitch1) {
01669 vmin = Min(vmin,v);
01670 vmax = Min(vmax,v);
01671 }
01672 }
01673 else if(ta < tswitch1 && tb > tswitch1) {
01674
01675 Real vbend = dx0 + tswitch1*a1;
01676 if(vbend < vmin) vmin = vbend;
01677 else if(vbend > vmax) vmax = vbend;
01678 vbend = dx1 + (tswitch2-ttotal)*a2;
01679 if(vbend < vmin) vmin = vbend;
01680 else if(vbend > vmax) vmax = vbend;
01681 }
01682 }
01683
01684 bool ParabolicRamp1D::IsValid() const
01685 {
01686 if(tswitch1 < 0 || tswitch2 < tswitch1 || ttotal < tswitch2) {
01687 if(gVerbose >= 1)
01688 PARABOLIC_RAMP_PERROR("Ramp has invalid timing %g %g %g\n",tswitch1,tswitch2,ttotal);
01689 return false;
01690 }
01691
01692 Real t2mT = tswitch2 - ttotal;
01693 if(tswitch1 != tswitch2) {
01694 if(!FuzzyEquals(a1*tswitch1 + dx0,v,EpsilonV)) {
01695 if(gVerbose >= 1)
01696 PARABOLIC_RAMP_PERROR("Ramp has incorrect switch 1 speed: %g vs %g\n",a1*tswitch1 + dx0,v);
01697 return false;
01698 }
01699 if(!FuzzyEquals(a2*t2mT + dx1,v,EpsilonV)) {
01700 if(gVerbose >= 1)
01701 PARABOLIC_RAMP_PERROR("Ramp has incorrect switch 2 speed: %g vs %g\n",a2*t2mT + dx1,v);
01702 return false;
01703 }
01704 }
01705
01706 Real xswitch = x0 + 0.5*a1*Sqr(tswitch1) + dx0*tswitch1;
01707 Real xswitch2 = xswitch + (tswitch2-tswitch1)*v;
01708 if(!FuzzyEquals(xswitch2,x1 + 0.5*a2*Sqr(t2mT) + dx1*t2mT,EpsilonX)) {
01709 if(gVerbose >= 1)
01710 PARABOLIC_RAMP_PERROR("Ramp has incorrect switch 2 position: %g vs %g\n",xswitch2,x1 + 0.5*a2*Sqr(t2mT) + dx1*t2mT);
01711 if(gVerbose >= 2) {
01712 PARABOLIC_RAMP_PERROR("Ramp %g,%g -> %g,%g\n",x0,dx0,x1,dx1);
01713 PARABOLIC_RAMP_PERROR("Acceleration %g, vel %g, deceleration %g\n",a1,v,a2);
01714 PARABOLIC_RAMP_PERROR("Switch times %g %g %g\n",tswitch1,tswitch2,ttotal);
01715 }
01716 return false;
01717 }
01718 return true;
01719 }
01720
01721
01722
01723
01724
01725 void ParabolicRampND::SetConstant(const Vector& x,Real t)
01726 {
01727 x0 = x1 = x;
01728 dx0.resize(x.size());
01729 dx1.resize(x.size());
01730 fill(dx0.begin(),dx0.end(),0);
01731 fill(dx1.begin(),dx1.end(),0);
01732 endTime = t;
01733 ramps.resize(x.size());
01734 for(size_t i=0;i<x.size();i++)
01735 ramps[i].SetConstant(x[i],t);
01736 }
01737
01738 void ParabolicRampND::SetLinear(const Vector& _x0,const Vector& _x1,Real t)
01739 {
01740 PARABOLIC_RAMP_ASSERT(_x0.size() == _x1.size());
01741 PARABOLIC_RAMP_ASSERT(t > 0);
01742 x0 = _x0;
01743 x1 = _x1;
01744 dx0.resize(_x1.size());
01745 for(size_t i=0;i<_x1.size();i++)
01746 dx0[i] = (_x1[i]-_x0[i])/t;
01747 dx1 = dx0;
01748 endTime = t;
01749 ramps.resize(_x0.size());
01750 for(size_t i=0;i<_x0.size();i++)
01751 ramps[i].SetLinear(_x0[i],_x1[i],t);
01752 }
01753
01754 bool ParabolicRampND::SolveMinTimeLinear(const Vector& amax,const Vector& vmax)
01755 {
01756 PARABOLIC_RAMP_ASSERT(x0.size() == dx0.size());
01757 PARABOLIC_RAMP_ASSERT(x1.size() == dx1.size());
01758 PARABOLIC_RAMP_ASSERT(x0.size() == x1.size());
01759 PARABOLIC_RAMP_ASSERT(x0.size() == amax.size());
01760 PARABOLIC_RAMP_ASSERT(x0.size() == vmax.size());
01761 endTime = 0;
01762 ramps.resize(x0.size());
01763 ParabolicRamp1D sramp;
01764 sramp.x0 = 0;
01765 sramp.x1 = 1;
01766 sramp.dx0 = 0;
01767 sramp.dx1 = 0;
01768 Real svmax=Inf,samax=Inf;
01769 for(size_t i=0;i<ramps.size();i++) {
01770 ramps[i].x0=x0[i];
01771 ramps[i].x1=x1[i];
01772 ramps[i].dx0=dx0[i];
01773 ramps[i].dx1=dx1[i];
01774 if(vmax[i]==0 || amax[i]==0) {
01775 if(!FuzzyEquals(x0[i],x1[i],EpsilonX)) {
01776 if(gVerbose >= 1)
01777 PARABOLIC_RAMP_PERROR("index %d vmax = %g, amax = %g, X0 != X1 (%g != %g)\n",i,vmax[i],amax[i],x0[i],x1[i]);
01778 return false;
01779 }
01780 if(!FuzzyEquals(dx0[i],dx1[i],EpsilonV)) {
01781 if(gVerbose >= 1)
01782 PARABOLIC_RAMP_PERROR("index %d vmax = %g, amax = %g, DX0 != DX1 (%g != %g)\n",i,vmax[i],amax[i],dx0[i],dx1[i]);
01783 return false;
01784 }
01785 ramps[i].tswitch1=ramps[i].tswitch2=ramps[i].ttotal=0;
01786 ramps[i].a1=ramps[i].a1=ramps[i].v=0;
01787 continue;
01788 }
01789 if(vmax[i] < svmax*Abs(x1[i]-x0[i]))
01790 svmax = vmax[i]/Abs(x1[i]-x0[i]);
01791 if(amax[i] < samax*Abs(x1[i]-x0[i]))
01792 samax = amax[i]/Abs(x1[i]-x0[i]);
01793 }
01794
01795 if(IsInf(svmax) && IsInf(samax)) {
01796
01797 SetConstant(x0);
01798 return true;
01799 }
01800
01801 bool res=sramp.SolveMinTime(samax,svmax);
01802 if(!res) {
01803 if(gVerbose >= 1)
01804 PARABOLIC_RAMP_PERROR("Warning in straight-line parameter solve\n");
01805 if(gErrorGetchar) getchar();
01806 return false;
01807 }
01808
01809 endTime = sramp.ttotal;
01810 for(size_t i=0;i<ramps.size();i++) {
01811 ramps[i].v = svmax * (x1[i]-x0[i]);
01812 ramps[i].a1 = samax * (x1[i]-x0[i]);
01813 ramps[i].a2 = -samax * (x1[i]-x0[i]);
01814 ramps[i].tswitch1 = sramp.tswitch1;
01815 ramps[i].tswitch2 = sramp.tswitch2;
01816 ramps[i].ttotal = endTime;
01817 if(gValidityCheckLevel >= 2) {
01818 if(!ramps[i].IsValid()) {
01819 if(gVerbose >= 1)
01820 PARABOLIC_RAMP_PERROR("Warning, error in straight-line path formula\n");
01821 if(gVerbose >= 2) {
01822 for(size_t j=0;j<dx0.size();j++)
01823 PARABOLIC_RAMP_PERROR("%g ",dx0[j]);
01824 for(size_t j=0;j<dx1.size();j++)
01825 PARABOLIC_RAMP_PERROR("%g ",dx1[j]);
01826 }
01827 if(gErrorGetchar) getchar();
01828 }
01829 }
01830
01831
01832 if(Abs(ramps[i].v) > vmax[i]) {
01833 if(Abs(ramps[i].v) > vmax[i]+EpsilonV) {
01834 if(gVerbose >= 1) {
01835 PARABOLIC_RAMP_PERROR("Warning, numerical error in straight-line formula?\n");
01836 PARABOLIC_RAMP_PERROR("velocity |%g|>%g\n",ramps[i].v,vmax[i]);
01837 }
01838 if(gErrorGetchar) getchar();
01839 }
01840 else ramps[i].v = Sign(ramps[i].v)*vmax[i];
01841 }
01842 if(Abs(ramps[i].a1) > amax[i]) {
01843 if(Abs(ramps[i].a1) > amax[i]+EpsilonA) {
01844 if(gVerbose >= 1) {
01845 PARABOLIC_RAMP_PERROR("Warning, numerical error in straight-line formula?\n");
01846 PARABOLIC_RAMP_PERROR("accel |%g|>%g\n",ramps[i].a1,amax[i]);
01847 }
01848 if(gErrorGetchar) getchar();
01849 }
01850 else ramps[i].a1 = Sign(ramps[i].a1)*amax[i];
01851 }
01852 if(Abs(ramps[i].a2) > amax[i]) {
01853 if(Abs(ramps[i].a2) > amax[i]+EpsilonA) {
01854 if(gVerbose >= 1) {
01855 PARABOLIC_RAMP_PERROR("Warning, numerical error in straight-line formula?\n");
01856 PARABOLIC_RAMP_PERROR("accel |%g|>%g\n",ramps[i].a2,amax[i]);
01857 }
01858 if(gErrorGetchar) getchar();
01859 }
01860 else ramps[i].a2 = Sign(ramps[i].a2)*amax[i];
01861 }
01862 }
01863 return true;
01864 }
01865
01866 bool ParabolicRampND::SolveMinTime(const Vector& amax,const Vector& vmax)
01867 {
01868 PARABOLIC_RAMP_ASSERT(x0.size() == dx0.size());
01869 PARABOLIC_RAMP_ASSERT(x1.size() == dx1.size());
01870 PARABOLIC_RAMP_ASSERT(x0.size() == x1.size());
01871 PARABOLIC_RAMP_ASSERT(x0.size() == amax.size());
01872 PARABOLIC_RAMP_ASSERT(x0.size() == vmax.size());
01873 endTime = 0;
01874 ramps.resize(x0.size());
01875 for(size_t i=0;i<ramps.size();i++) {
01876 ramps[i].x0=x0[i];
01877 ramps[i].x1=x1[i];
01878 ramps[i].dx0=dx0[i];
01879 ramps[i].dx1=dx1[i];
01880 if(vmax[i]==0 || amax[i]==0) {
01881 if(!FuzzyEquals(x0[i],x1[i],EpsilonX)) {
01882 if(gVerbose >= 1)
01883 PARABOLIC_RAMP_PERROR("index %d vmax = %g, amax = %g, X0 != X1 (%g != %g)\n",i,vmax[i],amax[i],x0[i],x1[i]);
01884 return false;
01885 }
01886 if(!FuzzyEquals(dx0[i],dx1[i],EpsilonV)) {
01887 if(gVerbose >= 1)
01888 PARABOLIC_RAMP_PERROR("index %d vmax = %g, amax = %g, DX0 != DX1 (%g != %g)\n",i,vmax[i],amax[i],dx0[i],dx1[i]);
01889 return false;
01890 }
01891 ramps[i].tswitch1=ramps[i].tswitch2=ramps[i].ttotal=0;
01892 ramps[i].a1=ramps[i].a2=ramps[i].v=0;
01893 continue;
01894 }
01895 if(!ramps[i].SolveMinTime(amax[i],vmax[i])) return false;
01896 if(ramps[i].ttotal > endTime) endTime = ramps[i].ttotal;
01897 }
01898
01899
01900 while(true) {
01901 bool solved = true;
01902 for(size_t i=0;i<ramps.size();i++) {
01903 if(ramps[i].ttotal == endTime) continue;
01904 if(vmax[i]==0 || amax[i]==0) {
01905 ramps[i].ttotal = endTime;
01906 continue;
01907 }
01908 if(!ramps[i].SolveMinAccel(endTime,vmax[i])) {
01909 if(gVerbose >= 1)
01910 PARABOLIC_RAMP_PERROR("Failed solving min accel for joint %d\n",i);
01911 if(gVerbose >= 2) {
01912 ramps[i].SolveMinTime(amax[i],vmax[i]);
01913 PARABOLIC_RAMP_PERROR("its min time is %g\n",ramps[i].ttotal);
01914 if(ramps[i].tswitch1==ramps[i].tswitch2)
01915 PARABOLIC_RAMP_PERROR("its type is PP\n");
01916 else if(Abs(ramps[i].v)==vmax[i])
01917 PARABOLIC_RAMP_PERROR("its type is PLP (vmax)\n");
01918 else
01919 PARABOLIC_RAMP_PERROR("its type is PLP (v=%g %%)\n",ramps[i].v/vmax[i]);
01920 }
01921 if(gErrorSave) SaveRamp("ParabolicRampND_SolveMinAccel_failure.dat",ramps[i].x0,ramps[i].dx0,ramps[i].x1,ramps[i].dx1,-1,vmax[i],endTime);
01922 if(gErrorSave) {
01923 PARABOLIC_RAMP_PERROR("Saving to failed_ramps.txt\n");
01924 FILE* f=fopen("failed_ramps.txt","w+");
01925 fprintf(f,"MinAccel T=%g, vmax=%g\n",endTime,vmax[i]);
01926 fprintf(f,"x0=%g, dx0=%g\n",ramps[i].x0,ramps[i].dx0);
01927 fprintf(f,"x1=%g, dx1=%g\n",ramps[i].x1,ramps[i].dx1);
01928 fprintf(f,"MinTime solution v=%g, t1=%g, t2=%g, T=%g\n",ramps[i].v,ramps[i].tswitch1,ramps[i].tswitch2,ramps[i].ttotal);
01929 fprintf(f,"\n");
01930 fclose(f);
01931 }
01932 return false;
01933 }
01934 if(Abs(ramps[i].a1) > amax[i] || Abs(ramps[i].a2) > amax[i] || Abs(ramps[i].v) > vmax[i]) {
01935 bool res=ramps[i].SolveMinTime2(amax[i],vmax[i],endTime);
01936 if(!res) {
01937 if(gVerbose >= 1)
01938 PARABOLIC_RAMP_PERROR("Couldn't solve min-time with lower bound!\n");
01939 if(gErrorGetchar) getchar();
01940 return false;
01941 }
01942 PARABOLIC_RAMP_ASSERT(ramps[i].ttotal > endTime);
01943 endTime = ramps[i].ttotal;
01944 solved = false;
01945 break;
01946 }
01947 PARABOLIC_RAMP_ASSERT(Abs(ramps[i].a1) <= amax[i]+EpsilonA);
01948 PARABOLIC_RAMP_ASSERT(Abs(ramps[i].a2) <= amax[i]+EpsilonA);
01949 PARABOLIC_RAMP_ASSERT(Abs(ramps[i].v) <= vmax[i]+EpsilonV);
01950 PARABOLIC_RAMP_ASSERT(ramps[i].ttotal==endTime);
01951 }
01952
01953 if(solved) break;
01954 }
01955 return true;
01956 }
01957
01958 bool ParabolicRampND::SolveMinAccel(const Vector& vmax,Real time)
01959 {
01960 PARABOLIC_RAMP_ASSERT(x0.size() == dx0.size());
01961 PARABOLIC_RAMP_ASSERT(x1.size() == dx1.size());
01962 PARABOLIC_RAMP_ASSERT(x0.size() == x1.size());
01963 PARABOLIC_RAMP_ASSERT(x0.size() == vmax.size());
01964 endTime = time;
01965 ramps.resize(x0.size());
01966 for(size_t i=0;i<ramps.size();i++) {
01967 ramps[i].x0=x0[i];
01968 ramps[i].x1=x1[i];
01969 ramps[i].dx0=dx0[i];
01970 ramps[i].dx1=dx1[i];
01971 if(vmax[i]==0) {
01972 PARABOLIC_RAMP_ASSERT(FuzzyEquals(x0[i],x1[i],EpsilonX));
01973 PARABOLIC_RAMP_ASSERT(FuzzyEquals(dx0[i],dx1[i],EpsilonV));
01974 ramps[i].tswitch1=ramps[i].tswitch2=ramps[i].ttotal=0;
01975 ramps[i].a1=ramps[i].a2=ramps[i].v=0;
01976 continue;
01977 }
01978 if(!ramps[i].SolveMinAccel(endTime,vmax[i])) {
01979 return false;
01980 }
01981 }
01982 return true;
01983 }
01984
01985 bool ParabolicRampND::SolveMinAccelLinear(const Vector& vmax,Real time)
01986 {
01987 PARABOLIC_RAMP_ASSERT(x0.size() == dx0.size());
01988 PARABOLIC_RAMP_ASSERT(x1.size() == dx1.size());
01989 PARABOLIC_RAMP_ASSERT(x0.size() == x1.size());
01990 PARABOLIC_RAMP_ASSERT(x0.size() == vmax.size());
01991 endTime = 0;
01992 ramps.resize(x0.size());
01993 ParabolicRamp1D sramp;
01994 sramp.x0 = 0;
01995 sramp.x1 = 1;
01996 sramp.dx0 = 0;
01997 sramp.dx1 = 0;
01998 Real svmax=Inf;
01999 for(size_t i=0;i<ramps.size();i++) {
02000 ramps[i].x0=x0[i];
02001 ramps[i].x1=x1[i];
02002 ramps[i].dx0=dx0[i];
02003 ramps[i].dx1=dx1[i];
02004 if(vmax[i]==0) {
02005 if(!FuzzyEquals(x0[i],x1[i],EpsilonX)) {
02006 if(gVerbose >= 1)
02007 PARABOLIC_RAMP_PERROR("index %d vmax = %g, X0 != X1 (%g != %g)\n",i,vmax[i],x0[i],x1[i]);
02008 return false;
02009 }
02010 if(!FuzzyEquals(dx0[i],dx1[i],EpsilonV)) {
02011 if(gVerbose >= 1)
02012 PARABOLIC_RAMP_PERROR("index %d vmax = %g, DX0 != DX1 (%g != %g)\n",i,vmax[i],dx0[i],dx1[i]);
02013 return false;
02014 }
02015 ramps[i].tswitch1=ramps[i].tswitch2=ramps[i].ttotal=0;
02016 ramps[i].a1=ramps[i].a1=ramps[i].v=0;
02017 continue;
02018 }
02019 if(vmax[i] < svmax*Abs(x1[i]-x0[i]))
02020 svmax = vmax[i]/Abs(x1[i]-x0[i]);
02021 }
02022
02023 if(IsInf(svmax)) {
02024
02025 SetConstant(x0);
02026 return true;
02027 }
02028
02029 bool res=sramp.SolveMinAccel(svmax,time);
02030 if(!res) {
02031 if(gVerbose >= 1)
02032 PARABOLIC_RAMP_PERROR("Warning in straight-line parameter solve\n");
02033 if(gErrorGetchar) getchar();
02034 return false;
02035 }
02036
02037 endTime = sramp.ttotal;
02038 for(size_t i=0;i<ramps.size();i++) {
02039 ramps[i].v = sramp.v * (x1[i]-x0[i]);
02040 ramps[i].a1 = sramp.a1 * (x1[i]-x0[i]);
02041 ramps[i].a2 = sramp.a2 * (x1[i]-x0[i]);
02042 ramps[i].tswitch1 = sramp.tswitch1;
02043 ramps[i].tswitch2 = sramp.tswitch2;
02044 ramps[i].ttotal = endTime;
02045 if(gValidityCheckLevel >= 2) {
02046 if(!ramps[i].IsValid()) {
02047 if(gVerbose >= 1)
02048 PARABOLIC_RAMP_PERROR("Warning, error in straight-line path formula\n");
02049 if(gErrorGetchar) getchar();
02050 res=false;
02051 }
02052 }
02053 }
02054 return res;
02055 }
02056
02057 void ParabolicRampND::SolveBraking(const Vector& amax)
02058 {
02059 PARABOLIC_RAMP_ASSERT(x0.size() == dx0.size());
02060 PARABOLIC_RAMP_ASSERT(x0.size() == amax.size());
02061 x1.resize(x0.size());
02062 dx1.resize(x0.size());
02063 endTime = 0;
02064 ramps.resize(x0.size());
02065 for(size_t i=0;i<ramps.size();i++) {
02066 if(amax[i]==0) {
02067 PARABOLIC_RAMP_ASSERT(FuzzyEquals(dx0[i],0.0,EpsilonV));
02068 ramps[i].SetConstant(0);
02069 continue;
02070 }
02071 ramps[i].x0 = x0[i];
02072 ramps[i].dx0 = dx0[i];
02073 ramps[i].SolveBraking(amax[i]);
02074 }
02075 for(size_t i=0;i<ramps.size();i++)
02076 endTime = Max(endTime,ramps[i].ttotal);
02077 for(size_t i=0;i<ramps.size();i++) {
02078 if(amax[i] != 0 && ramps[i].ttotal != endTime) {
02079
02080 ramps[i].ttotal = endTime;
02081
02082
02083 ramps[i].a2 = -dx0[i] / endTime;
02084 ramps[i].a1 = -ramps[i].a2;
02085 ramps[i].x1 = ramps[i].x0 + endTime*ramps[i].dx0 + 0.5*Sqr(endTime)*ramps[i].a2;
02086 }
02087 x1[i]=ramps[i].x1;
02088 dx1[i]=0;
02089 }
02090 if(gValidityCheckLevel >= 2)
02091 PARABOLIC_RAMP_ASSERT(IsValid());
02092 }
02093
02094 void ParabolicRampND::Evaluate(Real t,Vector& x) const
02095 {
02096 x.resize(ramps.size());
02097 for(size_t j=0;j<ramps.size();j++)
02098 x[j]=ramps[j].Evaluate(t);
02099 }
02100
02101 void ParabolicRampND::Derivative(Real t,Vector& x) const
02102 {
02103 x.resize(ramps.size());
02104 for(size_t j=0;j<ramps.size();j++)
02105 x[j]=ramps[j].Derivative(t);
02106 }
02107
02108 void ParabolicRampND::Accel(Real t,Vector& x) const
02109 {
02110 x.resize(ramps.size());
02111 for(size_t j=0;j<ramps.size();j++)
02112 x[j]=ramps[j].Accel(t);
02113 }
02114
02115 void ParabolicRampND::Output(Real dt,std::vector<Vector>& path) const
02116 {
02117 PARABOLIC_RAMP_ASSERT(!ramps.empty());
02118 int size = (int)ceil(endTime/dt)+1;
02119 path.resize(size);
02120 if(size == 1) {
02121 path[0].resize(ramps.size());
02122 for(size_t j=0;j<ramps.size();j++)
02123 path[0][j] = ramps[j].x0;
02124 return;
02125 }
02126 for(int i=0;i<size;i++) {
02127 Real t=endTime*Real(i)/Real(size-1);
02128 path[i].resize(ramps.size());
02129 for(size_t j=0;j<ramps.size();j++)
02130 path[i][j]=ramps[j].Evaluate(t);
02131 }
02132
02133
02134
02135
02136
02137
02138
02139
02140
02141
02142
02143
02144
02145
02146
02147 }
02148
02149
02150 void ParabolicRampND::Dilate(Real timeScale)
02151 {
02152 for(size_t i=0;i<ramps.size();i++)
02153 ramps[i].Dilate(timeScale);
02154 }
02155
02156 void ParabolicRampND::TrimFront(Real tcut)
02157 {
02158 PARABOLIC_RAMP_ASSERT(tcut <= endTime);
02159 Evaluate(tcut,x0);
02160 Derivative(tcut,dx0);
02161 endTime -= tcut;
02162 for(size_t i=0;i<ramps.size();i++)
02163 ramps[i].TrimFront(tcut);
02164 if(gValidityCheckLevel >= 2)
02165 PARABOLIC_RAMP_ASSERT(IsValid());
02166 }
02167
02168 void ParabolicRampND::TrimBack(Real tcut)
02169 {
02170 for(size_t i=0;i<ramps.size();i++)
02171 PARABOLIC_RAMP_ASSERT(endTime == ramps[i].ttotal);
02172 PARABOLIC_RAMP_ASSERT(tcut <= endTime);
02173 Evaluate(endTime-tcut,x1);
02174 Derivative(endTime-tcut,dx1);
02175 endTime -= tcut;
02176 for(size_t i=0;i<ramps.size();i++)
02177 ramps[i].TrimBack(tcut);
02178 if(gValidityCheckLevel >= 2)
02179 PARABOLIC_RAMP_ASSERT(IsValid());
02180 }
02181
02182 void ParabolicRampND::Bounds(Vector& xmin,Vector& xmax) const
02183 {
02184 xmin.resize(ramps.size());
02185 xmax.resize(ramps.size());
02186 for(size_t i=0;i<ramps.size();i++) {
02187 ramps[i].Bounds(xmin[i],xmax[i]);
02188 }
02189 }
02190
02191 void ParabolicRampND::Bounds(Real ta,Real tb,Vector& xmin,Vector& xmax) const
02192 {
02193 xmin.resize(ramps.size());
02194 xmax.resize(ramps.size());
02195 for(size_t i=0;i<ramps.size();i++) {
02196 ramps[i].Bounds(ta,tb,xmin[i],xmax[i]);
02197 }
02198 }
02199
02200 void ParabolicRampND::DerivBounds(Vector& vmin,Vector& vmax) const
02201 {
02202 vmin.resize(ramps.size());
02203 vmax.resize(ramps.size());
02204 for(size_t i=0;i<ramps.size();i++) {
02205 ramps[i].DerivBounds(vmin[i],vmax[i]);
02206 }
02207 }
02208
02209 void ParabolicRampND::DerivBounds(Real ta,Real tb,Vector& vmin,Vector& vmax) const
02210 {
02211 vmin.resize(ramps.size());
02212 vmax.resize(ramps.size());
02213 for(size_t i=0;i<ramps.size();i++) {
02214 ramps[i].DerivBounds(ta,tb,vmin[i],vmax[i]);
02215 }
02216 }
02217
02218 bool ParabolicRampND::IsValid() const
02219 {
02220 if(endTime < 0) {
02221 if(gVerbose >= 1) PARABOLIC_RAMP_PERROR("ParabolicRampND::IsValid(): endTime is negative\n");
02222 return false;
02223 }
02224 for(size_t i=0;i<ramps.size();i++) {
02225 if(!ramps[i].IsValid()) {
02226 if(gVerbose >= 1) PARABOLIC_RAMP_PERROR("ParabolicRampND::IsValid(): element %d is invalid\n",i);
02227 return false;
02228 }
02229 if(!FuzzyEquals(ramps[i].ttotal,endTime,EpsilonT)) {
02230 if(gVerbose >= 1) PARABOLIC_RAMP_PERROR("ParabolicRampND::IsValid(): element %d has different end time %g != %g\n",i,ramps[i].ttotal,endTime);
02231 return false;
02232 }
02233 if(!FuzzyEquals(ramps[i].x0,x0[i],EpsilonX)) {
02234 if(gVerbose >= 1) PARABOLIC_RAMP_PERROR("ParabolicRampND::IsValid(): element %d has different x0 %g != %g\n",i,ramps[i].x0,x0[i]);
02235 return false;
02236 }
02237 if(!FuzzyEquals(ramps[i].x1,x1[i],EpsilonX)) {
02238 if(gVerbose >= 1) PARABOLIC_RAMP_PERROR("ParabolicRampND::IsValid(): element %d has different x1 %g != %g\n",i,ramps[i].x1,x1[i]);
02239 return false;
02240 }
02241 if(!FuzzyEquals(ramps[i].dx0,dx0[i],EpsilonV)) {
02242 if(gVerbose >= 1) PARABOLIC_RAMP_PERROR("ParabolicRampND::IsValid(): element %d has different dx0 %g != %g\n",i,ramps[i].dx0,dx0[i]);
02243 return false;
02244 }
02245 if(!FuzzyEquals(ramps[i].dx1,dx1[i],EpsilonV)) {
02246 if(gVerbose >= 1) PARABOLIC_RAMP_PERROR("ParabolicRampND::IsValid(): element %d has different dx1 %g != %g\n",i,ramps[i].dx1,dx1[i]);
02247 return false;
02248 }
02249 }
02250 return true;
02251 }
02252
02253 bool SolveMinTimeBounded(Real x0,Real v0,Real x1,Real v1,Real amax,Real vmax,Real xmin,Real xmax,ParabolicRamp1D& ramp)
02254 {
02255 PARABOLIC_RAMP_ASSERT(x0 >= xmin && x0 <= xmax && x1 >= xmin && x1 <= xmax);
02256 ramp.x0 = x0;
02257 ramp.dx0 = v0;
02258 ramp.x1 = x1;
02259 ramp.dx1 = v1;
02260 if(!ramp.SolveMinTime(amax,vmax)) return false;
02261 Real bmin,bmax;
02262 ramp.Bounds(bmin,bmax);
02263 if(bmin < xmin || bmax > xmax) return false;
02264 return true;
02265 }
02266
02267 inline Real BrakeTime(Real x,Real v,Real xbound)
02268 {
02269 return 2.0*(xbound-x)/v;
02270 }
02271
02272 inline Real BrakeAccel(Real x,Real v,Real xbound)
02273 {
02274 Real tb=BrakeTime(x,v,xbound);
02275 if(FuzzyEquals(tb,0.0,EpsilonT)) return 0;
02276 return -v/tb;
02277 }
02278
02279 bool SolveMinAccelBounded(Real x0,Real v0,Real x1,Real v1,Real endTime,Real vmax,Real xmin,Real xmax,std::vector<ParabolicRamp1D>& ramps)
02280 {
02281 PARABOLIC_RAMP_ASSERT(x0 >= xmin && x0 <= xmax && x1 >= xmin && x1 <= xmax);
02282 ParabolicRamp1D ramp;
02283 ramp.x0 = x0;
02284 ramp.dx0 = v0;
02285 ramp.x1 = x1;
02286 ramp.dx1 = v1;
02287 if(!ramp.SolveMinAccel(endTime,vmax)) return false;
02288 Real bmin,bmax;
02289 ramp.Bounds(bmin,bmax);
02290 if(bmin >= xmin && bmax <= xmax) {
02291 ramps.resize(1);
02292 ramps[0] = ramp;
02293 return true;
02294 }
02295
02296
02297 ramps.resize(0);
02298 vector<ParabolicRamp1D> temp;
02299
02300 Real bt0=Inf,bt1=Inf;
02301 Real ba0=Inf,ba1=Inf;
02302 Real bx0=Inf,bx1=Inf;
02303 if(v0 > 0) {
02304 bt0 = BrakeTime(x0,v0,xmax);
02305 bx0 = xmax;
02306 ba0 = BrakeAccel(x0,v0,xmax);
02307 }
02308 else if(v0 < 0) {
02309 bt0 = BrakeTime(x0,v0,xmin);
02310 bx0 = xmin;
02311 ba0 = BrakeAccel(x0,v0,xmin);
02312 }
02313 if(v1 < 0) {
02314 bt1 = BrakeTime(x1,-v1,xmax);
02315 bx1 = xmax;
02316 ba1 = BrakeAccel(x1,-v1,xmax);
02317 }
02318 else if(v1 > 0) {
02319 bt1 = BrakeTime(x1,-v1,xmin);
02320 bx1 = xmin;
02321 ba1 = BrakeAccel(x1,-v1,xmin);
02322 }
02323 Real amax=Inf;
02324
02325
02326
02327
02328
02329
02330
02331 if(bt0 < endTime && Abs(ba0) < amax) {
02332
02333 temp.resize(2);
02334 temp[0].x0 = x0;
02335 temp[0].dx0 = v0;
02336 temp[0].x1 = bx0;
02337 temp[0].dx1 = 0;
02338 temp[0].a1 = ba0;
02339 temp[0].v = 0;
02340 temp[0].a2 = 0;
02341 temp[0].tswitch1 = bt0;
02342 temp[0].tswitch2 = bt0;
02343 temp[0].ttotal = bt0;
02344 temp[1].x0 = bx0;
02345 temp[1].dx0 = 0;
02346 temp[1].x1 = x1;
02347 temp[1].dx1 = v1;
02348 gMinAccelQuiet = true;
02349
02350 if(Abs(x1-bx0) < (endTime-bt0)*vmax) {
02351 if(temp[1].SolveMinAccel(endTime-bt0,vmax)) {
02352 if(Max(Abs(temp[1].a1),Abs(temp[1].a2)) < amax) {
02353 temp[1].Bounds(bmin,bmax);
02354 if(bmin >= xmin && bmax <= xmax) {
02355
02356 ramps = temp;
02357 amax = Max(Abs(ba0),Max(Abs(temp[1].a1),Abs(temp[1].a2)));
02358 }
02359 }
02360 }
02361 }
02362 gMinAccelQuiet = false;
02363 }
02364
02365
02366 if(bt1 < endTime && Abs(ba1) < amax) {
02367
02368 temp.resize(2);
02369 temp[0].x0 = x0;
02370 temp[0].dx0 = v0;
02371 temp[0].x1 = bx1;
02372 temp[0].dx1 = 0;
02373 temp[1].x0 = bx1;
02374 temp[1].dx0 = 0;
02375 temp[1].x1 = x1;
02376 temp[1].dx1 = v1;
02377 temp[1].a1 = ba1;
02378 temp[1].v = 0;
02379 temp[1].a2 = 0;
02380 temp[1].tswitch1 = bt1;
02381 temp[1].tswitch2 = bt1;
02382 temp[1].ttotal = bt1;
02383 gMinAccelQuiet = true;
02384
02385 if(Abs(x0-bx1) < (endTime-bt1)*vmax) {
02386 if(temp[0].SolveMinAccel(endTime-bt1,vmax)) {
02387 if(Max(Abs(temp[0].a1),Abs(temp[0].a2)) < amax) {
02388 temp[0].Bounds(bmin,bmax);
02389 if(bmin >= xmin && bmax <= xmax) {
02390
02391 ramps = temp;
02392 amax = Max(Abs(ba1),Max(Abs(temp[0].a1),Abs(temp[0].a2)));
02393 }
02394 }
02395 }
02396 }
02397 gMinAccelQuiet = false;
02398 }
02399 if(bx0 == bx1) {
02400
02401 if(bt0 + bt1 < endTime && Max(Abs(ba0),Abs(ba1)) < amax) {
02402 temp.resize(1);
02403 temp[0].x0 = x0;
02404 temp[0].dx0 = v0;
02405 temp[0].x1 = x1;
02406 temp[0].dx1 = v1;
02407 temp[0].a1 = ba0;
02408 temp[0].v = 0;
02409 temp[0].a2 = ba1;
02410 temp[0].tswitch1 = bt0;
02411 temp[0].tswitch2 = endTime-bt1;
02412 temp[0].ttotal = endTime;
02413 ramps = temp;
02414 amax = Max(Abs(ba0),Abs(ba1));
02415 if(gValidityCheckLevel >= 2)
02416 PARABOLIC_RAMP_ASSERT(temp[0].IsValid());
02417 }
02418 }
02419 else {
02420
02421 if(bt0 + bt1 < endTime && Max(Abs(ba0),Abs(ba1)) < amax) {
02422
02423
02424 temp.resize(3);
02425 temp[0].x0 = x0;
02426 temp[0].dx0 = v0;
02427 temp[0].x1 = bx0;
02428 temp[0].dx1 = 0;
02429 temp[0].a1 = ba0;
02430 temp[0].v = 0;
02431 temp[0].a2 = 0;
02432 temp[0].tswitch1 = bt0;
02433 temp[0].tswitch2 = bt0;
02434 temp[0].ttotal = bt0;
02435
02436 temp[2].x0 = bx1;
02437 temp[2].dx0 = 0;
02438 temp[2].x1 = x1;
02439 temp[2].dx1 = v1;
02440 temp[2].a1 = ba1;
02441 temp[2].v = 0;
02442 temp[2].a2 = 0;
02443 temp[2].tswitch1 = bt1;
02444 temp[2].tswitch2 = bt1;
02445 temp[2].ttotal = bt1;
02446
02447 temp[1].x0 = bx0;
02448 temp[1].dx0 = 0;
02449 temp[1].x1 = bx1;
02450 temp[1].dx1 = 0;
02451 gMinAccelQuiet = true;
02452 if(Abs(bx0-bx1) < (endTime-bt0-bt1)*vmax) {
02453 if(temp[1].SolveMinAccel(endTime - bt0 - bt1,vmax)) {
02454 temp[1].Bounds(bmin,bmax);
02455 PARABOLIC_RAMP_ASSERT(bmin >= xmin && bmax <= xmax);
02456 if(Max(Abs(temp[1].a1),Abs(temp[1].a2)) < amax) {
02457 ramps = temp;
02458 amax = Max(Max(Abs(temp[1].a1),Abs(temp[1].a2)),Max(Abs(ba0),Abs(ba1)));
02459 }
02460 }
02461 }
02462 gMinAccelQuiet = false;
02463 }
02464 }
02465 if(ramps.empty()) {
02466 if(gVerbose >= 1) PARABOLIC_RAMP_PERROR("SolveMinAccelBounded: Warning, can't find bounded trajectory?\n");
02467 if(gVerbose >= 2) {
02468 PARABOLIC_RAMP_PERROR("x0 %g v0 %g, x1 %g v1 %g\n",x0,v0,x1,v1);
02469 PARABOLIC_RAMP_PERROR("endTime %g, vmax %g\n",endTime,vmax);
02470 PARABOLIC_RAMP_PERROR("x bounds [%g,%g]\n",xmin,xmax);
02471 }
02472 if(gErrorGetchar) getchar();
02473 return false;
02474 }
02475 if(gValidityCheckLevel >= 1) {
02476 for(size_t i=0;i<ramps.size();i++) {
02477 ramps[i].Bounds(bmin,bmax);
02478 if(bmin < xmin-EpsilonX || bmax > xmax+EpsilonX) {
02479 if(gVerbose >= 1)
02480 PARABOLIC_RAMP_PERROR("SolveMinAccelBounded: Warning, path exceeds bounds?\n");
02481 if(gVerbose >= 2)
02482 PARABOLIC_RAMP_PERROR(" ramp[%d] bounds %g %g, limits %g %g\n",i,bmin,bmax,xmin,xmax);
02483 if(gErrorGetchar) getchar();
02484 return false;
02485 }
02486 }
02487 }
02488
02489 PARABOLIC_RAMP_ASSERT(ramps.front().x0 == x0);
02490 PARABOLIC_RAMP_ASSERT(ramps.front().dx0 == v0);
02491 PARABOLIC_RAMP_ASSERT(ramps.back().x1 == x1);
02492 PARABOLIC_RAMP_ASSERT(ramps.back().dx1 == v1);
02493 double ttotal = 0;
02494 for(size_t i=0;i<ramps.size();i++)
02495 ttotal += ramps[i].ttotal;
02496 if(!FuzzyEquals(ttotal,endTime,EpsilonT*0.1)) {
02497 if(gVerbose >= 1) PARABOLIC_RAMP_PERROR("SolveMinTimeBounded: Numerical timing error");
02498 if(gVerbose >= 2) {
02499 PARABOLIC_RAMP_PERROR("Ramp times: ");
02500 for(size_t i=0;i<ramps.size();i++)
02501 PARABOLIC_RAMP_PERROR("%g ",ramps[i].ttotal);
02502 PARABOLIC_RAMP_PERROR("\n");
02503 }
02504 }
02505 PARABOLIC_RAMP_ASSERT(FuzzyEquals(ttotal,endTime,EpsilonT*0.1));
02506 return true;
02507 }
02508
02509 Real SolveMinTimeBounded(const Vector& x0,const Vector& v0,const Vector& x1,const Vector& v1,
02510 const Vector& amax,const Vector& vmax,const Vector& xmin,const Vector& xmax,
02511 vector<vector<ParabolicRamp1D> >& ramps)
02512 {
02513 PARABOLIC_RAMP_ASSERT(x0.size() == v0.size());
02514 PARABOLIC_RAMP_ASSERT(x1.size() == v1.size());
02515 PARABOLIC_RAMP_ASSERT(x0.size() == x1.size());
02516 PARABOLIC_RAMP_ASSERT(x0.size() == amax.size());
02517 PARABOLIC_RAMP_ASSERT(x0.size() == vmax.size());
02518 for(size_t i=0;i<x0.size();i++) {
02519 PARABOLIC_RAMP_ASSERT(x0[i] >= xmin[i] && x0[i] <= xmax[i]);
02520 PARABOLIC_RAMP_ASSERT(x1[i] >= xmin[i] && x1[i] <= xmax[i]);
02521 PARABOLIC_RAMP_ASSERT(Abs(v0[i]) <= vmax[i]);
02522 PARABOLIC_RAMP_ASSERT(Abs(v1[i]) <= vmax[i]);
02523 }
02524 Real endTime = 0;
02525 ramps.resize(x0.size());
02526 for(size_t i=0;i<ramps.size();i++) {
02527 ramps[i].resize(1);
02528 ramps[i][0].x0=x0[i];
02529 ramps[i][0].x1=x1[i];
02530 ramps[i][0].dx0=v0[i];
02531 ramps[i][0].dx1=v1[i];
02532 if(vmax[i]==0 || amax[i]==0) {
02533 if(!FuzzyEquals(x0[i],x1[i],EpsilonX)) {
02534 if(gVerbose >= 1)
02535 PARABOLIC_RAMP_PERROR("index %d vmax = %g, amax = %g, X0 != X1 (%g != %g)\n",i,vmax[i],amax[i],x0[i],x1[i]);
02536 return -1;
02537 }
02538 if(!FuzzyEquals(v0[i],v1[i],EpsilonV)) {
02539 if(gVerbose >= 1)
02540 PARABOLIC_RAMP_PERROR("index %d vmax = %g, amax = %g, DX0 != DX1 (%g != %g)\n",i,vmax[i],amax[i],v0[i],v1[i]);
02541 return -1;
02542 }
02543 ramps[i][0].tswitch1=ramps[i][0].tswitch2=ramps[i][0].ttotal=0;
02544 ramps[i][0].a1=ramps[i][0].a2=ramps[i][0].v=0;
02545 continue;
02546 }
02547 if(!ramps[i][0].SolveMinTime(amax[i],vmax[i])) return -1;
02548 Real bmin,bmax;
02549 ramps[i][0].Bounds(bmin,bmax);
02550 if(bmin < xmin[i] || bmax > xmax[i]) return -1;
02551 if(ramps[i][0].ttotal > endTime) endTime = ramps[i][0].ttotal;
02552 }
02553
02554
02555 while(true) {
02556 bool solved = true;
02557 for(size_t i=0;i<ramps.size();i++) {
02558 PARABOLIC_RAMP_ASSERT(ramps[i].size() > 0);
02559 if(vmax[i]==0 || amax[i]==0) {
02560 ramps[i][0].ttotal = endTime;
02561 continue;
02562 }
02563
02564 Real ttotal = 0;
02565 for(size_t j=0;j<ramps[i].size();j++)
02566 ttotal += ramps[i][j].ttotal;
02567 if(FuzzyEquals(ttotal,endTime,EpsilonT)) continue;
02568
02569
02570 if(!SolveMinAccelBounded(x0[i],v0[i],x1[i],v1[i],endTime,vmax[i],xmin[i],xmax[i],ramps[i])) {
02571 if(gVerbose >= 1)
02572 PARABOLIC_RAMP_PERROR("Failed solving bounded min accel for joint %d\n",i);
02573 return -1;
02574 }
02575
02576 bool inVelBounds = true;
02577 for(size_t j=0;j<ramps[i].size();j++)
02578 if(Abs(ramps[i][j].a1) > amax[i]+EpsilonA || Abs(ramps[i][j].a2) > amax[i]+EpsilonA || Abs(ramps[i][j].v) > vmax[i]+EpsilonV) {
02579
02580 inVelBounds = false;
02581 break;
02582 }
02583 if(!inVelBounds) {
02584 ramps[i].resize(1);
02585 ramps[i][0].x0=x0[i];
02586 ramps[i][0].x1=x1[i];
02587 ramps[i][0].dx0=v0[i];
02588 ramps[i][0].dx1=v1[i];
02589 gMinTime2Quiet = true;
02590 bool res=ramps[i][0].SolveMinTime2(amax[i],vmax[i],endTime);
02591 gMinTime2Quiet = false;
02592 if(!res) {
02593 return -1;
02594 }
02595 Real bmin,bmax;
02596 ramps[i][0].Bounds(bmin,bmax);
02597 if(bmin < xmin[i] || bmax > xmax[i]) {
02598
02599
02600 return -1;
02601 }
02602
02603
02604 ttotal = 0;
02605 for(size_t j=0;j<ramps[i].size();j++)
02606 ttotal += ramps[i][j].ttotal;
02607 PARABOLIC_RAMP_ASSERT(ttotal > endTime);
02608 endTime = ttotal;
02609 solved = false;
02610 break;
02611 }
02612 ttotal = 0;
02613 for(size_t j=0;j<ramps[i].size();j++) {
02614 PARABOLIC_RAMP_ASSERT(Abs(ramps[i][j].a1) <= amax[i]+EpsilonA);
02615 PARABOLIC_RAMP_ASSERT(Abs(ramps[i][j].a2) <= amax[i]+EpsilonA);
02616 PARABOLIC_RAMP_ASSERT(Abs(ramps[i][j].v) <= vmax[i]+EpsilonV);
02617 ttotal += ramps[i][j].ttotal;
02618 }
02619 PARABOLIC_RAMP_ASSERT(FuzzyEquals(ttotal,endTime,EpsilonT*0.1));
02620 }
02621
02622 if(solved) break;
02623 }
02624 return endTime;
02625 }
02626
02627 bool SolveMinAccelBounded(const Vector& x0,const Vector& v0,const Vector& x1,const Vector& v1,
02628 Real endTime,const Vector& vmax,const Vector& xmin,const Vector& xmax,
02629 vector<vector<ParabolicRamp1D> >& ramps)
02630 {
02631 PARABOLIC_RAMP_ASSERT(x0.size() == v0.size());
02632 PARABOLIC_RAMP_ASSERT(x1.size() == v1.size());
02633 PARABOLIC_RAMP_ASSERT(x0.size() == x1.size());
02634 PARABOLIC_RAMP_ASSERT(x0.size() == vmax.size());
02635 for(size_t i=0;i<x0.size();i++) {
02636 PARABOLIC_RAMP_ASSERT(x0[i] >= xmin[i] && x0[i] <= xmax[i]);
02637 PARABOLIC_RAMP_ASSERT(x1[i] >= xmin[i] && x1[i] <= xmax[i]);
02638 PARABOLIC_RAMP_ASSERT(Abs(v0[i]) <= vmax[i]);
02639 PARABOLIC_RAMP_ASSERT(Abs(v1[i]) <= vmax[i]);
02640 }
02641 for(size_t i=0;i<ramps.size();i++) {
02642 if(vmax[i]==0) {
02643 ramps[i].resize(1);
02644 ramps[i][0].x0=x0[i];
02645 ramps[i][0].x1=x1[i];
02646 ramps[i][0].dx0=v0[i];
02647 ramps[i][0].dx1=v1[i];
02648 ramps[i][0].ttotal = endTime;
02649 continue;
02650 }
02651
02652 if(!SolveMinAccelBounded(x0[i],v0[i],x1[i],v1[i],endTime,vmax[i],xmin[i],xmax[i],ramps[i])) {
02653 if(gVerbose >= 1)
02654 PARABOLIC_RAMP_PERROR("Failed solving bounded min accel for joint %d\n",i);
02655 return false;
02656 }
02657 }
02658 return true;
02659 }
02660
02661 void CombineRamps(const std::vector<std::vector<ParabolicRamp1D> >& ramps,std::vector<ParabolicRampND>& ndramps)
02662 {
02663 ndramps.resize(0);
02664 vector<vector<ParabolicRamp1D>::const_iterator> indices(ramps.size());
02665 for(size_t i=0;i<ramps.size();i++) {
02666 PARABOLIC_RAMP_ASSERT(!ramps[i].empty());
02667 indices[i] = ramps[i].begin();
02668 }
02669 vector<double> timeOffsets(ramps.size(),0);
02670 Real t=0;
02671 while(true) {
02672
02673 Real tnext=Inf;
02674 for(size_t i=0;i<ramps.size();i++) {
02675 if(indices[i] != ramps[i].end())
02676 tnext = Min(tnext,timeOffsets[i]+indices[i]->ttotal);
02677 }
02678 if(IsInf(tnext)) break;
02679 if(! (tnext > t || t == 0)) {
02680 if(gVerbose >= 1)
02681 PARABOLIC_RAMP_PERROR("CombineRamps: error finding next time step?\n");
02682 if(gVerbose >= 2) {
02683 PARABOLIC_RAMP_PERROR("tnext = %g, t = %g, step = %d\n",tnext,t,ndramps.size());
02684 for(size_t k=0;k<ramps.size();k++) {
02685 PARABOLIC_RAMP_PERROR("Ramp %d times: ",k);
02686 Real ttotal = 0.0;
02687 for(size_t j=0;j<ramps[k].size();j++) {
02688 PARABOLIC_RAMP_PERROR("%g ",ramps[k][j].ttotal);
02689 ttotal += ramps[k][j].ttotal;
02690 }
02691 PARABOLIC_RAMP_PERROR(", total %g\n",ttotal);
02692 }
02693 }
02694 }
02695 PARABOLIC_RAMP_ASSERT(tnext > t || t == 0);
02696 if(tnext == 0) {
02697 for(size_t i=0;i<ramps.size();i++)
02698 PARABOLIC_RAMP_ASSERT(ramps[i].size()==1);
02699 }
02700
02701 ndramps.resize(ndramps.size()+1);
02702 ParabolicRampND& ramp=ndramps.back();
02703 ramp.x0.resize(ramps.size());
02704 ramp.x1.resize(ramps.size());
02705 ramp.dx0.resize(ramps.size());
02706 ramp.dx1.resize(ramps.size());
02707 ramp.ramps.resize(ramps.size());
02708 ramp.endTime = tnext-t;
02709 for(size_t i=0;i<ramps.size();i++) {
02710 if(indices[i] != ramps[i].end()) {
02711 ParabolicRamp1D iramp = *indices[i];
02712 if(indices[i] == --ramps[i].end() && FuzzyEquals(tnext-timeOffsets[i],indices[i]->ttotal,EpsilonT*0.1)) {
02713
02714 }
02715 else {
02716 iramp.TrimBack((timeOffsets[i]-tnext)+indices[i]->ttotal);
02717 }
02718 iramp.TrimFront(t-timeOffsets[i]);
02719 Real oldTotal = iramp.ttotal;
02720 iramp.ttotal = ramp.endTime;
02721 if(iramp.tswitch1 > iramp.ttotal) iramp.tswitch1 = iramp.ttotal;
02722 if(iramp.tswitch2 > iramp.ttotal) iramp.tswitch2 = iramp.ttotal;
02723 if(gValidityCheckLevel >= 2) {
02724 if(!iramp.IsValid()) {
02725 if(gVerbose >= 1) {
02726 PARABOLIC_RAMP_PERROR("CombineRamps: Trimming caused ramp to become invalid\n");
02727 PARABOLIC_RAMP_PERROR("Old total time %g, new total time %g\n",oldTotal,iramp.ttotal);
02728 }
02729 }
02730 PARABOLIC_RAMP_ASSERT(iramp.IsValid());
02731 }
02732 ramp.ramps[i] = iramp;
02733 ramp.x0[i] = iramp.x0;
02734 ramp.dx0[i] = iramp.dx0;
02735 ramp.x1[i] = iramp.x1;
02736 ramp.dx1[i] = iramp.dx1;
02737 if(FuzzyEquals(tnext,timeOffsets[i]+indices[i]->ttotal,EpsilonT*0.1)) {
02738 timeOffsets[i] = tnext;
02739 indices[i]++;
02740 }
02741 PARABOLIC_RAMP_ASSERT(ramp.ramps[i].ttotal == ramp.endTime);
02742 }
02743 else {
02744
02745 PARABOLIC_RAMP_ASSERT(!ramps[i].empty());
02746 ramp.x0[i] = ramps[i].back().x1;
02747 ramp.dx0[i] = ramps[i].back().dx1;
02748
02749 ramp.x1[i] = ramps[i].back().x1;
02750 ramp.dx1[i] = ramps[i].back().dx1;
02751 if(!FuzzyEquals(ramps[i].back().dx1*(tnext-t),0.0,EpsilonV)) {
02752 if(gVerbose >= 1)
02753 PARABOLIC_RAMP_PERROR("CombineRamps: warning, propagating time %g distance %g off the back, vel %g\n",(tnext-t),ramps[i].back().dx1*(tnext-t),ramp.dx0[i]);
02754 if(gVerbose >= 2) {
02755 for(size_t k=0;k<ramps.size();k++) {
02756 PARABOLIC_RAMP_PERROR("Ramp %d times: ",k);
02757 Real ttotal = 0.0;
02758 for(size_t j=0;j<ramps[k].size();j++) {
02759 PARABOLIC_RAMP_PERROR("%g ",ramps[k][j].ttotal);
02760 ttotal += ramps[k][j].ttotal;
02761 }
02762 PARABOLIC_RAMP_PERROR(", total %g\n",ttotal);
02763 }
02764 if(gErrorGetchar) getchar();
02765 }
02766 }
02767
02768 ramp.ramps[i].x0 = ramp.x0[i];
02769 ramp.ramps[i].dx0 = ramp.dx0[i];
02770 ramp.ramps[i].x1 = ramp.x1[i];
02771 ramp.ramps[i].dx1 = ramp.dx1[i];
02772 ramp.ramps[i].ttotal = ramp.ramps[i].tswitch2 = (tnext-t);
02773 ramp.ramps[i].tswitch1 = 0;
02774 ramp.ramps[i].v = ramp.dx1[i];
02775 ramp.ramps[i].a1 = ramp.ramps[i].a2 = 0;
02776 if(gValidityCheckLevel >= 2) {
02777 PARABOLIC_RAMP_ASSERT(ramp.ramps[i].IsValid());
02778 PARABOLIC_RAMP_ASSERT(ramp.ramps[i].ttotal == ramp.endTime);
02779 }
02780 }
02781 }
02782 if(gValidityCheckLevel >= 2)
02783 PARABOLIC_RAMP_ASSERT(ramp.IsValid());
02784 if(ndramps.size() > 1) {
02785 ramp.x0 = ndramps[ndramps.size()-2].x1;
02786 ramp.dx0 = ndramps[ndramps.size()-2].dx1;
02787 for(size_t i=0;i<ramp.ramps.size();i++) {
02788 ramp.ramps[i].x0=ramp.x0[i];
02789 ramp.ramps[i].dx0=ramp.dx0[i];
02790 }
02791 }
02792 if(gValidityCheckLevel >= 2)
02793 PARABOLIC_RAMP_ASSERT(ramp.IsValid());
02794
02795 t = tnext;
02796 if(tnext == 0)
02797 break;
02798 }
02799 for(size_t i=0;i<ramps.size();i++) {
02800 if(!FuzzyEquals(ramps[i].front().x0,ndramps.front().x0[i],EpsilonX)) {
02801 PARABOLIC_RAMP_PERROR("CombineRamps: Error: %d start %g != %g\n",i,ramps[i].front().x0,ndramps.front().x0[i]);
02802 if(gErrorGetchar) getchar();
02803 }
02804 if(!FuzzyEquals(ramps[i].front().dx0,ndramps.front().dx0[i],EpsilonV)) {
02805 PARABOLIC_RAMP_PERROR("CombineRamps: Error: %d start %g != %g\n",i,ramps[i].front().dx0,ndramps.front().dx0[i]);
02806 if(gErrorGetchar) getchar();
02807 }
02808 if(!FuzzyEquals(ramps[i].back().x1,ndramps.back().x1[i],EpsilonX)) {
02809 PARABOLIC_RAMP_PERROR("CombineRamps: Error: %d back %g != %g\n",i,ramps[i].back().x1,ndramps.back().x1[i]);
02810 if(gErrorGetchar) getchar();
02811 }
02812 if(!FuzzyEquals(ramps[i].back().dx1,ndramps.back().dx1[i],EpsilonV)) {
02813 PARABOLIC_RAMP_PERROR("CombineRamps: Error: %d back %g != %g\n",i,ramps[i].back().dx1,ndramps.back().dx1[i]);
02814 if(gErrorGetchar) getchar();
02815 }
02816 ndramps.front().x0[i] = ndramps.front().ramps[i].x0 = ramps[i].front().x0;
02817 ndramps.front().dx0[i] = ndramps.front().ramps[i].dx0 = ramps[i].front().dx0;
02818 ndramps.back().x1[i] = ndramps.back().ramps[i].x1 = ramps[i].back().x1;
02819 ndramps.back().dx1[i] = ndramps.back().ramps[i].dx1 = ramps[i].back().dx1;
02820 }
02821 }
02822
02823
02824 }