hl_interface.cpp
Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (c) 2011, Markus Achtelik, ASL, ETH Zurich, Switzerland
00004 You can contact the author at <markus dot achtelik at mavt dot ethz dot ch>
00005 
00006 All rights reserved.
00007 
00008 Redistribution and use in source and binary forms, with or without
00009 modification, are permitted provided that the following conditions are met:
00010 * Redistributions of source code must retain the above copyright
00011 notice, this list of conditions and the following disclaimer.
00012 * Redistributions in binary form must reproduce the above copyright
00013 notice, this list of conditions and the following disclaimer in the
00014 documentation and/or other materials provided with the distribution.
00015 * Neither the name of ETHZ-ASL nor the
00016 names of its contributors may be used to endorse or promote products
00017 derived from this software without specific prior written permission.
00018 
00019 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00020 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022 DISCLAIMED. IN NO EVENT SHALL ETHZ-ASL BE LIABLE FOR ANY
00023 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029 
00030 */
00031 
00032 #include "hl_interface.h"
00033 #include "helper.h"
00034 
00035 HLInterface::HLInterface(ros::NodeHandle & nh, CommPtr & comm) :
00036   nh_(nh), pnh_("~"), comm_(comm), gps_status_(sensor_msgs::NavSatStatus::STATUS_NO_FIX), gps_satellites_used_(0),
00037       diag_updater_(), diag_imu_freq_(diagnostic_updater::FrequencyStatusParam(&diag_imu_freq_min_,
00038                                                                                &diag_imu_freq_max_, 0, 5))
00039 {
00040   pnh_.param("frame_id", frame_id_, std::string("fcu"));
00041   pnh_.param("k_stick", k_stick_, 25);
00042   pnh_.param("k_stick_yaw", k_stick_yaw_, 120);
00043   pnh_.param("stddev_angular_velocity", angular_velocity_variance_, 0.013); // taken from experiments
00044   pnh_.param("stddev_linear_acceleration", linear_acceleration_variance_, 0.083); // taken from experiments
00045   angular_velocity_variance_ *= angular_velocity_variance_;
00046   linear_acceleration_variance_ *= linear_acceleration_variance_;
00047 
00048   imu_pub_ = nh_.advertise<asctec_hl_comm::mav_imu> ("imu_custom", 1);
00049   imu_ros_pub_ = nh_.advertise<sensor_msgs::Imu> ("imu", 1);
00050   gps_pub_ = nh_.advertise<sensor_msgs::NavSatFix> ("gps", 1);
00051   gps_custom_pub_ = nh_.advertise<asctec_hl_comm::GpsCustom> ("gps_custom", 1);
00052   rc_pub_ = nh_.advertise<asctec_hl_comm::mav_rcdata> ("rcdata", 1);
00053   status_pub_ = nh_.advertise<asctec_hl_comm::mav_status> ("status", 1);
00054   mag_pub_ = nh_.advertise<geometry_msgs::Vector3Stamped> ("mag", 1);
00055 
00056   control_sub_ = nh_.subscribe("control", 1, &HLInterface::controlCmdCallback, this);
00057 
00058   motor_srv_ = nh_.advertiseService("motor_control", &HLInterface::cbMotors, this);
00059   crtl_srv_ = nh_.advertiseService("control", &HLInterface::cbCtrl, this);
00060 
00061   config_ = asctec_hl_interface::HLInterfaceConfig::__getDefault__();
00062 
00063   // bring up dynamic reconfigure
00064   reconf_srv_ = new ReconfigureServer(pnh_);
00065   ReconfigureServer::CallbackType f = boost::bind(&HLInterface::cbConfig, this, _1, _2);
00066   reconf_srv_->setCallback(f);
00067 
00068   diag_updater_.add("AscTec AutoPilot status", this, &HLInterface::diagnostic);
00069   diag_updater_.setHardwareID("none");
00070   diag_updater_.add(diag_imu_freq_);
00071   diag_updater_.force_update();
00072 
00073   // register callbacks for packets from serial port
00074   comm_->registerCallback(HLI_PACKET_ID_IMU, &HLInterface::processImuData, this);
00075   comm_->registerCallback(HLI_PACKET_ID_RC, &HLInterface::processRcData, this);
00076   comm_->registerCallback(HLI_PACKET_ID_GPS, &HLInterface::processGpsData, this);
00077   comm_->registerCallback(HLI_PACKET_ID_STATUS, &HLInterface::processStatusData, this);
00078   comm_->registerCallback(HLI_PACKET_ID_TIMESYNC, &HLInterface::processTimeSyncData, this);
00079   comm_->registerCallback(HLI_PACKET_ID_MAG, &HLInterface::processMagData, this);
00080 }
00081 
00082 HLInterface::~HLInterface()
00083 {
00084   delete reconf_srv_;
00085 }
00086 
00087 void HLInterface::processImuData(uint8_t * buf, uint32_t bufLength)
00088 {
00089   HLI_IMU* data = (HLI_IMU*)buf;
00090   static int seq = 0;
00091   diag_imu_freq_.tick();
00092 
00093   double roll = helper::asctecAttitudeToSI(data->ang_roll);
00094   double pitch = helper::asctecAttitudeToSI(data->ang_pitch);
00095   double yaw = helper::asctecAttitudeToSI(data->ang_yaw);
00096 
00097   if (yaw > M_PI)
00098     yaw -= 2 * M_PI;
00099 
00100   double height = data->height * 0.001;
00101   double differential_height = data->differential_height * 0.001;
00102 
00103   uint32_t subs_imu = imu_pub_.getNumSubscribers();
00104   uint32_t subs_imu_ros = imu_ros_pub_.getNumSubscribers();
00105 
00106   if (subs_imu > 0 || subs_imu_ros > 0)
00107   {
00108     geometry_msgs::Quaternion q;
00109     helper::angle2quaternion(roll, pitch, yaw, &q.w, &q.x, &q.y, &q.z);
00110 
00111     if (subs_imu > 0)
00112     {
00113       asctec_hl_comm::mav_imuPtr msg(new asctec_hl_comm::mav_imu);
00114 
00115       msg->header.stamp = ros::Time(data->timestamp * 1.0e-6);
00116       msg->header.seq = seq;
00117       msg->header.frame_id = frame_id_;
00118       msg->acceleration.x = helper::asctecAccToSI(data->acc_x);
00119       msg->acceleration.y = helper::asctecAccToSI(data->acc_y);
00120       msg->acceleration.z = helper::asctecAccToSI(data->acc_z);
00121       msg->angular_velocity.x = helper::asctecOmegaToSI(data->ang_vel_roll);
00122       msg->angular_velocity.y = helper::asctecOmegaToSI(data->ang_vel_pitch);
00123       msg->angular_velocity.z = helper::asctecOmegaToSI(data->ang_vel_yaw);
00124       msg->differential_height = differential_height;
00125       msg->height = height;
00126       msg->orientation = q;
00127 
00128       imu_pub_.publish(msg);
00129     }
00130     if (subs_imu_ros > 0)
00131     {
00132       sensor_msgs::ImuPtr msg(new sensor_msgs::Imu);
00133 
00134       msg->header.stamp = ros::Time(data->timestamp * 1.0e-6);
00135       msg->header.seq = seq;
00136       msg->header.frame_id = frame_id_;
00137       msg->linear_acceleration.x = helper::asctecAccToSI(data->acc_x);
00138       msg->linear_acceleration.y = helper::asctecAccToSI(data->acc_y);
00139       msg->linear_acceleration.z = helper::asctecAccToSI(data->acc_z);
00140       msg->angular_velocity.x = helper::asctecOmegaToSI(data->ang_vel_roll);
00141       msg->angular_velocity.y = helper::asctecOmegaToSI(data->ang_vel_pitch);
00142       msg->angular_velocity.z = helper::asctecOmegaToSI(data->ang_vel_yaw);
00143       msg->orientation = q;
00144       helper::setDiagonalCovariance(msg->angular_velocity_covariance, angular_velocity_variance_);
00145       helper::setDiagonalCovariance(msg->linear_acceleration_covariance, linear_acceleration_variance_);
00146 
00147       imu_ros_pub_.publish(msg);
00148     }
00149   }
00150 
00151   seq++;
00152 }
00153 
00154 void HLInterface::processGpsData(uint8_t * buf, uint32_t bufLength)
00155 {
00156   HLI_GPS* data = (HLI_GPS*)buf;
00157   static int seq = 0;
00158   sensor_msgs::NavSatFixPtr gps_fix(new sensor_msgs::NavSatFix);
00159   asctec_hl_comm::GpsCustomPtr gps_custom(new asctec_hl_comm::GpsCustom);
00160 
00161   gps_fix->header.stamp = ros::Time(((double)data->timestamp) * 1.0e-6);
00162   gps_fix->header.seq = seq;
00163   gps_fix->header.frame_id = frame_id_;
00164   gps_fix->latitude = static_cast<double> (data->latitude) * 1.0e-7;
00165   gps_fix->longitude = static_cast<double> (data->longitude) * 1.0e-7;
00166   gps_fix->altitude = static_cast<double> (data->height) * 1.0e-3;
00167 
00168   // TODO: check covariance
00169   double var_h = static_cast<double> (data->horizontalAccuracy) * 1.0e-3 / 3.0; // accuracy, 3 sigma bound ???
00170   double var_v = static_cast<double> (data->verticalAccuracy) * 1.0e-3 / 3.0;
00171   var_h *= var_h;
00172   var_v *= var_v;
00173 
00174   gps_fix->position_covariance[0] = var_h;
00175   gps_fix->position_covariance[4] = var_h;
00176   gps_fix->position_covariance[8] = var_v;
00177   gps_fix->position_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_APPROXIMATED;
00178 
00179   gps_fix->status.service = sensor_msgs::NavSatStatus::SERVICE_GPS;
00180 
00181   if (data->status & 0x01)
00182     gps_fix->status.status = sensor_msgs::NavSatStatus::STATUS_FIX;
00183   else
00184     gps_fix->status.status = sensor_msgs::NavSatStatus::STATUS_NO_FIX;
00185 
00186   gps_custom->header = gps_fix->header;
00187   gps_custom->status = gps_fix->status;
00188   gps_custom->longitude = gps_fix->longitude;
00189   gps_custom->latitude = gps_fix->latitude;
00190   gps_custom->altitude = gps_fix->altitude;
00191   gps_custom->position_covariance = gps_fix->position_covariance;
00192   gps_custom->position_covariance_type = gps_fix->position_covariance_type;
00193 
00194   gps_custom->velocity_x = static_cast<double> (data->speedX) * 1.0e-3;
00195   gps_custom->velocity_y = static_cast<double> (data->speedY) * 1.0e-3;
00196 
00197   gps_custom->pressure_height = static_cast<double>(data->pressure_height) * 1.0e-3;
00198 
00199   // TODO: check covariance
00200   double var_vel = static_cast<double> (data->speedAccuracy) * 1.0e-3 / 3.0; // accuracy, 3 sigma bound ???
00201   var_vel *= var_vel;
00202   gps_custom->velocity_covariance[0] = gps_custom->velocity_covariance[3] = var_vel;
00203 
00204   // copy this for the other status message
00205   gps_status_ = gps_fix->status.status;
00206   gps_satellites_used_ = data->numSatellites;
00207 
00208   seq++;
00209   gps_pub_.publish(gps_fix);
00210   gps_custom_pub_.publish(gps_custom);
00211 }
00212 
00213 void HLInterface::processRcData(uint8_t * buf, uint32_t bufLength)
00214 {
00215   HLI_RCDATA* data = (HLI_RCDATA*)buf;
00216   static int seq = 0;
00217   asctec_hl_comm::mav_rcdataPtr msg(new asctec_hl_comm::mav_rcdata);
00218 
00219   msg->header.stamp = ros::Time(data->timestamp * 1.0e-6);
00220   msg->header.frame_id = frame_id_;
00221   msg->header.seq = seq;
00222 
00223   size_t n_channels = std::min(msg->channel.size(), size_t(HLI_NUMBER_RC_CHANNELS));
00224 
00225   for (size_t i = 0; i < n_channels; i++)
00226     msg->channel[i] = data->channel[i];
00227 
00228   seq++;
00229   rc_pub_.publish(msg);
00230 }
00231 
00232 void HLInterface::processStatusData(uint8_t * buf, uint32_t bufLength)
00233 {
00234   HLI_STATUS* data = (HLI_STATUS*)buf;
00235   static int seq = 0;
00236   asctec_hl_comm::mav_statusPtr msg(new asctec_hl_comm::mav_status);
00237 
00238   msg->header.stamp = ros::Time(data->timestamp * 1.0e-6);
00239   msg->header.frame_id = frame_id_;
00240   msg->header.seq = seq;
00241 
00242   msg->battery_voltage = data->battery_voltage * 0.001;
00243   msg->flight_time = data->flight_time;
00244   msg->debug1 = data->debug1;
00245   msg->debug2 = data->debug2;
00246   msg->cpu_load = data->cpu_load;
00247 
00248   switch (data->motors)
00249   {
00250     case -1:
00251       msg->motor_status = "off";
00252       break;
00253     case 0:
00254       msg->motor_status = "stopping";
00255       break;
00256     case 1:
00257       msg->motor_status = "starting";
00258       break;
00259     case 2:
00260       msg->motor_status = "running";
00261       break;
00262     default:
00263       msg->motor_status = "";
00264       break;
00265   }
00266 
00267   if ((data->flight_mode & 0x0F) == HLI_FLIGHTMODE_ACC)
00268     msg->flight_mode_ll = "Acc";
00269   else if ((data->flight_mode & 0x0F) == HLI_FLIGHTMODE_HEIGHT)
00270     msg->flight_mode_ll = "Height";
00271   else if ((data->flight_mode & 0x0F) == HLI_FLIGHTMODE_GPS)
00272     msg->flight_mode_ll = "GPS";
00273   else
00274     msg->flight_mode_ll = "unknown";
00275 
00276   msg->serial_interface_enabled = data->flight_mode & HLI_SERIALINTERFACE_ENABLED_BIT;
00277   msg->serial_interface_active = data->flight_mode & HLI_SERIALINTERFACE_ACTIVE_BIT;
00278 
00279   switch (gps_status_)
00280   {
00281     case sensor_msgs::NavSatStatus::STATUS_NO_FIX:
00282       msg->gps_status = "GPS no fix";
00283       break;
00284     case sensor_msgs::NavSatStatus::STATUS_FIX:
00285       msg->gps_status = "GPS fix";
00286       break;
00287     case sensor_msgs::NavSatStatus::STATUS_SBAS_FIX:
00288       msg->gps_status = "SBAS fix";
00289       break;
00290     case sensor_msgs::NavSatStatus::STATUS_GBAS_FIX:
00291       msg->gps_status = "GBAS fix";
00292       break;
00293     default:
00294       msg->gps_status = "";
00295       break;
00296   }
00297 
00298   msg->gps_num_satellites = gps_satellites_used_;
00299 
00300   msg->have_SSDK_parameters = data->have_SSDK_parameters == 1;
00301 
00302   switch (data->state_estimation)
00303   {
00304     case HLI_MODE_STATE_ESTIMATION_EXT:
00305       msg->state_estimation = asctec_hl_interface::HLInterface_STATE_EST_EXTERN;
00306       break;
00307     case HLI_MODE_STATE_ESTIMATION_HL_EKF:
00308       msg->state_estimation = asctec_hl_interface::HLInterface_STATE_EST_HIGHLEVEL_EKF;
00309       break;
00310     case HLI_MODE_STATE_ESTIMATION_HL_SSDK:
00311       msg->state_estimation = asctec_hl_interface::HLInterface_STATE_EST_HIGHLEVEL_SSDK;
00312       break;
00313     case HLI_MODE_STATE_ESTIMATION_OFF:
00314       msg->state_estimation = asctec_hl_interface::HLInterface_STATE_EST_OFF;
00315       break;
00316     default:
00317       msg->state_estimation = "unknown";
00318       break;
00319   }
00320 
00321   switch (data->position_control)
00322   {
00323     case HLI_MODE_POSCTRL_HL:
00324       msg->position_control = asctec_hl_interface::HLInterface_POSCTRL_HIGHLEVEL;
00325       break;
00326     case HLI_MODE_POSCTRL_LL:
00327       msg->position_control = asctec_hl_interface::HLInterface_POSCTRL_GPS;
00328       break;
00329     case HLI_MODE_POSCTRL_OFF:
00330       msg->position_control = asctec_hl_interface::HLInterface_POSCTRL_OFF;
00331       break;
00332     default:
00333       msg->position_control = "unknown";
00334       break;
00335   }
00336 
00337   msg->rx_packets = comm_->getRxPackets();
00338   msg->rx_packets_good = comm_->getRxPacketsGood();
00339   msg->tx_packets = data->rx_packets;
00340   msg->tx_packets_good = data->rx_packets_good;
00341 
00342   msg->timesync_offset = (float)data->timesync_offset * 1e-6;
00343 
00344   seq++;
00345   status_ = *msg;
00346   status_pub_.publish(msg);
00347 
00348   diag_updater_.update();
00349 }
00350 
00351 
00352 void HLInterface::diagnostic(diagnostic_updater::DiagnosticStatusWrapper & stat)
00353 {
00354   unsigned char summary_level = diagnostic_msgs::DiagnosticStatus::OK;
00355   std::string summary_message = "OK";
00356 
00357   // TODO: are these thresholds ok?
00358 
00359   if (status_.battery_voltage < (config_.battery_warning - 0.5))
00360   {
00361     summary_level = diagnostic_msgs::DiagnosticStatus::ERROR;
00362     summary_message = "battery voltage critical - land now !!!";
00363     ROS_ERROR_STREAM_THROTTLE(1, "" << summary_message << ": " << status_.battery_voltage << " V");
00364   }
00365   else if (status_.battery_voltage < config_.battery_warning)
00366   {
00367     summary_level = diagnostic_msgs::DiagnosticStatus::WARN;
00368     summary_message = "battery voltage low";
00369     ROS_WARN_STREAM_THROTTLE(1, "" << summary_message << ": " << status_.battery_voltage << " V");
00370   }
00371 
00372   stat.summary(summary_level, summary_message);
00373   stat.add("Battery voltage [V]", status_.battery_voltage);
00374   stat.add("Flight time [s]", status_.flight_time);
00375   stat.add("HLP cpu load [%]", status_.cpu_load);
00376   stat.add("Position control mode", status_.position_control);
00377   stat.add("State estimation mode", status_.state_estimation);
00378   stat.add("GPS status", status_.gps_status);
00379   stat.add("GPS # satellites", status_.gps_num_satellites);
00380   stat.add("Flight mode LLP", status_.flight_mode_ll);
00381   stat.add("Motor status", status_.motor_status);
00382   stat.add("Successful TX packets [%]", (float)status_.tx_packets_good/(float)status_.tx_packets*100.0);
00383   stat.add("Successful RX packets [%]", (float)status_.rx_packets_good/(float)status_.rx_packets*100.0);
00384   stat.add("Serial interface enabled", static_cast<bool>(status_.serial_interface_enabled));
00385   stat.add("Serial interface active", static_cast<bool>(status_.serial_interface_active));
00386   stat.add("Have SSDK parameters", static_cast<bool>(status_.have_SSDK_parameters));
00387   stat.add("Timesync offset [ms]", status_.timesync_offset*1000.0);
00388   stat.add("Debug 1", status_.debug1);
00389   stat.add("Debug 2", status_.debug2);
00390 }
00391 
00392 void HLInterface::processTimeSyncData(uint8_t * buf, uint32_t bufLength)
00393 {
00394   HLI_TIMESYNC data = *(HLI_TIMESYNC*)buf;
00395 
00396   data.ts1 = (uint64_t)(ros::Time::now().toSec() * 1.0e6);
00397 
00398   comm_->sendPacket(HLI_PACKET_ID_TIMESYNC, data);
00399 
00400   // warn if imu time is too far away from pc time. At low baudrates, the IMU will take longer to sync.
00401   ROS_WARN_STREAM_COND(std::abs(status_.timesync_offset) > 0.002, "imu time is off by "<<status_.timesync_offset * 1e3 <<" ms");
00402 }
00403 
00404 void HLInterface::processMagData(uint8_t * buf, uint32_t bufLength)
00405 {
00406   HLI_MAG* data = (HLI_MAG*)buf;
00407   static int seq = 0;
00408   geometry_msgs::Vector3StampedPtr msg(new geometry_msgs::Vector3Stamped);
00409 
00410   msg->header.stamp = ros::Time(data->timestamp * 1.0e-6);
00411   msg->header.frame_id = frame_id_;
00412   msg->header.seq = seq;
00413 
00414   msg->vector.x = data->x;
00415   msg->vector.y = data->y;
00416   msg->vector.z = data->z;
00417 
00418   seq++;
00419   mag_pub_.publish(msg);
00420 }
00421 
00422 bool HLInterface::cbMotors(asctec_hl_comm::mav_ctrl_motors::Request &req,
00423                            asctec_hl_comm::mav_ctrl_motors::Response &resp)
00424 {
00425   HLI_MOTORS data;
00426 
00427   if (req.startMotors)
00428   {
00429     data.motors = 1;
00430     ROS_INFO("request to start motors");
00431   }
00432   else
00433   {
00434     data.motors = 0;
00435     ROS_INFO("request to stop motors");
00436   }
00437 
00438   // make sure packet arrives
00439   bool success = false;
00440   for (int i = 0; i < 5; i++)
00441   {
00442     success = comm_->sendPacketAck(HLI_PACKET_ID_MOTORS, data, 0.5);
00443     if (success)
00444       break;
00445   }
00446 
00447   if(!success)
00448   {
00449     ROS_WARN("unable to send motor on/off command");
00450     resp.motorsRunning = status_.motor_status == "running";
00451     return false;
00452   }
00453 
00454   ros::Duration d(0.1);
00455   for (int i = 0; i < 10; i++)
00456   {
00457     if (req.startMotors && status_.motor_status == "running")
00458     {
00459       resp.motorsRunning = true;
00460       return true;
00461     }
00462     else if (!req.startMotors && status_.motor_status == "off")
00463     {
00464       resp.motorsRunning = false;
00465       return true;
00466     }
00467     d.sleep();
00468   }
00469 
00470   ROS_WARN("switching motors %s timed out", req.startMotors?"on":"off");
00471   return false;
00472 }
00473 
00474 void HLInterface::controlCmdCallback(const asctec_hl_comm::mav_ctrlConstPtr & msg)
00475 {
00476   sendControlCmd(*msg);
00477 }
00478 
00479 bool HLInterface::cbCtrl(asctec_hl_comm::MavCtrlSrv::Request & req, asctec_hl_comm::MavCtrlSrv::Response & resp)
00480 {
00481   sendControlCmd(req.ctrl, &resp.ctrl_result);
00482   return resp.ctrl_result.type != -1;
00483 }
00484 
00485 void HLInterface::sendControlCmd(const asctec_hl_comm::mav_ctrl & ctrl, asctec_hl_comm::mav_ctrl * ctrl_result)
00486 {
00487   bool validCommand = false;
00488 
00489   if (ctrl.type == asctec_hl_comm::mav_ctrl::acceleration)
00490   {
00491     if (config_.position_control == asctec_hl_interface::HLInterface_POSCTRL_OFF)
00492     {
00493       sendAccCommandLL(ctrl, ctrl_result);
00494       validCommand = true;
00495     }
00496     else
00497     {
00498       ROS_WARN_STREAM_THROTTLE(2,
00499           "GPS/Highlevel position control must be turned off. "
00500           "Set \"position_control\" parameter to \"off\"");
00501       if(ctrl_result != NULL)
00502         ctrl_result->type = -1;
00503     }
00504   }
00505 
00506   else if (ctrl.type == asctec_hl_comm::mav_ctrl::velocity)
00507   {
00508     if (config_.position_control == asctec_hl_interface::HLInterface_POSCTRL_GPS)
00509     {
00510       sendVelCommandLL(ctrl, ctrl_result);
00511       validCommand = true;
00512     }
00513     else if (config_.position_control == asctec_hl_interface::HLInterface_POSCTRL_HIGHLEVEL)
00514     {
00515       sendVelCommandHL(ctrl, ctrl_result);
00516       validCommand = true;
00517     }
00518     else
00519     {
00520       ROS_WARN_STREAM_THROTTLE(2,
00521           "Higlevel or Lowlevel processor position control has not "
00522           "been chosen. Set \"position_control\" parameter to "
00523           "\"HighLevel\" or \"GPS\" ! sending nothing to mav !");
00524       if(ctrl_result != NULL)
00525         ctrl_result->type = -1;
00526     }
00527 
00528   }
00529   else if (ctrl.type == asctec_hl_comm::mav_ctrl::position)
00530   {
00531     // allow to "inherit" max velocity from parameters
00532     asctec_hl_comm::mav_ctrl ctrl_msg = ctrl;
00533     if(ctrl_msg.v_max_xy == -1)
00534       ctrl_msg.v_max_xy = config_.max_velocity_xy;
00535 
00536     if(ctrl_msg.v_max_z == -1)
00537       ctrl_msg.v_max_z = config_.max_velocity_z;
00538 
00539     if (config_.position_control == asctec_hl_interface::HLInterface_POSCTRL_HIGHLEVEL &&
00540         config_.state_estimation != asctec_hl_interface::HLInterface_STATE_EST_OFF)
00541     {
00542       sendPosCommandHL(ctrl_msg, ctrl_result);
00543       validCommand = true;
00544     }
00545     else
00546     {
00547       ROS_WARN_STREAM_THROTTLE(2,
00548           "Higlevel processor position control was not chosen and/or no state "
00549           "estimation was selected. Set the \"position_control\" parameter to "
00550           "\"HighLevel\" and the \"state_estimation\" parameter to anything but \"off\"! sending nothing to mav !");
00551       if(ctrl_result != NULL)
00552         ctrl_result->type = -1;
00553     }
00554   }
00555 
00556   // was the controlmode specified properly?
00557   if (!validCommand)
00558   {
00559     ROS_WARN_STREAM_THROTTLE(2,"Control type was not specified ... not sending anything to the mav");
00560   }
00561 }
00562 
00563 void HLInterface::sendAccCommandLL(const asctec_hl_comm::mav_ctrl & msg, asctec_hl_comm::mav_ctrl * ctrl_result)
00564 {
00565   HLI_CMD_LL ctrlLL;
00566 
00567   // spin-directions positive according to right hand rule around axis
00568   ctrlLL.x = helper::clamp<short>(-2047, 2047, (short)(msg.x * 180.0 / M_PI * 1000.0 / (float)k_stick_)); // cmd=real_angle*1000/K_stick
00569   ctrlLL.y = helper::clamp<short>(-2047, 2047, (short)(msg.y * 180.0 / M_PI * 1000.0 / (float)k_stick_)); // dito
00570 
00571   // cmd=real_anglular_velocity*1000/k_stick_yaw,
00572   // cmd is limited to +- 1700 such that it's not possible to switch the motors with a bad command
00573   ctrlLL.yaw = helper::clamp<short>(-1700, 1700, (short)(msg.yaw * 180.0 / M_PI * 1000.0 / (float)k_stick_yaw_));
00574 
00575   // catch wrong thrust command ;-)
00576   if (msg.z > 1.0)
00577   {
00578     ROS_ERROR(
00579         "I just prevented you from giving full thrust..."
00580         "\nset the input range correct!!! [0 ... 1.0] ");
00581 
00582     if(ctrl_result != NULL)
00583       ctrl_result->type = -1;
00584 
00585     return;
00586   }
00587   else
00588   {
00589     ctrlLL.z = helper::clamp<short>(0, 4096, (short)(msg.z * 4096.0));
00590   }
00591 
00592   if(ctrl_result != NULL)
00593   {
00594     *ctrl_result = msg;
00595     ctrl_result->x = static_cast<float>(ctrlLL.x * k_stick_) / 180.0 * M_PI * 1e-3;
00596     ctrl_result->y = static_cast<float>(ctrlLL.y * k_stick_) / 180.0 * M_PI * 1e-3;
00597     ctrl_result->z = static_cast<float>(ctrlLL.z) / 4096.0;
00598     ctrl_result->yaw = static_cast<float>(ctrlLL.yaw * k_stick_yaw_) / 180.0 * M_PI * 1e-3;
00599   }
00600 
00601 //  ROS_INFO_STREAM("sending command: x:"<<ctrlLL.x<<" y:"<<ctrlLL.y<<" yaw:"<<ctrlLL.yaw<<" z:"<<ctrlLL.z<<" ctrl:"<<enable_ctrl_);
00602   comm_->sendPacket(HLI_PACKET_ID_CONTROL_LL, ctrlLL);
00603 }
00604 
00605 void HLInterface::sendVelCommandLL(const asctec_hl_comm::mav_ctrl & msg, asctec_hl_comm::mav_ctrl * ctrl_result)
00606 {
00607   HLI_CMD_LL ctrlLL;
00608 
00609   ctrlLL.x = helper::clamp<short>(-2047, 2047, (short)(msg.x / config_.max_velocity_xy * 2047.0));
00610   ctrlLL.y = helper::clamp<short>(-2047, 2047, (short)(msg.y / config_.max_velocity_xy * 2047.0));
00611   ctrlLL.yaw = helper::clamp<short>(-2047, 2047, (short)(msg.yaw / config_.max_velocity_yaw* 2047.0));
00612   ctrlLL.z = helper::clamp<short>(-2047, 2047, (short)(msg.z / config_.max_velocity_z * 2047.0)) + 2047; // "zero" is still 2047!
00613 
00614   if (ctrl_result != NULL)
00615   {
00616     *ctrl_result = msg;
00617     ctrl_result->x = static_cast<float> (ctrlLL.x) / 2047.0 * config_.max_velocity_xy;
00618     ctrl_result->y = static_cast<float> (ctrlLL.y) / 2047.0 * config_.max_velocity_xy;
00619     ctrl_result->z = static_cast<float> (ctrlLL.z - 2047) / 2047.0 * config_.max_velocity_z;
00620     ctrl_result->yaw = static_cast<float> (ctrlLL.yaw) / 2047.0 * config_.max_velocity_yaw;
00621   }
00622 
00623 //  ROS_INFO_STREAM("sending command: x:"<<ctrlLL.x<<" y:"<<ctrlLL.y<<" yaw:"<<ctrlLL.yaw<<" z:"<<ctrlLL.z<<" ctrl:"<<enable_ctrl_);
00624   comm_->sendPacket(HLI_PACKET_ID_CONTROL_LL, ctrlLL);
00625 }
00626 
00627 void HLInterface::sendVelCommandHL(const asctec_hl_comm::mav_ctrl & msg, asctec_hl_comm::mav_ctrl * ctrl_result)
00628 {
00629   HLI_CMD_HL ctrlHL;
00630 
00631   ctrlHL.vX = (short)(helper::clamp<float>(-config_.max_velocity_xy, config_.max_velocity_xy, msg.x) * 1000.0);
00632   ctrlHL.vY = (short)(helper::clamp<float>(-config_.max_velocity_xy, config_.max_velocity_xy, msg.y) * 1000.0);
00633   ctrlHL.vZ = (short)(helper::clamp<float>(-config_.max_velocity_z, config_.max_velocity_z, msg.z) * 1000.0);
00634   ctrlHL.vYaw = (short)(helper::clamp<float>(-config_.max_velocity_yaw, config_.max_velocity_yaw, msg.yaw) * 180.0 / M_PI * 1000.0);
00635 
00636   ctrlHL.x = 0;
00637   ctrlHL.y = 0;
00638   ctrlHL.z = 0;
00639   ctrlHL.heading = 0;
00640 
00641   ctrlHL.bitfield = 1;
00642 
00643   if (ctrl_result != NULL)
00644   {
00645     *ctrl_result = msg;
00646     ctrl_result->x = static_cast<float> (ctrlHL.vX) * 1e-3;
00647     ctrl_result->y = static_cast<float> (ctrlHL.vY) * 1e-3;
00648     ctrl_result->z = static_cast<float> (ctrlHL.vZ) * 1e-3;
00649     ctrl_result->yaw = static_cast<float> (ctrlHL.vYaw) / 180.0e3 * M_PI;
00650   }
00651 
00652   comm_->sendPacket(HLI_PACKET_ID_CONTROL_HL, ctrlHL);
00653 }
00654 void HLInterface::sendPosCommandHL(const asctec_hl_comm::mav_ctrl & msg, asctec_hl_comm::mav_ctrl * ctrl_result)
00655 {
00656   HLI_CMD_HL ctrlHL;
00657   static unsigned int seq = 1; // <-- set to one, otherwise first packet doesn't get through
00658 
00659   if (std::abs(msg.yaw) > M_PI)
00660   {
00661     ROS_WARN("yaw has to be in [-pi ... pi], got %f instead", msg.yaw);
00662     if (ctrl_result != NULL)
00663       ctrl_result->type = -1;
00664     return;
00665   }
00666 
00667   ctrlHL.seq = seq;
00668   ctrlHL.vX = 0;
00669   ctrlHL.vX = 0;
00670   ctrlHL.vZ = 0;
00671   //                    ctrlHL.vHeading = 0;
00672 
00673   ctrlHL.x = static_cast<int>(helper::clamp<float>(config_.min_pos_x, config_.max_pos_x, msg.x) * 1000.0);
00674   ctrlHL.y = static_cast<int>(helper::clamp<float>(config_.min_pos_y, config_.max_pos_y, msg.y) * 1000.0);
00675   ctrlHL.z = static_cast<int>(helper::clamp<float>(config_.min_pos_z, config_.max_pos_z, msg.z) * 1000.0);
00676   // asctec uses 0...360° * 1000, we -pi...+pi
00677   ctrlHL.heading = helper::yaw2asctec(msg.yaw);
00678 
00679   ctrlHL.vMaxXY = static_cast<short>(std::min<float>(config_.max_velocity_xy, msg.v_max_xy)*1000);
00680   ctrlHL.vMaxZ = static_cast<short>(std::min<float>(config_.max_velocity_z, msg.v_max_z)*1000);
00681 
00682   ctrlHL.bitfield = 0;
00683 
00684   if (ctrl_result != NULL)
00685   {
00686     *ctrl_result = msg;
00687     ctrl_result->x = static_cast<float> (ctrlHL.x) * 1e-3;
00688     ctrl_result->y = static_cast<float> (ctrlHL.y) * 1e-3;
00689     ctrl_result->z = static_cast<float> (ctrlHL.z) * 1e-3;
00690     ctrl_result->yaw = static_cast<float> (ctrlHL.heading) / 180.0e3 * M_PI;
00691     if (ctrl_result->yaw > M_PI)
00692         ctrl_result->yaw -= 2 * M_PI;
00693   }
00694 
00695   comm_->sendPacket(HLI_PACKET_ID_CONTROL_HL, ctrlHL);
00696   seq++;
00697 }
00698 
00699 void HLInterface::cbConfig(asctec_hl_interface::HLInterfaceConfig & config, uint32_t level)
00700 {
00701 
00702   if (level & asctec_hl_interface::HLInterface_HLI_CONFIG)
00703   {
00713     enable_ctrl_ = 0;
00714     if (config.enable_x)
00715       enable_ctrl_ |= 1;
00716     if (config.enable_y)
00717       enable_ctrl_ |= 1 << 1;
00718     if (config.enable_yaw)
00719       enable_ctrl_ |= 1 << 2;
00720     if (config.enable_z)
00721       enable_ctrl_ |= 1 << 3;
00722     if (config.position_control == asctec_hl_interface::HLInterface_POSCTRL_GPS)
00723     {
00724       enable_ctrl_ |= 1 << 4;
00725       enable_ctrl_ |= 1 << 5;
00726     }
00727 
00728     HLI_CONFIG cfg;
00729     cfg.position_control_axis_enable = enable_ctrl_;
00730 
00731     if (config.position_control == asctec_hl_interface::HLInterface_POSCTRL_HIGHLEVEL)
00732       cfg.mode_position_control = HLI_MODE_POSCTRL_HL;
00733     else if (config.position_control == asctec_hl_interface::HLInterface_POSCTRL_GPS)
00734       cfg.mode_position_control = HLI_MODE_POSCTRL_LL;
00735     else
00736       cfg.mode_position_control = HLI_MODE_POSCTRL_OFF;
00737 
00738     if (config.state_estimation == asctec_hl_interface::HLInterface_STATE_EST_EXTERN)
00739       cfg.mode_state_estimation = HLI_MODE_STATE_ESTIMATION_EXT;
00740     else if (config.state_estimation == asctec_hl_interface::HLInterface_STATE_EST_HIGHLEVEL_SSDK)
00741       cfg.mode_state_estimation = HLI_MODE_STATE_ESTIMATION_HL_SSDK;
00742     else if (config.state_estimation == asctec_hl_interface::HLInterface_STATE_EST_HIGHLEVEL_EKF)
00743       cfg.mode_state_estimation = HLI_MODE_STATE_ESTIMATION_HL_EKF;
00744     else
00745       cfg.mode_state_estimation = HLI_MODE_STATE_ESTIMATION_OFF;
00746 
00747     cfg.battery_warning_voltage = static_cast<uint16_t>(config.battery_warning * 1000); // convert to mV
00748 
00749     if(!comm_->sendPacketAck(HLI_PACKET_ID_CONFIG, cfg)){
00750       config.enable_x = config_.enable_x;
00751       config.enable_y = config_.enable_y;
00752       config.enable_z = config_.enable_z;
00753       config.enable_yaw = config_.enable_yaw;
00754       config.position_control = config_.position_control;
00755       config.state_estimation = config_.state_estimation;
00756       config.battery_warning = config_.battery_warning;
00757     }
00758   }
00759 
00760   if (level & asctec_hl_interface::HLInterface_PACKET_RATE)
00761   {
00762     HLI_SUBSCRIPTION ps;
00763     ps.imu = helper::rateToPeriod(config.packet_rate_imu);
00764     ps.rcdata = helper::rateToPeriod(config.packet_rate_rc);
00765     ps.gps = helper::rateToPeriod(config.packet_rate_gps);
00766     ps.ssdk_debug = helper::rateToPeriod(config.packet_rate_ssdk_debug);
00767     ps.ekf_state = helper::rateToPeriod(config.packet_rate_ekf_state);
00768     ps.mag = helper::rateToPeriod(config.packet_rate_mag);
00769 
00770     diag_imu_freq_min_ = 0.95 * config.packet_rate_imu;
00771     diag_imu_freq_max_ = 1.05 * config.packet_rate_imu;
00772 
00773     if(!comm_->sendPacketAck(HLI_PACKET_ID_SUBSCRIPTION, ps)){
00774       config.packet_rate_imu = config_.packet_rate_imu;
00775       config.packet_rate_rc = config_.packet_rate_rc;
00776       config.packet_rate_gps = config_.packet_rate_gps;
00777       config.packet_rate_ssdk_debug = config_.packet_rate_ssdk_debug;
00778       config.packet_rate_ekf_state = config_.packet_rate_ekf_state;
00779       config.packet_rate_mag = config_.packet_rate_mag;
00780     }
00781   }
00782 
00783   config_ = config;
00784 }
00785 
00786 


asctec_hl_interface
Author(s): Markus Achtelik, Michael Achtelik, Stephan Weiss, Laurent Kneip
autogenerated on Tue Jan 7 2014 11:05:25