31 #include <GeographicLib/UTMUPS.hpp>
32 #include <boost/tokenizer.hpp>
87 msg.pose.covariance[0] = -1.0;
88 msg.pose.covariance[7] = -1.0;
89 msg.pose.covariance[14] = -1.0;
107 msg.pose.pose.orientation.w =
108 std::numeric_limits<double>::quiet_NaN();
109 msg.pose.pose.orientation.x =
110 std::numeric_limits<double>::quiet_NaN();
111 msg.pose.pose.orientation.y =
112 std::numeric_limits<double>::quiet_NaN();
113 msg.pose.pose.orientation.z =
114 std::numeric_limits<double>::quiet_NaN();
120 msg.pose.covariance[21] =
123 msg.pose.covariance[21] = -1.0;
125 msg.pose.covariance[28] =
128 msg.pose.covariance[28] = -1.0;
130 msg.pose.covariance[35] =
133 msg.pose.covariance[35] = -1.0;
136 msg.pose.covariance[21] = -1.0;
137 msg.pose.covariance[28] = -1.0;
138 msg.pose.covariance[35] = -1.0;
154 msg.pose.covariance[23] =
158 msg.pose.covariance[29] =
160 msg.pose.covariance[33] =
162 msg.pose.covariance[34] =
213 publish<PoseWithCovarianceStampedMsg>(
"pose", msg);
217 const std::shared_ptr<Telegram>& telegram)
227 std::string serialnumber;
231 serialnumber =
"unknown";
234 uint16_t indicators_type_mask =
static_cast<uint16_t
>(255);
235 uint16_t indicators_value_mask =
static_cast<uint16_t
>(3840);
236 uint16_t qualityind_pos;
237 for (uint16_t i =
static_cast<uint16_t
>(0);
241 static_cast<uint16_t
>(0))
245 8) ==
static_cast<uint16_t
>(0))
247 gnss_status.level = DiagnosticStatusMsg::STALE;
249 indicators_value_mask) >>
250 8) ==
static_cast<uint16_t
>(1) ||
252 indicators_value_mask) >>
253 8) ==
static_cast<uint16_t
>(2))
258 gnss_status.level = DiagnosticStatusMsg::OK;
271 for (uint16_t i =
static_cast<uint16_t
>(0);
274 if (i == qualityind_pos)
279 static_cast<uint16_t
>(1))
281 gnss_status.values[i].key =
"GNSS Signals, Main Antenna";
282 gnss_status.values[i].value = std::to_string(
285 static_cast<uint16_t
>(2))
287 gnss_status.values[i].key =
"GNSS Signals, Aux1 Antenna";
288 gnss_status.values[i].value = std::to_string(
291 static_cast<uint16_t
>(11))
293 gnss_status.values[i].key =
"RF Power, Main Antenna";
294 gnss_status.values[i].value = std::to_string(
297 static_cast<uint16_t
>(12))
299 gnss_status.values[i].key =
"RF Power, Aux1 Antenna";
300 gnss_status.values[i].value = std::to_string(
303 static_cast<uint16_t
>(21))
305 gnss_status.values[i].key =
"CPU Headroom";
306 gnss_status.values[i].value = std::to_string(
309 static_cast<uint16_t
>(25))
311 gnss_status.values[i].key =
"OCXO Stability";
312 gnss_status.values[i].value = std::to_string(
315 static_cast<uint16_t
>(30))
317 gnss_status.values[i].key =
"Base Station Measurements";
318 gnss_status.values[i].value = std::to_string(
323 static_cast<uint16_t
>(31));
324 gnss_status.values[i].key =
"RTK Post-Processing";
325 gnss_status.values[i].value = std::to_string(
329 gnss_status.hardware_id = serialnumber;
330 gnss_status.name =
"septentrio_driver: Quality indicators";
331 gnss_status.message =
332 "GNSS quality Indicators (from 0 for low quality to 10 for high quality, 15 if unknown)";
333 msg.status.push_back(gnss_status);
350 publish<DiagnosticArrayMsg>(
"/diagnostics", msg);
359 diagOsnma.name =
"septentrio_driver: OSNMA";
360 diagOsnma.message =
"Current status of the OSNMA authentication";
362 diagOsnma.values.resize(6);
363 diagOsnma.values[0].key =
"status";
368 diagOsnma.values[0].value =
"Disabled";
374 diagOsnma.values[0].value =
375 "Initializing " + std::to_string(percent) +
" %";
380 diagOsnma.values[0].value =
"Waiting on NTP";
385 diagOsnma.values[0].value =
"Init failed - inconsistent time";
390 diagOsnma.values[0].value =
"Init failed - KROOT signature invalid";
395 diagOsnma.values[0].value =
"Init failed - invalid param received";
400 diagOsnma.values[0].value =
"Authenticating";
408 diagOsnma.values[1].key =
"trusted_time_delta";
410 diagOsnma.values[1].value =
413 diagOsnma.values[1].value =
"N/A";
417 uint8_t gal_authentic = (gal_auth & gal_active).count();
418 uint8_t gal_spoofed = (~gal_auth & gal_active).count();
419 diagOsnma.values[2].key =
"Galileo authentic";
420 diagOsnma.values[2].value = std::to_string(gal_authentic);
421 diagOsnma.values[3].key =
"Galileo spoofed";
422 diagOsnma.values[3].value = std::to_string(gal_spoofed);
426 uint8_t gps_authentic = (gps_auth & gps_active).count();
427 uint8_t gps_spoofed = (~gps_auth & gps_active).count();
428 diagOsnma.values[4].key =
"GPS authentic";
429 diagOsnma.values[4].value = std::to_string(gps_authentic);
430 diagOsnma.values[5].key =
"GPS spoofed";
431 diagOsnma.values[5].value = std::to_string(gps_spoofed);
433 if ((gal_spoofed + gps_spoofed) == 0)
434 diagOsnma.level = DiagnosticStatusMsg::OK;
435 else if ((gal_authentic + gps_authentic) > 0)
440 msg.status.push_back(diagOsnma);
443 publish<DiagnosticArrayMsg>(
"/diagnostics", msg);
452 diagRf.name =
"septentrio_driver: AIM+ status";
454 "Current status of the AIM+ interference and spoofing mitigation";
456 diagRf.values.resize(2);
457 diagRf.values[0].key =
"interference";
458 bool mitigated =
false;
459 bool detected =
false;
462 std::bitset<8> info = rfband.info;
473 diagRf.values[0].value =
"present";
474 aimMsg.interference = AimPlusStatusMsg::INTERFERENCE_PRESENT;
475 }
else if (mitigated)
477 diagRf.values[0].value =
"mitigated";
478 aimMsg.interference = AimPlusStatusMsg::INTERFERENCE_MITIGATED;
481 diagRf.values[0].value =
"spectrum clean";
482 aimMsg.interference = AimPlusStatusMsg::SPECTRUM_CLEAN;
485 diagRf.values[1].key =
"spoofing";
486 bool spoofed =
false;
488 if (flags.test(0) && flags.test(1))
490 diagRf.values[1].value =
"detected by OSNMA and authenticity test";
492 AimPlusStatusMsg::SPOOFING_DETECTED_BY_OSNMA_AND_AUTHENTCITY_TEST;
494 }
else if (flags.test(0))
496 diagRf.values[1].value =
"detected by authenticity test";
498 AimPlusStatusMsg::SPOOFING_DETECTED_BY_AUTHENTCITY_TEST;
500 }
else if (flags.test(1))
502 diagRf.values[1].value =
"detected by OSNMA";
503 aimMsg.spoofing = AimPlusStatusMsg::SPOOFING_DETECTED_BY_OSNMA;
507 diagRf.values[1].value =
"none detected";
508 aimMsg.spoofing = AimPlusStatusMsg::NONE_DETECTED;
512 aimMsg.osnma_authenticating =
516 aimMsg.galileo_authentic = (gal_auth & gal_active).count();
517 aimMsg.galileo_spoofed = (~gal_auth & gal_active).count();
520 aimMsg.gps_authentic = (gps_auth & gps_active).count();
521 aimMsg.gps_spoofed = (~gps_auth & gps_active).count();
524 aimMsg.osnma_authenticating =
false;
525 aimMsg.galileo_authentic = 0;
526 aimMsg.galileo_spoofed = 0;
527 aimMsg.gps_authentic = 0;
528 aimMsg.gps_spoofed = 0;
533 publish<AimPlusStatusMsg>(
"aimplusstatus", aimMsg);
535 if (spoofed || detected)
540 diagRf.level = DiagnosticStatusMsg::OK;
542 msg.status.push_back(diagRf);
545 publish<DiagnosticArrayMsg>(
"/diagnostics", msg);
562 bool valid_orientation =
false;
576 if ((tsImu - tsIns) > maxDt)
578 valid_orientation =
false;
594 valid_orientation =
false;
598 valid_orientation =
false;
607 msg.orientation_covariance[0] =
609 msg.orientation_covariance[4] =
611 msg.orientation_covariance[8] =
615 valid_orientation =
false;
619 valid_orientation =
false;
624 msg.orientation_covariance[1] =
626 msg.orientation_covariance[2] =
628 msg.orientation_covariance[3] =
631 msg.orientation_covariance[5] =
633 msg.orientation_covariance[6] =
635 msg.orientation_covariance[7] =
641 valid_orientation =
false;
645 if (!valid_orientation)
647 msg.orientation.w = std::numeric_limits<double>::quiet_NaN();
648 msg.orientation.x = std::numeric_limits<double>::quiet_NaN();
649 msg.orientation.y = std::numeric_limits<double>::quiet_NaN();
650 msg.orientation.z = std::numeric_limits<double>::quiet_NaN();
651 msg.orientation_covariance[0] = -1.0;
652 msg.orientation_covariance[4] = -1.0;
653 msg.orientation_covariance[8] = -1.0;
656 publish<ImuMsg>(
"imu", msg);
692 msg.twist.twist.linear.x = vel(0);
693 msg.twist.twist.linear.y = vel(1);
694 msg.twist.twist.linear.z = vel(2);
697 msg.twist.twist.linear.x = std::numeric_limits<double>::quiet_NaN();
698 msg.twist.twist.linear.y = std::numeric_limits<double>::quiet_NaN();
699 msg.twist.twist.linear.z = std::numeric_limits<double>::quiet_NaN();
706 Eigen::Matrix3d covVel_local = Eigen::Matrix3d::Zero();
716 covVel_local(0, 0) = -1.0;
723 covVel_local(1, 1) = -1.0;
727 covVel_local(2, 2) = -1.0;
730 covVel_local(0, 1) = covVel_local(1, 0) =
735 covVel_local(0, 2) = covVel_local(2, 0) =
738 covVel_local(2, 1) = covVel_local(1, 2) =
743 covVel_local(0, 2) = covVel_local(2, 0) =
746 covVel_local(2, 1) = covVel_local(1, 2) =
751 covVel_local(0, 0) = -1.0;
752 covVel_local(1, 1) = -1.0;
753 covVel_local(2, 2) = -1.0;
756 msg.twist.covariance[0] = covVel_local(0, 0);
757 msg.twist.covariance[1] = covVel_local(0, 1);
758 msg.twist.covariance[2] = covVel_local(0, 2);
759 msg.twist.covariance[6] = covVel_local(1, 0);
760 msg.twist.covariance[7] = covVel_local(1, 1);
761 msg.twist.covariance[8] = covVel_local(1, 2);
762 msg.twist.covariance[12] = covVel_local(2, 0);
763 msg.twist.covariance[13] = covVel_local(2, 1);
764 msg.twist.covariance[14] = covVel_local(2, 2);
767 msg.twist.covariance[0] = -1.0;
768 msg.twist.covariance[7] = -1.0;
769 msg.twist.covariance[14] = -1.0;
772 msg.twist.covariance[21] = -1.0;
773 msg.twist.covariance[28] = -1.0;
774 msg.twist.covariance[35] = -1.0;
776 publish<TwistWithCovarianceStampedMsg>(
"twist_ins", msg);
808 msg.twist.twist.linear.x = vel(0);
809 msg.twist.twist.linear.y = vel(1);
810 msg.twist.twist.linear.z = vel(2);
813 msg.twist.twist.linear.x = std::numeric_limits<double>::quiet_NaN();
814 msg.twist.twist.linear.y = std::numeric_limits<double>::quiet_NaN();
815 msg.twist.twist.linear.z = std::numeric_limits<double>::quiet_NaN();
820 Eigen::Matrix3d covVel_local = Eigen::Matrix3d::Zero();
828 covVel_local(0, 0) = -1.0;
835 covVel_local(1, 1) = -1.0;
839 covVel_local(2, 2) = -1.0;
841 covVel_local(0, 1) = covVel_local(1, 0) =
845 covVel_local(0, 2) = covVel_local(2, 0) =
847 covVel_local(2, 1) = covVel_local(1, 2) =
851 covVel_local(0, 2) = covVel_local(2, 0) =
853 covVel_local(2, 1) = covVel_local(1, 2) =
857 msg.twist.covariance[0] = covVel_local(0, 0);
858 msg.twist.covariance[1] = covVel_local(0, 1);
859 msg.twist.covariance[2] = covVel_local(0, 2);
860 msg.twist.covariance[6] = covVel_local(1, 0);
861 msg.twist.covariance[7] = covVel_local(1, 1);
862 msg.twist.covariance[8] = covVel_local(1, 2);
863 msg.twist.covariance[12] = covVel_local(2, 0);
864 msg.twist.covariance[13] = covVel_local(2, 1);
865 msg.twist.covariance[14] = covVel_local(2, 2);
868 msg.twist.covariance[0] = -1.0;
869 msg.twist.covariance[7] = -1.0;
870 msg.twist.covariance[14] = -1.0;
873 msg.twist.covariance[21] = -1.0;
874 msg.twist.covariance[28] = -1.0;
875 msg.twist.covariance[35] = -1.0;
877 publish<TwistWithCovarianceStampedMsg>(
"twist_gnss", msg);
895 std::string zonestring;
896 bool northernHemisphere;
899 double meridian_convergence = 0.0;
907 GeographicLib::UTMUPS::Forward(
910 easting, northing, meridian_convergence, k, zone);
911 }
catch (
const std::exception& e)
914 "UTMUPS conversion exception: " + std::string(e.what()));
925 zone, northernHemisphere, easting,
926 northing, meridian_convergence, k);
928 GeographicLib::UTMUPS::EncodeZone(zone, northernHemisphere);
929 }
catch (
const std::exception& e)
932 "UTMUPS conversion exception: " + std::string(e.what()));
942 msg.pose.pose.position.x = easting;
943 msg.pose.pose.position.y = northing;
947 msg.pose.pose.position.x = northing;
948 msg.pose.pose.position.y = easting;
952 msg.header.frame_id =
"utm_" + zonestring;
959 Eigen::Matrix3d P_pos = -Eigen::Matrix3d::Identity();
980 yaw +=
deg2rad(meridian_convergence);
982 yaw -=
deg2rad(meridian_convergence);
987 msg.pose.pose.orientation =
991 msg.pose.pose.orientation.w = std::numeric_limits<double>::quiet_NaN();
992 msg.pose.pose.orientation.x = std::numeric_limits<double>::quiet_NaN();
993 msg.pose.pose.orientation.y = std::numeric_limits<double>::quiet_NaN();
994 msg.pose.pose.orientation.z = std::numeric_limits<double>::quiet_NaN();
1000 msg.pose.covariance[21] =
1003 msg.pose.covariance[21] = -1.0;
1005 msg.pose.covariance[28] =
1008 msg.pose.covariance[28] = -1.0;
1010 msg.pose.covariance[35] =
1013 msg.pose.covariance[35] = -1.0;
1016 msg.pose.covariance[21] = -1.0;
1017 msg.pose.covariance[28] = -1.0;
1018 msg.pose.covariance[35] = -1.0;
1046 double cg = std::cos(meridian_convergence);
1047 double sg = std::sin(meridian_convergence);
1048 Eigen::Matrix3d R = Eigen::Matrix3d::Identity();
1053 P_pos = (R * P_pos * R.transpose()).eval();
1056 msg.pose.covariance[0] = P_pos(0, 0);
1057 msg.pose.covariance[1] = P_pos(0, 1);
1058 msg.pose.covariance[2] = P_pos(0, 2);
1059 msg.pose.covariance[6] = P_pos(1, 0);
1060 msg.pose.covariance[7] = P_pos(1, 1);
1061 msg.pose.covariance[8] = P_pos(1, 2);
1062 msg.pose.covariance[12] = P_pos(2, 0);
1063 msg.pose.covariance[13] = P_pos(2, 1);
1064 msg.pose.covariance[14] = P_pos(2, 2);
1081 publish<LocalizationMsg>(
"localization", msg);
1102 msg.header.frame_id =
"ecef";
1122 msg.pose.covariance[0] = -1.0;
1123 msg.pose.covariance[7] = -1.0;
1124 msg.pose.covariance[14] = -1.0;
1151 Eigen::Quaterniond q_local_ecef;
1158 Eigen::Quaterniond q_b_local =
1161 Eigen::Quaterniond q_b_ecef = q_local_ecef * q_b_local;
1163 msg.pose.pose.orientation =
1167 msg.pose.pose.orientation.w = std::numeric_limits<double>::quiet_NaN();
1168 msg.pose.pose.orientation.x = std::numeric_limits<double>::quiet_NaN();
1169 msg.pose.pose.orientation.y = std::numeric_limits<double>::quiet_NaN();
1170 msg.pose.pose.orientation.z = std::numeric_limits<double>::quiet_NaN();
1172 Eigen::Matrix3d covAtt_local = Eigen::Matrix3d::Zero();
1173 bool covAttValid =
true;
1181 covAtt_local(0, 0) = -1.0;
1182 covAttValid =
false;
1188 covAtt_local(1, 1) = -1.0;
1189 covAttValid =
false;
1192 covAtt_local(2, 2) =
1196 covAtt_local(2, 2) = -1.0;
1197 covAttValid =
false;
1201 covAtt_local(0, 0) = -1.0;
1202 covAtt_local(1, 1) = -1.0;
1203 covAtt_local(2, 2) = -1.0;
1204 covAttValid =
false;
1220 Eigen::Matrix3d R_local_ecef;
1228 Eigen::Matrix3d covAtt_ecef =
1229 R_local_ecef * covAtt_local * R_local_ecef.transpose();
1231 msg.pose.covariance[21] = covAtt_ecef(0, 0);
1232 msg.pose.covariance[22] = covAtt_ecef(0, 1);
1233 msg.pose.covariance[23] = covAtt_ecef(0, 2);
1234 msg.pose.covariance[27] = covAtt_ecef(1, 0);
1235 msg.pose.covariance[28] = covAtt_ecef(1, 1);
1236 msg.pose.covariance[29] = covAtt_ecef(1, 2);
1237 msg.pose.covariance[33] = covAtt_ecef(2, 0);
1238 msg.pose.covariance[34] = covAtt_ecef(2, 1);
1239 msg.pose.covariance[35] = covAtt_ecef(2, 2);
1242 msg.pose.covariance[21] = -1.0;
1243 msg.pose.covariance[28] = -1.0;
1244 msg.pose.covariance[35] = -1.0;
1250 publish<LocalizationMsg>(
"localization_ecef", msg);
1259 Eigen::Matrix3d R_local_body =
1273 Eigen::Vector3d vel_local;
1277 vel_local << ve, vn, vu;
1281 vel_local << vn, ve, -vu;
1284 Eigen::Vector3d vel_body = R_local_body * vel_local;
1285 msg.twist.twist.linear.x = vel_body(0);
1286 msg.twist.twist.linear.y = vel_body(1);
1287 msg.twist.twist.linear.z = vel_body(2);
1290 msg.twist.twist.linear.x = std::numeric_limits<double>::quiet_NaN();
1291 msg.twist.twist.linear.y = std::numeric_limits<double>::quiet_NaN();
1292 msg.twist.twist.linear.z = std::numeric_limits<double>::quiet_NaN();
1294 Eigen::Matrix3d covVel_local = Eigen::Matrix3d::Zero();
1304 covVel_local(0, 0) = -1.0;
1311 covVel_local(1, 1) = -1.0;
1315 covVel_local(2, 2) = -1.0;
1318 covVel_local(0, 0) = -1.0;
1319 covVel_local(1, 1) = -1.0;
1320 covVel_local(2, 2) = -1.0;
1332 covVel_local(0, 2) = covVel_local(2, 0) =
1334 covVel_local(2, 1) = covVel_local(1, 2) =
1347 Eigen::Matrix3d covVel_body =
1348 R_local_body * covVel_local * R_local_body.transpose();
1350 msg.twist.covariance[0] = covVel_body(0, 0);
1351 msg.twist.covariance[1] = covVel_body(0, 1);
1352 msg.twist.covariance[2] = covVel_body(0, 2);
1353 msg.twist.covariance[6] = covVel_body(1, 0);
1354 msg.twist.covariance[7] = covVel_body(1, 1);
1355 msg.twist.covariance[8] = covVel_body(1, 2);
1356 msg.twist.covariance[12] = covVel_body(2, 0);
1357 msg.twist.covariance[13] = covVel_body(2, 1);
1358 msg.twist.covariance[14] = covVel_body(2, 2);
1361 msg.twist.covariance[0] = -1.0;
1362 msg.twist.covariance[7] = -1.0;
1363 msg.twist.covariance[14] = -1.0;
1366 msg.twist.covariance[21] = -1.0;
1367 msg.twist.covariance[28] = -1.0;
1368 msg.twist.covariance[35] = -1.0;
1397 switch (type_of_pvt)
1401 msg.status.status = NavSatStatusMsg::STATUS_NO_FIX;
1407 msg.status.status = NavSatStatusMsg::STATUS_FIX;
1417 msg.status.status = NavSatStatusMsg::STATUS_GBAS_FIX;
1422 msg.status.status = NavSatStatusMsg::STATUS_SBAS_FIX;
1429 "PVTGeodetic's Mode field contains an invalid type of PVT solution.");
1433 bool gps_in_pvt =
false;
1434 bool glo_in_pvt =
false;
1435 bool com_in_pvt =
false;
1436 bool gal_in_pvt =
false;
1437 uint32_t mask_2 = 1;
1438 for (
int bit = 0; bit != 31; ++bit)
1441 if (bit <= 5 && in_use)
1445 if (8 <= bit && bit <= 12 && in_use)
1447 if (((13 <= bit && bit <= 14) || (28 <= bit && bit <= 30)) && in_use)
1449 if ((bit == 17 || (19 <= bit && bit <= 22)) && in_use)
1455 gps_in_pvt * 1 + glo_in_pvt * 2 + com_in_pvt * 4 + gal_in_pvt * 8;
1456 msg.status.service = service;
1469 msg.position_covariance_type = NavSatFixMsg::COVARIANCE_TYPE_KNOWN;
1482 switch (type_of_pvt)
1486 msg.status.status = NavSatStatusMsg::STATUS_NO_FIX;
1492 msg.status.status = NavSatStatusMsg::STATUS_FIX;
1502 msg.status.status = NavSatStatusMsg::STATUS_GBAS_FIX;
1507 msg.status.status = NavSatStatusMsg::STATUS_SBAS_FIX;
1514 "INSNavGeod's Mode field contains an invalid type of PVT solution.");
1518 bool gps_in_pvt =
false;
1519 bool glo_in_pvt =
false;
1520 bool com_in_pvt =
false;
1521 bool gal_in_pvt =
false;
1522 uint32_t mask_2 = 1;
1523 for (
int bit = 0; bit != 31; ++bit)
1526 if (bit <= 5 && in_use)
1530 if (8 <= bit && bit <= 12 && in_use)
1532 if (((13 <= bit && bit <= 14) || (28 <= bit && bit <= 30)) && in_use)
1534 if ((bit == 17 || (19 <= bit && bit <= 22)) && in_use)
1540 gps_in_pvt * 1 + glo_in_pvt * 2 + com_in_pvt * 4 + gal_in_pvt * 8;
1541 msg.status.service = service;
1548 msg.position_covariance[0] =
1550 msg.position_covariance[4] =
1563 msg.position_covariance_type =
1564 NavSatFixMsg::COVARIANCE_TYPE_DIAGONAL_KNOWN;
1566 publish<NavSatFixMsg>(
"navsatfix", msg);
1621 std::vector<int32_t> cno_tracked;
1622 std::vector<int32_t> svid_in_sync;
1630 svid_in_sync.push_back(
1631 static_cast<int32_t
>(measepoch_channel_type1.sv_id));
1634 if (((measepoch_channel_type1.type & type_mask) ==
1635 static_cast<uint8_t
>(1)) ||
1636 ((measepoch_channel_type1.type & type_mask) ==
1637 static_cast<uint8_t
>(2)))
1639 cno_tracked.push_back(
1640 static_cast<int32_t
>(measepoch_channel_type1.cn0) / 4);
1643 cno_tracked.push_back(
1644 static_cast<int32_t
>(measepoch_channel_type1.cn0) / 4 +
1645 static_cast<int32_t
>(10));
1651 std::vector<int32_t> svid_in_sync_2;
1652 std::vector<int32_t> elevation_tracked;
1653 std::vector<int32_t> azimuth_tracked;
1654 std::vector<int32_t> svid_pvt;
1656 std::vector<int32_t> ordering;
1663 bool to_be_added =
false;
1664 for (int32_t j = 0; j < static_cast<int32_t>(svid_in_sync.size());
1667 if (svid_in_sync[j] ==
1668 static_cast<int32_t
>(channel_sat_info.sv_id))
1670 ordering.push_back(j);
1677 svid_in_sync_2.push_back(
1678 static_cast<int32_t
>(channel_sat_info.sv_id));
1679 elevation_tracked.push_back(
1680 static_cast<int32_t
>(channel_sat_info.elev));
1681 static uint16_t azimuth_mask = 511;
1682 azimuth_tracked.push_back(
static_cast<int32_t
>(
1683 (channel_sat_info.az_rise_set & azimuth_mask)));
1685 svid_pvt.reserve(channel_sat_info.stateInfo.size());
1686 for (
const auto& channel_state_info : channel_sat_info.stateInfo)
1689 bool pvt_status =
false;
1690 uint16_t pvt_status_mask = std::pow(2, 15) + std::pow(2, 14);
1691 for (
int k = 15; k != -1; k -= 2)
1693 uint16_t pvt_status_value =
1694 (channel_state_info.pvt_status & pvt_status_mask) >>
1696 if (pvt_status_value == 2)
1702 pvt_status_mask = pvt_status_mask - std::pow(2, k) -
1703 std::pow(2, k - 1) +
1704 std::pow(2, k - 2) +
1711 static_cast<int32_t
>(channel_sat_info.sv_id));
1716 msg.status.satellite_used_prn =
1719 msg.status.satellites_visible =
static_cast<uint16_t
>(svid_in_sync.size());
1720 msg.status.satellite_visible_prn = svid_in_sync_2;
1721 msg.status.satellite_visible_z = elevation_tracked;
1722 msg.status.satellite_visible_azimuth = azimuth_tracked;
1725 std::vector<int32_t> cno_tracked_reordered;
1728 for (int32_t k = 0; k < static_cast<int32_t>(ordering.size()); ++k)
1730 cno_tracked_reordered.push_back(cno_tracked[ordering[k]]);
1733 msg.status.satellite_visible_snr = cno_tracked_reordered;
1741 uint16_t status_mask =
1743 uint16_t type_of_pvt =
1745 switch (type_of_pvt)
1749 msg.status.status = GpsStatusMsg::STATUS_NO_FIX;
1755 msg.status.status = GpsStatusMsg::STATUS_FIX;
1765 msg.status.status = GpsStatusMsg::STATUS_GBAS_FIX;
1772 if (reference_id == 131 || reference_id == 133 ||
1773 reference_id == 135 || reference_id == 135)
1775 msg.status.status = GpsStatusMsg::STATUS_WAAS_FIX;
1778 msg.status.status = GpsStatusMsg::STATUS_SBAS_FIX;
1786 "PVTGeodetic's Mode field contains an invalid type of PVT solution.");
1792 msg.status.motion_source = GpsStatusMsg::SOURCE_POINTS;
1795 msg.status.orientation_source = GpsStatusMsg::SOURCE_POINTS;
1796 msg.status.position_source = GpsStatusMsg::SOURCE_GPS;
1893 msg.position_covariance_type = NavSatFixMsg::COVARIANCE_TYPE_KNOWN;
1899 uint16_t status_mask =
1901 uint16_t type_of_pvt =
1903 switch (type_of_pvt)
1907 msg.status.status = GpsStatusMsg::STATUS_NO_FIX;
1913 msg.status.status = GpsStatusMsg::STATUS_FIX;
1923 msg.status.status = GpsStatusMsg::STATUS_GBAS_FIX;
1931 "INSNavGeod's Mode field contains an invalid type of PVT solution.");
1937 msg.status.motion_source = GpsStatusMsg::SOURCE_POINTS;
1940 msg.status.orientation_source = GpsStatusMsg::SOURCE_POINTS;
1941 msg.status.position_source = GpsStatusMsg::SOURCE_GPS;
2036 msg.position_covariance[0] =
2038 msg.position_covariance[4] =
2051 msg.position_covariance_type =
2052 NavSatFixMsg::COVARIANCE_TYPE_DIAGONAL_KNOWN;
2054 publish<GpsFixMsg>(
"gpsfix", msg);
2063 msg.source =
"GPST";
2065 publish<TimeReferenceMsg>(
"gpst", msg);
2068 template <
typename T>
2070 const std::shared_ptr<Telegram>& telegram,
2076 msg.header.frame_id =
frameId;
2080 if constexpr (std::is_same<INSNavCartMsg, T>::value ||
2081 std::is_same<INSNavGeodMsg, T>::value)
2083 time_obj -= msg.latency * 100000ul;
2084 }
else if constexpr (std::is_same<PVTCartesianMsg, T>::value ||
2085 std::is_same<PVTGeodeticMsg, T>::value)
2089 }
else if constexpr (std::is_same<PosCovCartesianMsg, T>::value ||
2090 std::is_same<PosCovGeodeticMsg, T>::value ||
2091 std::is_same<VelCovCartesianMsg, T>::value ||
2092 std::is_same<VelCovGeodeticMsg, T>::value ||
2093 std::is_same<AttEulerMsg, T>::value ||
2094 std::is_same<AttCovEulerMsg, T>::value ||
2095 std::is_same<BaseVectorCartMsg, T>::value ||
2096 std::is_same<BaseVectorGeodMsg, T>::value)
2127 static uint64_t secToNSec = 1000000000;
2128 static uint64_t mSec2NSec = 1000000;
2129 static uint64_t nsOfGpsStart =
2133 static uint64_t nsecPerWeek = 7 * 24 * 60 * 60 * secToNSec;
2135 time_obj = nsOfGpsStart + tow * mSec2NSec + wnc * nsecPerWeek;
2147 template <
typename M>
2163 "Not publishing message with GNSS time because no leap seconds are available yet.");
2168 "No leap seconds were set and none were received from log yet.");
2192 "Not publishing tf with GNSS time because no leap seconds are available yet.");
2197 "No leap seconds were set and none were received from log yet. ");
2222 telegram->message.end(), msg))
2228 publish<PVTCartesianMsg>(
"pvtcartesian", msg);
2260 telegram->message.end(), msg))
2266 publish<BaseVectorCartMsg>(
"basevectorcart", msg);
2277 telegram->message.end(), msg))
2283 publish<BaseVectorGeodMsg>(
"basevectorgeod", msg);
2294 telegram->message.end(), msg))
2300 publish<PosCovCartesianMsg>(
"poscovcartesian", msg);
2447 telegram->message.end(), msg,
2454 publish<IMUSetupMsg>(
"imusetup", msg);
2465 telegram->message.end(), msg,
2472 publish<VelSensorSetupMsg>(
"velsensorsetup", msg);
2484 telegram->message.end(), msg,
2488 "parse error in ExtEventINSNavCart");
2500 publish<INSNavCartMsg>(
"exteventinsnavcart", msg);
2511 telegram->message.end(), msg,
2515 "parse error in ExtEventINSNavGeod");
2527 publish<INSNavGeodMsg>(
"exteventinsnavgeod", msg);
2533 bool hasImuMeas =
false;
2578 if (!
DOPParser(
node_, telegram->message.begin(), telegram->message.end(),
2593 telegram->message.end(), msg))
2599 publish<VelCovCartesianMsg>(
"velcovcartesian", msg);
2652 static const int32_t ins_major = 1;
2653 static const int32_t ins_minor = 4;
2654 static const int32_t ins_patch = 0;
2655 static const int32_t gnss_major = 4;
2656 static const int32_t gnss_minor = 12;
2657 static const int32_t gnss_patch = 1;
2659 boost::tokenizer<>::iterator it = tok.begin();
2660 std::vector<int32_t> major_minor_patch;
2661 major_minor_patch.reserve(3);
2662 for (boost::tokenizer<>::iterator it = tok.begin(); it != tok.end();
2665 int32_t v = std::atoi(it->c_str());
2666 major_minor_patch.push_back(v);
2668 if (major_minor_patch.size() < 3)
2675 if ((major_minor_patch[0] < ins_major) ||
2676 ((major_minor_patch[0] == ins_major) &&
2677 (major_minor_patch[1] < ins_minor)) ||
2678 ((major_minor_patch[0] == ins_major) &&
2679 (major_minor_patch[1] == ins_minor) &&
2680 (major_minor_patch[2] < ins_patch)))
2684 "INS receiver has firmware version: " +
2686 ", which does not support all features. Please update to at least " +
2687 std::to_string(ins_major) +
"." +
2688 std::to_string(ins_minor) +
"." +
2689 std::to_string(ins_patch) +
" or consult README.");
2694 if ((major_minor_patch[0] < gnss_major) ||
2695 ((major_minor_patch[0] == gnss_major) &&
2696 (major_minor_patch[1] < gnss_minor)) ||
2697 ((major_minor_patch[0] == gnss_major) &&
2698 (major_minor_patch[1] == gnss_minor) &&
2699 (major_minor_patch[2] < gnss_patch)))
2703 "GNSS receiver has firmware version: " +
2705 ", which may not support all features. Please update to at least " +
2706 std::to_string(gnss_major) +
"." +
2707 std::to_string(gnss_minor) +
"." +
2708 std::to_string(gnss_patch) +
" or consult README.");
2720 telegram->message.end(), msg))
2731 std::to_string(sbfId) +
" received.");
2742 if ((unix_old != 0) && (
unix_time_ > unix_old))
2746 std::stringstream ss;
2747 ss <<
"Waiting for " << sleep_nsec / 1000000 <<
" milliseconds...";
2750 std::this_thread::sleep_for(std::chrono::nanoseconds(sleep_nsec));
2756 std::string message(telegram->message.begin(), telegram->message.end());
2761 boost::char_separator<char> sep_2(
",*",
"", boost::keep_empty_tokens);
2762 boost::tokenizer<boost::char_separator<char>> tokens(message, sep_2);
2763 std::vector<std::string> body;
2765 for (boost::tokenizer<boost::char_separator<char>>::iterator tok_iter =
2767 tok_iter != tokens.end(); ++tok_iter)
2769 body.push_back(*tok_iter);
2772 std::string id(body[0].begin() + 1, body[0].end());
2793 "GpggaMsg: " + std::string(e.what()));
2796 publish<GpggaMsg>(
"gpgga", msg);
2813 "GprmcMsg: " + std::string(e.what()));
2816 publish<GprmcMsg>(
"gprmc", msg);
2833 "GpgsaMsg: " + std::string(e.what()));
2854 publish<GpgsaMsg>(
"gpgsa", msg);
2871 "GpgsvMsg: " + std::string(e.what()));
2893 publish<GpgsvMsg>(
"gpgsv", msg);