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 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 
00045 
00046 
00047 
00048 
00049 
00050 
00051 
00052 
00053 
00054 
00055 
00056 
00057 
00058 
00059 
00060 
00061 
00062 
00063 
00064 
00065 #include "collvoid_local_planner/orca.h"
00066 
00067 namespace collvoid{
00068 
00069 
00070   Line createOrcaLine(Agent* me, Agent* other, double trunc_time, double timestep, double left_pref, double cur_allowed_error){
00071 
00072     Vector2 relativePosition = other->getPosition() - me->getPosition();
00073     double combinedRadius = me->getRadius() + other->getRadius();
00074 
00075     return createOrcaLine(combinedRadius, relativePosition, me->getVelocity(), other->getVelocity(),trunc_time, timestep, left_pref, cur_allowed_error, other->controlled_);
00076   }  
00077   
00078   Line createOrcaLine(double combinedRadius, const Vector2& relativePosition, const Vector2& me_vel, const Vector2& other_vel, double trunc_time, double timestep, double left_pref, double cur_allowed_error, bool controlled){
00079 
00080     double invTimeHorizon = 1.0f / trunc_time;
00081     if (collvoid::abs(other_vel) < EPSILON){
00082       invTimeHorizon = 1.0f / 2.0;
00083       
00084     }
00085     
00086 
00087     
00088     const Vector2 relativeVelocity = me_vel - other_vel;
00089     const double distSq = absSqr(relativePosition);
00090     
00091     double combinedRadiusSq = sqr(combinedRadius);
00092 
00093     Line line;
00094     Vector2 u;
00095 
00096     if (distSq > combinedRadiusSq) {
00097       combinedRadius += cur_allowed_error; 
00098       combinedRadiusSq = sqr(combinedRadius);
00099       
00100       const Vector2 w = relativeVelocity - invTimeHorizon * relativePosition;
00101       
00102       const double wLengthSq = absSqr(w);
00103 
00104       const double dotProduct1 = w * relativePosition;
00105 
00106       if (dotProduct1 < 0.0f && sqr(dotProduct1) > combinedRadiusSq * wLengthSq) {
00107         
00108         const double wLength = std::sqrt(wLengthSq);
00109         const Vector2 unitW = w / wLength;
00110 
00111         line.dir = Vector2(unitW.y(), -unitW.x());
00112         u = (combinedRadius * invTimeHorizon - wLength) * unitW;
00113       } else {
00114         
00115         const double leg = std::sqrt(distSq - combinedRadiusSq);
00116 
00117         if (det(relativePosition, w) > -left_pref) { 
00118           
00119           line.dir = Vector2(relativePosition.x() * leg - relativePosition.y() * combinedRadius, relativePosition.x() * combinedRadius + relativePosition.y() * leg) / distSq;
00120         } else {
00121           
00122           line.dir = -Vector2(relativePosition.x() * leg + relativePosition.y() * combinedRadius, -relativePosition.x() * combinedRadius + relativePosition.y() * leg) / distSq;
00123         }
00124 
00125         const double dotProduct2 = relativeVelocity * line.dir;
00126 
00127         u = dotProduct2 * line.dir - relativeVelocity;
00128       }
00129     } else {
00130       
00131       const double invTimeStep = 1.0f/timestep;
00132       
00133       const Vector2 w = relativeVelocity - invTimeStep * relativePosition;
00134 
00135       const double wLength = abs(w);
00136       const Vector2 unitW = w / wLength;
00137       
00138       line.dir = Vector2(unitW.y(), -unitW.x());
00139       u = (combinedRadius * invTimeStep - wLength) * unitW;
00140     }
00141 
00142     double factor = 0.5;
00143     if (!controlled) {
00144       factor = 1.0;
00145     }
00146     line.point = me_vel + factor * u;
00147     
00148     return line;
00149   }
00150 
00151   Line createStationaryAgent(Agent* me, Agent* other) {
00152     double dist = collvoid::abs(me->getPosition() - other->getPosition());
00153     Line line;
00154     Vector2 relative_position = other->getPosition() - me->getPosition();
00155     line.point = normalize(relative_position) * (dist - me->getRadius() - other->getRadius() - 0.05);
00156 
00157     line.dir = Vector2 (-normalize(relative_position).y(),normalize(relative_position).x()) ; 
00158     
00159     return line;
00160   
00161   }
00162 
00163 
00164   void addAccelerationConstraintsXY(double max_vel_x, double acc_lim_x, double max_vel_y, double acc_lim_y, Vector2 cur_vel, double heading, double sim_period, bool holo_robot, std::vector<Line>& additional_orca_lines){
00165     double max_lim_x, max_lim_y, min_lim_x, min_lim_y;
00166     Line line_x_back, line_x_front, line_y_left, line_y_right;
00167   
00168     Vector2 dir_front =  Vector2(cos(heading), sin(heading));
00169     Vector2 dir_right =  Vector2(dir_front.y(),-dir_front.x());
00170     if(holo_robot) {
00171 
00172       cur_vel = rotateVectorByAngle(cur_vel.x(), cur_vel.y(), -heading);
00173 
00174       double cur_x = cur_vel.x();
00175       double cur_y = cur_vel.y();
00176 
00177       
00178       max_lim_x = std::min(max_vel_x, cur_x + sim_period * acc_lim_x);
00179       max_lim_y = std::min(max_vel_y, cur_y + sim_period * acc_lim_y);
00180       min_lim_x = std::max(-max_vel_x, cur_x - sim_period * acc_lim_x);
00181       min_lim_y = std::max(-max_vel_y, cur_y - sim_period * acc_lim_y);
00182 
00183       
00184 
00185       line_x_front.point = dir_front * max_lim_x;
00186       line_x_front.dir =  -dir_right;
00187 
00188       line_x_back.point = dir_front * min_lim_x;
00189       line_x_back.dir = dir_right;
00190   
00191   
00192       additional_orca_lines.push_back(line_x_front);
00193       additional_orca_lines.push_back(line_x_back);
00194   
00195       line_y_left.point = -dir_right * max_lim_y;
00196       line_y_left.dir = -dir_front;
00197 
00198       line_y_right.point = -dir_right * min_lim_y;
00199       line_y_right.dir = dir_front;
00200   
00201   
00202       additional_orca_lines.push_back(line_y_left);
00203       additional_orca_lines.push_back(line_y_right);
00204     }
00205     else {
00206 
00207       double cur_x = collvoid::abs(cur_vel);
00208       max_lim_x = std::min(max_vel_x, cur_x + sim_period * acc_lim_x);
00209       min_lim_x = std::max(-max_vel_x, cur_x - sim_period * acc_lim_x);
00210 
00211       line_x_front.point = dir_front * max_lim_x;
00212       line_x_front.dir =  -dir_right;
00213       
00214       line_x_back.point = dir_front * min_lim_x;
00215       line_x_back.dir = dir_right;
00216   
00217       
00218       additional_orca_lines.push_back(line_x_front);
00219       additional_orca_lines.push_back(line_x_back);
00220   
00221      
00222     }
00223   }
00224   
00225   void addMovementConstraintsDiffSimple(double max_track_speed, double heading, std::vector<Line>& additional_orca_lines) {
00226     Line maxVel1;
00227     Line maxVel2;
00228 
00229     Vector2 dir =  Vector2(cos(heading), sin(heading));
00230     maxVel1.point = 0.95*max_track_speed * Vector2(-dir.y(),dir.x());
00231     maxVel1.dir = -dir;
00232     maxVel2.dir = dir;
00233     maxVel2.point = -max_track_speed * Vector2(-dir.y(),dir.x());
00234     additional_orca_lines.push_back(maxVel1);
00235     additional_orca_lines.push_back(maxVel2);
00236     
00237     
00238     
00239     
00240     
00241     
00242     
00243     
00244     
00245     
00246     
00247     
00248 
00249 
00250   }
00251 
00252   void addMovementConstraintsDiff(double error, double T,  double max_vel_x, double max_vel_th, double heading, double v_max_ang, std::vector<Line>& additional_orca_lines){
00253     
00254     
00255     
00256     
00257     
00258     
00259     
00260     
00261     
00262     
00263 
00264     
00265     
00266     
00267     
00268     
00269 
00270 
00271     double min_theta = M_PI / 2.0;
00272     double max_track_speed = calculateMaxTrackSpeedAngle(T,min_theta, error, max_vel_x, max_vel_th, v_max_ang);
00273 
00274     Vector2 first_point = max_track_speed * Vector2(cos(heading - min_theta), sin(heading - min_theta));
00275     double steps = 10.0;
00276     double step_size = - M_PI / steps;
00277     
00278     
00279     
00280     
00281 
00282 
00283     for (int i=1; i<=(int)steps; i++) {
00284     
00285       Line line;
00286       double cur_ang = min_theta + i* step_size;
00287       Vector2 second_point = Vector2(cos(heading - cur_ang), sin(heading - cur_ang));
00288       double track_speed = calculateMaxTrackSpeedAngle(T,cur_ang, error, max_vel_x, max_vel_th, v_max_ang);
00289       second_point = track_speed * second_point;
00290       line.point = first_point;
00291       line.dir = normalize(second_point - first_point);
00292       additional_orca_lines.push_back(line);
00293       
00294       first_point = second_point;
00295     }
00296   }
00297 
00298   double beta(double T, double theta, double v_max_ang){
00299     return - ((2.0 * T * T * sin(theta)) / theta) * v_max_ang;
00300   }
00301 
00302   double gamma(double T, double theta, double error, double v_max_ang) {
00303     return ((2.0 * T * T * (1.0 - cos(theta))) / (theta * theta)) * v_max_ang * v_max_ang - error * error;
00304   }
00305 
00306   double calcVstar(double vh, double theta){
00307     return vh * ((theta * sin(theta))/(2.0 * (1.0 - cos(theta))));
00308   }
00309 
00310   double calcVstarError(double T,double theta, double error) {
00311     return calcVstar(error/T,theta) * sqrt((2.0*(1.0-cos(theta)))/(2.0*(1.0-cos(theta))-collvoid::sqr(sin(theta))));
00312   }
00313 
00314   double calculateMaxTrackSpeedAngle(double T, double theta, double error, double max_vel_x, double max_vel_th, double v_max_ang){
00315     if (fabs(theta) <= EPSILON)
00316       return max_vel_x;
00317     if (fabs(theta/T) <= max_vel_th) {
00318       double vstar_error = calcVstarError(T,theta,error);
00319       if (vstar_error <= v_max_ang) { 
00320         
00321         return std::min(vstar_error * (2.0 * (1.0 - cos(theta))) / (theta*sin(theta)),max_vel_x);
00322       }
00323       else {
00324         double a, b, g;
00325         a = T * T;
00326         b = beta(T,theta,v_max_ang);
00327         g = gamma(T,theta,error, v_max_ang);
00328         
00329         return std::min((-b+sqrt(collvoid::sqr(b)-4*collvoid::sqr(a)*g))/ (2.0 * g), max_vel_x);
00330       }
00331     }
00332     else
00333       
00334       return std::min(sign(theta)*error*max_vel_th/theta,max_vel_x);
00335   }
00336 
00337 
00338 
00339   
00340 
00341   bool linearProgram1(const std::vector<Line>& lines, size_t lineNo, float radius, const Vector2& optVelocity, bool dirOpt, Vector2& result)
00342   {
00343     const float dotProduct = lines[lineNo].point * lines[lineNo].dir;
00344     const float discriminant = sqr(dotProduct) + sqr(radius) - absSqr(lines[lineNo].point);
00345     
00346     if (discriminant < 0.0f) {
00347       
00348       return false;
00349     }
00350     
00351     const float sqrtDiscriminant = std::sqrt(discriminant);
00352     float tLeft = -dotProduct - sqrtDiscriminant;
00353     float tRight = -dotProduct + sqrtDiscriminant;
00354     
00355     for (size_t i = 0; i < lineNo; ++i) {
00356       const float denominator = det(lines[lineNo].dir, lines[i].dir);
00357       const float numerator = det(lines[i].dir, lines[lineNo].point - lines[i].point);
00358 
00359       if (std::fabs(denominator) <= EPSILON) {
00360         
00361         if (numerator < 0.0f) {
00362           return false;
00363         } else {
00364           continue;
00365         }
00366       }
00367 
00368       const float t = numerator / denominator;
00369 
00370       if (denominator >= 0.0f) {
00371         
00372         tRight = std::min(tRight, t);
00373       } else {
00374         
00375         tLeft = std::max(tLeft, t);
00376       }
00377 
00378       if (tLeft > tRight) {
00379         return false;
00380       }
00381     }
00382 
00383     if (dirOpt) {
00384       
00385       if (optVelocity * lines[lineNo].dir > 0.0f) {
00386         
00387         result = lines[lineNo].point + tRight * lines[lineNo].dir;
00388       } else {
00389         
00390         result = lines[lineNo].point + tLeft * lines[lineNo].dir;
00391       }
00392     } else {
00393       
00394       const float t = lines[lineNo].dir * (optVelocity - lines[lineNo].point);
00395 
00396       if (t < tLeft) {
00397         result = lines[lineNo].point + tLeft * lines[lineNo].dir;
00398       } else if (t > tRight) {
00399         result = lines[lineNo].point + tRight * lines[lineNo].dir;
00400       } else {
00401         result = lines[lineNo].point + t * lines[lineNo].dir;
00402       }
00403     }
00404 
00405     return true;
00406   }
00407 
00408   size_t linearProgram2(const std::vector<Line>& lines, float radius, const Vector2& optVelocity, bool dirOpt, Vector2& result)
00409   {
00410     if (dirOpt) {
00411       
00412 
00413 
00414 
00415       result = optVelocity * radius;
00416     } else if (absSqr(optVelocity) > sqr(radius)) {
00417       
00418       result = normalize(optVelocity) * radius;
00419     } else {
00420       
00421       result = optVelocity;
00422     }
00423 
00424     for (size_t i = 0; i < lines.size(); ++i) {
00425       if (det(lines[i].dir, lines[i].point - result) > 0.0f) {
00426         
00427         const Vector2 tempResult = result;
00428         if (!linearProgram1(lines, i, radius, optVelocity, dirOpt, result)) {
00429           result = tempResult;
00430           return i;
00431         }
00432       }
00433     }
00434 
00435     return lines.size();
00436   }
00437 
00438   void linearProgram3(const std::vector<Line>& lines, size_t numObstLines, size_t beginLine, float radius, Vector2& result)
00439   {
00440     float distance = 0.0f;
00441 
00442     for (size_t i = beginLine; i < lines.size(); ++i) {
00443       if (det(lines[i].dir, lines[i].point - result) > distance) {
00444         
00445         std::vector<Line> projLines(lines.begin(), lines.begin() + numObstLines);
00446 
00447         for (size_t j = numObstLines; j < i; ++j) {
00448           Line line;
00449 
00450           float determinant = det(lines[i].dir, lines[j].dir);
00451 
00452           if (std::fabs(determinant) <= EPSILON) {
00453             
00454             if (lines[i].dir * lines[j].dir > 0.0f) {
00455               
00456               continue;
00457             } else {
00458               
00459               line.point = 0.5f * (lines[i].point + lines[j].point);
00460             }
00461           } else {
00462             line.point = lines[i].point + (det(lines[j].dir, lines[i].point - lines[j].point) / determinant) * lines[i].dir;
00463           }
00464 
00465           line.dir = normalize(lines[j].dir - lines[i].dir);
00466           projLines.push_back(line);
00467         }
00468 
00469         const Vector2 tempResult = result;
00470         if (linearProgram2(projLines, radius, Vector2(-lines[i].dir.y(), lines[i].dir.x()), true, result) < projLines.size()) {
00471           
00472 
00473 
00474 
00475 
00476           result = tempResult;
00477         }
00478 
00479         distance = det(lines[i].dir, lines[i].point - result);
00480       }
00481     }
00482   }
00483 
00484 
00485 
00486 
00487 }
00488 
00489