00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "asctec_proc/asctec_proc.h"
00023
00024 namespace asctec
00025 {
00026
00027 AsctecProc::AsctecProc(ros::NodeHandle nh, ros::NodeHandle nh_private):
00028 nh_(nh),
00029 nh_private_(nh_private)
00030 {
00031 ROS_INFO("Starting AsctecProc");
00032
00033 ros::NodeHandle nh_rawdata (nh_, asctec::ROS_NAMESPACE);
00034 ros::NodeHandle nh_procdata (nh_, mav::ROS_NAMESPACE);
00035
00036
00037
00038 initializeParams();
00039
00040
00041
00042 motors_on_ = false;
00043 engaging_ = false;
00044
00045 ctrl_roll_ = 0;
00046 ctrl_pitch_ = 0;
00047 ctrl_yaw_ = 0;
00048 ctrl_thrust_ = 0;
00049
00050 assembleCtrlCommands();
00051
00052
00053
00054 imu_publisher_ = nh_procdata.advertise<sensor_msgs::Imu>(
00055 mav::IMU_TOPIC, 10);
00056 height_publisher_ = nh_procdata.advertise<mav_msgs::Height>(
00057 mav::P_HEIGHT_TOPIC, 10);
00058 height_filtered_publisher_ = nh_procdata.advertise<mav_msgs::Height>(
00059 mav::P_HEIGHT_FILTERED_TOPIC, 10);
00060 ctrl_input_publisher_ = nh_rawdata.advertise<asctec_msgs::CtrlInput>(
00061 asctec::CTRL_INPUT_TOPIC, 10);
00062
00063
00064
00065 imu_calcdata_subscriber_ = nh_rawdata.subscribe(
00066 asctec::IMU_CALCDATA_TOPIC, 10, &AsctecProc::imuCalcDataCallback, this);
00067 ll_status_subscriber_ = nh_rawdata.subscribe(
00068 asctec::LL_STATUS_TOPIC, 5, &AsctecProc::llStatusCallback, this);
00069
00070 if (enable_ctrl_thrust_)
00071 {
00072 cmd_thrust_subscriber_ = nh_procdata.subscribe(
00073 mav::CMD_THRUST_TOPIC, 1, &AsctecProc::cmdThrustCallback, this);
00074 }
00075 if (enable_ctrl_roll_)
00076 {
00077 cmd_roll_subscriber_ = nh_procdata.subscribe(
00078 mav::CMD_ROLL_TOPIC, 1, &AsctecProc::cmdRollCallback, this);
00079 }
00080 if (enable_ctrl_pitch_)
00081 {
00082 cmd_pitch_subscriber_ = nh_procdata.subscribe(
00083 mav::CMD_PITCH_TOPIC, 1, &AsctecProc::cmdPitchCallback, this);
00084 }
00085 if (enable_ctrl_yaw_)
00086 {
00087 cmd_yaw_subscriber_ = nh_procdata.subscribe(
00088 mav::CMD_YAW_RATE_TOPIC, 5, &AsctecProc::cmdYawCallback, this);
00089 }
00090
00091
00092
00093 if(enable_state_changes_)
00094 {
00095 set_motors_on_off_srv_ = nh_procdata.advertiseService(
00096 "setMotorsOnOff", &AsctecProc::setMotorsOnOff, this);
00097 }
00098
00099 get_motors_on_off_srv_ = nh_procdata.advertiseService(
00100 "getMotorsOnOff", &AsctecProc::getMotorsOnOff, this);
00101 }
00102
00103 AsctecProc::~AsctecProc()
00104 {
00105 ROS_INFO("Destroying AsctecProc");
00106
00107 }
00108
00109 void AsctecProc::initializeParams()
00110 {
00111 if (!nh_private_.getParam ("enable_state_changes", enable_state_changes_))
00112 enable_state_changes_ = false;
00113
00114 if (!nh_private_.getParam ("enable_ctrl_thrust", enable_ctrl_thrust_))
00115 enable_ctrl_thrust_ = false;
00116 if (!nh_private_.getParam ("enable_ctrl_pitch", enable_ctrl_pitch_))
00117 enable_ctrl_pitch_ = false;
00118 if (!nh_private_.getParam ("enable_ctrl_roll", enable_ctrl_roll_))
00119 enable_ctrl_roll_ = false;
00120 if (!nh_private_.getParam ("enable_ctrl_yaw", enable_ctrl_yaw_))
00121 enable_ctrl_yaw_ = false;
00122
00123 if (!nh_private_.getParam ("max_ctrl_thrust", max_ctrl_thrust_))
00124 max_ctrl_thrust_ = 2200;
00125 if (!nh_private_.getParam ("max_ctrl_roll", max_ctrl_roll_))
00126 max_ctrl_roll_ = 300;
00127 if (!nh_private_.getParam ("max_ctrl_pitch", max_ctrl_pitch_))
00128 max_ctrl_pitch_ = 300;
00129 if (!nh_private_.getParam ("max_ctrl_yaw", max_ctrl_yaw_))
00130 max_ctrl_yaw_ = 600;
00131 }
00132
00133 bool AsctecProc::setMotorsOnOff(mav_msgs::SetMotorsOnOff::Request &req,
00134 mav_msgs::SetMotorsOnOff::Response &res)
00135 {
00136 state_mutex_.lock();
00137 engaging_ = true;
00138
00139 if (req.on && !motors_on_)
00140 {
00141 ctrl_roll_ = 0;
00142 ctrl_pitch_ = 0;
00143 ctrl_yaw_ = 0;
00144 ctrl_thrust_ = 0;
00145 startMotors();
00146 }
00147 else
00148 {
00149 stopMotors();
00150 }
00151
00152 engaging_ = false;
00153 state_mutex_.unlock();
00154
00155 return (req.on == motors_on_);
00156 }
00157
00158 bool AsctecProc::getMotorsOnOff(mav_msgs::GetMotorsOnOff::Request &req,
00159 mav_msgs::GetMotorsOnOff::Response &res)
00160 {
00161 state_mutex_.lock();
00162 res.on = motors_on_;
00163 state_mutex_.unlock();
00164
00165 return true;
00166 }
00167
00168 void AsctecProc::llStatusCallback (const asctec_msgs::LLStatusPtr& ll_status_msg)
00169 {
00170
00171 motors_on_ = ll_status_msg->flying;
00172 }
00173
00174 void AsctecProc::cmdRollCallback(const std_msgs::Float64ConstPtr& cmd_roll_msg)
00175 {
00176 if (!motors_on_ || engaging_) return;
00177
00178 state_mutex_.lock();
00179
00180
00181 ctrl_roll_ = (int)(cmd_roll_msg->data * asctec::ROS_TO_ASC_ROLL);
00182
00183 ROS_INFO ("cmd_roll received: %f (%d)", cmd_roll_msg->data, ctrl_roll_);
00184
00185
00186 if (ctrl_roll_ > max_ctrl_roll_)
00187 {
00188 ROS_WARN("ctrl_roll of %d too big, clamping to %d!", ctrl_roll_, max_ctrl_roll_);
00189 ctrl_roll_ = max_ctrl_roll_;
00190 }
00191 else if (ctrl_roll_ < -max_ctrl_roll_)
00192 {
00193 ROS_WARN("ctrl_roll of %d too small, clamping to -%d!", ctrl_roll_, -max_ctrl_roll_);
00194 ctrl_roll_ = -max_ctrl_roll_;
00195 }
00196
00197 publishCtrlInputMsg();
00198
00199 state_mutex_.unlock();
00200 }
00201
00202 void AsctecProc::cmdPitchCallback(const std_msgs::Float64ConstPtr& cmd_pitch_msg)
00203 {
00204 if (!motors_on_ || engaging_) return;
00205
00206 state_mutex_.lock();
00207
00208
00209 ctrl_pitch_ = (int)(cmd_pitch_msg->data * asctec::ROS_TO_ASC_PITCH);
00210
00211 ROS_DEBUG ("cmd_pitch received: %f (%d)", cmd_pitch_msg->data, ctrl_pitch_);
00212
00213
00214 if (ctrl_pitch_ > max_ctrl_pitch_)
00215 {
00216 ROS_WARN("ctrl_pitch of %d too big, clamping to %d!", ctrl_pitch_, max_ctrl_pitch_);
00217 ctrl_pitch_ = max_ctrl_pitch_;
00218 }
00219 else if (ctrl_pitch_ < -max_ctrl_pitch_)
00220 {
00221 ROS_WARN("ctrl_pitch of %d too small, clamping to -%d!", ctrl_pitch_, -max_ctrl_pitch_);
00222 ctrl_pitch_ = -max_ctrl_pitch_;
00223 }
00224
00225 publishCtrlInputMsg();
00226
00227 state_mutex_.unlock();
00228 }
00229
00230 void AsctecProc::cmdYawCallback(const std_msgs::Float64ConstPtr& cmd_yaw_rate_msg)
00231 {
00232 if (!motors_on_ || engaging_) return;
00233
00234 state_mutex_.lock();
00235
00236
00237 ctrl_yaw_ = (int)(cmd_yaw_rate_msg->data * asctec::ROS_TO_ASC_YAW_RATE);
00238
00239 ROS_DEBUG ("cmd_yaw received: %f (%d)", cmd_yaw_rate_msg->data, ctrl_yaw_);
00240
00241
00242 if (ctrl_yaw_ > max_ctrl_yaw_)
00243 {
00244 ROS_WARN("ctrl_yaw of %d too big, clamping to %d!", ctrl_yaw_, max_ctrl_yaw_);
00245 ctrl_yaw_ = max_ctrl_yaw_;
00246 }
00247 else if (ctrl_yaw_ < -max_ctrl_yaw_)
00248 {
00249 ROS_WARN("ctrl_yaw of %d too small, clamping to -%d!", ctrl_yaw_, -max_ctrl_yaw_);
00250 ctrl_yaw_ = -max_ctrl_yaw_;
00251 }
00252
00253 publishCtrlInputMsg();
00254
00255 state_mutex_.unlock();
00256 }
00257
00258 void AsctecProc::cmdThrustCallback(const std_msgs::Float64ConstPtr& cmd_thrust_msg)
00259 {
00260 if (!motors_on_ || engaging_) return;
00261
00262 state_mutex_.lock();
00263
00264
00265 ctrl_thrust_ = (int)(cmd_thrust_msg->data * asctec::ROS_TO_ASC_THRUST);
00266
00267 ROS_DEBUG ("cmd_thrust received: %f (%d)", cmd_thrust_msg->data, ctrl_thrust_);
00268
00269
00270 if (ctrl_thrust_ > max_ctrl_thrust_)
00271 {
00272 ROS_WARN("ctrl_thrust of %d too big, clamping to %d!", ctrl_thrust_, max_ctrl_thrust_);
00273 ctrl_thrust_ = max_ctrl_thrust_;
00274 }
00275 else if (ctrl_thrust_ < 0)
00276 {
00277 ROS_WARN("ctrl_thrust of %d too small, clamping to 0!", ctrl_thrust_);
00278 ctrl_thrust_ = 0;
00279 }
00280
00281 publishCtrlInputMsg();
00282
00283 state_mutex_.unlock();
00284 }
00285
00286 void AsctecProc::imuCalcDataCallback(const asctec_msgs::IMUCalcDataConstPtr& imu_calcdata_msg)
00287 {
00288
00289 sensor_msgs::ImuPtr imu_msg;
00290 imu_msg = boost::make_shared<sensor_msgs::Imu>();
00291 createImuMsg (imu_calcdata_msg, imu_msg);
00292 imu_publisher_.publish(imu_msg);
00293
00294
00295 mav_msgs::HeightPtr height_msg;
00296 height_msg = boost::make_shared<mav_msgs::Height>();
00297 createHeightMsg (imu_calcdata_msg, height_msg);
00298 height_publisher_.publish(height_msg);
00299
00300
00301 mav_msgs::HeightPtr height_filtered_msg;
00302 height_filtered_msg = boost::make_shared<mav_msgs::Height>();
00303 createHeightFilteredMsg (imu_calcdata_msg, height_filtered_msg);
00304 height_filtered_publisher_.publish(height_filtered_msg);
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325 }
00326
00327 void AsctecProc::createHeightMsg(const asctec_msgs::IMUCalcDataConstPtr& imu_calcdata_msg,
00328 mav_msgs::HeightPtr& height_msg)
00329 {
00330
00331 height_msg->header.stamp = imu_calcdata_msg->header.stamp;
00332 height_msg->header.frame_id = "imu";
00333
00334 height_msg->height = imu_calcdata_msg->height_reference * asctec::ASC_TO_ROS_HEIGHT;
00335 height_msg->climb = imu_calcdata_msg->dheight_reference * asctec::ASC_TO_ROS_HEIGHT;
00336 }
00337
00338 void AsctecProc::createHeightFilteredMsg(const asctec_msgs::IMUCalcDataConstPtr& imu_calcdata_msg,
00339 mav_msgs::HeightPtr& height_filtered_msg)
00340 {
00341
00342 height_filtered_msg->header.stamp = imu_calcdata_msg->header.stamp;
00343 height_filtered_msg->header.frame_id = "imu";
00344
00345 height_filtered_msg->height = imu_calcdata_msg->height * asctec::ASC_TO_ROS_HEIGHT;
00346 height_filtered_msg->climb = imu_calcdata_msg->dheight * asctec::ASC_TO_ROS_HEIGHT;
00347 }
00348
00349 void AsctecProc::createImuMsg(const asctec_msgs::IMUCalcDataConstPtr& imu_calcdata_msg,
00350 sensor_msgs::ImuPtr& imu_msg)
00351 {
00352
00353 imu_msg->header.stamp = imu_calcdata_msg->header.stamp;
00354 imu_msg->header.frame_id = "imu";
00355
00356
00357 imu_msg->linear_acceleration.x = imu_calcdata_msg->acc_x_calib * asctec::ASC_TO_ROS_ACC * -1.0;
00358 imu_msg->linear_acceleration.y = imu_calcdata_msg->acc_y_calib * asctec::ASC_TO_ROS_ACC * -1.0;
00359 imu_msg->linear_acceleration.z = imu_calcdata_msg->acc_z_calib * asctec::ASC_TO_ROS_ACC * -1.0;
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374 imu_msg->angular_velocity.x = imu_calcdata_msg->angvel_roll * asctec::ASC_TO_ROS_ANGVEL * -1.0;
00375 imu_msg->angular_velocity.y = imu_calcdata_msg->angvel_nick * asctec::ASC_TO_ROS_ANGVEL;
00376 imu_msg->angular_velocity.z = imu_calcdata_msg->angvel_yaw * asctec::ASC_TO_ROS_ANGVEL * -1.0;
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392 btQuaternion orientation;
00393 orientation.setRPY(imu_calcdata_msg->angle_roll * asctec::ASC_TO_ROS_ANGLE * -1.0,
00394 imu_calcdata_msg->angle_nick * asctec::ASC_TO_ROS_ANGLE,
00395 imu_calcdata_msg->angle_yaw * asctec::ASC_TO_ROS_ANGLE * -1.0);
00396
00397 imu_msg->orientation.x = orientation.getX();
00398 imu_msg->orientation.y = orientation.getY();
00399 imu_msg->orientation.z = orientation.getZ();
00400 imu_msg->orientation.w = orientation.getW();
00401 }
00402
00403 void AsctecProc::startMotors()
00404 {
00405
00406
00407
00408 ROS_INFO ("Starting motors...");
00409
00410 ctrl_input_publisher_.publish(ctrl_input_toggle_msg_);
00411
00412 for (int i = 0; i < 15; ++i)
00413 {
00414 if (motors_on_) break;
00415
00416 ros::Duration(0.20).sleep();
00417 ctrl_input_publisher_.publish(ctrl_input_toggle_msg_);
00418 }
00419
00420 ctrl_input_publisher_.publish(ctrl_input_zero_msg_);
00421
00422 ROS_INFO("Motors are ON");
00423 }
00424
00425 void AsctecProc::stopMotors()
00426 {
00427
00428
00429
00430 ROS_INFO ("Stopping motors...");
00431
00432 ctrl_input_publisher_.publish(ctrl_input_toggle_msg_);
00433
00434 for (int i = 0; i < 15; ++i)
00435 {
00436 if (!motors_on_) break;
00437
00438 ros::Duration(0.20).sleep();
00439 ctrl_input_publisher_.publish(ctrl_input_toggle_msg_);
00440 }
00441
00442 ctrl_input_publisher_.publish(ctrl_input_zero_msg_);
00443
00444 ROS_INFO("Motors are OFF");
00445 }
00446
00447 void AsctecProc::assembleCtrlCommands()
00448 {
00449
00450
00451 ctrl_input_toggle_msg_ = boost::make_shared<asctec_msgs::CtrlInput>();
00452
00453 ctrl_input_toggle_msg_->thrust = 0;
00454 ctrl_input_toggle_msg_->roll = 0;
00455 ctrl_input_toggle_msg_->pitch = 0;
00456 ctrl_input_toggle_msg_->yaw = -2047;
00457 ctrl_input_toggle_msg_->ctrl = int(0b1100);
00458
00459 ctrl_input_toggle_msg_->chksum = ctrl_input_toggle_msg_->roll + ctrl_input_toggle_msg_->pitch +
00460 ctrl_input_toggle_msg_->yaw + ctrl_input_toggle_msg_->thrust +
00461 ctrl_input_toggle_msg_->ctrl - 21846;
00462
00463
00464
00465 ctrl_input_zero_msg_ = boost::make_shared<asctec_msgs::CtrlInput>();
00466
00467 ctrl_input_zero_msg_->thrust = 0;
00468 ctrl_input_zero_msg_->roll = 0;
00469 ctrl_input_zero_msg_->pitch = 0;
00470 ctrl_input_zero_msg_->yaw = 0;
00471 ctrl_input_zero_msg_->ctrl = int(0b1100);
00472
00473 ctrl_input_zero_msg_->chksum = ctrl_input_zero_msg_->roll + ctrl_input_zero_msg_->pitch +
00474 ctrl_input_zero_msg_->yaw + ctrl_input_zero_msg_->thrust +
00475 ctrl_input_zero_msg_->ctrl - 21846;
00476 }
00477
00478 void AsctecProc::publishCtrlInputMsg()
00479 {
00480 ROS_DEBUG("Publishing ctrl_input_msg");
00481
00482
00483
00484 asctec_msgs::CtrlInputPtr ctrl_input_msg;
00485 ctrl_input_msg = boost::make_shared<asctec_msgs::CtrlInput>();
00486
00487 ctrl_input_msg->thrust = ctrl_thrust_;
00488 ctrl_input_msg->roll = ctrl_roll_;
00489 ctrl_input_msg->pitch = ctrl_pitch_;
00490 ctrl_input_msg->yaw = ctrl_yaw_;
00491 ctrl_input_msg->ctrl = int(0b0000);
00492
00493 if (enable_ctrl_thrust_) ctrl_input_msg->ctrl |= 0b1000;
00494 if (enable_ctrl_yaw_) ctrl_input_msg->ctrl |= 0b0100;
00495 if (enable_ctrl_roll_) ctrl_input_msg->ctrl |= 0b0010;
00496 if (enable_ctrl_pitch_) ctrl_input_msg->ctrl |= 0b0001;
00497
00498
00499 ctrl_input_msg->chksum = ctrl_input_msg->roll + ctrl_input_msg->pitch +
00500 ctrl_input_msg->yaw + ctrl_input_msg->thrust +
00501 ctrl_input_msg->ctrl - 21846;
00502 ctrl_input_msg->header.stamp = ros::Time::now();
00503 ctrl_input_publisher_.publish(ctrl_input_msg);
00504 }
00505
00506 }