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 #include "robot_localization/navsat_transform.h"
00034 #include "robot_localization/filter_common.h"
00035 #include "robot_localization/navsat_conversions.h"
00036
00037 #include <tf/tfMessage.h>
00038 #include <tf/transform_broadcaster.h>
00039
00040 namespace RobotLocalization
00041 {
00042 NavSatTransform::NavSatTransform() :
00043 magneticDeclination_(0.0),
00044 utmOdomTfYaw_(0.0),
00045 yawOffset_(0.0),
00046 broadcastUtmTransform_(false),
00047 hasOdom_(false),
00048 hasGps_(false),
00049 hasImu_(false),
00050 transformGood_(false),
00051 gpsUpdated_(false),
00052 odomUpdated_(false),
00053 publishGps_(false),
00054 useOdometryYaw_(false),
00055 worldFrameId_("odom"),
00056 utmZone_("")
00057 {
00058 latestUtmCovariance_.resize(POSE_SIZE, POSE_SIZE);
00059 }
00060
00061 NavSatTransform::~NavSatTransform()
00062 {
00063
00064 }
00065
00066 void NavSatTransform::odomCallback(const nav_msgs::OdometryConstPtr& msg)
00067 {
00068 tf::poseMsgToTF(msg->pose.pose, latestWorldPose_);
00069 worldFrameId_ = msg->header.frame_id;
00070 hasOdom_ = true;
00071 odomUpdateTime_ = msg->header.stamp;
00072 odomUpdated_ = true;
00073
00074
00075
00076
00077
00078 if(useOdometryYaw_ && !transformGood_)
00079 {
00080 tf::quaternionMsgToTF(msg->pose.pose.orientation, latestOrientation_);
00081 hasImu_ = true;
00082 }
00083 }
00084
00085 void NavSatTransform::gpsFixCallback(const sensor_msgs::NavSatFixConstPtr& msg)
00086 {
00087 hasGps_ = (msg->status.status != sensor_msgs::NavSatStatus::STATUS_NO_FIX &&
00088 !std::isnan(msg->altitude) &&
00089 !std::isnan(msg->latitude) &&
00090 !std::isnan(msg->longitude));
00091
00092 if(hasGps_)
00093 {
00094 double utmX = 0;
00095 double utmY = 0;
00096 NavsatConversions::LLtoUTM(msg->latitude, msg->longitude, utmY, utmX, utmZone_);
00097 latestUtmPose_.setOrigin(tf::Vector3(utmX, utmY, msg->altitude));
00098 latestUtmCovariance_.setZero();
00099
00100
00101 for (size_t i = 0; i < POSITION_SIZE; i++)
00102 {
00103 for (size_t j = 0; j < POSITION_SIZE; j++)
00104 {
00105 latestUtmCovariance_(i, j) = msg->position_covariance[POSITION_SIZE * i + j];
00106 }
00107 }
00108
00109 gpsUpdateTime_ = msg->header.stamp;
00110 gpsUpdated_ = true;
00111 }
00112 }
00113
00114 void NavSatTransform::imuCallback(const sensor_msgs::ImuConstPtr& msg)
00115 {
00116 tf::quaternionMsgToTF(msg->orientation, latestOrientation_);
00117 hasImu_ = true;
00118 }
00119
00120 void NavSatTransform::computeTransform()
00121 {
00122
00123
00124
00125 if(!transformGood_ &&
00126 hasOdom_ &&
00127 hasGps_ &&
00128 hasImu_)
00129 {
00130
00131 tf::Matrix3x3 mat(latestOrientation_);
00132
00133
00134 double imuRoll;
00135 double imuPitch;
00136 double imuYaw;
00137 mat.getRPY(imuRoll, imuPitch, imuYaw);
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156 imuYaw += (magneticDeclination_ + yawOffset_);
00157
00158 ROS_INFO_STREAM("Corrected for magnetic declination of " << std::fixed << magneticDeclination_ <<
00159 ", user-specified offset of " << yawOffset_ << ", and fixed offset of " << (M_PI / 2.0) <<
00160 ". Transform heading factor is now " << imuYaw);
00161
00162
00163 tf::Quaternion imuQuat;
00164 imuQuat.setRPY(0.0, 0.0, imuYaw);
00165
00166
00167
00168
00169 tf::Pose utmPoseWithOrientation;
00170 utmPoseWithOrientation.setOrigin(latestUtmPose_.getOrigin());
00171 utmPoseWithOrientation.setRotation(imuQuat);
00172 utmWorldTransform_.mult(latestWorldPose_, utmPoseWithOrientation.inverse());
00173
00174 utmWorldTransInverse_ = utmWorldTransform_.inverse();
00175
00176 double roll = 0;
00177 double pitch = 0;
00178 double yaw = 0;
00179 mat.setRotation(latestWorldPose_.getRotation());
00180 mat.getRPY(roll, pitch, yaw);
00181
00182 ROS_INFO_STREAM("Latest world frame pose is: " << std::fixed <<
00183 "\nPosition: (" << latestWorldPose_.getOrigin().getX() << ", " <<
00184 latestWorldPose_.getOrigin().getY() << ", " <<
00185 latestWorldPose_.getOrigin().getZ() << ")" <<
00186 "\nOrientation: (" << roll << ", " <<
00187 pitch << ", " <<
00188 yaw << ")");
00189
00190 mat.setRotation(utmWorldTransform_.getRotation());
00191 mat.getRPY(roll, pitch, yaw);
00192
00193 ROS_INFO_STREAM("World frame->utm transform is " << std::fixed <<
00194 "\nPosition: (" << utmWorldTransform_.getOrigin().getX() << ", " <<
00195 utmWorldTransform_.getOrigin().getY() << ", " <<
00196 utmWorldTransform_.getOrigin().getZ() << ")" <<
00197 "\nOrientation: (" << roll << ", " <<
00198 pitch << ", " <<
00199 yaw << ")");
00200
00201 transformGood_ = true;
00202 }
00203 }
00204
00205 bool NavSatTransform::prepareGpsOdometry(nav_msgs::Odometry &gpsOdom)
00206 {
00207 bool newData = false;
00208
00209 if(transformGood_ && gpsUpdated_)
00210 {
00211 tf::Pose transformedUtm;
00212
00213 transformedUtm.mult(utmWorldTransform_, latestUtmPose_);
00214 transformedUtm.setRotation(tf::Quaternion::getIdentity());
00215
00216
00217 tf::Matrix3x3 rot(utmWorldTransform_.getRotation());
00218 Eigen::MatrixXd rot6d(POSE_SIZE, POSE_SIZE);
00219 rot6d.setIdentity();
00220
00221 for(size_t rInd = 0; rInd < POSITION_SIZE; ++rInd)
00222 {
00223 rot6d(rInd, 0) = rot.getRow(rInd).getX();
00224 rot6d(rInd, 1) = rot.getRow(rInd).getY();
00225 rot6d(rInd, 2) = rot.getRow(rInd).getZ();
00226 rot6d(rInd+POSITION_SIZE, 3) = rot.getRow(rInd).getX();
00227 rot6d(rInd+POSITION_SIZE, 4) = rot.getRow(rInd).getY();
00228 rot6d(rInd+POSITION_SIZE, 5) = rot.getRow(rInd).getZ();
00229 }
00230
00231
00232 latestUtmCovariance_ = rot6d * latestUtmCovariance_.eval() * rot6d.transpose();
00233
00234
00235 tf::poseTFToMsg(transformedUtm, gpsOdom.pose.pose);
00236 gpsOdom.pose.pose.position.z = (zeroAltitude_ ? 0.0 : gpsOdom.pose.pose.position.z);
00237
00238
00239 for (size_t i = 0; i < POSE_SIZE; i++)
00240 {
00241 for (size_t j = 0; j < POSE_SIZE; j++)
00242 {
00243 gpsOdom.pose.covariance[POSE_SIZE * i + j] = latestUtmCovariance_(i, j);
00244 }
00245 }
00246
00247 gpsOdom.header.frame_id = worldFrameId_;
00248 gpsOdom.header.stamp = gpsUpdateTime_;
00249
00250
00251 gpsUpdated_ = false;
00252 newData = true;
00253 }
00254
00255 return newData;
00256 }
00257
00258 bool NavSatTransform::prepareFilteredGps(sensor_msgs::NavSatFix &filteredGps)
00259 {
00260 bool newData = false;
00261
00262 if(transformGood_ && odomUpdated_)
00263 {
00264 tf::Pose odomAsUtm;
00265
00266 odomAsUtm.mult(utmWorldTransInverse_, latestWorldPose_);
00267 odomAsUtm.setRotation(tf::Quaternion::getIdentity());
00268
00269
00270 tf::Matrix3x3 rot(utmWorldTransInverse_.getRotation());
00271 Eigen::MatrixXd rot6d(POSE_SIZE, POSE_SIZE);
00272 rot6d.setIdentity();
00273
00274 for(size_t rInd = 0; rInd < POSITION_SIZE; ++rInd)
00275 {
00276 rot6d(rInd, 0) = rot.getRow(rInd).getX();
00277 rot6d(rInd, 1) = rot.getRow(rInd).getY();
00278 rot6d(rInd, 2) = rot.getRow(rInd).getZ();
00279 rot6d(rInd+POSITION_SIZE, 3) = rot.getRow(rInd).getX();
00280 rot6d(rInd+POSITION_SIZE, 4) = rot.getRow(rInd).getY();
00281 rot6d(rInd+POSITION_SIZE, 5) = rot.getRow(rInd).getZ();
00282 }
00283
00284
00285 latestOdomCovariance_ = rot6d * latestOdomCovariance_.eval() * rot6d.transpose();
00286
00287
00288 NavsatConversions::UTMtoLL(odomAsUtm.getOrigin().getY(), odomAsUtm.getOrigin().getX(), utmZone_, filteredGps.latitude, filteredGps.longitude);
00289 filteredGps.altitude = odomAsUtm.getOrigin().getZ();
00290
00291
00292 for (size_t i = 0; i < POSITION_SIZE; i++)
00293 {
00294 for (size_t j = 0; j < POSITION_SIZE; j++)
00295 {
00296 filteredGps.position_covariance[POSITION_SIZE * i + j] = latestUtmCovariance_(i, j);
00297 }
00298 }
00299
00300 filteredGps.position_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_KNOWN;
00301 filteredGps.status.status = sensor_msgs::NavSatStatus::STATUS_GBAS_FIX;
00302 filteredGps.header.frame_id = "gps";
00303 filteredGps.header.stamp = odomUpdateTime_;
00304
00305
00306 odomUpdated_ = false;
00307 newData = true;
00308 }
00309
00310 return newData;
00311 }
00312
00313 void NavSatTransform::run()
00314 {
00315 ros::Time::init();
00316
00317 double frequency = 10.0;
00318 double delay = 0.0;
00319
00320 ros::NodeHandle nh;
00321 ros::NodeHandle nhPriv("~");
00322
00323
00324 nhPriv.getParam("magnetic_declination_radians", magneticDeclination_);
00325 nhPriv.param("yaw_offset", yawOffset_, 0.0);
00326 nhPriv.param("broadcast_utm_transform", broadcastUtmTransform_, false);
00327 nhPriv.param("zero_altitude", zeroAltitude_, false);
00328 nhPriv.param("publish_filtered_gps", publishGps_, false);
00329 nhPriv.param("use_odometry_yaw", useOdometryYaw_, false);
00330 nhPriv.param("frequency", frequency, 10.0);
00331 nhPriv.param("delay", delay, 0.0);
00332
00333
00334 ros::Subscriber odomSub = nh.subscribe("odometry/filtered", 1, &NavSatTransform::odomCallback, this);
00335 ros::Subscriber gpsSub = nh.subscribe("gps/fix", 1, &NavSatTransform::gpsFixCallback, this);
00336 ros::Subscriber imuSub;
00337
00338 if(!useOdometryYaw_)
00339 {
00340 imuSub = nh.subscribe("imu/data", 1, &NavSatTransform::imuCallback, this);
00341 }
00342
00343 ros::Publisher gpsOdomPub = nh.advertise<nav_msgs::Odometry>("odometry/gps", 10);
00344 ros::Publisher filteredGpsPub;
00345
00346 if(publishGps_)
00347 {
00348 filteredGpsPub = nh.advertise<sensor_msgs::NavSatFix>("gps/filtered", 10);
00349 }
00350
00351 tf::TransformBroadcaster utmBroadcaster;
00352 tf::StampedTransform utmTransformStamped;
00353 utmTransformStamped.child_frame_id_ = "utm";
00354
00355
00356
00357 ros::Duration startDelay(delay);
00358 startDelay.sleep();
00359
00360 ros::Rate rate(frequency);
00361 while(ros::ok())
00362 {
00363 ros::spinOnce();
00364
00365 if(!transformGood_)
00366 {
00367 computeTransform();
00368
00369 if(transformGood_ && !useOdometryYaw_)
00370 {
00371
00372 imuSub.shutdown();
00373 }
00374 }
00375 else
00376 {
00377 nav_msgs::Odometry gpsOdom;
00378 if(prepareGpsOdometry(gpsOdom))
00379 {
00380 gpsOdomPub.publish(gpsOdom);
00381 }
00382
00383 if(publishGps_)
00384 {
00385 sensor_msgs::NavSatFix odomGps;
00386 if(prepareFilteredGps(odomGps))
00387 {
00388 filteredGpsPub.publish(odomGps);
00389 }
00390 }
00391
00392
00393
00394 if(transformGood_ && broadcastUtmTransform_)
00395 {
00396 utmTransformStamped.setData(utmWorldTransform_);
00397 utmTransformStamped.frame_id_ = worldFrameId_;
00398 utmTransformStamped.stamp_ = ros::Time::now();
00399 utmBroadcaster.sendTransform(utmTransformStamped);
00400 }
00401 }
00402
00403 rate.sleep();
00404 }
00405
00406 }
00407 }