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/EKF3D.hpp>
00038 #include <labust/navigation/LDTravModelExtended.hpp>
00039 #include <labust/tools/GeoUtilities.hpp>
00040 #include <labust/tools/MatrixLoader.hpp>
00041 #include <labust/tools/conversions.hpp>
00042 #include <labust/tools/DynamicsLoader.hpp>
00043 #include <labust/math/NumberManipulation.hpp>
00044 #include <labust/simulation/DynamicsParams.hpp>
00045 #include <labust/navigation/KFModelLoader.hpp>
00046 
00047 
00048 #include <auv_msgs/NavSts.h>
00049 #include <auv_msgs/BodyForceReq.h>
00050 #include <geometry_msgs/TwistStamped.h>
00051 #include <geometry_msgs/TransformStamped.h>
00052 #include <std_msgs/Float32.h>
00053 #include <std_msgs/Bool.h>
00054 
00055 #include <ros/ros.h>
00056 
00057 #include <boost/bind.hpp>
00058 
00059 using namespace labust::navigation;
00060 
00061 Estimator3D::Estimator3D():
00062                 tauIn(KFNav::vector::Zero(KFNav::inputSize)),
00063                 measurements(KFNav::vector::Zero(KFNav::stateNum)),
00064                 newMeas(KFNav::vector::Zero(KFNav::stateNum)),
00065                 alt(0),
00066                 useYawRate(false),
00067                 dvl_model(0),
00068                 compassVariance(0.3),
00069                 gyroVariance(0.003),
00070                 absoluteEKF(false),
00071                 max_dvl(1.5),
00072                 min_altitude(0.5),
00073                 dvl_timeout(5),
00074                 dvl_time(ros::Time::now()){this->onInit();};
00075 
00076 void Estimator3D::onInit()
00077 {
00078         ros::NodeHandle nh, ph("~");
00079         
00080         configureNav(nav,nh);
00081         
00082         stateHat = nh.advertise<auv_msgs::NavSts>("stateHat",1);
00083         stateMeas = nh.advertise<auv_msgs::NavSts>("meas",1);
00084         currentsHat = nh.advertise<geometry_msgs::TwistStamped>("currentsHat",1);
00085         buoyancyHat = nh.advertise<std_msgs::Float32>("buoyancy",1);
00086         turns_pub = nh.advertise<std_msgs::Float32>("turns",1);
00087         unsafe_dvl = nh.advertise<std_msgs::Bool>("unsafe_dvl",1);
00088         
00089         tauAch = nh.subscribe<auv_msgs::BodyForceReq>("tauAch", 1, &Estimator3D::onTau,this);
00090         depth = nh.subscribe<std_msgs::Float32>("depth", 1,     &Estimator3D::onDepth, this);
00091         altitude = nh.subscribe<std_msgs::Float32>("altitude", 1, &Estimator3D::onAltitude, this);
00092         modelUpdate = nh.subscribe<navcon_msgs::ModelParamsUpdate>("model_update", 1, &Estimator3D::onModelUpdate,this);
00093         resetTopic = nh.subscribe<std_msgs::Bool>("reset_nav_covariance", 1, &Estimator3D::onReset,this);
00094         useGyro = nh.subscribe<std_msgs::Bool>("use_gyro", 1, &Estimator3D::onUseGyro,this);
00095 
00096 
00097         KFmode = quadMeasAvailable = false;
00098         sub = nh.subscribe<auv_msgs::NED>("quad_delta_pos", 1, &Estimator3D::deltaPosCallback,this);
00099         subKFmode = nh.subscribe<std_msgs::Bool>("KFmode", 1, &Estimator3D::KFmodeCallback, this);
00100 
00101         
00102         ph.param("dvl_model",dvl_model, dvl_model);
00103         nav.useDvlModel(dvl_model);
00104         ph.param("imu_with_yaw_rate",useYawRate,useYawRate);
00105         ph.param("compass_variance",compassVariance,compassVariance);
00106         ph.param("gyro_variance",gyroVariance,gyroVariance);
00107         ph.param("max_dvl",max_dvl,max_dvl);
00108         ph.param("min_altitude", min_altitude, min_altitude);
00109         ph.param("dvl_timeout", dvl_timeout, dvl_timeout);
00110         double trustf(0);
00111         ph.param("dvl_rot_trust_factor", trustf, trustf);
00112         double sway_corr(0);
00113         ph.param("sway_corr", sway_corr, sway_corr);
00114         ph.param("absoluteEKF", absoluteEKF,absoluteEKF);
00115 
00116         
00117         gps.configure(nh);
00118         dvl.configure(nh);
00119         imu.configure(nh);
00120         imu.setGpsHandler(&gps);
00121 
00122   Pstart = nav.getStateCovariance();
00123   nav.setDVLRotationTrustFactor(trustf);
00124   nav.setSwayCorrection(sway_corr);
00125 
00126  
00127 
00128 }
00129 
00130 void Estimator3D::onReset(const std_msgs::Bool::ConstPtr& reset)
00131 {
00132    if (reset->data)
00133    {
00134       nav.setStateCovariance(10000*KFNav::matrix::Identity(KFNav::stateNum, KFNav::stateNum));
00135    }
00136 }
00137 
00138 void Estimator3D::onUseGyro(const std_msgs::Bool::ConstPtr& use_gyro)
00139 {
00140    if (use_gyro->data)
00141    {
00142       nav.R0(KFNav::psi, KFNav::psi) = gyroVariance;
00143       ROS_INFO("Switch to using gyro measurements.");
00144    }
00145    else
00146    {
00147       nav.R0(KFNav::psi, KFNav::psi) = compassVariance;
00148       ROS_INFO("Switch to using compass measurements.");
00149    }
00150 }
00151 
00152 void Estimator3D::configureNav(KFNav& nav, ros::NodeHandle& nh)
00153 {
00154         ROS_INFO("Configure navigation.");
00155 
00156         labust::simulation::DynamicsParams params;
00157         labust::tools::loadDynamicsParams(nh, params);
00158 
00159         ROS_INFO("Loaded dynamics params.");
00160 
00161         this->params[X].alpha = params.m + params.Ma(0,0);
00162         this->params[X].beta = params.Dlin(0,0);
00163         this->params[X].betaa = params.Dquad(0,0);
00164 
00165         this->params[Y].alpha = params.m + params.Ma(1,1);
00166         this->params[Y].beta = params.Dlin(1,1);
00167         this->params[Y].betaa = params.Dquad(1,1);
00168 
00169         this->params[Z].alpha = params.m + params.Ma(2,2);
00170         this->params[Z].beta = params.Dlin(2,2);
00171         this->params[Z].betaa = params.Dquad(2,2);
00172 
00173         this->params[K].alpha = params.Io(0,0) + params.Ma(3,3);
00174         this->params[K].beta = params.Dlin(3,3);
00175         this->params[K].betaa = params.Dquad(3,3);
00176 
00177         this->params[M].alpha = params.Io(1,1) + params.Ma(4,4);
00178         this->params[M].beta = params.Dlin(4,4);
00179         this->params[M].betaa = params.Dquad(4,4);
00180 
00181         this->params[N].alpha = params.Io(2,2) + params.Ma(5,5);
00182         this->params[N].beta = params.Dlin(5,5);
00183         this->params[N].betaa = params.Dquad(5,5);
00184 
00185         nav.setParameters(this->params[X], this->params[Y],
00186                         this->params[Z], this->params[K],
00187                         this->params[M], this->params[N]);
00188 
00189         nav.initModel();
00190         labust::navigation::kfModelLoader(nav, nh, "ekfnav");
00191 }
00192 
00193 void Estimator3D::onModelUpdate(const navcon_msgs::ModelParamsUpdate::ConstPtr& update)
00194 {
00195         ROS_INFO("Updating the model parameters for %d DoF.",update->dof);
00196         params[update->dof].alpha = update->alpha;
00197         if (update->use_linear)
00198         {
00199                 params[update->dof].beta = update->beta;
00200                 params[update->dof].betaa = 0;
00201         }
00202         else
00203         {
00204                 params[update->dof].beta = 0;
00205                 params[update->dof].betaa = update->betaa;
00206         }
00207         nav.setParameters(this->params[X],this->params[Y],
00208                         this->params[Z], this->params[K],
00209                         this->params[M],this->params[N]);
00210 }
00211 
00212 void Estimator3D::onTau(const auv_msgs::BodyForceReq::ConstPtr& tau)
00213 {
00214         tauIn(KFNav::X) = tau->wrench.force.x;
00215         tauIn(KFNav::Y) = tau->wrench.force.y;
00216         tauIn(KFNav::Z) = tau->wrench.force.z;
00217         tauIn(KFNav::Kroll) = tau->wrench.torque.x;
00218         tauIn(KFNav::M) = tau->wrench.torque.y;
00219         tauIn(KFNav::N) = tau->wrench.torque.z;
00220 };
00221 
00222 void Estimator3D::onDepth(const std_msgs::Float32::ConstPtr& data)
00223 {
00224         boost::mutex::scoped_lock l(meas_mux);
00225         measurements(KFNav::zp) = data->data;
00226         newMeas(KFNav::zp) = 1;
00227         ROS_INFO("Depth measurement received: %f", newMeas(KFNav::zp));
00228 };
00229 
00230 void Estimator3D::onAltitude(const std_msgs::Float32::ConstPtr& data)
00231 {
00232         boost::mutex::scoped_lock l(meas_mux);
00233         measurements(KFNav::altitude) = data->data;
00234         
00235         if (data->data <= min_altitude) return;
00236         
00237         if (fabs(data->data-nav.getState()(KFNav::altitude)) < 3*nav.calculateAltInovationVariance(nav.getStateCovariance()))
00238         {
00239                 newMeas(KFNav::altitude) = 1;
00240                 alt = data->data;
00241                 ROS_DEBUG("Accepted altitude: meas=%f, estimate=%f, variance=%f",
00242                         data->data, nav.getState()(KFNav::altitude), 3*nav.calculateAltInovationVariance(nav.getStateCovariance()));
00243         }
00244         else
00245         {
00246                 ROS_INFO("Dissmissed altitude: meas=%f, estimate=%f, variance=%f",
00247                         data->data, nav.getState()(KFNav::altitude), 10* nav.calculateAltInovationVariance(nav.getStateCovariance()));
00248         }
00249 };
00250 
00251 void Estimator3D::deltaPosCallback(const auv_msgs::NED::ConstPtr& msg){
00252 
00253         quadMeasAvailable = true;
00254         deltaXpos = msg->north;
00255         deltaYpos = msg->east;
00256         
00257 }
00258 
00259 void Estimator3D::KFmodeCallback(const std_msgs::Bool::ConstPtr& msg){
00260 
00261         if(!absoluteEKF){
00262                 KFmode = msg->data;
00263 
00264                 if(KFmode && (KFmodePast xor KFmode)){
00265 
00266                         KFmodePast = KFmode;
00267                         KFNav::matrix P = nav.getStateCovariance();
00268                         P(KFNav::xp,KFNav::xp) = 10000;
00269                         P(KFNav::yp,KFNav::yp) = 10000;
00270                         nav.setStateCovariance(P);
00271 
00272                         
00273                         
00274                         
00275 
00276 
00277                 } else if(!KFmode && (KFmodePast xor KFmode)){
00278 
00279                 KFmodePast = KFmode;
00280                         KFNav::matrix P = nav.getStateCovariance();
00281                         P(KFNav::xp,KFNav::xp) = 10000;
00282                         P(KFNav::yp,KFNav::yp) = 10000;
00283                         nav.setStateCovariance(P);
00284 
00285                         
00286 
00287                         
00288 
00289                         
00290                 }
00291         }
00292 }
00293 
00294 void Estimator3D::processMeasurements()
00295 {
00296         boost::mutex::scoped_lock l(meas_mux);
00297         if(KFmode == true && absoluteEKF == false)
00298                 {
00299                         if ((newMeas(KFNav::xp) = newMeas(KFNav::yp) = quadMeasAvailable)){
00300 
00301                                 quadMeasAvailable = false;
00302                                 measurements(KFNav::xp) = deltaXpos;
00303                                 measurements(KFNav::yp) = deltaYpos;
00304                     }
00305                 } else {
00306 
00307                         
00308                         if ((newMeas(KFNav::xp) = newMeas(KFNav::yp) = gps.newArrived()))
00309                         {
00310                                 measurements(KFNav::xp) = gps.position().first;
00311                                 measurements(KFNav::yp) = gps.position().second;
00312                         }
00313                 }
00314 
00315                 
00316 
00317         
00318         if ((newMeas(KFNav::phi) = newMeas(KFNav::theta) = newMeas(KFNav::psi) = imu.newArrived()))
00319         {
00320                 measurements(KFNav::phi) = imu.orientation()[ImuHandler::roll];
00321                 measurements(KFNav::theta) = imu.orientation()[ImuHandler::pitch];
00322                 measurements(KFNav::psi) = imu.orientation()[ImuHandler::yaw];
00323 
00324                 ROS_DEBUG("NEW IMU: r=%f, p=%f, y=%f", imu.orientation()[ImuHandler::roll],
00325                                 imu.orientation()[ImuHandler::pitch],
00326                                 imu.orientation()[ImuHandler::yaw]);
00327 
00328 
00329                 if ((newMeas(KFNav::r) = useYawRate))
00330                 {
00331                         measurements(KFNav::r) = imu.rate()[ImuHandler::r];
00332                         
00333                         dvl.current_r(measurements(KFNav::r));
00334                 }
00335         }
00336         
00337         
00338         if ((newMeas(KFNav::u) = newMeas(KFNav::v) = dvl.newArrived()))
00339         {
00340                 double vx = dvl.body_speeds()[DvlHandler::u];
00341                 double vy = dvl.body_speeds()[DvlHandler::v];
00342                 double vxe = nav.getState()(KFNav::u); 
00343                 double vye = nav.getState()(KFNav::v); 
00344 
00345                 double rvx(10),rvy(10);
00346                 
00347                 
00348                 nav.calculateUVInovationVariance(nav.getStateCovariance(), rvx, rvy);
00349 
00350                 double cpsi = cos(nav.getState()(KFNav::psi));
00351                 double spsi = sin(nav.getState()(KFNav::psi));
00352                 double xc = nav.getState()(KFNav::xc);
00353                 double yc = nav.getState()(KFNav::yc);
00354                 switch (dvl_model)
00355                 {
00356                   case 1:
00357                     vxe += xc*cpsi + yc*spsi;
00358                     vye += -xc*spsi + yc*cpsi;
00359                     break;
00360                 default: break;
00361                 }
00362 
00363                 if ((fabs((vx - vxe)) > fabs(rvx)) || (fabs((vy - vye)) > fabs(rvy)))
00364                 {
00365                         ROS_INFO("Outlier rejected: meas=%f, est=%f, tolerance=%f", vx, nav.getState()(KFNav::u), fabs(rvx));
00366                         ROS_INFO("Outlier rejected: meas=%f, est=%f, tolerance=%f", vy, nav.getState()(KFNav::v), fabs(rvy));
00367                         newMeas(KFNav::u) = false;
00368                         newMeas(KFNav::v) = false;
00369                 }
00370                 measurements(KFNav::u) = vx;
00371                 measurements(KFNav::v) = vy;
00372 
00373                 
00374                 if ((fabs(vx) > max_dvl) || (fabs(vy) > max_dvl))
00375                 {
00376                         ROS_INFO("DVL measurement failed sanity check for maximum speed %f. Got: vx=%f, vy=%f.",max_dvl, vx, vy);
00377                         newMeas(KFNav::u) = false;
00378                         newMeas(KFNav::v) = false;
00379                 }
00380 
00381                 if (newMeas(KFNav::u) || newMeas(KFNav::v))
00382                 {
00383                         dvl_time = ros::Time::now();
00384                         std_msgs::Bool data;
00385                         data.data = false;
00386                         unsafe_dvl.publish(data);
00387                 }
00388                 
00389         }
00390         else
00391         {
00392                 if ((ros::Time::now() - dvl_time).toSec() > dvl_timeout)
00393                 {
00394                         std_msgs::Bool data;
00395                         data.data = true;
00396                         unsafe_dvl.publish(data);
00397                 }
00398         }
00399         l.unlock();
00400 
00401         
00402         auv_msgs::NavSts::Ptr meas(new auv_msgs::NavSts());
00403         meas->body_velocity.x = measurements(KFNav::u);
00404         meas->body_velocity.y = measurements(KFNav::v);
00405         meas->body_velocity.z = measurements(KFNav::w);
00406 
00407         meas->position.north = measurements(KFNav::xp);
00408         meas->position.east = measurements(KFNav::yp);
00409         meas->position.depth = measurements(KFNav::zp);
00410         meas->altitude = measurements(KFNav::altitude);
00411 
00412         meas->orientation.roll = measurements(KFNav::phi);
00413         meas->orientation.pitch = measurements(KFNav::theta);
00414         meas->orientation.yaw = labust::math::wrapRad(measurements(KFNav::psi));
00415         if (useYawRate) meas->orientation_rate.yaw = measurements(KFNav::r);
00416 
00417         meas->origin.latitude = gps.origin().first;
00418         meas->origin.longitude = gps.origin().second;
00419         meas->global_position.latitude = gps.latlon().first;
00420         meas->global_position.longitude = gps.latlon().second;
00421 
00422         meas->header.stamp = ros::Time::now();
00423         meas->header.frame_id = "local";
00424         stateMeas.publish(meas);
00425 }
00426 
00427 void Estimator3D::publishState()
00428 {
00429         auv_msgs::NavSts::Ptr state(new auv_msgs::NavSts());
00430         const KFNav::vector& estimate = nav.getState();
00431         state->body_velocity.x = estimate(KFNav::u);
00432         state->body_velocity.y = estimate(KFNav::v);
00433         state->body_velocity.z = estimate(KFNav::w);
00434 
00435         Eigen::Matrix2d R;
00436         double yaw = labust::math::wrapRad(estimate(KFNav::psi));
00437         R<<cos(yaw),-sin(yaw),sin(yaw),cos(yaw);
00438         Eigen::Vector2d in, out;
00439         in << estimate(KFNav::xc), estimate(KFNav::yc);
00440         out = R.transpose()*in;
00441 
00442         state->gbody_velocity.x = estimate(KFNav::u) + out(0);
00443         state->gbody_velocity.y = estimate(KFNav::v) + out(1);
00444         state->gbody_velocity.z = estimate(KFNav::w);
00445 
00446         state->orientation_rate.roll = estimate(KFNav::p);
00447         state->orientation_rate.pitch = estimate(KFNav::q);
00448         state->orientation_rate.yaw = estimate(KFNav::r);
00449 
00450         state->position.north = estimate(KFNav::xp);
00451         state->position.east = estimate(KFNav::yp);
00452         state->position.depth = estimate(KFNav::zp);
00453         state->altitude = estimate(KFNav::altitude);
00454 
00455         state->orientation.roll = estimate(KFNav::phi);
00456         state->orientation.pitch = estimate(KFNav::theta);
00457         state->orientation.yaw = labust::math::wrapRad(estimate(KFNav::psi));
00458 
00459         state->origin.latitude = gps.origin().first;
00460     state->origin.longitude = gps.origin().second;
00461         std::pair<double, double> diffAngle = labust::tools::meter2deg(state->position.north,
00462                         state->position.east,
00463                         
00464                         state->origin.latitude);
00465         state->global_position.latitude = state->origin.latitude + diffAngle.first;
00466         state->global_position.longitude = state->origin.longitude + diffAngle.second;
00467 
00468         const KFNav::matrix& covariance = nav.getStateCovariance();
00469         state->position_variance.north = covariance(KFNav::xp, KFNav::xp);
00470         state->position_variance.east = covariance(KFNav::yp, KFNav::yp);
00471         state->position_variance.depth = covariance(KFNav::zp,KFNav::zp);
00472         state->orientation_variance.roll =  covariance(KFNav::phi, KFNav::phi);
00473         state->orientation_variance.pitch =  covariance(KFNav::theta, KFNav::theta);
00474         state->orientation_variance.yaw =  covariance(KFNav::psi, KFNav::psi);
00475 
00476         state->header.stamp = ros::Time::now();
00477         state->header.frame_id = "local";
00478         stateHat.publish(state);
00479 
00480         geometry_msgs::TwistStamped::Ptr current(new geometry_msgs::TwistStamped());
00481         current->twist.linear.x = estimate(KFNav::xc);
00482         current->twist.linear.y = estimate(KFNav::yc);
00483         current->header.stamp = ros::Time::now();
00484         current->header.frame_id = "local";
00485         currentsHat.publish(current);
00486 
00487         std_msgs::Float32::Ptr buoyancy(new std_msgs::Float32());
00488         buoyancy->data = estimate(KFNav::buoyancy);
00489         buoyancyHat.publish(buoyancy);
00490 
00491         std_msgs::Float32::Ptr turns(new std_msgs::Float32());
00492         turns->data = estimate(KFNav::psi)/(2*M_PI);
00493         turns_pub.publish(turns);
00494 }
00495 
00496 void Estimator3D::start()
00497 {
00498         ros::NodeHandle ph("~");
00499         double Ts(0.1);
00500         ph.param("Ts",Ts,Ts);
00501         ros::Rate rate(1/Ts);
00502         nav.setTs(Ts);
00503 
00504         while (ros::ok())
00505         {
00506                 nav.predict(tauIn);
00507                 processMeasurements();
00508                 bool newArrived(false);
00509                 boost::mutex::scoped_lock l(meas_mux);
00510                 for(size_t i=0; i<newMeas.size(); ++i)  if ((newArrived = newMeas(i))) break;
00511 
00512                 
00513                 bool updateDVL = !newMeas(KFNav::r);
00514 
00515                 std::ostringstream out;
00516                 out<<newMeas;
00517                 ROS_INFO("Measurements %d:%s",KFNav::psi, out.str().c_str());
00518 
00519                 if (newArrived) nav.correct(nav.update(measurements, newMeas));
00520                 KFNav::vector tcstate = nav.getState();
00521                 if (tcstate(KFNav::buoyancy) < -30) tcstate(KFNav::buoyancy) = -10;
00522                 if (tcstate(KFNav::buoyancy) > 0) tcstate(KFNav::buoyancy) = 0;
00523                 nav.setState(tcstate);
00524                 l.unlock();
00525                 publishState();
00526 
00527                 
00528                 geometry_msgs::TransformStamped transform;
00529                 KFNav::vectorref cstate = nav.getState();
00530                 
00531                 if (updateDVL) dvl.current_r(cstate(KFNav::r));
00532 
00533                 transform.transform.translation.x = cstate(KFNav::xp);
00534                 transform.transform.translation.y = cstate(KFNav::yp);
00535                 transform.transform.translation.z = cstate(KFNav::zp);
00536 
00537 
00538                 labust::tools::quaternionFromEulerZYX(cstate(KFNav::phi),
00539                                 cstate(KFNav::theta),
00540                                 cstate(KFNav::psi),
00541                                 transform.transform.rotation);
00542                 if(absoluteEKF){
00543                         transform.child_frame_id = "base_link_abs";
00544                 } else{
00545                         transform.child_frame_id = "base_link";
00546                 }
00547                 transform.header.frame_id = "local";
00548                 transform.header.stamp = ros::Time::now();
00549                 broadcaster.sendTransform(transform);
00550 
00551                 rate.sleep();
00552                 ros::spinOnce();
00553         }
00554 }
00555 
00556 int main(int argc, char* argv[])
00557 {
00558         ros::init(argc,argv,"nav_3d");
00559         Estimator3D nav;
00560         nav.start();
00561         return 0;
00562 }
00563 
00564