imu_pub.cpp
Go to the documentation of this file.
00001 
00009 /*
00010  * Copyright 2013 Vladimir Ermakov.
00011  *
00012  * This program is free software; you can redistribute it and/or modify
00013  * it under the terms of the GNU General Public License as published by
00014  * the Free Software Foundation; either version 3 of the License, or
00015  * (at your option) any later version.
00016  *
00017  * This program is distributed in the hope that it will be useful, but
00018  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
00019  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
00020  * for more details.
00021  *
00022  * You should have received a copy of the GNU General Public License along
00023  * with this program; if not, write to the Free Software Foundation, Inc.,
00024  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00025  */
00026 
00027 #include <cmath>
00028 #include <mavros/mavros_plugin.h>
00029 #include <pluginlib/class_list_macros.h>
00030 #include <tf/transform_datatypes.h>
00031 
00032 #include <sensor_msgs/Imu.h>
00033 #include <sensor_msgs/MagneticField.h>
00034 #include <sensor_msgs/Temperature.h>
00035 #include <sensor_msgs/FluidPressure.h>
00036 #include <geometry_msgs/Vector3.h>
00037 
00038 namespace mavplugin {
00039 
00043 class IMUPubPlugin : public MavRosPlugin {
00044 public:
00045         IMUPubPlugin() :
00046                 uas(nullptr),
00047                 linear_accel_vec(),
00048                 has_hr_imu(false),
00049                 has_scaled_imu(false),
00050                 has_att_quat(false)
00051         { };
00052 
00053         void initialize(UAS &uas_,
00054                         ros::NodeHandle &nh,
00055                         diagnostic_updater::Updater &diag_updater)
00056         {
00057                 double linear_stdev, angular_stdev, orientation_stdev, mag_stdev;
00058 
00059                 uas = &uas_;
00060 
00061                 nh.param<std::string>("imu/frame_id", frame_id, "fcu");
00062                 nh.param("imu/linear_acceleration_stdev", linear_stdev, 0.0003); // check default by MPU6000 spec
00063                 nh.param("imu/angular_velocity_stdev", angular_stdev, 0.02 * (M_PI / 180.0)); // check default by MPU6000 spec
00064                 nh.param("imu/orientation_stdev", orientation_stdev, 1.0);
00065                 nh.param("imu/magnetic_stdev", mag_stdev, 0.0);
00066 
00067                 setup_covariance(linear_acceleration_cov, linear_stdev);
00068                 setup_covariance(angular_velocity_cov, angular_stdev);
00069                 setup_covariance(orientation_cov, orientation_stdev);
00070                 setup_covariance(magnetic_cov, mag_stdev);
00071                 setup_covariance(unk_orientation_cov, 0.0);
00072 
00073                 imu_pub = nh.advertise<sensor_msgs::Imu>("imu/data", 10);
00074                 magn_pub = nh.advertise<sensor_msgs::MagneticField>("imu/mag", 10);
00075                 temp_pub = nh.advertise<sensor_msgs::Temperature>("imu/temperature", 10);
00076                 press_pub = nh.advertise<sensor_msgs::FluidPressure>("imu/atm_pressure", 10);
00077                 imu_raw_pub = nh.advertise<sensor_msgs::Imu>("imu/data_raw", 10);
00078         }
00079 
00080         std::string const get_name() const {
00081                 return "IMUPub";
00082         }
00083 
00084         const message_map get_rx_handlers() {
00085                 return {
00086                         MESSAGE_HANDLER(MAVLINK_MSG_ID_ATTITUDE, &IMUPubPlugin::handle_attitude),
00087                         MESSAGE_HANDLER(MAVLINK_MSG_ID_ATTITUDE_QUATERNION, &IMUPubPlugin::handle_attitude_quaternion),
00088                         MESSAGE_HANDLER(MAVLINK_MSG_ID_HIGHRES_IMU, &IMUPubPlugin::handle_highres_imu),
00089                         MESSAGE_HANDLER(MAVLINK_MSG_ID_RAW_IMU, &IMUPubPlugin::handle_raw_imu),
00090                         MESSAGE_HANDLER(MAVLINK_MSG_ID_SCALED_IMU, &IMUPubPlugin::handle_scaled_imu),
00091                         MESSAGE_HANDLER(MAVLINK_MSG_ID_SCALED_PRESSURE, &IMUPubPlugin::handle_scaled_pressure),
00092                 };
00093         }
00094 
00095 private:
00096         std::string frame_id;
00097         UAS *uas;
00098 
00099         ros::Publisher imu_pub;
00100         ros::Publisher imu_raw_pub;
00101         ros::Publisher magn_pub;
00102         ros::Publisher temp_pub;
00103         ros::Publisher press_pub;
00104 
00105         bool has_hr_imu;
00106         bool has_scaled_imu;
00107         bool has_att_quat;
00108         geometry_msgs::Vector3 linear_accel_vec;
00109         boost::array<double, 9> linear_acceleration_cov;
00110         boost::array<double, 9> angular_velocity_cov;
00111         boost::array<double, 9> orientation_cov;
00112         boost::array<double, 9> unk_orientation_cov;
00113         boost::array<double, 9> magnetic_cov;
00114 
00115         static constexpr double GAUSS_TO_TESLA = 1.0e-4;
00116         static constexpr double MILLIT_TO_TESLA = 1000.0;
00117         static constexpr double MILLIRS_TO_RADSEC = 1.0e-3;
00118         static constexpr double MILLIG_TO_MS2 = 9.80665 / 1000.0;
00119         static constexpr double MILLIBAR_TO_PASCAL = 1.0e2;
00120 
00121         /* -*- helpers -*- */
00122 
00123         void setup_covariance(boost::array<double, 9> &cov, double stdev) {
00124                 std::fill(cov.begin(), cov.end(), 0.0);
00125                 if (stdev == 0.0)
00126                         cov[0] = -1.0;
00127                 else {
00128                         cov[0+0] = cov[3+1] = cov[6+2] = std::pow(stdev, 2);
00129                 }
00130         }
00131 
00132         void uas_store_attitude(tf::Quaternion &orientation,
00133                         geometry_msgs::Vector3 &gyro_vec,
00134                         geometry_msgs::Vector3 &acc_vec)
00135         {
00136                 tf::Vector3 angular_velocity;
00137                 tf::Vector3 linear_acceleration;
00138                 tf::vector3MsgToTF(gyro_vec, angular_velocity);
00139                 tf::vector3MsgToTF(acc_vec, linear_acceleration);
00140 
00141                 uas->set_attitude_orientation(orientation);
00142                 uas->set_attitude_angular_velocity(angular_velocity);
00143                 uas->set_attitude_linear_acceleration(linear_acceleration);
00144         }
00145 
00147         void fill_imu_msg_attitude(sensor_msgs::ImuPtr &imu_msg,
00148                         tf::Quaternion &orientation,
00149                         double xg, double yg, double zg)
00150         {
00151                 tf::quaternionTFToMsg(orientation, imu_msg->orientation);
00152 
00153                 imu_msg->angular_velocity.x = xg;
00154                 imu_msg->angular_velocity.y = yg;
00155                 imu_msg->angular_velocity.z = zg;
00156 
00157                 // vector from HIGHRES_IMU or RAW_IMU
00158                 imu_msg->linear_acceleration = linear_accel_vec;
00159 
00160                 imu_msg->orientation_covariance = orientation_cov;
00161                 imu_msg->angular_velocity_covariance = angular_velocity_cov;
00162                 imu_msg->linear_acceleration_covariance = linear_acceleration_cov;
00163         }
00164 
00166         void fill_imu_msg_raw(sensor_msgs::ImuPtr &imu_msg,
00167                         double xg, double yg, double zg,
00168                         double xa, double ya, double za)
00169         {
00170                 imu_msg->angular_velocity.x = xg;
00171                 imu_msg->angular_velocity.y = yg;
00172                 imu_msg->angular_velocity.z = zg;
00173 
00174                 imu_msg->linear_acceleration.x = xa;
00175                 imu_msg->linear_acceleration.y = ya;
00176                 imu_msg->linear_acceleration.z = za;
00177                 linear_accel_vec = imu_msg->linear_acceleration;
00178 
00179                 imu_msg->orientation_covariance = unk_orientation_cov;
00180                 imu_msg->angular_velocity_covariance = angular_velocity_cov;
00181                 imu_msg->linear_acceleration_covariance = linear_acceleration_cov;
00182         }
00183 
00184         /* -*- message handlers -*- */
00185 
00186         void handle_attitude(const mavlink_message_t *msg, uint8_t sysid, uint8_t compid) {
00187                 if (has_att_quat)
00188                         return;
00189 
00190                 mavlink_attitude_t att;
00191                 mavlink_msg_attitude_decode(msg, &att);
00192 
00193                 sensor_msgs::ImuPtr imu_msg = boost::make_shared<sensor_msgs::Imu>();
00194 
00195                 // NED -> ENU (body-fixed)
00196                 tf::Quaternion orientation = tf::createQuaternionFromRPY(
00197                                 att.roll, -att.pitch, -att.yaw);
00198 
00199                 fill_imu_msg_attitude(imu_msg, orientation,
00200                                 att.rollspeed,
00201                                 -att.pitchspeed,
00202                                 -att.yawspeed);
00203 
00204                 uas_store_attitude(orientation,
00205                                 imu_msg->angular_velocity,
00206                                 imu_msg->linear_acceleration);
00207 
00208                 // publish data
00209                 imu_msg->header.frame_id = frame_id;
00210                 imu_msg->header.stamp = ros::Time::now();
00211                 imu_pub.publish(imu_msg);
00212         }
00213 
00214         // almost the same as handle_attitude(), but for ATTITUDE_QUATERNION
00215         void handle_attitude_quaternion(const mavlink_message_t *msg, uint8_t sysid, uint8_t compid) {
00216                 mavlink_attitude_quaternion_t att_q;
00217                 mavlink_msg_attitude_quaternion_decode(msg, &att_q);
00218 
00219                 ROS_INFO_COND_NAMED(!has_att_quat, "imu", "Attitude quaternion IMU detected!");
00220                 has_att_quat = true;
00221 
00222                 sensor_msgs::ImuPtr imu_msg = boost::make_shared<sensor_msgs::Imu>();
00223 
00224                 // PX4 NED (w x y z) -> ROS ENU (x -y -z w) (body-fixed)
00225                 tf::Quaternion orientation(att_q.q2, -att_q.q3, -att_q.q4, att_q.q1);
00226 
00227                 fill_imu_msg_attitude(imu_msg, orientation,
00228                                 att_q.rollspeed,
00229                                 -att_q.pitchspeed,
00230                                 -att_q.yawspeed);
00231 
00232                 uas_store_attitude(orientation,
00233                                 imu_msg->angular_velocity,
00234                                 imu_msg->linear_acceleration);
00235 
00236                 // publish data
00237                 imu_msg->header.frame_id = frame_id;
00238                 imu_msg->header.stamp = ros::Time::now();
00239                 imu_pub.publish(imu_msg);
00240         }
00241 
00242         void handle_highres_imu(const mavlink_message_t *msg, uint8_t sysid, uint8_t compid) {
00243                 mavlink_highres_imu_t imu_hr;
00244                 mavlink_msg_highres_imu_decode(msg, &imu_hr);
00245 
00246                 ROS_INFO_COND_NAMED(!has_hr_imu, "imu", "High resolution IMU detected!");
00247                 has_hr_imu = true;
00248 
00249                 std_msgs::Header header;
00250                 header.stamp = ros::Time::now();
00251                 header.frame_id = frame_id;
00252 
00253                 /* imu/data_raw filled by HR IMU */
00254                 if (imu_hr.fields_updated & ((7<<3)|(7<<0))) {
00255                         sensor_msgs::ImuPtr imu_msg = boost::make_shared<sensor_msgs::Imu>();
00256 
00257                         fill_imu_msg_raw(imu_msg,
00258                                         imu_hr.xgyro, -imu_hr.ygyro, -imu_hr.zgyro,
00259                                         imu_hr.xacc, -imu_hr.yacc, -imu_hr.zacc);
00260 
00261                         imu_msg->header = header;
00262                         imu_raw_pub.publish(imu_msg);
00263                 }
00264 
00265                 if (imu_hr.fields_updated & (7<<6)) {
00266                         sensor_msgs::MagneticFieldPtr magn_msg = boost::make_shared<sensor_msgs::MagneticField>();
00267 
00268                         // Convert from local NED plane to ENU
00269                         magn_msg->magnetic_field.x = imu_hr.ymag * GAUSS_TO_TESLA;
00270                         magn_msg->magnetic_field.y = imu_hr.xmag * GAUSS_TO_TESLA;
00271                         magn_msg->magnetic_field.z = -imu_hr.zmag * GAUSS_TO_TESLA;
00272 
00273                         magn_msg->magnetic_field_covariance = magnetic_cov;
00274 
00275                         magn_msg->header = header;
00276                         magn_pub.publish(magn_msg);
00277                 }
00278 
00279                 if (imu_hr.fields_updated & (1<<9)) {
00280                         sensor_msgs::FluidPressurePtr atmp_msg = boost::make_shared<sensor_msgs::FluidPressure>();
00281 
00282                         atmp_msg->fluid_pressure = imu_hr.abs_pressure * MILLIBAR_TO_PASCAL;
00283                         atmp_msg->header = header;
00284                         press_pub.publish(atmp_msg);
00285                 }
00286 
00287                 if (imu_hr.fields_updated & (1<<12)) {
00288                         sensor_msgs::TemperaturePtr temp_msg = boost::make_shared<sensor_msgs::Temperature>();
00289 
00290                         temp_msg->temperature = imu_hr.temperature;
00291                         temp_msg->header = header;
00292                         temp_pub.publish(temp_msg);
00293                 }
00294         }
00295 
00296         void handle_raw_imu(const mavlink_message_t *msg, uint8_t sysid, uint8_t compid) {
00297                 if (has_hr_imu || has_scaled_imu)
00298                         return;
00299 
00300                 sensor_msgs::ImuPtr imu_msg = boost::make_shared<sensor_msgs::Imu>();
00301                 mavlink_raw_imu_t imu_raw;
00302                 mavlink_msg_raw_imu_decode(msg, &imu_raw);
00303 
00304                 std_msgs::Header header;
00305                 header.stamp = ros::Time::now();
00306                 header.frame_id = frame_id;
00307 
00308                 /* NOTE: APM send SCALED_IMU data as RAW_IMU */
00309                 fill_imu_msg_raw(imu_msg,
00310                                 imu_raw.xgyro * MILLIRS_TO_RADSEC,
00311                                 -imu_raw.ygyro * MILLIRS_TO_RADSEC,
00312                                 -imu_raw.zgyro * MILLIRS_TO_RADSEC,
00313                                 imu_raw.xacc * MILLIG_TO_MS2,
00314                                 -imu_raw.yacc * MILLIG_TO_MS2,
00315                                 -imu_raw.zacc * MILLIG_TO_MS2);
00316 
00317                 if (!uas->is_ardupilotmega()) {
00318                         ROS_WARN_THROTTLE_NAMED(60, "imu", "RAW_IMU: linear acceleration known on APM only");
00319                         linear_accel_vec.x = 0.0;
00320                         linear_accel_vec.y = 0.0;
00321                         linear_accel_vec.z = 0.0;
00322                 }
00323 
00324                 imu_msg->header = header;
00325                 imu_raw_pub.publish(imu_msg);
00326 
00327                 /* -*- magnetic vector -*- */
00328                 sensor_msgs::MagneticFieldPtr magn_msg = boost::make_shared<sensor_msgs::MagneticField>();
00329 
00330                 // Convert from local NED plane to ENU
00331                 magn_msg->magnetic_field.x = imu_raw.ymag * MILLIT_TO_TESLA;
00332                 magn_msg->magnetic_field.y = imu_raw.xmag * MILLIT_TO_TESLA;
00333                 magn_msg->magnetic_field.z = -imu_raw.zmag * MILLIT_TO_TESLA;
00334 
00335                 magn_msg->magnetic_field_covariance = magnetic_cov;
00336 
00337                 magn_msg->header = header;
00338                 magn_pub.publish(magn_msg);
00339         }
00340 
00341         void handle_scaled_imu(const mavlink_message_t *msg, uint8_t sysid, uint8_t compid) {
00342                 if (has_hr_imu)
00343                         return;
00344 
00345                 ROS_INFO_COND_NAMED(!has_scaled_imu, "imu", "Scaled IMU message used.");
00346                 has_scaled_imu = true;
00347 
00348                 sensor_msgs::ImuPtr imu_msg = boost::make_shared<sensor_msgs::Imu>();
00349                 mavlink_scaled_imu_t imu_raw;
00350                 mavlink_msg_scaled_imu_decode(msg, &imu_raw);
00351 
00352                 std_msgs::Header header;
00353                 header.stamp = ros::Time::now();
00354                 header.frame_id = frame_id;
00355 
00356                 fill_imu_msg_raw(imu_msg,
00357                                 imu_raw.xgyro * MILLIRS_TO_RADSEC,
00358                                 -imu_raw.ygyro * MILLIRS_TO_RADSEC,
00359                                 -imu_raw.zgyro * MILLIRS_TO_RADSEC,
00360                                 imu_raw.xacc * MILLIG_TO_MS2,
00361                                 -imu_raw.yacc * MILLIG_TO_MS2,
00362                                 -imu_raw.zacc * MILLIG_TO_MS2);
00363 
00364                 imu_msg->header = header;
00365                 imu_raw_pub.publish(imu_msg);
00366 
00367                 /* -*- magnetic vector -*- */
00368                 sensor_msgs::MagneticFieldPtr magn_msg = boost::make_shared<sensor_msgs::MagneticField>();
00369 
00370                 // Convert from local NED plane to ENU
00371                 magn_msg->magnetic_field.x = imu_raw.ymag * MILLIT_TO_TESLA;
00372                 magn_msg->magnetic_field.y = imu_raw.xmag * MILLIT_TO_TESLA;
00373                 magn_msg->magnetic_field.z = -imu_raw.zmag * MILLIT_TO_TESLA;
00374 
00375                 magn_msg->magnetic_field_covariance = magnetic_cov;
00376 
00377                 magn_msg->header = header;
00378                 magn_pub.publish(magn_msg);
00379         }
00380 
00381         void handle_scaled_pressure(const mavlink_message_t *msg, uint8_t sysid, uint8_t compid) {
00382                 if (has_hr_imu)
00383                         return;
00384 
00385                 mavlink_scaled_pressure_t press;
00386                 mavlink_msg_scaled_pressure_decode(msg, &press);
00387 
00388                 std_msgs::Header header;
00389                 header.stamp = ros::Time::now();
00390                 header.frame_id = frame_id;
00391 
00392                 sensor_msgs::TemperaturePtr temp_msg = boost::make_shared<sensor_msgs::Temperature>();
00393                 temp_msg->temperature = press.temperature / 100.0;
00394                 temp_msg->header = header;
00395                 temp_pub.publish(temp_msg);
00396 
00397                 sensor_msgs::FluidPressurePtr atmp_msg = boost::make_shared<sensor_msgs::FluidPressure>();
00398                 atmp_msg->fluid_pressure = press.press_abs * 100.0;
00399                 atmp_msg->header = header;
00400                 press_pub.publish(atmp_msg);
00401         }
00402 };
00403 
00404 }; // namespace mavplugin
00405 
00406 PLUGINLIB_EXPORT_CLASS(mavplugin::IMUPubPlugin, mavplugin::MavRosPlugin)
00407 


mavros
Author(s): Vladimir Ermakov
autogenerated on Wed Aug 26 2015 12:29:13