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