controller.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 <ros/ros.h>
00035 #include <nodelet/nodelet.h>
00036 #include <pluginlib/class_list_macros.h>
00037 #include <diagnostic_updater/diagnostic_updater.h>
00038 #include <map>
00039 #include <string>
00040 #include <set>
00041 #include <algorithm>
00042 #include "topic_tools/MuxAdd.h"
00043 #include "topic_tools/MuxSelect.h"
00044 #include "topic_tools/MuxList.h"
00045 //#include "flyer_controller/control_mode.h"
00046 #include "flyer_controller/control_modes.h"
00047 #include "flyer_controller/control_mode_cmd.h"
00048 #include "flyer_controller/control_mode_status.h"
00049 #include "flyer_controller/controller_status.h"
00050 #include "flyer_controller/controller_cmd.h"
00051 #include <boost/algorithm/string.hpp>
00052 
00053 using namespace std;
00054 
00055 namespace flyer_controller
00056 {
00057 
00058 namespace ControllerTypes
00059 {
00060 enum ControllerStates
00061 {
00062   ERROR = 0, OFF = 1, INITIALIZE = 2, STANDBY = 3, OPERATIONAL = 4
00063 };
00064 typedef ControllerStates ControllerState;
00065 
00066 }
00067 
00068 using namespace ControllerTypes;
00069 
00070 class Controller : public nodelet::Nodelet
00071 {
00072 private:
00073   ros::NodeHandle nh;
00074   ros::NodeHandle nh_priv;
00075   // Parameters
00076   string initial_active_mode;
00077   string initial_standby_mode;
00078   double mainloop_rate;
00079   // Publishers
00080   ros::Publisher status_pub;
00081   map<string, ros::Publisher> mode_cmd_pubs;
00082   // Subscribers
00083   ros::Subscriber cmd_sub;
00084   map<string, ros::Subscriber> mode_status_subs;
00085   // Timers
00086   ros::Timer mainloop_timer;
00087   // Diagnostic Updater
00088   diagnostic_updater::Updater diag_updater;
00089 
00090   // Service Servers
00091   ros::ServiceServer control_modes_service;
00092   // Members
00093   string current_mode;
00094   string standby_mode;
00095   set<string> registered_modes;
00096   map<string, string> node_mode_map; // map from node name to mode
00097   map<string, string> mode_node_map; //map from mode name to node
00098   map<string, control_mode_status> latest_mode_status;
00099   ControllerState state;
00100   string info;
00101   bool command_pending;
00102   string pending_command;
00103   boost::mutex mainloop_mutex;
00104   boost::mutex register_mutex;
00105 
00106   // Methods
00107 public:
00108   Controller() :
00109     initial_active_mode("idle"), initial_standby_mode("attitude"), mainloop_rate(5.0), diag_updater(), state(OFF),
00110         info(""), command_pending(false), pending_command("")
00111   {
00112   }
00113 
00114   void onInit()
00115   {
00116 
00117     nh = getMTNodeHandle();
00118     nh_priv = getMTPrivateNodeHandle();
00119 
00120     NODELET_INFO("controller.cpp onInit() begin");
00121 
00122     // Diagnostics
00123     diag_updater.add("Controller Status", this, &Controller::diagnostics);
00124     diag_updater.setHardwareID("none");
00125     diag_updater.force_update();
00126     // Parameters
00127     nh_priv.param("initial_active_mode", initial_active_mode, initial_active_mode);
00128     nh_priv.param("initial_standby_mode", initial_standby_mode, initial_standby_mode);
00129     nh_priv.param("mainloop_rate", mainloop_rate, mainloop_rate);
00130     // Publishers
00131     status_pub = nh_priv.advertise<controller_status> ("status", 1, true);
00132     // Subscribers
00133     cmd_sub = nh_priv.subscribe("cmd", 10, &Controller::commandCallback, this);
00134     // Service Server
00135     control_modes_service = nh_priv.advertiseService("control_modes", &Controller::controlModesServiceCallback, this);
00136 
00137     // Timers
00138     mainloop_timer = nh.createTimer(ros::Duration(1 / mainloop_rate), &Controller::mainLoopCallback, this);
00139 
00140     state = INITIALIZE;
00141 
00142     NODELET_INFO("controller.cpp onInit() done");
00143 
00144   }
00145 
00146   std::string stateToString(ControllerTypes::ControllerState t)
00147   {
00148     switch (t)
00149     {
00150       case ControllerTypes::OFF:
00151         return "OFF";
00152       case ControllerTypes::ERROR:
00153         return "ERROR";
00154       case ControllerTypes::INITIALIZE:
00155         return "INITIALIZE";
00156       case ControllerTypes::STANDBY:
00157         return "STANDBY";
00158       case ControllerTypes::OPERATIONAL:
00159         return "OPERATIONAL";
00160     }
00161     return "Unknown";
00162   }
00163 
00164 private:
00165 
00166   void diagnostics(diagnostic_updater::DiagnosticStatusWrapper& stat)
00167   {
00168     int status;
00169     status = ((state != ERROR) ? diagnostic_msgs::DiagnosticStatus::OK : diagnostic_msgs::DiagnosticStatus::ERROR);
00170     stat.summary(status, stateToString(state));
00171     stat.add("info", info);
00172     stat.add("registered modes", registered_modes.size());
00173     stat.add("current mode", current_mode);
00174     stat.add("standby mode", standby_mode);
00175   }
00176 
00177   void commandCallback(const controller_cmdConstPtr& msg)
00178   {
00179     // TODO: we could implement "callerid" to ensure that we are only getting commands
00180     // from 'authorized' sources..
00181     ROS_INFO_STREAM("Command received: " << msg->cmd);
00182     if (command_pending)
00183     {
00184       ROS_ERROR("Command already pending - new command ignored");
00185     }
00186     else
00187     {
00188       command_pending = true;
00189       pending_command = msg->cmd;
00190     }
00191   }
00192 
00193   bool controlModesServiceCallback(control_modes::Request& request, control_modes::Response& response)
00194   {
00195     boost::mutex::scoped_lock lock(register_mutex);
00196     ROS_INFO_STREAM("Service call received. Request was: " << request.request);
00197     vector<string> words;
00198     boost::split(words, request.request, boost::is_any_of(" "));
00199 
00200     if (words.size() > 0)
00201     {
00202       if (words[0] == "register")
00203       {
00204         if (words.size() != 3)
00205         {
00206           ROS_ERROR("Invalid request");
00207           response.response = "failure";
00208           response.reason = "invalid number of parameters";
00209         }
00210         else
00211         {
00212           string mode_name = words[1];
00213           string mode_node = words[2];
00214           if (registered_modes.count(mode_name) > 0)
00215           {
00216             ROS_ERROR_STREAM("A control mode named " << mode_name << " has already been registered.");
00217             response.response = "failure";
00218             response.reason = "control mode already registered";
00219           }
00220           else
00221           {
00222             ROS_INFO_STREAM("Registering control mode, name: " << mode_name << ", node: " << mode_node);
00223             mode_cmd_pubs[mode_name] = nh.advertise<control_mode_cmd> (mode_node + "/cmd", 1, true);
00224             //string topic = mode_node + "/control_mode_status";
00225             //            mode_status_subs[mode_name] = nh.subscribe(mode_node + "/status", 10,
00226             //                                                       &Controller::controlModesStatusCallback, this);
00227             mode_status_subs[mode_name]
00228                 = nh.subscribe<control_mode_status> (
00229                                                      mode_node + "/status",
00230                                                      10,
00231                                                      boost::bind(&Controller::controlModesStatusCallback, this, _1,
00232                                                                  mode_node));
00233             registered_modes.insert(mode_name);
00234             node_mode_map[nh.resolveName(mode_node)] = mode_name;
00235             mode_node_map[mode_name] = nh.resolveName(mode_node);
00236             response.response = "success";
00237           }
00238         }
00239       }
00240     }
00241     else
00242     {
00243       response.response = "failure";
00244       response.reason = "invalid request";
00245     }
00246     ROS_INFO_STREAM("Completed service call. Request was: " << request.request);
00247 
00248     return true; // or are we supposed to return false upon failure?
00249   }
00250 
00251   void controlModesStatusCallback(const flyer_controller::control_mode_statusConstPtr& msg, string source) //const ros::MessageEvent<flyer_controller::control_mode_status const>& event)
00252   {
00253     //    const std::string& publisher_name = event.getPublisherName();
00254     //    ROS_INFO_STREAM("Got control mode status from: " << publisher_name);
00255     //    latest_mode_status[node_mode_map[publisher_name]] = *(event.getMessage()); //msg;
00256     latest_mode_status[node_mode_map[source]] = *msg; //msg;
00257   }
00258 
00259   void mainLoopCallback(const ros::TimerEvent& e)
00260   {
00261     boost::mutex::scoped_lock lock(mainloop_mutex);
00262 
00263     diag_updater.update();
00264 
00265     switch (state)
00266     {
00267       case ERROR:
00268         break;
00269       case OFF:
00270         break;
00271       case INITIALIZE:
00272         execute_INITIALIZE();
00273         break;
00274       case STANDBY:
00275         execute_STANDBY();
00276         break;
00277       case OPERATIONAL:
00278         execute_OPERATIONAL();
00279         break;
00280       default:
00281         break;
00282     }
00283     controller_statusPtr status_msg(new controller_status);
00284     status_msg->state = state;
00285     status_msg->info = info;
00286     status_msg->active_mode = current_mode;
00287     status_msg->header.stamp = e.current_real;
00288     map<string, control_mode_status>::iterator it;
00289     getStandbyModes(status_msg->standby_modes);
00290     status_pub.publish(status_msg);
00291   }
00292 
00293   void getStandbyModes(vector<string>& modes)
00294   {
00295     map<string, control_mode_status>::iterator it;
00296     modes.clear();
00297     for (it = latest_mode_status.begin(); it != latest_mode_status.end(); it++)
00298     {
00299       if ((*it).second.state == control_mode_status::STATE_STANDBY)
00300       {
00301         modes.push_back((*it).first);
00302       }
00303     }
00304 
00305   }
00306 
00307   void execute_INITIALIZE()
00308   {
00309     // In this state we are waiting for our initial active and standby modes to register themselves..
00310     // We also need the mux to be ready to add topics
00311     static bool initialize_waiting_modes_mux = true, initialize_transitioned_active_mode = false,
00312                 initialize_transitioned_standby_mode = false, initialize_active_mode_in_standby = false,
00313                 initialize_standby_mode_in_standby = false, initialize_active_muxed = false, initialize_standby_muxed =
00314                     false;
00315     enum InitializePhases
00316     {
00317       INITIALIZE_WAIT_MODES_MUX, INITIALIZE_TRANSITION_ACTIVE, INITIALIZE_TRANSITION_STANDBY,
00318       INITIALIZE_WAIT_STANDBY_TALKBACK
00319     };
00320 
00321     static InitializePhases init_phase = INITIALIZE_WAIT_MODES_MUX;
00322 
00323     // TODO: complete this refactoring..
00324     switch (init_phase)
00325     {
00326       case INITIALIZE_WAIT_MODES_MUX:
00327       {
00328 
00329       }
00330         break;
00331     }
00332 
00333     if (initialize_waiting_modes_mux)
00334     {
00335       if (registered_modes.count(initial_active_mode) > 0 && registered_modes.count(initial_standby_mode) > 0
00336           && ros::service::exists("controller_mux/add", false))
00337       {
00338         ROS_INFO("Initial modes have registered");
00339         info = "got modes and mux";
00340         diag_updater.force_update();
00341         initialize_waiting_modes_mux = false;
00342       }
00343       else
00344       {
00345         info = "waiting for modes and mux";
00346       }
00347     }
00348     else // got modes and mux
00349     {
00350       topic_tools::MuxAdd mux_add_srv;
00351       if (!initialize_transitioned_active_mode) // need to command active mode to STANDBY
00352       {
00353         control_mode_cmdPtr active_to_standby_msg(new control_mode_cmd);
00354         active_to_standby_msg->cmd = "mode standby";
00355         mode_cmd_pubs[initial_active_mode].publish(active_to_standby_msg);
00356         initialize_transitioned_active_mode = true;
00357       }
00358       else
00359       {
00360         if (!initialize_active_muxed)
00361         {
00362           mux_add_srv.request.topic = "control_mode_" + initial_active_mode + "/output";
00363           if (ros::service::call("controller_mux/add", mux_add_srv))
00364           {
00365             initialize_active_muxed = true;
00366           }
00367         }
00368       }
00369       if (!initialize_transitioned_standby_mode) // need to command active mode to STANDBY
00370       {
00371         control_mode_cmdPtr standby_to_standby_msg(new control_mode_cmd);
00372         standby_to_standby_msg->cmd = "mode standby";
00373         mode_cmd_pubs[initial_standby_mode].publish(standby_to_standby_msg);
00374         initialize_transitioned_standby_mode = true;
00375       }
00376       else
00377       {
00378         if (!initialize_standby_muxed)
00379         {
00380           mux_add_srv.request.topic = "control_mode_" + initial_standby_mode + "/output";
00381           if (ros::service::call("controller_mux/add", mux_add_srv))
00382           {
00383             initialize_standby_muxed = true;
00384           }
00385         }
00386       }
00387       if (initialize_transitioned_active_mode && initialize_active_muxed && initialize_transitioned_standby_mode
00388           && initialize_standby_muxed)
00389       {
00390         info = "waiting for STANDBY talkback";
00391         //ROS_INFO_STREAM("Latest active status:" << int(latest_mode_status[initial_active_mode].state));
00392         if (latest_mode_status[initial_active_mode].state == control_mode_status::STATE_STANDBY
00393             && latest_mode_status[initial_standby_mode].state == control_mode_status::STATE_STANDBY)
00394         {
00395           ROS_INFO_STREAM("Initial active and standby modes reporting STANDBY state, controller going to STANDBY");
00396           state = STANDBY;
00397           info = "";
00398           current_mode = initial_active_mode;
00399           standby_mode = initial_standby_mode;
00400           diag_updater.force_update();
00401         }
00402       }
00403     }
00404   }
00405 
00406   void execute_STANDBY()
00407   {
00408     // This is the state that the Controller should end up in after a successful startup, with no action on the operator's part
00409     // required. In this state, both the 'active' and 'standby' control modes are in state STANDBY, meaning that they are
00410     // receiving joystick and state messages and they are routed to the mux. The mux however is still routing the nonexistent
00411     // 'dummy' topic.
00412     // In order to proceed to OPERATIONAL, the operator should have to perform some action, like clicking a specific joystick button
00413     // or something like that.
00414 
00415     // STANDBY:
00416     static bool standby_entering_operational = false, standby_commanded_active_mode = false,
00417                 standby_mux_selected_active = false;
00418 
00419     // TODO: add checking that current and standby modes are still in standby as expected; otherwise... go to ERROR?
00420     if (command_pending)
00421     {
00422       if (pending_command == "mode operational" and !standby_entering_operational)
00423       {
00424         ROS_INFO("Entering OPERATIONAL");
00425         command_pending = false;
00426         pending_command = "";
00427         info = "entering OPERATIONAL";
00428         diag_updater.force_update();
00429         standby_entering_operational = true;
00430       }
00431       else
00432       {
00433         ROS_ERROR("Invalid command in STANDBY mode");
00434         command_pending = false;
00435         pending_command = "";
00436       }
00437     }
00438     if (standby_entering_operational)
00439     {
00440       if (!standby_commanded_active_mode)
00441       {
00442         // To enter operational, the current mode has to be successfully transitioned to ACTIVE
00443         control_mode_cmdPtr current_to_active_msg(new control_mode_cmd);
00444         current_to_active_msg->cmd = "mode active";
00445         mode_cmd_pubs[current_mode].publish(current_to_active_msg);
00446         standby_commanded_active_mode = true;
00447         info = "commanded current mode to ACTIVE";
00448       }
00449       else
00450       {
00451         if (!standby_mux_selected_active)
00452         {
00453           topic_tools::MuxSelect mux_sel_srv;
00454           mux_sel_srv.request.topic = mode_node_map[current_mode] + "/output";
00455           ros::service::call("controller_mux/select", mux_sel_srv);
00456           standby_mux_selected_active = true;
00457           info = "requested mux select: " + mode_node_map[current_mode] + "/output";
00458         }
00459         else
00460         {
00461           // TODO: listen for mux talkback
00462         }
00463         // Check that current mode is reporting back as active
00464         if (latest_mode_status[current_mode].state == control_mode_status::STATE_ACTIVE)
00465         {
00466           state = OPERATIONAL;
00467           info = "current mode reporting ACTIVE";
00468           diag_updater.force_update();
00469         }
00470       }
00471     }
00472   }
00473 
00474   enum OPERATIONAL_Substate
00475   {
00476     OP_READY, OP_ACTIVATING_MODE, OP_STANDBYING_MODE
00477   };
00478 
00479   void execute_OPERATIONAL()
00480   {
00481     // Now in operational is where flying can be done. Controller's main job here is to arbitrate the switching of
00482     // modes. Note that since Controller has really no knowledge of what any specific mode does, it is up to the mode
00483     // being transitioned-to to determine if it's safe/appropriate to go ACTIVE.
00484     // The process of switching modes proceeds as follows:
00485     // - new_mode must equal standby_mode
00486     // - new_mode must be reporting 'ready' to become active (how?)
00487     // - (growth) active_mode is asked if it is okay to become inactive (think of a real case where this is needed)
00488     // - new_mode is commanded to become active and mux selects it
00489     static OPERATIONAL_Substate substate = OP_READY;
00490     static OPERATIONAL_Substate prev_substate = OP_READY;
00491     bool reset = true;
00492     string new_mode = "";
00493 
00494     if (substate == OP_READY)
00495     {
00496       execute_OPERATIONAL_READY(substate, new_mode);
00497     }
00498     if (substate != prev_substate)
00499     {
00500       ROS_DEBUG_STREAM("Operational substate changed: " << prev_substate << " -> " << substate);
00501       reset = true;
00502     }
00503     else
00504     {
00505       reset = false;
00506     }
00507 
00508     prev_substate = substate;
00509 
00510     bool substate_completed = false;
00511     switch (substate)
00512     {
00513       case OP_READY:
00514         break;
00515       case OP_ACTIVATING_MODE:
00516         substate_completed = execute_OPERATIONAL_ACTIVATING_MODE(reset, new_mode);
00517         break;
00518       case OP_STANDBYING_MODE:
00519         substate_completed = execute_OPERATIONAL_STANDBYING_MODE(reset, new_mode);
00520         break;
00521     }
00522     if (substate_completed)
00523     {
00524       substate = OP_READY;
00525     }
00526 
00527   }
00528 
00529   void execute_OPERATIONAL_READY(OPERATIONAL_Substate& substate, string& new_mode)
00530   {
00531     // In this substate we are ready to accept a new command. If one is pending,
00532     // it is parsed to determine its validity. If valid, then the appropriate substate
00533     // is returned
00534 
00535     if (command_pending)
00536     {
00537       bool valid = false;
00538       string reason = "";
00539       vector<string> words;
00540       boost::split(words, pending_command, boost::is_any_of(" "));
00541       if (words.size() > 0)
00542       {
00543         if (words[0] == "control_mode")
00544         // Do something with control modes. E.g.:
00545         // control_mode to_active attitude
00546         // control_mode to_standby hover
00547         {
00548           if (words.size() == 3)
00549           {
00550             if (words[1] == "to_active")
00551             {
00552               new_mode = words[2];
00553               if (new_mode == current_mode)
00554               {
00555                 reason = ": current_mode already " + new_mode;
00556               }
00557               else
00558               {
00559                 vector<string>::iterator it;
00560                 vector<string> standby_modes;
00561                 getStandbyModes(standby_modes);
00562                 if (find(standby_modes.begin(), standby_modes.end(), new_mode) != standby_modes.end())//(new_mode == standby_mode)
00563                 {
00564                   valid = true;
00565                   info = "mode change accepted";
00566                   substate = OP_ACTIVATING_MODE;
00567                 }
00568                 else
00569                 {
00570                   ROS_ERROR_STREAM("Mode " << new_mode << " is not in STANDBY, cannot activate");
00571                 }
00572               }
00573             }
00574             else if (words[1] == "to_standby")
00575             {
00576               new_mode = words[2];
00577               valid = true;
00578               substate = OP_STANDBYING_MODE;
00579             }
00580             else if (words[1] == "to_idle")
00581             {
00582               ROS_ERROR("control_mode to_idle commands not yet implemented");
00583             }
00584           }
00585         }
00586       }
00587 
00588       if (!valid)
00589       {
00590         ROS_ERROR_STREAM("Invalid command" << reason);
00591         info = "mode change rejected";
00592       }
00593 
00594       // In any event the command has been processed..
00595       command_pending = false;
00596       pending_command = "";
00597     }
00598 
00599   }
00600 
00601   bool execute_OPERATIONAL_ACTIVATING_MODE(bool reset, const string mode_to_activate)
00602   {
00603     enum SequenceStatus
00604     {
00605       MODE_CHANGE_ACCEPTED, WAITING_NEW_ACTIVE_TALKBACK, WAITING_OLD_STANDBY_TALKBACK, FINISHED
00606     };
00607     static SequenceStatus sequence_status = FINISHED;
00608     static string new_mode;
00609     ROS_DEBUG_STREAM(
00610                      "execute_OPERATIONAL_ACTIVATING_MODE, reset=" << reset << ", new_mode=" << new_mode
00611                          << ", sequence_status=" << sequence_status);
00612     if (reset)
00613     {
00614       sequence_status = MODE_CHANGE_ACCEPTED;
00615       new_mode = mode_to_activate;
00616     }
00617 
00618     switch (sequence_status)
00619     {
00620       case MODE_CHANGE_ACCEPTED:
00621       {
00622         if (latest_mode_status[new_mode].ready)
00623         {
00624           // Mux select new_mode/output
00625           topic_tools::MuxSelect mux_sel_srv;
00626           mux_sel_srv.request.topic = mode_node_map[new_mode] + "/output";
00627           ros::service::call("controller_mux/select", mux_sel_srv);
00628           // Transition new_mode to ACTIVE:
00629           control_mode_cmdPtr new_to_active_msg(new control_mode_cmd);
00630           new_to_active_msg->cmd = "mode active";
00631           mode_cmd_pubs[new_mode].publish(new_to_active_msg);
00632           info = "mux selected and commanded current mode to ACTIVE - waiting to see ACTIVE";
00633           sequence_status = WAITING_NEW_ACTIVE_TALKBACK;
00634         }
00635         else
00636         {
00637           ROS_ERROR_STREAM("mode " << new_mode << " reporting not ready to go ACTIVE, mode transition cancelled");
00638           info = "mode change failed -- see log";
00639           sequence_status = FINISHED;
00640         }
00641       }
00642         break;
00643       case WAITING_NEW_ACTIVE_TALKBACK:
00644       {
00645         if (latest_mode_status[new_mode].state == control_mode_status::STATE_ACTIVE)
00646         {
00647           // Transition old mode to STANDBY:
00648           control_mode_cmdPtr old_to_standby_msg(new control_mode_cmd);
00649           old_to_standby_msg->cmd = "mode standby";
00650           mode_cmd_pubs[current_mode].publish(old_to_standby_msg);
00651           info = "commanded current mode to STANDBY - waiting to see STANDBY";
00652           sequence_status = WAITING_OLD_STANDBY_TALKBACK;
00653         }
00654       }
00655         break;
00656       case WAITING_OLD_STANDBY_TALKBACK:
00657       {
00658         if (latest_mode_status[current_mode].state == control_mode_status::STATE_STANDBY)
00659         {
00660           info = "old mode in STANDBY -- mode transition complete!";
00661           standby_mode = current_mode;
00662           current_mode = new_mode;
00663           sequence_status = FINISHED;
00664         }
00665       }
00666         break;
00667       case FINISHED:
00668       {
00669         ROS_ERROR("The code shouldn't get here--please debug!");
00670       }
00671         break;
00672     }
00673 
00674     return (sequence_status == FINISHED);
00675   }
00676 
00677   bool execute_OPERATIONAL_STANDBYING_MODE(bool reset, const string mode_to_standby)
00678   {
00679     enum SequenceStatus
00680     {
00681       MODE_CHANGE_ACCEPTED, WAITING_STANDBY_TALKBACK, ADDING_MUXER_INPUT, WAITING_MUXER_TALKBACK, FINISHED
00682     };
00683     static SequenceStatus sequence_status = FINISHED;
00684     static string new_mode;
00685     static int muxer_talkback_wait_cycles = 10;
00686 
00687     ROS_DEBUG_STREAM(
00688                      "execute_OPERATIONAL_STANDBYING_MODE, reset=" << reset << ", new_mode=" << new_mode
00689                          << ", sequence_status=" << sequence_status);
00690     if (reset)
00691     {
00692       sequence_status = MODE_CHANGE_ACCEPTED;
00693       new_mode = mode_to_standby;
00694       muxer_talkback_wait_cycles = 10;
00695     }
00696 
00697     switch (sequence_status)
00698     {
00699       case MODE_CHANGE_ACCEPTED:
00700       {
00701         // Transition new_mode to STANDBY:
00702         control_mode_cmdPtr new_to_standby_msg(new control_mode_cmd);
00703         new_to_standby_msg->cmd = "mode standby";
00704         mode_cmd_pubs[new_mode].publish(new_to_standby_msg);
00705         info = "mode " + new_mode + " commanded to STANDBY - waiting to see STANDBY";
00706         sequence_status = WAITING_STANDBY_TALKBACK;
00707       }
00708         break;
00709       case WAITING_STANDBY_TALKBACK:
00710       {
00711         if (latest_mode_status[new_mode].state == control_mode_status::STATE_STANDBY)
00712         {
00713           info = "mode in STANDBY - adding to muxer";
00714           sequence_status = ADDING_MUXER_INPUT;
00715         }
00716       }
00717         break;
00718       case ADDING_MUXER_INPUT:
00719       {
00720         topic_tools::MuxAdd mux_add_srv;
00721         mux_add_srv.request.topic = "control_mode_" + new_mode + "/output";
00722         ros::service::call("controller_mux/add", mux_add_srv);
00723         info = "waiting for muxer talkback...";
00724         sequence_status = WAITING_MUXER_TALKBACK;
00725       }
00726         break;
00727       case WAITING_MUXER_TALKBACK:
00728       {
00729         topic_tools::MuxList mux_list_srv;
00730         ros::service::call("controller_mux/list", mux_list_srv);
00731         vector<string>::iterator it;
00732         string full_topic_name = ros::names::resolve("control_mode_" + new_mode + "/output");
00733         if (find(mux_list_srv.response.topics.begin(), mux_list_srv.response.topics.end(), full_topic_name)
00734             != mux_list_srv.response.topics.end())
00735         {
00736           sequence_status = FINISHED;
00737           info = "muxer has " + full_topic_name + " in its input list - mode is in STANDBY";
00738         }
00739         else
00740         {
00741           muxer_talkback_wait_cycles--;
00742         }
00743         if (muxer_talkback_wait_cycles <= 0)
00744         {
00745           ROS_ERROR_STREAM(
00746                            "Muxer still doesn't have topic " << full_topic_name << " after " << (10
00747                                - muxer_talkback_wait_cycles) << "tries...");
00748         }
00749       }
00750         break;
00751       case FINISHED:
00752       {
00753         ROS_ERROR("The code shouldn't get here--please debug!");
00754       }
00755         break;
00756     }
00757 
00758     return (sequence_status == FINISHED);
00759   }
00760 
00761 }; // class
00762 PLUGINLIB_DECLARE_CLASS(flyer_controller, Controller, flyer_controller::Controller, nodelet::Nodelet)
00763 ;
00764 
00765 } // namespace
00766 
00767 //int main(int argc, char** argv)
00768 //{
00769 //  ros::init(argc, argv, "controller");
00770 //  flyer_controller::Controller controller;
00771 //  ros::spin();
00772 //
00773 //  return 0;
00774 //}
00775 


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