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 #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);
00044 pnh_.param("stddev_linear_acceleration", linear_acceleration_variance_, 0.083);
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
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
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
00169 double var_h = static_cast<double> (data->horizontalAccuracy) * 1.0e-3 / 3.0;
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
00200 double var_vel = static_cast<double> (data->speedAccuracy) * 1.0e-3 / 3.0;
00201 var_vel *= var_vel;
00202 gps_custom->velocity_covariance[0] = gps_custom->velocity_covariance[3] = var_vel;
00203
00204
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
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
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
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
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
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
00568 ctrlLL.x = helper::clamp<short>(-2047, 2047, (short)(msg.x * 180.0 / M_PI * 1000.0 / (float)k_stick_));
00569 ctrlLL.y = helper::clamp<short>(-2047, 2047, (short)(msg.y * 180.0 / M_PI * 1000.0 / (float)k_stick_));
00570
00571
00572
00573 ctrlLL.yaw = helper::clamp<short>(-1700, 1700, (short)(msg.yaw * 180.0 / M_PI * 1000.0 / (float)k_stick_yaw_));
00574
00575
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
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;
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
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;
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
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
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);
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