00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
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 <auv_msgs/NavSts.h>
00048 #include <auv_msgs/BodyForceReq.h>
00049 #include <sensor_msgs/NavSatFix.h>
00050 #include <sensor_msgs/Imu.h>
00051 #include <geometry_msgs/TransformStamped.h>
00052 #include <geometry_msgs/TwistStamped.h>
00053 
00054 #include <tf2_ros/buffer.h>
00055 #include <tf2_ros/transform_listener.h>
00056 #include <tf2_ros/transform_broadcaster.h>
00057 #include <Eigen/Dense>
00058 
00059 #include <ros/ros.h>
00060 
00061 #include <boost/bind.hpp>
00062 #include <sstream>
00063 #include <fstream>
00064 
00065 typedef labust::navigation::KFCore<labust::navigation::XYModel> KFNav;
00066 tf2_ros::Buffer buffer;
00067 tf2_ros::TransformListener* listener;
00068 
00069 ros::Time t;
00070 KFNav::vector measurement(KFNav::vector::Zero(KFNav::stateNum)), newMeas(KFNav::vector::Zero(KFNav::stateNum));
00071 
00072 void handleTau(KFNav::vector& tauIn, const auv_msgs::BodyForceReq::ConstPtr& tau)
00073 {
00074         tauIn(KFNav::X) = tau->wrench.force.x;
00075         tauIn(KFNav::Y) = tau->wrench.force.y;
00076         tauIn(KFNav::N) = tau->wrench.torque.z;
00077 };
00078 
00079 void handleGPS(KFNav::vector& xy, const sensor_msgs::NavSatFix::ConstPtr& data)
00080 {
00081         enum {x,y,newMsg};
00082         
00083         geometry_msgs::TransformStamped transformDeg, transformLocal;
00084         try
00085         {
00086                 transformLocal = buffer.lookupTransform("local", "gps_frame", ros::Time(0));
00087                 transformDeg = buffer.lookupTransform("worldLatLon", "local", ros::Time(0));
00088 
00089                 std::pair<double,double> posxy =
00090                                 labust::tools::deg2meter(data->latitude - transformDeg.transform.translation.y,
00091                                                 data->longitude - transformDeg.transform.translation.x,
00092                                                 transformDeg.transform.translation.y);
00093 
00094                 
00095                 Eigen::Vector3d pos = Eigen::Vector3d(posxy.first, posxy.second,0);
00096 
00097                 
00098                 
00099                 xy(x) = posxy.first;
00100                 xy(y) = posxy.second;
00101                 xy(newMsg) = 1;
00102 
00103                 
00104                 newMeas(KFNav::xp) = 1;
00105                 newMeas(KFNav::yp) = 1;
00106                 measurement(KFNav::xp) = posxy.first;
00107                 measurement(KFNav::yp) = posxy.second;
00108         }
00109         catch(tf2::TransformException& ex)
00110         {
00111                 ROS_WARN("%s",ex.what());
00112         }
00113 };
00114 
00115 void handleImu(KFNav::vector& rpy, const sensor_msgs::Imu::ConstPtr& data)
00116 {
00117         enum {r,p,y,newMsg};
00118         double roll,pitch,yaw;
00119         static labust::math::unwrap unwrap;
00120         
00121 
00122         geometry_msgs::TransformStamped transform;
00123         try
00124         {
00125                 t = data->header.stamp;
00126                 transform = buffer.lookupTransform("base_link", "imu_frame", ros::Time(0));
00127                 Eigen::Quaternion<double> meas(data->orientation.w, data->orientation.x,data->orientation.y,
00128                                 data->orientation.z);
00129                 Eigen::Quaternion<double> rot(transform.transform.rotation.w,
00130                                 transform.transform.rotation.x,
00131                                 transform.transform.rotation.y,
00132                                 transform.transform.rotation.z);
00133                 Eigen::Quaternion<double> result = meas*rot;
00134                 
00135                 
00136                 labust::tools::eulerZYXFromQuaternion(result, roll, pitch, yaw);
00137                 
00138 
00139 
00140 
00141                 ROS_INFO("Received RPY:%f,%f,%f",roll,pitch,yaw);
00142                 ROS_INFO("Received Quaternion:%f,%f,%f,%f",data->orientation.x,data->orientation.y,
00143                                 data->orientation.z,data->orientation.w);
00144                 rpy(r) = roll;
00145                 rpy(p) = pitch;
00146                 rpy(y) = yaw;
00147                 rpy(newMsg) = 1;
00148 
00149                 
00150                 newMeas(KFNav::psi) = 1;
00151                 newMeas(KFNav::r) = 1;
00152                 measurement(KFNav::psi) = unwrap(yaw);
00153                 measurement(KFNav::r) = data->angular_velocity.z;
00154         }
00155         catch (tf2::TransformException& ex)
00156         {
00157                 ROS_WARN("%s",ex.what());
00158         }
00159 };
00160 
00161 void configureNav(KFNav& nav, ros::NodeHandle& nh)
00162 {
00163         ROS_INFO("Configure navigation.");
00164 
00165         labust::simulation::DynamicsParams params;
00166         labust::tools::loadDynamicsParams(nh, params);
00167 
00168         ROS_INFO("Loaded dynamics params.");
00169 
00170         KFNav::ModelParams surge,sway,yaw;
00171         surge.alpha = params.m + params.Ma(0,0);
00172         sway.alpha = params.m + params.Ma(1,1);
00173         yaw.alpha = params.Io(2,2) + params.Ma(5,5);
00174         surge.beta = params.Dlin(0,0);
00175         sway.beta = params.Dlin(1,1);
00176         yaw.beta = params.Dlin(5,5);
00177         surge.betaa = params.Dquad(0,0);
00178         sway.betaa = params.Dquad(1,1);
00179         yaw.betaa = params.Dquad(5,5);
00180         nav.setParameters(surge, sway, yaw);
00181 
00182         nav.initModel();
00183         labust::navigation::kfModelLoader(nav, nh, "ekfnav");
00184 
00185         std::cout<<"V:"<<nav.V<<std::endl;
00186 }
00187 
00188 void offline_sim(const std::string& filename, KFNav& ekf)
00189 {
00190         std::fstream file(filename.c_str());
00191         std::ofstream log("test.csv");
00192         std::cout<<"Reading log file:"<<filename<<std::endl;
00193 
00194         
00195         log<<"%element: off_data\n"
00196         "% body_velocity.x\n"
00197         "% body_velocity.y\n"
00198         "% orientation_rate.yaw\n"
00199         "% position.north\n"
00200         "% position.east\n"
00201         "% orientation.yaw\n"
00202         "% current.xc\n"
00203         "% current.yc\n"
00204         "% b1\n"
00205         "% b2\n"
00206         "%element: off_cov \n"
00207   "% u_cov\n"
00208         "% v_cov\n"
00209         "% r_cov\n"
00210         "% x_cov\n"
00211         "% y_cov\n"
00212         "% psi_cov\n"
00213         "% xc_cov\n"
00214         "% yc_cov\n"
00215         "% b1_cov\n"
00216         "% b2_cov\n";
00217 
00218         double tauX,tauY,tauN,x,y,psi,yaw_rate;
00219         file>>tauX>>tauY>>tauN>>x>>y>>psi>>yaw_rate;
00220 
00221         KFNav::vector state(KFNav::vector::Zero(KFNav::stateNum));
00222         state(KFNav::xp) = x;
00223         state(KFNav::yp) = y;
00224         state(KFNav::psi) = psi;
00225 
00226         ekf.setState(state);
00227 
00228         double lastx,lasty;
00229         labust::math::unwrap unwrap;
00230 
00231         int i=0;
00232         while(!file.eof() && ros::ok())
00233         {
00234                 file>>tauX>>tauY>>tauN>>x>>y>>psi>>yaw_rate;
00235                 
00236                 KFNav::input_type input(KFNav::inputSize);
00237                 input(KFNav::X) = tauX;
00238                 input(KFNav::Y) = tauY;
00239                 input(KFNav::N) = tauN;
00240                 ekf.predict(input);
00241 
00242                 KFNav::vector newMeas(KFNav::vector::Zero(KFNav::stateNum));
00243                 KFNav::vector measurement(KFNav::vector::Zero(KFNav::stateNum));
00244 
00245                 double yaw = unwrap(psi);
00246 
00247                 newMeas(KFNav::psi) = 1;
00248                 newMeas(KFNav::r) = 1;
00249                 measurement(KFNav::psi) = yaw;
00250                 measurement(KFNav::r) = yaw_rate;
00251 
00252                 if (i%10 == 0)
00253                 {
00254                         
00255                         newMeas(KFNav::xp) = 1;
00256                         newMeas(KFNav::yp) = 1;
00257                         measurement(KFNav::xp) = x;
00258                         measurement(KFNav::yp) = y;
00259                 }
00260 
00261                 ekf.correct(ekf.update(measurement, newMeas));
00262 
00263                 lastx=x;
00264                 lasty=y;
00265 
00266                 
00267                 
00268                 
00269                 
00270 
00271                 log<<ekf.getState()(0);
00272                 for (size_t j = 1; j< ekf.getState().size(); ++j)
00273                         log<<","<<((j==KFNav::psi)?labust::math::wrapRad(ekf.getState()(j)):ekf.getState()(j));
00274                 for (size_t j = 0; j< ekf.getState().size(); ++j)       log<<","<<ekf.getStateCovariance()(j,j);
00275                 log<<"\n";
00276 
00277                 ++i;
00278         }
00279 }
00280 
00281 
00282 int main(int argc, char* argv[])
00283 {
00284         ros::init(argc,argv,"pladypos_nav");
00285         ros::NodeHandle nh;
00286         KFNav nav;
00287         
00288         configureNav(nav,nh);
00289 
00290         double outlierR;
00291         nh.param("outlier_radius",outlierR,1.0);
00292 
00294         
00295         bool offline(false);
00296         nh.param("offline",offline,false);
00297         std::string filename("");
00298         nh.param("offline_file",filename,filename);
00299 
00300         if (offline)
00301         {
00302                 offline_sim(filename, nav);
00303                 return 0;
00304         }
00306 
00307         
00308         ros::Publisher stateHat = nh.advertise<auv_msgs::NavSts>("stateHat",1);
00309         ros::Publisher stateMeas = nh.advertise<auv_msgs::NavSts>("meas",1);
00310         ros::Publisher currentTwist = nh.advertise<geometry_msgs::TwistStamped>("currentsHat",1);
00311         ros::Publisher bodyFlowFrame = nh.advertise<geometry_msgs::TwistStamped>("body_flow_frame_twist",1);
00312         
00313         KFNav::vector tau(KFNav::vector::Zero(KFNav::inputSize)),xy(KFNav::vector::Zero(2+1)),rpy(KFNav::vector::Zero(3+1));
00314 
00315         tf2_ros::TransformBroadcaster broadcast;
00316         listener = new tf2_ros::TransformListener(buffer);
00317 
00318         ros::Subscriber tauAch = nh.subscribe<auv_msgs::BodyForceReq>("tauAch", 1, boost::bind(&handleTau,boost::ref(tau),_1));
00319         ros::Subscriber navFix = nh.subscribe<sensor_msgs::NavSatFix>("gps", 1, boost::bind(&handleGPS,boost::ref(xy),_1));
00320         ros::Subscriber imu = nh.subscribe<sensor_msgs::Imu>("imu", 1, boost::bind(&handleImu,boost::ref(rpy),_1));
00321 
00322         ros::Rate rate(10);
00323 
00324         auv_msgs::NavSts meas,state;
00325         geometry_msgs::TwistStamped current, flowspeed;
00326         meas.header.frame_id = "local";
00327         state.header.frame_id = "local";
00328         current.header.frame_id = "local";
00329 
00330         labust::math::unwrap unwrap;
00331 
00332 
00333 
00334 
00335 
00336 
00337 
00338 
00339 
00340         while (ros::ok())
00341         {
00342                 nav.predict(tau);
00343 
00344                 bool newArrived(false);
00345 
00346                 for(size_t i=0; i<newMeas.size(); ++i)
00347                 {
00348                         if ((newArrived = newMeas(i))) break;
00349                 }
00350 
00351                 if (newArrived)
00352                 {
00353                         
00354                         bool outlier = false;
00355                         double x(nav.getState()(KFNav::xp)), y(nav.getState()(KFNav::yp));
00356                         double inx(0),iny(0);
00357                         nav.calculateXYInovationVariance(nav.getStateCovariance(),inx,iny);
00358                         outlier = sqrt(pow(x-xy(0),2) + pow(y-xy(1),2)) > outlierR*sqrt(inx*inx + iny*iny);
00359 
00360                         if (outlier)
00361                         {
00362                                 ROS_INFO("Outlier rejected: meas(%f, %f), estimate(%f,%f), inovationCov(%f,%f)",xy(0),xy(1),x,y,inx,iny);
00363                                 newMeas(KFNav::xp) = 0;
00364                                 newMeas(KFNav::yp) = 0;
00365                         }
00366 
00367                         nav.correct(nav.update(measurement, newMeas));
00368                         
00369                         newMeas = KFNav::vector::Zero(KFNav::stateNum);
00370                 }
00371 
00372 
00373 
00374 
00375 
00376 
00377 
00378 
00379 
00380 
00381 
00382 
00383 
00384 
00385 
00386 
00387 
00388 
00389 
00390 
00391 
00392 
00393 
00394 
00395 
00396 
00397 
00398 
00399 
00400 
00401                 meas.orientation.roll = rpy(0);
00402                 meas.orientation.pitch = rpy(1);
00403                 meas.orientation.yaw = rpy(2);
00404                 meas.orientation_rate.yaw = measurement(KFNav::r);
00405                 meas.position.north = xy(0);
00406                 meas.position.east = xy(1);
00407                 meas.header.stamp = ros::Time::now();
00408                 stateMeas.publish(meas);
00409 
00410                 const KFNav::vector& estimate = nav.getState();
00411                 state.body_velocity.x = estimate(KFNav::u);
00412                 state.body_velocity.y = estimate(KFNav::v);
00413                 state.orientation_rate.yaw = estimate(KFNav::r);
00414                 state.position.north = estimate(KFNav::xp);
00415                 state.position.east = estimate(KFNav::yp);
00416                 current.twist.linear.x = estimate(KFNav::xc);
00417                 current.twist.linear.y = estimate(KFNav::yc);
00418 
00419                 const KFNav::matrix& covariance = nav.getStateCovariance();
00420                 state.position_variance.north = covariance(KFNav::xp, KFNav::xp);
00421                 state.position_variance.east = covariance(KFNav::yp, KFNav::yp);
00422                 state.orientation_variance.yaw =  covariance(KFNav::psi, KFNav::psi);
00423 
00424                 try
00425                 {
00426                         geometry_msgs::TransformStamped transformDeg;
00427                         transformDeg = buffer.lookupTransform("worldLatLon", "local", ros::Time(0));
00428 
00429                         std::pair<double, double> diffAngle = labust::tools::meter2deg(state.position.north,
00430                                         state.position.east,
00431                                         
00432                                         transformDeg.transform.translation.y);
00433                         state.global_position.latitude = transformDeg.transform.translation.y + diffAngle.first;
00434                         state.global_position.longitude = transformDeg.transform.translation.x + diffAngle.second;
00435                         state.origin.latitude = transformDeg.transform.translation.y;
00436                         state.origin.longitude = transformDeg.transform.translation.x;
00437                 }
00438                 catch(tf2::TransformException& ex)
00439                 {
00440                         ROS_WARN("%s",ex.what());
00441                 }
00442 
00443                 state.orientation.yaw = labust::math::wrapRad(estimate(KFNav::psi));
00444 
00445                 geometry_msgs::TransformStamped transform;
00446                 transform.transform.translation.x = estimate(KFNav::xp);
00447                 transform.transform.translation.y = estimate(KFNav::yp);
00448                 transform.transform.translation.z = 0;
00449                 labust::tools::quaternionFromEulerZYX(rpy(0),rpy(1),estimate(KFNav::psi),
00450                                 transform.transform.rotation);
00451                 transform.child_frame_id = "base_link";
00452                 transform.header.frame_id = "local";
00453                 transform.header.stamp = ros::Time::now();
00454                 broadcast.sendTransform(transform);
00455 
00456                 
00457                 double xdot,ydot;
00458                 nav.getNEDSpeed(xdot,ydot);
00459                 labust::tools::quaternionFromEulerZYX(rpy(0),rpy(1),atan2(ydot,xdot),transform.transform.rotation);
00460                 transform.child_frame_id = "base_link_flow";
00461                 broadcast.sendTransform(transform);
00462 
00463                 flowspeed.twist.linear.x = xdot;
00464                 flowspeed.twist.linear.y = ydot;
00465                 bodyFlowFrame.publish(flowspeed);
00466                 currentTwist.publish(current);
00467                 state.header.stamp = t;
00468                 stateHat.publish(state);
00469 
00470                 rate.sleep();
00471                 ros::spinOnce();
00472         }
00473 
00474         return 0;
00475 }
00476