31 #include <GeographicLib/UTMUPS.hpp>
32 #include <boost/tokenizer.hpp>
88 msg.pose.covariance[0] = -1.0;
89 msg.pose.covariance[7] = -1.0;
90 msg.pose.covariance[14] = -1.0;
102 msg.pose.pose.orientation =
106 msg.pose.pose.orientation =
125 msg.pose.covariance[21] = -1.0;
126 msg.pose.covariance[28] = -1.0;
127 msg.pose.covariance[35] = -1.0;
174 roll = std::isnan(roll) ? 0.0 : roll;
175 pitch = std::isnan(pitch) ? 0.0 : pitch;
196 msg.pose.covariance[23] =
204 msg.pose.covariance[33] =
211 publish<PoseWithCovarianceStampedMsg>(
"pose", msg);
215 const std::shared_ptr<Telegram>& telegram)
228 std::string serialnumber;
232 serialnumber =
"unknown";
235 uint16_t indicators_type_mask =
static_cast<uint16_t
>(255);
236 uint16_t indicators_value_mask =
static_cast<uint16_t
>(3840);
237 uint16_t qualityind_pos;
238 for (uint16_t i =
static_cast<uint16_t
>(0);
242 static_cast<uint16_t
>(0))
246 8) ==
static_cast<uint16_t
>(0))
248 gnss_status.level = DiagnosticStatusMsg::STALE;
250 indicators_value_mask) >>
251 8) ==
static_cast<uint16_t
>(1) ||
253 indicators_value_mask) >>
254 8) ==
static_cast<uint16_t
>(2))
259 gnss_status.level = DiagnosticStatusMsg::OK;
272 for (uint16_t i =
static_cast<uint16_t
>(0);
275 if (i == qualityind_pos)
280 static_cast<uint16_t
>(1))
282 gnss_status.values[i].key =
"GNSS Signals, Main Antenna";
283 gnss_status.values[i].value = std::to_string(
286 static_cast<uint16_t
>(2))
288 gnss_status.values[i].key =
"GNSS Signals, Aux1 Antenna";
289 gnss_status.values[i].value = std::to_string(
292 static_cast<uint16_t
>(11))
294 gnss_status.values[i].key =
"RF Power, Main Antenna";
295 gnss_status.values[i].value = std::to_string(
298 static_cast<uint16_t
>(12))
300 gnss_status.values[i].key =
"RF Power, Aux1 Antenna";
301 gnss_status.values[i].value = std::to_string(
304 static_cast<uint16_t
>(21))
306 gnss_status.values[i].key =
"CPU Headroom";
307 gnss_status.values[i].value = std::to_string(
310 static_cast<uint16_t
>(25))
312 gnss_status.values[i].key =
"OCXO Stability";
313 gnss_status.values[i].value = std::to_string(
316 static_cast<uint16_t
>(30))
318 gnss_status.values[i].key =
"Base Station Measurements";
319 gnss_status.values[i].value = std::to_string(
324 static_cast<uint16_t
>(31));
325 gnss_status.values[i].key =
"RTK Post-Processing";
326 gnss_status.values[i].value = std::to_string(
330 gnss_status.hardware_id = serialnumber;
331 gnss_status.name =
"septentrio_driver: Quality indicators";
332 gnss_status.message =
333 "GNSS quality Indicators (from 0 for low quality to 10 for high quality, 15 if unknown)";
334 msg.status.push_back(gnss_status);
336 receiver_status.hardware_id = serialnumber;
337 receiver_status.name =
"septentrio_driver: receiver status";
338 receiver_status.message =
"Receiver status";
339 receiver_status.values.resize(5);
340 receiver_status.values[0].key =
"ExtError";
341 receiver_status.values[0].value =
343 receiver_status.values[1].key =
"RxError";
344 receiver_status.values[1].value =
346 receiver_status.values[2].key =
"RxStatus";
347 receiver_status.values[2].value =
349 receiver_status.values[3].key =
"Uptime in s";
350 receiver_status.values[3].value =
352 receiver_status.values[4].key =
"CPU load in %";
353 receiver_status.values[4].value =
360 receiver_status.level = DiagnosticStatusMsg::OK;
361 msg.status.push_back(receiver_status);
378 publish<DiagnosticArrayMsg>(
"/diagnostics", msg);
387 diagOsnma.name =
"septentrio_driver: OSNMA";
388 diagOsnma.message =
"Current status of the OSNMA authentication";
390 diagOsnma.values.resize(6);
391 diagOsnma.values[0].key =
"status";
396 diagOsnma.values[0].value =
"Disabled";
402 diagOsnma.values[0].value =
403 "Initializing " + std::to_string(percent) +
" %";
408 diagOsnma.values[0].value =
"Waiting on NTP";
413 diagOsnma.values[0].value =
"Init failed - inconsistent time";
418 diagOsnma.values[0].value =
"Init failed - KROOT signature invalid";
423 diagOsnma.values[0].value =
"Init failed - invalid param received";
428 diagOsnma.values[0].value =
"Authenticating";
436 diagOsnma.values[1].key =
"trusted_time_delta";
438 diagOsnma.values[1].value =
441 diagOsnma.values[1].value =
"N/A";
445 uint8_t gal_authentic = (gal_auth & gal_active).count();
446 uint8_t gal_spoofed = (~gal_auth & gal_active).count();
447 diagOsnma.values[2].key =
"Galileo authentic";
448 diagOsnma.values[2].value = std::to_string(gal_authentic);
449 diagOsnma.values[3].key =
"Galileo spoofed";
450 diagOsnma.values[3].value = std::to_string(gal_spoofed);
454 uint8_t gps_authentic = (gps_auth & gps_active).count();
455 uint8_t gps_spoofed = (~gps_auth & gps_active).count();
456 diagOsnma.values[4].key =
"GPS authentic";
457 diagOsnma.values[4].value = std::to_string(gps_authentic);
458 diagOsnma.values[5].key =
"GPS spoofed";
459 diagOsnma.values[5].value = std::to_string(gps_spoofed);
461 if ((gal_spoofed + gps_spoofed) == 0)
462 diagOsnma.level = DiagnosticStatusMsg::OK;
463 else if ((gal_authentic + gps_authentic) > 0)
468 msg.status.push_back(diagOsnma);
471 publish<DiagnosticArrayMsg>(
"/diagnostics", msg);
480 diagRf.name =
"septentrio_driver: AIM+ status";
482 "Current status of the AIM+ interference and spoofing mitigation";
484 diagRf.values.resize(2);
485 diagRf.values[0].key =
"interference";
486 bool mitigated =
false;
487 bool detected =
false;
490 std::bitset<8> info = rfband.info;
501 diagRf.values[0].value =
"present";
502 aimMsg.interference = AimPlusStatusMsg::INTERFERENCE_PRESENT;
503 }
else if (mitigated)
505 diagRf.values[0].value =
"mitigated";
506 aimMsg.interference = AimPlusStatusMsg::INTERFERENCE_MITIGATED;
509 diagRf.values[0].value =
"spectrum clean";
510 aimMsg.interference = AimPlusStatusMsg::SPECTRUM_CLEAN;
513 diagRf.values[1].key =
"spoofing";
514 bool spoofed =
false;
516 if (flags.test(0) && flags.test(1))
518 diagRf.values[1].value =
"detected by OSNMA and authenticity test";
520 AimPlusStatusMsg::SPOOFING_DETECTED_BY_OSNMA_AND_AUTHENTCITY_TEST;
522 }
else if (flags.test(0))
524 diagRf.values[1].value =
"detected by authenticity test";
526 AimPlusStatusMsg::SPOOFING_DETECTED_BY_AUTHENTCITY_TEST;
528 }
else if (flags.test(1))
530 diagRf.values[1].value =
"detected by OSNMA";
531 aimMsg.spoofing = AimPlusStatusMsg::SPOOFING_DETECTED_BY_OSNMA;
535 diagRf.values[1].value =
"none detected";
536 aimMsg.spoofing = AimPlusStatusMsg::NONE_DETECTED;
540 aimMsg.osnma_authenticating =
544 aimMsg.galileo_authentic = (gal_auth & gal_active).count();
545 aimMsg.galileo_spoofed = (~gal_auth & gal_active).count();
548 aimMsg.gps_authentic = (gps_auth & gps_active).count();
549 aimMsg.gps_spoofed = (~gps_auth & gps_active).count();
552 aimMsg.osnma_authenticating =
false;
553 aimMsg.galileo_authentic = 0;
554 aimMsg.galileo_spoofed = 0;
555 aimMsg.gps_authentic = 0;
556 aimMsg.gps_spoofed = 0;
561 publish<AimPlusStatusMsg>(
"aimplusstatus", aimMsg);
563 if (spoofed || detected)
568 diagRf.level = DiagnosticStatusMsg::OK;
570 msg.status.push_back(diagRf);
573 publish<DiagnosticArrayMsg>(
"/diagnostics", msg);
596 bool valid_orientation =
false;
610 valid_orientation =
true;
615 valid_orientation =
true;
625 msg.orientation_covariance[0] =
628 msg.orientation_covariance[4] =
631 msg.orientation_covariance[8] =
638 msg.orientation_covariance[1] =
641 msg.orientation_covariance[2] =
644 msg.orientation_covariance[3] =
648 msg.orientation_covariance[5] =
651 msg.orientation_covariance[6] =
654 msg.orientation_covariance[7] =
660 msg.orientation_covariance[0] = -1.0;
661 msg.orientation_covariance[4] = -1.0;
662 msg.orientation_covariance[8] = -1.0;
667 if (!valid_orientation)
672 publish<ImuMsg>(
"imu", msg);
682 msg.twist.covariance[21] = -1.0;
683 msg.twist.covariance[28] = -1.0;
684 msg.twist.covariance[35] = -1.0;
709 msg.twist.twist.linear.x = vel(0);
710 msg.twist.twist.linear.y = vel(1);
711 msg.twist.twist.linear.z = vel(2);
721 Eigen::Matrix3d covVel_local = Eigen::Matrix3d::Zero();
731 covVel_local(0, 0) = -1.0;
738 covVel_local(1, 1) = -1.0;
742 covVel_local(2, 2) = -1.0;
745 covVel_local(0, 1) = covVel_local(1, 0) =
750 covVel_local(0, 2) = covVel_local(2, 0) =
753 covVel_local(2, 1) = covVel_local(1, 2) =
758 covVel_local(0, 2) = covVel_local(2, 0) =
761 covVel_local(2, 1) = covVel_local(1, 2) =
766 covVel_local(0, 0) = -1.0;
767 covVel_local(1, 1) = -1.0;
768 covVel_local(2, 2) = -1.0;
771 msg.twist.covariance[0] = covVel_local(0, 0);
772 msg.twist.covariance[1] = covVel_local(0, 1);
773 msg.twist.covariance[2] = covVel_local(0, 2);
774 msg.twist.covariance[6] = covVel_local(1, 0);
775 msg.twist.covariance[7] = covVel_local(1, 1);
776 msg.twist.covariance[8] = covVel_local(1, 2);
777 msg.twist.covariance[12] = covVel_local(2, 0);
778 msg.twist.covariance[13] = covVel_local(2, 1);
779 msg.twist.covariance[14] = covVel_local(2, 2);
782 msg.twist.covariance[0] = -1.0;
783 msg.twist.covariance[7] = -1.0;
784 msg.twist.covariance[14] = -1.0;
787 publish<TwistWithCovarianceStampedMsg>(
"twist_ins", msg);
813 msg.twist.twist.linear.x = vel(0);
814 msg.twist.twist.linear.y = vel(1);
815 msg.twist.twist.linear.z = vel(2);
823 Eigen::Matrix3d covVel_local = Eigen::Matrix3d::Zero();
831 covVel_local(0, 0) = -1.0;
838 covVel_local(1, 1) = -1.0;
842 covVel_local(2, 2) = -1.0;
844 covVel_local(0, 1) = covVel_local(1, 0) =
849 covVel_local(0, 2) = covVel_local(2, 0) =
852 covVel_local(2, 1) = covVel_local(1, 2) =
857 covVel_local(0, 2) = covVel_local(2, 0) =
860 covVel_local(2, 1) = covVel_local(1, 2) =
864 msg.twist.covariance[0] = covVel_local(0, 0);
865 msg.twist.covariance[1] = covVel_local(0, 1);
866 msg.twist.covariance[2] = covVel_local(0, 2);
867 msg.twist.covariance[6] = covVel_local(1, 0);
868 msg.twist.covariance[7] = covVel_local(1, 1);
869 msg.twist.covariance[8] = covVel_local(1, 2);
870 msg.twist.covariance[12] = covVel_local(2, 0);
871 msg.twist.covariance[13] = covVel_local(2, 1);
872 msg.twist.covariance[14] = covVel_local(2, 2);
875 msg.twist.covariance[0] = -1.0;
876 msg.twist.covariance[7] = -1.0;
877 msg.twist.covariance[14] = -1.0;
880 publish<TwistWithCovarianceStampedMsg>(
"twist_gnss", msg);
898 std::string zonestring;
899 bool northernHemisphere;
902 double meridian_convergence = 0.0;
910 GeographicLib::UTMUPS::Forward(
913 easting, northing, meridian_convergence, k, zone);
914 }
catch (
const std::exception& e)
917 "UTMUPS conversion exception: " + std::string(e.what()));
928 zone, northernHemisphere, easting,
929 northing, meridian_convergence, k);
931 GeographicLib::UTMUPS::EncodeZone(zone, northernHemisphere);
932 }
catch (
const std::exception& e)
935 "UTMUPS conversion exception: " + std::string(e.what()));
945 msg.pose.pose.position.x = easting;
946 msg.pose.pose.position.y = northing;
950 msg.pose.pose.position.x = northing;
951 msg.pose.pose.position.y = easting;
955 msg.header.frame_id =
"utm_" + zonestring;
962 Eigen::Matrix3d P_pos = -Eigen::Matrix3d::Identity();
983 yaw +=
deg2rad(meridian_convergence);
985 yaw -=
deg2rad(meridian_convergence);
990 msg.pose.pose.orientation =
1007 msg.pose.covariance[21] = -1.0;
1008 msg.pose.covariance[28] = -1.0;
1009 msg.pose.covariance[35] = -1.0;
1037 double cg = std::cos(meridian_convergence);
1038 double sg = std::sin(meridian_convergence);
1039 Eigen::Matrix3d R = Eigen::Matrix3d::Identity();
1044 P_pos = (R * P_pos * R.transpose()).eval();
1047 msg.pose.covariance[0] = P_pos(0, 0);
1048 msg.pose.covariance[1] = P_pos(0, 1);
1049 msg.pose.covariance[2] = P_pos(0, 2);
1050 msg.pose.covariance[6] = P_pos(1, 0);
1051 msg.pose.covariance[7] = P_pos(1, 1);
1052 msg.pose.covariance[8] = P_pos(1, 2);
1053 msg.pose.covariance[12] = P_pos(2, 0);
1054 msg.pose.covariance[13] = P_pos(2, 1);
1055 msg.pose.covariance[14] = P_pos(2, 2);
1078 publish<LocalizationMsg>(
"localization", msg);
1099 msg.header.frame_id =
"ecef";
1119 msg.pose.covariance[0] = -1.0;
1120 msg.pose.covariance[7] = -1.0;
1121 msg.pose.covariance[14] = -1.0;
1148 Eigen::Quaterniond q_local_ecef;
1155 Eigen::Quaterniond q_b_local =
1158 Eigen::Quaterniond q_b_ecef = q_local_ecef * q_b_local;
1160 msg.pose.pose.orientation =
1166 Eigen::Matrix3d covAtt_local = Eigen::Matrix3d::Zero();
1167 bool covAttValid =
true;
1182 covAtt_local(0, 0) = -1.0;
1183 covAtt_local(1, 1) = -1.0;
1184 covAtt_local(2, 2) = -1.0;
1185 covAttValid =
false;
1207 Eigen::Matrix3d R_local_ecef;
1215 Eigen::Matrix3d covAtt_ecef =
1216 R_local_ecef * covAtt_local * R_local_ecef.transpose();
1218 msg.pose.covariance[21] = covAtt_ecef(0, 0);
1219 msg.pose.covariance[22] = covAtt_ecef(0, 1);
1220 msg.pose.covariance[23] = covAtt_ecef(0, 2);
1221 msg.pose.covariance[27] = covAtt_ecef(1, 0);
1222 msg.pose.covariance[28] = covAtt_ecef(1, 1);
1223 msg.pose.covariance[29] = covAtt_ecef(1, 2);
1224 msg.pose.covariance[33] = covAtt_ecef(2, 0);
1225 msg.pose.covariance[34] = covAtt_ecef(2, 1);
1226 msg.pose.covariance[35] = covAtt_ecef(2, 2);
1229 msg.pose.covariance[21] = -1.0;
1230 msg.pose.covariance[28] = -1.0;
1231 msg.pose.covariance[35] = -1.0;
1237 publish<LocalizationMsg>(
"localization_ecef", msg);
1248 Eigen::Matrix3d R_local_body =
1256 Eigen::Vector3d vel_local;
1260 vel_local << ve, vn, vu;
1264 vel_local << vn, ve, -vu;
1267 Eigen::Vector3d vel_body = R_local_body * vel_local;
1268 msg.twist.twist.linear.x = vel_body(0);
1269 msg.twist.twist.linear.y = vel_body(1);
1270 msg.twist.twist.linear.z = vel_body(2);
1275 Eigen::Matrix3d covVel_local = Eigen::Matrix3d::Zero();
1285 covVel_local(0, 0) = -1.0;
1292 covVel_local(1, 1) = -1.0;
1296 covVel_local(2, 2) = -1.0;
1299 covVel_local(0, 0) = -1.0;
1300 covVel_local(1, 1) = -1.0;
1301 covVel_local(2, 2) = -1.0;
1313 covVel_local(0, 2) = covVel_local(2, 0) =
1315 covVel_local(2, 1) = covVel_local(1, 2) =
1328 Eigen::Matrix3d covVel_body =
1329 R_local_body * covVel_local * R_local_body.transpose();
1331 msg.twist.covariance[0] = covVel_body(0, 0);
1332 msg.twist.covariance[1] = covVel_body(0, 1);
1333 msg.twist.covariance[2] = covVel_body(0, 2);
1334 msg.twist.covariance[6] = covVel_body(1, 0);
1335 msg.twist.covariance[7] = covVel_body(1, 1);
1336 msg.twist.covariance[8] = covVel_body(1, 2);
1337 msg.twist.covariance[12] = covVel_body(2, 0);
1338 msg.twist.covariance[13] = covVel_body(2, 1);
1339 msg.twist.covariance[14] = covVel_body(2, 2);
1342 msg.twist.covariance[0] = -1.0;
1343 msg.twist.covariance[7] = -1.0;
1344 msg.twist.covariance[14] = -1.0;
1347 msg.twist.covariance[21] = -1.0;
1348 msg.twist.covariance[28] = -1.0;
1349 msg.twist.covariance[35] = -1.0;
1358 msg.status.status = NavSatStatusMsg::STATUS_NO_FIX;
1363 msg.status.status = NavSatStatusMsg::STATUS_FIX;
1368 msg.status.status = NavSatStatusMsg::STATUS_FIX;
1373 msg.status.status = NavSatStatusMsg::STATUS_FIX;
1378 msg.status.status = NavSatStatusMsg::STATUS_FIX;
1383 msg.status.status = NavSatStatusMsg::STATUS_FIX;
1388 msg.status.status = NavSatStatusMsg::STATUS_FIX;
1393 msg.status.status = NavSatStatusMsg::STATUS_FIX;
1398 msg.status.status = NavSatStatusMsg::STATUS_FIX;
1403 msg.status.status = NavSatStatusMsg::STATUS_SBAS_FIX;
1408 msg.status.status = NavSatStatusMsg::STATUS_NO_FIX;
1411 "PVTGeodetic's Mode field contains an invalid type of PVT solution.");
1443 bool gps_in_pvt =
false;
1444 bool glo_in_pvt =
false;
1445 bool com_in_pvt =
false;
1446 bool gal_in_pvt =
false;
1447 uint32_t mask_2 = 1;
1448 for (
int bit = 0; bit != 31; ++bit)
1451 if (bit <= 5 && in_use)
1455 if (8 <= bit && bit <= 12 && in_use)
1457 if (((13 <= bit && bit <= 14) || (28 <= bit && bit <= 30)) && in_use)
1459 if ((bit == 17 || (19 <= bit && bit <= 22)) && in_use)
1465 gps_in_pvt * 1 + glo_in_pvt * 2 + com_in_pvt * 4 + gal_in_pvt * 8;
1466 msg.status.service = service;
1479 msg.position_covariance_type = NavSatFixMsg::COVARIANCE_TYPE_KNOWN;
1493 bool gps_in_pvt =
false;
1494 bool glo_in_pvt =
false;
1495 bool com_in_pvt =
false;
1496 bool gal_in_pvt =
false;
1497 uint32_t mask_2 = 1;
1498 for (
int bit = 0; bit != 31; ++bit)
1501 if (bit <= 5 && in_use)
1505 if (8 <= bit && bit <= 12 && in_use)
1507 if (((13 <= bit && bit <= 14) || (28 <= bit && bit <= 30)) && in_use)
1509 if ((bit == 17 || (19 <= bit && bit <= 22)) && in_use)
1515 gps_in_pvt * 1 + glo_in_pvt * 2 + com_in_pvt * 4 + gal_in_pvt * 8;
1516 msg.status.service = service;
1523 msg.position_covariance[0] =
1525 msg.position_covariance[4] =
1538 msg.position_covariance_type =
1539 NavSatFixMsg::COVARIANCE_TYPE_DIAGONAL_KNOWN;
1541 publish<NavSatFixMsg>(
"navsatfix", msg);
1550 msg.status.status = GpsStatusMsg::STATUS_NO_FIX;
1555 msg.status.status = GpsStatusMsg::STATUS_FIX;
1560 msg.status.status = GpsStatusMsg::STATUS_FIX;
1565 msg.status.status = GpsStatusMsg::STATUS_DGPS_FIX;
1570 msg.status.status = GpsStatusMsg::STATUS_DGPS_FIX;
1575 msg.status.status = GpsStatusMsg::STATUS_DGPS_FIX;
1580 msg.status.status = GpsStatusMsg::STATUS_DGPS_FIX;
1585 msg.status.status = GpsStatusMsg::STATUS_DGPS_FIX;
1590 msg.status.status = GpsStatusMsg::STATUS_DGPS_FIX;
1597 if (reference_id == 131 || reference_id == 133 || reference_id == 135 ||
1598 reference_id == 135)
1600 msg.status.status = GpsStatusMsg::STATUS_WAAS_FIX;
1603 msg.status.status = GpsStatusMsg::STATUS_SBAS_FIX;
1609 msg.status.status = GpsStatusMsg::STATUS_NO_FIX;
1612 "PVTGeodetic's Mode field contains an invalid type of PVT solution.");
1673 std::vector<int32_t> cno_tracked;
1674 std::vector<int32_t> svid_in_sync;
1682 svid_in_sync.push_back(
1683 static_cast<int32_t
>(measepoch_channel_type1.sv_id));
1686 if (((measepoch_channel_type1.type & type_mask) ==
1687 static_cast<uint8_t
>(1)) ||
1688 ((measepoch_channel_type1.type & type_mask) ==
1689 static_cast<uint8_t
>(2)))
1691 cno_tracked.push_back(
1692 static_cast<int32_t
>(measepoch_channel_type1.cn0) / 4);
1695 cno_tracked.push_back(
1696 static_cast<int32_t
>(measepoch_channel_type1.cn0) / 4 +
1697 static_cast<int32_t
>(10));
1703 std::vector<int32_t> svid_in_sync_2;
1704 std::vector<int32_t> elevation_tracked;
1705 std::vector<int32_t> azimuth_tracked;
1706 std::vector<int32_t> svid_pvt;
1708 std::vector<int32_t> ordering;
1715 bool to_be_added =
false;
1716 for (int32_t j = 0; j < static_cast<int32_t>(svid_in_sync.size());
1719 if (svid_in_sync[j] ==
1720 static_cast<int32_t
>(channel_sat_info.sv_id))
1722 ordering.push_back(j);
1729 svid_in_sync_2.push_back(
1730 static_cast<int32_t
>(channel_sat_info.sv_id));
1731 elevation_tracked.push_back(
1732 static_cast<int32_t
>(channel_sat_info.elev));
1733 constexpr uint16_t azimuth_mask = 511;
1734 azimuth_tracked.push_back(
static_cast<int32_t
>(
1735 (channel_sat_info.az_rise_set & azimuth_mask)));
1737 svid_pvt.reserve(channel_sat_info.stateInfo.size());
1738 for (
const auto& channel_state_info : channel_sat_info.stateInfo)
1741 bool pvt_status =
false;
1742 uint16_t pvt_status_mask = std::pow(2, 15) + std::pow(2, 14);
1743 for (
int k = 15; k != -1; k -= 2)
1745 uint16_t pvt_status_value =
1746 (channel_state_info.pvt_status & pvt_status_mask) >>
1748 if (pvt_status_value == 2)
1754 pvt_status_mask = pvt_status_mask - std::pow(2, k) -
1755 std::pow(2, k - 1) +
1756 std::pow(2, k - 2) +
1763 static_cast<int32_t
>(channel_sat_info.sv_id));
1768 msg.status.satellite_used_prn =
1771 msg.status.satellites_visible =
static_cast<uint16_t
>(svid_in_sync.size());
1772 msg.status.satellite_visible_prn = svid_in_sync_2;
1773 msg.status.satellite_visible_z = elevation_tracked;
1774 msg.status.satellite_visible_azimuth = azimuth_tracked;
1777 std::vector<int32_t> cno_tracked_reordered;
1780 for (int32_t k = 0; k < static_cast<int32_t>(ordering.size()); ++k)
1782 cno_tracked_reordered.push_back(cno_tracked[ordering[k]]);
1785 msg.status.satellite_visible_snr = cno_tracked_reordered;
1796 msg.status.motion_source = GpsStatusMsg::SOURCE_POINTS;
1799 msg.status.orientation_source = GpsStatusMsg::SOURCE_POINTS;
1800 msg.status.position_source = GpsStatusMsg::SOURCE_GPS;
1897 msg.position_covariance_type = NavSatFixMsg::COVARIANCE_TYPE_KNOWN;
1906 msg.status.motion_source = GpsStatusMsg::SOURCE_POINTS;
1909 msg.status.orientation_source = GpsStatusMsg::SOURCE_POINTS;
1910 msg.status.position_source = GpsStatusMsg::SOURCE_GPS;
2005 msg.position_covariance[0] =
2007 msg.position_covariance[4] =
2020 msg.position_covariance_type =
2021 NavSatFixMsg::COVARIANCE_TYPE_DIAGONAL_KNOWN;
2023 publish<GpsFixMsg>(
"gpsfix", msg);
2032 msg.source =
"GPST";
2034 publish<TimeReferenceMsg>(
"gpst", msg);
2037 template <
typename T>
2039 const std::shared_ptr<Telegram>& telegram,
2045 msg.header.frame_id =
frameId;
2049 if constexpr (std::is_same<INSNavCartMsg, T>::value ||
2050 std::is_same<INSNavGeodMsg, T>::value)
2052 time_obj -= msg.latency * 100000ul;
2053 }
else if constexpr (std::is_same<PVTCartesianMsg, T>::value ||
2054 std::is_same<PVTGeodeticMsg, T>::value)
2058 }
else if constexpr (std::is_same<PosCovCartesianMsg, T>::value ||
2059 std::is_same<PosCovGeodeticMsg, T>::value ||
2060 std::is_same<VelCovCartesianMsg, T>::value ||
2061 std::is_same<VelCovGeodeticMsg, T>::value ||
2062 std::is_same<AttEulerMsg, T>::value ||
2063 std::is_same<AttCovEulerMsg, T>::value ||
2064 std::is_same<BaseVectorCartMsg, T>::value ||
2065 std::is_same<BaseVectorGeodMsg, T>::value)
2096 constexpr uint64_t secToNSec = 1000000000;
2097 constexpr uint64_t mSec2NSec = 1000000;
2098 constexpr uint64_t nsOfGpsStart =
2102 constexpr uint64_t nsecPerWeek = 7 * 24 * 60 * 60 * secToNSec;
2104 time_obj = nsOfGpsStart + tow * mSec2NSec + wnc * nsecPerWeek;
2116 template <
typename M>
2132 "Not publishing message with GNSS time because no leap seconds are available yet.");
2137 "No leap seconds were set and none were received from log yet.");
2161 "Not publishing tf with GNSS time because no leap seconds are available yet.");
2166 "No leap seconds were set and none were received from log yet. ");
2191 telegram->message.end(), msg))
2197 publish<PVTCartesianMsg>(
"pvtcartesian", msg);
2230 telegram->message.end(), msg))
2236 publish<BaseVectorCartMsg>(
"basevectorcart", msg);
2247 telegram->message.end(), msg))
2253 publish<BaseVectorGeodMsg>(
"basevectorgeod", msg);
2264 telegram->message.end(), msg))
2270 publish<PosCovCartesianMsg>(
"poscovcartesian", msg);
2426 telegram->message.end(), msg,
2433 publish<IMUSetupMsg>(
"imusetup", msg);
2444 telegram->message.end(), msg,
2451 publish<VelSensorSetupMsg>(
"velsensorsetup", msg);
2463 telegram->message.end(), msg,
2467 "parse error in ExtEventINSNavCart");
2479 publish<INSNavCartMsg>(
"exteventinsnavcart", msg);
2490 telegram->message.end(), msg,
2494 "parse error in ExtEventINSNavGeod");
2506 publish<INSNavGeodMsg>(
"exteventinsnavgeod", msg);
2554 if (!
DOPParser(
node_, telegram->message.begin(), telegram->message.end(),
2570 telegram->message.end(), msg))
2576 publish<VelCovCartesianMsg>(
"velcovcartesian", msg);
2630 static const int32_t ins_major = 1;
2631 static const int32_t ins_minor = 4;
2632 static const int32_t ins_patch = 0;
2633 static const int32_t gnss_major = 4;
2634 static const int32_t gnss_minor = 12;
2635 static const int32_t gnss_patch = 1;
2637 boost::tokenizer<>::iterator it = tok.begin();
2638 std::vector<int32_t> major_minor_patch;
2639 major_minor_patch.reserve(3);
2640 for (boost::tokenizer<>::iterator it = tok.begin(); it != tok.end();
2643 int32_t v = std::atoi(it->c_str());
2644 major_minor_patch.push_back(v);
2646 if (major_minor_patch.size() < 3)
2653 if ((major_minor_patch[0] < ins_major) ||
2654 ((major_minor_patch[0] == ins_major) &&
2655 (major_minor_patch[1] < ins_minor)) ||
2656 ((major_minor_patch[0] == ins_major) &&
2657 (major_minor_patch[1] == ins_minor) &&
2658 (major_minor_patch[2] < ins_patch)))
2662 "INS receiver has firmware version: " +
2664 ", which does not support all features. Please update to at least " +
2665 std::to_string(ins_major) +
"." +
2666 std::to_string(ins_minor) +
"." +
2667 std::to_string(ins_patch) +
" or consult README.");
2672 if ((major_minor_patch[0] < gnss_major) ||
2673 ((major_minor_patch[0] == gnss_major) &&
2674 (major_minor_patch[1] < gnss_minor)) ||
2675 ((major_minor_patch[0] == gnss_major) &&
2676 (major_minor_patch[1] == gnss_minor) &&
2677 (major_minor_patch[2] < gnss_patch)))
2681 "GNSS receiver has firmware version: " +
2683 ", which may not support all features. Please update to at least " +
2684 std::to_string(gnss_major) +
"." +
2685 std::to_string(gnss_minor) +
"." +
2686 std::to_string(gnss_patch) +
" or consult README.");
2698 telegram->message.end(), msg))
2709 std::to_string(sbfId) +
" received.");
2720 if ((unix_old != 0) && (
unix_time_ > unix_old))
2724 std::stringstream ss;
2725 ss <<
"Waiting for " << sleep_nsec / 1000000 <<
" milliseconds...";
2728 std::this_thread::sleep_for(std::chrono::nanoseconds(sleep_nsec));
2734 std::string message(telegram->message.begin(), telegram->message.end());
2739 boost::char_separator<char> sep_2(
",*",
"", boost::keep_empty_tokens);
2740 boost::tokenizer<boost::char_separator<char>> tokens(message, sep_2);
2741 std::vector<std::string> body;
2743 for (boost::tokenizer<boost::char_separator<char>>::iterator tok_iter =
2745 tok_iter != tokens.end(); ++tok_iter)
2747 body.push_back(*tok_iter);
2750 std::string id(body[0].begin() + 1, body[0].end());
2771 "GpggaMsg: " + std::string(e.what()));
2774 publish<GpggaMsg>(
"gpgga", msg);
2791 "GprmcMsg: " + std::string(e.what()));
2794 publish<GprmcMsg>(
"gprmc", msg);
2811 "GpgsaMsg: " + std::string(e.what()));
2832 publish<GpgsaMsg>(
"gpgsa", msg);
2849 "GpgsvMsg: " + std::string(e.what()));
2871 publish<GpgsvMsg>(
"gpgsv", msg);