00001
00002
00003
00004
00005
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
00085 if ((int)inputBuffer.size()==options.maxInputBufferSize->getValue()) inputBuffer.pop_front();
00086 inputBuffer.push_back(newInput);
00087
00088
00089 intTime = Time(newInput.timeStamp);
00090 }
00091 scopedInputMutex.unlock();
00092
00093 boost::mutex::scoped_lock scopedMeasureMutex(newMeasureMutex);
00094 if (newMeasureReceived)
00095 {
00096
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
00108 if ((int)measureBuffer.size()==options.maxMeasureBufferSize->getValue()) measureBuffer.pop_front();
00109 measureBuffer.insert(measureBufferIndex-1,newMeasure);
00110
00111
00112 stateBuffer.erase(stateBufferIndex,stateBuffer.end());
00113
00114
00115 currentInputIndex = inputBufferIndex;
00116 nextMeasureIndex = measureBufferIndex;
00117 predTime = stateBufferIndex->timeStamp;
00118 saveTimer.reset();
00119 }
00120 }
00121 scopedMeasureMutex.unlock();
00122
00123
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):
00162 publishEstimate(internalState);
00163 return;
00164
00165 case (2):
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):
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
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
00266 void KalmanStateEstimator::prediction(StateBufferElement& state, const InputBufferElement& u, double Tpred)
00267 {
00268 double lTpred = options.lTpred->getValue();
00269
00270
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
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
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
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
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
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 }