ComplementaryStateEstimator.cpp
Go to the documentation of this file.
00001 /*
00002  * ComplementaryStateEstimator.cpp
00003  *
00004  *  Created on: Jul 11, 2012
00005  *      Author: rspica
00006  */
00007 
00008 #include <StateEstimators/ComplementaryFilter/ComplementaryStateEstimator.hpp>
00009 #include <tk_state/StateEstimatorController.hpp>
00010 #include <telekyb_defines/physic_defines.hpp>
00011 
00012 #include <telekyb_base/ROS.hpp>
00013 #include <telekyb_msgs/TKState.h>
00014 #include <geometry_msgs/Vector3Stamped.h>
00015 
00016 #include <boost/numeric/odeint.hpp>
00017 
00018 #include <cmath>
00019 
00020 PLUGINLIB_DECLARE_CLASS(tk_state, ComplementaryStateEstimator, telekyb_state::ComplementaryStateEstimator, TELEKYB_NAMESPACE::StateEstimator);
00021 
00022 namespace telekyb_state {
00023 
00024 ComplementaryStateEstimatorOptions::ComplementaryStateEstimatorOptions()
00025         : OptionContainer("ComplementaryStateEstimator")
00026 {
00027         tViconSeTopicName = addOption<std::string>("tViconSeTopicName","TopicName of Vicon Sensor.","undef",true,true);
00028         tImuSeTopicName = addOption<std::string>("tImuSeTopicName","TopicName of Imu Sensor.","undef",true,true);
00029         tViconRepubTopicName = addOption<std::string>("tViconRepubTopicName","TopicName for Vicon republishing.","undef",true,true);
00030 
00031         imuAccBias = addOption<Eigen::Vector3d>("imuAccBias","Imu accelerometer bias", Eigen::Vector3d::Zero(), false, true);
00032         imuGyrBias = addOption<Eigen::Vector3d>("imuGyrBias","Imu gyroscope bias", Eigen::Vector3d::Zero(), false, true);
00033         vicPosition = addOption<Eigen::Vector3d>("vicPosition","Position of the Vicon frame in the IMU frame", Eigen::Vector3d::Zero(), false, true);
00034         vicOrientation = addOption<Eigen::Vector2d>("vicOrientation","Orientation of the Vicon frame w.r.t. the IMU frame (roll and pitch)", Eigen::Vector2d::Zero(), false, true);
00035         worldGravity = addOption<Eigen::Vector3d>("worldGravity","Gravity vector in the world frame", Eigen::Vector3d(0.0,0.0,GRAVITY), false, true);
00036 
00037         predStep = addOption<double>("predStep", "Step size for state estimation", 1e-3, false, true);
00038         pubStep = addOption<double>("pubStep", "Step size for state publication", 1e-2, false, true);
00039         normalizationGain = addOption<double>("normalizationGain", "Gain for quaternon normalization", 1, false, true);
00040 
00041         positionGain = addOption<Eigen::Matrix3d>("positionGain","Position gain for the estimation", 33*Eigen::Matrix3d::Identity(), false, true);
00042         velocityGain = addOption<Eigen::Matrix3d>("velocityGain","Velocity gain for the estimation", 362*Eigen::Matrix3d::Identity(), false, true);
00043         rotationGain = addOption<Eigen::Matrix3d>("rotationGain","Orientation gain for the estimation", 10*Eigen::Matrix3d::Identity(), false, true);
00044         biasGain = addOption<Eigen::Matrix3d>("biasGain","Bias gain for the estimation", Eigen::Matrix3d::Zero(), false, true);
00045 
00046         matrixA = addOption<Eigen::Matrix3d>("matrixA","Matrix A", Eigen::Matrix3d::Identity(), false, true);
00047         vectorB = addOption<Eigen::Vector3d>("vectorB","Vector B", Eigen::Vector3d::Zero(), false, true);
00048 
00049         tOmegaFilterFreq = addOption<double>("tOmegaFilterFreq", "Omega filter cutoff frequency in Hz", 30.0, false, true);
00050         tOmegaSampleTime = addOption<double>("tOmegaSampleTime", "Omega filter sample time in s", 1.0/1080.0, false, true);
00051 }
00052 
00053 
00054 void ComplementaryStateEstimator::initVelocityFilters()
00055 {
00056         IIRLowPass isLowPass;
00057         for(int i=0;i<3;i++){
00058                 omegaFilter[i] = new IIRFilter(
00059                                 isLowPass,
00060                                 2.0*M_PI*options.tOmegaFilterFreq->getValue(),
00061                                 1.0,
00062                                 options.tOmegaSampleTime->getValue());
00063         }
00064 }
00065 
00066 
00067 
00068 ComplementaryStateEstimator::ComplementaryStateEstimator():
00069         spinning(false),
00070         isInitialized(false),
00071         receivedFirstInput(false),
00072         receivedFirstMeasure(false){
00073 }
00074 
00075 void ComplementaryStateEstimator::initialize()
00076 {
00077         nodeHandle = ROSModule::Instance().getMainNodeHandle();
00078         system = DynamicSystem(options.positionGain->getValue(), options.velocityGain->getValue(), options.rotationGain->getValue(), options.biasGain->getValue(),
00079                         options.worldGravity->getValue(), options.normalizationGain->getValue(), options.matrixA->getValue(), options.vectorB->getValue());
00080 
00081         initVelocityFilters();
00082 
00083 
00084 }
00085 
00086 void ComplementaryStateEstimator::initializationDone()
00087 {
00088         boost::mutex::scoped_lock(threadMutex);
00089         if (!isInitialized) {
00090                 isInitialized = true;
00091 
00092                 spinning = true;
00093                 ROS_INFO("Initialization Done. Starting State Estimation Thread...");
00094                 thread = boost::thread(&ComplementaryStateEstimator::spin, this);
00095         }
00096 }
00097 
00098 void ComplementaryStateEstimator::spin()
00099 {
00100         pubTimer.reset();
00101         ros::Rate rate(1/options.predStep->getValue());
00102         while(spinning)
00103                 {
00104 //                      rtTimer.reset();
00105 
00106                         prediction(internalState, options.predStep->getValue());
00107 
00108 /*                      if (pubTimer.getElapsed()>=options.pubStep->getValue()){
00109                                 publishState();
00110                                 pubTimer.reset();
00111                         }*/
00112                         publishState();
00113 
00114 //                      Time toSleep = Time(options.predStep->getValue()) - rtTimer.getElapsed();
00115 //                      if (toSleep>0) {
00116 //                              //toSleep.sleep();
00117 //                      } else {
00118 //                              ROS_WARN("State estimation was too slow!");
00119 //                      }
00120                         rate.sleep();
00121         }
00122 }
00123 
00124 // Prediction function ====================================================
00125 void ComplementaryStateEstimator::prediction(State& state, double predStep)
00126 {
00127 
00128         ROS_DEBUG_STREAM("Performing prediction with state... " << std::endl
00129                 << "Position: [" << state.position.transpose() << "]'" << std::endl
00130                 << "Velocity: [" << state.lin_velocity.transpose() << "]'" << std::endl
00131                 << "Orientation: [" << state.orientation.w() << " " << state.orientation.vec().transpose() << "]'" << std::endl
00132                 << "... input ... " << std::endl
00133                 << "Linear acceleration: [" << system.getInput().lin_acc.transpose() << "]'" << std::endl
00134                 << "Angular velocity: [" << system.getInput().ang_vel.transpose() << "]'" << std::endl
00135                 << "... and measure... " << std::endl
00136                 << "Position: [" << system.getMeasure().position.transpose() << "]'" << std::endl
00137                 << "Orientation: [" << system.getMeasure().orientation.w() << " " << system.getMeasure().orientation.vec().transpose() << "]'" << std::endl
00138                 << "Prediction step: " << predStep << std::endl);
00139 
00140         typedef boost::numeric::odeint::runge_kutta4< State, double, State, double, boost::numeric::odeint::vector_space_algebra> stepper;
00141         boost::numeric::odeint::integrate_const( stepper() , system , state , 0.0, predStep, predStep);
00142 
00143         ROS_DEBUG_STREAM("Resulting in the state... " << std::endl
00144                         << "Position: [" << state.position.transpose() << "]'" << std::endl
00145                         << "Velocity: [" << state.lin_velocity.transpose() << "]'" << std::endl
00146                         << "Orientation: [" << state.orientation.w() << " " << state.orientation.vec().transpose() << "]'" << std::endl);
00147 
00148         return;
00149 }
00150 
00151 void ComplementaryStateEstimator::inputCallback(const tk_draft_msgs::TKSmallImuConstPtr& msg)
00152 {
00153         boost::mutex::scoped_lock scopedLock(imuMutex);
00154 
00155         /* Filter omega */
00156         double output[3];
00157         std::vector<double> input(1);
00158         input[0]=msg->angular_velocity.x;
00159         omegaFilter[0]->step(input, output[0]);
00160         input[0] = msg->angular_velocity.y;
00161         omegaFilter[1]->step(input, output[1]);
00162         input[0] = msg->angular_velocity.z;
00163         omegaFilter[2]->step(input, output[2]);
00164 
00165         angVelFiltered = Eigen::Vector3d(output[0], output[1], output[2]);
00166 
00167         /* Note: sending non filtered angular velocity to the complementary filter */
00168         Input lastInput;
00169         lastInput.ang_vel = Eigen::Vector3d(msg->angular_velocity.x, msg->angular_velocity.y, msg->angular_velocity.z);
00170 
00171         lastInput.lin_acc = Eigen::Vector3d(msg->linear_acceleration.x, msg->linear_acceleration.y, msg->linear_acceleration.z);
00172         system.setInput(lastInput);
00173 
00174 
00175         ROS_DEBUG_STREAM("Imu received at system time: " << ros::Time::now() << std::endl
00176                 << "Linear acceleration: [" << lastInput.ang_vel.transpose() << "]'" << std::endl
00177                 << "Angular velocity: [" << lastInput.lin_acc.transpose() << "]'" << std::endl);
00178 
00179         if (!isInitialized){
00180                 if(!receivedFirstInput) {
00181                         ROS_INFO_STREAM("Complementary state estimator received the first input containing: " << std::endl
00182                                                         << "Angular velocity: [" << lastInput.ang_vel.transpose() << "]'" << std::endl
00183                                                         << "Linear acceleration: [" << lastInput.lin_acc.transpose() << "]'");
00184 
00185                         receivedFirstInput = true;
00186                 }
00187                 if(receivedFirstMeasure){
00188                         internalState.position = system.getMeasure().position;
00189                         internalState.lin_velocity = Eigen::Vector3d::Zero(); //assumes we start from zero velocity
00190                         internalState.orientation = system.getMeasure().orientation;
00191                         internalState.bias = options.imuAccBias->getValue();
00192 
00193                         initializationDone();
00194                         ROS_INFO_STREAM("Complementary state estimator is ready to go!" << std::endl
00195                                         << "Initialized with:" << std::endl
00196                                         << "Position: [" << internalState.position.transpose() << "]'" << std::endl
00197                                         << "Velocity: [" << internalState.lin_velocity.transpose() << "]'" << std::endl
00198                                         << "Orientation: [" << internalState.orientation.w() << " " << internalState.orientation.vec().transpose() << "]'" << std::endl);
00199                 }
00200         }
00201 
00202         scopedLock.unlock();
00203 
00204 }
00205 
00206 
00207 void ComplementaryStateEstimator::measureCallback(const geometry_msgs::TransformStampedConstPtr& msg)
00208 {
00209         boost::mutex::scoped_lock scopedLock(viconMutex);
00210 
00211         Eigen::Quaterniond receivedQuaternion(-msg->transform.rotation.w, -msg->transform.rotation.x, msg->transform.rotation.y, msg->transform.rotation.z);
00212         receivedQuaternion = receivedQuaternion*Eigen::Quaterniond(cos(0.5*options.vicOrientation->getValue()(1)),0.0,-sin(0.5*options.vicOrientation->getValue()(1)),0.0)*
00213                                                Eigen::Quaterniond(cos(0.5*options.vicOrientation->getValue()(0)),-sin(0.5*options.vicOrientation->getValue()(0)),0.0,0.0);
00214         if (abs(receivedQuaternion.squaredNorm()-1)>1e-5){
00215                 ROS_WARN("Received non valid quaternion. Ignoring measure!");
00216                 return;
00217         }
00218 
00219         Measure lastMeasure;
00220         lastMeasure.position = Eigen::Vector3d(msg->transform.translation.x, -msg->transform.translation.y, -msg->transform.translation.z);
00221         lastMeasure.orientation = receivedQuaternion;
00222         system.setMeasure(lastMeasure);
00223         scopedLock.unlock();
00224 
00225         geometry_msgs::TransformStamped repubMsg(*msg);
00226         repubMsg.header.stamp = ros::Time::now();
00227         viconRepublisher.publish(repubMsg);
00228 
00229         ROS_DEBUG_STREAM("Measure received at system time: " << ros::Time::now() << std::endl
00230                 << "Position: [" << lastMeasure.position.transpose() << "]'" << std::endl
00231                 << "Orientation: [" << lastMeasure.orientation.w() << " " << lastMeasure.orientation.vec().transpose() << "]'" << std::endl);
00232 
00233         if (!isInitialized){
00234                 if(!receivedFirstMeasure){
00235                         receivedFirstMeasure = true;
00236                         ROS_INFO_STREAM("Complementary state estimator received the first measure containing: " << std::endl
00237                                                                 << "Position: [" << lastMeasure.position.transpose() << "]'" << std::endl
00238                                                                 << "Orientation: [" << lastMeasure.orientation.w() << " " << lastMeasure.orientation.vec().transpose() << "]'" << std::endl);
00239                 }
00240                 if(receivedFirstInput){
00241                         internalState.position = system.getMeasure().position;
00242                         internalState.lin_velocity = Eigen::Vector3d::Zero(); //assumes we start from zero velocity
00243                         internalState.orientation = system.getMeasure().orientation;
00244                         internalState.bias = options.imuAccBias->getValue();
00245                         //isInitialized = true;
00246                         initializationDone();
00247                         ROS_INFO_STREAM("Complementary state estimator is ready to go!" << std::endl
00248                                         << "Initialized with:" << std::endl
00249                                         << "Position: [" << internalState.position.transpose() << "]'" << std::endl
00250                                         << "Velocity: [" << internalState.lin_velocity.transpose() << "]'" << std::endl
00251                                         << "Orientation: [" << internalState.orientation.w() << " " << internalState.orientation.vec().transpose() << "]'" << std::endl);
00252                 }
00253         }
00254 
00255 }
00256 
00257 void ComplementaryStateEstimator::publishState(){
00258 
00259         TKState tStateMsg;
00260 
00261         tStateMsg.time = ros::Time::now();
00262 
00263         // empty msg
00264         tStateMsg.position = internalState.position;
00265         tStateMsg.linVelocity = internalState.lin_velocity;
00266         tStateMsg.orientation = internalState.orientation;
00267 
00268         boost::mutex::scoped_lock scopedImuLock(imuMutex);
00269         tStateMsg.angVelocity = angVelFiltered;
00270         scopedImuLock.unlock();
00271 
00272         stateEstimatorController.activeStateCallBack(tStateMsg);
00273 
00274         geometry_msgs::Vector3Stamped biasMsg;
00275         biasMsg.header.stamp = tStateMsg.time.toRosTime();
00276         biasMsg.vector.x = internalState.bias(0);
00277         biasMsg.vector.y = internalState.bias(1);
00278         biasMsg.vector.z = internalState.bias(2);
00279 
00280         biasPub.publish(biasMsg);
00281 }
00282 
00283 
00284 void ComplementaryStateEstimator::willBecomeActive()
00285 {
00286         viconSub = nodeHandle.subscribe<geometry_msgs::TransformStamped>(
00287                         options.tViconSeTopicName->getValue(),1, &ComplementaryStateEstimator::measureCallback, this);
00288 
00289 
00290         imuSub = nodeHandle.subscribe<tk_draft_msgs::TKSmallImu>(
00291                         options.tImuSeTopicName->getValue(),1, &ComplementaryStateEstimator::inputCallback, this);
00292 
00293         biasPub = nodeHandle.advertise<geometry_msgs::Vector3Stamped>("AccelerometerBias",1);
00294 
00295         viconRepublisher = nodeHandle.advertise<geometry_msgs::TransformStamped>(options.tViconRepubTopicName->getValue(),1);
00296 }
00297 
00298 void ComplementaryStateEstimator::willBecomeInActive()
00299 {
00300         viconSub.shutdown();
00301         imuSub.shutdown();
00302         biasPub.shutdown();
00303 }
00304 
00305 void ComplementaryStateEstimator::destroy()
00306 {
00307         for(int i=0;i<3;i++){
00308                 delete omegaFilter[i];
00309         }
00310 
00311         spinning = false;
00312         thread.join();
00313 }
00314 
00315 std::string ComplementaryStateEstimator::getName() const
00316 {
00317         return std::string("ComplementaryStateEstimator");
00318 }
00319 
00320 } /* 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