KalmanStateEstimator.cpp
Go to the documentation of this file.
00001 /*
00002  * ServoInterface.cpp
00003  *
00004  *  Created on: Jun 19, 2012
00005  *      Author: rspica
00006  */
00007 #include <math.h>
00008 #include <limits>
00009 #include <StateEstimators/KalmanStateEstimator.hpp>
00010 
00011 #include <tk_state/StateEstimatorController.hpp>
00012 
00013 #include <telekyb_base/ROS.hpp>
00014 
00015 #include <telekyb_msgs/TKState.h>
00016 #include <telekyb_defines/physic_defines.hpp>
00017 
00018 PLUGINLIB_DECLARE_CLASS(tk_state, KalmanStateEstimator, telekyb_state::KalmanStateEstimator, TELEKYB_NAMESPACE::StateEstimator);
00019 
00020 namespace telekyb_state {
00021 
00022 KalmanStateEstimatorOptions::KalmanStateEstimatorOptions()
00023         : OptionContainer("Kalman")
00024 {
00025         imuTopic = addOption<std::string>("imuTopic", "Imu data topic name", "TKImu", false, true);
00026         viconTopic = addOption<std::string>("viconTopic", "Vicon data topic name", "TKVicon", false, true);
00027         stateTopic = addOption<std::string>("stateTopic", "Topic on which the state must be published", "TKKalman", false, true);
00028 
00029         Eigen::Matrix<double,6,6> rt;
00030         rt.Zero();
00031         imuCov = addOption<Eigen::Matrix<double,6,6> >("imuCov", "IMU noise covariance matrix", rt, false, true);
00032 
00033         imuAccBias = addOption<Eigen::Vector3d>("imuAccBias", "IMU accelerometer bias", Eigen::Vector3d::Zero(), false, true);
00034         imuGyrBias = addOption<Eigen::Vector3d>("imuGyrBias", "IMU gyroscope bias", Eigen::Vector3d::Zero(), false, true);
00035 
00036         Eigen::Matrix<double,6,6> qt;
00037         qt.Zero();
00038         vicCov = addOption<Eigen::Matrix<double,6,6> >("vicCov", "Vicon noise covariance matrix", qt, false, true);
00039 
00040         Eigen::Matrix<double,9,9> dt;
00041         dt.Zero();
00042         discCov = addOption<Eigen::Matrix<double,9,9> >("discCov", "Discretization noise covariance matrix", dt, false, true);
00043 
00044         Eigen::Matrix<double,9,9> initC;
00045         initC.Zero();
00046         initC.block<3,3>(0,0) = qt.block<3,3>(0,0);
00047         initC.block<3,3>(3,3) = 10*qt.block<3,3>(0,0);
00048         initC.block<3,3>(6,6) = qt.block<3,3>(3,3);
00049         initStateCov = addOption<Eigen::Matrix<double,9,9> >("initStateCov", "Initial state covariance estimate", initC, false, true);
00050 
00051         vicPosition = addOption<Eigen::Vector3d>("initState", "Initial estimate for Vicon position", Eigen::Vector3d(0.0,0.0,0.0), false, true);
00052         vicOrientation = addOption<Eigen::Quaterniond>("vicOrientation", "Initial estimate for Vicon orientation", Eigen::Quaterniond(1.0,0.0,0.0,0.0), false, true);
00053 
00054         predStep = addOption<double>("predStep", "Prediction time step", 1e-3, false, true);
00055         minStep = addOption<double>("minStep", "Minimum prediction time step", 1e-3, false, true);
00056         saveStep = addOption<double>("minStep", "Time step for saving states", 1e-3, false, true);
00057 
00058         lTpred = addOption<double>("lTpred", "Multiplier for quaternion prediction normalization", 0.8, false, true);
00059 
00060         maxStateBufferSize = addOption<int>("maxStateBufferSize", "Maximum number of states to be saved in the state buffer", 200, false, true);
00061         maxMeasureBufferSize = addOption<int>("maxMeasureBufferSize", "Maximum number of measures to be saved in the measure buffer", 200, false, true);
00062         maxInputBufferSize = addOption<int>("maxInputBufferSize", "Maximum number of inputs to be saved in the input buffer", 200, false, true);
00063 
00064 }
00065 
00066 void KalmanStateEstimator::initialize()
00067 {
00068         isInitialized = false;
00069         isInitializedLinVel = false;
00070         isInitializedPose = false;
00071         isInitializedAngVel = false;
00072 
00073         newMeasureReceived = false;
00074         newInputReceived = false;
00075 
00076         nodeHandle = ROSModule::Instance().getMainNodeHandle();
00077 }
00078 
00079 void KalmanStateEstimator::core()
00080 {
00081         boost::mutex::scoped_lock scopedInputMutex(newInputMutex);
00082         if (newInputReceived)
00083         {
00084                 //delete first input if the buffer is too big
00085                 if ((int)inputBuffer.size()==options.maxInputBufferSize->getValue()) inputBuffer.pop_front();
00086                 inputBuffer.push_back(newInput);
00087 
00088                 //syncronize internal time with the IMU
00089                 intTime = Time(newInput.timeStamp);
00090         }
00091         scopedInputMutex.unlock();
00092 
00093         boost::mutex::scoped_lock scopedMeasureMutex(newMeasureMutex);
00094         if (newMeasureReceived)
00095         {
00096                 //Check if the current measure is newer than the oldest saved state.
00097                 std::deque<StateBufferElement, Eigen::aligned_allocator<StateBufferElement> >::iterator stateBufferIndex;
00098                 std::deque<InputBufferElement, Eigen::aligned_allocator<InputBufferElement> >::iterator inputBufferIndex;
00099                 std::deque<MeasureBufferElement, Eigen::aligned_allocator<MeasureBufferElement> >::iterator measureBufferIndex;
00100 
00101                 if (((stateBufferIndex = searchInBuffer<StateBufferElement>(stateBuffer,newMeasure.timeStamp)) < stateBuffer.begin()) ||
00102                         ((inputBufferIndex = searchInBuffer<InputBufferElement>(inputBuffer,newMeasure.timeStamp)) < inputBuffer.begin()) ||
00103                         ((measureBufferIndex = searchInBuffer<MeasureBufferElement>(measureBuffer,newMeasure.timeStamp)) < measureBuffer.begin()))
00104                 {
00105                         ROS_WARN("A measure has been neglected because it was too old. Consider increasing the size of the state and input buffers");
00106                 } else {
00107                         // add measure to the buffer (delete oldest entry if the bus is too big)
00108                         if ((int)measureBuffer.size()==options.maxMeasureBufferSize->getValue()) measureBuffer.pop_front();
00109                         measureBuffer.insert(measureBufferIndex-1,newMeasure);
00110 
00111                         // Delete newer states from buffer (must be recomputed)
00112                         stateBuffer.erase(stateBufferIndex,stateBuffer.end());
00113 
00114                         // set filter position
00115                         currentInputIndex = inputBufferIndex;
00116                         nextMeasureIndex = measureBufferIndex;
00117                         predTime = stateBufferIndex->timeStamp;
00118                         saveTimer.reset();
00119                 }
00120         }
00121         scopedMeasureMutex.unlock();
00122 
00123         // wait until initialization is completed
00124         if (!isInitialized) return;
00125 
00126 
00127         double nextMeasureTime, nextInputTime, step;
00128         if (nextMeasureIndex > measureBuffer.end())
00129         {
00130                 nextMeasureTime = INFINITY;
00131         } else {
00132                 nextMeasureTime = nextMeasureIndex->timeStamp;
00133         }
00134 
00135         if (currentInputIndex >= inputBuffer.end())
00136         {
00137                 nextInputTime = INFINITY;
00138         } else {
00139                 nextInputTime = (currentInputIndex+1)->timeStamp;
00140         }
00141 
00142         while (true)
00143         {
00144                 int condition = tools.min(Eigen::Vector4d(options.predStep->getValue(),
00145                                                                                                         intTime.toDSec()-predTime,
00146                                                                                                         nextInputTime-predTime,
00147                                                                                                         nextMeasureTime-predTime), step);
00148                 if (step>=options.minStep->getValue())
00149                 {
00150                         prediction(internalState,*currentInputIndex,step);
00151                 }
00152                 predTime += step;
00153                 if (saveTimer.getElapsed() >= options.saveStep->getValue())
00154                 {
00155                         stateBuffer.push_back(internalState);
00156                         saveTimer.reset();
00157                 }
00158 
00159                 switch (condition)
00160                 {
00161                         case (1): //prediction is complete
00162                                 publishEstimate(internalState);
00163                                 return;
00164 
00165                         case (2): //input must be changed
00166                                 currentInputIndex++;
00167                                 if (currentInputIndex == inputBuffer.end())
00168                                 {
00169                                         nextInputTime = INFINITY;
00170                                 } else {
00171                                         nextInputTime = (currentInputIndex+1)->timeStamp;
00172                                 }
00173                                 break;
00174 
00175                         case (3): //update is required
00176                                 viconHanler.update(internalState, *nextMeasureIndex);
00177                                 nextMeasureIndex++;
00178                                 if (nextMeasureIndex == measureBuffer.end())
00179                                         {
00180                                                 nextMeasureTime = INFINITY;
00181                                         } else {
00182                                                 nextMeasureTime = (nextMeasureIndex)->timeStamp;
00183                                         }
00184                                 break;
00185                         default:
00186                                 ROS_ERROR("Unexpected condition");
00187                                 break;
00188                 }
00189         }
00190 
00191 
00192 }
00193 
00194 void KalmanStateEstimator::publishEstimate(const StateBufferElement & estimate)
00195 {
00196         statePub.publish(estimate.state);
00197         return;
00198 }
00199 
00200 
00201 void KalmanStateEstimator::imuCallback(const sensor_msgs::Imu::ConstPtr& msg)
00202 {
00203         boost::mutex::scoped_lock scopedLockMutex(newInputMutex);
00204         //save the new input in the buffer
00205         newInput.timeStamp = msg->header.stamp.sec;
00206         newInput.input = *msg;
00207         newInputReceived = true;
00208 
00209         if (!isInitialized)
00210         {
00211                 if (!isInitializedAngVel)
00212                 {
00213                         internalState.state.twist.angular = msg->angular_velocity;
00214                         isInitializedAngVel = true;
00215                 }
00216                 if (isInitializedLinVel)
00217                 {
00218                         internalState.covariance = options.initStateCov->getValue();
00219                         isInitialized = true;
00220                 }
00221         }
00222 
00223         scopedLockMutex.unlock();
00224 }
00225 
00226 
00227 void KalmanStateEstimator::viconCallback(const geometry_msgs::TransformStamped::ConstPtr& msg)
00228 {
00229         boost::mutex::scoped_lock scopedLockMutex(newMeasureMutex);
00230         MeasureBufferElement measure;
00231         newMeasure.timeStamp = msg->header.stamp.sec;
00232         newMeasure.measure = *msg;
00233         newMeasureReceived = true;
00234         if(!isInitialized)
00235         {
00236                 if (!isInitializedLinVel)
00237                 {
00238                         if(!isInitializedPose)
00239                         {
00240                                 internalState.state.pose.position.x = msg->transform.translation.x;
00241                                 internalState.state.pose.position.y = msg->transform.translation.y;
00242                                 internalState.state.pose.position.z = msg->transform.translation.z;
00243 
00244                                 internalState.state.pose.orientation.w = msg->transform.rotation.w;
00245                                 internalState.state.pose.orientation.x = msg->transform.rotation.x;
00246                                 internalState.state.pose.orientation.y = msg->transform.rotation.y;
00247                                 internalState.state.pose.orientation.z = msg->transform.rotation.z;
00248 
00249                                 internalState.timeStamp = msg->header.stamp.toSec();
00250                                 internalState.state.header.stamp.fromSec(internalState.timeStamp);
00251                                 isInitializedPose = true;
00252                         } else {
00253                                 internalState.state.twist.linear.x = (msg->transform.translation.x - internalState.state.pose.position.x)/(msg->header.stamp.toSec()-internalState.timeStamp);
00254                                 internalState.state.twist.linear.y = (msg->transform.translation.y - internalState.state.pose.position.y)/(msg->header.stamp.toSec()-internalState.timeStamp);
00255                                 internalState.state.twist.linear.z = (msg->transform.translation.z - internalState.state.pose.position.z)/(msg->header.stamp.toSec()-internalState.timeStamp);
00256                                 isInitializedLinVel = true;
00257                         }
00258                 } else if (isInitializedAngVel)
00259                         isInitialized = true;
00260         }
00261 
00262         scopedLockMutex.unlock();
00263 }
00264 
00265 // Prediction function ====================================================
00266 void KalmanStateEstimator::prediction(StateBufferElement& state, const InputBufferElement& u, double Tpred)
00267 {
00268         double lTpred = options.lTpred->getValue();
00269 
00270         //read the state
00271         Eigen::Vector3d  r(state.state.pose.position.x,state.state.pose.position.y,state.state.pose.position.z);
00272         Eigen::Vector3d dr(state.state.twist.linear.x,state.state.twist.linear.y,state.state.twist.linear.z);
00273         Eigen::Quaterniond q(state.state.pose.orientation.w,state.state.pose.orientation.x,state.state.pose.orientation.y,state.state.pose.orientation.z);
00274 
00275         //read input commands
00276         Eigen::Vector3d w(u.input.angular_velocity.x,u.input.angular_velocity.y,u.input.angular_velocity.z);
00277         Eigen::Vector3d a(u.input.linear_acceleration.x,u.input.linear_acceleration.y,u.input.linear_acceleration.z);
00278 
00279         w -= options.imuGyrBias->getValue();
00280         a -= options.imuAccBias->getValue();
00281 
00282         //compute coefficients
00283         Eigen::Matrix4d qqT;
00284         qqT(0) = q.w()*q.w();
00285         qqT.block<3,3>(1,1) = q.vec()*q.vec().transpose();
00286         qqT.block<3,1>(0,1) = q.w()*q.vec();
00287         qqT.block<1,3>(1,0) = qqT.block<3,1>(0,1).transpose();
00288         double qTq = qqT.trace();
00289 
00290         double s = .5*w.norm()*Tpred;
00291 
00292         double sss,f3;
00293         if (abs(s)<std::numeric_limits<double>::epsilon())
00294         {
00295                 sss = 1;
00296                 f3 = -1/3*pow(.5*Tpred,3);
00297         } else {
00298                 sss = sin(s)/s;
00299                 f3 = pow(.5*Tpred,3)*(cos(s)-sss)/pow(s,2);
00300         }
00301 
00302         double k = 1-qTq;
00303         double f1 = cos(s)+lTpred*k;
00304         double f2 = .5*Tpred*sss;
00305 
00306         r += dr*Tpred;
00307         dr += (q*a-Eigen::Vector3d(0,0,GRAVITY))*Tpred;
00308         q = tools.toQuaternion((Eigen::Vector4d)(f1*tools.toVector(q) + f2*tools.toVector(Eigen::Quaterniond(0.0,w(1),w(2),w(3))*q)));
00309 
00310         state.state.pose.position.x = r(0);
00311         state.state.pose.position.y = r(1);
00312         state.state.pose.position.z = r(2);
00313 
00314         state.state.twist.linear.x = dr(0);
00315         state.state.twist.linear.y = dr(1);
00316         state.state.twist.linear.z = dr(2);
00317 
00318         state.state.pose.orientation.w = q.w();
00319         state.state.pose.orientation.x = q.vec()(0);
00320         state.state.pose.orientation.y = q.vec()(1);
00321         state.state.pose.orientation.z = q.vec()(2);
00322 
00323         state.state.twist.angular.x = w(0);
00324         state.state.twist.angular.y = w(1);
00325         state.state.twist.angular.z = w(2);
00326 
00327         //Compute state-transition matrix
00328         Eigen::Matrix<double, 9, 9> G;
00329         G.Zero();
00330 
00331         G.block<3,3>(0,0).Identity();
00332         G.block<3,3>(0,3) = Tpred*Eigen::Matrix3d::Identity();
00333 
00334         G.block<3,3>(3,3).Identity();
00335         G.block<3,3>(3,6) = Tpred*tools.gamma(q,a)*tools.jacqp(q);
00336 
00337         Eigen::Matrix4d jacqq;
00338         jacqq = f1*Eigen::Matrix4d::Identity() + f2*tools.qLeft(Eigen::Quaterniond(0,w(0),w(1),w(2))) - 2*lTpred*qqT;
00339         G.block<3,3>(6,6) = tools.jacpq(q)*jacqq*tools.jacqp(q);
00340 
00341         //Compute noise matrix
00342 
00343         Eigen::Matrix<double, 4, 3> T;
00344         T = tools.matW(q)*(f2*Eigen::Matrix3d::Identity()+f3*(w*w.transpose()))-.5*Tpred*f2*tools.toVector(q)*w.transpose();
00345 
00346         Eigen::Matrix<double, 9, 6> F;
00347         F <<    Eigen::Matrix3d::Zero(),        Eigen::Matrix3d::Zero(),
00348                         Eigen::Matrix3d::Zero(), Tpred*q.toRotationMatrix(),
00349                                    tools.jacpq(q)*T,    Eigen::Matrix3d::Zero();
00350 
00351         //Compute covariance prediction
00352         state.covariance = G*state.covariance*G.transpose() + (F*options.imuCov->getValue()*F.transpose() + options.discCov->getValue())*Tpred;
00353 
00354         state.timeStamp = state.state.header.stamp.toSec() + Tpred;
00355         state.state.header.stamp.fromSec(state.timeStamp);
00356 }
00357 
00358 
00359 void KalmanStateEstimator::willBecomeActive()
00360 {
00361         imuSub = nodeHandle.subscribe(options.imuTopic->getValue(),1, &KalmanStateEstimator::imuCallback, this);
00362         vicSub = nodeHandle.subscribe(options.viconTopic->getValue(),1, &KalmanStateEstimator::viconCallback, this);
00363         statePub = nodeHandle.advertise<telekyb_msgs::TKState>(options.stateTopic->getValue(),1);
00364 }
00365 
00366 
00367 void KalmanStateEstimator::willBecomeInActive()
00368 {
00369         imuSub.shutdown();
00370         vicSub.shutdown();
00371 }
00372 
00373 void KalmanStateEstimator::destroy(){}
00374 
00375 std::string KalmanStateEstimator::getName() const
00376 {
00377         return options.viconTopic->getValue();
00378 }
00379 
00380 } /* namespace telekyb_state */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends


tk_state
Author(s): Dr. Antonio Franchi and Martin Riedel
autogenerated on Mon Nov 11 2013 11:13:03