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