00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 #include <algorithm>
00035 #include <cmath>
00036 #include <ros/ros.h>
00037 #include <nodelet/nodelet.h>
00038 #include <pluginlib/class_list_macros.h>
00039 #include <diagnostic_updater/diagnostic_updater.h>
00040 #include <diagnostic_updater/update_functions.h>
00041 #include <dynamic_reconfigure/server.h>
00042 #include <starmac_robots_asctec/AscTecAdapterConfig.h>
00043 #include <string>
00044 #include <angles/angles.h>
00045 
00046 
00047 
00048 #include "asctec_hl_comm/mav_status.h"
00049 #include "asctec_hl_comm/mav_ctrl.h"
00050 #include "std_msgs/Bool.h"
00051 #include "flyer_controller/control_mode_output.h"
00052 #include "starmac_robots_asctec/pid.h"
00053 #include <nav_msgs/Odometry.h>
00054 #include <sensor_msgs/Imu.h>
00055 
00056 #include <tf/tf.h>
00057 #include <tf/transform_datatypes.h>
00058 #include "starmac_robots_asctec/misc.h"
00059 
00060 
00061 
00062 using namespace std;
00063 
00064 
00065 static double ROLL_SCALE = M_PI / 180.0; 
00066 static double PITCH_SCALE = M_PI / 180.0; 
00067 static double MAX_ROLL_CMD = M_PI_2; 
00068 static double MAX_PITCH_CMD = M_PI_2; 
00069 static double MAX_YAW_RATE_CMD = 2.0 * M_PI; 
00070 static double MAX_THRUST_CMD = 32; 
00071 
00072 
00073 
00074 
00075 static double YAW_SCALE = M_PI / 180.0; 
00076 
00077 static double THRUST_SCALE = 1.0 / 32.0; 
00078 
00079 namespace starmac_robots_asctec
00080 {
00081 
00082 class AscTecHLInterfaceAdapterNodelet : public nodelet::Nodelet
00083 {
00084 private:
00085   ros::NodeHandle nh;
00086   ros::NodeHandle nh_priv;
00087   
00088   diagnostic_updater::Updater diag_updater;
00089   double min_freq;
00090   double max_freq;
00091   diagnostic_updater::FrequencyStatus freq_status;
00092   
00093   dynamic_reconfigure::Server<starmac_robots_asctec::AscTecAdapterConfig> dyn_reconfig_srv;
00094   
00095   
00096   
00097   ros::Duration deadman_timeout; 
00098   double alt_KP; 
00099   double alt_KI; 
00100   double alt_KD; 
00101   double alt_KDD; 
00102   double alt_Ilimit; 
00103   double yaw_KP; 
00104   double yaw_KI; 
00105   double yaw_KD; 
00106   double yaw_Ilimit; 
00107   double yaw_rate_limit; 
00108   double roll_slew_rate_limit; 
00109   double pitch_slew_rate_limit; 
00110   double yaw_slew_rate_limit; 
00111   double alt_slew_rate_limit; 
00112   double nominal_thrust; 
00113   double thrust_mult; 
00114   double max_thrust; 
00115   bool thrust_autoadjust; 
00116   double accel_bias; 
00117   unsigned int land_now_thrust_decrease_rate; 
00118   double land_now_min_thrust_ratio; 
00119   double pitch_trim; 
00120   double roll_trim; 
00121   double yaw_offset; 
00122   
00123   ros::Publisher output;
00124   ros::Publisher estop_pub;
00125   ros::Publisher imu_pub;
00126   
00127   ros::Subscriber motor_enable_sub;
00128   ros::Subscriber control_input_sub;
00129   ros::Subscriber state_sub;
00130   ros::Subscriber mav_status_sub;
00131   ros::Subscriber imu_sub;
00132   ros::Subscriber land_now_sub;
00133   
00134   ros::Timer deadman_timer;
00135   
00136   bool latest_motor_enable;
00137   bool deadman; 
00138   ros::Time prev_control_input_time;
00139   ros::Time last_motor_enable_time;
00140   ros::Time last_mav_status_time;
00141   ros::Time last_state_time;
00142   ros::Time last_imu_time;
00143   starmac_robots_asctec::Pid alt_pid;
00144   starmac_robots_asctec::Pid yaw_pid;
00145   nav_msgs::Odometry latest_state;
00146   asctec_hl_comm::mav_status latest_mav_status;
00147   flyer_controller::control_mode_output prev_control_input_msg;
00148   ros::Duration max_motor_enable_age;
00149   ros::Duration max_mav_status_age;
00150   ros::Duration max_control_input_age;
00151   ros::Duration max_state_age;
00152   double alt_p_term;
00153   double alt_i_term;
00154   double alt_d_term;
00155   double alt_dd_term;
00156   double last_z_accel;
00157   bool land_now;
00158   bool estop_sent;
00159   bool got_first_state;
00160   double latest_battery_voltage;
00161   double min_battery_voltage;
00162   bool battery_low_warning_sent;
00163   bool mav_status_cb_called;
00164   bool got_first_control_input;
00165   double last_thrust;
00166 
00167 public:
00168   AscTecHLInterfaceAdapterNodelet() :
00169         diag_updater(),
00170         min_freq(0.1),
00171         max_freq(1000),
00172         freq_status(diagnostic_updater::FrequencyStatusParam(&min_freq, &max_freq)),
00173         
00174         
00175         
00176         deadman_timeout(0.5), alt_KP(2.0),
00177         alt_KI(0.1),
00178         alt_KD(3.0),
00179         alt_KDD(0.0),
00180         alt_Ilimit(5.0),
00181         yaw_KP(1.0),
00182         yaw_KI(1.0),
00183         yaw_KD(0.0),
00184         yaw_Ilimit(5.0),
00185         yaw_rate_limit(4.0), 
00186         roll_slew_rate_limit(10),
00187         pitch_slew_rate_limit(10),
00188         yaw_slew_rate_limit(5),
00189         alt_slew_rate_limit(0.1), 
00190         nominal_thrust(14.0),
00191         thrust_mult(1.0),
00192         max_thrust(18.0),
00193         thrust_autoadjust(true),
00194         accel_bias(9.81),
00195         land_now_thrust_decrease_rate(200),
00196         
00197         latest_motor_enable(false), deadman(false), prev_control_input_time(0), last_motor_enable_time(0), 
00198         last_mav_status_time(0), last_state_time(0), max_motor_enable_age(ros::Duration(0)),
00199         max_mav_status_age(ros::Duration(0)), max_control_input_age(ros::Duration(0)), max_state_age(ros::Duration(0)),
00200         land_now_min_thrust_ratio(0.5), pitch_trim(0), roll_trim(0), yaw_offset(0),
00201         last_z_accel(0), land_now(false), estop_sent(false), got_first_state(false), latest_battery_voltage(0), min_battery_voltage(0),
00202         battery_low_warning_sent(false), mav_status_cb_called(false), got_first_control_input(false),
00203         last_thrust(0)
00204   {
00205   }
00206 
00207   void onInit()
00208   {
00209     nh_priv = getPrivateNodeHandle();
00210     initDiagnostics();
00211     
00212     initParameters();
00213     initPublishers();
00214     initSubscribers();
00215     initTimers();
00216   }
00217 
00218 private:
00219 
00220   void initDiagnostics()
00221   {
00222     
00223     diag_updater.add("AscTecAdapter Status", this, &AscTecHLInterfaceAdapterNodelet::diagnostics);
00224     diag_updater.add(freq_status);
00225     diag_updater.setHardwareID("none");
00226     diag_updater.force_update();
00227   }
00228 
00229   void initDynamicReconfigure()
00230   {
00231     
00232     dynamic_reconfigure::Server<starmac_robots_asctec::AscTecAdapterConfig>::CallbackType f =
00233         boost::bind(&AscTecHLInterfaceAdapterNodelet::cfgCallback, this, _1, _2);
00234     dyn_reconfig_srv.setCallback(f);
00235   }
00236 
00237   void initParameters()
00238   {
00239     
00240     
00241     
00242     double temp = deadman_timeout.toSec();
00243     nh_priv.param("deadman_timeout", temp, temp);
00244     deadman_timeout.fromSec(temp);
00245     nh_priv.param("alt_KP", alt_KP, alt_KP);
00246     nh_priv.param("alt_KI", alt_KI, alt_KI);
00247     nh_priv.param("alt_KD", alt_KD, alt_KD);
00248     nh_priv.param("alt_KDD", alt_KDD, alt_KDD);
00249     nh_priv.param("alt_Ilimit", alt_Ilimit, alt_Ilimit);
00250     nh_priv.param("yaw_KP", yaw_KP, yaw_KP);
00251     nh_priv.param("yaw_KI", yaw_KI, yaw_KI);
00252     nh_priv.param("yaw_KD", yaw_KD, yaw_KD);
00253     nh_priv.param("yaw_Ilimit", yaw_Ilimit, yaw_Ilimit);
00254     nh_priv.param("yaw_rate_limit", yaw_rate_limit, yaw_rate_limit);
00255     nh_priv.param("roll_slew_rate_limit", roll_slew_rate_limit, roll_slew_rate_limit);
00256     nh_priv.param("pitch_slew_rate_limit", pitch_slew_rate_limit, pitch_slew_rate_limit);
00257     nh_priv.param("yaw_slew_rate_limit", yaw_slew_rate_limit, yaw_slew_rate_limit);
00258     nh_priv.param("alt_slew_rate_limit", alt_slew_rate_limit, alt_slew_rate_limit);
00259     nh_priv.param("nominal_thrust", nominal_thrust, nominal_thrust);
00260     nh_priv.param("thrust_mult", thrust_mult, thrust_mult);
00261     nh_priv.param("max_thrust", max_thrust, max_thrust);
00262     nh_priv.param("thrust_autoadjust", thrust_autoadjust, thrust_autoadjust);
00263     nh_priv.param("accel_bias", accel_bias, accel_bias);
00264     int temp_uint; 
00265     nh_priv.param("land_now_thrust_decrease_rate", temp_uint, (int)land_now_thrust_decrease_rate);
00266     land_now_thrust_decrease_rate = (unsigned int)temp_uint;
00267     nh_priv.param("land_now_min_thrust_ratio", land_now_min_thrust_ratio, land_now_min_thrust_ratio);
00268     nh_priv.param("pitch_trim", pitch_trim, pitch_trim);
00269     nh_priv.param("roll_trim", roll_trim, roll_trim);
00270     nh_priv.param("yaw_offset", yaw_offset, yaw_offset);
00271     
00272     setAltControllerParams(alt_KP, alt_KI, alt_KD, alt_Ilimit);
00273     setYawControllerParams(yaw_KP, yaw_KI, yaw_KD, yaw_Ilimit);
00274   }
00275 
00276   void initPublishers()
00277   {
00278     
00279     output = nh.advertise<asctec_hl_comm::mav_ctrl> ("fcu/control", 10);
00280     
00281     imu_pub = nh.advertise<sensor_msgs::Imu> ("asctec/imu", 10);
00282   }
00283 
00284   void initTimers()
00285   {
00286     
00287     double deadman_timer_period = deadman_timeout.toSec() / 2;
00288     min_freq = 0.95 / deadman_timer_period;
00289     max_freq = 1.05 / deadman_timer_period;
00290     deadman_timer = nh.createTimer(ros::Duration(deadman_timer_period),
00291                                    &AscTecHLInterfaceAdapterNodelet::deadmanCallback, this);
00292   }
00293 
00294   void initSubscribers()
00295   {
00296     
00297     motor_enable_sub = nh.subscribe("teleop_flyer/motor_enable", 1,
00298                                     &AscTecHLInterfaceAdapterNodelet::motorEnableCallback, this,
00299                                     ros::TransportHints().tcpNoDelay());
00300     control_input_sub = nh.subscribe("controller_mux/output", 1,
00301                                      &AscTecHLInterfaceAdapterNodelet::controlInputCallback, this,
00302                                      ros::TransportHints().tcpNoDelay());
00303     state_sub = nh.subscribe("odom", 1, &AscTecHLInterfaceAdapterNodelet::stateCallback, this,
00304                              ros::TransportHints().tcpNoDelay());
00305 
00306     mav_status_sub = nh.subscribe("fcu/status", 1, &AscTecHLInterfaceAdapterNodelet::mavStatusCallback, this,
00307                                   ros::TransportHints().tcpNoDelay());
00308     
00309     
00310     land_now_sub = nh_priv.subscribe("land_now", 10, &AscTecHLInterfaceAdapterNodelet::landNowCallback, this,
00311                                      ros::TransportHints().tcpNoDelay());
00312   }
00313 
00314   void cfgCallback(starmac_robots_asctec::AscTecAdapterConfig &config, uint32_t level)
00315   {
00316     ROS_INFO("Reconfigure request");
00317     if (isSafeToReconfigure())
00318     {
00319       setYawControllerParams(config.yaw_KP, config.yaw_KI, config.yaw_KD, config.yaw_Ilimit);
00320       roll_trim = config.roll_trim;
00321       pitch_trim = config.pitch_trim;
00322     }
00323     else
00324     {
00325       ROS_ERROR("Cannot reconfigure; isSafeToReconfigure() returned false");
00326     }
00327   }
00328 
00329   void setAltControllerParams(double KP, double KI, double KD, double Ilimit)
00330   {
00331     alt_pid.initPid(KP, KI, KD, Ilimit, -Ilimit);
00332     ROS_INFO("Altitude controller gains set: KP=%f, KI=%f, KD=%f, Ilimit=%f", KP, KI, KD, Ilimit);
00333   }
00334 
00335   void setYawControllerParams(double KP, double KI, double KD, double Ilimit)
00336   {
00337     yaw_pid.initPid(KP, KI, KD, Ilimit, -Ilimit);
00338     ROS_INFO("Yaw controller gains set: KP=%f, KI=%f, KD=%f, Ilimit=%f", KP, KI, KD, Ilimit);
00339   }
00340 
00341   void diagnostics(diagnostic_updater::DiagnosticStatusWrapper& stat)
00342   {
00343     if (deadman)
00344     {
00345       stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Deadman Tripped");
00346     }
00347     else
00348     {
00349       if (min_battery_voltage < 10.0)
00350       {
00351         stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Low Battery");
00352         if (not battery_low_warning_sent)
00353         {
00354           ROS_WARN("Battery voltage below 10V");
00355           battery_low_warning_sent = true;
00356         }
00357       }
00358       else
00359       {
00360         stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "OK");
00361       }
00362     }
00363     stat.add("Motor Enable", latest_motor_enable);
00364     stat.add("Deadman Tripped", deadman);
00365     stat.add("max ll_status age", max_mav_status_age);
00366     stat.add("max control inputs age", max_control_input_age);
00367     stat.add("max motor_enable age", max_motor_enable_age);
00368     stat.add("max state age", max_state_age);
00369     stat.add("alt P term", alt_p_term);
00370     stat.add("alt I term", alt_i_term);
00371     stat.add("alt D term", alt_d_term);
00372     stat.add("alt DD term", alt_dd_term);
00373     stat.add("Battery Voltage (current)", latest_battery_voltage);
00374     stat.add("Battery Voltage (minimum)", min_battery_voltage);
00375   }
00376 
00377   void motorEnableCallback(const std_msgs::BoolConstPtr& msg)
00378   {
00379     static bool first = true;
00380     latest_motor_enable = msg->data;
00381     ros::Time now = ros::Time::now();
00382     if (!first)
00383     {
00384       max_motor_enable_age = max(now - last_motor_enable_time, max_motor_enable_age);
00385     }
00386     else
00387     {
00388       first = false;
00389     }
00390     last_motor_enable_time = now;
00391   }
00392 
00393   void stateCallback(const nav_msgs::OdometryConstPtr& msg)
00394   {
00395     static bool first = true;
00396     latest_state = *msg;
00397     ROS_DEBUG_STREAM("Got state with z = " << latest_state.pose.pose.position.z);
00398     ros::Time now = ros::Time::now();
00399     if (!first)
00400     {
00401       max_state_age = max(now - last_state_time, max_state_age);
00402     }
00403     else
00404     {
00405       first = false;
00406       got_first_state = true;
00407     }
00408     last_state_time = now;
00409   }
00410 
00411   
00412   
00413   
00414   
00415   
00416   
00417   
00418   
00419   
00420   
00421   
00422   
00423   
00424   
00425   
00426   
00427   
00428   
00429   
00430   
00431   
00432   
00433   
00434   
00435   
00436   
00437   
00438   
00439   
00440   
00441   
00442   
00443   
00444   
00445   
00446   
00447   
00448   
00449   
00450   
00451   
00452   
00453   
00454   
00455   
00456   
00457   
00458   
00459   
00460   
00461 
00462   void landNowCallback(const std_msgs::BoolConstPtr& msg)
00463   {
00464     land_now = msg->data;
00465   }
00466 
00467   void mavStatusCallback(const asctec_hl_comm::mav_statusConstPtr& msg)
00468   {
00469     latest_mav_status = *msg;
00470     ros::Time now = ros::Time::now();
00471     if (mav_status_cb_called)
00472     {
00473       max_mav_status_age = max(now - last_mav_status_time, max_mav_status_age);
00474     }
00475     else
00476     {
00477       min_battery_voltage = 9999;
00478       mav_status_cb_called = true;
00479     }
00480     last_mav_status_time = now;
00481     latest_battery_voltage = (double)latest_mav_status.battery_voltage;
00482     min_battery_voltage = min(latest_battery_voltage, min_battery_voltage);
00483   }
00484 
00485   void controlInputCallback(const flyer_controller::control_mode_outputConstPtr& msg)
00486   {
00487     ros::Time now = ros::Time::now();
00488     ros::Duration dt = now - prev_control_input_time;
00489     static bool prev_motor_enable = false;
00490     if (got_first_control_input)
00491     {
00492       max_control_input_age = max(dt, max_control_input_age);
00493     }
00494     else
00495     {
00496       got_first_control_input = true;
00497     }
00498 
00499     
00500     double roll_cmd_limited, pitch_cmd_limited, yaw_cmd_limited, alt_cmd_limited;
00501     double dt_sec = dt.toSec();
00502     
00503     
00504     
00505     limitSlewRate(msg->roll_cmd, prev_control_input_msg.roll_cmd, dt_sec, roll_slew_rate_limit, roll_cmd_limited);
00506     
00507     
00508     
00509     limitSlewRate(msg->pitch_cmd, prev_control_input_msg.pitch_cmd, dt_sec, pitch_slew_rate_limit, pitch_cmd_limited);
00510 
00511     if (not msg->direct_yaw_rate_commands)
00512       limitSlewRate(msg->yaw_cmd, prev_control_input_msg.yaw_cmd, dt_sec, yaw_slew_rate_limit, yaw_cmd_limited);
00513 
00514     if (not msg->direct_thrust_commands)
00515       limitSlewRate(msg->alt_cmd, prev_control_input_msg.alt_cmd, dt_sec, alt_slew_rate_limit, alt_cmd_limited);
00516 
00517     if (latest_motor_enable and not prev_motor_enable)
00518     {
00519       double pe, de, ie;
00520       yaw_pid.getCurrentPIDErrors(&pe, &de, &ie);
00521       ROS_INFO_STREAM("Yaw integrator was at:" << ie);
00522       alt_pid.reset();
00523       yaw_pid.reset();
00524       ROS_INFO("Reset yaw & alt integrators");
00525     }
00526     prev_motor_enable = latest_motor_enable;
00527     double thrust_cmd = 0; 
00528     if (got_first_state)
00529     {
00530       if (not msg->direct_thrust_commands)
00531       {
00532         
00533         thrust_cmd = computeThrust(alt_cmd_limited, dt);
00534       }
00535       else
00536       {
00537         double yaw, pitch, roll;
00538         getLatestYPR(yaw, pitch, roll);
00539         double tfactor = 1;
00540         if (thrust_autoadjust)
00541           tfactor = 1 / (cos(pitch) * cos(roll));
00542         thrust_cmd = tfactor * msg->thrust_cmd;
00543       }
00544     }
00545     else
00546     {
00547       ROS_DEBUG("got_first_state was false..");
00548     }
00549     double yaw_rate_cmd = 0; 
00550     if (not land_now)
00551     {
00552       
00553       
00554       
00555       
00556       if (msg->direct_yaw_rate_commands)
00557         yaw_rate_cmd = msg->yaw_rate_cmd;
00558       else if (got_first_state)
00559         yaw_rate_cmd = computeYawRate(yaw_cmd_limited, dt);
00560     }
00561     else
00562     {
00563       
00564       roll_cmd_limited = roll_trim;
00565       pitch_cmd_limited = pitch_trim;
00566     }
00567     asctec_hl_comm::mav_ctrlPtr ctrl_msg(new asctec_hl_comm::mav_ctrl);
00568     ctrl_msg->type = asctec_hl_comm::mav_ctrl::acceleration;
00569     ctrl_msg->header.stamp = now;
00570     double roll_cmd_rotated, pitch_cmd_rotated; 
00571     rotateRollAndPitch(roll_cmd_limited, pitch_cmd_limited, roll_cmd_rotated, pitch_cmd_rotated);
00572     roll_cmd_rotated += roll_trim;
00573     pitch_cmd_rotated += pitch_trim;
00574     if (!deadman && dt.toSec() < 1.0)
00575     {
00576       bool motors = msg->motors_on and latest_motor_enable;
00577       if (not motors)
00578       {
00579         thrust_cmd = 0;
00580       }
00581       assemble_command(roll_cmd_rotated, pitch_cmd_rotated, yaw_rate_cmd, thrust_cmd, ctrl_msg);
00582     }
00583     if (deadman)
00584     {
00585 
00586       
00587       
00588       
00589       
00590       
00591       
00592       
00593       
00594       
00595       
00596       
00597       
00598       
00599     }
00600     ctrl_msg->header.stamp = now;
00601     output.publish(ctrl_msg);
00602     prev_control_input_time = now;
00603     prev_control_input_msg = *msg;
00604   }
00605 
00606   void rotateRollAndPitch(const double roll_cmd, const double pitch_cmd, double& roll_cmd_rotated,
00607                           double& pitch_cmd_rotated)
00608   {
00609     double cy = cos(angles::from_degrees(yaw_offset));
00610     double sy = sin(angles::from_degrees(yaw_offset));
00611     roll_cmd_rotated = cy * roll_cmd - sy * pitch_cmd;
00612     pitch_cmd_rotated = sy * roll_cmd + cy * pitch_cmd;
00613   }
00614 
00615   double computeThrust(const double alt_cmd, ros::Duration& dt)
00616   {
00617     
00618     
00619     
00620     static bool landing_now = false;
00621     static int land_now_start_thrust = 0;
00622     static ros::Time land_now_start_time;
00623     if (land_now)
00624     {
00625       if (!landing_now)
00626       {
00627         ROS_INFO("Received land_now instruction. Decreasing thrust at %d counts/s to %d counts",
00628                  land_now_thrust_decrease_rate, int(land_now_min_thrust_ratio * double(nominal_thrust)));
00629         land_now_start_thrust = last_thrust;
00630         land_now_start_time = ros::Time::now();
00631         landing_now = true;
00632       }
00633       last_thrust = max(
00634                         land_now_min_thrust_ratio * nominal_thrust,
00635                         land_now_start_thrust - (ros::Time::now() - land_now_start_time).toSec()
00636                             * land_now_thrust_decrease_rate);
00637     }
00638     else
00639     {
00640       if (landing_now)
00641       {
00642         
00643         landing_now = false;
00644       }
00645       double alt_err = (-latest_state.pose.pose.position.z) - alt_cmd;
00646       double alt_vel_err = -latest_state.twist.twist.linear.z;
00647       alt_pid.updatePid(alt_err, alt_vel_err, dt);
00648       double pe, ie, de;
00649       alt_pid.getCurrentPIDErrors(&pe, &ie, &de);
00650       alt_p_term = alt_KP * pe;
00651       alt_i_term = alt_KI * ie;
00652       alt_d_term = alt_KD * de;
00653       alt_dd_term = alt_KDD * last_z_accel;
00654       double yaw, pitch, roll;
00655       getLatestYPR(yaw, pitch, roll);
00656       double tfactor = 1;
00657       if (thrust_autoadjust)
00658         tfactor = 1 / (cos(pitch) * cos(roll));
00659       last_thrust = tfactor * (nominal_thrust + alt_pid.getCurrentCmd() + alt_dd_term);
00660     }
00661     return last_thrust;
00662   }
00663 
00664   double computeYawRate(double yaw_cmd, 
00665                         ros::Duration& dt)
00666   {
00667     double yaw, pitch, roll; 
00668     getLatestYPR(yaw, pitch, roll);
00669     
00670     double yaw_err = angles::to_degrees(
00671                                         angles::shortest_angular_distance(angles::from_degrees(yaw_cmd),
00672                                                                           yaw + angles::from_degrees(yaw_offset))); 
00673     
00674     yaw_pid.updatePid(yaw_err, dt);
00675     double yaw_rate_cmd = min(yaw_rate_limit, max(-yaw_rate_limit, yaw_pid.getCurrentCmd())); 
00676     
00677     return yaw_rate_cmd;
00678   }
00679 
00680   void getLatestYPR(double& yaw, 
00681                     double& pitch, 
00682                     double& roll 
00683   )
00684   {
00685     tf::Quaternion temp_q;
00686     
00687     
00688     
00689     
00690     tf::quaternionMsgToTF(latest_state.pose.pose.orientation, temp_q);
00691     
00692     tf::Matrix3x3 temp_mat = tf::Matrix3x3(temp_q);
00693     temp_mat.getEulerYPR(yaw, pitch, roll);
00694   }
00695 
00696   void assemble_command(double roll, 
00697                         double pitch, 
00698                         double yaw_rate, 
00699                         double thrust, 
00700                         asctec_hl_comm::mav_ctrlPtr ctrl_msg)
00701   {
00702     ctrl_msg->y = -float(min(MAX_ROLL_CMD, max(-MAX_ROLL_CMD, roll * ROLL_SCALE)));
00703     ctrl_msg->x = -float(min(MAX_PITCH_CMD, max(-MAX_PITCH_CMD, pitch * PITCH_SCALE)));
00704     ctrl_msg->yaw = -float(min(MAX_YAW_RATE_CMD, max(-MAX_YAW_RATE_CMD, yaw_rate * YAW_SCALE)));
00705     ctrl_msg->z = float(min(MAX_THRUST_CMD, min(max_thrust, max(0.0, thrust * thrust_mult * THRUST_SCALE))));
00706   }
00707 
00708   void deadmanCallback(const ros::TimerEvent& e)
00709   {
00710     
00711     
00712     
00713     
00714     
00715     
00716     
00717     
00718     
00719     
00720     
00721     
00722     
00723     
00724     
00725     
00726     
00727     
00728     
00729     
00730     
00731     
00732     
00733     
00734     
00735     
00736     
00737     
00738     
00739     
00740     
00741     
00742     
00743     
00744     
00745     
00746     
00747     
00748     
00749     
00750     
00751     
00752     
00753     
00754     
00755     
00756     
00757     
00758     
00759     
00760     
00761     
00762     
00763     
00764     
00765     diag_updater.update();
00766   }
00767 
00768   bool isSafeToReconfigure()
00769   {
00770     return (not latest_motor_enable); 
00771   }
00772 };
00773 PLUGINLIB_DECLARE_CLASS(starmac_robots_asctec, AscTecHLInterfaceAdapterNodelet, starmac_robots_asctec::AscTecHLInterfaceAdapterNodelet, nodelet::Nodelet)
00774 
00775 } 
00776