quadrotor_propulsion.cpp
Go to the documentation of this file.
00001 //=================================================================================================
00002 // Copyright (c) 2013, Johannes Meyer, TU Darmstadt
00003 // All rights reserved.
00004 
00005 // Redistribution and use in source and binary forms, with or without
00006 // modification, are permitted provided that the following conditions are met:
00007 //     * Redistributions of source code must retain the above copyright
00008 //       notice, this list of conditions and the following disclaimer.
00009 //     * Redistributions in binary form must reproduce the above copyright
00010 //       notice, this list of conditions and the following disclaimer in the
00011 //       documentation and/or other materials provided with the distribution.
00012 //     * Neither the name of the Flight Systems and Automatic Control group,
00013 //       TU Darmstadt, nor the names of its contributors may be used to
00014 //       endorse or promote products derived from this software without
00015 //       specific prior written permission.
00016 
00017 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00018 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00019 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00020 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
00021 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00022 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00023 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00024 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00026 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027 //=================================================================================================
00028 
00029 #include <hector_quadrotor_model/quadrotor_propulsion.h>
00030 #include <hector_quadrotor_model/helpers.h>
00031 
00032 #include <ros/node_handle.h>
00033 #include <ros/callback_queue.h>
00034 
00035 #include <boost/array.hpp>
00036 
00037 extern "C" {
00038   #include "quadrotorPropulsion/quadrotorPropulsion.h"
00039   #include "quadrotorPropulsion/quadrotorPropulsion_initialize.h"
00040 }
00041 
00042 namespace hector_quadrotor_model {
00043 
00044 // extern void quadrotorPropulsion(const real_T xin[4], const real_T uin[10], const PropulsionParameters parameter, real_T dt, real_T y[6], real_T xpred[4]);
00045 struct QuadrotorPropulsion::PropulsionModel {
00046   PropulsionParameters parameters_;
00047   boost::array<real_T,4>  x;
00048   boost::array<real_T,4>  x_pred;
00049   boost::array<real_T,10> u;
00050   boost::array<real_T,14> y;
00051 };
00052 
00053 QuadrotorPropulsion::QuadrotorPropulsion()
00054 {
00055   // initialize propulsion model
00056   quadrotorPropulsion_initialize();
00057   propulsion_model_ = new PropulsionModel;
00058 }
00059 
00060 QuadrotorPropulsion::~QuadrotorPropulsion()
00061 {
00062   delete propulsion_model_;
00063 }
00064 
00065 inline void QuadrotorPropulsion::f(const real_T xin[4], const real_T uin[10], real_T dt, real_T y[14], real_T xpred[4]) const
00066 {
00067   ::quadrotorPropulsion(xin, uin, propulsion_model_->parameters_, dt, y, xpred);
00068 }
00069 
00070 void QuadrotorPropulsion::configure(const std::string &ns)
00071 {
00072   ros::NodeHandle param(ns);
00073 
00074   // get model parameters
00075   param.getParam("k_m",     propulsion_model_->parameters_.k_m);
00076   param.getParam("k_t",     propulsion_model_->parameters_.k_t);
00077   param.getParam("CT0s",    propulsion_model_->parameters_.CT0s);
00078   param.getParam("CT1s",    propulsion_model_->parameters_.CT1s);
00079   param.getParam("CT2s",    propulsion_model_->parameters_.CT2s);
00080   param.getParam("J_M",     propulsion_model_->parameters_.J_M);
00081   param.getParam("l_m",     propulsion_model_->parameters_.l_m);
00082   param.getParam("Psi",     propulsion_model_->parameters_.Psi);
00083   param.getParam("R_A",     propulsion_model_->parameters_.R_A);
00084   param.getParam("alpha_m", propulsion_model_->parameters_.alpha_m);
00085   param.getParam("beta_m",  propulsion_model_->parameters_.beta_m);
00086 
00087 #ifndef NDEBUG
00088   std::cout << "Loaded the following quadrotor propulsion model parameters from namespace " << param.getNamespace() << ":" << std::endl;
00089   std::cout << "k_m     = " << propulsion_model_->parameters_.k_m << std::endl;
00090   std::cout << "k_t     = " << propulsion_model_->parameters_.k_t << std::endl;
00091   std::cout << "CT2s    = " << propulsion_model_->parameters_.CT2s << std::endl;
00092   std::cout << "CT1s    = " << propulsion_model_->parameters_.CT1s << std::endl;
00093   std::cout << "CT0s    = " << propulsion_model_->parameters_.CT0s << std::endl;
00094   std::cout << "Psi     = " << propulsion_model_->parameters_.Psi << std::endl;
00095   std::cout << "J_M     = " << propulsion_model_->parameters_.J_M << std::endl;
00096   std::cout << "R_A     = " << propulsion_model_->parameters_.R_A << std::endl;
00097   std::cout << "l_m     = " << propulsion_model_->parameters_.l_m << std::endl;
00098   std::cout << "alpha_m = " << propulsion_model_->parameters_.alpha_m << std::endl;
00099   std::cout << "beta_m  = " << propulsion_model_->parameters_.beta_m << std::endl;
00100 #endif
00101 
00102   initial_voltage_ = 14.8;
00103   param.getParam("supply_voltage", initial_voltage_);
00104   reset();
00105 }
00106 
00107 void QuadrotorPropulsion::reset()
00108 {
00109   boost::mutex::scoped_lock lock(mutex_);
00110 
00111   propulsion_model_->x.assign(0.0);
00112   propulsion_model_->x_pred.assign(0.0);
00113   propulsion_model_->u.assign(0.0);
00114   propulsion_model_->y.assign(0.0);
00115 
00116   wrench_ = geometry_msgs::Wrench();
00117 
00118   motor_status_ = hector_uav_msgs::MotorStatus();
00119   motor_status_.voltage.resize(4);
00120   motor_status_.frequency.resize(4);
00121   motor_status_.current.resize(4);
00122 
00123   supply_ = hector_uav_msgs::Supply();
00124   supply_.voltage.resize(1);
00125   supply_.voltage[0] = initial_voltage_;
00126 
00127   last_command_time_ = ros::Time();
00128 
00129   command_queue_ = std::queue<hector_uav_msgs::MotorPWMConstPtr>(); // .clear();
00130 }
00131 
00132 void QuadrotorPropulsion::setVoltage(const hector_uav_msgs::MotorPWM& voltage)
00133 {
00134   boost::mutex::scoped_lock lock(mutex_);
00135   last_command_time_ = voltage.header.stamp;
00136 
00137   if (motor_status_.on && voltage.pwm.size() >= 4) {
00138     propulsion_model_->u[6] = voltage.pwm[0] * supply_.voltage[0] / 255.0;
00139     propulsion_model_->u[7] = voltage.pwm[1] * supply_.voltage[0] / 255.0;
00140     propulsion_model_->u[8] = voltage.pwm[2] * supply_.voltage[0] / 255.0;
00141     propulsion_model_->u[9] = voltage.pwm[3] * supply_.voltage[0] / 255.0;
00142   } else {
00143     propulsion_model_->u[6] = 0.0;
00144     propulsion_model_->u[7] = 0.0;
00145     propulsion_model_->u[8] = 0.0;
00146     propulsion_model_->u[9] = 0.0;
00147   }
00148 }
00149 
00150 void QuadrotorPropulsion::setTwist(const geometry_msgs::Twist &twist)
00151 {
00152   boost::mutex::scoped_lock lock(mutex_);
00153   propulsion_model_->u[0] = twist.linear.x;
00154   propulsion_model_->u[1] = -twist.linear.y;
00155   propulsion_model_->u[2] = -twist.linear.z;
00156   propulsion_model_->u[3] = twist.angular.x;
00157   propulsion_model_->u[4] = -twist.angular.y;
00158   propulsion_model_->u[5] = -twist.angular.z;
00159 }
00160 
00161 void QuadrotorPropulsion::addVoltageToQueue(const hector_uav_msgs::MotorPWMConstPtr& command)
00162 {
00163   boost::mutex::scoped_lock lock(command_queue_mutex_);
00164 
00165   if (!motor_status_.on) {
00166     ROS_WARN_NAMED("quadrotor_propulsion", "Received new motor command. Enabled motors.");
00167     engage();
00168   }
00169 
00170   ROS_DEBUG_STREAM_NAMED("quadrotor_propulsion", "Received motor command valid at " << command->header.stamp);
00171   command_queue_.push(command);
00172   command_condition_.notify_all();
00173 }
00174 
00175 bool QuadrotorPropulsion::processQueue(const ros::Time &timestamp, const ros::Duration &tolerance, const ros::Duration &delay, const ros::WallDuration &wait, ros::CallbackQueue *callback_queue) {
00176   boost::mutex::scoped_lock lock(command_queue_mutex_);
00177   bool new_command = false;
00178 
00179   ros::Time min(timestamp), max(timestamp);
00180   try {
00181     min = timestamp - delay - tolerance /* - ros::Duration(dt) */;
00182   } catch (std::runtime_error &e) {}
00183 
00184   try {
00185     max = timestamp - delay + tolerance;
00186   } catch (std::runtime_error &e) {}
00187 
00188   do {
00189 
00190     if (!command_queue_.empty()) {
00191       hector_uav_msgs::MotorPWMConstPtr new_motor_voltage = command_queue_.front();
00192       ros::Time new_time = new_motor_voltage->header.stamp;
00193 
00194       if (new_time.isZero() || (new_time >= min && new_time <= max)) {
00195         setVoltage(*new_motor_voltage);
00196         command_queue_.pop();
00197         new_command = true;
00198 
00199         ROS_DEBUG_STREAM_NAMED("quadrotor_propulsion", "Using motor command valid at t = " << new_time.toSec() << "s for simulation step at t = " << timestamp.toSec() << "s (dt = " << (timestamp - new_time).toSec() << "s)");
00200 
00201       // new motor command is too old:
00202       } else if (new_time < min) {
00203         ROS_DEBUG_NAMED("quadrotor_propulsion", "Command received was %fs too old. Discarding.", (new_time - timestamp).toSec());
00204         command_queue_.pop();
00205         continue;
00206 
00207       // new motor command is too new:
00208       } else {
00209         // do nothing
00210       }
00211 
00212     } else {
00213       if (!motor_status_.on || wait.isZero()) break;
00214 
00215       ROS_DEBUG_NAMED("quadrotor_propulsion", "Waiting for command at simulation step t = %fs... last update was %fs ago", timestamp.toSec(), (timestamp - last_command_time_).toSec());
00216       if (!callback_queue) {
00217         if (command_condition_.timed_wait(lock, wait.toBoost())) continue;
00218       } else {
00219         lock.unlock();
00220         callback_queue->callAvailable(wait);
00221         lock.lock();
00222         if (!command_queue_.empty()) continue;
00223       }
00224 
00225       ROS_ERROR_NAMED("quadrotor_propulsion", "Command timed out. Disabled motors.");
00226       shutdown();
00227     }
00228 
00229   } while(false);
00230 
00231   return new_command;
00232 }
00233 
00234 void QuadrotorPropulsion::update(double dt)
00235 {
00236   if (dt <= 0.0) return;
00237 
00238 //  std::cout << "u = [ ";
00239 //  for(std::size_t i = 0; i < propulsion_model_->u.size(); ++i)
00240 //    std::cout << propulsion_model_->u[i] << " ";
00241 //  std::cout << "]" << std::endl;
00242 
00243   checknan(propulsion_model_->u, "propulsion model input");
00244   checknan(propulsion_model_->x, "propulsion model state");
00245 
00246   // update propulsion model
00247   f(propulsion_model_->x.data(), propulsion_model_->u.data(), dt, propulsion_model_->y.data(), propulsion_model_->x_pred.data());
00248   propulsion_model_->x = propulsion_model_->x_pred;
00249 
00250   checknan(propulsion_model_->y, "propulsion model output");
00251 
00252   //  std::cout << "y = [ ";
00253   //  for(std::size_t i = 0; i < propulsion_model_->y.size(); ++i)
00254   //    std::cout << propulsion_model_->y[i] << " ";
00255   //  std::cout << "]" << std::endl;
00256 
00257   wrench_.force.x  =  propulsion_model_->y[0];
00258   wrench_.force.y  = -propulsion_model_->y[1];
00259   wrench_.force.z  =  propulsion_model_->y[2];
00260   wrench_.torque.x =  propulsion_model_->y[3];
00261   wrench_.torque.y = -propulsion_model_->y[4];
00262   wrench_.torque.z = -propulsion_model_->y[5];
00263 
00264   motor_status_.voltage[0] = propulsion_model_->u[6];
00265   motor_status_.voltage[1] = propulsion_model_->u[7];
00266   motor_status_.voltage[2] = propulsion_model_->u[8];
00267   motor_status_.voltage[3] = propulsion_model_->u[9];
00268 
00269   motor_status_.frequency[0] = propulsion_model_->y[6];
00270   motor_status_.frequency[1] = propulsion_model_->y[7];
00271   motor_status_.frequency[2] = propulsion_model_->y[8];
00272   motor_status_.frequency[3] = propulsion_model_->y[9];
00273   motor_status_.running = motor_status_.frequency[0] > 1.0 && motor_status_.frequency[1] > 1.0 && motor_status_.frequency[2] > 1.0 && motor_status_.frequency[3] > 1.0;
00274 
00275   motor_status_.current[0] = propulsion_model_->y[10];
00276   motor_status_.current[1] = propulsion_model_->y[11];
00277   motor_status_.current[2] = propulsion_model_->y[12];
00278   motor_status_.current[3] = propulsion_model_->y[13];
00279 }
00280 
00281 void QuadrotorPropulsion::engage()
00282 {
00283   motor_status_.on = true;
00284 }
00285 
00286 void QuadrotorPropulsion::shutdown()
00287 {
00288   motor_status_.on = false;
00289 }
00290 
00291 } // namespace hector_quadrotor_model


hector_quadrotor_model
Author(s): Johannes Meyer and Alexander Sendobry
autogenerated on Mon Oct 6 2014 00:29:53