44 std::string
lower = model;
46 if(
lower ==
"portable") {
47 return ublox_msgs::CfgNAV5::DYN_MODEL_PORTABLE;
48 }
else if(
lower ==
"stationary") {
49 return ublox_msgs::CfgNAV5::DYN_MODEL_STATIONARY;
50 }
else if(
lower ==
"pedestrian") {
51 return ublox_msgs::CfgNAV5::DYN_MODEL_PEDESTRIAN;
52 }
else if(
lower ==
"automotive") {
53 return ublox_msgs::CfgNAV5::DYN_MODEL_AUTOMOTIVE;
54 }
else if(
lower ==
"sea") {
55 return ublox_msgs::CfgNAV5::DYN_MODEL_SEA;
56 }
else if(
lower ==
"airborne1") {
57 return ublox_msgs::CfgNAV5::DYN_MODEL_AIRBORNE_1G;
58 }
else if(
lower ==
"airborne2") {
59 return ublox_msgs::CfgNAV5::DYN_MODEL_AIRBORNE_2G;
60 }
else if(
lower ==
"airborne4") {
61 return ublox_msgs::CfgNAV5::DYN_MODEL_AIRBORNE_4G;
62 }
else if(
lower ==
"wristwatch") {
63 return ublox_msgs::CfgNAV5::DYN_MODEL_WRIST_WATCH;
64 }
else if(
lower ==
"bike") {
65 return ublox_msgs::CfgNAV5::DYN_MODEL_BIKE;
68 throw std::runtime_error(
"Invalid settings: " +
lower +
69 " is not a valid dynamic model.");
73 std::string
lower = mode;
76 return ublox_msgs::CfgNAV5::FIX_MODE_2D_ONLY;
77 }
else if (
lower ==
"3d") {
78 return ublox_msgs::CfgNAV5::FIX_MODE_3D_ONLY;
79 }
else if (
lower ==
"auto") {
80 return ublox_msgs::CfgNAV5::FIX_MODE_AUTO;
83 throw std::runtime_error(
"Invalid settings: " + mode +
84 " is not a valid fix mode.");
110 ROS_INFO(
"U-Blox Firmware Version: %d", ublox_version);
115 std::string ref_rov) {
116 if (product_category.compare(
"HPG") == 0 && ref_rov.compare(
"REF") == 0)
118 else if (product_category.compare(
"HPG") == 0 && ref_rov.compare(
"ROV") == 0)
120 else if (product_category.compare(
"HPG") == 0)
122 else if (product_category.compare(
"HDG") == 0)
124 else if (product_category.compare(
"TIM") == 0)
126 else if (product_category.compare(
"ADR") == 0 ||
127 product_category.compare(
"UDR") == 0 ||
128 product_category.compare(
"LAP") == 0)
130 else if (product_category.compare(
"FTS") == 0)
132 else if(product_category.compare(
"SPG") != 0)
133 ROS_WARN(
"Product category %s %s from MonVER message not recognized %s",
134 product_category.c_str(), ref_rov.c_str(),
135 "options are HPG REF, HPG ROV, HPG #.#, HDG #.#, TIM, ADR, UDR, LAP, FTS, SPG");
139 nh->param(
"device",
device_, std::string(
"/dev/ttyACM0"));
140 nh->param(
"frame_id",
frame_id, std::string(
"gps"));
151 | ublox_msgs::CfgPRT::PROTO_NMEA
152 | ublox_msgs::CfgPRT::PROTO_RTCM);
156 if (
nh->hasParam(
"usb/in") ||
nh->hasParam(
"usb/out")) {
159 throw std::runtime_error(std::string(
"usb/out is set, therefore ") +
160 "usb/in must be set");
163 throw std::runtime_error(std::string(
"usb/in is set, therefore ") +
164 "usb/out must be set");
181 nh->param(
"fix_mode",
fix_mode_, std::string(
"auto"));
185 ROS_WARN(
"Warning: PPP is enabled - this is an expert setting.");
190 throw std::runtime_error(std::string(
"Invalid settings: size of rtcm_ids") +
191 " must match size of rtcm_rates");
198 std::vector<float> shift, rot;
201 ||
nh->getParam(
"dat/shift", shift)
202 ||
nh->getParam(
"dat/rot", rot)
204 throw std::runtime_error(std::string(
"dat/set is true, therefore ") +
205 "dat/majA, dat/flat, dat/shift, dat/rot, & dat/scale must be set");
206 if(shift.size() != 3 || rot.size() != 3)
207 throw std::runtime_error(std::string(
"size of dat/shift & dat/rot ") +
237 gps.
poll(ublox_msgs::MonVER::CLASS_ID, ublox_msgs::MonVER::MESSAGE_ID);
241 static std::vector<uint8_t> payload(1, 1);
250 if (payload[0] > 32) {
267 ROS_DEBUG(
"Subscribing to U-Blox messages");
269 nh->param(
"publish/all",
enabled[
"all"],
false);
270 nh->param(
"inf/all",
enabled[
"inf"],
true);
280 publish<ublox_msgs::NavSTATUS>, _1,
"navstatus"),
kSubscribeRate);
285 publish<ublox_msgs::NavPOSECEF>, _1,
"navposecef"),
kSubscribeRate);
292 nh->param(
"publish/nmea",
enabled[
"nmea"],
false);
297 nh->param(
"inf/debug",
enabled[
"inf_debug"],
false);
353 if (!
nh->hasParam(
"diagnostic_period"))
357 updater->setHardwareID(
"ublox");
368 ublox_msgs::MonVER monVer;
370 throw std::runtime_error(
"Failed to poll MonVER & set relevant settings");
372 ROS_DEBUG(
"%s, HW VER: %s", monVer.swVersion.c_array(),
373 monVer.hwVersion.c_array());
375 std::vector<std::string> extension;
376 extension.reserve(monVer.extension.size());
377 for(std::size_t i = 0; i < monVer.extension.size(); ++i) {
378 ROS_DEBUG(
"%s", monVer.extension[i].field.c_array());
380 unsigned char* end = std::find(monVer.extension[i].field.begin(),
381 monVer.extension[i].field.end(),
'\0');
382 extension.push_back(std::string(monVer.extension[i].field.begin(), end));
386 for(std::size_t i = 0; i < extension.size(); ++i) {
387 std::size_t found = extension[i].find(
"PROTVER");
388 if (found != std::string::npos) {
390 extension[i].substr(8, extension[i].size()-8).c_str());
395 ROS_WARN(
"Failed to parse MonVER and determine protocol version. %s",
396 "Defaulting to firmware version 6.");
401 std::vector<std::string> strs;
402 if(extension.size() > 0)
403 boost::split(strs, extension[extension.size()-1], boost::is_any_of(
";"));
404 for(
size_t i = 0; i < strs.size(); i++)
407 for(std::size_t i = 0; i < extension.size(); ++i) {
408 std::vector<std::string> strs;
410 if(i <= extension.size() - 2) {
411 boost::split(strs, extension[i], boost::is_any_of(
"="));
412 if(strs.size() > 1) {
413 if (strs[0].compare(std::string(
"FWVER")) == 0) {
423 if(i >= extension.size() - 2) {
424 boost::split(strs, extension[i], boost::is_any_of(
";"));
425 for(
size_t i = 0; i < strs.size(); i++)
435 throw std::runtime_error(
"Failed to initialize.");
436 if (
load_.loadMask != 0) {
437 ROS_DEBUG(
"Loading u-blox configuration from memory. %u",
load_.loadMask);
439 throw std::runtime_error(std::string(
"Failed to load configuration ") +
442 ROS_DEBUG(
"Loaded I/O configuration from memory, resetting serial %s",
447 throw std::runtime_error(std::string(
"Failed to reset serial I/O") +
448 "after loading I/O configurations from device memory.");
457 std::stringstream ss;
458 ss <<
"Failed to set measurement rate to " <<
meas_rate
459 <<
"ms and navigation rate to " <<
nav_rate;
460 throw std::runtime_error(ss.str());
465 throw std::runtime_error(std::string(
"Failed to ") +
471 throw std::runtime_error(std::string(
"Failed to ") +
475 throw std::runtime_error(
"Failed to set model: " +
dynamic_model_ +
".");
477 throw std::runtime_error(
"Failed to set fix mode: " +
fix_mode_ +
".");
479 std::stringstream ss;
480 ss <<
"Failed to set dead reckoning limit: " <<
dr_limit_ <<
".";
481 throw std::runtime_error(ss.str());
484 throw std::runtime_error(
"Failed to set user-defined datum.");
491 if (
save_.saveMask != 0) {
492 ROS_DEBUG(
"Saving the u-blox configuration, mask %u, device %u",
495 ROS_ERROR(
"u-blox unable to save configuration to non-volatile memory");
497 }
catch (std::exception& e) {
498 ROS_FATAL(
"Error configuring u-blox: %s", e.what());
505 ublox_msgs::CfgINF
msg;
507 ublox_msgs::CfgINF_Block block;
508 block.protocolID = block.PROTOCOL_ID_UBX;
510 uint8_t mask = (
enabled[
"inf_error"] ? block.INF_MSG_ERROR : 0) |
511 (
enabled[
"inf_warning"] ? block.INF_MSG_WARNING : 0) |
512 (
enabled[
"inf_notice"] ? block.INF_MSG_NOTICE : 0) |
513 (
enabled[
"inf_test"] ? block.INF_MSG_TEST : 0) |
514 (
enabled[
"inf_debug"] ? block.INF_MSG_DEBUG : 0);
515 for (
int i = 0; i < block.infMsgMask.size(); i++)
516 block.infMsgMask[i] = mask;
518 msg.blocks.push_back(block);
521 if (
uart_in_ & ublox_msgs::CfgPRT::PROTO_NMEA) {
522 ublox_msgs::CfgINF_Block block;
523 block.protocolID = block.PROTOCOL_ID_NMEA;
525 for (
int i = 0; i < block.infMsgMask.size(); i++)
526 block.infMsgMask[i] = mask;
527 msg.blocks.push_back(block);
532 ROS_WARN(
"Failed to configure INF messages");
539 if (boost::regex_match(
device_, match,
540 boost::regex(
"(tcp|udp)://(.+):(\\d+)"))) {
541 std::string proto(match[1]);
542 if (proto ==
"tcp") {
543 std::string host(match[2]);
544 std::string port(match[3]);
545 ROS_INFO(
"Connecting to %s://%s:%s ...", proto.c_str(), host.c_str(),
548 }
else if (proto ==
"udp") {
549 std::string host(match[2]);
550 std::string port(match[3]);
551 ROS_INFO(
"Connecting to %s://%s:%s ...", proto.c_str(), host.c_str(),
555 throw std::runtime_error(
"Protocol '" + proto +
"' is unsupported");
576 if(
nh->param(
"raw_data",
false))
586 ROS_INFO(
"U-Blox configured successfully.");
593 if (
device_.substr(0, 6) ==
"udp://") {
636 bool compat, consider;
639 throw std::runtime_error(std::string(
"Invalid settings: nmea/set is ") +
640 "true, therefore nmea/version must be set");
642 throw std::runtime_error(std::string(
"Invalid settings: nmea/set is ") +
643 "true, therefore nmea/num_sv must be set");
644 if (!
nh->getParam(
"nmea/compat", compat))
645 throw std::runtime_error(std::string(
"Invalid settings: nmea/set is ") +
646 "true, therefore nmea/compat must be set");
647 if (!
nh->getParam(
"nmea/consider", consider))
648 throw std::runtime_error(std::string(
"Invalid settings: nmea/set is ") +
649 "true, therefore nmea/consider must be set");
657 nh->param(
"nmea/filter/pos", temp,
false);
659 nh->param(
"nmea/filter/msk_pos", temp,
false);
661 nh->param(
"nmea/filter/time", temp,
false);
663 nh->param(
"nmea/filter/date", temp,
false);
665 nh->param(
"nmea/filter/sbas", temp,
false);
667 nh->param(
"nmea/filter/track", temp,
false);
673 ROS_WARN(
"ublox_version < 7, ignoring GNSS settings");
676 throw std::runtime_error(
"Failed to configure NMEA");
702 publish<ublox_msgs::NavSVINFO>, _1,
"navsvinfo"),
715 if (
last_nav_sol_.gpsFix == ublox_msgs::NavSOL::GPS_DEAD_RECKONING_ONLY) {
716 stat.level = diagnostic_msgs::DiagnosticStatus::WARN;
717 stat.message =
"Dead reckoning only";
718 }
else if (
last_nav_sol_.gpsFix == ublox_msgs::NavSOL::GPS_2D_FIX) {
719 stat.level = diagnostic_msgs::DiagnosticStatus::OK;
720 stat.message =
"2D fix";
721 }
else if (
last_nav_sol_.gpsFix == ublox_msgs::NavSOL::GPS_3D_FIX) {
722 stat.level = diagnostic_msgs::DiagnosticStatus::OK;
723 stat.message =
"3D fix";
725 ublox_msgs::NavSOL::GPS_GPS_DEAD_RECKONING_COMBINED) {
726 stat.level = diagnostic_msgs::DiagnosticStatus::OK;
727 stat.message =
"GPS and dead reckoning combined";
728 }
else if (
last_nav_sol_.gpsFix == ublox_msgs::NavSOL::GPS_TIME_ONLY_FIX) {
729 stat.level = diagnostic_msgs::DiagnosticStatus::OK;
730 stat.message =
"Time fix only";
733 if (!(
last_nav_sol_.flags & ublox_msgs::NavSOL::FLAGS_GPS_FIX_OK)) {
734 stat.level = diagnostic_msgs::DiagnosticStatus::WARN;
735 stat.message +=
", fix not ok";
738 if (
last_nav_sol_.gpsFix == ublox_msgs::NavSOL::GPS_NO_FIX) {
739 stat.level = diagnostic_msgs::DiagnosticStatus::ERROR;
740 stat.message =
"No fix";
770 fix_.latitude = m.lat * 1e-7;
771 fix_.longitude = m.lon * 1e-7;
772 fix_.altitude = m.height * 1e-3;
775 fix_.status.status =
fix_.status.STATUS_FIX;
777 fix_.status.status =
fix_.status.STATUS_NO_FIX;
780 const double varH = pow(m.hAcc / 1000.0, 2);
781 const double varV = pow(m.vAcc / 1000.0, 2);
783 fix_.position_covariance[0] = varH;
784 fix_.position_covariance[4] = varH;
785 fix_.position_covariance[8] = varV;
786 fix_.position_covariance_type =
787 sensor_msgs::NavSatFix::COVARIANCE_TYPE_DIAGONAL_KNOWN;
789 fix_.status.service =
fix_.status.SERVICE_GPS;
806 nh->advertise<geometry_msgs::TwistWithCovarianceStamped>(
"fix_velocity",
815 velocity_.twist.twist.linear.x = m.velE / 100.0;
816 velocity_.twist.twist.linear.y = m.velN / 100.0;
817 velocity_.twist.twist.linear.z = -m.velD / 100.0;
819 const double varSpeed = pow(m.sAcc / 100.0, 2);
822 velocity_.twist.covariance[cols * 0 + 0] = varSpeed;
823 velocity_.twist.covariance[cols * 1 + 1] = varSpeed;
824 velocity_.twist.covariance[cols * 2 + 2] = varSpeed;
825 velocity_.twist.covariance[cols * 3 + 3] = -1;
854 ublox_msgs::CfgGNSS_Block::SIG_CFG_QZSS_L1CA);
858 ROS_WARN(
"gnss/gps is true, but GPS GNSS is not supported by this device");
860 ROS_WARN(
"gnss/glonass is true, but GLONASS is not %s",
861 "supported by this device");
863 ROS_WARN(
"gnss/qzss is true, but QZSS is not supported by this device");
865 ROS_WARN(
"gnss/sbas is true, but SBAS is not supported by this device");
867 if(
nh->hasParam(
"gnss/galileo"))
868 ROS_WARN(
"ublox_version < 8, ignoring Galileo GNSS Settings");
869 if(
nh->hasParam(
"gnss/beidou"))
870 ROS_WARN(
"ublox_version < 8, ignoring BeiDou Settings");
871 if(
nh->hasParam(
"gnss/imes"))
872 ROS_WARN(
"ublox_version < 8, ignoring IMES GNSS Settings");
876 + (
enable_glonass_ ? 1 : 0) * sensor_msgs::NavSatStatus::SERVICE_GLONASS;
883 bool compat, consider;
886 throw std::runtime_error(std::string(
"Invalid settings: nmea/set is ") +
887 "true, therefore nmea/version must be set");
889 throw std::runtime_error(std::string(
"Invalid settings: nmea/set is ") +
890 "true, therefore nmea/num_sv must be set");
892 throw std::runtime_error(std::string(
"Invalid settings: nmea/set is ") +
893 "true, therefore nmea/sv_numbering must be set");
894 if (!
nh->getParam(
"nmea/compat", compat))
895 throw std::runtime_error(std::string(
"Invalid settings: nmea/set is ") +
896 "true, therefore nmea/compat must be set");
897 if (!
nh->getParam(
"nmea/consider", consider))
898 throw std::runtime_error(std::string(
"Invalid settings: nmea/set is ") +
899 "true, therefore nmea/consider must be set");
906 nh->param(
"nmea/filter/pos", temp,
false);
908 nh->param(
"nmea/filter/msk_pos", temp,
false);
910 nh->param(
"nmea/filter/time", temp,
false);
912 nh->param(
"nmea/filter/date", temp,
false);
914 nh->param(
"nmea/filter/gps_only", temp,
false);
916 nh->param(
"nmea/filter/track", temp,
false);
919 nh->param(
"nmea/gnssToFilter/gps", temp,
false);
921 nh->param(
"nmea/gnssToFilter/sbas", temp,
false);
923 nh->param(
"nmea/gnssToFilter/qzss", temp,
false);
925 nh->param(
"nmea/gnssToFilter/glonass", temp,
false);
935 ublox_msgs::CfgGNSS cfgGNSSRead;
938 ROS_DEBUG(
"Num. tracking channels in hardware: %i", cfgGNSSRead.numTrkChHw);
939 ROS_DEBUG(
"Num. tracking channels to use: %i", cfgGNSSRead.numTrkChUse);
941 throw std::runtime_error(
"Failed to read the GNSS config.");
944 ublox_msgs::CfgGNSS cfgGNSSWrite;
945 cfgGNSSWrite.numConfigBlocks = 1;
946 cfgGNSSWrite.numTrkChHw = cfgGNSSRead.numTrkChHw;
947 cfgGNSSWrite.numTrkChUse = cfgGNSSRead.numTrkChUse;
948 cfgGNSSWrite.msgVer = 0;
952 ublox_msgs::CfgGNSS_Block block;
953 block.gnssId = block.GNSS_ID_GLONASS;
954 block.resTrkCh = block.RES_TRK_CH_GLONASS;
955 block.maxTrkCh = block.MAX_TRK_CH_GLONASS;
957 cfgGNSSWrite.blocks.push_back(block);
959 throw std::runtime_error(std::string(
"Failed to ") +
967 ublox_msgs::CfgGNSS_Block block;
968 block.gnssId = block.GNSS_ID_QZSS;
969 block.resTrkCh = block.RES_TRK_CH_QZSS;
970 block.maxTrkCh = block.MAX_TRK_CH_QZSS;
972 cfgGNSSWrite.blocks[0] = block;
974 throw std::runtime_error(std::string(
"Failed to ") +
982 ublox_msgs::CfgGNSS_Block block;
983 block.gnssId = block.GNSS_ID_SBAS;
984 block.resTrkCh = block.RES_TRK_CH_SBAS;
985 block.maxTrkCh = block.MAX_TRK_CH_SBAS;
986 block.flags =
enable_sbas_ ? block.SIG_CFG_SBAS_L1CA : 0;
987 cfgGNSSWrite.blocks[0] = block;
989 throw std::runtime_error(std::string(
"Failed to ") +
996 throw std::runtime_error(
"Failed to configure NMEA");
1014 publish<ublox_msgs::NavSVINFO>, _1,
"navsvinfo"),
1044 ublox_msgs::CfgGNSS_Block::SIG_CFG_QZSS_L1CA);
1047 ROS_WARN(
"gnss/gps is true, but GPS GNSS is not supported by %s",
1050 ROS_WARN(
"gnss/glonass is true, but GLONASS is not supported by %s",
1053 ROS_WARN(
"gnss/galileo is true, but Galileo GNSS is not supported %s",
1056 ROS_WARN(
"gnss/beidou is true, but Beidou GNSS is not supported %s",
1059 ROS_WARN(
"gnss/imes is true, but IMES GNSS is not supported by %s",
1062 ROS_WARN(
"gnss/qzss is true, but QZSS is not supported by this device");
1064 ROS_WARN(
"gnss/sbas is true, but SBAS is not supported by this device");
1068 + (
enable_glonass_ ? 1 : 0) * sensor_msgs::NavSatStatus::SERVICE_GLONASS
1069 + (
enable_beidou_ ? 1 : 0) * sensor_msgs::NavSatStatus::SERVICE_COMPASS
1070 + (
enable_galileo_ ? 1 : 0) * sensor_msgs::NavSatStatus::SERVICE_GALILEO;
1077 bool compat, consider;
1082 throw std::runtime_error(std::string(
"Invalid settings: nmea/set is ") +
1083 "true, therefore nmea/version must be set");
1085 throw std::runtime_error(std::string(
"Invalid settings: nmea/set is ") +
1086 "true, therefore nmea/num_sv must be set");
1088 throw std::runtime_error(std::string(
"Invalid settings: nmea/set is ") +
1089 "true, therefore nmea/sv_numbering must be set");
1090 if (!
nh->getParam(
"nmea/compat", compat))
1091 throw std::runtime_error(std::string(
"Invalid settings: nmea/set is ") +
1092 "true, therefore nmea/compat must be set");
1093 if (!
nh->getParam(
"nmea/consider", consider))
1094 throw std::runtime_error(std::string(
"Invalid settings: nmea/set is ") +
1095 "true, therefore nmea/consider must be set");
1101 nh->param(
"nmea/limit82", temp,
false);
1103 nh->param(
"nmea/high_prec", temp,
false);
1106 nh->param(
"nmea/filter/pos", temp,
false);
1108 nh->param(
"nmea/filter/msk_pos", temp,
false);
1110 nh->param(
"nmea/filter/time", temp,
false);
1112 nh->param(
"nmea/filter/date", temp,
false);
1114 nh->param(
"nmea/filter/gps_only", temp,
false);
1116 nh->param(
"nmea/filter/track", temp,
false);
1119 nh->param(
"nmea/gnssToFilter/gps", temp,
false);
1121 nh->param(
"nmea/gnssToFilter/sbas", temp,
false);
1123 nh->param(
"nmea/gnssToFilter/qzss", temp,
false);
1125 nh->param(
"nmea/gnssToFilter/glonass", temp,
false);
1127 nh->param(
"nmea/gnssToFilter/beidou", temp,
false);
1133 std::vector<uint8_t> bdsTalkerId;
1134 getRosUint(
"nmea/bds_talker_id", bdsTalkerId);
1135 if(bdsTalkerId.size() >= 2) {
1136 cfg_nmea_.bdsTalkerId[0] = bdsTalkerId[0];
1137 cfg_nmea_.bdsTalkerId[1] = bdsTalkerId[1];
1148 ROS_ERROR(
"u-blox failed to clear flash memory");
1154 ublox_msgs::CfgGNSS cfg_gnss;
1157 ROS_DEBUG(
"Num. tracking channels in hardware: %i", cfg_gnss.numTrkChHw);
1158 ROS_DEBUG(
"Num. tracking channels to use: %i", cfg_gnss.numTrkChUse);
1160 throw std::runtime_error(
"Failed to read the GNSS config.");
1164 bool correct =
true;
1165 for (
int i = 0; i < cfg_gnss.blocks.size(); i++) {
1166 ublox_msgs::CfgGNSS_Block block = cfg_gnss.blocks[i];
1167 if (block.gnssId == block.GNSS_ID_GPS
1168 &&
enable_gps_ != (block.flags & block.FLAGS_ENABLE)) {
1170 cfg_gnss.blocks[i].flags =
1171 (cfg_gnss.blocks[i].flags & ~block.FLAGS_ENABLE) |
enable_gps_;
1172 ROS_DEBUG(
"GPS Configuration is different");
1173 }
else if (block.gnssId == block.GNSS_ID_SBAS
1174 &&
enable_sbas_ != (block.flags & block.FLAGS_ENABLE)) {
1176 cfg_gnss.blocks[i].flags =
1177 (cfg_gnss.blocks[i].flags & ~block.FLAGS_ENABLE) |
enable_sbas_;
1178 ROS_DEBUG(
"SBAS Configuration is different");
1179 }
else if (block.gnssId == block.GNSS_ID_GALILEO
1182 cfg_gnss.blocks[i].flags =
1184 ROS_DEBUG(
"Galileo GNSS Configuration is different");
1185 }
else if (block.gnssId == block.GNSS_ID_BEIDOU
1188 cfg_gnss.blocks[i].flags =
1189 (cfg_gnss.blocks[i].flags & ~block.FLAGS_ENABLE) |
enable_beidou_;
1190 ROS_DEBUG(
"BeiDou Configuration is different");
1191 }
else if (block.gnssId == block.GNSS_ID_IMES
1192 &&
enable_imes_ != (block.flags & block.FLAGS_ENABLE)) {
1194 cfg_gnss.blocks[i].flags =
1195 (cfg_gnss.blocks[i].flags & ~block.FLAGS_ENABLE) |
enable_imes_;
1196 }
else if (block.gnssId == block.GNSS_ID_QZSS
1199 &&
qzss_sig_cfg_ != (block.flags & block.FLAGS_SIG_CFG_MASK)))) {
1200 ROS_DEBUG(
"QZSS Configuration is different %u, %u",
1201 block.flags & block.FLAGS_ENABLE,
1204 ROS_DEBUG(
"QZSS Configuration: %u", block.flags);
1205 cfg_gnss.blocks[i].flags =
1206 (cfg_gnss.blocks[i].flags & ~block.FLAGS_ENABLE) |
enable_qzss_;
1207 ROS_DEBUG(
"QZSS Configuration: %u", cfg_gnss.blocks[i].flags);
1211 }
else if (block.gnssId == block.GNSS_ID_GLONASS
1214 cfg_gnss.blocks[i].flags =
1216 ROS_DEBUG(
"GLONASS Configuration is different");
1223 ROS_DEBUG(
"U-Blox GNSS configuration is correct. GNSS not re-configured.");
1224 else if (!
gps.
configGnss(cfg_gnss, boost::posix_time::seconds(15)))
1225 throw std::runtime_error(std::string(
"Failed to cold reset device ") +
1226 "after configuring GNSS");
1232 throw std::runtime_error(
"Failed to configure NMEA");
1268 nh->param(
"publish/rxm/all",
enabled[
"rxm"],
true);
1311 : protocol_version_(protocol_version)
1321 if(nav_rate_hz != 1)
1322 ROS_WARN(
"Nav Rate recommended to be 1 Hz");
1327 throw std::runtime_error(std::string(
"Failed to ")
1328 + (
use_adr_ ?
"enable" :
"disable") +
"use_adr");
1333 nh->param(
"publish/esf/all",
enabled[
"esf"],
true);
1372 publish<ublox_msgs::EsfSTATUS>, _1,
"esfstatus"),
kSubscribeRate);
1375 nh->param(
"publish/hnr/pvt",
enabled[
"hnr_pvt"],
true);
1386 nh->advertise<sensor_msgs::TimeReference>(
"interrupt_time",
kROSQueueSize);
1391 static const float rad_per_sec = pow(2, -12) * M_PI / 180.0F;
1392 static const float m_per_sec_sq = pow(2, -10);
1393 static const float deg_c = 1e-2;
1395 std::vector<uint32_t> imu_data = m.data;
1396 for (
int i=0; i < imu_data.size(); i++){
1397 unsigned int data_type = imu_data[i] >> 24;
1398 int32_t data_value =
static_cast<int32_t
>(imu_data[i] << 8);
1401 imu_.orientation_covariance[0] = -1;
1402 imu_.linear_acceleration_covariance[0] = -1;
1403 imu_.angular_velocity_covariance[0] = -1;
1405 if (data_type == 14) {
1406 imu_.angular_velocity.x = data_value * rad_per_sec;
1407 }
else if (data_type == 16) {
1408 imu_.linear_acceleration.x = data_value * m_per_sec_sq;
1409 }
else if (data_type == 13) {
1410 imu_.angular_velocity.y = data_value * rad_per_sec;
1411 }
else if (data_type == 17) {
1412 imu_.linear_acceleration.y = data_value * m_per_sec_sq;
1413 }
else if (data_type == 5) {
1414 imu_.angular_velocity.z = data_value * rad_per_sec;
1415 }
else if (data_type == 18) {
1416 imu_.linear_acceleration.z = data_value * m_per_sec_sq;
1417 }
else if (data_type == 12) {
1438 time_ref_pub.publish(
t_ref_);
1451 ROS_WARN(
"For HPG Ref devices, nav_rate should be exactly 1 Hz.");
1454 throw std::runtime_error(
"Invalid settings: TMODE3 must be set");
1456 if(
tmode3_ == ublox_msgs::CfgTMODE3::FLAGS_MODE_FIXED) {
1458 throw std::runtime_error(std::string(
"Invalid settings: arp/position ")
1459 +
"must be set if TMODE3 is fixed");
1461 throw std::runtime_error(std::string(
"Invalid settings: arp/position_hp ")
1462 +
"must be set if TMODE3 is fixed");
1464 throw std::runtime_error(std::string(
"Invalid settings: arp/acc ")
1465 +
"must be set if TMODE3 is fixed");
1467 ROS_WARN(
"arp/lla_flag param not set, assuming ARP coordinates are %s",
1471 }
else if(
tmode3_ == ublox_msgs::CfgTMODE3::FLAGS_MODE_SURVEY_IN) {
1474 throw std::runtime_error(std::string(
"Invalid settings: sv_in/min_dur ")
1475 +
"must be set if TMODE3 is survey-in");
1477 throw std::runtime_error(std::string(
"Invalid settings: sv_in/acc_lim ")
1478 +
"must be set if TMODE3 is survey-in");
1479 }
else if(
tmode3_ != ublox_msgs::CfgTMODE3::FLAGS_MODE_DISABLED) {
1480 throw std::runtime_error(std::string(
"tmode3 param invalid. See CfgTMODE3")
1481 +
" flag constants for possible values.");
1488 if(
tmode3_ == ublox_msgs::CfgTMODE3::FLAGS_MODE_DISABLED) {
1490 throw std::runtime_error(
"Failed to disable TMODE3.");
1492 }
else if(
tmode3_ == ublox_msgs::CfgTMODE3::FLAGS_MODE_FIXED) {
1495 throw std::runtime_error(
"Failed to set TMODE3 to fixed.");
1497 throw std::runtime_error(
"Failed to set RTCM rates");
1499 }
else if(
tmode3_ == ublox_msgs::CfgTMODE3::FLAGS_MODE_SURVEY_IN) {
1501 ublox_msgs::NavSVIN nav_svin;
1503 throw std::runtime_error(std::string(
"Failed to poll NavSVIN while") +
1504 " configuring survey-in");
1506 if(nav_svin.active) {
1511 if(nav_svin.valid) {
1515 ublox_msgs::NavPVT nav_pvt;
1517 throw std::runtime_error(std::string(
"Failed to poll NavPVT while") +
1518 " configuring survey-in");
1520 if (nav_pvt.fixType == nav_pvt.FIX_TYPE_TIME_ONLY
1521 && nav_pvt.flags & nav_pvt.FLAGS_GNSS_FIX_OK) {
1530 if(1000 % meas_rate_temp != 0)
1533 if(!
gps.
configRate(meas_rate_temp, (
int) 1000 / meas_rate_temp))
1534 throw std::runtime_error(std::string(
"Failed to set nav rate to 1 Hz") +
1535 "before setting TMODE3 to survey-in.");
1538 ROS_ERROR(
"Failed to disable TMODE3 before setting to survey-in.");
1543 throw std::runtime_error(
"Failed to set TMODE3 to survey-in.");
1574 ROS_INFO(
"Setting mode (internal state) to Time Mode");
1584 ROS_ERROR(
"Failed to configure RTCM IDs");
1598 stat.level = diagnostic_msgs::DiagnosticStatus::WARN;
1599 stat.message =
"Not configured";
1601 stat.level = diagnostic_msgs::DiagnosticStatus::OK;
1602 stat.message =
"Disabled";
1605 stat.level = diagnostic_msgs::DiagnosticStatus::ERROR;
1606 stat.message =
"Survey-In inactive and invalid";
1608 stat.level = diagnostic_msgs::DiagnosticStatus::WARN;
1609 stat.message =
"Survey-In active but invalid";
1611 stat.level = diagnostic_msgs::DiagnosticStatus::OK;
1612 stat.message =
"Survey-In complete";
1614 stat.level = diagnostic_msgs::DiagnosticStatus::OK;
1615 stat.message =
"Survey-In active and valid";
1629 stat.level = diagnostic_msgs::DiagnosticStatus::OK;
1630 stat.message =
"Fixed Position";
1632 stat.level = diagnostic_msgs::DiagnosticStatus::OK;
1633 stat.message =
"Time";
1643 ublox_msgs::CfgDGNSS::DGNSS_MODE_RTK_FIXED);
1649 throw std::runtime_error(std::string(
"Failed to Configure DGNSS"));
1655 nh->param(
"publish/nav/relposned",
enabled[
"nav_relposned"],
enabled[
"nav"]);
1665 updater->add(
"Carrier Phase Solution",
this,
1677 stat.level = diagnostic_msgs::DiagnosticStatus::ERROR;
1678 stat.message =
"None";
1681 stat.level = diagnostic_msgs::DiagnosticStatus::WARN;
1682 stat.message =
"Float";
1683 }
else if (carr_soln &
last_rel_pos_.FLAGS_CARR_SOLN_FIXED) {
1684 stat.level = diagnostic_msgs::DiagnosticStatus::OK;
1685 stat.message =
"Fixed";
1695 stat.
add(
"Relative Position N [m]", rel_pos_n);
1697 stat.
add(
"Relative Position E [m]", rel_pos_e);
1699 stat.
add(
"Relative Position D [m]", rel_pos_d);
1705 if (
enabled[
"nav_relposned"]) {
1707 nh->advertise<ublox_msgs::NavRELPOSNED>(
"navrelposned",
kROSQueueSize);
1720 nh->param(
"publish/nav/hpposecef",
enabled[
"nav_hpposecef"],
enabled[
"nav"]);
1723 publish<ublox_msgs::NavHPPOSECEF>, _1,
"navhpposecef"),
kSubscribeRate);
1729 nh->param(
"publish/nav/hpposllh",
enabled[
"nav_hpposllh"],
enabled[
"nav"]);
1737 nh->param(
"publish/nav/relposned",
enabled[
"nav_relposned"],
enabled[
"nav"]);
1747 if (
enabled[
"nav_hpposllh"]) {
1754 sensor_msgs::NavSatFix fix_msg;
1759 fix_msg.header.frame_id =
frame_id;
1760 fix_msg.latitude = m.lat * 1e-7 + m.latHp * 1e-9;
1761 fix_msg.longitude = m.lon * 1e-7 + m.lonHp * 1e-9;
1762 fix_msg.altitude = m.height * 1e-3 + m.heightHp * 1e-4;
1764 if (m.invalid_llh) {
1765 fix_msg.status.status = fix_msg.status.STATUS_NO_FIX;
1767 fix_msg.status.status = fix_msg.status.STATUS_FIX;
1771 const double varH = pow(m.hAcc / 10000.0, 2);
1772 const double varV = pow(m.vAcc / 10000.0, 2);
1774 fix_msg.position_covariance[0] = varH;
1775 fix_msg.position_covariance[4] = varH;
1776 fix_msg.position_covariance[8] = varV;
1777 fix_msg.position_covariance_type =
1778 sensor_msgs::NavSatFix::COVARIANCE_TYPE_DIAGONAL_KNOWN;
1780 fix_msg.status.service = fix_msg.status.SERVICE_GPS;
1781 fixPublisher.
publish(fix_msg);
1786 if (
enabled[
"nav_relposned"]) {
1788 nh->advertise<ublox_msgs::NavRELPOSNED9>(
"navrelposned",
kROSQueueSize);
1799 imu_.linear_acceleration_covariance[0] = -1;
1800 imu_.angular_velocity_covariance[0] = -1;
1803 double heading = M_PI_2 - (
static_cast<double>(m.relPosHeading) * 1e-5 / 180.0 * M_PI);
1805 orientation.
setRPY(0, 0, heading);
1806 imu_.orientation.x = orientation[0];
1807 imu_.orientation.y = orientation[1];
1808 imu_.orientation.z = orientation[2];
1809 imu_.orientation.w = orientation[3];
1810 imu_.orientation_covariance[0] = 1000.0;
1811 imu_.orientation_covariance[4] = 1000.0;
1812 imu_.orientation_covariance[8] = 1000.0;
1814 if (m.flags & ublox_msgs::NavRELPOSNED9::FLAGS_REL_POS_HEAD_VALID)
1816 imu_.orientation_covariance[8] = pow(m.accHeading * 1e-5 / 180.0 * M_PI, 2);
1836 throw std::runtime_error(std::string(
"Failed to Configure TIM Product to UTC Time"));
1839 throw std::runtime_error(std::string(
"Failed to Configure TIM Product"));
1853 ROS_INFO(
"Subscribed to TIM-TM2 messages on topic tim/tm2");
1874 nh->advertise<sensor_msgs::TimeReference>(
"interrupt_time",
kROSQueueSize);
1877 t_ref_.header.seq = m.risingEdgeCount;
1881 t_ref_.time_ref =
ros::Time((m.wnR * 604800 + m.towMsR / 1000), (m.towMsR % 1000) * 1000000 + m.towSubMsR);
1883 std::ostringstream src;
1884 src <<
"TIM" << int(m.ch);
1885 t_ref_.source = src.str();
1891 time_ref_pub.publish(
t_ref_);