nav_node.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/LDTravModel.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 
00048 #include <kdl/frames.hpp>
00049 #include <auv_msgs/NavSts.h>
00050 #include <auv_msgs/BodyForceReq.h>
00051 #include <nav_msgs/Odometry.h>
00052 #include <sensor_msgs/NavSatFix.h>
00053 #include <sensor_msgs/Imu.h>
00054 #include <sensor_msgs/FluidPressure.h>
00055 #include <geometry_msgs/TwistStamped.h>
00056 
00057 #include <tf/transform_broadcaster.h>
00058 #include <tf/transform_listener.h>
00059 
00060 #include <ros/ros.h>
00061 
00062 #include <boost/bind.hpp>
00063 #include <sstream>
00064 
00065 typedef labust::navigation::KFCore<labust::navigation::LDTravModel> KFNav;
00066 tf::TransformListener* listener;
00067 
00068 ros::Time t;
00069 double g_acc(9.81), rho(1025);
00070 
00071 void handleTau(KFNav::vector& tauIn, const auv_msgs::BodyForceReq::ConstPtr& tau)
00072 {
00073         tauIn(KFNav::X) = tau->wrench.force.x;
00074         tauIn(KFNav::Y) = tau->wrench.force.y;
00075         tauIn(KFNav::Z) = tau->wrench.force.z;
00076         tauIn(KFNav::N) = tau->wrench.torque.z;
00077 };
00078 
00079 void handleGPS(KFNav::vector& measurement, KFNav::vector& newFlag, const sensor_msgs::NavSatFix::ConstPtr& data)
00080 {
00081         //Calculate to X-Y tangent plane
00082         tf::StampedTransform transformDeg, transformLocal;
00083         try
00084         {
00085                 listener->lookupTransform("local", "gps_frame", ros::Time(0), transformLocal);
00086                 listener->lookupTransform("/worldLatLon", "local", ros::Time(0), transformDeg);
00087 
00088                 std::pair<double,double> posxy =
00089                                 labust::tools::deg2meter(data->latitude - transformDeg.getOrigin().y(),
00090                                                 data->longitude - transformDeg.getOrigin().x(),
00091                                                 transformDeg.getOrigin().y());
00092 
00093                 //correct for lever arm shift during pitch and roll
00094                 tf::Vector3 pos = tf::Vector3(posxy.first, posxy.second,0);
00095 
00096                 //xy(x) = pos.x();
00097                 //xy(y) = pos.y();
00098                 measurement(KFNav::xp) = posxy.first;
00099                 newFlag(KFNav::xp) = 1;
00100                 measurement(KFNav::yp) = posxy.second;
00101                 newFlag(KFNav::yp) = 1;
00102         }
00103         catch(tf::TransformException& ex)
00104         {
00105                 ROS_ERROR("%s",ex.what());
00106         }
00107 };
00108 
00109 void handleImu(KFNav::vector& rpy,  const sensor_msgs::Imu::ConstPtr& data)
00110 {
00111         enum {r,p,y,newMsg};
00112         double roll,pitch,yaw;
00113         static labust::math::unwrap unwrap;
00114 
00115         tf::StampedTransform transform;
00116         try
00117         {
00118                 t = data->header.stamp;
00119                 listener->lookupTransform("base_link", "imu_frame", ros::Time(0), transform);
00120                 tf::Quaternion meas(data->orientation.x,data->orientation.y,
00121                                 data->orientation.z,data->orientation.w);
00122                 tf::Quaternion result = meas*transform.getRotation();
00123 
00124                 KDL::Rotation::Quaternion(result.x(),result.y(),result.z(),result.w()).GetEulerZYX(yaw,pitch,roll);
00125                 /*labust::tools::eulerZYXFromQuaternion(
00126                                 Eigen::Quaternion<float>(result.x(),result.y(),
00127                                                 result.z(),result.w()),
00128                                 roll,pitch,yaw);*/
00129                 //ROS_INFO("Received RPY:%f,%f,%f",roll,pitch,yaw);
00130 
00131                 rpy(r) = roll;
00132                 rpy(p) = pitch;
00133                 rpy(y) = unwrap(yaw);
00134                 rpy(newMsg) = 1;
00135         }
00136         catch (tf::TransformException& ex)
00137         {
00138                 ROS_ERROR("%s",ex.what());
00139         }
00140 };
00141 
00142 void handleDvl(KFNav::vector& measurement, KFNav::vector& newFlag,
00143                 const geometry_msgs::TwistStamped::ConstPtr& data)
00144 {
00145         measurement(KFNav::u) = data->twist.linear.x;
00146         newFlag(KFNav::u)=1;
00147         measurement(KFNav::v) = data->twist.linear.y;
00148         newFlag(KFNav::v)=1;
00149         //measurement(KFNav::w) = data->twist.linear.z;
00150         //newFlag(KFNav::w)=1;
00151 };
00152 
00153 void handlePressure(KFNav::vector& measurement, KFNav::vector& newFlag,
00154                 const std_msgs::Float32::ConstPtr& data)
00155 {
00156         measurement(KFNav::zp) = data->data;
00157         newFlag(KFNav::zp)=1;
00158 };
00159 
00160 void configureNav(KFNav& nav, ros::NodeHandle& nh)
00161 {
00162         ROS_INFO("Configure navigation.");
00163 
00164         labust::simulation::DynamicsParams params;
00165         labust::tools::loadDynamicsParams(nh, params);
00166 
00167         ROS_INFO("Loaded dynamics params.");
00168 
00169         KFNav::ModelParams surge,sway,heave,yaw;
00170         surge.alpha = params.m + params.Ma(0,0);
00171         sway.alpha = params.m + params.Ma(1,1);
00172         heave.alpha = params.m + params.Ma(2,2);
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         sway.beta = params.Dlin(2,2);
00177         yaw.beta = params.Dlin(5,5);
00178         surge.betaa = params.Dquad(0,0);
00179         sway.betaa = params.Dquad(1,1);
00180         sway.betaa = params.Dquad(2,2);
00181         yaw.betaa = params.Dquad(5,5);
00182         nav.setParameters(surge,sway,heave,yaw);
00183 
00184         g_acc = params.g_acc;
00185         rho = params.rho;
00186 
00187         nav.initModel();
00188         labust::navigation::kfModelLoader(nav, nh, "ekfnav");
00189 }
00190 
00191 //consider making 2 corrections based on arrived measurements (async)
00192 int main(int argc, char* argv[])
00193 {
00194         ros::init(argc,argv,"rov_nav");
00195         ros::NodeHandle nh;
00196         KFNav nav;
00197         //Configure the navigation
00198         configureNav(nav,nh);
00199 
00200         double outlierR;
00201         nh.param("outlier_radius",outlierR,1.0);
00202 
00203         //Publishers
00204         ros::Publisher stateHat = nh.advertise<auv_msgs::NavSts>("stateHat",1);
00205         ros::Publisher stateMeas = nh.advertise<auv_msgs::NavSts>("meas",1);
00206         ros::Publisher currentTwist = nh.advertise<geometry_msgs::TwistStamped>("currentsHat",1);
00207         ros::Publisher bodyFlowFrame = nh.advertise<geometry_msgs::TwistStamped>("body_flow_frame_twist",1);
00208         //Subscribers
00209         KFNav::vector tau(KFNav::vector::Zero(KFNav::inputSize)),
00210                         measurements(KFNav::vector::Zero(KFNav::stateNum)),
00211                         newMeasFlag(KFNav::vector::Zero(KFNav::stateNum));
00212         KFNav::vector rpy(KFNav::vector::Zero(3+1));
00213 
00214         tf::TransformBroadcaster broadcast;
00215         listener = new tf::TransformListener();
00216 
00217         ros::Subscriber tauAch = nh.subscribe<auv_msgs::BodyForceReq>("tauAch", 1,
00218                         boost::bind(&handleTau,boost::ref(tau),_1));
00219         ros::Subscriber navFix = nh.subscribe<sensor_msgs::NavSatFix>("gps", 1,
00220                         boost::bind(&handleGPS,boost::ref(measurements),boost::ref(newMeasFlag),_1));
00221         ros::Subscriber imu = nh.subscribe<sensor_msgs::Imu>("imu", 1,
00222                         boost::bind(&handleImu,boost::ref(rpy),_1));
00223         ros::Subscriber dvl = nh.subscribe<geometry_msgs::TwistStamped>("dvl", 1,
00224                         boost::bind(&handleDvl,boost::ref(measurements),boost::ref(newMeasFlag),_1));
00225         ros::Subscriber pressure = nh.subscribe<sensor_msgs::FluidPressure>("pressure", 1,
00226                         boost::bind(&handlePressure,boost::ref(measurements),boost::ref(newMeasFlag),_1));
00227 
00228         ros::Rate rate(10);
00229 
00230         nav_msgs::Odometry odom;
00231         auv_msgs::NavSts meas,state;
00232         geometry_msgs::TwistStamped current, flowspeed;
00233         meas.header.frame_id = "local";
00234         state.header.frame_id = "local";
00235         current.header.frame_id = "local";
00236 
00237         labust::math::unwrap unwrap;
00238 
00239         while (ros::ok())
00240         {
00241                 nav.predict(tau);
00242                 if (rpy(3))
00243                 {
00244                         ROS_INFO("Set the yaw.");
00245                         double yaw = unwrap(rpy(2));
00246                         measurements(KFNav::psi) = yaw;
00247                         newMeasFlag(KFNav::psi) = 1;
00248                 }
00249 
00250                 bool anyNew = false;
00251                 for (size_t i=0; i<newMeasFlag.size(); ++i) if ((anyNew = (newMeasFlag(i)))) break;
00252 
00253                 if (anyNew)
00254                 {
00255                         ROS_INFO("Do update.");
00256                         nav.correct(nav.update(measurements, newMeasFlag));
00257                         ROS_INFO("Correction step.");
00258                 }
00259 
00260                 meas.orientation.roll = rpy(0);
00261                 meas.orientation.pitch = rpy(1);
00262                 meas.orientation.yaw = rpy(2);
00263                 meas.position.north = measurements(KFNav::xp);
00264                 meas.position.east = measurements(KFNav::yp);
00265                 meas.position.depth = measurements(KFNav::zp);
00266                 meas.body_velocity.x = measurements(KFNav::u);
00267                 meas.body_velocity.y = measurements(KFNav::v);
00268                 meas.body_velocity.z = measurements(KFNav::w);
00269                 stateMeas.publish(meas);
00270 
00271                 const KFNav::vector& estimate = nav.getState();
00272                 state.body_velocity.x = estimate(KFNav::u);
00273                 state.body_velocity.y = estimate(KFNav::v);
00274                 state.body_velocity.z = estimate(KFNav::w);
00275                 state.orientation_rate.yaw = estimate(KFNav::r);
00276                 state.position.north = estimate(KFNav::xp);
00277                 state.position.east = estimate(KFNav::yp);
00278                 state.position.depth = estimate(KFNav::zp);
00279                 current.twist.linear.x = estimate(KFNav::xc);
00280                 current.twist.linear.y = estimate(KFNav::yc);
00281 
00282                 const KFNav::matrix& covariance = nav.getStateCovariance();
00283                 state.position_variance.north = covariance(KFNav::xp, KFNav::xp);
00284                 state.position_variance.east = covariance(KFNav::yp, KFNav::yp);
00285                 state.position_variance.depth = covariance(KFNav::zp,KFNav::zp);
00286                 state.orientation_variance.yaw =  covariance(KFNav::psi, KFNav::psi);
00287 
00288                 try
00289                 {
00290                         tf::StampedTransform transformDeg;
00291                         listener->lookupTransform("/worldLatLon", "local", ros::Time(0), transformDeg);
00292 
00293                         std::pair<double, double> diffAngle = labust::tools::meter2deg(state.position.north,
00294                                         state.position.east,
00295                                         //The latitude angle
00296                                         transformDeg.getOrigin().y());
00297                         state.global_position.latitude = transformDeg.getOrigin().y() + diffAngle.first;
00298                         state.global_position.longitude = transformDeg.getOrigin().x() + diffAngle.second;
00299                 }
00300                 catch(tf::TransformException& ex)
00301                 {
00302                         ROS_WARN("Unable to set global position. %s",ex.what());
00303                 }
00304 
00305                 state.orientation.yaw = labust::math::wrapRad(estimate(KFNav::psi));
00306 
00307                 tf::StampedTransform transform;
00308                 transform.setOrigin(tf::Vector3(estimate(KFNav::xp), estimate(KFNav::yp), 0.0));
00309                 Eigen::Quaternion<float> q;
00310                 labust::tools::quaternionFromEulerZYX(rpy(0),rpy(1),estimate(KFNav::psi),q);
00311                 transform.setRotation(tf::Quaternion(q.x(),q.y(),q.z(),q.w()));
00312                 broadcast.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "local", "base_link"));
00313 
00314                 //Calculate the flow frame (instead of heading use course)
00315                 double xdot,ydot;
00316                 nav.getNEDSpeed(xdot,ydot);
00317                 labust::tools::quaternionFromEulerZYX(rpy(0),rpy(1),atan2(ydot,xdot),q);
00318                 transform.setRotation(tf::Quaternion(q.x(),q.y(),q.z(),q.w()));
00319                 broadcast.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "local", "base_link_flow"));
00320 
00321                 flowspeed.twist.linear.x = xdot;
00322                 flowspeed.twist.linear.y = ydot;
00323                 bodyFlowFrame.publish(flowspeed);
00324                 currentTwist.publish(current);
00325                 state.header.stamp = t;
00326                 stateHat.publish(state);
00327 
00328                 rate.sleep();
00329                 ros::spinOnce();
00330         }
00331 
00332         return 0;
00333 }
00334 
00335 


ldtravocean
Author(s):
autogenerated on Fri Feb 7 2014 11:37:01