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 <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
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
00091 tf::Vector3 pos = tf::Vector3(posxy.first, posxy.second,0);
00092
00093
00094
00095 xy(x) = posxy.first;
00096 xy(y) = posxy.second;
00097 xy(newMsg) = 1;
00098
00099
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
00129
00130
00131
00132
00133 rpy(r) = roll;
00134 rpy(p) = pitch;
00135 rpy(y) = yaw;
00136 rpy(newMsg) = 1;
00137
00138
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
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
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
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
00254
00255
00256
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
00269 int main(int argc, char* argv[])
00270 {
00271 ros::init(argc,argv,"pladypos_nav");
00272 ros::NodeHandle nh;
00273 KFNav nav;
00274
00275 configureNav(nav,nh);
00276
00277 double outlierR;
00278 nh.param("outlier_radius",outlierR,1.0);
00279
00281
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
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
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
00320
00321
00322
00323
00324
00325
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
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
00356 newMeas = KFNav::vector::Zero(KFNav::stateNum);
00357 }
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
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
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
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