35 #include <boost/array.hpp>    67       , J_M(
std::numeric_limits<
real_T>::infinity())
    68       , R_A(
std::numeric_limits<
real_T>::infinity())
    77   boost::array<real_T,4>  
x;
    79   boost::array<real_T,10> 
u;
    80   boost::array<real_T,14> 
y;
    92   delete propulsion_model_;
   136   for (i = 0; i < 4; i++) {
   143   memset(&y[0], 0, 14U * 
sizeof(
real_T));
   144   for (i = 0; i < 4; i++) {
   151   for (i = 0; i < 3; i++) {
   162   v_1[0] = -uin[2] + parameter.
l_m * uin[4];
   163   v_1[1] = -uin[2] - parameter.
l_m * uin[3];
   164   v_1[2] = -uin[2] - parameter.
l_m * uin[4];
   165   v_1[3] = -uin[2] + parameter.
l_m * uin[3];
   168   for (i = 0; i < 4; i++) {
   183     temp = (U[i] * parameter.
beta_m - parameter.
Psi * xin[i]) / (2.0 *
   187     d0 = parameter.
Psi * temp;
   206     xpred[i] = xin[i] + dt * (1.0 / parameter.
J_M * (d0 - (parameter.
k_t * b_F_m
   207       + parameter.
k_m * xin[i])));
   218   y[3] = (F_m[3] - F_m[1]) * parameter.
l_m;
   221   y[4] = (F_m[0] - F_m[2]) * parameter.
l_m;
   224   y[5] = ((-M_e[0] - M_e[2]) + M_e[1]) + M_e[3];
   227   for (i = 0; i < 4; i++) {
   232   for (i = 0; i < 4; i++) {
   241 inline void QuadrotorPropulsion::f(
const double xin[4], 
const double uin[10], 
double dt, 
double y[14], 
double xpred[4])
 const   249   if (!param.
getParam(
"k_m",     propulsion_model_->parameters_.k_m)) 
return false;
   250   if (!param.
getParam(
"k_t",     propulsion_model_->parameters_.k_t)) 
return false;
   251   if (!param.
getParam(
"CT0s",    propulsion_model_->parameters_.CT0s)) 
return false;
   252   if (!param.
getParam(
"CT1s",    propulsion_model_->parameters_.CT1s)) 
return false;
   253   if (!param.
getParam(
"CT2s",    propulsion_model_->parameters_.CT2s)) 
return false;
   254   if (!param.
getParam(
"J_M",     propulsion_model_->parameters_.J_M)) 
return false;
   255   if (!param.
getParam(
"l_m",     propulsion_model_->parameters_.l_m)) 
return false;
   256   if (!param.
getParam(
"Psi",     propulsion_model_->parameters_.Psi)) 
return false;
   257   if (!param.
getParam(
"R_A",     propulsion_model_->parameters_.R_A)) 
return false;
   258   if (!param.
getParam(
"alpha_m", propulsion_model_->parameters_.alpha_m)) 
return false;
   259   if (!param.
getParam(
"beta_m",  propulsion_model_->parameters_.beta_m)) 
return false;
   262   std::cout << 
"Loaded the following quadrotor propulsion model parameters from namespace " << param.
getNamespace() << 
":" << std::endl;
   263   std::cout << 
"k_m     = " << propulsion_model_->parameters_.k_m << std::endl;
   264   std::cout << 
"k_t     = " << propulsion_model_->parameters_.k_t << std::endl;
   265   std::cout << 
"CT2s    = " << propulsion_model_->parameters_.CT2s << std::endl;
   266   std::cout << 
"CT1s    = " << propulsion_model_->parameters_.CT1s << std::endl;
   267   std::cout << 
"CT0s    = " << propulsion_model_->parameters_.CT0s << std::endl;
   268   std::cout << 
"Psi     = " << propulsion_model_->parameters_.Psi << std::endl;
   269   std::cout << 
"J_M     = " << propulsion_model_->parameters_.J_M << std::endl;
   270   std::cout << 
"R_A     = " << propulsion_model_->parameters_.R_A << std::endl;
   271   std::cout << 
"l_m     = " << propulsion_model_->parameters_.l_m << std::endl;
   272   std::cout << 
"alpha_m = " << propulsion_model_->parameters_.alpha_m << std::endl;
   273   std::cout << 
"beta_m  = " << propulsion_model_->parameters_.beta_m << std::endl;
   276   initial_voltage_ = 14.8;
   277   param.
getParam(
"supply_voltage", initial_voltage_);
   285   boost::mutex::scoped_lock lock(mutex_);
   287   propulsion_model_->x.assign(0.0);
   288   propulsion_model_->x_pred.assign(0.0);
   289   propulsion_model_->u.assign(0.0);
   290   propulsion_model_->y.assign(0.0);
   292   wrench_ = geometry_msgs::Wrench();
   294   motor_status_ = hector_uav_msgs::MotorStatus();
   295   motor_status_.voltage.resize(4);
   296   motor_status_.frequency.resize(4);
   297   motor_status_.current.resize(4);
   299   supply_ = hector_uav_msgs::Supply();
   300   supply_.voltage.resize(1);
   301   supply_.voltage[0] = initial_voltage_;
   305   command_queue_ = std::queue<hector_uav_msgs::MotorPWMConstPtr>(); 
   310   boost::mutex::scoped_lock lock(mutex_);
   311   last_command_time_ = voltage.header.stamp;
   313   if (motor_status_.on && voltage.pwm.size() >= 4) {
   314     propulsion_model_->u[6] = voltage.pwm[0] * supply_.voltage[0] / 255.0;
   315     propulsion_model_->u[7] = voltage.pwm[1] * supply_.voltage[0] / 255.0;
   316     propulsion_model_->u[8] = voltage.pwm[2] * supply_.voltage[0] / 255.0;
   317     propulsion_model_->u[9] = voltage.pwm[3] * supply_.voltage[0] / 255.0;
   319     propulsion_model_->u[6] = 0.0;
   320     propulsion_model_->u[7] = 0.0;
   321     propulsion_model_->u[8] = 0.0;
   322     propulsion_model_->u[9] = 0.0;
   328   boost::mutex::scoped_lock lock(mutex_);
   329   propulsion_model_->u[0] = twist.linear.x;
   330   propulsion_model_->u[1] = -twist.linear.y;
   331   propulsion_model_->u[2] = -twist.linear.z;
   332   propulsion_model_->u[3] = twist.angular.x;
   333   propulsion_model_->u[4] = -twist.angular.y;
   334   propulsion_model_->u[5] = -twist.angular.z;
   338   limit(boost::iterator_range<boost::array<real_T,10>::iterator>(&(propulsion_model_->u[0]), &(propulsion_model_->u[6])), -100.0, 100.0);
   343   hector_uav_msgs::MotorPWMPtr pwm(
new hector_uav_msgs::MotorPWM);
   344   pwm->header = command->header;
   345   pwm->pwm.resize(command->voltage.size());
   346   for(std::size_t i = 0; i < command->voltage.size(); ++i) {
   347     int temp = round(command->voltage[i] / supply_.voltage[0] * 255.0);
   360   boost::mutex::scoped_lock lock(command_queue_mutex_);
   362   if (!motor_status_.on) {
   363     ROS_WARN_NAMED(
"quadrotor_propulsion", 
"Received new motor command. Enabled motors.");
   368   command_queue_.push(pwm);
   369   command_condition_.notify_all();
   373   boost::mutex::scoped_lock lock(command_queue_mutex_);
   374   bool new_command = 
false;
   376   ros::Time min(timestamp), max(timestamp);
   378     min = timestamp - delay - tolerance ;
   379   } 
catch (std::runtime_error &e) {}
   382     max = timestamp - delay + tolerance;
   383   } 
catch (std::runtime_error &e) {}
   387     while(!command_queue_.empty()) {
   388       hector_uav_msgs::MotorPWMConstPtr new_motor_voltage = command_queue_.front();
   389       ros::Time new_time = new_motor_voltage->header.stamp;
   391       if (new_time.
isZero() || (new_time >= min && new_time <= max)) {
   392         setVoltage(*new_motor_voltage);
   393         command_queue_.pop();
   397       } 
else if (new_time < min) {
   398         ROS_DEBUG_NAMED(
"quadrotor_propulsion", 
"Command received was %fs too old. Discarding.", (new_time - timestamp).toSec());
   399         command_queue_.pop();
   407     if (command_queue_.empty() && !new_command) {
   408       if (!motor_status_.on || wait.
isZero()) 
break;
   410       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());
   411       if (!callback_queue) {
   412         if (command_condition_.timed_wait(lock, wait.
toBoost())) 
continue;
   417         if (!command_queue_.empty()) 
continue;
   420       ROS_ERROR_NAMED(
"quadrotor_propulsion", 
"Command timed out. Disabled motors.");
   427       ROS_DEBUG_STREAM_NAMED(
"quadrotor_propulsion", 
"Using motor command valid at t = " << last_command_time_.toSec() << 
"s for simulation step at t = " << timestamp.
toSec() << 
"s (dt = " << (timestamp - last_command_time_).toSec() << 
"s)");
   435   if (dt <= 0.0) 
return;
   441   checknan(propulsion_model_->u, 
"propulsion model input");
   442   checknan(propulsion_model_->x, 
"propulsion model state");
   445   f(propulsion_model_->x.data(), propulsion_model_->u.data(), dt, propulsion_model_->y.data(), propulsion_model_->x_pred.data());
   446   propulsion_model_->x = propulsion_model_->x_pred;
   450                                                  "propulsion.torque:  " << 
PrintVector<double>(propulsion_model_->y.begin() + 3, propulsion_model_->y.begin() + 6));
   452   checknan(propulsion_model_->y, 
"propulsion model output");
   454   wrench_.force.x  =  propulsion_model_->y[0];
   455   wrench_.force.y  = -propulsion_model_->y[1];
   456   wrench_.force.z  =  propulsion_model_->y[2];
   457   wrench_.torque.x =  propulsion_model_->y[3];
   458   wrench_.torque.y = -propulsion_model_->y[4];
   459   wrench_.torque.z = -propulsion_model_->y[5];
   461   motor_status_.voltage[0] = propulsion_model_->u[6];
   462   motor_status_.voltage[1] = propulsion_model_->u[7];
   463   motor_status_.voltage[2] = propulsion_model_->u[8];
   464   motor_status_.voltage[3] = propulsion_model_->u[9];
   466   motor_status_.frequency[0] = propulsion_model_->y[6];
   467   motor_status_.frequency[1] = propulsion_model_->y[7];
   468   motor_status_.frequency[2] = propulsion_model_->y[8];
   469   motor_status_.frequency[3] = propulsion_model_->y[9];
   470   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;
   472   motor_status_.current[0] = propulsion_model_->y[10];
   473   motor_status_.current[1] = propulsion_model_->y[11];
   474   motor_status_.current[2] = propulsion_model_->y[12];
   475   motor_status_.current[3] = propulsion_model_->y[13];
   480   motor_status_.on = 
true;
   485   motor_status_.on = 
false;
 bool configure(const ros::NodeHandle ¶m=ros::NodeHandle("~"))
boost::array< real_T, 4 > x
#define ROS_DEBUG_STREAM_NAMED(name, args)
#define ROS_WARN_NAMED(name,...)
bool processQueue(const ros::Time ×tamp, const ros::Duration &tolerance=ros::Duration(), const ros::Duration &delay=ros::Duration(), const ros::WallDuration &wait=ros::WallDuration(), ros::CallbackQueue *callback_queue=0)
PropulsionParameters parameters_
boost::array< real_T, 4 > x_pred
static real_T rt_powd_snf(real_T u0, real_T u1)
#define ROS_DEBUG_NAMED(name,...)
boost::array< real_T, 10 > u
void quadrotorPropulsion(const real_T xin[4], const real_T uin[10], const PropulsionParameters parameter, real_T dt, real_T y[14], real_T xpred[4])
void addPWMToQueue(const hector_uav_msgs::MotorPWMConstPtr &pwm)
const std::string & getNamespace() const 
boost::posix_time::time_duration toBoost() const
void limit(T &value, const T &min, const T &max)
static void checknan(T &value, const std::string &text="")
ROSCONSOLE_DECL void shutdown()
void f(const double xin[4], const double uin[10], double dt, double y[14], double xpred[4]) const 
bool getParam(const std::string &key, std::string &s) const 
void setVoltage(const hector_uav_msgs::MotorPWM &command)
#define ROS_ERROR_NAMED(name,...)
boost::array< real_T, 14 > y
void setTwist(const geometry_msgs::Twist &twist)
void addCommandToQueue(const hector_uav_msgs::MotorCommandConstPtr &command)