control_mode_autosequence.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2010, UC Regents
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of the University of California nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *********************************************************************/
00034 #include "flyer_controller/control_mode.h"
00035 #include "flyer_controller/hover_modes.h"
00036 // msg:
00037 //#include "flyer_controller/control_mode_hover_info.h"
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   // Parameters
00069   double waypoint_update_rate; // [Hz] rate at which to update the controller setpoint
00070   double reached_tolerance; // [m] when within this lateral distance of an autosequence point, consider that point to be 'reached'
00071   double reached_tolerance_yaw; // [deg] when within this angular distance of an autosequence point's yaw value (if defined), consider that point to be 'reached'
00072   double waypoint_speed; // [m/s] lateral speed at which to move the controller setpoint between autosequence points
00073   double max_waypoint_lead; // [m] how far from the current position can the moving waypoint be (per axis)? (NOT IMPLEMENTED)
00074   // Publishers
00075   ros::Publisher autosequence_info_pub;
00076   // Services
00077   ros::ServiceServer get_autosequence_srv;
00078   // Timers
00079   ros::Timer waypoint_update_timer;
00080   // Members
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   /* Autosequence control_mode_cmd syntax:
00127    Define a new autosequence, made up of the named hover_points (which should have been
00128    previously defined with set hover_point commands):
00129    define autosequence my_autosequence point_name1 [pause] [,point_name2 [pause]] ... [,point_nameN]
00130 
00131    Set commanded altitude to 1.23 (can only be lower than joystick altitude):
00132    alt_override 1.23
00133 
00134    Shorthand to define a single-point autosequence and execute it: (NOT IMPLEMENTED!)
00135    goto 1.23 -0.5 45 // north east [yaw]
00136 
00137    Execute autosequence:
00138    execute autosequence foo
00139 
00140    Proceed with autosequence:
00141    proceed
00142 
00143    Cancel autosequence:
00144    cancel
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         //        publish_autosequence_trajectory_viz(new_autosequence);
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     //    publish_autosequence_trajectory_viz(autosequences[autosequence_name]);
00273     executing = true;
00274     wp_update_state = AutosequenceTypes::WAITING_PROCEED;
00275     current_autosequence = autosequence_name;
00276     current_point = 0;
00277     //set_hover_point(autosequences[autosequence_name][current_point].point);
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     //    publish_current_destination_marker(segment_end);
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     // TODO: rework for new method of joystick handling
00321 //    static sensor_msgs::Joy prev_joy;
00322 //    if (cancel_commanded)
00323 //    {
00324 //      cancel_autosequence();
00325 //    }
00326 //    else
00327 //    {
00328 //      switch (wp_update_state)
00329 //      {
00330 //        case AutosequenceTypes::IDLE:
00331 //          break;
00332 //        case AutosequenceTypes::PAUSED:
00333 //          if (proceed_commanded or ((latest_opercmd.buttons[BTN_PROCEED] == 1) and (prev_joy.buttons[BTN_PROCEED] == 0)))
00334 //          {
00335 //            proceed_autosequence();
00336 //          }
00337 //          break;
00338 //        case AutosequenceTypes::WAITING_PROCEED:
00339 //          if (proceed_commanded or ((latest_opercmd.buttons[BTN_PROCEED] == 1) and (prev_joy.buttons[BTN_PROCEED] == 0)))
00340 //          {
00341 //            proceed_autosequence();
00342 //          }
00343 //          break;
00344 //        case AutosequenceTypes::MOVING:
00345 //          if (pause_commanded or ((latest_opercmd.buttons[BTN_PAUSE] == 1) and (prev_joy.buttons[BTN_PAUSE] == 0)))
00346 //          {
00347 //            pause_autosequence();
00348 //          }
00349 //          else
00350 //          {
00351 //            if (reached_point(segment_end))
00352 //            {
00353 //              do_reached_point();
00354 //            }
00355 //            else
00356 //            {
00357 //              hover_point new_point;
00358 //              new_point.north_vel = 0;
00359 //              new_point.east_vel = 0;
00360 //              new_point.name = "_autosequence_waypoint";
00361 //              calc_waypoint_location(new_point, (event.current_real - event.last_real).toSec());
00362 //              set_hover_point(new_point, false);
00363 //            }
00364 //          }
00365 //          break;
00366 //      }
00367 //    }
00368 //
00369 //    prev_joy = latest_opercmd;
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       //set_hover_point(autosequences[current_autosequence][current_point + 1].point);
00379       segment_start = segment_end;
00380       segment_end = autosequences[current_autosequence][current_point + 1].point;
00381       //                publish_current_destination_marker(segment_end);
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         // stay in MOVING
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     //NODELET_INFO_STREAM("Reached: " << (reached ? "true" : "false") << " Error_norm = " << error_norm << " Yaw_err = " << yaw_err);
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     //ros::Duration t_segment = ros::Time::now() - segment_start_time;
00422     //    double current_north, current_east;
00423     //    get_current_lateral_position(current_north, current_east);
00424     double delta_north = segment_end.north - segment_start.north;
00425     double delta_east = segment_end.east - segment_start.east;
00426     //    NODELET_INFO_STREAM("delta_north = " << delta_north << " delta_east = " << delta_east);
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     //      NODELET_INFO_STREAM("dir_north = " << dir_north << " dir_east = " << dir_east);
00436     //      NODELET_INFO_STREAM("dt = " << dt);
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     //double distance = min(norm_delta, waypoint_speed * t_segment.toSec());
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     // @todo: don't redo this every iteration..
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 }; // class
00521 
00522 PLUGINLIB_DECLARE_CLASS(flyer_controller, ControlModeAutosequence, flyer_controller::ControlModeAutosequence, nodelet::Nodelet)
00523 ;
00524 
00525 } // namespace


flyer_controller
Author(s): Patrick Bouffard
autogenerated on Sun Jan 5 2014 11:37:53