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/DynamicPath.h"
00032 #include "constraint_aware_spline_smoother/ParabolicPathSmooth/Timer.h"
00033 #include "constraint_aware_spline_smoother/ParabolicPathSmooth/Config.h"
00034 #include "constraint_aware_spline_smoother/ParabolicPathSmooth/Math.h"
00035 #include <assert.h>
00036 #include <stdlib.h>
00037 #include <stdio.h>
00038 #include <list>
00039 #include <algorithm>
00040 using namespace std;
00041
00042 namespace ParabolicRamp {
00043
00044 inline Real LInfDistance(const Vector& a,const Vector& b)
00045 {
00046 PARABOLIC_RAMP_ASSERT(a.size()==b.size());
00047 Real d=0;
00048 for(size_t i=0;i<a.size();i++)
00049 d = Max(d,Abs(a[i]-b[i]));
00050 return d;
00051 }
00052
00053 inline bool InBounds(const Vector& x,const Vector& bmin,const Vector& bmax)
00054 {
00055 PARABOLIC_RAMP_ASSERT(x.size()==bmin.size());
00056 PARABOLIC_RAMP_ASSERT(x.size()==bmax.size());
00057 for(size_t i=0;i<x.size();i++)
00058 if(x[i] < bmin[i] || x[i] > bmax[i]) return false;
00059 return true;
00060 }
00061
00062 inline Real MaxBBLInfDistance(const Vector& x,const Vector& bmin,const Vector& bmax)
00063 {
00064 PARABOLIC_RAMP_ASSERT(x.size()==bmin.size());
00065 PARABOLIC_RAMP_ASSERT(x.size()==bmax.size());
00066 Real d=0;
00067 for(size_t i=0;i<x.size();i++)
00068 d = Max(d,Max(Abs(x[i]-bmin[i]),Abs(x[i]-bmax[i])));
00069 return d;
00070 }
00071
00072 inline bool SolveMinTime(const Vector& x0,const Vector& dx0,const Vector& x1,const Vector& dx1,
00073 const Vector& accMax,const Vector& velMax,const Vector& xMin,const Vector& xMax,DynamicPath& out)
00074 {
00075 if(xMin.empty()) {
00076 out.ramps.resize(1);
00077 ParabolicRampND& temp=out.ramps[0];
00078 temp.x0=x0;
00079 temp.x1=x1;
00080 temp.dx0=dx0;
00081 temp.dx1=dx1;
00082 bool res=temp.SolveMinTime(accMax,velMax);
00083 if(!res) return false;
00084 }
00085 else {
00086 vector<std::vector<ParabolicRamp1D> > ramps;
00087 Real res=SolveMinTimeBounded(x0,dx0,x1,dx1,
00088 accMax,velMax,xMin,xMax,
00089 ramps);
00090 if(res < 0) return false;
00091 CombineRamps(ramps,out.ramps);
00092 }
00093 PARABOLIC_RAMP_ASSERT(out.IsValid());
00094 return true;
00095 }
00096
00097 DynamicPath::DynamicPath()
00098 {}
00099
00100 void DynamicPath::Init(const Vector& _velMax,const Vector& _accMax)
00101 {
00102 velMax = _velMax;
00103 accMax = _accMax;
00104 PARABOLIC_RAMP_ASSERT(velMax.size() == accMax.size());
00105 if(!velMax.empty() && !xMin.empty()) PARABOLIC_RAMP_ASSERT(xMin.size() == velMax.size());
00106 }
00107
00108 void DynamicPath::SetJointLimits(const Vector& _xMin,const Vector& _xMax)
00109 {
00110 xMin = _xMin;
00111 xMax = _xMax;
00112 PARABOLIC_RAMP_ASSERT(xMin.size() == xMax.size());
00113 if(!velMax.empty() && !xMin.empty()) PARABOLIC_RAMP_ASSERT(xMin.size() == velMax.size());
00114 }
00115
00116 Real DynamicPath::GetTotalTime() const
00117 {
00118 Real t=0;
00119 for(size_t i=0;i<ramps.size();i++) t+=ramps[i].endTime;
00120 return t;
00121 }
00122
00123 int DynamicPath::GetSegment(Real t,Real& u) const
00124 {
00125 if(t < 0) return -1;
00126 for(size_t i=0;i<ramps.size();i++) {
00127 if(t <= ramps[i].endTime) {
00128 u = t;
00129 return (int)i;
00130 }
00131 t -= ramps[i].endTime;
00132 }
00133 u = t;
00134 return (int)ramps.size();
00135 }
00136
00137 void DynamicPath::Evaluate(Real t,Vector& x) const
00138 {
00139 PARABOLIC_RAMP_ASSERT(!ramps.empty());
00140 if(t < 0) {
00141 x = ramps.front().x0;
00142 }
00143 else {
00144 for(size_t i=0;i<ramps.size();i++) {
00145 if(t <= ramps[i].endTime) {
00146 ramps[i].Evaluate(t,x);
00147 return;
00148 }
00149 t -= ramps[i].endTime;
00150 }
00151 x = ramps.back().x1;
00152 }
00153 }
00154
00155 void DynamicPath::Derivative(Real t,Vector& dx) const
00156 {
00157 PARABOLIC_RAMP_ASSERT(!ramps.empty());
00158 if(t < 0) {
00159 dx = ramps.front().dx0;
00160 }
00161 else {
00162 for(size_t i=0;i<ramps.size();i++) {
00163 if(t <= ramps[i].endTime) {
00164 ramps[i].Derivative(t,dx);
00165 return;
00166 }
00167 t -= ramps[i].endTime;
00168 }
00169 dx = ramps.back().dx1;
00170 }
00171 }
00172
00173 void DynamicPath::SetMilestones(const vector<Vector>& x)
00174 {
00175 if(x.empty()) {
00176 ramps.resize(0);
00177 }
00178 else if(x.size()==1) {
00179 ramps.resize(1);
00180 ramps[0].SetConstant(x[0]);
00181 }
00182 else {
00183 Vector zero(x[0].size(),0.0);
00184 ramps.resize(x.size()-1);
00185 for(size_t i=0;i<ramps.size();i++) {
00186 ramps[i].x0 = x[i];
00187 ramps[i].x1 = x[i+1];
00188 ramps[i].dx0 = zero;
00189 ramps[i].dx1 = zero;
00190 bool res=ramps[i].SolveMinTimeLinear(accMax,velMax);
00191 PARABOLIC_RAMP_ASSERT(res);
00192 }
00193 }
00194 }
00195
00196 void DynamicPath::SetMilestones(const vector<Vector>& x,const vector<Vector>& dx)
00197 {
00198 if(x.empty()) {
00199 ramps.resize(0);
00200 }
00201 else if(x.size()==1) {
00202 ramps.resize(1);
00203 ramps[0].SetConstant(x[0]);
00204 }
00205 else {
00206 if(xMin.empty()) {
00207 ramps.resize(x.size()-1);
00208 for(size_t i=0;i<ramps.size();i++) {
00209 ramps[i].x0 = x[i];
00210 ramps[i].x1 = x[i+1];
00211 ramps[i].dx0 = dx[i];
00212 ramps[i].dx1 = dx[i+1];
00213 bool res=ramps[i].SolveMinTime(accMax,velMax);
00214 PARABOLIC_RAMP_ASSERT(res);
00215 }
00216 }
00217 else {
00218
00219 ramps.resize(0);
00220 ramps.reserve(x.size()-1);
00221 std::vector<std::vector<ParabolicRamp1D> > tempRamps;
00222 std::vector<ParabolicRampND> tempRamps2;
00223 PARABOLIC_RAMP_ASSERT(InBounds(x[0],xMin,xMax));
00224 for(size_t i=0;i+1<x.size();i++) {
00225 PARABOLIC_RAMP_ASSERT(InBounds(x[i+1],xMin,xMax));
00226 Real res=SolveMinTimeBounded(x[i],dx[i],x[i+1],dx[i+1],
00227 accMax,velMax,xMin,xMax,
00228 tempRamps);
00229 PARABOLIC_RAMP_ASSERT(res >= 0);
00230 CombineRamps(tempRamps,tempRamps2);
00231 ramps.insert(ramps.end(),tempRamps2.begin(),tempRamps2.end());
00232 }
00233 }
00234 }
00235 }
00236
00237 void DynamicPath::GetMilestones(vector<Vector>& x,vector<Vector>& dx) const
00238 {
00239 if(ramps.empty()) {
00240 x.resize(0);
00241 dx.resize(0);
00242 return;
00243 }
00244 x.resize(ramps.size()+1);
00245 dx.resize(ramps.size()+1);
00246 x[0] = ramps[0].x0;
00247 dx[0] = ramps[0].dx0;
00248 for(size_t i=0;i<ramps.size();i++) {
00249 x[i+1] = ramps[i].x1;
00250 dx[i+1] = ramps[i].dx1;
00251 }
00252 }
00253
00254 void DynamicPath::Append(const Vector& x)
00255 {
00256 size_t n=ramps.size();
00257 size_t p=n-1;
00258 if(ramps.size()==0) {
00259 ramps.resize(1);
00260 ramps[0].SetConstant(x);
00261 }
00262 else {
00263 if(xMin.empty()) {
00264 ramps.resize(ramps.size()+1);
00265 ramps[n].x0 = ramps[p].x1;
00266 ramps[n].dx0 = ramps[p].dx1;
00267 ramps[n].x1 = x;
00268 ramps[n].dx1.resize(x.size());
00269 fill(ramps[n].dx1.begin(),ramps[n].dx1.end(),0);
00270 bool res=ramps[n].SolveMinTime(accMax,velMax);
00271 PARABOLIC_RAMP_ASSERT(res);
00272 }
00273 else {
00274 PARABOLIC_RAMP_ASSERT(InBounds(x,xMin,xMax));
00275 std::vector<std::vector<ParabolicRamp1D> > tempRamps;
00276 std::vector<ParabolicRampND> tempRamps2;
00277 Vector zero(x.size(),0.0);
00278 Real res=SolveMinTimeBounded(ramps[p].x1,ramps[p].dx1,x,zero,
00279 accMax,velMax,xMin,xMax,tempRamps);
00280 PARABOLIC_RAMP_ASSERT(res>=0);
00281 CombineRamps(tempRamps,tempRamps2);
00282 ramps.insert(ramps.end(),tempRamps2.begin(),tempRamps2.end());
00283 }
00284 }
00285 }
00286
00287 void DynamicPath::Append(const Vector& x,const Vector& dx)
00288 {
00289 size_t n=ramps.size();
00290 size_t p=n-1;
00291 PARABOLIC_RAMP_ASSERT(ramps.size()!=0);
00292 if(xMin.empty()) {
00293 ramps.resize(ramps.size()+1);
00294 ramps[n].x0 = ramps[p].x1;
00295 ramps[n].dx0 = ramps[p].dx1;
00296 ramps[n].x1 = x;
00297 ramps[n].dx1 = dx;
00298 bool res=ramps[n].SolveMinTime(accMax,velMax);
00299 PARABOLIC_RAMP_ASSERT(res);
00300 }
00301 else {
00302 PARABOLIC_RAMP_ASSERT(InBounds(x,xMin,xMax));
00303 std::vector<std::vector<ParabolicRamp1D> > tempRamps;
00304 std::vector<ParabolicRampND> tempRamps2;
00305 Real res=SolveMinTimeBounded(ramps[p].x1,ramps[p].dx1,x,dx,
00306 accMax,velMax,xMin,xMax,tempRamps);
00307 PARABOLIC_RAMP_ASSERT(res>=0);
00308 CombineRamps(tempRamps,tempRamps2);
00309 ramps.insert(ramps.end(),tempRamps2.begin(),tempRamps2.end());
00310 }
00311 }
00312
00313 void DynamicPath::Concat(const DynamicPath& suffix)
00314 {
00315 PARABOLIC_RAMP_ASSERT(&suffix != this);
00316 if(suffix.ramps.empty()) return;
00317 if(ramps.empty()) {
00318 *this=suffix;
00319 return;
00320 }
00321
00322 if(ramps.back().x1 != suffix.ramps.front().x0 ||
00323 ramps.back().dx1 != suffix.ramps.front().dx0) {
00324 Real xmax=0,dxmax=0;
00325 for(size_t i=0;i<ramps.back().x1.size();i++) {
00326 xmax=Max(xmax,Abs(ramps.back().x1[i]-suffix.ramps.front().x0[i]));
00327 dxmax=Max(dxmax,Abs(ramps.back().dx1[i]-suffix.ramps.front().dx0[i]));
00328 }
00329 if(Abs(xmax) > EpsilonX || Abs(dxmax) > EpsilonV) {
00330 printf("Concat endpoint error\n");
00331 printf("x:\n");
00332 for(size_t i=0;i<ramps.back().x1.size();i++)
00333 printf("%g - %g = %g\n",ramps.back().x1[i],suffix.ramps.front().x0[i],ramps.back().x1[i]-suffix.ramps.front().x0[i]);
00334 printf("dx:\n");
00335 for(size_t i=0;i<ramps.back().x1.size();i++)
00336 printf("%g - %g = %g\n",ramps.back().dx1[i],suffix.ramps.front().dx0[i],ramps.back().dx1[i]-suffix.ramps.front().dx0[i]);
00337 getchar();
00338 }
00339 ramps.back().x1 = ramps.front().x0;
00340 ramps.back().dx1 = ramps.front().dx0;
00341 for(size_t i=0;i<ramps.back().x1.size();i++) {
00342 ramps.back().ramps[i].x1 = suffix.ramps.front().x0[i];
00343 ramps.back().ramps[i].dx1 = suffix.ramps.front().dx0[i];
00344 }
00345 }
00346 PARABOLIC_RAMP_ASSERT(ramps.back().x1 == suffix.ramps.front().x0);
00347 PARABOLIC_RAMP_ASSERT(ramps.back().dx1 == suffix.ramps.front().dx0);
00348 ramps.insert(ramps.end(),suffix.ramps.begin(),suffix.ramps.end());
00349 }
00350
00351 void DynamicPath::Split(Real t,DynamicPath& before,DynamicPath& after) const
00352 {
00353 PARABOLIC_RAMP_ASSERT(IsValid());
00354 PARABOLIC_RAMP_ASSERT(&before != this);
00355 PARABOLIC_RAMP_ASSERT(&after != this);
00356 if(ramps.empty()) {
00357 before=*this;
00358 after=*this;
00359 return;
00360 }
00361 after.velMax = before.velMax = velMax;
00362 after.accMax = before.accMax = accMax;
00363 after.xMin = before.xMin = xMin;
00364 after.xMax = before.xMax = xMax;
00365 after.ramps.resize(0);
00366 before.ramps.resize(0);
00367 if(t < 0) {
00368 before.ramps.resize(1);
00369 before.ramps[0].SetConstant(ramps[0].x0);
00370
00371 after.ramps.resize(1);
00372 after.ramps[0].SetConstant(ramps[0].x0,-t);
00373 }
00374 for(size_t i=0;i<ramps.size();i++) {
00375 if(t < 0) {
00376 after.ramps.push_back(ramps[i]);
00377 }
00378 else {
00379 if(t < ramps[i].endTime) {
00380
00381 ParabolicRampND temp=ramps[i];
00382 temp.TrimBack(temp.endTime-t);
00383 before.ramps.push_back(temp);
00384 temp=ramps[i];
00385 temp.TrimFront(t);
00386 if(!after.ramps.empty()) {
00387 printf("DynamicPath::Split: Uh... weird, after is not empty?\n");
00388 printf("t = %g, i = %d, endtime = %g\n",t,i,ramps[i].endTime);
00389 }
00390 PARABOLIC_RAMP_ASSERT(after.ramps.size() == 0);
00391 after.ramps.push_back(temp);
00392 }
00393 else {
00394 before.ramps.push_back(ramps[i]);
00395 }
00396 t -= ramps[i].endTime;
00397 }
00398 }
00399
00400 if(t > 0) {
00401 ParabolicRampND temp;
00402 temp.SetConstant(ramps.back().x1,t);
00403 before.ramps.push_back(temp);
00404 }
00405 if(t >= 0) {
00406 ParabolicRampND temp;
00407 temp.SetConstant(ramps.back().x1);
00408 after.ramps.push_back(temp);
00409 }
00410 PARABOLIC_RAMP_ASSERT(before.IsValid());
00411 PARABOLIC_RAMP_ASSERT(after.IsValid());
00412 }
00413
00414
00415
00416
00417 struct RampSection
00418 {
00419 Real ta,tb;
00420 Vector xa,xb;
00421 Real da,db;
00422 };
00423
00424
00425
00426
00427
00428 bool CheckRamp(const ParabolicRampND& ramp,FeasibilityCheckerBase* feas,DistanceCheckerBase* distance,int maxiters)
00429 {
00430 if(!feas->ConfigFeasible(ramp.x0)) return false;
00431 if(!feas->ConfigFeasible(ramp.x1)) return false;
00432 PARABOLIC_RAMP_ASSERT(distance->ObstacleDistanceNorm()==Inf);
00433 RampSection section;
00434 section.ta = 0;
00435 section.tb = ramp.endTime;
00436 section.xa = ramp.x0;
00437 section.xb = ramp.x1;
00438 section.da = distance->ObstacleDistance(ramp.x0);
00439 section.db = distance->ObstacleDistance(ramp.x1);
00440 if(section.da <= 0.0) return false;
00441 if(section.db <= 0.0) return false;
00442 list<RampSection> queue;
00443 queue.push_back(section);
00444 int iters=0;
00445 while(!queue.empty()) {
00446 section = queue.front();
00447 queue.erase(queue.begin());
00448
00449
00450 if(LInfDistance(section.xa,section.xb) <= section.da+section.db) {
00451 Vector bmin,bmax;
00452 ramp.Bounds(section.ta,section.tb,bmin,bmax);
00453 if(MaxBBLInfDistance(section.xa,bmin,bmax) < section.da &&
00454 MaxBBLInfDistance(section.xb,bmin,bmax) < section.db)
00455
00456 continue;
00457 }
00458 Real tc = (section.ta+section.tb)*0.5;
00459 Vector xc;
00460 ramp.Evaluate(tc,xc);
00461 if(!feas->ConfigFeasible(xc)) return false;
00462
00463 Real dc = distance->ObstacleDistance(xc);
00464 RampSection sa,sb;
00465 sa.ta = section.ta;
00466 sa.xa = section.xa;
00467 sa.da = section.da;
00468 sa.tb = sb.ta = tc;
00469 sa.xb = sb.xa = xc;
00470 sa.db = sb.da = dc;
00471 sb.tb = section.tb;
00472 sb.xb = section.xb;
00473 sb.db = section.db;
00474
00475
00476 queue.push_back(sa);
00477 queue.push_back(sb);
00478
00479 if(iters++ >= maxiters) return false;
00480 }
00481 return true;
00482 }
00483
00484 bool CheckRamp(const ParabolicRampND& ramp,FeasibilityCheckerBase* space,Real tol)
00485 {
00486 PARABOLIC_RAMP_ASSERT(tol > 0);
00487 if(!space->ConfigFeasible(ramp.x0)) return false;
00488 if(!space->ConfigFeasible(ramp.x1)) return false;
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509 vector<Real> divs;
00510 Real t=0;
00511 divs.push_back(t);
00512 while(t < ramp.endTime) {
00513 Real tnext=t;
00514 Real amax = 0;
00515 Real switchNext=ramp.endTime;
00516 for(size_t i=0;i<ramp.ramps.size();i++) {
00517 if(t < ramp.ramps[i].tswitch1) {
00518 switchNext = Min(switchNext, ramp.ramps[i].tswitch1);
00519 amax = Max(amax,Max(Abs(ramp.ramps[i].a1),Abs(ramp.ramps[i].a2)));
00520 }
00521 else if(t < ramp.ramps[i].tswitch2) {
00522 switchNext = Min(switchNext, ramp.ramps[i].tswitch2);
00523 }
00524 else if(t < ramp.ramps[i].ttotal) {
00525 amax = Max(amax,Max(Abs(ramp.ramps[i].a1),Abs(ramp.ramps[i].a2)));
00526 }
00527 }
00528 Real dt = 2.0*Sqrt(tol/amax);
00529 if(t+dt > switchNext) tnext = switchNext;
00530 else tnext = t+dt;
00531
00532 t = tnext;
00533 divs.push_back(tnext);
00534 }
00535 divs.push_back(ramp.endTime);
00536
00537
00538 list<pair<int,int> > segs;
00539 segs.push_back(pair<int,int>(0,divs.size()-1));
00540 Vector q1,q2;
00541 while(!segs.empty()) {
00542 int i=segs.front().first;
00543 int j=segs.front().second;
00544 segs.erase(segs.begin());
00545 if(j == i+1) {
00546
00547 ramp.Evaluate(divs[i],q1);
00548 ramp.Evaluate(divs[j],q2);
00549 if(!space->SegmentFeasible(q1,q2)) return false;
00550 }
00551 else {
00552 int k=(i+j)/2;
00553 ramp.Evaluate(divs[k],q1);
00554 if(!space->ConfigFeasible(q1)) return false;
00555 segs.push_back(pair<int,int>(i,k));
00556 segs.push_back(pair<int,int>(k,j));
00557 }
00558 }
00559 return true;
00560 }
00561
00562 RampFeasibilityChecker::RampFeasibilityChecker(FeasibilityCheckerBase* _feas,Real _tol)
00563 :feas(_feas),tol(_tol),distance(NULL),maxiters(0)
00564 {}
00565
00566 RampFeasibilityChecker::RampFeasibilityChecker(FeasibilityCheckerBase* _feas,DistanceCheckerBase* _distance,int _maxiters)
00567 :feas(_feas),tol(0),distance(_distance),maxiters(_maxiters)
00568 {}
00569
00570 bool RampFeasibilityChecker::Check(const ParabolicRampND& x)
00571 {
00572 if(distance) return CheckRamp(x,feas,distance,maxiters);
00573 else return CheckRamp(x,feas,tol);
00574 }
00575
00576
00577 bool DynamicPath::TryShortcut(Real t1,Real t2,RampFeasibilityChecker& check)
00578 {
00579 if(t1 > t2) Swap(t1,t2);
00580 Real u1,u2;
00581 int i1 = GetSegment(t1,u1);
00582 int i2 = GetSegment(t2,u2);
00583 if(i1 == i2) return false;
00584 PARABOLIC_RAMP_ASSERT(u1 >= 0);
00585 PARABOLIC_RAMP_ASSERT(u1 <= ramps[i1].endTime+EpsilonT);
00586 PARABOLIC_RAMP_ASSERT(u2 >= 0);
00587 PARABOLIC_RAMP_ASSERT(u2 <= ramps[i2].endTime+EpsilonT);
00588 u1 = Min(u1,ramps[i1].endTime);
00589 u2 = Min(u2,ramps[i2].endTime);
00590 DynamicPath intermediate;
00591 if(xMin.empty()) {
00592 intermediate.ramps.resize(1);
00593 ParabolicRampND& test=intermediate.ramps[0];
00594 ramps[i1].Evaluate(u1,test.x0);
00595 ramps[i2].Evaluate(u2,test.x1);
00596 ramps[i1].Derivative(u1,test.dx0);
00597 ramps[i2].Derivative(u2,test.dx1);
00598 bool res=test.SolveMinTime(accMax,velMax);
00599 if(!res) return false;
00600 PARABOLIC_RAMP_ASSERT(test.endTime >= 0);
00601 PARABOLIC_RAMP_ASSERT(test.IsValid());
00602 }
00603 else {
00604 Vector x0,x1,dx0,dx1;
00605 ramps[i1].Evaluate(u1,x0);
00606 ramps[i2].Evaluate(u2,x1);
00607 ramps[i1].Derivative(u1,dx0);
00608 ramps[i2].Derivative(u2,dx1);
00609 vector<std::vector<ParabolicRamp1D> > intramps;
00610 Real res=SolveMinTimeBounded(x0,dx0,x1,dx1,
00611 accMax,velMax,xMin,xMax,
00612 intramps);
00613 if(res < 0) return false;
00614 CombineRamps(intramps,intermediate.ramps);
00615 intermediate.accMax = accMax;
00616 intermediate.velMax = velMax;
00617 PARABOLIC_RAMP_ASSERT(intermediate.IsValid());
00618 }
00619 for(size_t i=0;i<intermediate.ramps.size();i++)
00620 if(!check.Check(intermediate.ramps[i])) return false;
00621
00622
00623
00624 ramps[i1].TrimBack(ramps[i1].endTime-u1);
00625 ramps[i1].x1 = intermediate.ramps.front().x0;
00626 ramps[i1].dx1 = intermediate.ramps.front().dx0;
00627 ramps[i2].TrimFront(u2);
00628 ramps[i2].x0 = intermediate.ramps.back().x1;
00629 ramps[i2].dx0 = intermediate.ramps.back().dx1;
00630
00631
00632 for(int i=0;i<i2-i1-1;i++)
00633 ramps.erase(ramps.begin()+i1+1);
00634 ramps.insert(ramps.begin()+i1+1,intermediate.ramps.begin(),intermediate.ramps.end());
00635
00636
00637 for(size_t i=0;i+1<ramps.size();i++) {
00638 PARABOLIC_RAMP_ASSERT(ramps[i].x1 == ramps[i+1].x0);
00639 PARABOLIC_RAMP_ASSERT(ramps[i].dx1 == ramps[i+1].dx0);
00640 }
00641 return true;
00642 }
00643
00644 int DynamicPath::Shortcut(int numIters,RampFeasibilityChecker& check)
00645 {
00646 RandomNumberGeneratorBase rng;
00647 return Shortcut(numIters,check,&rng);
00648 }
00649
00650 int DynamicPath::Shortcut(int numIters,RampFeasibilityChecker& check,RandomNumberGeneratorBase* rng)
00651 {
00652 int shortcuts = 0;
00653 vector<Real> rampStartTime(ramps.size());
00654 Real endTime=0;
00655 for(size_t i=0;i<ramps.size();i++) {
00656 rampStartTime[i] = endTime;
00657 endTime += ramps[i].endTime;
00658 }
00659 Vector x0,x1,dx0,dx1;
00660 DynamicPath intermediate;
00661 intermediate.Init(velMax,accMax);
00662 intermediate.SetJointLimits(xMin,xMax);
00663 for(int iters=0;iters<numIters;iters++) {
00664 Real t1=rng->Rand()*endTime,t2=rng->Rand()*endTime;
00665 if(t1 > t2) Swap(t1,t2);
00666 int i1 = std::upper_bound(rampStartTime.begin(),rampStartTime.end(),t1)-rampStartTime.begin()-1;
00667 int i2 = std::upper_bound(rampStartTime.begin(),rampStartTime.end(),t2)-rampStartTime.begin()-1;
00668 if(i1 == i2) continue;
00669 Real u1 = t1-rampStartTime[i1];
00670 Real u2 = t2-rampStartTime[i2];
00671 PARABOLIC_RAMP_ASSERT(u1 >= 0);
00672 PARABOLIC_RAMP_ASSERT(u1 <= ramps[i1].endTime+EpsilonT);
00673 PARABOLIC_RAMP_ASSERT(u2 >= 0);
00674 PARABOLIC_RAMP_ASSERT(u2 <= ramps[i2].endTime+EpsilonT);
00675 u1 = Min(u1,ramps[i1].endTime);
00676 u2 = Min(u2,ramps[i2].endTime);
00677 ramps[i1].Evaluate(u1,x0);
00678 ramps[i2].Evaluate(u2,x1);
00679 ramps[i1].Derivative(u1,dx0);
00680 ramps[i2].Derivative(u2,dx1);
00681 bool res=SolveMinTime(x0,dx0,x1,dx1,accMax,velMax,xMin,xMax,intermediate);
00682 if(!res) continue;
00683 bool feas=true;
00684 for(size_t i=0;i<intermediate.ramps.size();i++)
00685 if(!check.Check(intermediate.ramps[i])) {
00686 feas=false;
00687 break;
00688 }
00689 if(!feas) continue;
00690
00691 shortcuts++;
00692 ramps[i1].TrimBack(ramps[i1].endTime-u1);
00693 ramps[i1].x1 = intermediate.ramps.front().x0;
00694 ramps[i1].dx1 = intermediate.ramps.front().dx0;
00695 ramps[i2].TrimFront(u2);
00696 ramps[i2].x0 = intermediate.ramps.back().x1;
00697 ramps[i2].dx0 = intermediate.ramps.back().dx1;
00698
00699
00700 for(int i=0;i<i2-i1-1;i++)
00701 ramps.erase(ramps.begin()+i1+1);
00702 ramps.insert(ramps.begin()+i1+1,intermediate.ramps.begin(),intermediate.ramps.end());
00703
00704
00705 for(size_t i=0;i+1<ramps.size();i++) {
00706 PARABOLIC_RAMP_ASSERT(ramps[i].x1 == ramps[i+1].x0);
00707 PARABOLIC_RAMP_ASSERT(ramps[i].dx1 == ramps[i+1].dx0);
00708 }
00709
00710
00711 rampStartTime.resize(ramps.size());
00712 endTime=0;
00713 for(size_t i=0;i<ramps.size();i++) {
00714 rampStartTime[i] = endTime;
00715 endTime += ramps[i].endTime;
00716 }
00717 }
00718 return shortcuts;
00719 }
00720
00721 int DynamicPath::ShortCircuit(RampFeasibilityChecker& check)
00722 {
00723 int shortcuts=0;
00724 DynamicPath intermediate;
00725 for(int i=0;i+1<(int)ramps.size();i++) {
00726 bool res=SolveMinTime(ramps[i].x0,ramps[i].dx0,ramps[i].x1,ramps[i].dx1,accMax,velMax,xMin,xMax,intermediate);
00727 if(!res) continue;
00728 bool feas=true;
00729 for(size_t j=0;j<intermediate.ramps.size();j++)
00730 if(!check.Check(intermediate.ramps[j])) {
00731 feas=false;
00732 break;
00733 }
00734 if(!feas) continue;
00735
00736 ramps.erase(ramps.begin()+i+1);
00737 ramps.insert(ramps.begin()+i+1,intermediate.ramps.begin(),intermediate.ramps.end());
00738 i += (int)intermediate.ramps.size()-2;
00739 shortcuts++;
00740 }
00741 return shortcuts;
00742 }
00743
00744
00745 int DynamicPath::OnlineShortcut(Real leadTime,Real padTime,RampFeasibilityChecker& check)
00746 {
00747 RandomNumberGeneratorBase rng;
00748 return OnlineShortcut(leadTime,padTime,check,&rng);
00749 }
00750
00751 int DynamicPath::OnlineShortcut(Real leadTime,Real padTime,RampFeasibilityChecker& check,RandomNumberGeneratorBase* rng)
00752 {
00753 Timer timer;
00754 int shortcuts = 0;
00755 vector<Real> rampStartTime(ramps.size());
00756 Real endTime=0;
00757 for(size_t i=0;i<ramps.size();i++) {
00758 rampStartTime[i] = endTime;
00759 endTime += ramps[i].endTime;
00760 }
00761 Vector x0,x1,dx0,dx1;
00762 DynamicPath intermediate;
00763 while(1) {
00764
00765 Real starttime = timer.ElapsedTime()-leadTime;
00766 if(starttime+padTime >= endTime) break;
00767 starttime = Max(0.0,starttime+padTime);
00768
00769 Real t1=starttime+Sqr(rng->Rand())*(endTime-starttime),t2=starttime+rng->Rand()*(endTime-starttime);
00770 if(t1 > t2) Swap(t1,t2);
00771 int i1 = std::upper_bound(rampStartTime.begin(),rampStartTime.end(),t1)-rampStartTime.begin()-1;
00772 int i2 = std::upper_bound(rampStartTime.begin(),rampStartTime.end(),t2)-rampStartTime.begin()-1;
00773 if(i1 == i2) continue;
00774 Real u1 = t1-rampStartTime[i1];
00775 Real u2 = t2-rampStartTime[i2];
00776 PARABOLIC_RAMP_ASSERT(u1 >= 0);
00777 PARABOLIC_RAMP_ASSERT(u1 <= ramps[i1].endTime+EpsilonT);
00778 PARABOLIC_RAMP_ASSERT(u2 >= 0);
00779 PARABOLIC_RAMP_ASSERT(u2 <= ramps[i2].endTime+EpsilonT);
00780 u1 = Min(u1,ramps[i1].endTime);
00781 u2 = Min(u2,ramps[i2].endTime);
00782 ramps[i1].Evaluate(u1,x0);
00783 ramps[i2].Evaluate(u2,x1);
00784 ramps[i1].Derivative(u1,dx0);
00785 ramps[i2].Derivative(u2,dx1);
00786 bool res=SolveMinTime(x0,dx0,x1,dx1,accMax,velMax,xMin,xMax,intermediate);
00787 if(!res) continue;
00788 bool feas=true;
00789 for(size_t i=0;i<intermediate.ramps.size();i++)
00790 if(!check.Check(intermediate.ramps[i])) {
00791 feas=false;
00792 break;
00793 }
00794 if(!feas) continue;
00795
00796 if(timer.ElapsedTime()-leadTime > t1) continue;
00797
00798 shortcuts++;
00799
00800 ramps[i1].TrimBack(ramps[i1].endTime-u1);
00801 ramps[i1].x1 = intermediate.ramps.front().x0;
00802 ramps[i1].dx1 = intermediate.ramps.front().dx0;
00803 ramps[i2].TrimFront(u2);
00804 ramps[i2].x0 = intermediate.ramps.back().x1;
00805 ramps[i2].dx0 = intermediate.ramps.back().dx1;
00806 PARABOLIC_RAMP_ASSERT(ramps[i1].IsValid());
00807 PARABOLIC_RAMP_ASSERT(ramps[i2].IsValid());
00808
00809
00810 for(int i=0;i<i2-i1-1;i++)
00811 ramps.erase(ramps.begin()+i1+1);
00812 ramps.insert(ramps.begin()+i1+1,intermediate.ramps.begin(),intermediate.ramps.end());
00813
00814
00815 for(size_t i=0;i+1<ramps.size();i++) {
00816 PARABOLIC_RAMP_ASSERT(ramps[i].x1 == ramps[i+1].x0);
00817 PARABOLIC_RAMP_ASSERT(ramps[i].dx1 == ramps[i+1].dx0);
00818 }
00819
00820
00821 rampStartTime.resize(ramps.size());
00822 endTime=0;
00823 for(size_t i=0;i<ramps.size();i++) {
00824 rampStartTime[i] = endTime;
00825 endTime += ramps[i].endTime;
00826 }
00827 }
00828 return shortcuts;
00829 }
00830
00831 bool DynamicPath::IsValid() const
00832 {
00833 if(ramps.empty()) {
00834 fprintf(stderr,"DynamicPath::IsValid: empty path\n");
00835 return false;
00836 }
00837 for(size_t i=0;i<ramps.size();i++) {
00838 if(!ramps[i].IsValid()) {
00839 fprintf(stderr,"DynamicPath::IsValid: ramp %d is invalid\n",i);
00840 return false;
00841 }
00842 for(size_t j=0;j<ramps[i].ramps.size();j++) {
00843 if(Abs(ramps[i].ramps[j].a1) > accMax[j]+EpsilonA ||
00844 Abs(ramps[i].ramps[j].v) > velMax[j] ||
00845 Abs(ramps[i].ramps[j].a2) > accMax[j]+EpsilonA) {
00846 fprintf(stderr,"DynamicPath::IsValid: invalid acceleration or velocity on ramp %d\n",i);
00847 fprintf(stderr,"\ta1 %g, v %g, a2 %g. amax %g, vmax %g\n",ramps[i].ramps[j].a1,ramps[i].ramps[j].v,ramps[i].ramps[j].a2,accMax[j],velMax[j]);
00848 return false;
00849 }
00850 }
00851 }
00852 for(size_t i=1;i<ramps.size();i++) {
00853 if(ramps[i].x0 != ramps[i-1].x1) {
00854 fprintf(stderr,"DynamicPath::IsValid: discontinuity at ramp %d\n",i);
00855 for(size_t j=0;j<ramps[i].x0.size();j++)
00856 fprintf(stderr,"%g ",ramps[i].x0[j]);
00857 fprintf(stderr,"\n");
00858 for(size_t j=0;j<ramps[i-1].x1.size();j++)
00859 fprintf(stderr,"%g ",ramps[i-1].x1[j]);
00860 fprintf(stderr,"\n");
00861 return false;
00862 }
00863 if(ramps[i].dx0 != ramps[i-1].dx1) {
00864 fprintf(stderr,"DynamicPath::IsValid: derivative discontinuity at ramp %d\n",i);
00865 for(size_t j=0;j<ramps[i].dx0.size();j++)
00866 fprintf(stderr,"%g ",ramps[i].dx0[j]);
00867 fprintf(stderr,"\n");
00868 for(size_t j=0;j<ramps[i-1].dx1.size();j++)
00869 fprintf(stderr,"%g ",ramps[i-1].dx1[j]);
00870 fprintf(stderr,"\n");
00871
00872 return false;
00873 }
00874 }
00875 return true;
00876 }
00877
00878 }