00001
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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);
00063 nh.param("imu/angular_velocity_stdev", angular_stdev, 0.02 * (M_PI / 180.0));
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
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
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
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
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
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
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
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
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
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
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
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
00328 sensor_msgs::MagneticFieldPtr magn_msg = boost::make_shared<sensor_msgs::MagneticField>();
00329
00330
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
00368 sensor_msgs::MagneticFieldPtr magn_msg = boost::make_shared<sensor_msgs::MagneticField>();
00369
00370
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 };
00405
00406 PLUGINLIB_EXPORT_CLASS(mavplugin::IMUPubPlugin, mavplugin::MavRosPlugin)
00407