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/xml/XMLReader.hpp>
00038 #include <labust/simulation/VehicleModel6DOF.hpp>
00039 #include <labust/vehicles/ScaleAllocation.hpp>
00040 #include <labust/tools/rosutils.hpp>
00041 #include <labust/tools/GeoUtilities.hpp>
00042
00043 #include <auv_msgs/NavSts.h>
00044 #include <auv_msgs/BodyForceReq.h>
00045 #include <nav_msgs/Odometry.h>
00046 #include <std_msgs/String.h>
00047 #include <sensor_msgs/NavSatFix.h>
00048 #include <sensor_msgs/Imu.h>
00049 #include <sensor_msgs/FluidPressure.h>
00050 #include <geometry_msgs/TwistStamped.h>
00051 #include <tf/transform_broadcaster.h>
00052 #include <tf/transform_listener.h>
00053 #include <ros/ros.h>
00054
00055 #include <Eigen/Dense>
00056
00057 #include <boost/bind.hpp>
00058
00059 #include <sstream>
00060 #include <string>
00061
00062 double modelLat(0),modelLon(0);
00063 double originLat(0), originLon(0);
00064 double thrustScale(1);
00065
00066 nav_msgs::Odometry* mapToUWSimOdometry(const labust::simulation::vector& eta,
00067 const labust::simulation::vector& nu,
00068 nav_msgs::Odometry* odom,
00069 tf::TransformListener& lisWorld)
00070 {
00071 using namespace labust::simulation;
00072 using namespace Eigen;
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082 tf::StampedTransform transform;
00083 try
00084 {
00085 lisWorld.lookupTransform("uwsim_frame", "base_link", ros::Time(0), transform);
00086 }
00087 catch (tf::TransformException& ex)
00088 {
00089 ROS_ERROR("%s",ex.what());
00090 }
00091
00092
00093
00094
00095
00096
00097
00098
00099 odom->twist.twist.linear.x = nu(VehicleModel6DOF::u);
00100 odom->twist.twist.linear.y = nu(VehicleModel6DOF::v);
00101 odom->twist.twist.linear.z = nu(VehicleModel6DOF::w);
00102
00103 odom->twist.twist.angular.x = nu(VehicleModel6DOF::p);
00104 odom->twist.twist.angular.y = nu(VehicleModel6DOF::q);
00105 odom->twist.twist.angular.z = nu(VehicleModel6DOF::r);
00106 odom->child_frame_id = "base_link";
00107
00108
00109 odom->pose.pose.orientation.x = transform.getRotation().x();
00110 odom->pose.pose.orientation.y = transform.getRotation().y();
00111 odom->pose.pose.orientation.z = transform.getRotation().z();
00112 odom->pose.pose.orientation.w = transform.getRotation().w();
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124 odom->pose.pose.position.x = transform.getOrigin().x();
00125 odom->pose.pose.position.y = transform.getOrigin().y();
00126 odom->pose.pose.position.z = transform.getOrigin().z();
00127
00128 odom->header.stamp = ros::Time::now();
00129 odom->header.frame_id = "uwsim_frame";
00130
00131 return odom;
00132 }
00133
00134 geometry_msgs::TwistStamped* mapToDvl(const labust::simulation::vector& eta,
00135 const labust::simulation::vector& nu, geometry_msgs::TwistStamped* dvl,
00136 tf::TransformBroadcaster& dvlBroadcast)
00137 {
00138 using namespace labust::simulation;
00139 dvl->twist.linear.x = nu(VehicleModel6DOF::u);
00140 dvl->twist.linear.y = nu(VehicleModel6DOF::v);
00141 dvl->twist.linear.z = nu(VehicleModel6DOF::w);
00142
00143 dvl->header.frame_id="base_link";
00144 dvl->header.stamp = ros::Time::now();
00145
00146 tf::Transform transform;
00147 transform.setOrigin(tf::Vector3(0, 0, 0));
00148 transform.setRotation(tf::createQuaternionFromRPY(0,0,0));
00149 dvlBroadcast.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "base_link", "imu_frame"));
00150
00151 return dvl;
00152 }
00153
00154 auv_msgs::NavSts* mapToNavSts(const labust::simulation::vector& eta, const labust::simulation::vector& nu, auv_msgs::NavSts* nav)
00155 {
00156 using namespace labust::simulation;
00157 using namespace Eigen;
00158 nav->global_position.latitude = modelLat;
00159 nav->global_position.longitude = modelLon;
00160
00161 nav->position.north = eta(VehicleModel6DOF::x);
00162 nav->position.east = eta(VehicleModel6DOF::y);
00163 nav->position.depth = eta(VehicleModel6DOF::z);
00164 nav->orientation.roll = eta(VehicleModel6DOF::phi);
00165 nav->orientation.pitch = eta(VehicleModel6DOF::theta);
00166 nav->orientation.yaw = eta(VehicleModel6DOF::psi);
00167
00168 nav->body_velocity.x = nu(VehicleModel6DOF::u);
00169 nav->body_velocity.y = nu(VehicleModel6DOF::v);
00170 nav->body_velocity.z = nu(VehicleModel6DOF::w);
00171 nav->orientation_rate.roll = nu(VehicleModel6DOF::p);
00172 nav->orientation_rate.pitch = nu(VehicleModel6DOF::q);
00173 nav->orientation_rate.yaw = nu(VehicleModel6DOF::r);
00174
00175 nav->header.stamp = ros::Time::now();
00176
00177 return nav;
00178 }
00179
00180 sensor_msgs::NavSatFix* mapToNavSatFix(const labust::simulation::vector& eta, const labust::simulation::vector& nu, sensor_msgs::NavSatFix* fix,
00181 const std::string& utmzone, tf::TransformListener& lisWorld, tf::TransformBroadcaster& gpsBroadcast)
00182 {
00183 using namespace labust::simulation;
00184 using namespace Eigen;
00185
00186 tf::StampedTransform transformLocal, transformDeg;
00187
00188 try
00189 {
00190
00191 lisWorld.lookupTransform("/worldLatLon", "/world", ros::Time(0), transformDeg);
00192 originLat = transformDeg.getOrigin().y();
00193 originLon = transformDeg.getOrigin().x();
00194 }
00195 catch (tf::TransformException& ex)
00196 {
00197 ROS_ERROR("%s",ex.what());
00198 }
00199
00200 try
00201 {
00202 lisWorld.lookupTransform("base_link", "gps_frame", ros::Time(0), transformLocal);
00203
00204
00205 fix->altitude = eta(VehicleModel6DOF::z) - transformLocal.getOrigin().z() ;
00206
00207 std::pair<double, double> diffAngle = labust::tools::meter2deg(eta(VehicleModel6DOF::x),
00208 eta(VehicleModel6DOF::y),
00209
00210 originLat);
00211
00212 modelLat = fix->latitude = originLat + diffAngle.first;
00213 modelLon = fix->longitude = originLon + diffAngle.second;
00214 fix->header.stamp = ros::Time::now();
00215 fix->header.frame_id = "worldLatLon";
00216
00217 tf::Transform transform;
00218 Eigen::Quaternion<float> q;
00219 transform.setOrigin(tf::Vector3(eta(VehicleModel6DOF::x),
00220 eta(VehicleModel6DOF::y),
00221 eta(VehicleModel6DOF::z)));
00222 labust::tools::quaternionFromEulerZYX(eta(VehicleModel6DOF::phi),
00223 eta(VehicleModel6DOF::theta),
00224 eta(VehicleModel6DOF::psi), q);
00225 transform.setRotation(tf::Quaternion(q.x(),q.y(),q.z(),q.w()));
00226 gpsBroadcast.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "local", "base_link_noisy"));
00227 }
00228 catch (tf::TransformException& ex)
00229 {
00230 ROS_ERROR("%s",ex.what());
00231 }
00232
00233 return fix;
00234 }
00235
00236 sensor_msgs::Imu* mapToImu(const labust::simulation::vector& eta,
00237 const labust::simulation::vector& nu, const labust::simulation::vector& nuacc,
00238 sensor_msgs::Imu* imu, tf::TransformBroadcaster& imuBroadcast)
00239 {
00240 using namespace labust::simulation;
00241 using namespace Eigen;
00242
00243 imu->header.stamp = ros::Time::now();
00244 imu->header.frame_id = "imu_frame";
00245 imu->linear_acceleration.x = nuacc(VehicleModel6DOF::x);
00246 imu->linear_acceleration.y = nuacc(VehicleModel6DOF::y);
00247 imu->linear_acceleration.z = nuacc(VehicleModel6DOF::z);
00248 imu->angular_velocity.x = nu(VehicleModel6DOF::p);
00249 imu->angular_velocity.y = nu(VehicleModel6DOF::q);
00250 imu->angular_velocity.z = nu(VehicleModel6DOF::r);
00251
00252 Quaternion<float> quat;
00253 labust::tools::quaternionFromEulerZYX(eta(VehicleModel6DOF::phi),
00254 eta(VehicleModel6DOF::theta),
00255 eta(VehicleModel6DOF::psi), quat);
00256
00257 imu->orientation.x = quat.x();
00258 imu->orientation.y = quat.y();
00259 imu->orientation.z = quat.z();
00260 imu->orientation.w = quat.w();
00261
00262 tf::Transform transform;
00263 transform.setOrigin(tf::Vector3(0, 0, 0));
00264 transform.setRotation(tf::createQuaternionFromRPY(0,0,0));
00265 imuBroadcast.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "base_link", "imu_frame"));
00266
00267 return imu;
00268 }
00269
00270 void handleTau(labust::simulation::vector* tauIn, const auv_msgs::BodyForceReq::ConstPtr& tau)
00271 {
00272 using namespace labust::simulation;
00273 (*tauIn)(VehicleModel6DOF::X) = thrustScale*tau->wrench.force.x;
00274 (*tauIn)(VehicleModel6DOF::Y) = thrustScale*tau->wrench.force.y;
00275 (*tauIn)(VehicleModel6DOF::Z) = thrustScale*tau->wrench.force.z;
00276 (*tauIn)(VehicleModel6DOF::K) = thrustScale*tau->wrench.torque.x;
00277 (*tauIn)(VehicleModel6DOF::M) = thrustScale*tau->wrench.torque.y;
00278 (*tauIn)(VehicleModel6DOF::N) = thrustScale*tau->wrench.torque.z;
00279 };
00280
00281 void handleCurrent(labust::simulation::vector* current, const std_msgs::String::ConstPtr& data)
00282 {
00283 std::istringstream out(data->data);
00284 float a;
00285 out>>(*current)(0)>>(*current)(1)>>(*current)(2);;
00286 };
00287
00288
00289
00290
00291
00292 int main(int argc, char* argv[])
00293 {
00294 ros::init(argc,argv,"model_node");
00295
00296
00297 labust::xml::ReaderPtr reader(new labust::xml::Reader(argv[1],true));
00298 reader->useNode(reader->value<_xmlNode*>("//configurations"));
00299 labust::simulation::VehicleModel6DOF model(reader);
00300
00301 ros::NodeHandle nh,ph("~");
00302
00303
00304 ros::Publisher state = nh.advertise<auv_msgs::NavSts>("meas",1);
00305 ros::Publisher stateNoisy = nh.advertise<auv_msgs::NavSts>("noisy_meas",1);
00306
00307 ros::Publisher tauAch = nh.advertise<auv_msgs::BodyForceReq>("tauAch",1);
00308 ros::Publisher gpsFix = nh.advertise<sensor_msgs::NavSatFix>("fix",1);
00309 ros::Publisher imuMeas = nh.advertise<sensor_msgs::Imu>("imu_model",1);
00310 ros::Publisher dvlMeas = nh.advertise<geometry_msgs::TwistStamped>("dvl",1);
00311 ros::Publisher pressureMeas = nh.advertise<sensor_msgs::FluidPressure>("pressure",1);
00312
00313 labust::simulation::vector tau(labust::simulation::zero_v(6)), current(labust::simulation::zero_v(3));
00314 ros::Subscriber tauSub = nh.subscribe<auv_msgs::BodyForceReq>("tauIn", 1, boost::bind(&handleTau,&tau,_1));
00315 ros::Subscriber curSub = nh.subscribe<std_msgs::String>("currents", 1, boost::bind(&handleCurrent,¤t,_1));
00316
00317 tf::TransformBroadcaster localFrame;
00318 tf::TransformListener lisWorld;
00319 bool publishWorld, useNoisy;
00320 double gpsTime;
00321 nh.param("LocalOriginLat",originLat,originLat);
00322 nh.param("LocalOriginLon",originLon,originLon);
00323 ph.param("publish_world", publishWorld, true);
00324 ph.param("use_noise", useNoisy, false);
00325 ph.param("gps_time",gpsTime,1.0);
00326 ph.param("thrustScale",thrustScale,1.0);
00327
00328 std::string utmzone;
00329
00330
00331
00332
00333
00334
00335 auv_msgs::NavSts nav,navNoisy;
00336 nav_msgs::Odometry odom;
00337 sensor_msgs::NavSatFix fix;
00338 sensor_msgs::Imu imu;
00339 geometry_msgs::TwistStamped dvl;
00340 sensor_msgs::FluidPressure depth;
00341
00342 double fs(10);
00343 int wrap(1);
00344 ph.param("Rate",fs,fs);
00345 ph.param("ModelWrap",wrap,wrap);
00346 ros::Rate rate(fs);
00347 model.setTs(1/(fs*wrap));
00348
00349
00350
00351
00352 Eigen::Matrix<float, 3,4> B;
00353 float cp(cos(M_PI/4)),sp(sin(M_PI/4));
00354 B<<cp,cp,cp,cp,
00355 sp,-sp,-sp,sp,
00356 1,-1,1,-1;
00357
00358 double maxThrust(100/(2*cp)),minThrust(-maxThrust);
00359 ph.param("maxThrust",maxThrust,maxThrust);
00360 ph.param("minThrust",minThrust,-maxThrust);
00361
00362
00363
00364 labust::vehicles::ScaleAllocation allocator(B,maxThrust,minThrust);
00365
00366 ros::Time lastGps = ros::Time::now();
00367 while (ros::ok())
00368 {
00369 using namespace labust::simulation;
00370 Eigen::Vector3f tauXYN,tauXYNsc;
00371 tauXYN<<tau(VehicleModel6DOF::X),tau(VehicleModel6DOF::Y),tau(VehicleModel6DOF::N);
00372 double scale = allocator.scale(tauXYN,&tauXYNsc);
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384 auv_msgs::BodyForceReq t;
00385
00386 tau(VehicleModel6DOF::X) = t.wrench.force.x = tauXYNsc(0);
00387 tau(VehicleModel6DOF::Y) = t.wrench.force.y = tauXYNsc(1);
00388 t.wrench.force.z = tau(VehicleModel6DOF::Z);
00389 t.wrench.torque.x = tau(VehicleModel6DOF::K);
00390 t.wrench.torque.y = tau(VehicleModel6DOF::M);
00391 tau(VehicleModel6DOF::N) = t.wrench.torque.z = tauXYNsc(2);
00392
00393 t.header.stamp = ros::Time::now();
00394
00395
00396
00397
00398
00399
00400
00401 if (scale>1)
00402 {
00403
00404 t.disable_axis.x = t.disable_axis.y = t.disable_axis.yaw = 1;
00405 }
00406
00407 tauAch.publish(t);
00408
00409 model.setCurrent(current);
00410
00411 for (size_t i=0; i<wrap;++i) model.step(tau);
00412
00413
00414 state.publish(*mapToNavSts(model.Eta(),model.Nu(),&nav));
00415 stateNoisy.publish(*mapToNavSts(model.EtaNoisy(),model.NuNoisy(),&navNoisy));
00416
00417 const vector& Nu = (useNoisy?model.NuNoisy():model.Nu());
00418 const vector& Eta = (useNoisy?model.EtaNoisy():model.Eta());
00419 if ((ros::Time::now()-lastGps).sec >= gpsTime)
00420 {
00421 mapToNavSatFix(Eta,Nu,&fix,utmzone,lisWorld,localFrame);
00422 if (fix.altitude >= 0)
00423 {
00424 gpsFix.publish(fix);
00425 }
00426 lastGps = ros::Time::now();
00427 }
00428
00429 imuMeas.publish(*mapToImu(Eta,Nu,model.NuAcc(),&imu,localFrame));
00430 dvlMeas.publish(*mapToDvl(Eta,Nu,&dvl,localFrame));
00431 depth.fluid_pressure = model.getPressure(Eta(VehicleModel6DOF::z));
00432 depth.header.frame_id = "local";
00433 pressureMeas.publish(depth);
00434
00435 tf::Transform transform;
00436 transform.setOrigin(tf::Vector3(originLon, originLat, 0));
00437 transform.setRotation(tf::createQuaternionFromRPY(0,0,0));
00438 Eigen::Quaternion<float> q;
00439 labust::tools::quaternionFromEulerZYX(M_PI,0,M_PI/2,q);
00440 if (publishWorld)
00441 {
00442 localFrame.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "/worldLatLon", "/world"));
00443 transform.setOrigin(tf::Vector3(0, 0, 0));
00444 transform.setRotation(tf::Quaternion(q.x(),q.y(),q.z(),q.w()));
00445 localFrame.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "/world", "local"));
00446 }
00447
00448 tf::Transform transform3;
00449 transform3.setOrigin(tf::Vector3(0, 0, 0));
00450 q = q.conjugate();
00451 transform3.setRotation(tf::Quaternion(q.x(),q.y(),q.z(),q.w()));
00452 localFrame.sendTransform(tf::StampedTransform(transform3, ros::Time::now(), "local", "uwsim_frame"));
00453
00454 const vector& eta = model.Eta();
00455
00456 transform.setOrigin(tf::Vector3(eta(VehicleModel6DOF::x),
00457 eta(VehicleModel6DOF::y),
00458 eta(VehicleModel6DOF::z)));
00459 labust::tools::quaternionFromEulerZYX(eta(VehicleModel6DOF::phi),
00460 eta(VehicleModel6DOF::theta),
00461 eta(VehicleModel6DOF::psi), q);
00462 transform.setRotation(tf::Quaternion(q.x(),q.y(),q.z(),q.w()));
00463 localFrame.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "local", "base_link_sim"));
00464
00465 tf::Transform transform2;
00466 transform2.setOrigin(tf::Vector3(0, 0, -0.25));
00467 transform2.setRotation(tf::createQuaternionFromRPY(0,0,0));
00468 localFrame.sendTransform(tf::StampedTransform(transform2, ros::Time::now(), "base_link", "gps_frame"));
00469
00470 rate.sleep();
00471 ros::spinOnce();
00472 }
00473
00474 return 0;
00475 }
00476