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 #ifndef UBLOX_GPS_NODE_H
00031 #define UBLOX_GPS_NODE_H
00032
00033
00034 #include <vector>
00035 #include <set>
00036
00037 #include <boost/algorithm/string.hpp>
00038 #include <boost/lexical_cast.hpp>
00039 #include <boost/regex.hpp>
00040
00041 #include <ros/ros.h>
00042 #include <ros/console.h>
00043 #include <ros/serialization.h>
00044 #include <diagnostic_updater/diagnostic_updater.h>
00045 #include <diagnostic_updater/publisher.h>
00046
00047 #include <geometry_msgs/TwistWithCovarianceStamped.h>
00048 #include <geometry_msgs/Vector3Stamped.h>
00049 #include <sensor_msgs/NavSatFix.h>
00050
00051 #include <ublox_msgs/ublox_msgs.h>
00052
00053 #include <ublox_gps/gps.h>
00054 #include <ublox_gps/utils.h>
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00081 namespace ublox_node {
00082
00084 const static uint32_t kROSQueueSize = 1;
00086 const static uint16_t kDefaultMeasPeriod = 250;
00088 const static uint32_t kSubscribeRate = 1;
00090 const static uint32_t kNavSvInfoSubscribeRate = 20;
00091
00092
00094 boost::shared_ptr<diagnostic_updater::Updater> updater;
00096 boost::shared_ptr<ros::NodeHandle> nh;
00097
00099 ublox_gps::Gps gps;
00101 std::set<std::string> supported;
00103
00107 std::map<std::string, bool> enabled;
00109 std::string frame_id;
00112 int fix_status_service;
00114 uint16_t meas_rate;
00116 uint16_t nav_rate;
00118 std::vector<uint8_t> rtcm_ids;
00120 std::vector<uint8_t> rtcm_rates;
00121
00123 struct UbloxTopicDiagnostic {
00124 UbloxTopicDiagnostic() {}
00125
00134 UbloxTopicDiagnostic (std::string topic, double freq_tol, int freq_window) {
00135 const double target_freq = 1.0 / (meas_rate * 1e-3 * nav_rate);
00136 min_freq = target_freq;
00137 max_freq = target_freq;
00138 diagnostic_updater::FrequencyStatusParam freq_param(&min_freq, &max_freq,
00139 freq_tol, freq_window);
00140 diagnostic = new diagnostic_updater::HeaderlessTopicDiagnostic(topic,
00141 *updater,
00142 freq_param);
00143 }
00144
00155 UbloxTopicDiagnostic (std::string topic, double freq_min, double freq_max,
00156 double freq_tol, int freq_window) {
00157 min_freq = freq_min;
00158 max_freq = freq_max;
00159 diagnostic_updater::FrequencyStatusParam freq_param(&min_freq, &max_freq,
00160 freq_tol, freq_window);
00161 diagnostic = new diagnostic_updater::HeaderlessTopicDiagnostic(topic,
00162 *updater,
00163 freq_param);
00164 }
00165
00167 diagnostic_updater::HeaderlessTopicDiagnostic *diagnostic;
00169 double min_freq;
00171 double max_freq;
00172 };
00173
00175 struct FixDiagnostic {
00176 FixDiagnostic() {}
00177
00187 FixDiagnostic (std::string name, double freq_tol, int freq_window,
00188 double stamp_min) {
00189 const double target_freq = 1.0 / (meas_rate * 1e-3 * nav_rate);
00190 min_freq = target_freq;
00191 max_freq = target_freq;
00192 diagnostic_updater::FrequencyStatusParam freq_param(&min_freq, &max_freq,
00193 freq_tol, freq_window);
00194 double stamp_max = meas_rate * 1e-3 * (1 + freq_tol);
00195 diagnostic_updater::TimeStampStatusParam time_param(stamp_min, stamp_max);
00196 diagnostic = new diagnostic_updater::TopicDiagnostic(name,
00197 *updater,
00198 freq_param,
00199 time_param);
00200 }
00201
00203 diagnostic_updater::TopicDiagnostic *diagnostic;
00205 double min_freq;
00207 double max_freq;
00208 };
00209
00211 FixDiagnostic freq_diag;
00212
00228 uint8_t modelFromString(const std::string& model);
00229
00239 uint8_t fixModeFromString(const std::string& mode);
00240
00248 template <typename V, typename T>
00249 void checkMin(V val, T min, std::string name) {
00250 if(val < min) {
00251 std::stringstream oss;
00252 oss << "Invalid settings: " << name << " must be > " << min;
00253 throw std::runtime_error(oss.str());
00254 }
00255 }
00256
00265 template <typename V, typename T>
00266 void checkRange(V val, T min, T max, std::string name) {
00267 if(val < min || val > max) {
00268 std::stringstream oss;
00269 oss << "Invalid settings: " << name << " must be in range [" << min <<
00270 ", " << max << "].";
00271 throw std::runtime_error(oss.str());
00272 }
00273 }
00274
00283 template <typename V, typename T>
00284 bool checkRange(std::vector<V> val, T min, T max, std::string name) {
00285 for(size_t i = 0; i < val.size(); i++) {
00286 std::stringstream oss;
00287 oss << name << "[" << i << "]";
00288 checkRange(val[i], min, max, name);
00289 }
00290 }
00291
00299 template <typename U>
00300 bool getRosUint(const std::string& key, U &u) {
00301 int param;
00302 if (!nh->getParam(key, param)) return false;
00303
00304 U min = 0;
00305 U max = ~0;
00306 checkRange(param, min, max, key);
00307
00308 u = (U) param;
00309 return true;
00310 }
00311
00320 template <typename U, typename V>
00321 void getRosUint(const std::string& key, U &u, V default_val) {
00322 if(!getRosUint(key, u))
00323 u = default_val;
00324 }
00325
00331 template <typename U>
00332 bool getRosUint(const std::string& key, std::vector<U> &u) {
00333 std::vector<int> param;
00334 if (!nh->getParam(key, param)) return false;
00335
00336
00337 U min = 0;
00338 U max = ~0;
00339 checkRange(param, min, max, key);
00340
00341
00342 u.insert(u.begin(), param.begin(), param.end());
00343 return true;
00344 }
00345
00353 template <typename I>
00354 bool getRosInt(const std::string& key, I &u) {
00355 int param;
00356 if (!nh->getParam(key, param)) return false;
00357
00358 I min = 1 << (sizeof(I) * 8 - 1);
00359 I max = (I)~(min);
00360 checkRange(param, min, max, key);
00361
00362 u = (I) param;
00363 return true;
00364 }
00365
00374 template <typename U, typename V>
00375 void getRosInt(const std::string& key, U &u, V default_val) {
00376 if(!getRosInt(key, u))
00377 u = default_val;
00378 }
00379
00385 template <typename I>
00386 bool getRosInt(const std::string& key, std::vector<I> &i) {
00387 std::vector<int> param;
00388 if (!nh->getParam(key, param)) return false;
00389
00390
00391 I min = 1 << (sizeof(I) * 8 - 1);
00392 I max = (I)~(min);
00393 checkRange(param, min, max, key);
00394
00395
00396 i.insert(i.begin(), param.begin(), param.end());
00397 return true;
00398 }
00399
00408 template <typename MessageT>
00409 void publish(const MessageT& m, const std::string& topic) {
00410 static ros::Publisher publisher = nh->advertise<MessageT>(topic,
00411 kROSQueueSize);
00412 publisher.publish(m);
00413 }
00414
00420 bool supportsGnss(std::string gnss) {
00421 return supported.count(gnss) > 0;
00422 }
00423
00430 class ComponentInterface {
00431 public:
00437 virtual void getRosParams() = 0;
00438
00443 virtual bool configureUblox() = 0;
00444
00450 virtual void initializeRosDiagnostics() = 0;
00451
00455 virtual void subscribe() = 0;
00456 };
00457
00458 typedef boost::shared_ptr<ComponentInterface> ComponentPtr;
00459
00475 class UbloxNode : public virtual ComponentInterface {
00476 public:
00478 const static double kResetWait = 10.0;
00480 const static double kPollDuration = 1.0;
00481
00483 const static float kDiagnosticPeriod = 0.2;
00485 const static double kFixFreqTol = 0.15;
00487 const static double kFixFreqWindow = 10;
00489 const static double kTimeStampStatusMin = 0;
00490
00494 UbloxNode();
00495
00499 void getRosParams();
00500
00505 bool configureUblox();
00506
00510 void subscribe();
00511
00515 void initializeRosDiagnostics();
00516
00520 void printInf(const ublox_msgs::Inf &m, uint8_t id);
00521
00522 private:
00523
00527 void initializeIo();
00528
00533 void initialize();
00534
00538 void shutdown();
00539
00544 bool resetDevice();
00545
00551 void processMonVer();
00552
00557 void addFirmwareInterface();
00558
00566 void addProductInterface(std::string product_category,
00567 std::string ref_rov = "");
00568
00573 void pollMessages(const ros::TimerEvent& event);
00574
00578 void configureInf();
00579
00581
00585 std::vector<boost::shared_ptr<ComponentInterface> > components_;
00586
00588 float protocol_version_;
00589
00591 std::string device_;
00593 std::string dynamic_model_;
00595 std::string fix_mode_;
00597 uint8_t dmodel_;
00599 uint8_t fmode_;
00601 uint32_t baudrate_;
00603 uint16_t uart_in_;
00605 uint16_t uart_out_;
00607 uint16_t usb_tx_;
00609
00610 bool set_usb_;
00612 uint16_t usb_in_;
00614 uint16_t usb_out_ ;
00616 double rate_;
00618 bool set_dat_;
00620 ublox_msgs::CfgDAT cfg_dat_;
00622 bool enable_sbas_;
00624 bool enable_ppp_;
00626 uint8_t sbas_usage_;
00628 uint8_t max_sbas_;
00630 uint8_t dr_limit_;
00632 ublox_msgs::CfgCFG load_;
00634 ublox_msgs::CfgCFG save_;
00635 };
00636
00642 class UbloxFirmware : public virtual ComponentInterface {
00643 public:
00647 void initializeRosDiagnostics();
00648
00649 protected:
00653 virtual void fixDiagnostic(
00654 diagnostic_updater::DiagnosticStatusWrapper& stat) = 0;
00655 };
00656
00660 class UbloxFirmware6 : public UbloxFirmware {
00661 public:
00662 UbloxFirmware6();
00663
00667 void getRosParams();
00668
00673 bool configureUblox();
00674
00678 void subscribe();
00679
00680 protected:
00685 void fixDiagnostic(diagnostic_updater::DiagnosticStatusWrapper& stat);
00686
00687 private:
00695 void callbackNavPosLlh(const ublox_msgs::NavPOSLLH& m);
00696
00703 void callbackNavVelNed(const ublox_msgs::NavVELNED& m);
00704
00711 void callbackNavSol(const ublox_msgs::NavSOL& m);
00712
00714 ublox_msgs::NavPOSLLH last_nav_pos_;
00716 ublox_msgs::NavVELNED last_nav_vel_;
00718 ublox_msgs::NavSOL last_nav_sol_;
00720 sensor_msgs::NavSatFix fix_;
00722 geometry_msgs::TwistWithCovarianceStamped velocity_;
00723
00725 ublox_msgs::CfgNMEA6 cfg_nmea_;
00727 bool set_nmea_;
00728 };
00729
00739 template<typename NavPVT>
00740 class UbloxFirmware7Plus : public UbloxFirmware {
00741 public:
00750 void callbackNavPvt(const NavPVT& m) {
00751 if(enabled["nav_pvt"]) {
00752
00753 static ros::Publisher publisher = nh->advertise<NavPVT>("navpvt",
00754 kROSQueueSize);
00755 publisher.publish(m);
00756 }
00757
00758
00759
00760
00761 static ros::Publisher fixPublisher =
00762 nh->advertise<sensor_msgs::NavSatFix>("fix", kROSQueueSize);
00763
00764 sensor_msgs::NavSatFix fix;
00765 fix.header.frame_id = frame_id;
00766
00767 uint8_t valid_time = m.VALID_DATE | m.VALID_TIME | m.VALID_FULLY_RESOLVED;
00768 if (m.valid & valid_time == valid_time
00769 && m.flags2 & m.FLAGS2_CONFIRMED_AVAILABLE) {
00770
00771 fix.header.stamp.sec = toUtcSeconds(m);
00772 fix.header.stamp.nsec = m.nano;
00773 } else {
00774
00775 fix.header.stamp = ros::Time::now();
00776 }
00777
00778 fix.latitude = m.lat * 1e-7;
00779 fix.longitude = m.lon * 1e-7;
00780 fix.altitude = m.height * 1e-3;
00781
00782 bool fixOk = m.flags & m.FLAGS_GNSS_FIX_OK;
00783 if (fixOk && m.fixType >= m.FIX_TYPE_2D) {
00784 fix.status.status = fix.status.STATUS_FIX;
00785 if(m.flags & m.CARRIER_PHASE_FIXED)
00786 fix.status.status = fix.status.STATUS_GBAS_FIX;
00787 }
00788 else {
00789 fix.status.status = fix.status.STATUS_NO_FIX;
00790 }
00791
00792 fix.status.service = fix_status_service;
00793
00794
00795 const double varH = pow(m.hAcc / 1000.0, 2);
00796 const double varV = pow(m.vAcc / 1000.0, 2);
00797 fix.position_covariance[0] = varH;
00798 fix.position_covariance[4] = varH;
00799 fix.position_covariance[8] = varV;
00800 fix.position_covariance_type =
00801 sensor_msgs::NavSatFix::COVARIANCE_TYPE_DIAGONAL_KNOWN;
00802
00803 fixPublisher.publish(fix);
00804
00805
00806
00807
00808 static ros::Publisher velocityPublisher =
00809 nh->advertise<geometry_msgs::TwistWithCovarianceStamped>("fix_velocity",
00810 kROSQueueSize);
00811 geometry_msgs::TwistWithCovarianceStamped velocity;
00812 velocity.header.stamp = fix.header.stamp;
00813 velocity.header.frame_id = frame_id;
00814
00815
00816 velocity.twist.twist.linear.x = m.velE * 1e-3;
00817 velocity.twist.twist.linear.y = m.velN * 1e-3;
00818 velocity.twist.twist.linear.z = -m.velD * 1e-3;
00819
00820 const double covSpeed = pow(m.sAcc * 1e-3, 2);
00821 const int cols = 6;
00822 velocity.twist.covariance[cols * 0 + 0] = covSpeed;
00823 velocity.twist.covariance[cols * 1 + 1] = covSpeed;
00824 velocity.twist.covariance[cols * 2 + 2] = covSpeed;
00825 velocity.twist.covariance[cols * 3 + 3] = -1;
00826
00827 velocityPublisher.publish(velocity);
00828
00829
00830
00831
00832 last_nav_pvt_ = m;
00833 freq_diag.diagnostic->tick(fix.header.stamp);
00834 updater->update();
00835 }
00836
00837 protected:
00838
00842 void fixDiagnostic(diagnostic_updater::DiagnosticStatusWrapper& stat) {
00843
00844 if (last_nav_pvt_.fixType ==
00845 ublox_msgs::NavPVT::FIX_TYPE_DEAD_RECKONING_ONLY) {
00846 stat.level = diagnostic_msgs::DiagnosticStatus::WARN;
00847 stat.message = "Dead reckoning only";
00848 } else if (last_nav_pvt_.fixType == ublox_msgs::NavPVT::FIX_TYPE_2D) {
00849 stat.level = diagnostic_msgs::DiagnosticStatus::WARN;
00850 stat.message = "2D fix";
00851 } else if (last_nav_pvt_.fixType == ublox_msgs::NavPVT::FIX_TYPE_3D) {
00852 stat.level = diagnostic_msgs::DiagnosticStatus::OK;
00853 stat.message = "3D fix";
00854 } else if (last_nav_pvt_.fixType ==
00855 ublox_msgs::NavPVT::FIX_TYPE_GNSS_DEAD_RECKONING_COMBINED) {
00856 stat.level = diagnostic_msgs::DiagnosticStatus::OK;
00857 stat.message = "GPS and dead reckoning combined";
00858 } else if (last_nav_pvt_.fixType ==
00859 ublox_msgs::NavPVT::FIX_TYPE_TIME_ONLY) {
00860 stat.level = diagnostic_msgs::DiagnosticStatus::OK;
00861 stat.message = "Time only fix";
00862 }
00863
00864
00865 if (!(last_nav_pvt_.flags & ublox_msgs::NavPVT::FLAGS_GNSS_FIX_OK)) {
00866 stat.level = diagnostic_msgs::DiagnosticStatus::WARN;
00867 stat.message += ", fix not ok";
00868 }
00869
00870 if (last_nav_pvt_.fixType == ublox_msgs::NavPVT::FIX_TYPE_NO_FIX) {
00871 stat.level = diagnostic_msgs::DiagnosticStatus::ERROR;
00872 stat.message = "No fix";
00873 }
00874
00875
00876 stat.add("iTOW [ms]", last_nav_pvt_.iTOW);
00877 stat.add("Latitude [deg]", last_nav_pvt_.lat * 1e-7);
00878 stat.add("Longitude [deg]", last_nav_pvt_.lon * 1e-7);
00879 stat.add("Altitude [m]", last_nav_pvt_.height * 1e-3);
00880 stat.add("Height above MSL [m]", last_nav_pvt_.hMSL * 1e-3);
00881 stat.add("Horizontal Accuracy [m]", last_nav_pvt_.hAcc * 1e-3);
00882 stat.add("Vertical Accuracy [m]", last_nav_pvt_.vAcc * 1e-3);
00883 stat.add("# SVs used", (int)last_nav_pvt_.numSV);
00884 }
00885
00887 NavPVT last_nav_pvt_;
00888
00890 bool enable_gps_;
00892 bool enable_glonass_;
00894 bool enable_qzss_;
00896 bool enable_sbas_;
00898 uint32_t qzss_sig_cfg_;
00899 };
00900
00904 class UbloxFirmware7 : public UbloxFirmware7Plus<ublox_msgs::NavPVT7> {
00905 public:
00906 UbloxFirmware7();
00907
00913 void getRosParams();
00914
00918 bool configureUblox();
00919
00925 void subscribe();
00926
00927 private:
00929
00932 ublox_msgs::CfgNMEA7 cfg_nmea_;
00934 bool set_nmea_;
00935 };
00936
00940 class UbloxFirmware8 : public UbloxFirmware7Plus<ublox_msgs::NavPVT> {
00941 public:
00942 UbloxFirmware8();
00943
00949 void getRosParams();
00950
00958 bool configureUblox();
00959
00967 void subscribe();
00968
00969 private:
00970
00972 bool enable_galileo_;
00974 bool enable_beidou_;
00976 bool enable_imes_;
00978 bool set_nmea_;
00980 ublox_msgs::CfgNMEA cfg_nmea_;
00982 bool save_on_shutdown_;
00984 bool clear_bbr_;
00985 };
00986
00990 class RawDataProduct: public virtual ComponentInterface {
00991 public:
00992 static const double kRtcmFreqTol = 0.15;
00993 static const int kRtcmFreqWindow = 25;
00994
00998 void getRosParams() {}
00999
01004 bool configureUblox() { return true; }
01005
01011 void subscribe();
01012
01016 void initializeRosDiagnostics();
01017
01018 private:
01020 std::vector<UbloxTopicDiagnostic> freq_diagnostics_;
01021 };
01022
01027 class AdrUdrProduct: public virtual ComponentInterface {
01028 public:
01034 void getRosParams();
01035
01041 bool configureUblox();
01042
01049 void subscribe();
01050
01055 void initializeRosDiagnostics() {
01056 ROS_WARN("ROS Diagnostics specific to u-blox ADR/UDR devices is %s",
01057 "unimplemented. See AdrUdrProduct class in node.h & node.cpp.");
01058 }
01059
01060 protected:
01062 bool use_adr_;
01063 };
01064
01069 class FtsProduct: public virtual ComponentInterface {
01074 void getRosParams() {
01075 ROS_WARN("Functionality specific to u-blox FTS devices is %s",
01076 "unimplemented. See FtsProduct class in node.h & node.cpp.");
01077 }
01078
01083 bool configureUblox() {}
01084
01089 void subscribe() {}
01090
01095 void initializeRosDiagnostics() {}
01096 };
01097
01102 class HpgRefProduct: public virtual ComponentInterface {
01103 public:
01113 void getRosParams();
01114
01123 bool configureUblox();
01124
01130 void subscribe();
01131
01135 void initializeRosDiagnostics();
01136
01145 void callbackNavSvIn(ublox_msgs::NavSVIN m);
01146
01147 protected:
01154 void tmode3Diagnostics(diagnostic_updater::DiagnosticStatusWrapper& stat);
01155
01161 bool setTimeMode();
01162
01164 ublox_msgs::NavSVIN last_nav_svin_;
01165
01167 uint8_t tmode3_;
01168
01169
01171
01172 bool lla_flag_;
01174
01175 std::vector<float> arp_position_;
01177
01178 std::vector<int8_t> arp_position_hp_;
01180
01181 float fixed_pos_acc_;
01182
01183
01185
01190 bool svin_reset_;
01192
01193 uint32_t sv_in_min_dur_;
01195
01196 float sv_in_acc_lim_;
01197
01199 enum {
01200 INIT,
01201 FIXED,
01202 DISABLED,
01203 SURVEY_IN,
01204 TIME
01205 } mode_;
01206 };
01207
01211 class HpgRovProduct: public virtual ComponentInterface {
01212 public:
01213
01215 const static double kRtcmFreqMin = 1;
01217 const static double kRtcmFreqMax = 10;
01219 const static double kRtcmFreqTol = 0.1;
01221 const static int kRtcmFreqWindow = 25;
01227 void getRosParams();
01228
01235 bool configureUblox();
01236
01240 void subscribe();
01241
01246 void initializeRosDiagnostics();
01247
01248 protected:
01253 void carrierPhaseDiagnostics(
01254 diagnostic_updater::DiagnosticStatusWrapper& stat);
01255
01261 void callbackNavRelPosNed(const ublox_msgs::NavRELPOSNED &m);
01262
01263
01265 ublox_msgs::NavRELPOSNED last_rel_pos_;
01266
01268
01269 uint8_t dgnss_mode_;
01270
01272 UbloxTopicDiagnostic freq_rtcm_;
01273 };
01274
01279 class TimProduct: public virtual ComponentInterface {
01284 void getRosParams() {
01285 ROS_WARN("Functionality specific to u-blox TIM devices is only %s",
01286 "partially implemented. See TimProduct class in node.h & node.cpp.");
01287 }
01288
01293 bool configureUblox() {}
01294
01300 void subscribe();
01301
01306 void initializeRosDiagnostics() {}
01307 };
01308
01309 }
01310
01311 #endif