run.cc
Go to the documentation of this file.
00001 /*
00002  *  Navigator run controller
00003  *
00004  *  Copyright (C) 2007, 2010, Austin Robot Technology
00005  *  License: Modified BSD Software License Agreement
00006  *
00007  *  $Id: run.cc 1856 2011-11-18 00:39:09Z jack.oquin $
00008  */
00009 
00010 #include "navigator_internal.h"
00011 #include "Controller.h"
00012 #include "course.h"
00013 #include "obstacle.h"
00014 #include "ntimer.h"
00015 #include "run.h"
00016 
00017 #include "halt.h"
00018 #include "road.h"
00019 #if NOT_PORTED_TO_ROS
00020 #include "safety.h"
00021 #include "voronoi_zone.h"
00022 #endif
00023 
00024 #include <art_nav/estimate.h>
00025 #include <art_map/ZoneOps.h>
00026 
00027 /* @brief Navigator run controller */
00028 
00029 static const char *state_name[] =
00030   {
00031     "Continue",
00032     "Escape",
00033     "Replan",
00034   };
00035 
00036 Run::Run(Navigator *navptr, int _verbose):
00037   Controller(navptr, _verbose)
00038 {
00039   halt =        new Halt(navptr, _verbose);
00040   road =        new Road(navptr, _verbose);
00041 #if NOT_PORTED_TO_ROS
00042   safety =      new Safety(navptr, _verbose);
00043   unstuck =     new VoronoiZone(navptr, _verbose);
00044 
00045   escape_timer = new NavTimer(cycle);
00046 #endif
00047   go_state = Continue;
00048 };
00049 
00050 Run::~Run()
00051 {
00052   delete halt;
00053   delete road;
00054 #if NOT_PORTED_TO_ROS
00055   delete safety;
00056   delete unstuck;
00057 
00058   delete escape_timer;
00059 #endif
00060 };
00061 
00062 // go to escape state
00063 void Run::begin_escape(void)
00064 {
00065 #if NOT_PORTED_TO_ROS
00066   unstuck->reset();
00067   blockage_pose = estimate->pos;
00068   blockage_waypt_dist =
00069     Euclidean::DistanceToWaypt(estimate->pos, order->waypt[1]);
00070   escape_timer->Start(escape_timeout_secs);
00071   set_go_state(Escape);
00072 #endif
00073 }
00074 
00087 Controller::result_t Run::control(pilot_command_t &pcmd)
00088 {
00089   // Do nothing if the order is still Run.  Wait until Commander sends
00090   // a new behavior.  Also, wait until the course controller receives
00091   // data from the maplanes driver.
00092   if (NavBehavior(order->behavior) == NavBehavior::Run
00093       || course->polygons.empty())
00094     {
00095       ROS_DEBUG_STREAM("run controller not initialized, have "
00096                        << course->polygons.size() << " polygons");
00097       // Run order in Run state is valid, but does nothing.
00098       // Do nothing until lanes data are initialized.
00099       return halt->control(pcmd);
00100     }
00101   
00102   // initialize pilot command to speed limit, straight ahead
00103   pcmd.yawRate = 0.0;
00104   pcmd.velocity = fminf(order->max_speed, config_->max_speed);
00105   
00106   // estimate current dead reckoning position based on time of current
00107   // cycle and latest odometry course and speed
00108   Estimate::control_pose(*odom, ros::Time::now(), *estimate);
00109 
00110   course->begin_run_cycle();
00111 
00112   trace("begin run controller", pcmd);
00113 
00114   result_t result;
00115 
00116   // select subordinate controller based on order behavior
00117   switch (order->behavior.value)
00118     {
00119     case NavBehavior::Go:
00120       result = go(pcmd);
00121       break;
00122 
00123     case NavBehavior::Initialize: 
00124       result = initialize(pcmd);
00125       break;
00126       
00127     default:
00128       ROS_ERROR("unsupported Navigator behavior: %s (halting)",
00129                 NavBehavior(order->behavior).Name());
00130       halt->control(pcmd);
00131       result = NotImplemented;
00132     }
00133 
00134 #if NOT_PORTED_TO_ROS
00135   if (extra_safety_check)
00136     {
00137       // make safety check for obstacle in our immediate path
00138       result_t sres = safety->control(pcmd);
00139       if (sres != OK)
00140         result = sres;
00141     }
00142 #endif
00143 
00144   if (navdata->reverse)
00145     {
00146       // modify pilot command to use reverse motion
00147       pcmd.velocity = -pcmd.velocity;
00148     }
00149 
00150   course->end_run_cycle();
00151 
00152   trace("run controller", pcmd, result);
00153 
00154   return result;
00155 };
00156 
00166 Controller::result_t Run::initialize(pilot_command_t &pcmd)
00167 {
00168   result_t result;
00169 
00170   ElementID start_way = starting_waypt();
00171   if (start_way != ElementID())
00172     {
00173       course->new_waypoint_reached(start_way);
00174       ROS_INFO("starting way-point: %s", start_way.name().str);
00175       result = OK;
00176     }
00177   else
00178     {
00179       // no starting way-point found
00180       ROS_WARN("no starting way-point found, run failed.");
00181       result = NotApplicable;
00182       course->no_waypoint_reached();
00183     }
00184   
00185   halt->control(pcmd);
00186   return result;
00187 }
00188 
00189 
00219 Controller::result_t Run::go(pilot_command_t &pcmd)
00220 {
00221   if (ElementID(order->waypt[0].id) == ElementID(order->waypt[1].id))
00222     {
00223       // halt and let Commander catch up (does not count as timeout)
00224       ROS_INFO("already reached all way-points in order, halting");
00225       return halt->control(pcmd);
00226     }
00227 
00228 #if 0 // not doing blockage timer yet
00229   // check whether car moving, set blockage timer appropriately
00230   obstacle->update_blockage_state();
00231 
00232   // increment and check blockage timer -- do once per cycle
00233   if (obstacle->blockage_timeout())
00234     {
00235       obstacle->unblocked();            // cancel timer
00236       if (escape)
00237         {
00238           ART_MSG(1, "Run controller blocked, try to escape.");
00239           begin_escape();
00240         }
00241       else
00242         ART_MSG(1, "Run controller blocked, but not trying to escape.");
00243     }
00244 #endif // no blockage timeout
00245 
00246   switch (go_state)
00247     {
00248 #if 0 // not doing Escape yet
00249     case Escape:
00250       {
00251         float blockage_distance =
00252           Euclidean::DistanceTo(blockage_pose, estimate->pos);
00253 
00254         if (!escape_timer->Check()
00255             && blockage_distance < escape_distance)
00256           {
00257             // vehicle blocked, try to escape (reach waypt[1] if close)
00258             result_t result = unstuck->control(pcmd);
00259             if (result != Finished)
00260                 return result;
00261 
00262             ART_MSG(1, "Unstuck controller returns Finished");
00263           }
00264 
00265         ART_MSG(1, "Car moved %.3fm since blocking, try to replan.",
00266                 blockage_distance);
00267         escape_timer->Cancel();
00268         last_replan = order->replan_num;
00269         set_go_state(Replan);
00270         // fall through...
00271       }
00272 #endif // no escape yet
00273 
00274     case Replan:
00275       if (order->replan_num == last_replan)
00276         {
00277           ElementID start_id = starting_waypt();
00278           navdata->replan_waypt = start_id.toMapID();
00279           if (start_id == ElementID())
00280             {
00281               ROS_WARN("Unable to replan from here, keep trying to escape.");
00282               begin_escape();
00283             }
00284           return halt->control(pcmd);
00285         }
00286 
00287       // Commander issued new replanned order
00288       navdata->replan_waypt = ElementID().toMapID();
00289       road->reset();
00290       set_go_state(Continue);
00291       // fall through...
00292 
00293     case Continue:
00294       // normal processing -- run the road state machine
00295       return road->control(pcmd);
00296 
00297     default:
00298       // not reached, only to avoid compiler warning
00299       return NotImplemented;
00300     }
00301 }
00302 
00303 // reset all subordinate controllers
00304 void Run::reset(void)
00305 {
00306   go_state = Continue;
00307 
00308   halt->reset();
00309   road->reset();
00310 
00311 #if NOT_PORTED_TO_ROS
00312   safety->reset();
00313 #endif
00314 }
00315 
00317 void Run::set_go_state(state_t newstate)
00318 {
00319   if (go_state != newstate)
00320     {
00321       ROS_DEBUG("Go behavior state changing from %s to %s",
00322                 state_name[go_state], state_name[newstate]);
00323       go_state = newstate;
00324     }
00325 }
00326 
00333 ElementID Run::starting_waypt(void)
00334 {
00335   ElementID waypt;
00336 
00337 #if NOT_PORTED_TO_ROS
00338   // first look for a containing zone
00339   segment_id_t starting_zone =
00340     ZoneOps::containing_zone(course->zones, MapXY(estimate->pos));
00341 
00342   if (verbose >= 4)
00343     ART_MSG(2, "Run::starting_waypt() containing zone is %d", starting_zone);
00344 
00345   if(starting_zone > 0) {
00346     ZonePerimeter zone = ZoneOps::get_zone_by_id(course->zones, starting_zone);
00347     
00348     waypt = (ZoneOps::starting_node_for_zone(zone)).id;
00349     
00350     if (waypt != ElementID())
00351       {
00352         ART_MSG(2, "Starting at %s in zone %d",
00353                 waypt.name().str, zone.zone_id);
00354         return waypt;
00355       }
00356   }
00357 #endif
00358 
00359   // not in a zone -- find an appropriate lane polygon
00360   int index = pops->getStartingPoly(MapPose(estimate->pose.pose),
00361                                     course->polygons,
00362                                     config_->initialize_distance,
00363                                     config_->initialize_min_angle);
00364 
00365   if (index < 0)
00366     {
00367       // no starting way-point found
00368       ROS_FATAL_STREAM("getStartingPoly() failed, returning " << index);
00369     }
00370   else
00371     {
00372       waypt = course->polygons[index].start_way;
00373       ROS_DEBUG_STREAM("starting_waypt() is " << waypt.name().str
00374                        << ", polygon " << course->polygons[index].poly_id);
00375     }
00376 
00377   return waypt;
00378 }


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