nav_node2.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2010, LABUST, UNIZG-FER
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of the LABUST nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *
00034  *  Author : Dula Nad
00035  *  Created: 26.03.2013.
00036  *********************************************************************/
00037 #include <labust/navigation/KFCore.hpp>
00038 #include <labust/navigation/XYModel.hpp>
00039 #include <labust/math/NumberManipulation.hpp>
00040 #include <labust/tools/GeoUtilities.hpp>
00041 #include <labust/tools/MatrixLoader.hpp>
00042 #include <labust/tools/conversions.hpp>
00043 #include <labust/tools/DynamicsLoader.hpp>
00044 #include <labust/simulation/DynamicsParams.hpp>
00045 #include <labust/navigation/KFModelLoader.hpp>
00046 
00047 #include <kdl/frames.hpp>
00048 #include <auv_msgs/NavSts.h>
00049 #include <auv_msgs/BodyForceReq.h>
00050 #include <sensor_msgs/NavSatFix.h>
00051 #include <sensor_msgs/Imu.h>
00052 
00053 #include <tf/transform_broadcaster.h>
00054 #include <tf/transform_listener.h>
00055 
00056 #include <ros/ros.h>
00057 
00058 #include <boost/bind.hpp>
00059 #include <sstream>
00060 #include <fstream>
00061 
00062 typedef labust::navigation::KFCore<labust::navigation::XYModel> KFNav;
00063 tf::TransformListener* listener;
00064 
00065 ros::Time t;
00066 KFNav::vector measurement(KFNav::vector::Zero(KFNav::stateNum)), newMeas(KFNav::vector::Zero(KFNav::stateNum));
00067 
00068 void handleTau(KFNav::vector& tauIn, const auv_msgs::BodyForceReq::ConstPtr& tau)
00069 {
00070         tauIn(KFNav::X) = tau->wrench.force.x;
00071         tauIn(KFNav::Y) = tau->wrench.force.y;
00072         tauIn(KFNav::N) = tau->wrench.torque.z;
00073 };
00074 
00075 void handleGPS(KFNav::vector& xy, const sensor_msgs::NavSatFix::ConstPtr& data)
00076 {
00077         enum {x,y,newMsg};
00078         //Calculate to X-Y tangent plane
00079         tf::StampedTransform transformDeg, transformLocal;
00080         try
00081         {
00082                 listener->lookupTransform("local", "gps_frame", ros::Time(0), transformLocal);
00083                 listener->lookupTransform("/worldLatLon", "local", ros::Time(0), transformDeg);
00084 
00085                 std::pair<double,double> posxy =
00086                                 labust::tools::deg2meter(data->latitude - transformDeg.getOrigin().y(),
00087                                                 data->longitude - transformDeg.getOrigin().x(),
00088                                                 transformDeg.getOrigin().y());
00089 
00090                 //correct for lever arm shift during pitch and roll
00091                 tf::Vector3 pos = tf::Vector3(posxy.first, posxy.second,0);
00092 
00093                 //xy(x) = pos.x();
00094                 //xy(y) = pos.y();
00095                 xy(x) = posxy.first;
00096                 xy(y) = posxy.second;
00097                 xy(newMsg) = 1;
00098 
00099                 //For generic updates
00100                 newMeas(KFNav::xp) = 1;
00101                 newMeas(KFNav::yp) = 1;
00102                 measurement(KFNav::xp) = posxy.first;
00103                 measurement(KFNav::yp) = posxy.second;
00104         }
00105         catch(tf::TransformException& ex)
00106         {
00107                 ROS_ERROR("%s",ex.what());
00108         }
00109 };
00110 
00111 void handleImu(KFNav::vector& rpy, const sensor_msgs::Imu::ConstPtr& data)
00112 {
00113         enum {r,p,y,newMsg};
00114         double roll,pitch,yaw;
00115         static labust::math::unwrap unwrap;
00116         
00117 
00118         tf::StampedTransform transform;
00119         try
00120         {
00121                 t = data->header.stamp;
00122                 listener->lookupTransform("base_link", "imu_frame", ros::Time(0), transform);
00123                 tf::Quaternion meas(data->orientation.x,data->orientation.y,
00124                                 data->orientation.z,data->orientation.w);
00125                 tf::Quaternion result = meas*transform.getRotation();
00126 
00127                 KDL::Rotation::Quaternion(result.x(),result.y(),result.z(),result.w()).GetEulerZYX(yaw,pitch,roll);
00128                 /*labust::tools::eulerZYXFromQuaternion(
00129                                 Eigen::Quaternion<float>(result.x(),result.y(),
00130                                                 result.z(),result.w()),
00131                                 roll,pitch,yaw);*/
00132                 //ROS_INFO("Received RPY:%f,%f,%f",roll,pitch,yaw);
00133                 rpy(r) = roll;
00134                 rpy(p) = pitch;
00135                 rpy(y) = yaw;
00136                 rpy(newMsg) = 1;
00137 
00138                 //For generic updates
00139                 newMeas(KFNav::psi) = 1;
00140                 newMeas(KFNav::r) = 1;
00141                 measurement(KFNav::psi) = unwrap(yaw);
00142                 measurement(KFNav::r) = data->angular_velocity.z;
00143         }
00144         catch (tf::TransformException& ex)
00145         {
00146                 ROS_ERROR("%s",ex.what());
00147         }
00148 };
00149 
00150 void configureNav(KFNav& nav, ros::NodeHandle& nh)
00151 {
00152         ROS_INFO("Configure navigation.");
00153 
00154         labust::simulation::DynamicsParams params;
00155         labust::tools::loadDynamicsParams(nh, params);
00156 
00157         ROS_INFO("Loaded dynamics params.");
00158 
00159         KFNav::ModelParams surge,sway,yaw;
00160         surge.alpha = params.m + params.Ma(0,0);
00161         sway.alpha = params.m + params.Ma(1,1);
00162         yaw.alpha = params.Io(2,2) + params.Ma(5,5);
00163         surge.beta = params.Dlin(0,0);
00164         sway.beta = params.Dlin(1,1);
00165         yaw.beta = params.Dlin(5,5);
00166         surge.betaa = params.Dquad(0,0);
00167         sway.betaa = params.Dquad(1,1);
00168         yaw.betaa = params.Dquad(5,5);
00169         nav.setParameters(surge, sway, yaw);
00170 
00171         nav.initModel();
00172         labust::navigation::kfModelLoader(nav, nh, "ekfnav");
00173 }
00174 
00175 void offline_sim(const std::string& filename, KFNav& ekf)
00176 {
00177         std::fstream file(filename.c_str());
00178         std::ofstream log("test.csv");
00179         std::cout<<"Reading log file:"<<filename<<std::endl;
00180 
00181         //Define a desired structure
00182         log<<"%element: off_data\n"
00183         "% body_velocity.x\n"
00184         "% body_velocity.y\n"
00185         "% orientation_rate.yaw\n"
00186         "% position.north\n"
00187         "% position.east\n"
00188         "% orientation.yaw\n"
00189         "% current.xc\n"
00190         "% current.yc\n"
00191         "% b1\n"
00192         "% b2\n"
00193         "%element: off_cov \n"
00194   "% u_cov\n"
00195         "% v_cov\n"
00196         "% r_cov\n"
00197         "% x_cov\n"
00198         "% y_cov\n"
00199         "% psi_cov\n"
00200         "% xc_cov\n"
00201         "% yc_cov\n"
00202         "% b1_cov\n"
00203         "% b2_cov\n";
00204 
00205         double tauX,tauY,tauN,x,y,psi,yaw_rate;
00206         file>>tauX>>tauY>>tauN>>x>>y>>psi>>yaw_rate;
00207 
00208         KFNav::vector state(KFNav::vector::Zero(KFNav::stateNum));
00209         state(KFNav::xp) = x;
00210         state(KFNav::yp) = y;
00211         state(KFNav::psi) = psi;
00212 
00213         ekf.setState(state);
00214 
00215         double lastx,lasty;
00216         labust::math::unwrap unwrap;
00217 
00218         int i=0;
00219         while(!file.eof() && ros::ok())
00220         {
00221                 file>>tauX>>tauY>>tauN>>x>>y>>psi>>yaw_rate;
00222                 //psi -= 2*M_PI*3.0/180;
00223                 KFNav::input_type input(KFNav::inputSize);
00224                 input(KFNav::X) = tauX;
00225                 input(KFNav::Y) = tauY;
00226                 input(KFNav::N) = tauN;
00227                 ekf.predict(input);
00228 
00229                 KFNav::vector newMeas(KFNav::vector::Zero(KFNav::stateNum));
00230                 KFNav::vector measurement(KFNav::vector::Zero(KFNav::stateNum));
00231 
00232                 double yaw = unwrap(psi);
00233 
00234                 newMeas(KFNav::psi) = 1;
00235                 newMeas(KFNav::r) = 1;
00236                 measurement(KFNav::psi) = yaw;
00237                 measurement(KFNav::r) = yaw_rate;
00238 
00239                 if (i%10 == 0)
00240                 {
00241                         //if (!((lastx == x) && (lasty == y)))
00242                         newMeas(KFNav::xp) = 1;
00243                         newMeas(KFNav::yp) = 1;
00244                         measurement(KFNav::xp) = x;
00245                         measurement(KFNav::yp) = y;
00246                 }
00247 
00248                 ekf.correct(ekf.update(measurement, newMeas));
00249 
00250                 lastx=x;
00251                 lasty=y;
00252 
00253                 //std::cout<<"Meas:"<<x<<","<<y<<","<<M_PI*psi/180<<std::endl;
00254                 //std::cout<<"Estimate:"<<ekf.getState()(KFNav::xp)<<",";
00255                 //std::cout<<ekf.getState()(KFNav::yp)<<","<<ekf.getState()(KFNav::psi)<<std::endl;
00256                 //std::cout<<ekf.traceP()<<std::endl;
00257 
00258                 log<<ekf.getState()(0);
00259                 for (size_t j = 1; j< ekf.getState().size(); ++j)
00260                         log<<","<<((j==KFNav::psi)?labust::math::wrapRad(ekf.getState()(j)):ekf.getState()(j));
00261                 for (size_t j = 0; j< ekf.getState().size(); ++j)       log<<","<<ekf.getStateCovariance()(j,j);
00262                 log<<"\n";
00263 
00264                 ++i;
00265         }
00266 }
00267 
00268 //consider making 2 corrections based on arrived measurements (async)
00269 int main(int argc, char* argv[])
00270 {
00271         ros::init(argc,argv,"pladypos_nav");
00272         ros::NodeHandle nh;
00273         KFNav nav;
00274         //Configure the navigation
00275         configureNav(nav,nh);
00276 
00277         double outlierR;
00278         nh.param("outlier_radius",outlierR,1.0);
00279 
00281         //ADDED FOR LOG-BASED NAVIGATION TUNING
00282         bool offline(false);
00283         nh.param("offline",offline,false);
00284         std::string filename("");
00285         nh.param("offline_file",filename,filename);
00286 
00287         if (offline)
00288         {
00289                 offline_sim(filename, nav);
00290                 return 0;
00291         }
00293 
00294         //Publishers
00295         ros::Publisher stateHat = nh.advertise<auv_msgs::NavSts>("stateHat",1);
00296         ros::Publisher stateMeas = nh.advertise<auv_msgs::NavSts>("meas",1);
00297         ros::Publisher currentTwist = nh.advertise<geometry_msgs::TwistStamped>("currentsHat",1);
00298         ros::Publisher bodyFlowFrame = nh.advertise<geometry_msgs::TwistStamped>("body_flow_frame_twist",1);
00299         //Subscribers
00300         KFNav::vector tau(KFNav::vector::Zero(KFNav::inputSize)),xy(KFNav::vector::Zero(2+1)),rpy(KFNav::vector::Zero(3+1));
00301 
00302         tf::TransformBroadcaster broadcast;
00303         listener = new tf::TransformListener();
00304 
00305         ros::Subscriber tauAch = nh.subscribe<auv_msgs::BodyForceReq>("tauAch", 1, boost::bind(&handleTau,boost::ref(tau),_1));
00306         ros::Subscriber navFix = nh.subscribe<sensor_msgs::NavSatFix>("gps", 1, boost::bind(&handleGPS,boost::ref(xy),_1));
00307         ros::Subscriber imu = nh.subscribe<sensor_msgs::Imu>("imu", 1, boost::bind(&handleImu,boost::ref(rpy),_1));
00308 
00309         ros::Rate rate(10);
00310 
00311         auv_msgs::NavSts meas,state;
00312         geometry_msgs::TwistStamped current, flowspeed;
00313         meas.header.frame_id = "local";
00314         state.header.frame_id = "local";
00315         current.header.frame_id = "local";
00316 
00317         labust::math::unwrap unwrap;
00318 
00319 //      std::cout<<"Configured."<<std::endl;
00320 //      std::cout<<nav.A<<std::endl;
00321 //      std::cout<<nav.Q<<std::endl;
00322 //      std::cout<<nav.W<<std::endl;
00323 //      std::cout<<nav.R<<std::endl;
00324 //      std::cout<<nav.V<<std::endl;
00325 //      std::cout<<nav.getStateCovariance()<<std::endl;
00326 
00327         while (ros::ok())
00328         {
00329                 nav.predict(tau);
00330 
00331                 bool newArrived(false);
00332 
00333                 for(size_t i=0; i<newMeas.size(); ++i)
00334                 {
00335                         if ((newArrived = newMeas(i))) break;
00336                 }
00337 
00338                 if (newArrived)
00339                 {
00340                         //Generic measurment outlier rejection
00341                         bool outlier = false;
00342                         double x(nav.getState()(KFNav::xp)), y(nav.getState()(KFNav::yp));
00343                         double inx(0),iny(0);
00344                         nav.calculateXYInovationVariance(nav.getStateCovariance(),inx,iny);
00345                         outlier = sqrt(pow(x-xy(0),2) + pow(y-xy(1),2)) > outlierR*sqrt(inx*inx + iny*iny);
00346 
00347                         if (outlier)
00348                         {
00349                                 ROS_INFO("Outlier rejected: meas(%f, %f), estimate(%f,%f), inovationCov(%f,%f)",xy(0),xy(1),x,y,inx,iny);
00350                                 newMeas(KFNav::xp) = 0;
00351                                 newMeas(KFNav::yp) = 0;
00352                         }
00353 
00354                         nav.correct(nav.update(measurement, newMeas));
00355                         //Clear measurements
00356                         newMeas = KFNav::vector::Zero(KFNav::stateNum);
00357                 }
00358 
00359 //              if (rpy(3))
00360 //              {
00361 //                      double yaw = unwrap(rpy(2));
00362 //
00363 //                      bool outlier = false;
00364 //                      double x(nav.getState()(KFNav::xp)), y(nav.getState()(KFNav::yp));
00365 //                      double inx(0),iny(0);
00366 //                      nav.calculateXYInovationVariance(nav.getStateCovariance(),inx,iny);
00367 //                      outlier = sqrt(pow(x-xy(0),2) + pow(y-xy(1),2)) > outlierR*sqrt(inx*inx + iny*iny);
00368 //                      if (outlier)
00369 //                      {
00370 //                              ROS_INFO("Outlier rejected: meas(%f, %f), estimate(%f,%f), inovationCov(%f,%f)",xy(0),xy(1),x,y,inx,iny);
00371 //                              xy(2) = 0;
00372 //                      }
00373 //
00374 //                      if (xy(2) == 1 && !outlier)
00375 //                      {
00376 //                              ROS_INFO("XY correction: meas(%f, %f), estimate(%f,%f), inovationCov(%f,%f,%d)",xy(0),xy(1),x,y,inx,iny,nav.getInovationCovariance().size1());
00377 //                              nav.correct(nav.fullUpdate(xy(0),xy(1),yaw));
00378 //                              xy(2) = 0;
00379 //                      }
00380 //                      else
00381 //                      {
00382 //                              ROS_INFO("Heading correction:%f",yaw);
00383 //                              nav.correct(nav.yawUpdate(yaw));
00384 //                      }
00385 //                      rpy(3) = 0;
00386 //              }
00387 
00388                 meas.orientation.roll = rpy(0);
00389                 meas.orientation.pitch = rpy(1);
00390                 meas.orientation.yaw = rpy(2);
00391                 meas.orientation_rate.yaw = measurement(KFNav::r);
00392                 meas.position.north = xy(0);
00393                 meas.position.east = xy(1);
00394                 meas.header.stamp = ros::Time::now();
00395                 stateMeas.publish(meas);
00396 
00397                 const KFNav::vector& estimate = nav.getState();
00398                 state.body_velocity.x = estimate(KFNav::u);
00399                 state.body_velocity.y = estimate(KFNav::v);
00400                 state.orientation_rate.yaw = estimate(KFNav::r);
00401                 state.position.north = estimate(KFNav::xp);
00402                 state.position.east = estimate(KFNav::yp);
00403                 current.twist.linear.x = estimate(KFNav::xc);
00404                 current.twist.linear.y = estimate(KFNav::yc);
00405 
00406                 const KFNav::matrix& covariance = nav.getStateCovariance();
00407                 state.position_variance.north = covariance(KFNav::xp, KFNav::xp);
00408                 state.position_variance.east = covariance(KFNav::yp, KFNav::yp);
00409                 state.orientation_variance.yaw =  covariance(KFNav::psi, KFNav::psi);
00410 
00411                 try
00412                 {
00413                         tf::StampedTransform transformDeg;
00414                         listener->lookupTransform("/worldLatLon", "local", ros::Time(0), transformDeg);
00415 
00416                         std::pair<double, double> diffAngle = labust::tools::meter2deg(state.position.north,
00417                                         state.position.east,
00418                                         //The latitude angle
00419                                         transformDeg.getOrigin().y());
00420                         state.global_position.latitude = transformDeg.getOrigin().y() + diffAngle.first;
00421                         state.global_position.longitude = transformDeg.getOrigin().x() + diffAngle.second;
00422                         state.origin.latitude = transformDeg.getOrigin().y();
00423                         state.origin.longitude = transformDeg.getOrigin().x();
00424                 }
00425                 catch(tf::TransformException& ex)
00426                 {
00427                         ROS_ERROR("%s",ex.what());
00428                 }
00429 
00430                 state.orientation.yaw = labust::math::wrapRad(estimate(KFNav::psi));
00431 
00432                 tf::StampedTransform transform;
00433                 transform.setOrigin(tf::Vector3(estimate(KFNav::xp), estimate(KFNav::yp), 0.0));
00434                 Eigen::Quaternion<float> q;
00435                 labust::tools::quaternionFromEulerZYX(rpy(0),rpy(1),estimate(KFNav::psi),q);
00436                 transform.setRotation(tf::Quaternion(q.x(),q.y(),q.z(),q.w()));
00437                 broadcast.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "local", "base_link"));
00438 
00439                 //Calculate the flow frame (instead of heading use course)
00440                 double xdot,ydot;
00441                 nav.getNEDSpeed(xdot,ydot);
00442                 labust::tools::quaternionFromEulerZYX(rpy(0),rpy(1),atan2(ydot,xdot),q);
00443                 transform.setRotation(tf::Quaternion(q.x(),q.y(),q.z(),q.w()));
00444                 broadcast.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "local", "base_link_flow"));
00445 
00446                 flowspeed.twist.linear.x = xdot;
00447                 flowspeed.twist.linear.y = ydot;
00448                 bodyFlowFrame.publish(flowspeed);
00449                 currentTwist.publish(current);
00450                 state.header.stamp = t;
00451                 stateHat.publish(state);
00452 
00453                 rate.sleep();
00454                 ros::spinOnce();
00455         }
00456 
00457         return 0;
00458 }
00459 


labust_navigation
Author(s): Gyula Nagy
autogenerated on Fri Feb 7 2014 11:36:19