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 #include "flyer_controller/control_mode.h"
00035 #include "flyer_controller/hover_modes.h"
00036 
00037 
00038 #include "flyer_controller/control_mode_autosequence_info.h"
00039 #include "flyer_controller/Autosequence.h"
00040 #include "flyer_controller/GetAutosequence.h"
00041 
00042 namespace flyer_controller
00043 {
00044 
00045 const int BTN_PROCEED = 8;
00046 const int BTN_PAUSE = 7;
00047 
00048 struct autosequence_point
00049 {
00050   hover_point point;
00051   bool pause;
00052 };
00053 
00054 typedef vector<autosequence_point> autosequence;
00055 
00056 namespace AutosequenceTypes
00057 {
00058 enum WaypointUpdateStates
00059 {
00060   WAITING_PROCEED = 0, MOVING = 1, PAUSED = 2, IDLE = 3
00061 };
00062 typedef WaypointUpdateStates WaypointUpdateState;
00063 }
00064 
00065 class ControlModeAutosequence : public HoverMode
00066 {
00067 private:
00068   
00069   double waypoint_update_rate; 
00070   double reached_tolerance; 
00071   double reached_tolerance_yaw; 
00072   double waypoint_speed; 
00073   double max_waypoint_lead; 
00074   
00075   ros::Publisher autosequence_info_pub;
00076   
00077   ros::ServiceServer get_autosequence_srv;
00078   
00079   ros::Timer waypoint_update_timer;
00080   
00081   bool executing;
00082   string current_autosequence;
00083   unsigned int current_point;
00084   AutosequenceTypes::WaypointUpdateState wp_update_state;
00085   hover_point segment_start;
00086   hover_point segment_end;
00087   bool proceed_commanded;
00088   bool pause_commanded;
00089   bool cancel_commanded;
00090   control_mode_autosequence_info autosequence_info_msg;
00091 
00092 public:
00093   ControlModeAutosequence() :
00094     HoverMode("autosequence"), waypoint_update_rate(10), reached_tolerance(0.05), reached_tolerance_yaw(5.0),
00095         waypoint_speed(0.05), max_waypoint_lead(0.1), executing(false), current_autosequence(""), current_point(0),
00096         wp_update_state(AutosequenceTypes::IDLE), proceed_commanded(false), pause_commanded(false),
00097         cancel_commanded(false)
00098   {
00099 
00100   }
00101 
00102   void onInit()
00103   {
00104     HoverMode::onInit();
00105     nh_priv.param("waypoint_update_rate", waypoint_update_rate, waypoint_update_rate);
00106     nh_priv.param("reached_tolerance", reached_tolerance, reached_tolerance);
00107     nh_priv.param("reached_tolerance_yaw", reached_tolerance_yaw, reached_tolerance_yaw);
00108     nh_priv.param("waypoint_speed", waypoint_speed, waypoint_speed);
00109     nh_priv.param("max_waypoint_lead", max_waypoint_lead, max_waypoint_lead);
00110 
00111     autosequence_info_pub = nh_priv.advertise<control_mode_autosequence_info> ("autosequence_info", 10);
00112     get_autosequence_srv = nh_priv.advertiseService("get_autosequence",
00113                                                     &ControlModeAutosequence::get_autosequence_callback, this);
00114   }
00115 
00116 private:
00117   map<string, autosequence> autosequences;
00118 
00119   bool autosequence_exists(const string autosequence_name)
00120   {
00121     map<string, autosequence>::iterator it;
00122     it = autosequences.find(autosequence_name);
00123     return (not (it == autosequences.end()));
00124   }
00125 
00126   
00127 
00128 
00129 
00130 
00131 
00132 
00133 
00134 
00135 
00136 
00137 
00138 
00139 
00140 
00141 
00142 
00143 
00144 
00145 
00146 
00147   bool parseControlModeCmdDerived(const string cmd)
00148   {
00149     vector < string > words;
00150     boost::split(words, cmd, boost::is_any_of(" \t\n,"), boost::token_compress_on);
00151     int nw = words.size();
00152 
00153     if (words[0] == "define" and words[1] == "autosequence")
00154     {
00155       string autosequence_name = words[2];
00156       if (autosequence_exists(autosequence_name))
00157       {
00158         NODELET_WARN_STREAM("Autosequence '" << autosequence_name << "' exists and will be redefined.");
00159       }
00160       int i = 3;
00161       autosequence new_autosequence;
00162       bool fail = false;
00163       while ((i < nw) and not fail)
00164       {
00165         bool pause = false;
00166         if ((i < nw - 1) and words[i + 1] == "pause")
00167         {
00168           pause = true;
00169         }
00170         autosequence_point new_autosequence_point;
00171         if (hover_point_exists(words[i]))
00172         {
00173           NODELET_DEBUG_STREAM("Adding point " << words[i] << " to autosequence");
00174           new_autosequence_point.point = hover_points[words[i]];
00175           new_autosequence_point.pause = pause;
00176           new_autosequence.push_back(new_autosequence_point);
00177           if (pause)
00178             i += 2;
00179           else
00180             i++;
00181         }
00182         else
00183         {
00184           NODELET_ERROR_STREAM("Unknown hover point '" << words[i] << "'.");
00185           fail = true;
00186         }
00187       }
00188       if (!fail)
00189       {
00190         autosequences[autosequence_name] = new_autosequence;
00191         NODELET_INFO_STREAM("Completed autosequence definition for '" << autosequence_name << "' with "
00192             << new_autosequence.size() << " points");
00193         
00194       }
00195       else
00196       {
00197         NODELET_ERROR("Autosequence definition failed");
00198       }
00199 
00200     }
00201     else if (words[0] == "execute" and words[1] == "autosequence")
00202     {
00203       if (nw == 3)
00204       {
00205         if (autosequence_exists(words[2]))
00206         {
00207           if (not executing)
00208           {
00209             start_autosequence(words[2]);
00210           }
00211           else
00212           {
00213             NODELET_ERROR("Autosequence already executing");
00214           }
00215         }
00216         else
00217         {
00218           NODELET_ERROR_STREAM("Unknown autosequence '" << words[2] << "'");
00219         }
00220       }
00221       else
00222       {
00223         NODELET_ERROR("Invalid command");
00224       }
00225     }
00226     else if (words[0] == "proceed")
00227     {
00228       if (executing and ((wp_update_state == AutosequenceTypes::WAITING_PROCEED) or (wp_update_state
00229           == AutosequenceTypes::PAUSED)))
00230       {
00231         proceed_commanded = true;
00232       }
00233       else
00234       {
00235         NODELET_ERROR("Invalid command");
00236       }
00237     }
00238     else if (words[0] == "pause")
00239     {
00240       if (executing and (wp_update_state == AutosequenceTypes::MOVING))
00241       {
00242         pause_commanded = true;
00243       }
00244       else
00245       {
00246         NODELET_ERROR("Invalid command");
00247       }
00248 
00249     }
00250     else if (words[0] == "cancel")
00251     {
00252       if (executing)
00253       {
00254         NODELET_WARN_STREAM("Cancelling autosequence by operator request");
00255         cancel_commanded = true;
00256       }
00257       else
00258       {
00259         NODELET_ERROR("Invalid command");
00260       }
00261     }
00262     else
00263     {
00264       return false;
00265     }
00266     return true;
00267   }
00268 
00269   void start_autosequence(const string& autosequence_name)
00270   {
00271     NODELET_INFO("Starting autosequence - press PROCEED on joystick");
00272     
00273     executing = true;
00274     wp_update_state = AutosequenceTypes::WAITING_PROCEED;
00275     current_autosequence = autosequence_name;
00276     current_point = 0;
00277     
00278     segment_start.north = latest_state.pose.pose.position.x;
00279     segment_start.east = latest_state.pose.pose.position.y;
00280     segment_end = autosequences[autosequence_name][current_point].point;
00281     
00282     NODELET_INFO_STREAM("Destination: " << segment_end.north << " " << segment_end.east << " " << segment_end.yaw);
00283     waypoint_update_timer = nh.createTimer(ros::Duration(1 / waypoint_update_rate),
00284                                            &ControlModeAutosequence::updateWaypointCallback, this);
00285   }
00286 
00287   void cancel_autosequence()
00288   {
00289     executing = false;
00290     cancel_commanded = false;
00291     wp_update_state = AutosequenceTypes::IDLE;
00292     current_autosequence = "";
00293     current_point = 0;
00294     waypoint_update_timer.stop();
00295   }
00296 
00297   void proceed_autosequence()
00298   {
00299     NODELET_INFO("Proceeding");
00300     proceed_commanded = false;
00301     wp_update_state = AutosequenceTypes::MOVING;
00302     NODELET_INFO_STREAM("Destination: " << segment_end.north << " " << segment_end.east << " " << segment_end.yaw);
00303   }
00304 
00305   void pause_autosequence()
00306   {
00307     NODELET_INFO("Pausing (operator commanded)");
00308     wp_update_state = AutosequenceTypes::PAUSED;
00309     pause_commanded = false;
00310   }
00311 
00312   void complete_autosequence()
00313   {
00314     NODELET_INFO("Autosequence complete");
00315     cancel_autosequence();
00316   }
00317 
00318   void updateWaypointCallback(const ros::TimerEvent& event)
00319   {
00320     
00321 
00322 
00323 
00324 
00325 
00326 
00327 
00328 
00329 
00330 
00331 
00332 
00333 
00334 
00335 
00336 
00337 
00338 
00339 
00340 
00341 
00342 
00343 
00344 
00345 
00346 
00347 
00348 
00349 
00350 
00351 
00352 
00353 
00354 
00355 
00356 
00357 
00358 
00359 
00360 
00361 
00362 
00363 
00364 
00365 
00366 
00367 
00368 
00369 
00370   }
00371 
00372   void do_reached_point()
00373   {
00374     NODELET_DEBUG_STREAM("Reached " << segment_end.name);
00375     set_hover_point(segment_end, false);
00376     if (current_point < autosequences[current_autosequence].size() - 1)
00377     {
00378       
00379       segment_start = segment_end;
00380       segment_end = autosequences[current_autosequence][current_point + 1].point;
00381       
00382       if (autosequences[current_autosequence][current_point].pause)
00383       {
00384         wp_update_state = AutosequenceTypes::PAUSED;
00385         NODELET_INFO("Pausing (per autosequence definition) - press PROCEED button");
00386         NODELET_INFO_STREAM("Destination: " << segment_end.north << " " << segment_end.east << " " << segment_end.yaw);
00387       }
00388       else
00389       {
00390         NODELET_DEBUG_STREAM("Destination: " << segment_end.north << " " << segment_end.east << " " << segment_end.yaw);
00391         
00392       }
00393       current_point++;
00394     }
00395     else
00396     {
00397       complete_autosequence();
00398     }
00399 
00400   }
00401 
00402   bool reached_point(const hover_point& point)
00403   {
00404     double north_err;
00405     double east_err;
00406     double yaw_err;
00407     get_current_error_to_point(point, north_err, east_err, yaw_err);
00408     double error_norm = sqrt(north_err * north_err + east_err * east_err);
00409     bool reached = (error_norm <= reached_tolerance and (fabs(angles::to_degrees(yaw_err)) < reached_tolerance_yaw));
00410     
00411     return reached;
00412   }
00413 
00414   double norm2(double x1, double x2)
00415   {
00416     return sqrt(x1 * x1 + x2 * x2);
00417   }
00418 
00419   void calc_waypoint_location(hover_point& new_point, const double dt)
00420   {
00421     
00422     
00423     
00424     double delta_north = segment_end.north - segment_start.north;
00425     double delta_east = segment_end.east - segment_start.east;
00426     
00427     double norm_delta = norm2(delta_north, delta_east);
00428     double dir_north = 0;
00429     double dir_east = 0;
00430     if (norm_delta > 0.001)
00431     {
00432       dir_north = delta_north / norm_delta;
00433       dir_east = delta_east / norm_delta;
00434     }
00435     
00436     
00437     new_point.north = north_cmd + dir_north * dt * waypoint_speed;
00438     new_point.east = east_cmd + dir_east * dt * waypoint_speed;
00439     new_point.north_vel = dir_north * waypoint_speed;
00440     new_point.east_vel = dir_east * waypoint_speed;
00441     double norm_now = norm2(new_point.north - segment_start.north, new_point.east - segment_start.east);
00442     
00443     if (norm_now > norm_delta)
00444     {
00445       new_point.north = segment_end.north;
00446       new_point.east = segment_end.east;
00447     }
00448 
00449     if (not isnan(segment_end.yaw))
00450     {
00451       new_point.yaw = segment_end.yaw;
00452     }
00453     else
00454     {
00455       new_point.yaw = yaw_cmd;
00456     }
00457   }
00458 
00459   bool get_autosequence_callback(flyer_controller::GetAutosequence::Request& req,
00460                                  flyer_controller::GetAutosequence::Response& resp)
00461   {
00462     if (autosequence_exists(req.autosequence_name))
00463     {
00464       resp.found = true;
00465       resp.autosequence.name = req.autosequence_name;
00466       resp.autosequence.num_points = autosequences[req.autosequence_name].size();
00467       for (int i = 0; i < resp.autosequence.num_points; i++)
00468       {
00469         autosequence_point cur_pt = autosequences[req.autosequence_name][i];
00470         flyer_controller::AutosequencePoint new_ap;
00471         new_ap.pause = cur_pt.pause;
00472         new_ap.hover_point.name = cur_pt.point.name;
00473         new_ap.hover_point.x = cur_pt.point.north;
00474         new_ap.hover_point.y = cur_pt.point.east;
00475         new_ap.hover_point.vx = cur_pt.point.north_vel;
00476         new_ap.hover_point.vy = cur_pt.point.east_vel;
00477         new_ap.hover_point.yaw = cur_pt.point.yaw;
00478         resp.autosequence.points.push_back(new_ap);
00479       }
00480     }
00481     else
00482     {
00483       resp.found = false;
00484     }
00485     return true;
00486   }
00487 
00488   void reportStatusTimerCallback(const ros::TimerEvent& e)
00489   {
00490     HoverMode::reportStatusTimerCallback(e);
00491     control_mode_autosequence_infoPtr autosequence_info_msg(new control_mode_autosequence_info);
00492     autosequence_info_msg->current_autosequence = current_autosequence;
00493     autosequence_info_msg->current_point = current_point;
00494     autosequence_info_msg->header.stamp = e.current_real;
00495     switch (wp_update_state)
00496     {
00497       case AutosequenceTypes::IDLE:
00498         autosequence_info_msg->status = control_mode_autosequence_info::IDLE;
00499         break;
00500       case AutosequenceTypes::PAUSED:
00501         autosequence_info_msg->status = control_mode_autosequence_info::PAUSED;
00502         break;
00503       case AutosequenceTypes::WAITING_PROCEED:
00504         autosequence_info_msg->status = control_mode_autosequence_info::WAITING_PROCEED;
00505         break;
00506       case AutosequenceTypes::MOVING:
00507         autosequence_info_msg->status = control_mode_autosequence_info::MOVING;
00508         break;
00509     }
00510     
00511     autosequence_info_msg->defined_autosequences.clear();
00512     for (map<string, autosequence>::iterator iter = autosequences.begin(); iter != autosequences.end(); ++iter)
00513     {
00514       autosequence_info_msg->defined_autosequences.push_back(iter->first);
00515     }
00516     autosequence_info_pub.publish(autosequence_info_msg);
00517 
00518   }
00519 
00520 }; 
00521 
00522 PLUGINLIB_DECLARE_CLASS(flyer_controller, ControlModeAutosequence, flyer_controller::ControlModeAutosequence, nodelet::Nodelet)
00523 ;
00524 
00525 }