parking.cc
Go to the documentation of this file.
00001 /*
00002  *  Navigator parking controller
00003  *
00004  *  Copyright (C) 2007, 2010, Austin Robot Technology
00005  *
00006  *  License: Modified BSD Software License Agreement
00007  *
00008  *  Author: Patrick Beeson
00009  *
00010  *  $Id: parking.cc 626 2010-09-25 04:07:12Z jack.oquin $
00011  */
00012 
00013 #include "navigator_internal.h"
00014 #include "obstacle.h"
00015 #include "Controller.h"
00016 #include "course.h"
00017 #include "parking.h"
00018 #include <art_map/rotate_translate_transform.h>
00019 #include <art/steering.h>
00020 
00021 #include "safety.h"
00022 #include "stop.h"
00023 #include "halt.h"
00024 
00025 int find_spot(const std::vector<WayPointNode> &new_waypts)
00026 {
00027   for (uint i=0; i < new_waypts.size()-1;i++)
00028     if (new_waypts[i].is_spot &&
00029         new_waypts[i+1].is_spot &&
00030         new_waypts[i].id.lane==
00031         new_waypts[i+1].id.lane)
00032       {
00033         return (int)i;
00034       }
00035   return -1;
00036 }
00037 
00038 poly adjust_spot_and_return_poly(WayPointNode &p1,
00039                                  WayPointNode &p2,
00040                                  float dx,
00041                                  float dy) {
00042   poly spot;
00043 
00044   {
00045     posetype way_pose(p1.map.x, p1.map.y,
00046                       atan2f(p2.map.y-p1.map.y,
00047                              p2.map.x-p1.map.x));
00048     
00049     rotate_translate_transform trans;
00050     trans.find_transform(posetype(),way_pose);
00051 
00052     float dist=Euclidean::DistanceTo(p1.map,
00053                                      p2.map);  
00054     
00055     p1.map = MapXY(trans.apply_transform(posetype(dx, dy, 0)));
00056     p2.map = MapXY(trans.apply_transform(posetype(dx + dist, dy, 0)));
00057   }
00058 
00059   posetype way_pose(p1.map.x, p1.map.y,
00060                     atan2f(p2.map.y-p1.map.y,
00061                            p2.map.x-p1.map.x));
00062   
00063   rotate_translate_transform trans;
00064   trans.find_transform(posetype(),way_pose);
00065   
00066   float dist=Euclidean::DistanceTo(p1.map,
00067                                    p2.map);  
00068   
00069   // TODO: Make the + 1 a cfg option
00070   spot.p1 = MapXY(trans.apply_transform(posetype(0, p1.lane_width/2, 0)));
00071   spot.p2 = MapXY(trans.apply_transform(posetype(dist + 1, p2.lane_width/2, 0)));
00072   spot.p3 = MapXY(trans.apply_transform(posetype(dist + 1, -p2.lane_width/2, 0)));
00073   spot.p4 = MapXY(trans.apply_transform(posetype(0, -p1.lane_width/2, 0)));
00074 
00075   /*  
00076   fprintf(stderr, "p1=(%.3f, %.3f)\n", spot.p1.x, spot.p1.y);
00077   fprintf(stderr, "p2=(%.3f, %.3f)\n", spot.p2.x, spot.p2.y);
00078   fprintf(stderr, "p3=(%.3f, %.3f)\n", spot.p3.x, spot.p3.y);
00079   fprintf(stderr, "p4=(%.3f, %.3f)\n", spot.p4.x, spot.p4.y);
00080   */
00081   return spot;
00082 }
00083 
00084 int PARK_control::adjust_spot(std::vector<WayPointNode> &new_waypts,
00085                             ObstacleList obstacles,
00086                             float max_x_offset,
00087                             float max_y_offset,
00088                             float step_size) {
00089   PolyOps pops;
00090   int i = find_spot(new_waypts);
00091   if(i >= 0 && i < (int)new_waypts.size() - 1) {
00092     for(float dx = 0; dx <= max_x_offset; dx += step_size) {
00093       for(int x_sign = -1; x_sign <= 1; x_sign += 2) {
00094         for(float dy = 0; dy <= max_y_offset; dy += step_size) {
00095           for(int y_sign = -1; y_sign <= 1; y_sign += 2) {
00096             WayPointNode p1_new = new_waypts.at(i);
00097             WayPointNode p2_new = new_waypts.at(i+1);
00098             
00099             poly spot = adjust_spot_and_return_poly(p1_new,
00100                                                     p2_new,
00101                                                     x_sign * dx,
00102                                                     y_sign * dy);
00103             
00104             int obstacles_in_spot = 0;
00105             
00106             for(unsigned j = 0; j < obstacles.size(); j++) {
00107               if(pops.pointInPoly_ratio(obstacles[j], spot,1.1))
00108                 obstacles_in_spot++;
00109             }
00110             
00111             if(obstacles_in_spot <= min_obst) {
00112               float distt=sqrtf(dx*dx+dy*dy);
00113               if (distt <= min_adj_dist)
00114                 {
00115                   min_adj_dist=distt;
00116                   min_obst=obstacles_in_spot;
00117                   new_waypts.at(i) = p1_new;
00118                   new_waypts.at(i+1) = p2_new;
00119                   //          std::cerr<<"ADJUSTING SPOT BY X: "<<x_sign * dx
00120                   //                   <<" AND Y: "<<y_sign * dy<<"\n";
00121                   return 0;
00122                 }
00123             }
00124           }
00125         }
00126       }
00127     }
00128   }
00129   return -1;
00130 }
00131 
00132 PARK_control::PARK_control(Navigator *navptr, int _verbose):
00133   Controller(navptr, _verbose)
00134 {
00135   safety = new Safety(navptr, _verbose, 2);
00136   stop = new Stop(navptr, _verbose);
00137   halt = new Halt(navptr, _verbose);
00138   reset_me();
00139 
00140   state=hit_waypoint;
00141 }
00142 
00143 PARK_control::~PARK_control()
00144 {
00145   delete safety;
00146   delete stop;
00147   delete halt;
00148 }
00149 
00150 // configuration method
00151 void PARK_control::configure(ConfigFile* cf, int section)
00152 {
00153   park_max_speed = cf->ReadFloat(section, "park_max_speed", 0.5);
00154   
00155   // maximum speed when inside a park_control
00156   speed_limit = cf->ReadFloat(section, "park_control_speed_limit", 1.0);
00157   ART_MSG(2, "\tspeed limit for park_control is %.1f m/s", speed_limit);
00158   
00159   min_distance = cf->ReadFloat(section, "park_min_distance", 0.5);
00160   ART_MSG(2, "\tmin_distance for park_control is %.1f m/s", min_distance);
00161   
00162   min_theta = cf->ReadFloat(section, "park_min_theta", 0.25);
00163   ART_MSG(2, "\tmin_theta for park_control is %.1f m/s", min_theta);
00164   
00165   park_turn_ratio = cf->ReadFloat(section, "park_turn_ratio", 1.0);
00166   ART_MSG(2, "\tturn_ratio for park_control is %.3f", park_turn_ratio);
00167   
00168   find_a_better_spot = cf->ReadBool(section, "find_a_better_spot", false);
00169   ART_MSG(2, "\tfind_a_better_spot is %d", find_a_better_spot);
00170 
00171   find_spot_max_x_offset = cf->ReadFloat(section,
00172                                          "find_spot_max_x_offset", 1.0);
00173   ART_MSG(2, "\tfind_spot_max_x_offset is %.3f m", find_spot_max_x_offset);
00174 
00175   find_spot_max_y_offset = cf->ReadFloat(section,
00176                                          "find_spot_max_y_offset", 1.0);
00177   ART_MSG(2, "\tfind_spot_max_y_offset is %.3f m", find_spot_max_y_offset);
00178 
00179   find_spot_step_size = cf->ReadFloat(section, "find_spot_step_size", 0.1);
00180   ART_MSG(2, "\tfind_spot_step_size is %.3f m", find_spot_step_size);
00181 
00182   safety->configure(cf, section);
00183 }
00184 
00185 inline float real_random(float multi=1.0){
00186   return float(random())/RAND_MAX*multi;
00187 }
00188 
00189 
00190 // go to next park_control way-point
00191 //
00192 // returns: OK.
00193 //
00194 Controller::result_t PARK_control::control(pilot_command_t &pcmd,
00195                                          mapxy_list_t obs_list,
00196                                          bool voronoi_stuck) {
00197 
00198   result_t result = OK;  
00199   if (voronoi_stuck)
00200     {
00201       pcmd.velocity=speed_limit;
00202       navdata->reverse=true;
00203       pcmd.yawRate=0.0;
00204       result_t safe=safety->control(pcmd);
00205       int count=1;
00206       bool neg=false;
00207       float rand=real_random(Steering::maximum_yaw/2);
00208       while (safe>=Unsafe && fabsf(pcmd.yawRate) <= Steering::maximum_yaw)
00209         {
00210           if (!neg)
00211             pcmd.yawRate=rand*count;
00212           else
00213             {
00214               pcmd.yawRate=-rand*count;
00215               count++;
00216             }
00217           neg=!neg;
00218           pcmd.velocity=speed_limit;
00219           safe=safety->control(pcmd);
00220         }
00221       if (safe >= Unsafe)
00222         {
00223           pcmd.velocity=speed_limit;
00224           navdata->reverse=false;
00225           pcmd.yawRate=0;
00226           result_t safe=safety->control(pcmd);
00227           int count =1;
00228           bool neg=false;
00229           while (safe>=Unsafe && fabsf(pcmd.yawRate) <= Steering::maximum_yaw)
00230             {
00231               if (!neg)
00232                 pcmd.yawRate=rand*count;
00233               else
00234                 {
00235                   pcmd.yawRate=-rand*count;
00236                   count++;
00237                 }
00238               neg=!neg;
00239               pcmd.velocity=speed_limit;
00240               safe=safety->control(pcmd);
00241             }     
00242         }
00243       // must always run this on the final command
00244       result = safety->control(pcmd);      
00245       
00246 
00247 
00248       last_park_dist=pcmd.velocity;
00249       if (navdata->reverse)
00250         last_park_dist*=-1;
00251       last_park_turn=pcmd.yawRate;
00252       
00253       if (result >=Unsafe)
00254         {
00255           pcmd.velocity=speed_limit;
00256           navdata->reverse=true;
00257         }
00258       
00259       trace("park_control controller", pcmd, result);
00260       return result;
00261     }
00262 
00263   std::vector<WayPointNode> new_waypts;
00264   for(int i = 0; i < N_ORDER_WAYPTS; i++)
00265     new_waypts.push_back(order->waypt[i]);
00266 
00267   if(find_a_better_spot) {
00268     adjust_spot(new_waypts,
00269                 obstacle->lasers->all_obstacle_list,
00270                 find_spot_max_x_offset,
00271                 find_spot_max_y_offset,
00272                 find_spot_step_size);
00273   }
00274 
00275   if (!new_waypts[1].is_spot)
00276     state=hit_waypoint;
00277   else
00278     if ((new_waypts[1].is_spot && new_waypts[2].is_spot &&
00279          new_waypts[1].id.pt==1 && new_waypts[2].id.pt==2))
00280       state=approach_spot;
00281     else
00282       if (new_waypts[1].is_spot && new_waypts[2].is_spot &&
00283           new_waypts[1].id.pt==2 && new_waypts[2].id.pt==1)
00284         state=pull_in;
00285       else state=pull_out;
00286 
00287   if (course->spot_ahead())
00288     spot_points=course->calculate_spot_points(new_waypts);
00289   else if (!course->curr_spot())
00290     spot_points.clear();
00291 
00292   for (uint i=0; i<spot_points.size(); i++)
00293     obs_list.push_back(spot_points[i]);
00294 
00295 
00296 
00297         // Try going striaght back, then various ways of backwards and
00298         // turning.  Then forwards.
00299         
00300   
00301   switch (state)
00302     {
00303     case hit_waypoint:
00304     case approach_spot:
00305       {
00306         posetype way_pose(new_waypts[1].map.x,new_waypts[1].map.y,
00307                           atan2f(new_waypts[2].map.y-new_waypts[1].map.y,
00308                                  new_waypts[2].map.x-new_waypts[1].map.x));
00309         
00310         rotate_translate_transform trans;
00311         
00312         trans.find_transform(posetype(ArtVehicle::front_bumper_px,0,0),
00313                              way_pose);
00314         posetype npose=trans.apply_transform(posetype(0,0,0));
00315         
00316         new_end_pose.px=npose.x;
00317         new_end_pose.py=npose.y;
00318         new_end_pose.pa=npose.theta;
00319       }
00320       break;
00321     case pull_in:
00322       {
00323         posetype way_pose(new_waypts[1].map.x,new_waypts[1].map.y,
00324                           atan2f(new_waypts[1].map.y-new_waypts[2].map.y,
00325                                  new_waypts[1].map.x-new_waypts[2].map.x));
00326         
00327         rotate_translate_transform trans;
00328         
00329         trans.find_transform(posetype(ArtVehicle::front_bumper_px,0,0),
00330                              way_pose);
00331         posetype npose=trans.apply_transform(posetype());
00332         
00333         new_end_pose.px=npose.x;
00334         new_end_pose.py=npose.y;
00335         new_end_pose.pa=npose.theta;
00336       }
00337       break;
00338     case pull_out:
00339       {
00340         posetype way_pose(new_waypts[1].map.x,new_waypts[1].map.y,
00341                           atan2f(new_waypts[0].map.y-new_waypts[1].map.y,
00342                                  new_waypts[0].map.x-new_waypts[1].map.x));
00343         rotate_translate_transform trans;
00344         
00345         trans.find_transform(posetype(ArtVehicle::front_bumper_px*2.0,0,0),
00346                              way_pose);
00347         posetype npose=trans.apply_transform(posetype());
00348         
00349         new_end_pose.px=npose.x;
00350         new_end_pose.py=npose.y;
00351         new_end_pose.pa=npose.theta;
00352       }
00353       break;
00354     }
00355   
00356 
00357   
00358   pcmd.velocity=speed_limit;
00359   navdata->reverse=false;
00360   
00361   if (Epsilon::equal(estimate->vel.px,0.0))
00362     halting=false;
00363   else if (Epsilon::gte(fabsf(estimate->vel.px),park_max_speed))
00364     halting=true;
00365   //halting=false;
00366   
00367   //Find Parking controller and run first step.
00368   result = initialize(pcmd, obs_list);
00369   
00370   if (result==Finished)
00371     {
00372       ART_MSG(3,"PARK Finished");
00373       halting=true;
00374       halt->control(pcmd);
00375       return result;
00376     }
00377   else 
00378     if (halting)
00379       {
00380         //      ART_MSG(1,"PARK Halting");
00381         pcmd.velocity=0.0;
00382         pcmd.yawRate=lastYaw;
00383         return OK;
00384       }
00385     else
00386       {
00387         if (result==OK)
00388           {
00389             
00390             if (verbose >= 2)
00391               {
00392                 ART_MSG(5, "Go to pose %.3f,%.3f,%.3f",
00393                         new_end_pose.px, new_end_pose.py, new_end_pose.pa);
00394               } 
00395           }
00396         else
00397           {
00398             // Try going striaght back, then various ways of backwards and
00399             // turning.  Then forwards.
00400             
00401             ART_MSG(3,"Not App.");
00402             pcmd.velocity=speed_limit;
00403             navdata->reverse=true;
00404             pcmd.yawRate=0;
00405             result_t safe=safety->control(pcmd);
00406             int count=1;
00407             bool neg=false;
00408             float rand=real_random(Steering::maximum_yaw/2);
00409             while (safe>=Unsafe && fabsf(pcmd.yawRate) <= Steering::maximum_yaw)
00410               {
00411                 if (!neg)
00412                   pcmd.yawRate=rand*count;
00413                 else
00414                   {
00415                     pcmd.yawRate=-rand*count;
00416                     count++;
00417                   }
00418                 neg=!neg;
00419                 pcmd.velocity=speed_limit;
00420                 safe=safety->control(pcmd);
00421               }
00422             if (safe >= Unsafe)
00423               {
00424                 pcmd.velocity=speed_limit;
00425                 navdata->reverse=false;
00426                 pcmd.yawRate=0;
00427                 result_t safe=safety->control(pcmd);
00428                 int count =1;
00429                 bool neg=false;
00430                 while (safe>=Unsafe && fabsf(pcmd.yawRate) <= Steering::maximum_yaw)
00431                   {
00432                     if (!neg)
00433                       pcmd.yawRate=rand*count;
00434                     else
00435                       {
00436                         pcmd.yawRate=-rand*count;
00437                         count++;
00438                       }
00439                     neg=!neg;
00440                     pcmd.velocity=speed_limit;
00441                     safe=safety->control(pcmd);
00442                   }     
00443               }
00444           }
00445         
00446       }
00447   
00448   
00449   // must always run this on the final command
00450   result = safety->control(pcmd);      
00451 
00452   if (result >=Unsafe)
00453     {
00454       pcmd.velocity=speed_limit;
00455       navdata->reverse=true;
00456     }
00457   
00458   pcmd.velocity=fminf(speed_limit,pcmd.velocity);
00459   
00460   last_park_dist=pcmd.velocity;
00461   if (navdata->reverse)
00462     last_park_dist*=-1;
00463   last_park_turn=pcmd.yawRate;
00464   
00465   lastYaw=pcmd.yawRate;
00466   trace("park_control controller", pcmd, result);
00467   return result;
00468 }
00469 
00470 // reset all subordinate controllers
00471 void PARK_control::reset(void)
00472 {
00473   trace_reset("PARK_control");
00474   reset_me();
00475   halt->reset();
00476   safety->reset();
00477   stop->reset();
00478 }
00479 
00480 
00481 // reset controller
00482 void PARK_control::reset_me(void)
00483 {
00484   navdata->reverse = false;
00485   halting=true;
00486   park_distance=0.0;
00487   park_turn=0.0;
00488   last_park_turn=0.0;
00489   last_park_dist=0.0;
00490   min_adj_dist=Infinite::distance;
00491   min_obst=10000;
00492 }
00493 
00494 
00495 // initialize U-turn operation
00496 Controller::result_t PARK_control::initialize(pilot_command_t& pcmd,
00497                                             const mapxy_list_t& obs_list)
00498 {
00499   int pcase=1;
00500 
00501   // Bearing to goal
00502   park_turn =Coordinates::bearing(estimate->pos,MapXY(new_end_pose));
00503   // Distance to goal
00504   park_distance = Euclidean::DistanceTo(new_end_pose,estimate->pos);
00505   
00506   // heading offset
00507   float dheading=Coordinates::normalize(new_end_pose.pa-estimate->pos.pa);
00508   
00509 
00510 
00511   if (hit_way_point(park_distance, park_turn, dheading) &&
00512       Epsilon::equal(estimate->vel.px,0.0))
00513     return Finished;  
00514   
00515   if (halting)
00516     return OK;
00517 
00518   float b=fabsf(park_turn);
00519   float h=fabsf(dheading);
00520 
00521 
00522 
00523   if (b < DTOR(45))
00524     if (h < DTOR(45))
00525       pcase=1;
00526     else if (h <DTOR(135) && dheading > 0)
00527       pcase=5;
00528     else if (h <DTOR(135) && dheading < 0)
00529       pcase=7;
00530     else pcase=6;
00531   else if (b < DTOR(135) && park_turn >0)
00532     if (h < DTOR(45))
00533       pcase=8;
00534     else if (h <DTOR(135) && dheading > 0)
00535       pcase=2;
00536     else if (h <DTOR(135) && dheading < 0)
00537       pcase=10;
00538     else pcase=9;
00539   else if (b < DTOR(135) && park_turn < 0)
00540     if (h < DTOR(45))
00541       pcase=14;
00542     else if (h <DTOR(135) && dheading > 0)
00543       pcase=15;
00544     else if (h <DTOR(135) && dheading < 0)
00545       pcase=4;
00546     else pcase=16;
00547   else
00548     if (h < DTOR(45))
00549       pcase=11;
00550     else if (h <DTOR(135) && dheading > 0)
00551       pcase=12;
00552     else if (h <DTOR(135) && dheading < 0)
00553       pcase=13;
00554     else pcase=3;
00555 
00556   std::cerr << "Bearing: "<<RTOD(park_turn)<<"\t dhead: "<<RTOD(dheading)<<"\t distance "<<park_distance<<std::endl;
00557   std::cerr << "Case: "<<pcase<<"\n";
00558 
00559   switch(pcase)
00560     {
00561     case 1:
00562       if (fabsf(sinf(park_turn)*park_distance) <
00563           fabsf(sinf(dheading)*(park_distance+ 3.5)))
00564         park_turn=dheading;
00565       break;
00566     case 2:
00567     case 4:
00568       if (fabsf(dheading) > fabsf(park_turn))
00569         park_turn = dheading;
00570       break;
00571     case 3:
00572       {
00573         float new_turn=Coordinates::normalize(park_turn+M_PI);
00574         float new_head=Coordinates::normalize(dheading+M_PI);
00575         if (fabsf(sinf(new_turn)*park_distance) <
00576             fabsf(sinf(new_head)*(park_distance+ 3.5)))
00577           park_turn=dheading;
00578         park_distance*=-1;
00579         navdata->reverse=true;
00580       }
00581       break;
00582     case 5:
00583     case 6:
00584     case 7:
00585     case 9:
00586     case 16:
00587       break;
00588     case 8:
00589     case 10:
00590     case 14:
00591     case 15:
00592       park_turn*=1;
00593       park_distance*=-1;
00594       navdata->reverse=true;
00595       break;
00596     case 11:
00597       park_distance*=-1;
00598       navdata->reverse=true;
00599       park_turn=0;
00600       break;
00601     case 12:
00602     case 13:
00603       park_turn=dheading;
00604       park_distance*=-1;
00605       navdata->reverse=true;
00606       break;
00607     }
00608 
00609   if (fabsf(park_distance) < fmaxf(Steering::steer_speed_min,pcmd.velocity) && fabsf(park_turn) < Steering::maximum_yaw)
00610     pcmd.yawRate=park_turn;
00611   else
00612     pcmd.yawRate= fmaxf(Steering::steer_speed_min, pcmd.velocity)/
00613       fabs(park_distance)* park_turn * park_turn_ratio;
00614   pcmd.yawRate=fmaxf(-Steering::maximum_yaw/2,
00615                      fminf(Steering::maximum_yaw/2,pcmd.yawRate));
00616   
00617   if (safety->control(pcmd) < Unsafe)
00618     {
00619       return OK;
00620     }
00621   pcmd.velocity=speed_limit;
00622   navdata->reverse=true;
00623   pcmd.yawRate=dheading;
00624 
00625   if (safety->control(pcmd) < Unsafe)
00626     {
00627       return OK;
00628     }
00629 
00630   navdata->reverse=!navdata->reverse;
00631   pcmd.yawRate*=1;
00632   pcmd.velocity=speed_limit;
00633   
00634   if (safety->control(pcmd) < Unsafe)
00635     {
00636       return OK;
00637     }  
00638 
00639 
00640   return NotApplicable;
00641 
00642 }
00643 
00644 bool PARK_control::hit_way_point(float goal_distance, float goal_turn,
00645                                float dheading) {
00646   bool done=false;
00647   
00648   float car_bearing=Coordinates::bearing(new_end_pose,MapXY(estimate->pos));
00649   
00650   switch(state)
00651     {
00652     case hit_waypoint:
00653     case approach_spot:
00654       {
00655         if (fabsf(dheading) < DTOR(30))
00656           if (goal_distance < 1.0 ||
00657               (fabsf(car_bearing) < HALFPI))
00658             done=true;
00659       }
00660       break;
00661     case pull_in:
00662       {
00663         //      if (fabsf(dheading) < DTOR(20))
00664         if (goal_distance < 0.75 ||
00665             fabsf(car_bearing) < HALFPI)
00666           done=true;
00667       }
00668       break;
00669     case pull_out:
00670       {
00671         if (fabsf(dheading) > DTOR(45) ||
00672             fabsf(car_bearing) > HALFPI ||
00673             goal_distance < 1.0)
00674           //        fabsf(goal_turn) < HALFPI)
00675           done=true;
00676       }
00677       break;
00678     }      
00679 
00680   course->no_waypoint_reached();
00681 
00682   if (done)
00683     {
00684       navdata->last_waypt=order->waypt[1].id;
00685     }
00686 
00687   return done;
00688   
00689 }
00690 
00691 bool PARK_control::small_segment(float distance, float turn) {
00692   return (fabsf(distance) < min_distance &&
00693           fabsf(turn) < min_theta);
00694 }
00695 


art_nav
Author(s): Austin Robot Technology, Jack O'Quin
autogenerated on Fri Jan 3 2014 11:08:43