00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 #include <angles/angles.h>
00011 
00012 #include <art/DARPA_rules.h>
00013 
00014 #include "navigator_internal.h"
00015 #include "course.h"
00016 #include <art/steering.h>
00017 #include <art_map/coordinates.h>
00018 #include <art_nav/estimate.h>
00019 using art_msgs::ArtVehicle;
00020 using Coordinates::bearing;
00021 using Coordinates::normalize;
00022 
00024 #include <art_map/rotate_translate_transform.h>
00025 
00026 
00027 Course::Course(Navigator *_nav, int _verbose)
00028 {
00029   verbose = _verbose;
00030   nav = _nav;
00031 
00032   
00033   estimate = &nav->estimate;
00034   navdata = &nav->navdata;
00035   odom = nav->odometry;
00036   order = &nav->order;
00037   pops = nav->pops;
00038   config_ = &nav->config_;
00039 
00040   
00041   plan.clear();
00042   polygons.clear();
00043 
00044   for (unsigned i = 0; i < 2; ++i)
00045     adj_polys[i].clear();
00046   passing_lane = -1;
00047   passed_lane.clear();
00048 
00049   last_error=0;
00050 
00051   reset();
00052 }
00053 
00054 
00055 
00056 
00057 
00058 
00059 
00060 void Course::begin_run_cycle(void)
00061 {
00062   waypoint_checked = false;
00063 
00064   
00065   
00066   
00067   
00068 
00069   
00070   if (0 <= (poly_index = pops->getContainingPoly(plan,
00071                                                  MapPose(estimate->pose.pose))))
00072     {
00073       
00074       
00075       poly_index = pops->getPolyIndex(polygons, plan.at(poly_index));
00076     }
00077   else
00078     {
00079       
00080       poly_index = pops->getContainingPoly(polygons,
00081                                            MapPose(estimate->pose.pose));
00082     }
00083 
00084   
00085   if (poly_index < 0)                   
00086     navdata->cur_poly = -1;             
00087   else
00088     navdata->cur_poly = polygons.at(poly_index).poly_id;
00089 
00090   
00091   
00092   
00093   int limit = art_msgs::Order::N_WAYPTS; 
00094   while (ElementID(order->waypt[0].id) != ElementID(navdata->last_waypt)
00095          && --limit > 0)
00096     {
00097       ROS_DEBUG_STREAM("waypoint " << ElementID(order->waypt[1].id).name().str
00098                        << " already reached, advance order->waypt[] array");
00099       
00100       for (unsigned i = 1; i < art_msgs::Order::N_WAYPTS; ++i)
00101         order->waypt[i-1] = order->waypt[i];
00102     }
00103 
00104   
00105   for (unsigned i = 0; i < art_msgs::Order::N_WAYPTS; ++i)
00106     ROS_DEBUG("waypt[%u] %s (%.3f,%.3f), E%d G%d L%d P%d S%d X%d Z%d",
00107               i, ElementID(order->waypt[i].id).name().str,
00108               order->waypt[i].mapxy.x,
00109               order->waypt[i].mapxy.y,
00110               (bool) order->waypt[i].is_entry,
00111               (bool) order->waypt[i].is_goal,
00112               (bool) order->waypt[i].is_lane_change,
00113               (bool) order->waypt[i].is_spot,
00114               (bool) order->waypt[i].is_stop,
00115               (bool) order->waypt[i].is_exit,
00116               (bool) order->waypt[i].is_perimeter);
00117 }
00118 
00119 void Course::configure()
00120 {
00121   
00122   lane_change_secs = config_->lane_change_secs;
00123   
00124   heading_change_ratio = config_->heading_change_ratio;
00125   turning_latency = config_->turning_latency;
00126   k_error = config_->turning_offset_tune;
00127   k_theta = config_->turning_heading_tune;
00128   
00129   k_int = config_->turning_int_tune;
00130   
00131   min_lane_steer_dist = config_->min_lane_steer_dist;
00132   max_speed_for_sharp = config_->max_speed_for_sharp;
00133   spring_lookahead = config_->spring_lookahead;
00134   max_yaw_rate = config_->real_max_yaw_rate;
00135   zone_waypoint_radius = config_->zone_waypoint_radius;
00136   
00137   spot_waypoint_radius = config_->spot_waypoint_radius;
00138 
00139 #if 0
00140   ros::NodeHandle nh("~");
00141 
00142   
00143   nh.param("lane_change_secs", lane_change_secs, 2.0);
00144   ROS_INFO("lane change target is %.3f seconds ahead",
00145           lane_change_secs);
00146 
00147   
00148   nh.param("lane_steer_time", lane_steer_time, 2.0);
00149   ROS_INFO("lane steering time is %.3f seconds", lane_steer_time);
00150 
00151   nh.param("heading_change_ratio", heading_change_ratio, 0.75);
00152   ROS_INFO("heading change ratio is %.3f", heading_change_ratio);
00153 
00154   nh.param("turning_latency", turning_latency, 1.0);
00155   ROS_INFO("turning latency time is %.3f seconds", 1.0);
00156 
00157   
00158   nh.param("turning_offset_tune", k_error, 0.5);
00159   ROS_INFO("yaw tuning parameter (offset) is %.3f", k_error);
00160 
00161   
00162   nh.param("turning_heading_tune", k_theta, sqrt(k_error/2));
00163   ROS_INFO("yaw tuning parameter (heading) is %.3f", k_theta);
00164 
00165   
00166   nh.param("yaw_ratio", yaw_ratio, 0.75);
00167   ROS_INFO("yaw ratio is %.3f", yaw_ratio);
00168 
00169   
00170   nh.param("turning_int_tune", k_int, 1.25);
00171   ROS_INFO("yaw tuning parameter (integral) is %.3f", k_int);
00172 
00173   
00174   
00175   nh.param("min_lane_change_dist", min_lane_change_dist,
00176            (double) (DARPA_rules::min_forw_sep_travel
00177                      + ArtVehicle::front_bumper_px));
00178   ROS_INFO("minimum lane change distance is %.3f meters",
00179           min_lane_change_dist);
00180 
00181   
00182   
00183   nh.param("min_lane_steer_dist", min_lane_steer_dist,
00184            (double) ArtVehicle::front_bumper_px);
00185   ROS_INFO("minimum lane steering distance is %.3f meters",
00186           min_lane_steer_dist);
00187 
00188   
00189   nh.param("max_speed_for_sharp", max_speed_for_sharp ,3.0); 
00190   ROS_INFO("maximum speed to go full yaw is %.3f m/s", max_speed_for_sharp);
00191 
00192   
00193   nh.param("spring_lookahead", spring_lookahead, 0.0);
00194   ROS_INFO("spring lookahead distance is %.3f m", spring_lookahead);
00195 
00196   nh.param("real_max_yaw_rate", max_yaw_rate, Steering::maximum_yaw);
00197   ROS_INFO("real maximum yaw rate is %.3f (radians/s)", max_yaw_rate);
00198 
00199   nh.param("zone_waypoint_radius", zone_waypoint_radius, 1.0);
00200   ROS_INFO("zone waypoint radius is %.3f m", zone_waypoint_radius);
00201 
00202   nh.param("zone_perimeter_radius", zone_perimeter_radius, 2.0);
00203   ROS_INFO("zone perimeter radius is %.3f m", zone_perimeter_radius);
00204 
00205   nh.param("spot_waypoint_radius", spot_waypoint_radius, 0.5);
00206   ROS_INFO("spot waypoint radius is %.3f m", spot_waypoint_radius);
00207 #endif
00208 }
00209 
00220 void Course::desired_heading(pilot_command_t &pcmd, float offset_ratio)
00221 {
00222   if (Epsilon::equal(pcmd.velocity, 0.0))
00223     return;
00224 
00225   Polar aim_polar;                      
00226   
00227   float aim_next_heading = 0;
00228   float aim_distance = 0;
00229   bool aim_in_plan = false;
00230   int aim_index = -1;
00231   float used_velocity = estimate->twist.twist.linear.x;
00232   float target_dist = min_lane_steer_dist;
00233 
00234   if (plan.empty())
00235     {
00236       
00237       ROS_WARN_THROTTLE(40, "no lane data available, steer using waypoints.");
00238       aim_polar = head_for_waypt(target_dist);
00239       aim_distance = aim_polar.range;
00240       aim_next_heading =
00241         normalize(MapPose(estimate->pose.pose).yaw + aim_polar.heading);
00242     }
00243   else 
00244     {
00245       
00246       aim_index = pops->getPolyIndex(plan, aim_poly);
00247 
00248       poly_list_t edge;
00249       pops->add_polys_for_waypts(plan,edge,order->waypt[0].id,
00250                                  order->waypt[1].id);
00251 
00252       
00253       int nearby_poly =
00254         pops->getClosestPoly(edge, MapPose(estimate->pose.pose));
00255       if (nearby_poly >= 0)
00256         nearby_poly = pops->getPolyIndex(plan,edge.at(nearby_poly));
00257       else
00258         nearby_poly = pops->getClosestPoly(plan, MapPose(estimate->pose.pose));
00259 
00260       if (aim_poly.poly_id != -1
00261           && aim_index >= 0
00262           && aim_index < (int) plan.size() - 1)
00263         {
00264           if (nearby_poly >= 0)
00265             {
00266               int aim_index2 = pops->index_of_downstream_poly
00267                 (plan,nearby_poly,target_dist);       
00268           
00269               if (aim_index2 > aim_index && aim_index2 < (int) plan.size()-1) 
00270                 {
00271                   aim_index = aim_index2;
00272                   aim_poly.poly_id = -1; 
00273                 }
00274             }
00275 
00276           aim_distance = Euclidean::DistanceTo(plan.at(aim_index+1).midpoint,
00277                                                plan.at(aim_index).midpoint);
00278           aim_next_heading = atan2f(plan.at(aim_index+1).midpoint.y-
00279                                     plan.at(aim_index).midpoint.y,
00280                                     plan.at(aim_index+1).midpoint.x-
00281                                     plan.at(aim_index).midpoint.x);
00282 
00283           aim_in_plan = true;
00284           
00285           ROS_DEBUG("steering down the lane toward polygon %d",
00286                     plan.at(aim_index).poly_id);
00287         }
00288       else
00289         {
00290           if (nearby_poly >= 0)
00291             {
00292               ROS_DEBUG("nearby_poly in desired_heading() is %d",
00293                         plan.at(nearby_poly).poly_id);
00294               
00295               
00296               
00297               aim_index =
00298                 pops->index_of_downstream_poly(plan, nearby_poly,
00299                                                target_dist);
00300               if (aim_index >= 0 && aim_index < (int)plan.size()-1)
00301                 {
00302                   
00303                   aim_distance =
00304                     Euclidean::DistanceTo(plan.at(aim_index+1).midpoint,
00305                                           plan.at(aim_index).midpoint);
00306 
00307                   aim_next_heading = atan2f(plan.at(aim_index+1).midpoint.y-
00308                                             plan.at(aim_index).midpoint.y,
00309                                             plan.at(aim_index+1).midpoint.x-
00310                                             plan.at(aim_index).midpoint.x);
00311 
00312                   aim_in_plan = true;
00313                   
00314                   ROS_DEBUG("steering at least %.3fm "
00315                             "down the lane toward polygon %d",
00316                             target_dist, plan.at(aim_index).poly_id);
00317                 }
00318               else
00319                 {
00320                   
00321                   ROS_WARN_THROTTLE(40, "no polygon at least %.3fm away, "
00322                                      "steer using waypoints", target_dist);
00323                   aim_polar = head_for_waypt(target_dist);
00324                   
00325                   aim_distance = aim_polar.range;
00326                   aim_next_heading =
00327                     normalize(MapPose(estimate->pose.pose).yaw
00328                               + aim_polar.heading);
00329                 }
00330             }
00331           else
00332             {
00333               
00334               
00335               
00336               ROS_WARN_THROTTLE(40, "no lane data available, "
00337                                 "steer using waypoints.");
00338               aim_polar = head_for_waypt(target_dist);
00339               aim_distance = aim_polar.range;
00340               aim_next_heading =
00341                 normalize (MapPose(estimate->pose.pose).yaw
00342                            + aim_polar.heading);
00343             }
00344         }
00345     }
00346   
00347   
00348   ROS_DEBUG("desired, current positions: (%.3f, %.3f), (%.3f, %.3f, %.3f)",
00349             order->waypt[1].mapxy.x, order->waypt[1].mapxy.y,
00350             estimate->pose.pose.position.x,
00351             estimate->pose.pose.position.y,
00352             MapPose(estimate->pose.pose).yaw);
00353   
00354   float full_heading_change =
00355     fabs(normalize(aim_next_heading-MapPose(estimate->pose.pose).yaw));
00356   
00357   float max_speed_to_hit_aim = 
00358     max_speed_for_change_in_heading(full_heading_change,
00359                                     aim_distance,
00360                                     pcmd.velocity,
00361                                     max_yaw_rate);
00362 
00363   pcmd.velocity = fminf(pcmd.velocity,
00364                         max_speed_to_hit_aim);
00365   
00366 
00367 
00368 #if 0
00369   if (pcmd.velocity>used_velocity)
00370     used_velocity += fminf(pcmd.velocity-used_velocity,1.0*turning_latency);
00371   else if (pcmd.velocity < used_velocity)
00372     used_velocity-=fminf(used_velocity-pcmd.velocity,1.0*turning_latency);
00373 #endif
00374 
00375 #if 1
00376   used_velocity = fmaxf(pcmd.velocity,used_velocity);
00377 #endif
00378   
00379 #if 0
00380   used_velocity = fminf(used_velocity,pcmd.velocity);
00381 #endif
00382 
00383   ROS_DEBUG("Thresholding speed to %.3f m/s", used_velocity);
00384 
00385   float spring_yaw;
00386   if (aim_in_plan)
00387     spring_yaw = get_yaw_spring_system(aim_polar, aim_index, 
00388                                      aim_next_heading,
00389                                      max_yaw_rate, used_velocity,
00390                                      offset_ratio);
00391   else
00392     spring_yaw = get_yaw_spring_system(aim_polar, -1, aim_next_heading,
00393                                      max_yaw_rate, used_velocity);
00394   
00395   pcmd.yawRate = spring_yaw;
00396 
00397 #if 0
00398   if (Epsilon::equal(pcmd.yawRate,max_yaw_rate))
00399     pcmd.velocity = fminf(pcmd.velocity,Steering::steer_speed_min);
00400 #endif  
00401 
00402   nav->trace_controller("desired_heading", pcmd);
00403 }
00404 
00405 
00406 float Course::distance_in_plan(const MapPose &from,
00407                                const WayPointNode &wp) const
00408 {
00409   if (plan.empty())
00410     return Euclidean::DistanceToWaypt(from, wp);
00411   else return pops->distanceAlongLane(plan, from.map, wp.map);
00412 }
00413 
00414 
00415 float Course::distance_in_plan(const MapPose &from,
00416                                const MapPose &to) const
00417 {
00418   if (plan.empty())
00419     return Euclidean::DistanceTo(from, to);
00420   else return pops->distanceAlongLane(plan, from.map, to.map);
00421 }
00422 
00423 float Course::distance_in_plan(const MapPose &from,
00424                                const MapXY &to) const
00425 {
00426   if (plan.empty())
00427     return Euclidean::DistanceTo(from.map, to);
00428   else return pops->distanceAlongLane(plan, from.map,to);
00429 }
00430 
00431 
00432 
00433 
00434 
00435 
00436 
00437 
00438 void Course::end_run_cycle()
00439 {
00440   if (!waypoint_checked)
00441     ROS_ERROR("failed to check for way-point reached!");
00442 }
00443 
00444 
00445 
00446 
00447 
00448 
00449 
00450 
00451 
00452 int Course::find_aim_polygon(poly_list_t &lane)
00453 {
00454 
00455   poly_list_t edge;
00456   pops->add_polys_for_waypts(lane,edge,order->waypt[0].id,
00457                              order->waypt[1].id);
00458   
00459   
00460   int nearby_poly = pops->getClosestPoly(edge, MapPose(estimate->pose.pose));
00461   if (nearby_poly < 0)
00462     nearby_poly = pops->getClosestPoly(lane, MapPose(estimate->pose.pose));
00463   else
00464     nearby_poly = pops->getPolyIndex(lane,edge.at(nearby_poly));
00465 
00466   if (nearby_poly < 0)
00467     return -1;
00468   
00469 #if 1  
00470   float aim_distance = min_lane_steer_dist;
00471   
00472   ROS_DEBUG("aim point %.3fm ahead", aim_distance);
00473   
00474   return pops->index_of_downstream_poly(lane, nearby_poly, aim_distance);
00475 
00476 #else
00477 
00478   
00479   float lane_distance =
00480     pops->getShortestDistToPoly(MapPose(estimate->pose.pose), lane.at(nearby_poly));
00481   
00482   if (Epsilon::equal(lane_distance,0.0))
00483     return -1;
00484    
00485   float lane_change_distance_ratio = estimate->vel.x;
00486   float aim_distance;
00487 
00488   if (req_max_dist < Infinite::distance)
00489     aim_distance = req_max_dist;
00490   else 
00491     {  
00492       
00493       aim_distance = fminf(lane_distance * lane_change_distance_ratio,
00494                            estimate->vel.x * lane_change_secs);
00495     }
00496 
00497   float max_pass_distance = ArtVehicle::length*4;
00498 
00499   
00500   aim_distance = fminf(max_pass_distance,aim_distance);
00501 
00502   if (order->waypt[1].is_goal)
00503     {
00504       float way_dist = distance_in_plan(MapPose(estimate->pose.pose),
00505                                         order->waypt[1]);
00506       aim_distance = fminf(aim_distance,way_dist);
00507     }
00508 
00509   
00510   aim_distance = fmaxf(aim_distance, ArtVehicle::front_bumper_px);
00511 
00512   ROS_DEBUG("lane is %.3fm away, aim point %.3fm ahead",
00513             lane_distance, aim_distance);
00514   
00515   return pops->index_of_downstream_poly(lane, nearby_poly, aim_distance);
00516   
00517 #endif
00518 }
00519 
00520 
00521 
00522 
00523 
00524 
00525 
00526 
00527 
00528 
00529 
00530 
00531 
00532 
00533 
00534 
00535 
00536 bool Course::find_passing_lane(void)
00537 {
00538   ROS_DEBUG("find passing lane around waypoint %s",
00539             ElementID(order->waypt[1].id).name().str);
00540 
00541   
00542   adj_lane[0] = order->waypt[1].id;
00543   --adj_lane[0].lane;                   
00544 
00545   adj_lane[1] = order->waypt[1].id;
00546   ++adj_lane[1].lane;                   
00547 
00548 #if 1 // more general implementation, experimental
00549 
00550   int cur_index = pops->getClosestPoly(plan, MapPose(estimate->pose.pose));
00551   if (cur_index == -1)
00552     {
00553       ROS_WARN("no polygon nearby in plan");
00554       return false;
00555     }
00556   poly cur_poly = plan.at(cur_index);
00557   
00558   
00559   
00560   int left_lane = -1;                   
00561   int right_lane = -1;                  
00562   bool adj_forw[2];                     
00563 
00564   for (unsigned i = 0; i < 2; ++i)
00565     {
00566       adj_lane[i].pt = 0;               
00567       adj_polys[i].clear();
00568       if (adj_lane[i].lane == 0)        
00569         continue;
00570 
00571       
00572       pops->AddLanePolys(polygons, adj_polys[i], adj_lane[i]);
00573       int this_index =
00574         pops->getClosestPoly(adj_polys[i],
00575                              MapXY(order->waypt[1].mapxy));
00576       if (this_index < 0)               
00577         continue;
00578 
00579       
00580       poly this_poly = adj_polys[i].at(this_index);
00581       if (pops->left_of_poly(this_poly, cur_poly))
00582         left_lane = i;
00583       else
00584         right_lane = i;
00585 
00586       
00587       adj_forw[i] = pops->same_direction(cur_poly, this_poly, HALFPI);
00588       if (!adj_forw[i])
00589         {
00590           
00591           adj_polys[i].clear();
00592           pops->AddReverseLanePolys(polygons, adj_polys[i], adj_lane[i]);
00593         }
00594 
00595       if (verbose >= 4)
00596         log(adj_lane[i].lane_name().str, adj_polys[i]);
00597     }
00598 
00599   
00600   if (right_lane >= 0
00601       && adj_forw[right_lane])
00602     passing_lane = right_lane;          
00603   else if (left_lane >= 0
00604            && adj_forw[left_lane])
00605     passing_lane = left_lane;           
00606   else if (right_lane >= 0)
00607     passing_lane = right_lane;          
00608   else if (left_lane >= 0)
00609     passing_lane = left_lane;           
00610   else
00611     {
00612       passing_lane = -1;
00613       ROS_WARN("no passing lane available for waypoint %s",
00614                ElementID(order->waypt[1].id).name().str);
00615       return false;
00616     }
00617 
00618   
00619   passing_left = (passing_lane == left_lane);
00620 
00621   ROS_INFO("passing lane %s selected, to %s going %s",
00622            adj_lane[passing_lane].lane_name().str,
00623            (passing_left? "left": "right"),
00624            (adj_forw[passing_lane]? "forward": "backward"));
00625 
00626 #else // old version
00627 
00628   for (unsigned i = 0; i < 2; ++i)
00629     {
00630       
00631       
00632       
00633       adj_lane[i].pt = 0;               
00634       adj_polys[i].clear();
00635       if (adj_lane[i].lane > 0) 
00636         {
00637           pops->AddReverseLanePolys(polygons, adj_polys[i], adj_lane[i]);
00638         }
00639       if (verbose >= 4)
00640         log(adj_lane[i].lane_name().str, adj_polys[i]);
00641     }
00642 
00643   
00644   passing_lane = 1;
00645   while (passing_lane >= 0 && adj_polys[passing_lane].empty())
00646     {
00647       --passing_lane;
00648     }
00649 
00650   
00651   
00652   if (passing_lane < 0)
00653     {
00654       ROS_WARN("no passing lane available for waypoint %s",
00655                order->waypt[1].id.name().str);
00656       return false;
00657     }
00658 
00659   passing_left = true;                  
00660 
00661   ROS_DEBUG("passing lane %s selected",
00662             adj_lane[passing_lane].lane_name().str);
00663 
00664 #endif
00665 
00666   return true;
00667 }
00668 
00669 
00670 
00671 
00672 
00673 
00674 
00675 
00676 
00677 void Course::find_travel_lane(bool rejoin)
00678 {
00679   if (plan_valid())
00680     {
00681       ROS_DEBUG("find_travel_lane() plan still valid");
00682     }
00683   else
00684     {
00685       
00686       plan.clear();
00687       aim_poly.poly_id = -1;            
00688       set_plan_waypts();
00689     
00690       if (polygons.size() == 0)         
00691         {
00692           ROS_WARN("find_travel_lane() has no polygons");
00693           return;
00694         }
00695 
00696       
00697       pops->add_polys_for_waypts(polygons, plan,
00698                                  order->waypt[0].id, order->waypt[0].id);
00699       if (verbose >= 6)
00700         log("debug plan", plan);
00701 
00702       
00703       for (int i = 1; i < Order::N_WAYPTS; ++i)
00704         {
00705           
00706           if (ElementID(order->waypt[i-1].id)
00707               != ElementID(order->waypt[i].id))
00708             
00709             
00710             pops->add_polys_for_waypts(polygons, plan,
00711                                        order->waypt[i-1].id,
00712                                        order->waypt[i].id);
00713           
00714           if (order->waypt[i].is_perimeter)
00715             break;
00716         }
00717 
00718       if (plan.size() > 1)
00719         {
00720           ROS_DEBUG("plan[0] start, end waypoints are %s, %s, poly_id = %d",
00721                     plan.at(0).start_way.name().str,
00722                     plan.at(0).end_way.name().str,
00723                     plan.at(0).poly_id);
00724           ROS_DEBUG("plan[1] start, end waypoints are %s, %s, poly_id = %d",
00725                     plan.at(1).start_way.name().str,
00726                     plan.at(1).end_way.name().str,
00727                     plan.at(1).poly_id);
00728         }
00729       log("find_travel_lane() plan", plan);
00730     }
00731   
00732   new_plan_lanes = false;               
00733   aim_poly.poly_id = -1;                
00734 
00735   if (rejoin)
00736     {
00737       
00738       
00739       
00740       
00741       
00742 
00743       
00744       
00745       
00746       
00747       
00748 
00749       
00750       int aim_index = find_aim_polygon(plan);
00751       if (aim_index >= 0)
00752         {
00753           
00754           aim_poly = plan.at(aim_index);
00755           ROS_DEBUG("aim polygon is %d", aim_poly.poly_id);
00756         }
00757     }
00758 }
00759 
00760 
00761 
00762 
00763 
00764 
00765 
00766 Polar Course::head_for_waypt(float target_dist)
00767 {
00768   using Coordinates::MapXY_to_Polar;
00769   Polar aim_polar = MapXY_to_Polar(MapXY(order->waypt[1].mapxy),
00770                                    *estimate);
00771   if (aim_polar.range < target_dist)
00772     {
00773       if (special_waypt(1))
00774         {
00775           
00776           
00777           ART_MSG(8, "waypt[1] is a special way-point, keep current heading");
00778           aim_polar.heading=0.0;
00779         }
00780       else if (order->waypt[1].is_perimeter)
00781         {
00782           ART_MSG(8, "waypt[1] is a perimeter point");
00783           aim_polar = MapXY_to_Polar(MapXY(order->waypt[1].mapxy),
00784                                      *estimate);
00785           if (fabsf(bearing(MapPose(estimate->pose.pose),
00786                             MapXY(order->waypt[1].mapxy)))
00787               > HALFPI)
00788             new_waypoint_reached(order->waypt[1].id);
00789         }
00790       else
00791         {
00792           
00793           aim_polar = MapXY_to_Polar(MapXY(order->waypt[2].mapxy),
00794                                      *estimate);
00795           ART_MSG(8, "waypt[1] less than %.3fm away, using waypt[2] instead",
00796                   target_dist);
00797           
00798           new_waypoint_reached(order->waypt[1].id);
00799         }
00800     }
00801   return aim_polar;
00802 }
00803 
00804 
00805 Course::direction_t Course::lane_change_direction(void)
00806 {
00807   int w0_index = pops->get_waypoint_index(polygons, order->waypt[0].id);
00808   int w1_index = pops->get_waypoint_index(polygons, order->waypt[1].id);
00809 
00810   
00811   if (w0_index < 0 || w1_index < 0)
00812     return Straight;
00813 
00814   if (pops->left_of_poly(polygons.at(w1_index), polygons.at(w0_index)))
00815     return Left;
00816   else
00817     return Right;
00818 }
00819 
00820 
00821 
00822 
00823 
00824 
00825 
00826 
00827 
00828 
00829 
00830 
00831 
00832 bool Course::lane_waypoint_reached(void)
00833 {
00834   
00835   waypoint_checked = true;
00836 
00837   if (order->waypt[1].is_perimeter)
00838     return zone_perimeter_reached();
00839   
00840   
00841   
00842   
00843   
00844   
00845   if (special_waypt(1))
00846     return false;
00847 
00848 #ifdef USE_PATS
00849   ElementID last_way = pops->updateLaneLocation(polygons,
00850                                                 odom->pose,
00851                                                 order->waypt[0],
00852                                                 order->waypt[1]);
00853   if (last_way == order->waypt[1].id)
00854     {
00855       navdata->last_way = last_way;
00856       return true;
00857     }
00858   return false;
00859 #endif
00860 
00861   bool found = false;
00862 
00863   
00864   
00865   
00866 
00867   
00868   int w1_index = -1;
00869 
00870   w1_index = pops->get_waypoint_index(polygons, order->waypt[1].id);
00871   
00872   if (w1_index >= 0)
00873     {
00874       
00875       
00876       MapPose w1_pose(MapXY(order->waypt[1].mapxy),
00877                       pops->PolyHeading(polygons.at(w1_index)));
00878       
00879       
00880       
00881       float bearing_from_w1 = bearing(w1_pose,
00882                                       MapXY(odom->pose.pose.position));
00883       if (fabsf(bearing_from_w1) < angles::from_degrees(90))
00884         {
00885           
00886           ROS_INFO("reached waypoint %s, bearing %.3f radians",
00887                    ElementID(order->waypt[1].id).name().str,
00888                    bearing_from_w1);
00889           navdata->last_waypt = order->waypt[1].id;
00890           found = true;
00891         }
00892     }
00893 
00894   
00895   if (!found)
00896     ROS_DEBUG("cur_poly = %d, last_waypt = %s",
00897               navdata->cur_poly,
00898               ElementID(navdata->last_waypt).name().str);
00899   return found;
00900 }
00901 
00907 void Course::lanes_message(const art_msgs::ArtLanes &lanes)
00908 {
00909   
00910   polygons.resize(lanes.polygons.size());
00911   for (unsigned num = 0; num < lanes.polygons.size(); num++)
00912     polygons.at(num) = lanes.polygons[num];
00913 
00914   if (polygons.empty())
00915     ROS_WARN("empty lanes polygon list received!");
00916 
00917   
00918   new_plan_lanes = true;
00919 
00920   log("lanes input:", polygons);
00921 };
00922 
00923 
00924 void Course::log(const char *str, const poly_list_t &polys)
00925 {
00926   unsigned npolys = polys.size();
00927   if (npolys > 0)
00928     {
00929       for (unsigned i = 0; i < npolys; ++i)
00930         {
00931           ROS_DEBUG("polygon[%u] = %d", i, polys.at(i).poly_id);
00932           unsigned start_seq = i;
00933           while (i+1 < npolys
00934                  && abs(polys.at(i+1).poly_id - polys.at(i).poly_id) == 1)
00935             {
00936               ++i;
00937             }
00938           if (start_seq == i)
00939             ROS_DEBUG("%s polygon at %d", str, polys.at(i).poly_id);
00940           else
00941             ROS_DEBUG("%s polygons from %d to %d",
00942                       str, polys.at(start_seq).poly_id, polys.at(i).poly_id);
00943         }
00944     }
00945   else
00946     {
00947       ROS_INFO("%s no polygons at all", str);
00948     }
00949 }
00950 
00951 
00952 bool Course::new_waypts(void)
00953 {
00954   if (saved_replan_num!=order->replan_num)
00955     return true;
00956 
00957   for (unsigned i = 0; i < art_msgs::Order::N_WAYPTS; ++i)
00958     if (saved_waypt_id[i] != order->waypt[i].id)
00959       return true;
00960 
00961   
00962   return false;
00963 }
00964 
00965 
00966 void Course::reset(void)
00967 {
00968   ROS_INFO("Course class reset()");
00969 
00970   
00971   start_pass_location = MapPose();
00972 
00973   
00974   plan.clear();
00975   aim_poly.poly_id = -1;
00976 }
00977 
00978 
00979 ElementID Course::replan_roadblock(void)
00980 {
00981   saved_replan_num=order->replan_num;
00982 
00983   
00984   for (unsigned i = 0; i < art_msgs::Order::N_WAYPTS; ++i)
00985     {
00986       saved_waypt_id[i] = order->waypt[i].id;
00987       ROS_DEBUG("saved_waypt_id[%u] = %s",
00988                 i, saved_waypt_id[i].name().str);
00989     }
00990 
00991   
00992   int uturn_exit_index = 
00993     pops->getClosestPoly(plan,MapPose(estimate->pose.pose));
00994 
00995   MapPose exit_pose;
00996   exit_pose.map.x=plan.at(uturn_exit_index).midpoint.x;
00997   exit_pose.map.y=plan.at(uturn_exit_index).midpoint.y;
00998 
00999   
01000   
01001   ElementID reverse_lane =
01002     pops->getReverseLane(polygons,exit_pose);
01003 
01004   ROS_INFO("Replan from lane %s", reverse_lane.lane_name().str);
01005 
01006   return reverse_lane;
01007 }
01008 
01009 
01010 Course::direction_t Course::intersection_direction(void)
01011 {
01012   int w0_index =
01013     pops->getContainingPoly(polygons,
01014                             MapXY(order->waypt[0].mapxy));
01015   int w1_index =
01016     pops->getContainingPoly(polygons,
01017                             MapXY(order->waypt[1].mapxy));
01018 
01019   
01020   if (w0_index < 0 || w1_index < 0)
01021     return Straight;
01022 
01023   float w0_heading = pops->PolyHeading(polygons.at(w0_index));
01024   float w1_heading = pops->PolyHeading(polygons.at(w1_index));
01025   float heading_change = normalize(w1_heading - w0_heading);
01026                                             
01027   ROS_DEBUG("heading change from waypoint %s to %s is %.3f radians",
01028             ElementID(order->waypt[0].id).name().str,
01029             ElementID(order->waypt[1].id).name().str,
01030             heading_change);
01031 
01032   if (fabsf(heading_change) < angles::from_degrees(30))
01033     return Straight;
01034   else if (heading_change > 0.0)
01035     return Left;
01036   else
01037     return Right;
01038 }
01039 
01040 
01041 
01042 
01043 
01044 float Course::stop_waypt_distance(bool same_lane)
01045 {
01046   for (unsigned i = 1; i < art_msgs::Order::N_WAYPTS; ++i)
01047     {
01048       
01049       if (same_lane
01050           && !ElementID(order->waypt[i].id).same_lane(order->waypt[0].id))
01051         break;
01052 
01053       if (order->waypt[i].is_stop)
01054         {
01055           
01056           int stop_index =
01057             pops->getContainingPoly(polygons,
01058                                     MapXY(order->waypt[i].mapxy));
01059           if (stop_index < 0)           
01060             continue;                   
01061 
01062           stop_poly = polygons.at(stop_index);
01063           stop_waypt = WayPointNode(order->waypt[i]);
01064           float wayptdist = distance_in_plan(MapPose(estimate->pose.pose),
01065                                              stop_waypt);
01066           ROS_DEBUG("Stop at waypoint %s is %.3fm away",
01067                     stop_waypt.id.name().str, wayptdist);
01068           return wayptdist;
01069         }
01070     }
01071   return Infinite::distance;
01072 }
01073 
01074 
01075 
01076 
01077 
01078 
01079 
01080 
01081 
01082 
01083 
01084 
01085 
01086 bool Course::switch_to_passing_lane()
01087 {
01088   
01089   int aim_index = find_aim_polygon(adj_polys[passing_lane]);
01090   if (aim_index == -1)
01091     {
01092       ROS_WARN("unable to pass, no polygon near the aiming point");
01093       return false;
01094     }
01095 
01096   
01097   passed_lane = plan;
01098 
01099   
01100   plan.clear();
01101   pops->CollectPolys(adj_polys[passing_lane], plan, aim_index);
01102   
01103   log("switch_to_passing_lane() plan", plan);
01104   if (plan.empty())
01105     {
01106       ROS_WARN("no polygons in passing lane past aiming point");
01107       return false;
01108     }
01109 
01110   aim_poly=plan.at(0);
01111   MapXY aim_poly_midpt = pops->getPolyEdgeMidpoint(aim_poly);
01112   ROS_DEBUG("aiming at polygon %d, midpoint (%.3f, %.3f)",
01113            aim_poly.poly_id, aim_poly_midpt.x, aim_poly_midpt.y);
01114 
01115   MapXY start_point =
01116     pops->GetClosestPointToLine (pops->midpoint(aim_poly.p1,aim_poly.p4),
01117                                  pops->midpoint(aim_poly.p2,aim_poly.p3),
01118                                  MapXY(estimate->pose.pose.position),
01119                                  true);
01120 
01121   start_pass_location.map=start_point;
01122   start_pass_location.yaw=aim_poly.heading;
01123 
01124   ROS_INFO("passing starts at (%.3f, %.3f)",
01125            start_pass_location.map.x, start_pass_location.map.y);
01126 
01127   return true;
01128 }
01129 
01130 
01131 float Course::uturn_distance(void)
01132 {
01133   int i = uturn_order_index();
01134   if (i < 0)
01135     return Infinite::distance;
01136 
01137   
01138   int stop_index =
01139     pops->getContainingPoly(polygons,
01140                             MapXY(order->waypt[i].mapxy));
01141   if (stop_index < 0)           
01142     return Infinite::distance;
01143 
01144   
01145   stop_poly = polygons.at(stop_index);
01146   stop_waypt = WayPointNode(order->waypt[i]);
01147 
01148   
01149   float wayptdist = distance_in_plan(MapPose(estimate->pose.pose), stop_waypt);
01150   ROS_DEBUG("U-turn at waypoint %s, %.3fm away",
01151             stop_waypt.id.name().str, wayptdist);
01152   return wayptdist;
01153 }
01154 
01155 
01156 
01157 
01158 
01159 
01160 int Course::uturn_order_index(void)
01161 {
01162   for (unsigned i = 1; i < art_msgs::Order::N_WAYPTS-1; ++i)
01163     {
01164       
01165       if (!ElementID(order->waypt[i].id).same_lane(ElementID(order->waypt[0].id)))
01166         break;
01167       
01168       if (uturn_waypt(i))
01169         return i;
01170     }
01171   return -1;
01172 }
01173 
01174 
01175 bool Course::uturn_waypt(unsigned windex)
01176 {
01177   if (order->next_uturn < 0)
01178     return false;
01179     
01180   return (windex==(unsigned)order->next_uturn);
01181 }
01182 
01183 
01184 
01185 
01186 
01187 
01188 
01189 
01190 
01191 bool Course::zone_waypoint_reached(void)
01192 {
01193   bool found = false;
01194   waypoint_checked = true;
01195           
01196   
01197   Polar bumper_polar(0.0, ArtVehicle::front_bumper_px);
01198   float distance =
01199     Euclidean::DistanceToWaypt(bumper_polar,
01200                                MapPose(estimate->pose.pose),
01201                                WayPointNode(order->waypt[1]));
01202 
01203   if (distance <= zone_waypoint_radius)
01204     {
01205       
01206       ROS_DEBUG("reached zone waypoint %s, distance %.3fm",
01207                 ElementID(order->waypt[1].id).name().str, distance);
01208       navdata->last_waypt = order->waypt[1].id;
01209       found = true;
01210     }
01211   else
01212     {
01213       ROS_DEBUG("distance to zone waypoint %s is %.3fm",
01214                 ElementID(order->waypt[1].id).name().str, distance);
01215     }
01216   
01217   return found;
01218 }
01219 
01220 bool Course::zone_perimeter_reached(void)
01221 {
01222   bool found = false;
01223   waypoint_checked = true;
01224   
01225   int w1_index =
01226     pops->getClosestPoly(polygons,
01227                          MapXY(order->waypt[1].mapxy));
01228   if (w1_index >= 0)
01229     {
01230       
01231       
01232       MapPose w1_pose(order->waypt[1].mapxy, 
01233                       pops->PolyHeading(polygons.at(w1_index)));
01234       
01235 #if 1
01236       
01237       
01238       float bearing_from_w1 =
01239         bearing(w1_pose, MapXY(odom->pose.pose.position));
01240 #else // experimental code -- not working right yet
01241       
01242       
01243       Polar bumper_polar(0.0,
01244                          (ArtVehicle::front_bumper_px
01245                           + DARPA_rules::stop_line_to_bumper));
01246       MapXY bumper_pos = Polar_to_MapXY(bumper_polar, odom->pos);
01247       float bearing_from_w1 = bearing(w1_pose, bumper_pos);
01248 #endif
01249       if (fabsf(bearing_from_w1) < angles::from_degrees(90))
01250         {
01251           
01252           ROS_DEBUG("reached waypoint %s, bearing %.3f radians",
01253                     ElementID(order->waypt[1].id).name().str,
01254                     bearing_from_w1);
01255           navdata->last_waypt = order->waypt[1].id;
01256           found = true;
01257         }
01258     }
01259   
01260   return found;
01261 }
01262 
01263 
01264 bool Course::spot_waypoint_reached(void)
01265 {
01266   bool found = false;
01267   waypoint_checked = true;
01268           
01269   
01270   Polar bumper_polar(0.0, ArtVehicle::front_bumper_px);
01271   float distance =
01272     Euclidean::DistanceToWaypt(bumper_polar, MapPose(estimate->pose.pose),
01273                                WayPointNode(order->waypt[1]));
01274 
01275   if (distance <= spot_waypoint_radius)
01276     {
01277       
01278       ROS_DEBUG("reached spot waypoint %s, distance %.3fm",
01279                 ElementID(order->waypt[1].id).name().str, distance);
01280       navdata->last_waypt = order->waypt[1].id;
01281       found = true;
01282     }
01283   else
01284     {
01285       ROS_DEBUG("distance to spot waypoint %s is %.3fm",
01286                 ElementID(order->waypt[1].id).name().str, distance);
01287     }
01288 
01289   return found;
01290 }
01291 
01292 float Course::max_speed_for_slow_down(const float& final_speed,
01293                                       const float& distance,
01294                                       const float& max,
01295                                       const float& max_deceleration) {
01296   
01297   
01298   
01299   
01300   
01301   
01302   
01303   
01304   
01305   
01306   float vf2 = final_speed * final_speed;
01307   float tax = 2 * (-max_deceleration) * distance;
01308   
01309   
01310   if(tax > vf2)
01311     return 0.0;
01312   
01313   return fminf(max, sqrtf(vf2 - tax));
01314 }
01315 
01316 
01317 
01318 
01319 
01320 
01321 float Course::max_speed_for_change_in_heading(const float& dheading,
01322                                               const float& distance,
01323                                               const float& max,
01324                                               const float& maximum_yaw_rate) 
01325 {
01326   if (Epsilon::equal(dheading,0))
01327     {
01328       return max;
01329     }
01330   else
01331     {
01332       float new_speed=fminf(max,
01333                             fmaxf(max_speed_for_sharp,
01334                                   fabsf(heading_change_ratio *
01335                                         (maximum_yaw_rate / dheading)))); 
01336       ROS_DEBUG("slow for heading: distance: %.3f, dheading: %.3f, "
01337                 "maximum_yaw_rate: %.3f, max_speed: %.3f, final: %.3f",
01338                 distance, dheading, maximum_yaw_rate, max,new_speed); 
01339       return new_speed;
01340     }
01341 }
01342 
01343 
01344 float Course::get_yaw_spring_system(const Polar& aim_polar, 
01345                                     int poly_id,
01346                                     float poly_heading,
01347                                     float max_yaw,
01348                                     float curr_velocity,
01349                                     float offset_ratio)
01350 {
01351   float error = 0;
01352   float theta=-aim_polar.heading;
01353   float velocity = fmaxf(curr_velocity, Steering::steer_speed_min);
01354   nav_msgs::Odometry front_est;  
01355   Estimate::front_axle_pose(*estimate, front_est);
01356   ros::Duration frequency(1.0 / art_msgs::ArtHertz::NAVIGATOR);
01357   ros::Time time_in_future = (ros::Time::now()
01358                               + frequency
01359                               + ros::Duration(velocity * spring_lookahead));
01360   nav_msgs::Odometry pos_est;
01361   Estimate::control_pose(front_est, time_in_future, pos_est);
01362  
01363   if (poly_id >=0)
01364     {
01365       poly current_poly=plan.at(poly_id);
01366       posetype origin;                  
01367       posetype cpoly(current_poly.midpoint.x, current_poly.midpoint.y,
01368                      poly_heading);
01369       rotate_translate_transform trans;
01370       trans.find_transform(cpoly,origin);
01371       posetype car(pos_est.pose.pose.position.x,
01372                    pos_est.pose.pose.position.y,
01373                    0.0);
01374       posetype car_rel=trans.apply_transform(car);
01375 
01376       float width=Euclidean::DistanceTo(current_poly.p2,current_poly.p3);
01377 
01378       
01379       error=car_rel.y;
01380       
01381 
01382 #if 1 // still experimental:
01383 
01384       if (!Epsilon::equal(offset_ratio, 0.0))
01385         {
01386           
01387           
01388           
01389 
01390           MapXY mid_left_side =
01391             pops->midpoint(current_poly.p1, current_poly.p2);
01392           float half_lane_width =
01393             Euclidean::DistanceTo(current_poly.midpoint, mid_left_side);
01394           float lane_space = half_lane_width - ArtVehicle::halfwidth;
01395           float error_offset = 0.0;
01396           if (lane_space > 0.0)         
01397             error_offset = offset_ratio * lane_space;
01398           ROS_DEBUG("error offset %.3f, half lane width %.3f, ratio %.3f",
01399                     error_offset, half_lane_width, offset_ratio);
01400 
01401           
01402           error -= error_offset;
01403         }
01404 #endif
01405       error=fminf(fmaxf(-width,error),width);
01406       
01407       theta = normalize(MapPose(pos_est.pose.pose).yaw - poly_heading);
01408     }
01409 
01410 
01411   float cth = cosf(theta);
01412 
01413   float vcth = velocity*cth;
01414 
01415   if (fabsf(theta) >= HALFPI ||
01416       Epsilon::equal(cth,0.0) ||
01417       Epsilon::equal(vcth,0.0))
01418     {
01419       ART_MSG(8,"Spring system does not apply: heading offset %.3f", theta);
01420       if (Epsilon::equal(error,0)) {
01421         if (theta < 0)
01422           return max_yaw;
01423         else return -max_yaw;
01424       }
01425       else {
01426         if (error > 0)
01427           return max_yaw;
01428         else return -max_yaw;
01429       }
01430     }
01431   
01432   float d2=-k_theta*sinf(theta)/cth;
01433   float d1=-k_error*error/vcth;  
01434   
01435   
01436   
01437   
01438   
01439   
01440   
01441   
01442   
01443 
01444   if ((Coordinates::sign(error) == Coordinates::sign(last_error)) &&
01445       (fabsf(error) > fabs(last_error)))
01446     d1*=k_int;
01447 
01448   last_error=error;
01449   float yaw=d1+d2;
01450 
01451   ROS_DEBUG("Heading spring systems values: error %.3f, dtheta %.3f, "
01452             "d1 %.3f, d2 %.3f, d1+d2 %.3f", error, theta, d1, d2, yaw);
01453   
01454   if (yaw < 0)
01455     return fmaxf(-max_yaw, yaw);
01456   return fminf(max_yaw, yaw);
01457 }
01458 
01459 
01460 bool Course::spot_ahead()
01461 {
01462   for (uint i=0; i<art_msgs::Order::N_WAYPTS-1;i++)
01463     if (order->waypt[i].is_spot &&
01464         order->waypt[i+1].is_spot &&
01465         order->waypt[i].id.pt==1 &&
01466         order->waypt[i+1].id.pt==2)
01467       return true;
01468 
01469   return false;
01470 
01471 }
01472 
01473 bool Course::curr_spot()
01474 {
01475   return order->waypt[0].is_spot;
01476 }
01477 
01478 #if 0
01479 mapxy_list_t Course::calculate_zone_barrier_points() 
01480 {
01481   mapxy_list_t spot_points;
01482   
01483   return spot_points;
01484 
01485   if (order->waypt[1].is_spot)
01486     return spot_points;
01487 
01488   posetype way_pose(order->waypt[1].mapxy.x,
01489                     order->waypt[1].mapxy.y,
01490                     atan2f(order->waypt[2].mapxy.y-order->waypt[1].mapxy.y,
01491                            order->waypt[2].mapxy.x-order->waypt[1].mapxy.x));
01492   
01493   rotate_translate_transform trans;
01494   trans.find_transform(posetype(),way_pose);
01495   
01496   posetype npose;
01497   npose=trans.apply_transform(posetype(1,order->waypt[1].lane_width,0));
01498   spot_points.push_back(npose);
01499 
01500   npose=trans.apply_transform(posetype(1,order->waypt[1].lane_width/2,0));
01501   spot_points.push_back(npose);
01502   
01503   npose=trans.apply_transform(posetype(1,0,0));
01504   spot_points.push_back(npose);
01505   
01506   npose=trans.apply_transform(posetype(1,-order->waypt[1].lane_width/2,0));
01507   spot_points.push_back(npose);
01508   
01509   npose=trans.apply_transform(posetype(1,-order->waypt[1].lane_width,0));
01510   spot_points.push_back(npose);
01511 
01512   return spot_points;
01513 }
01514 
01515 mapxy_list_t Course::calculate_spot_points(const std::vector<WayPointNode>& new_waypts) 
01516 {
01517   mapxy_list_t spot_points;
01518 
01519   for (uint i=0; i<art_msgs::Order::N_WAYPTS-1;i++)
01520     if (new_waypts[i].is_spot &&
01521         new_waypts[i+1].is_spot &&
01522         new_waypts[i].id.pt==1 &&
01523         new_waypts[i+1].id.pt==2)
01524       {
01525         posetype way_pose(new_waypts[i].map.x,new_waypts[i].map.y,
01526                           atan2f(new_waypts[i+1].map.y-new_waypts[i].map.y,
01527                                  new_waypts[i+1].map.x-new_waypts[i].map.x));
01528 
01529         float dist=Euclidean::DistanceTo(new_waypts[i+1].map,
01530                                          new_waypts[i].map);
01531         rotate_translate_transform trans;
01532         trans.find_transform(posetype(),way_pose);
01533         
01534         posetype npose;
01535 
01536         npose=trans.apply_transform(posetype(0,new_waypts[i].lane_width/2,0));
01537         spot_points.push_back(npose);
01538 
01539         npose=trans.apply_transform(posetype(dist,new_waypts[i].lane_width/2,0));
01540         spot_points.push_back(npose);
01541 
01542         npose=trans.apply_transform(posetype(dist+2,new_waypts[i].lane_width,0));
01543         spot_points.push_back(npose);
01544 
01545         npose=trans.apply_transform(posetype(dist+2,new_waypts[i].lane_width/2,0));
01546         spot_points.push_back(npose);
01547 
01548         npose=trans.apply_transform(posetype(dist+2,0,0));
01549         spot_points.push_back(npose);
01550 
01551         npose=trans.apply_transform(posetype(dist+2,-new_waypts[i].lane_width/2,0));
01552         spot_points.push_back(npose);
01553 
01554         npose=trans.apply_transform(posetype(dist+2,new_waypts[i].lane_width/2,0));
01555         spot_points.push_back(npose);
01556 
01557         npose=trans.apply_transform(posetype(dist,-new_waypts[i].lane_width/2,0));
01558         spot_points.push_back(npose);
01559 
01560         npose=trans.apply_transform(posetype(0,-new_waypts[i].lane_width/2,0));
01561         spot_points.push_back(npose);
01562 
01563       }
01564   return spot_points;
01565 }
01566 
01567 mapxy_list_t Course::calculate_spot_points() 
01568 {
01569   mapxy_list_t spot_points;
01570 
01571   for (uint i=0; i<art_msgs::Order::N_WAYPTS-1;i++)
01572     if (order->waypt[i].is_spot &&
01573         order->waypt[i+1].is_spot &&
01574         order->waypt[i].id.pt==1 &&
01575         order->waypt[i+1].id.pt==2)
01576       {
01577         posetype way_pose(order->waypt[i].mapxy.x,
01578                           order->waypt[i].mapxy.y,
01579                           atan2f(order->waypt[i+1].mapxy.y-order->waypt[i].mapxy.y,
01580                                  order->waypt[i+1].mapxy.x-order->waypt[i].mapxy.x));
01581 
01582         float dist=Euclidean::DistanceTo(order->waypt[i+1].mapxy,
01583                                          order->waypt[i].mapxy);
01584         rotate_translate_transform trans;
01585         trans.find_transform(posetype(),way_pose);
01586         
01587         posetype npose;
01588 
01589         npose=trans.apply_transform(posetype(0,order->waypt[i].lane_width/2,0));
01590         spot_points.push_back(npose);
01591 
01592         npose=trans.apply_transform(posetype(dist,order->waypt[i].lane_width/2,0));
01593         spot_points.push_back(npose);
01594 
01595         npose=trans.apply_transform(posetype(dist+2,order->waypt[i].lane_width,0));
01596         spot_points.push_back(npose);
01597 
01598         npose=trans.apply_transform(posetype(dist+2,order->waypt[i].lane_width/2,0));
01599         spot_points.push_back(npose);
01600 
01601         npose=trans.apply_transform(posetype(dist+2,0,0));
01602         spot_points.push_back(npose);
01603 
01604         npose=trans.apply_transform(posetype(dist+2,-order->waypt[i].lane_width/2,0));
01605         spot_points.push_back(npose);
01606 
01607         npose=trans.apply_transform(posetype(dist+2,order->waypt[i].lane_width/2,0));
01608         spot_points.push_back(npose);
01609 
01610         npose=trans.apply_transform(posetype(dist,-order->waypt[i].lane_width/2,0));
01611         spot_points.push_back(npose);
01612 
01613         npose=trans.apply_transform(posetype(0,-order->waypt[i].lane_width/2,0));
01614         spot_points.push_back(npose);
01615 
01616       }
01617   return spot_points;
01618 }
01619 #endif
01620 
01621 bool Course::nqe_special(int i, int j)
01622 {
01623 #ifdef NQE
01624   
01625   typedef struct {
01626     ElementID start;
01627     ElementID end;
01628   } id_pair;
01629   
01630   static int num_pair=8;
01631   
01632   static id_pair id_table[]=
01633     {
01634       
01635       {ElementID(1,1,6),ElementID(41,1,1)},
01636       {ElementID(1,2,5),ElementID(41,2,1)},
01637       {ElementID(41,1,7),ElementID(1,1,1)},
01638       {ElementID(41,2,7),ElementID(1,2,1)},
01639       
01640       {ElementID(6,1,10),ElementID(5,1,1)},
01641       {ElementID(5,1,7),ElementID(6,1,1)},
01642       {ElementID(6,1,4),ElementID(8,2,1)},
01643       {ElementID(6,1,6),ElementID(7,1,1)},
01644     };
01645   
01646   for (int k=0; k< num_pair; k++)
01647     if (order->waypt[i].id==id_table[k].start &&
01648         order->waypt[j].id==id_table[k].end)
01649       return true;
01650 #endif
01651 
01652   return false;
01653   
01654 }