command.cpp
Go to the documentation of this file.
00001 
00009 /*
00010  * Copyright 2014 Vladimir Ermakov.
00011  *
00012  * This program is free software; you can redistribute it and/or modify
00013  * it under the terms of the GNU General Public License as published by
00014  * the Free Software Foundation; either version 3 of the License, or
00015  * (at your option) any later version.
00016  *
00017  * This program is distributed in the hope that it will be useful, but
00018  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
00019  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
00020  * for more details.
00021  *
00022  * You should have received a copy of the GNU General Public License along
00023  * with this program; if not, write to the Free Software Foundation, Inc.,
00024  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00025  */
00026 
00027 #include <chrono>
00028 #include <condition_variable>
00029 #include <mavros/mavros_plugin.h>
00030 #include <pluginlib/class_list_macros.h>
00031 
00032 #include <mavros/CommandLong.h>
00033 #include <mavros/CommandInt.h>
00034 #include <mavros/CommandBool.h>
00035 #include <mavros/CommandHome.h>
00036 #include <mavros/CommandTOL.h>
00037 
00038 namespace mavplugin {
00039 
00040 class CommandTransaction {
00041 public:
00042         std::mutex cond_mutex;
00043         std::condition_variable ack;
00044         uint16_t expected_command;
00045         uint8_t result;
00046 
00047         explicit CommandTransaction(uint16_t command) :
00048                 ack(),
00049                 expected_command(command),
00050                 result(MAV_RESULT_FAILED)
00051         { }
00052 };
00053 
00059 class CommandPlugin : public MavRosPlugin {
00060 public:
00061         CommandPlugin() :
00062                 uas(nullptr),
00063                 ACK_TIMEOUT_DT(ACK_TIMEOUT_MS / 1000.0)
00064         { };
00065 
00066         void initialize(UAS &uas_,
00067                         ros::NodeHandle &nh,
00068                         diagnostic_updater::Updater &diag_updater)
00069         {
00070                 uas = &uas_;
00071 
00072                 cmd_nh = ros::NodeHandle(nh, "cmd");
00073                 command_long_srv = cmd_nh.advertiseService("command", &CommandPlugin::command_long_cb, this);
00074                 command_int_srv = cmd_nh.advertiseService("command_int", &CommandPlugin::command_int_cb, this);
00075                 arming_srv = cmd_nh.advertiseService("arming", &CommandPlugin::arming_cb, this);
00076                 set_home_srv = cmd_nh.advertiseService("set_home", &CommandPlugin::set_home_cb, this);
00077                 takeoff_srv = cmd_nh.advertiseService("takeoff", &CommandPlugin::takeoff_cb, this);
00078                 land_srv = cmd_nh.advertiseService("land", &CommandPlugin::land_cb, this);
00079                 guided_srv = cmd_nh.advertiseService("guided_enable", &CommandPlugin::guided_cb, this);
00080         }
00081 
00082         std::string const get_name() const {
00083                 return "Command";
00084         }
00085 
00086         const message_map get_rx_handlers() {
00087                 return {
00088                         MESSAGE_HANDLER(MAVLINK_MSG_ID_COMMAND_ACK, &CommandPlugin::handle_command_ack)
00089                 };
00090         }
00091 
00092 private:
00093         std::recursive_mutex mutex;
00094         UAS *uas;
00095 
00096         ros::NodeHandle cmd_nh;
00097         ros::ServiceServer command_long_srv;
00098         ros::ServiceServer command_int_srv;
00099         ros::ServiceServer arming_srv;
00100         ros::ServiceServer set_home_srv;
00101         ros::ServiceServer takeoff_srv;
00102         ros::ServiceServer land_srv;
00103         ros::ServiceServer guided_srv;
00104 
00105         std::list<CommandTransaction *> ack_waiting_list;
00106         static constexpr int ACK_TIMEOUT_MS = 5000;
00107 
00108         const ros::Duration ACK_TIMEOUT_DT;
00109 
00110         /* -*- message handlers -*- */
00111 
00112         void handle_command_ack(const mavlink_message_t *msg, uint8_t sysid, uint8_t compid) {
00113                 mavlink_command_ack_t ack;
00114                 mavlink_msg_command_ack_decode(msg, &ack);
00115 
00116                 lock_guard lock(mutex);
00117                 for (auto it = ack_waiting_list.cbegin();
00118                                 it != ack_waiting_list.cend(); it++)
00119                         if ((*it)->expected_command == ack.command) {
00120                                 (*it)->result = ack.result;
00121                                 (*it)->ack.notify_all();
00122                                 return;
00123                         }
00124 
00125                 ROS_WARN_THROTTLE_NAMED(10, "cmd", "Unexpected command %u, result %u",
00126                         ack.command, ack.result);
00127         }
00128 
00129         /* -*- mid-level functions -*- */
00130 
00131         bool wait_ack_for(CommandTransaction *tr) {
00132                 std::unique_lock<std::mutex> lock(tr->cond_mutex);
00133 
00134                 return tr->ack.wait_for(lock, std::chrono::nanoseconds(ACK_TIMEOUT_DT.toNSec()))
00135                         == std::cv_status::no_timeout;
00136         }
00137 
00143         bool send_command_long_and_wait(uint16_t command, uint8_t confirmation,
00144                         float param1, float param2,
00145                         float param3, float param4,
00146                         float param5, float param6,
00147                         float param7,
00148                         unsigned char &success, uint8_t &result) {
00149                 unique_lock lock(mutex);
00150 
00151                 /* check transactions */
00152                 for (auto it = ack_waiting_list.cbegin();
00153                                 it != ack_waiting_list.cend(); it++)
00154                         if ((*it)->expected_command == command) {
00155                                 ROS_WARN_THROTTLE_NAMED(10, "cmd", "Command %u alredy in progress", command);
00156                                 return false;
00157                         }
00158 
00160                 bool is_ack_required = (confirmation != 0 || uas->is_ardupilotmega()) && !uas->is_px4();
00161                 if (is_ack_required)
00162                         ack_waiting_list.push_back(new CommandTransaction(command));
00163 
00164                 command_long(command, confirmation,
00165                                 param1, param2,
00166                                 param3, param4,
00167                                 param5, param6,
00168                                 param7);
00169 
00170                 if (is_ack_required) {
00171                         auto it = ack_waiting_list.begin();
00172                         for (; it != ack_waiting_list.end(); it++)
00173                                 if ((*it)->expected_command == command)
00174                                         break;
00175 
00176                         if (it == ack_waiting_list.end()) {
00177                                 ROS_ERROR_NAMED("cmd", "CommandTransaction not found for %u", command);
00178                                 return false;
00179                         }
00180 
00181                         lock.unlock();
00182                         bool is_not_timeout = wait_ack_for(*it);
00183                         lock.lock();
00184 
00185                         success = is_not_timeout && (*it)->result == MAV_RESULT_ACCEPTED;
00186                         result = (*it)->result;
00187 
00188                         delete *it;
00189                         ack_waiting_list.erase(it);
00190                 }
00191                 else {
00192                         success = true;
00193                         result = MAV_RESULT_ACCEPTED;
00194                 }
00195 
00196                 return true;
00197         }
00198 
00202         bool send_command_int(uint8_t frame, uint16_t command,
00203                         uint8_t current, uint8_t autocontinue,
00204                         float param1, float param2,
00205                         float param3, float param4,
00206                         int32_t x, int32_t y,
00207                         float z,
00208                         unsigned char &success) {
00209 
00210                 /* Note: seems that COMMAND_INT don't produce COMMAND_ACK
00211                  * so wait don't needed.
00212                  */
00213                 command_int(frame, command, current, autocontinue,
00214                                 param1, param2,
00215                                 param3, param4,
00216                                 x, y, z);
00217 
00218                 success = true;
00219                 return true;
00220         }
00221 
00222         /* -*- low-level send -*- */
00223 
00224         void command_long(uint16_t command, uint8_t confirmation,
00225                         float param1, float param2,
00226                         float param3, float param4,
00227                         float param5, float param6,
00228                         float param7) {
00229                 mavlink_message_t msg;
00230 
00231                 mavlink_msg_command_long_pack_chan(UAS_PACK_CHAN(uas), &msg,
00232                                 UAS_PACK_TGT(uas),
00233                                 command,
00234                                 confirmation,
00235                                 param1, param2,
00236                                 param3, param4,
00237                                 param5, param6,
00238                                 param7);
00239                 UAS_FCU(uas)->send_message(&msg);
00240         }
00241 
00242         void command_int(uint8_t frame, uint16_t command,
00243                         uint8_t current, uint8_t autocontinue,
00244                         float param1, float param2,
00245                         float param3, float param4,
00246                         int32_t x, int32_t y,
00247                         float z) {
00248                 mavlink_message_t msg;
00249 
00250                 mavlink_msg_command_int_pack_chan(UAS_PACK_CHAN(uas), &msg,
00251                                 UAS_PACK_TGT(uas),
00252                                 frame,
00253                                 command,
00254                                 current,
00255                                 autocontinue,
00256                                 param1, param2,
00257                                 param3, param4,
00258                                 x, y, z);
00259                 UAS_FCU(uas)->send_message(&msg);
00260         }
00261 
00262         /* -*- callbacks -*- */
00263 
00264         bool command_long_cb(mavros::CommandLong::Request &req,
00265                         mavros::CommandLong::Response &res) {
00266 
00267                 return send_command_long_and_wait(req.command, req.confirmation,
00268                                 req.param1, req.param2,
00269                                 req.param3, req.param4,
00270                                 req.param5, req.param6,
00271                                 req.param7,
00272                                 res.success, res.result);
00273         }
00274 
00275         bool command_int_cb(mavros::CommandInt::Request &req,
00276                         mavros::CommandInt::Response &res) {
00277                 return send_command_int(req.frame, req.command,
00278                                 req.current, req.autocontinue,
00279                                 req.param1, req.param2,
00280                                 req.param3, req.param4,
00281                                 req.x, req.y, req.z,
00282                                 res.success);
00283         }
00284 
00285         bool arming_cb(mavros::CommandBool::Request &req,
00286                         mavros::CommandBool::Response &res) {
00287 
00288                 return send_command_long_and_wait(MAV_CMD_COMPONENT_ARM_DISARM, 1,
00289                                 (req.value)? 1.0 : 0.0,
00290                                 0, 0, 0, 0, 0, 0,
00291                                 res.success, res.result);
00292         }
00293 
00294         bool set_home_cb(mavros::CommandHome::Request &req,
00295                         mavros::CommandHome::Response &res) {
00296 
00297                 return send_command_long_and_wait(MAV_CMD_DO_SET_HOME, 1,
00298                                 (req.current_gps)? 1.0 : 0.0,
00299                                 0, 0, 0, req.latitude, req.longitude, req.altitude,
00300                                 res.success, res.result);
00301         }
00302 
00303         bool takeoff_cb(mavros::CommandTOL::Request &req,
00304                         mavros::CommandTOL::Response &res) {
00305 
00306                 return send_command_long_and_wait(MAV_CMD_NAV_TAKEOFF, 1,
00307                                 req.min_pitch,
00308                                 0, 0,
00309                                 req.yaw,
00310                                 req.latitude, req.longitude, req.altitude,
00311                                 res.success, res.result);
00312         }
00313 
00314         bool land_cb(mavros::CommandTOL::Request &req,
00315                         mavros::CommandTOL::Response &res) {
00316 
00317                 return send_command_long_and_wait(MAV_CMD_NAV_LAND, 1,
00318                                 0, 0, 0,
00319                                 req.yaw,
00320                                 req.latitude, req.longitude, req.altitude,
00321                                 res.success, res.result);
00322         }
00323 
00324         bool guided_cb(mavros::CommandBool::Request &req,
00325                         mavros::CommandBool::Response &res) {
00326 
00327                 return send_command_long_and_wait(MAV_CMD_NAV_GUIDED_ENABLE, 1,
00328                                 (req.value)? 1.0 : 0.0,
00329                                 0, 0, 0, 0, 0, 0,
00330                                 res.success, res.result);
00331         }
00332 };
00333 
00334 }; // namespace mavplugin
00335 
00336 PLUGINLIB_EXPORT_CLASS(mavplugin::CommandPlugin, mavplugin::MavRosPlugin)
00337 


mavros
Author(s): Vladimir Ermakov
autogenerated on Wed Aug 26 2015 12:29:13