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