magnetic.cpp
Go to the documentation of this file.
00001 //=================================================================================================
00002 // Copyright (c) 2011, Johannes Meyer, TU Darmstadt
00003 // All rights reserved.
00004 
00005 // Redistribution and use in source and binary forms, with or without
00006 // modification, are permitted provided that the following conditions are met:
00007 //     * Redistributions of source code must retain the above copyright
00008 //       notice, this list of conditions and the following disclaimer.
00009 //     * Redistributions in binary form must reproduce the above copyright
00010 //       notice, this list of conditions and the following disclaimer in the
00011 //       documentation and/or other materials provided with the distribution.
00012 //     * Neither the name of the Flight Systems and Automatic Control group,
00013 //       TU Darmstadt, nor the names of its contributors may be used to
00014 //       endorse or promote products derived from this software without
00015 //       specific prior written permission.
00016 
00017 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00018 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00019 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00020 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
00021 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00022 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00023 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00024 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00026 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027 //=================================================================================================
00028 
00029 #include <hector_pose_estimation/measurements/magnetic.h>
00030 #include <hector_pose_estimation/pose_estimation.h>
00031 
00032 namespace hector_pose_estimation {
00033 
00034 MagneticModel::MagneticModel()
00035   : MeasurementModel(MeasurementDimension)
00036   , declination_(0.0), inclination_(60.0 * M_PI/180.0), magnitude_(0.0)
00037 //  , C_full_(3,StateDimension)
00038 {
00039   parameters().add("stddev", stddev_, 1.0);
00040   parameters().add("declination", declination_);
00041   parameters().add("inclination", inclination_);
00042   parameters().add("magnitude", magnitude_);
00043 
00044 //  C_full_= 0.0;
00045 }
00046 
00047 MagneticModel::~MagneticModel() {}
00048 
00049 bool MagneticModel::init()
00050 {
00051   NoiseCovariance noise = 0.0;
00052   noise(1,1) = noise(2,2) = noise(3,3) = pow(stddev_, 2);
00053   this->AdditiveNoiseSigmaSet(noise);
00054 
00055   updateMagneticField();
00056   return true;
00057 }
00058 
00059 SystemStatus MagneticModel::getStatusFlags() const {
00060   return STATE_YAW;
00061 }
00062 
00063 void MagneticModel::setReference(const GlobalReference::Heading &reference_heading) {
00064   magnetic_field_reference_(1) = reference_heading.cos * magnetic_field_north_(1) - reference_heading.sin * magnetic_field_north_(2);
00065   magnetic_field_reference_(2) = reference_heading.sin * magnetic_field_north_(1) + reference_heading.cos * magnetic_field_north_(2);
00066   magnetic_field_reference_(3) = magnetic_field_north_(3);
00067 }
00068 
00069 ColumnVector MagneticModel::ExpectedValueGet() const {
00070   const double qw = x_(QUATERNION_W);
00071   const double qx = x_(QUATERNION_X);
00072   const double qy = x_(QUATERNION_Y);
00073   const double qz = x_(QUATERNION_Z);
00074 
00075   y_(1) = (qw*qw+qx*qx-qy*qy-qz*qz) * magnetic_field_reference_(1) + (2.0*qx*qy+2.0*qw*qz)     * magnetic_field_reference_(2) + (2.0*qx*qz-2.0*qw*qy)     * magnetic_field_reference_(3);
00076   y_(2) = (2.0*qx*qy-2.0*qw*qz)     * magnetic_field_reference_(1) + (qw*qw-qx*qx+qy*qy-qz*qz) * magnetic_field_reference_(2) + (2.0*qy*qz+2.0*qw*qx)     * magnetic_field_reference_(3);
00077   y_(3) = (2.0*qx*qz+2.0*qw*qy)     * magnetic_field_reference_(1) + (2.0*qy*qz-2.0*qw*qx)     * magnetic_field_reference_(2) + (qw*qw-qx*qx-qy*qy+qz*qz) * magnetic_field_reference_(3);
00078 
00079   return y_;
00080 }
00081 
00082 Matrix MagneticModel::dfGet(unsigned int i) const {
00083   if (i != 0) return Matrix();
00084 
00085   const double& qw = x_(QUATERNION_W);
00086   const double& qx = x_(QUATERNION_X);
00087   const double& qy = x_(QUATERNION_Y);
00088   const double& qz = x_(QUATERNION_Z);
00089   const double& m1 = magnetic_field_reference_(1);
00090   const double& m2 = magnetic_field_reference_(2);
00091 //  const double& m3 = magnetic_field_reference_(3);
00092 
00093 //  C_full_(1,QUATERNION_W) =  2.0*qw * m1 + 2.0*qz * m2 - 2.0*qy * m3;
00094 //  C_full_(1,QUATERNION_X) =  2.0*qx * m1 + 2.0*qy * m2 + 2.0*qz * m3;
00095 //  C_full_(1,QUATERNION_Y) = -2.0*qy * m1 + 2.0*qx * m2 - 2.0*qw * m3;
00096 //  C_full_(1,QUATERNION_Z) = -2.0*qz * m1 + 2.0*qw * m2 + 2.0*qx * m3;
00097 //  C_full_(2,QUATERNION_W) = -2.0*qz * m1 + 2.0*qw * m2 + 2.0*qx * m3;
00098 //  C_full_(2,QUATERNION_X) =  2.0*qy * m1 - 2.0*qx * m2 + 2.0*qw * m3;
00099 //  C_full_(2,QUATERNION_Y) =  2.0*qx * m1 + 2.0*qy * m2 + 2.0*qz * m3;
00100 //  C_full_(2,QUATERNION_Z) = -2.0*qw * m1 - 2.0*qz * m2 + 2.0*qy * m3;
00101 //  C_full_(3,QUATERNION_W) =  2.0*qy * m1 - 2.0*qx * m2 + 2.0*qw * m3;
00102 //  C_full_(3,QUATERNION_X) =  2.0*qz * m1 - 2.0*qw * m2 - 2.0*qx * m3;
00103 //  C_full_(3,QUATERNION_Y) =  2.0*qw * m1 + 2.0*qz * m2 - 2.0*qy * m3;
00104 //  C_full_(3,QUATERNION_Z) =  2.0*qx * m1 + 2.0*qy * m2 + 2.0*qz * m3;
00105   // return C_full_;
00106 
00107   //
00108   // Magnetic field sensor should only measure the heading, not roll/pitch:
00109   //
00110   // q = [qw qx qy qz]';
00111   // dq/dyaw * dyaw/dq = 1/2 * [-qz -qy qx qw]' * 2 * [-qz -qy qx qw] =
00112   //  [ qz*qz  qz*qy -qz*qx -qz*qw ;
00113   //    qy*qz  qy*qy -qy*qx -qy*qw ;
00114   //   -qx*qz -qx*qy  qx*qx  qx*qw ;
00115   //   -qw*qz -qw*qy  qw*qx  qw*qw ]
00116   //
00117   // C = C_full * (dq/dyaw * dyaw/dq)
00118 
00119 //  for(int i = 1; i <= 3; ++i) {
00120 //    C_(i,QUATERNION_W) =  C_full_(i,QUATERNION_W) * qz*qz + C_full_(i,QUATERNION_X) * qy*qz - C_full_(i,QUATERNION_Y) * qx*qz - C_full_(i,QUATERNION_Z) * qw*qz;
00121 //    C_(i,QUATERNION_X) =  C_full_(i,QUATERNION_W) * qz*qy + C_full_(i,QUATERNION_X) * qy*qy - C_full_(i,QUATERNION_Y) * qx*qy - C_full_(i,QUATERNION_Z) * qw*qy;
00122 //    C_(i,QUATERNION_Y) = -C_full_(i,QUATERNION_W) * qz*qx - C_full_(i,QUATERNION_X) * qy*qx + C_full_(i,QUATERNION_Y) * qx*qx + C_full_(i,QUATERNION_Z) * qw*qx;
00123 //    C_(i,QUATERNION_Z) = -C_full_(i,QUATERNION_W) * qz*qw - C_full_(i,QUATERNION_X) * qy*qw + C_full_(i,QUATERNION_Y) * qx*qw + C_full_(i,QUATERNION_Z) * qw*qw;
00124 //  }
00125 
00126   double temp1 = -m2*qw*qw + 2*m1*qw*qz - m2*qx*qx + 2*m1*qx*qy + m2*qy*qy + m2*qz*qz;
00127   double temp2 =  m1*qw*qw + 2*m2*qw*qz - m1*qx*qx - 2*m2*qx*qy + m1*qy*qy - m1*qz*qz;
00128   double temp3 =  m1*qw*qx +   m2*qw*qy + m2*qx*qz -   m1*qy*qz;
00129   C_(1,QUATERNION_W) =  2*qz*temp1;
00130   C_(1,QUATERNION_X) =  2*qy*temp1;
00131   C_(1,QUATERNION_Y) = -2*qx*temp1;
00132   C_(1,QUATERNION_Z) = -2*qw*temp1;
00133   C_(2,QUATERNION_W) =  2*qz*temp2;
00134   C_(2,QUATERNION_X) =  2*qy*temp2;
00135   C_(2,QUATERNION_Y) = -2*qx*temp2;
00136   C_(2,QUATERNION_Z) = -2*qw*temp2;
00137   C_(3,QUATERNION_W) = -4*qz*temp3;
00138   C_(3,QUATERNION_X) = -4*qy*temp3;
00139   C_(3,QUATERNION_Y) =  4*qx*temp3;
00140   C_(3,QUATERNION_Z) =  4*qw*temp3;
00141 
00142   return C_;
00143 }
00144 
00145 double MagneticModel::getMagneticHeading(const StateVector& state, const MeasurementVector &y) const {
00146   MeasurementVector y_nav;
00147   const double& qw = state(QUATERNION_W), qx = state(QUATERNION_X), qy = state(QUATERNION_Y), qz = state(QUATERNION_Z);
00148   y_nav(1) = y(1) * (qw*qw + qx*qx - qy*qy - qz*qz) + y(2) * (2*qx*qy - 2*qw*qz)             + y(3) * (2*qw*qy + 2*qx*qz);
00149   y_nav(2) = y(1) * (2*qw*qz + 2*qx*qy)             + y(2) * (qw*qw - qx*qx + qy*qy - qz*qz) + y(3) * (2*qy*qz - 2*qw*qx);
00150   double heading_nav = -atan2(2*qx*qy + 2*qw*qz, qw*qw + qx*qx - qy*qy - qz*qz);
00151 
00152   return heading_nav - (-atan2(y_nav(2), y_nav(1)));
00153 }
00154 
00155 double MagneticModel::getTrueHeading(const StateVector& state, const MeasurementVector &y) const {
00156   return getMagneticHeading(state, y) + declination_;
00157 }
00158 
00159 void MagneticModel::updateMagneticField()
00160 {
00161   double cos_inclination, sin_inclination;
00162   sincos(inclination_, &sin_inclination, &cos_inclination);
00163 
00164   double cos_declination, sin_declination;
00165   sincos(declination_, &sin_declination, &cos_declination);
00166 
00167   // return normalized magnetic field if magnitude is zero
00168   double magnitude = magnitude_;
00169   if (magnitude == 0.0) magnitude = 1.0;
00170 
00171   magnetic_field_north_(1) = magnitude * (cos_inclination * cos_declination);
00172   magnetic_field_north_(2) = magnitude * (-sin_declination);
00173   magnetic_field_north_(3) = magnitude * (-sin_inclination * cos_declination);
00174 }
00175 
00176 Magnetic::Magnetic(const std::string &name)
00177   : Measurement_<MagneticModel>(name)
00178   , auto_heading_(true)
00179   , reference_(0)
00180   , deviation_(3, 0.0)
00181 {
00182   parameters().add("auto_heading", auto_heading_);
00183   parameters().add("deviation", deviation_);
00184 }
00185 
00186 void Magnetic::onReset() {
00187   reference_ = 0;
00188 }
00189 
00190 const MagneticModel::MeasurementVector& Magnetic::getVector(const Magnetic::Update& update) {
00191   y_ = Measurement_<MagneticModel>::getVector(update) + deviation_;
00192   if (getModel()->hasMagnitude()) return y_;
00193 
00194   double c = 1.0 / y_.norm();
00195   if (isinf(c)) {
00196     y_ = MeasurementVector(0.0);
00197   } else {
00198     y_ = y_ * c;
00199   }
00200   return y_;
00201 }
00202 
00203 const MagneticModel::NoiseCovariance& Magnetic::getCovariance(const Magnetic::Update& update) {
00204   if (getModel()->hasMagnitude()) return Measurement_<MagneticModel>::getCovariance(update);
00205 
00206   R_ = Measurement_<MagneticModel>::getCovariance(update);
00207   if (update.hasCovariance()) {
00208     double c = 1.0 / Measurement_<MagneticModel>::getVector(update).norm();
00209     if (isinf(c)) {
00210       R_ = 0.0;
00211       R_(1,1) = R_(2,2) = R_(3,3) = 1.0;
00212     } else {
00213       R_ =  R_ * (c*c);
00214     }
00215   }
00216 
00217   return R_;
00218 }
00219 
00220 bool Magnetic::beforeUpdate(PoseEstimation &estimator, const Magnetic::Update &update) {
00221   // reset reference position if Magnetic has not been updated for a while
00222   if (timedout()) reference_ = 0;
00223 
00224   if (reference_ != estimator.globalReference()) {
00225     reference_ = estimator.globalReference();
00226     if (auto_heading_) reference_->setCurrentHeading(estimator, getModel()->getTrueHeading(estimator.getState(), getVector(update)));
00227   }
00228 
00229   getModel()->setReference(reference_->heading());
00230   return true;
00231 }
00232 
00233 } // namespace hector_pose_estimation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends


hector_pose_estimation_core
Author(s): Johannes Meyer
autogenerated on Mon Jul 15 2013 16:48:43