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