12#include "vn/searcher.h"
21#include <imgui_internal.h>
68static void to_json(
json& j,
const SynchronizationControlRegister& synchronizationControlRegister)
71 {
"syncInMode", synchronizationControlRegister.syncInMode },
72 {
"syncInEdge", synchronizationControlRegister.syncInEdge },
73 {
"syncInSkipFactor", synchronizationControlRegister.syncInSkipFactor },
74 {
"syncOutMode", synchronizationControlRegister.syncOutMode },
75 {
"syncOutPolarity", synchronizationControlRegister.syncOutPolarity },
76 {
"syncOutSkipFactor", synchronizationControlRegister.syncOutSkipFactor },
77 {
"syncOutPulseWidth", synchronizationControlRegister.syncOutPulseWidth },
80static void from_json(
const json& j, SynchronizationControlRegister& synchronizationControlRegister)
82 if (j.contains(
"syncInMode"))
84 j.at(
"syncInMode").get_to(synchronizationControlRegister.syncInMode);
86 if (j.contains(
"syncInEdge"))
88 j.at(
"syncInEdge").get_to(synchronizationControlRegister.syncInEdge);
90 if (j.contains(
"syncInSkipFactor"))
92 j.at(
"syncInSkipFactor").get_to(synchronizationControlRegister.syncInSkipFactor);
94 if (j.contains(
"syncOutMode"))
96 j.at(
"syncOutMode").get_to(synchronizationControlRegister.syncOutMode);
98 if (j.contains(
"syncOutPolarity"))
100 j.at(
"syncOutPolarity").get_to(synchronizationControlRegister.syncOutPolarity);
102 if (j.contains(
"syncOutSkipFactor"))
104 j.at(
"syncOutSkipFactor").get_to(synchronizationControlRegister.syncOutSkipFactor);
106 if (j.contains(
"syncOutPulseWidth"))
108 j.at(
"syncOutPulseWidth").get_to(synchronizationControlRegister.syncOutPulseWidth);
112static void to_json(
json& j,
const CommunicationProtocolControlRegister& communicationProtocolControlRegister)
115 {
"serialCount", communicationProtocolControlRegister.serialCount },
116 {
"serialStatus", communicationProtocolControlRegister.serialStatus },
117 {
"spiCount", communicationProtocolControlRegister.spiCount },
118 {
"spiStatus", communicationProtocolControlRegister.spiStatus },
119 {
"serialChecksum", communicationProtocolControlRegister.serialChecksum },
120 {
"spiChecksum", communicationProtocolControlRegister.spiChecksum },
121 {
"errorMode", communicationProtocolControlRegister.errorMode },
124static void from_json(
const json& j, CommunicationProtocolControlRegister& communicationProtocolControlRegister)
126 if (j.contains(
"serialCount"))
128 j.at(
"serialCount").get_to(communicationProtocolControlRegister.serialCount);
130 if (j.contains(
"serialStatus"))
132 j.at(
"serialStatus").get_to(communicationProtocolControlRegister.serialStatus);
134 if (j.contains(
"spiCount"))
136 j.at(
"spiCount").get_to(communicationProtocolControlRegister.spiCount);
138 if (j.contains(
"spiStatus"))
140 j.at(
"spiStatus").get_to(communicationProtocolControlRegister.spiStatus);
142 if (j.contains(
"serialChecksum"))
144 j.at(
"serialChecksum").get_to(communicationProtocolControlRegister.serialChecksum);
146 if (j.contains(
"spiChecksum"))
148 j.at(
"spiChecksum").get_to(communicationProtocolControlRegister.spiChecksum);
150 if (j.contains(
"errorMode"))
152 j.at(
"errorMode").get_to(communicationProtocolControlRegister.errorMode);
156static void to_json(
json& j,
const BinaryOutputRegister& binaryOutputRegister)
159 {
"asyncMode", binaryOutputRegister.asyncMode },
160 {
"rateDivisor", binaryOutputRegister.rateDivisor },
161 {
"commonField", binaryOutputRegister.commonField },
162 {
"timeField", binaryOutputRegister.timeField },
163 {
"imuField", binaryOutputRegister.imuField },
164 {
"gpsField", binaryOutputRegister.gpsField },
165 {
"attitudeField", binaryOutputRegister.attitudeField },
166 {
"insField", binaryOutputRegister.insField },
167 {
"gps2Field", binaryOutputRegister.gps2Field },
170static void from_json(
const json& j, BinaryOutputRegister& binaryOutputRegister)
172 if (j.contains(
"asyncMode"))
174 j.at(
"asyncMode").get_to(binaryOutputRegister.asyncMode);
176 if (j.contains(
"rateDivisor"))
178 j.at(
"rateDivisor").get_to(binaryOutputRegister.rateDivisor);
180 if (j.contains(
"commonField"))
182 j.at(
"commonField").get_to(binaryOutputRegister.commonField);
184 if (j.contains(
"timeField"))
186 j.at(
"timeField").get_to(binaryOutputRegister.timeField);
188 if (j.contains(
"imuField"))
190 j.at(
"imuField").get_to(binaryOutputRegister.imuField);
192 if (j.contains(
"gpsField"))
194 j.at(
"gpsField").get_to(binaryOutputRegister.gpsField);
196 if (j.contains(
"attitudeField"))
198 j.at(
"attitudeField").get_to(binaryOutputRegister.attitudeField);
200 if (j.contains(
"insField"))
202 j.at(
"insField").get_to(binaryOutputRegister.insField);
204 if (j.contains(
"gps2Field"))
206 j.at(
"gps2Field").get_to(binaryOutputRegister.gps2Field);
214static void to_json(
json& j,
const ImuFilteringConfigurationRegister& imuFilteringConfigurationRegister)
217 {
"magWindowSize", imuFilteringConfigurationRegister.magWindowSize },
218 {
"accelWindowSize", imuFilteringConfigurationRegister.accelWindowSize },
219 {
"gyroWindowSize", imuFilteringConfigurationRegister.gyroWindowSize },
220 {
"tempWindowSize", imuFilteringConfigurationRegister.tempWindowSize },
221 {
"presWindowSize", imuFilteringConfigurationRegister.presWindowSize },
222 {
"magFilterMode", imuFilteringConfigurationRegister.magFilterMode },
223 {
"accelFilterMode", imuFilteringConfigurationRegister.accelFilterMode },
224 {
"gyroFilterMode", imuFilteringConfigurationRegister.gyroFilterMode },
225 {
"tempFilterMode", imuFilteringConfigurationRegister.tempFilterMode },
226 {
"presFilterMode", imuFilteringConfigurationRegister.presFilterMode },
229static void from_json(
const json& j, ImuFilteringConfigurationRegister& imuFilteringConfigurationRegister)
231 if (j.contains(
"magWindowSize"))
233 j.at(
"magWindowSize").get_to(imuFilteringConfigurationRegister.magWindowSize);
235 if (j.contains(
"accelWindowSize"))
237 j.at(
"accelWindowSize").get_to(imuFilteringConfigurationRegister.accelWindowSize);
239 if (j.contains(
"gyroWindowSize"))
241 j.at(
"gyroWindowSize").get_to(imuFilteringConfigurationRegister.gyroWindowSize);
243 if (j.contains(
"tempWindowSize"))
245 j.at(
"tempWindowSize").get_to(imuFilteringConfigurationRegister.tempWindowSize);
247 if (j.contains(
"presWindowSize"))
249 j.at(
"presWindowSize").get_to(imuFilteringConfigurationRegister.presWindowSize);
251 if (j.contains(
"magFilterMode"))
253 j.at(
"magFilterMode").get_to(imuFilteringConfigurationRegister.magFilterMode);
255 if (j.contains(
"accelFilterMode"))
257 j.at(
"accelFilterMode").get_to(imuFilteringConfigurationRegister.accelFilterMode);
259 if (j.contains(
"gyroFilterMode"))
261 j.at(
"gyroFilterMode").get_to(imuFilteringConfigurationRegister.gyroFilterMode);
263 if (j.contains(
"tempFilterMode"))
265 j.at(
"tempFilterMode").get_to(imuFilteringConfigurationRegister.tempFilterMode);
267 if (j.contains(
"presFilterMode"))
269 j.at(
"presFilterMode").get_to(imuFilteringConfigurationRegister.presFilterMode);
273static void to_json(
json& j,
const DeltaThetaAndDeltaVelocityConfigurationRegister& deltaThetaAndDeltaVelocityConfigurationRegister)
276 {
"integrationFrame", deltaThetaAndDeltaVelocityConfigurationRegister.integrationFrame },
277 {
"gyroCompensation", deltaThetaAndDeltaVelocityConfigurationRegister.gyroCompensation },
278 {
"accelCompensation", deltaThetaAndDeltaVelocityConfigurationRegister.accelCompensation },
279 {
"earthRateCorrection", deltaThetaAndDeltaVelocityConfigurationRegister.earthRateCorrection },
282static void from_json(
const json& j, DeltaThetaAndDeltaVelocityConfigurationRegister& deltaThetaAndDeltaVelocityConfigurationRegister)
284 if (j.contains(
"integrationFrame"))
286 j.at(
"integrationFrame").get_to(deltaThetaAndDeltaVelocityConfigurationRegister.integrationFrame);
288 if (j.contains(
"gyroCompensation"))
290 j.at(
"gyroCompensation").get_to(deltaThetaAndDeltaVelocityConfigurationRegister.gyroCompensation);
292 if (j.contains(
"accelCompensation"))
294 j.at(
"accelCompensation").get_to(deltaThetaAndDeltaVelocityConfigurationRegister.accelCompensation);
296 if (j.contains(
"earthRateCorrection"))
298 j.at(
"earthRateCorrection").get_to(deltaThetaAndDeltaVelocityConfigurationRegister.earthRateCorrection);
306static void to_json(
json& j,
const GpsConfigurationRegister& gpsConfigurationRegister)
309 {
"mode", gpsConfigurationRegister.mode },
310 {
"ppsSource", gpsConfigurationRegister.ppsSource },
311 {
"rate", gpsConfigurationRegister.rate },
312 {
"antPow", gpsConfigurationRegister.antPow },
315static void from_json(
const json& j, GpsConfigurationRegister& gpsConfigurationRegister)
317 if (j.contains(
"mode"))
319 j.at(
"mode").get_to(gpsConfigurationRegister.mode);
321 if (j.contains(
"ppsSource"))
323 j.at(
"ppsSource").get_to(gpsConfigurationRegister.ppsSource);
325 if (j.contains(
"rate"))
327 j.at(
"rate").get_to(gpsConfigurationRegister.rate);
329 if (j.contains(
"antPow"))
331 j.at(
"antPow").get_to(gpsConfigurationRegister.antPow);
335static void to_json(
json& j,
const GpsCompassBaselineRegister& gpsCompassBaselineRegister)
338 {
"position", gpsCompassBaselineRegister.position },
339 {
"uncertainty", gpsCompassBaselineRegister.uncertainty },
342static void from_json(
const json& j, GpsCompassBaselineRegister& gpsCompassBaselineRegister)
344 if (j.contains(
"position"))
346 j.at(
"position").get_to(gpsCompassBaselineRegister.position);
348 if (j.contains(
"uncertainty"))
350 j.at(
"uncertainty").get_to(gpsCompassBaselineRegister.uncertainty);
358static void to_json(
json& j,
const VpeBasicControlRegister& vpeBasicControlRegister)
361 {
"enable", vpeBasicControlRegister.enable },
362 {
"headingMode", vpeBasicControlRegister.headingMode },
363 {
"filteringMode", vpeBasicControlRegister.filteringMode },
364 {
"tuningMode", vpeBasicControlRegister.tuningMode },
367static void from_json(
const json& j, VpeBasicControlRegister& vpeBasicControlRegister)
369 if (j.contains(
"enable"))
371 j.at(
"enable").get_to(vpeBasicControlRegister.enable);
373 if (j.contains(
"headingMode"))
375 j.at(
"headingMode").get_to(vpeBasicControlRegister.headingMode);
377 if (j.contains(
"filteringMode"))
379 j.at(
"filteringMode").get_to(vpeBasicControlRegister.filteringMode);
381 if (j.contains(
"tuningMode"))
383 j.at(
"tuningMode").get_to(vpeBasicControlRegister.tuningMode);
387static void to_json(
json& j,
const VpeMagnetometerBasicTuningRegister& vpeMagnetometerBasicTuningRegister)
390 {
"baseTuning", vpeMagnetometerBasicTuningRegister.baseTuning },
391 {
"adaptiveTuning", vpeMagnetometerBasicTuningRegister.adaptiveTuning },
392 {
"adaptiveFiltering", vpeMagnetometerBasicTuningRegister.adaptiveFiltering },
395static void from_json(
const json& j, VpeMagnetometerBasicTuningRegister& vpeMagnetometerBasicTuningRegister)
397 if (j.contains(
"baseTuning"))
399 j.at(
"baseTuning").get_to(vpeMagnetometerBasicTuningRegister.baseTuning);
401 if (j.contains(
"adaptiveTuning"))
403 j.at(
"adaptiveTuning").get_to(vpeMagnetometerBasicTuningRegister.adaptiveTuning);
405 if (j.contains(
"adaptiveFiltering"))
407 j.at(
"adaptiveFiltering").get_to(vpeMagnetometerBasicTuningRegister.adaptiveFiltering);
411static void to_json(
json& j,
const VpeAccelerometerBasicTuningRegister& vpeAccelerometerBasicTuningRegister)
414 {
"baseTuning", vpeAccelerometerBasicTuningRegister.baseTuning },
415 {
"adaptiveTuning", vpeAccelerometerBasicTuningRegister.adaptiveTuning },
416 {
"adaptiveFiltering", vpeAccelerometerBasicTuningRegister.adaptiveFiltering },
419static void from_json(
const json& j, VpeAccelerometerBasicTuningRegister& vpeAccelerometerBasicTuningRegister)
421 if (j.contains(
"baseTuning"))
423 j.at(
"baseTuning").get_to(vpeAccelerometerBasicTuningRegister.baseTuning);
425 if (j.contains(
"adaptiveTuning"))
427 j.at(
"adaptiveTuning").get_to(vpeAccelerometerBasicTuningRegister.adaptiveTuning);
429 if (j.contains(
"adaptiveFiltering"))
431 j.at(
"adaptiveFiltering").get_to(vpeAccelerometerBasicTuningRegister.adaptiveFiltering);
435static void to_json(
json& j,
const VpeGyroBasicTuningRegister& vpeGyroBasicTuningRegister)
438 {
"angularWalkVariance", vpeGyroBasicTuningRegister.angularWalkVariance },
439 {
"baseTuning", vpeGyroBasicTuningRegister.baseTuning },
440 {
"adaptiveTuning", vpeGyroBasicTuningRegister.adaptiveTuning },
443static void from_json(
const json& j, VpeGyroBasicTuningRegister& vpeGyroBasicTuningRegister)
445 if (j.contains(
"angularWalkVariance"))
447 j.at(
"angularWalkVariance").get_to(vpeGyroBasicTuningRegister.angularWalkVariance);
449 if (j.contains(
"baseTuning"))
451 j.at(
"baseTuning").get_to(vpeGyroBasicTuningRegister.baseTuning);
453 if (j.contains(
"adaptiveTuning"))
455 j.at(
"adaptiveTuning").get_to(vpeGyroBasicTuningRegister.adaptiveTuning);
463static void to_json(
json& j,
const InsBasicConfigurationRegisterVn300& insBasicConfigurationRegisterVn300)
466 {
"scenario", insBasicConfigurationRegisterVn300.scenario },
467 {
"ahrsAiding", insBasicConfigurationRegisterVn300.ahrsAiding },
468 {
"estBaseline", insBasicConfigurationRegisterVn300.estBaseline },
471static void from_json(
const json& j, InsBasicConfigurationRegisterVn300& insBasicConfigurationRegisterVn300)
473 if (j.contains(
"scenario"))
475 j.at(
"scenario").get_to(insBasicConfigurationRegisterVn300.scenario);
477 if (j.contains(
"ahrsAiding"))
479 j.at(
"ahrsAiding").get_to(insBasicConfigurationRegisterVn300.ahrsAiding);
481 if (j.contains(
"estBaseline"))
483 j.at(
"estBaseline").get_to(insBasicConfigurationRegisterVn300.estBaseline);
487static void to_json(
json& j,
const StartupFilterBiasEstimateRegister& startupFilterBiasEstimateRegister)
490 {
"gyroBias", startupFilterBiasEstimateRegister.gyroBias },
491 {
"accelBias", startupFilterBiasEstimateRegister.accelBias },
492 {
"pressureBias", startupFilterBiasEstimateRegister.pressureBias },
495static void from_json(
const json& j, StartupFilterBiasEstimateRegister& startupFilterBiasEstimateRegister)
497 if (j.contains(
"gyroBias"))
499 j.at(
"gyroBias").get_to(startupFilterBiasEstimateRegister.gyroBias);
501 if (j.contains(
"accelBias"))
503 j.at(
"accelBias").get_to(startupFilterBiasEstimateRegister.accelBias);
505 if (j.contains(
"pressureBias"))
507 j.at(
"pressureBias").get_to(startupFilterBiasEstimateRegister.pressureBias);
515static void to_json(
json& j,
const MagnetometerCalibrationControlRegister& magnetometerCalibrationControlRegister)
518 {
"hsiMode", magnetometerCalibrationControlRegister.hsiMode },
519 {
"hsiOutput", magnetometerCalibrationControlRegister.hsiOutput },
520 {
"convergeRate", magnetometerCalibrationControlRegister.convergeRate },
523static void from_json(
const json& j, MagnetometerCalibrationControlRegister& magnetometerCalibrationControlRegister)
525 if (j.contains(
"hsiMode"))
527 j.at(
"hsiMode").get_to(magnetometerCalibrationControlRegister.hsiMode);
529 if (j.contains(
"hsiOutput"))
531 j.at(
"hsiOutput").get_to(magnetometerCalibrationControlRegister.hsiOutput);
533 if (j.contains(
"convergeRate"))
535 j.at(
"convergeRate").get_to(magnetometerCalibrationControlRegister.convergeRate);
543static void to_json(
json& j,
const MagneticAndGravityReferenceVectorsRegister& magneticAndGravityReferenceVectorsRegister)
546 {
"magRef", magneticAndGravityReferenceVectorsRegister.magRef },
547 {
"accRef", magneticAndGravityReferenceVectorsRegister.accRef },
550static void from_json(
const json& j, MagneticAndGravityReferenceVectorsRegister& magneticAndGravityReferenceVectorsRegister)
552 if (j.contains(
"magRef"))
554 j.at(
"magRef").get_to(magneticAndGravityReferenceVectorsRegister.magRef);
556 if (j.contains(
"accRef"))
558 j.at(
"accRef").get_to(magneticAndGravityReferenceVectorsRegister.accRef);
562static void to_json(
json& j,
const ReferenceVectorConfigurationRegister& referenceVectorConfigurationRegister)
565 {
"useMagModel", referenceVectorConfigurationRegister.useMagModel },
566 {
"useGravityModel", referenceVectorConfigurationRegister.useGravityModel },
567 {
"recalcThreshold", referenceVectorConfigurationRegister.recalcThreshold },
568 {
"year", referenceVectorConfigurationRegister.year },
569 {
"position", referenceVectorConfigurationRegister.position },
572static void from_json(
const json& j, ReferenceVectorConfigurationRegister& referenceVectorConfigurationRegister)
574 if (j.contains(
"useMagModel"))
576 j.at(
"useMagModel").get_to(referenceVectorConfigurationRegister.useMagModel);
578 if (j.contains(
"useGravityModel"))
580 j.at(
"useGravityModel").get_to(referenceVectorConfigurationRegister.useGravityModel);
582 if (j.contains(
"recalcThreshold"))
584 j.at(
"recalcThreshold").get_to(referenceVectorConfigurationRegister.recalcThreshold);
586 if (j.contains(
"year"))
588 j.at(
"year").get_to(referenceVectorConfigurationRegister.year);
590 if (j.contains(
"position"))
592 j.at(
"position").get_to(referenceVectorConfigurationRegister.position);
600static void to_json(
json& j,
const VelocityCompensationControlRegister& velocityCompensationControlRegister)
603 {
"mode", velocityCompensationControlRegister.mode },
604 {
"velocityTuning", velocityCompensationControlRegister.velocityTuning },
605 {
"rateTuning", velocityCompensationControlRegister.rateTuning },
608static void from_json(
const json& j, VelocityCompensationControlRegister& velocityCompensationControlRegister)
610 if (j.contains(
"mode"))
612 j.at(
"mode").get_to(velocityCompensationControlRegister.mode);
614 if (j.contains(
"velocityTuning"))
616 j.at(
"velocityTuning").get_to(velocityCompensationControlRegister.velocityTuning);
618 if (j.contains(
"rateTuning"))
620 j.at(
"rateTuning").get_to(velocityCompensationControlRegister.rateTuning);
630 (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS);
634 (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK);
639 if (bor.imuField & (vn::protocol::uart::IMUGROUP_ACCEL | vn::protocol::uart::IMUGROUP_UNCOMPACCEL))
643 if (bor.imuField & (vn::protocol::uart::IMUGROUP_ANGULARRATE | vn::protocol::uart::IMUGROUP_UNCOMPGYRO))
647 if (bor.imuField & (vn::protocol::uart::IMUGROUP_MAG | vn::protocol::uart::IMUGROUP_UNCOMPMAG))
651 if (bor.imuField & (vn::protocol::uart::IMUGROUP_MAG | vn::protocol::uart::IMUGROUP_UNCOMPMAG))
655 if (bor.imuField & vn::protocol::uart::IMUGROUP_TEMP)
659 if (bor.imuField & vn::protocol::uart::IMUGROUP_PRES)
663 LOG_DATA(
"Frequency of ImuFilter matches output frequency (coupled 'rateDivisor' and 'windowSize' of moving average filter.)");
665 if (sensor->
isInitialized() && sensor->
_vs.isConnected() && sensor->
_vs.verifySensorConnectivity())
671 catch (
const std::exception& e)
673 LOG_ERROR(
"Could not configure the imuFilteringConfigurationRegister: {}", e.what());
730 {
"TimeStartup", vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP,
731 []() { ImGui::TextUnformatted(
"Time since startup.\n\nThe system time since startup measured in nano seconds. The time since startup is based upon the internal\nTXCO oscillator for the MCU. The accuracy of the internal TXCO is +/- 20ppm (-40C to 85C)."); },
732 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& bor, uint32_t ) {
return (sensorModel != VectorNavModel::VN310
733 || !((bor.gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_TOW)
734 || (bor.gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_WEEK)
735 || (bor.gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_TOW)
736 || (bor.gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_WEEK)))
737 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPMAG)
738 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPACCEL)
739 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPGYRO)
740 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_TEMP)
741 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_PRES)
742 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTATHETA)
743 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTAVEL)
744 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_MAG)
745 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ACCEL)
746 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ANGULARRATE)
747 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YAWPITCHROLL)
748 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_QUATERNION)
749 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_DCM)
750 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_MAGNED)
751 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_ACCELNED)
752 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELBODY)
753 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELNED)
754 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YPRU)
755 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_INSSTATUS)
756 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_POSLLA)
757 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_POSECEF)
758 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELBODY)
759 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELNED)
760 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELECEF)
761 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_MAGECEF)
762 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_ACCELECEF)
763 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_LINEARACCELECEF)
764 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_POSU)
765 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELU); } },
766 {
"TimeGps", vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEGPS,
767 []() { ImGui::TextUnformatted(
"Absolute GPS time.\n\nThe absolute GPS time since start of GPS epoch 1980 expressed in nano seconds."); },
768 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; },
769 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& ) { (bor.timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEGPS) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS); } },
770 {
"GpsTow", vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW,
771 []() { ImGui::TextUnformatted(
"Time since start of GPS week.\n\nThe time since the start of the current GPS time week expressed in nano seconds."); },
772 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& bor, uint32_t ) {
return (sensorModel == VectorNavModel::VN310)
773 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPMAG)
774 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPACCEL)
775 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPGYRO)
776 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_TEMP)
777 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_PRES)
778 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTATHETA)
779 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTAVEL)
780 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_MAG)
781 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ACCEL)
782 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ANGULARRATE)
783 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YAWPITCHROLL)
784 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_QUATERNION)
785 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_DCM)
786 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_MAGNED)
787 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_ACCELNED)
788 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELBODY)
789 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELNED)
790 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YPRU)
791 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_INSSTATUS)
792 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_POSLLA)
793 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_POSECEF)
794 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELBODY)
795 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELNED)
796 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELECEF)
797 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_MAGECEF)
798 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_ACCELECEF)
799 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_LINEARACCELECEF)
800 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_POSU)
801 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELU); },
802 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& ) { (bor.timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS); } },
803 {
"GpsWeek", vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK,
804 []() { ImGui::TextUnformatted(
"GPS week.\n\nThe current GPS week."); },
805 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& bor, uint32_t ) {
return (sensorModel == VectorNavModel::VN310)
806 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPMAG)
807 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPACCEL)
808 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPGYRO)
809 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_TEMP)
810 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_PRES)
811 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTATHETA)
812 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTAVEL)
813 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_MAG)
814 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ACCEL)
815 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ANGULARRATE)
816 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YAWPITCHROLL)
817 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_QUATERNION)
818 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_DCM)
819 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_MAGNED)
820 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_ACCELNED)
821 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELBODY)
822 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELNED)
823 && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YPRU)
824 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_INSSTATUS)
825 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_POSLLA)
826 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_POSECEF)
827 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELBODY)
828 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELNED)
829 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELECEF)
830 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_MAGECEF)
831 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_ACCELECEF)
832 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_LINEARACCELECEF)
833 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_POSU)
834 && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELU); },
835 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& ) { (bor.timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS); } },
836 {
"TimeSyncIn", vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESYNCIN,
837 []() { ImGui::TextUnformatted(
"Time since last SyncIn trigger.\n\nThe time since the last SyncIn event trigger expressed in nano seconds."); } },
838 {
"TimeGpsPps", vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEGPSPPS,
839 []() { ImGui::TextUnformatted(
"Time since last GPS PPS trigger.\n\nThe time since the last GPS PPS trigger event expressed in nano seconds."); },
840 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; } },
841 {
"TimeUTC", vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEUTC,
842 []() { ImGui::TextUnformatted(
"UTC time.\n\nThe current UTC time. The year is given as a signed byte year offset from the year 2000. For example the\nyear 2013 would be given as year 13."); },
843 [](VectorNavModel ,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return false; },
844 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& ) { (bor.timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEUTC) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS); } },
845 {
"SyncInCnt", vn::protocol::uart::TimeGroup::TIMEGROUP_SYNCINCNT,
846 []() { ImGui::TextUnformatted(
"SyncIn trigger count.\n\nThe number of SyncIn trigger events that have occurred."); } },
847 {
"SyncOutCnt", vn::protocol::uart::TimeGroup::TIMEGROUP_SYNCOUTCNT,
848 []() { ImGui::TextUnformatted(
"SyncOut trigger count.\n\nThe number of SyncOut trigger events that have occurred."); } },
849 {
"TimeStatus", vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS,
850 []() { ImGui::TextUnformatted(
"Time valid status flags.");
851 if (ImGui::BeginTable(
"VectorNavTimeStatusTooltip", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
853 ImGui::TableSetupColumn(
"Bit Offset", ImGuiTableColumnFlags_WidthFixed);
854 ImGui::TableSetupColumn(
"Field", ImGuiTableColumnFlags_WidthFixed);
855 ImGui::TableSetupColumn(
"Description", ImGuiTableColumnFlags_WidthFixed);
856 ImGui::TableHeadersRow();
858 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"0");
859 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"timeOk");
860 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1 - GpsTow is valid");
862 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1");
863 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"dateOk");
864 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1 - TimeGps and GpsWeek are valid");
866 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"2");
867 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"utcTimeValid");
868 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1 - UTC time is valid");
870 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"3 - 7");
871 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"resv");
872 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Reserved for future use");
876 [](VectorNavModel ,
const vn::sensors::BinaryOutputRegister& bor, uint32_t ) {
return !(bor.commonField & vn::protocol::uart::CommonGroup::COMMONGROUP_TIMEGPS)
877 && !(bor.timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)
878 && !(bor.timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK)
879 && !(bor.timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEGPS)
880 && !(bor.timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEUTC)
881 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPMAG)
882 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPACCEL)
883 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPGYRO)
884 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_TEMP)
885 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_PRES)
886 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTATHETA)
887 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTAVEL)
888 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_MAG)
889 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ACCEL)
890 && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ANGULARRATE); } },
894 {
"ImuStatus", vn::protocol::uart::ImuGroup::IMUGROUP_IMUSTATUS,
895 []() { ImGui::TextUnformatted(
"Status is reserved for future use. Not currently used in the current code, as such will always report 0."); },
896 [](VectorNavModel ,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return false; } },
897 {
"UncompMag", vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPMAG,
898 []() { ImGui::TextUnformatted(
"Uncompensated magnetic measurement.\n\nThe IMU magnetic field measured in units of Gauss, given in the body frame. This measurement is\ncompensated by the static calibration (individual factory calibration stored in flash), and the user\ncompensation, however it is not compensated by the onboard Hard/Soft Iron estimator."); },
899 [](VectorNavModel ,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return true; }, coupleImuFilterRates },
900 {
"UncompAccel", vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPACCEL,
901 []() { ImGui::TextUnformatted(
"Uncompensated acceleration measurement.\n\nThe IMU acceleration measured in units of m/s^2, given in the body frame. This measurement is\ncompensated by the static calibration (individual factory calibration stored in flash), however it is not\ncompensated by any dynamic calibration such as bias compensation from the onboard INS Kalman filter."); },
902 [](VectorNavModel ,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return true; }, coupleImuFilterRates },
903 {
"UncompGyro", vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPGYRO,
904 []() { ImGui::TextUnformatted(
"Uncompensated angular rate measurement.\n\nThe IMU angular rate measured in units of rad/s, given in the body frame. This measurement is compensated\nby the static calibration (individual factory calibration stored in flash), however it is not compensated by any\ndynamic calibration such as the bias compensation from the onboard AHRS/INS Kalman filters."); },
905 [](VectorNavModel ,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return true; }, coupleImuFilterRates },
906 {
"Temp", vn::protocol::uart::ImuGroup::IMUGROUP_TEMP,
907 []() { ImGui::TextUnformatted(
"Temperature measurement.\n\nThe IMU temperature measured in units of Celsius."); },
908 [](VectorNavModel ,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return true; }, coupleImuFilterRates },
909 {
"Pres", vn::protocol::uart::ImuGroup::IMUGROUP_PRES,
910 []() { ImGui::TextUnformatted(
"Pressure measurement.\n\nThe IMU pressure measured in kilopascals. This is an absolute pressure measurement. Typical pressure at sea level would be around 100 kPa."); },
911 [](VectorNavModel ,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return true; }, coupleImuFilterRates },
912 {
"DeltaTheta", vn::protocol::uart::ImuGroup::IMUGROUP_DELTATHETA,
913 []() { ImGui::TextUnformatted(
"Delta theta angles.\n\nThe delta time (dtime) is the time interval that the delta angle and velocities are integrated over. The delta\ntheta (dtheta) is the delta rotation angles incurred due to rotation, by the local body reference frame, since\nthe last time the values were outputted by the device. The delta velocity (dvel) is the delta velocity incurred\ndue to motion, by the local body reference frame, since the last time the values were outputted by the device.\nThe frame of reference of these delta measurements are determined by the IntegrationFrame field in the\nDelta Theta and Delta Velocity Configuration Register (Register 82). These delta angles and delta velocities\nare calculated based upon the onboard coning and sculling integration performed onboard the sensor at the\nfull IMU rate (default 800Hz). The integration for both the delta angles and velocities are reset each time\neither of the values are either polled or sent out due to a scheduled asynchronous ASCII or binary output.\nDelta Theta and Delta Velocity values correctly capture the nonlinearities involved in measuring motion from\na rotating strapdown platform (as opposed to the older mechanically inertial navigation systems), thus\nproviding you with the ability to integrate velocity and angular rate at much lower speeds (say for example\n10 Hz, reducing bandwidth and computational complexity), while still maintaining the same numeric\nprecision as if you had performed the integration at the full IMU measurement rate of 800Hz. Time is given\nin seconds. Delta angles are given in degrees."); } },
914 {
"DeltaVel", vn::protocol::uart::ImuGroup::IMUGROUP_DELTAVEL,
915 []() { ImGui::TextUnformatted(
"Delta velocity.\n\nThe delta velocity (dvel) is the delta velocity incurred due to motion, since the last time the values were output\nby the device. The delta velocities are calculated based upon the onboard conning and sculling integration\nperformed onboard the sensor at the IMU sampling rate (nominally 800Hz). The integration for the delta\nvelocities are reset each time the values are either polled or sent out due to a scheduled asynchronous ASCII\nor binary output. Delta velocity is given in meters per second."); } },
916 {
"Mag", vn::protocol::uart::ImuGroup::IMUGROUP_MAG,
917 []() { ImGui::TextUnformatted(
"Compensated magnetic measurement.\n\nThe IMU compensated magnetic field measured units of Gauss, and given in the body frame. This\nmeasurement is compensated by the static calibration (individual factory calibration stored in flash), the user\ncompensation, and the dynamic calibration from the onboard Hard/Soft Iron estimator."); },
918 [](VectorNavModel ,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return true; }, coupleImuFilterRates },
919 {
"Accel", vn::protocol::uart::ImuGroup::IMUGROUP_ACCEL,
920 []() { ImGui::TextUnformatted(
"Compensated acceleration measurement.\n\nThe compensated acceleration measured in units of m/s^2, and given in the body frame. This measurement\nis compensated by the static calibration (individual factory calibration stored in flash), the user\ncompensation, and the dynamic bias compensation from the onboard INS Kalman filter."); },
921 [](VectorNavModel ,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return true; }, coupleImuFilterRates },
922 {
"AngularRate", vn::protocol::uart::ImuGroup::IMUGROUP_ANGULARRATE,
923 []() { ImGui::TextUnformatted(
"Compensated angular rate measurement.\n\nThe compensated angular rate measured in units of rad/s, and given in the body frame. This measurement\nis compensated by the static calibration (individual factor calibration stored in flash), the user compensation,\nand the dynamic bias compensation from the onboard INS Kalman filter."); },
924 [](VectorNavModel ,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return true; }, coupleImuFilterRates },
928 {
"UTC", vn::protocol::uart::GpsGroup::GPSGROUP_UTC,
929 []() { ImGui::TextUnformatted(
"GPS UTC Time\n\nThe current UTC time. The year is given as a signed byte year offset from the year 2000. For example the\nyear 2013 would be given as year 13."); },
930 [](VectorNavModel ,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return false; },
931 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& , uint32_t& binaryField) { (
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_UTC) && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO); } },
932 {
"Tow", vn::protocol::uart::GpsGroup::GPSGROUP_TOW,
933 []() { ImGui::TextUnformatted(
"GPS time of week\n\nThe GPS time of week given in nano seconds."); },
934 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t binaryField) {
return sensorModel == VectorNavModel::VN310
935 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSLLA)
936 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSECEF)
937 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELNED)
938 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELECEF)
939 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSU)
940 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELU); },
941 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { (
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_TOW) && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO) && ((bor.commonField & vn::protocol::uart::CommonGroup::COMMONGROUP_TIMESTARTUP) || (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP)); } },
942 {
"Week", vn::protocol::uart::GpsGroup::GPSGROUP_WEEK,
943 []() { ImGui::TextUnformatted(
"GPS week\n\nThe current GPS week."); },
944 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t binaryField) {
return sensorModel == VectorNavModel::VN310
945 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSLLA)
946 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSECEF)
947 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELNED)
948 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELECEF)
949 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSU)
950 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELU); },
951 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { (
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_WEEK) && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO) && ((bor.commonField & vn::protocol::uart::CommonGroup::COMMONGROUP_TIMESTARTUP) || (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP)); } },
952 {
"NumSats", vn::protocol::uart::GpsGroup::GPSGROUP_NUMSATS,
953 []() { ImGui::TextUnformatted(
"Number of tracked satellites\n\nThe number of tracked GNSS satellites."); },
954 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; } },
955 {
"Fix", vn::protocol::uart::GpsGroup::GPSGROUP_FIX,
956 []() { ImGui::TextUnformatted(
"GNSS fix\n\nThe current GNSS fix.");
957 if (ImGui::BeginTable(
"VectorNavFixTooltip", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
959 ImGui::TableSetupColumn(
"Value", ImGuiTableColumnFlags_WidthFixed);
960 ImGui::TableSetupColumn(
"Description", ImGuiTableColumnFlags_WidthFixed);
961 ImGui::TableHeadersRow();
963 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"0");
964 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"No fix");
966 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1");
967 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Time only");
969 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"2");
970 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"2D");
972 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"3");
973 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"3D");
975 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"4");
976 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"SBAS");
978 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"7");
979 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"RTK Float (only GNSS1)");
981 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"8");
982 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"RTK Fixed (only GNSS1)");
986 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t binaryField) {
return sensorModel == VectorNavModel::VN310
987 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSLLA)
988 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSECEF)
989 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELNED)
990 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELECEF)
991 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSU)
992 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELU); } },
993 {
"PosLla", vn::protocol::uart::GpsGroup::GPSGROUP_POSLLA,
994 []() { ImGui::TextUnformatted(
"GNSS position (latitude, longitude, altitude)\n\nThe current GNSS position measurement given as the geodetic latitude, longitude and altitude above the\nellipsoid. The units are in [deg, deg, m] respectively."); },
995 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; },
996 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) {
997 (
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSLLA)
998 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_FIX)
999 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TOW)
1000 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_WEEK)
1001 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO);
1002 bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP;
1004 {
"PosEcef", vn::protocol::uart::GpsGroup::GPSGROUP_POSECEF,
1005 []() { ImGui::TextUnformatted(
"GNSS position (ECEF)\n\nThe current GNSS position given in the Earth centered Earth fixed (ECEF) coordinate frame, given in meters."); },
1006 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; },
1007 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) {
1008 (
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSECEF)
1009 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_FIX)
1010 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TOW)
1011 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_WEEK)
1012 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO);
1013 bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP;
1015 {
"VelNed", vn::protocol::uart::GpsGroup::GPSGROUP_VELNED,
1016 []() { ImGui::TextUnformatted(
"GNSS velocity (NED)\n\nThe current GNSS velocity in the North East Down (NED) coordinate frame, given in m/s."); },
1017 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; },
1018 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) {
1019 (
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELNED)
1020 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_FIX)
1021 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TOW)
1022 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_WEEK)
1023 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO);
1024 bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP;
1026 {
"VelEcef", vn::protocol::uart::GpsGroup::GPSGROUP_VELECEF,
1027 []() { ImGui::TextUnformatted(
"GNSS velocity (ECEF)\n\nThe current GNSS velocity in the Earth centered Earth fixed (ECEF) coordinate frame, given in m/s."); },
1028 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; },
1029 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) {
1030 (
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELECEF)
1031 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_FIX)
1032 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TOW)
1033 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_WEEK)
1034 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO);
1035 bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP;
1037 {
"PosU", vn::protocol::uart::GpsGroup::GPSGROUP_POSU,
1038 []() { ImGui::TextUnformatted(
"GNSS position uncertainty (NED)\n\nThe current GNSS position uncertainty in the North East Down (NED) coordinate frame, given in meters (1 Sigma)."); },
1039 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; },
1040 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) {
1041 (
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSU)
1042 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_FIX)
1043 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TOW)
1044 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_WEEK)
1045 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO);
1046 bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP;
1048 {
"VelU", vn::protocol::uart::GpsGroup::GPSGROUP_VELU,
1049 []() { ImGui::TextUnformatted(
"GNSS velocity uncertainty\n\nThe current GNSS velocity uncertainty, given in m/s (1 Sigma)."); },
1050 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; },
1051 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) {
1052 (
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELU)
1053 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_FIX)
1054 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TOW)
1055 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_WEEK)
1056 && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO);
1057 bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP;
1059 {
"TimeU", vn::protocol::uart::GpsGroup::GPSGROUP_TIMEU,
1060 []() { ImGui::TextUnformatted(
"GNSS time uncertainty\n\nThe current GPS time uncertainty, given in seconds (1 Sigma)."); },
1061 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; },
1062 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& , uint32_t& binaryField) { (
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_TIMEU) && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO); } },
1063 {
"TimeInfo", vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO,
1064 []() { ImGui::TextUnformatted(
"GNSS time status and leap seconds\n\nFlags for valid GPS TOW, week number and UTC and current leap seconds.");
1065 if (ImGui::BeginTable(
"VectorNavTimeInfoTooltip", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F)))
1067 ImGui::TableSetupColumn(
"Bit Offset");
1068 ImGui::TableSetupColumn(
"Field");
1069 ImGui::TableSetupColumn(
"Description");
1070 ImGui::TableHeadersRow();
1072 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"0");
1073 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"timeOk");
1074 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1 - GpsTow is valid");
1076 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1");
1077 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"dateOk");
1078 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1 - TimeGps and GpsWeek are valid");
1080 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"2");
1081 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"utcTimeValid");
1082 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1 - UTC time is valid");
1084 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"3 - 7");
1085 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"resv");
1086 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Reserved for future use");
1090 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t binaryField) {
return sensorModel == VectorNavModel::VN310
1091 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_TOW)
1092 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_WEEK)
1093 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_UTC)
1094 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_TIMEU)
1095 && !(
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_RAWMEAS); } },
1096 {
"DOP", vn::protocol::uart::GpsGroup::GPSGROUP_DOP,
1097 []() { ImGui::TextUnformatted(
"Dilution of precision"); },
1098 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; } },
1099 {
"SatInfo", vn::protocol::uart::GpsGroup::GPSGROUP_SATINFO,
1100 []() { ImGui::TextUnformatted(
"Satellite Information\n\nInformation and measurements pertaining to each GNSS satellite in view.\n\nSatInfo Element:");
1101 if (ImGui::BeginTable(
"VectorNavSatInfoTooltip", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F)))
1103 ImGui::TableSetupColumn(
"Name");
1104 ImGui::TableSetupColumn(
"Description");
1105 ImGui::TableHeadersRow();
1107 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"sys");
1108 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"GNSS constellation indicator. See table below for details.");
1110 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"svId");
1111 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Space vehicle Id");
1113 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"flags");
1114 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Tracking info flags. See table below for details.");
1116 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"cno");
1117 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Carrier-to-noise density ratio (signal strength) [dB-Hz]");
1119 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"qi");
1120 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Quality Indicator. See table below for details.");
1122 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"el");
1123 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Elevation in degrees");
1125 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"az");
1126 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Azimuth angle in degrees");
1130 ImGui::BeginChild(
"VectorNavSatInfoTooltipGNSSConstelationChild", ImVec2(230, 217));
1131 ImGui::TextUnformatted(
"\nGNSS constellation indicator:");
1132 if (ImGui::BeginTable(
"VectorNavSatInfoTooltipGNSSConstelation", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F)))
1134 ImGui::TableSetupColumn(
"Value");
1135 ImGui::TableSetupColumn(
"Description");
1136 ImGui::TableHeadersRow();
1138 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"0");
1139 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"GPS");
1141 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1");
1142 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"SBAS");
1144 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"2");
1145 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Galileo");
1147 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"3");
1148 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"BeiDou");
1150 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"4");
1151 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"IMES");
1153 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"5");
1154 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"QZSS");
1156 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"6");
1157 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"GLONASS");
1163 ImGui::BeginChild(
"VectorNavSatInfoTooltipFlagsChild", ImVec2(260, 217));
1164 ImGui::TextUnformatted(
"\nTracking info flags:");
1165 if (ImGui::BeginTable(
"VectorNavSatInfoTooltipFlags", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F)))
1167 ImGui::TableSetupColumn(
"Bit Offset");
1168 ImGui::TableSetupColumn(
"Description");
1169 ImGui::TableHeadersRow();
1171 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"0");
1172 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Healthy");
1174 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1");
1175 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Almanac");
1177 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"2");
1178 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Ephemeris");
1180 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"3");
1181 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Differential Correction");
1183 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"4");
1184 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Used for Navigation");
1186 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"5");
1187 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Azimuth / Elevation Valid");
1189 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"6");
1190 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Used for RTK");
1195 ImGui::TextUnformatted(
"\nQuality Indicators:");
1196 if (ImGui::BeginTable(
"VectorNavSatInfoTooltipQuality", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F)))
1198 ImGui::TableSetupColumn(
"Value");
1199 ImGui::TableSetupColumn(
"Description");
1200 ImGui::TableHeadersRow();
1202 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"0");
1203 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"No signal");
1205 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1");
1206 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Searching signal");
1208 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"2");
1209 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Signal acquired");
1211 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"3");
1212 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Signal detected but unstable");
1214 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"4");
1215 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Code locked and time synchronized");
1217 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"5, 6, 7");
1218 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Code and carrier locked and time synchronized");
1222 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; } },
1223 {
"RawMeas", vn::protocol::uart::GpsGroup::GPSGROUP_RAWMEAS,
1224 []() { ImGui::TextUnformatted(
"GNSS Raw Measurements.\n\nSatRaw Element:");
1225 if (ImGui::BeginTable(
"VectorNavSatRawTooltip", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F)))
1227 ImGui::TableSetupColumn(
"Name");
1228 ImGui::TableSetupColumn(
"Description");
1229 ImGui::TableHeadersRow();
1231 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"sys");
1232 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"GNSS constellation indicator. See table below for details.");
1234 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"svId");
1235 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Space vehicle Id");
1237 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"freq");
1238 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Frequency indicator. See table below for details.");
1240 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"chan");
1241 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Channel Indicator. See table below for details.");
1243 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"slot");
1244 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Slot Id");
1246 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"cno");
1247 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Carrier-to-noise density ratio (signal strength) [dB-Hz]");
1249 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"flags");
1250 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Tracking info flags. See table below for details.");
1252 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"pr");
1253 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Pseudorange measurement in meters.");
1255 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"cp");
1256 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Carrier phase measurement in cycles.");
1258 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"dp");
1259 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Doppler measurement in Hz. Positive sign for approaching satellites.");
1263 ImGui::BeginChild(
"VectorNavSatRawTooltipGNSSConstelationChild", ImVec2(180, 217));
1264 ImGui::TextUnformatted(
"\nConstellation indicator:");
1265 if (ImGui::BeginTable(
"VectorNavSatRawTooltipGNSSConstelation", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F)))
1267 ImGui::TableSetupColumn(
"Value");
1268 ImGui::TableSetupColumn(
"Description");
1269 ImGui::TableHeadersRow();
1271 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"0");
1272 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"GPS");
1274 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1");
1275 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"SBAS");
1277 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"2");
1278 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Galileo");
1280 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"3");
1281 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"BeiDou");
1283 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"4");
1284 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"IMES");
1286 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"5");
1287 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"QZSS");
1289 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"6");
1290 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"GLONASS");
1296 ImGui::BeginChild(
"VectorNavSatRawTooltipFreqChild", ImVec2(270, 235));
1297 ImGui::TextUnformatted(
"\nFrequency indicator:");
1298 if (ImGui::BeginTable(
"VectorNavSatRawTooltipFreq", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F)))
1300 ImGui::TableSetupColumn(
"Value");
1301 ImGui::TableSetupColumn(
"Description");
1302 ImGui::TableHeadersRow();
1304 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"0");
1305 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Rx Channel");
1307 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1");
1308 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"L1(GPS,QZSS,SBAS), G1(GLO),\nE2-L1-E1(GAL), B1(BDS)");
1310 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"2");
1311 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"L2(GPS,QZSS), G2(GLO)");
1313 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"3");
1314 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"L5(GPS,QZSS,SBAS), E5a(GAL)");
1316 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"4");
1317 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"E6(GAL), LEX(QZSS), B3(BDS)");
1319 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"5");
1320 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"E5b(GAL), B2(BDS)");
1322 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"6");
1323 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"E5a+b(GAL)");
1329 ImGui::BeginChild(
"VectorNavSatRawTooltipFlagChild", ImVec2(255, 260));
1330 ImGui::TextUnformatted(
"\nTracking info flags:");
1331 if (ImGui::BeginTable(
"VectorNavSatRawTooltipFlags", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F)))
1333 ImGui::TableSetupColumn(
"Bit Offset");
1334 ImGui::TableSetupColumn(
"Description");
1335 ImGui::TableHeadersRow();
1337 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"0");
1338 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Searching");
1340 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1");
1341 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Tracking");
1343 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"2");
1344 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Time Valid");
1346 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"3");
1347 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Code Lock");
1349 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"4");
1350 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Phase Lock");
1352 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"5");
1353 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Phase Half Ambiguity");
1355 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"6");
1356 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Phase Half Sub");
1358 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"7");
1359 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Phase Slip");
1361 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"8");
1362 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Pseudorange Smoothed");
1367 ImGui::TextUnformatted(
"\nChannel indicator:");
1368 if (ImGui::BeginTable(
"VectorNavSatRawTooltipChan", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F)))
1370 ImGui::TableSetupColumn(
"Value");
1371 ImGui::TableSetupColumn(
"Description");
1372 ImGui::TableHeadersRow();
1374 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"0");
1375 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"P-code (GPS,GLO)");
1377 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1");
1378 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"C/A-code (GPS,GLO,SBAS,QZSS), C chan (GAL)");
1380 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"2");
1381 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"semi-codeless (GPS)");
1383 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"3");
1384 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Y-code (GPS)");
1386 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"4");
1387 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"M-code (GPS)");
1389 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"5");
1390 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"codeless (GPS)");
1392 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"6");
1393 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"A chan (GAL)");
1395 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"7");
1396 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"B chan (GAL)");
1398 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"8");
1399 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"I chan (GPS,GAL,QZSS,BDS)");
1401 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"9");
1402 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Q chan (GPS,GAL,QZSS,BDS)");
1404 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"10");
1405 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"M chan (L2CGPS, L2CQZSS), D chan (GPS,QZSS)");
1407 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"11");
1408 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"L chan (L2CGPS, L2CQZSS), P chan (GPS,QZSS)");
1410 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"12");
1411 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"B+C chan (GAL), I+Q chan (GPS,GAL,QZSS,BDS),\nM+L chan (GPS,QZSS), D+P chan (GPS,QZSS)");
1413 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"13");
1414 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"based on Z-tracking (GPS)");
1416 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"14");
1417 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"A+B+C (GAL)");
1421 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; },
1422 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& , uint32_t& binaryField) { (
static_cast<vn::protocol::uart::GpsGroup
>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_RAWMEAS) && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO); } },
1426 {
"VpeStatus", vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_VPESTATUS,
1427 []() { ImGui::TextUnformatted(
"VPE Status bitfield\n\n");
1428 if (ImGui::BeginTable(
"VectorNavSatRawTooltipChan", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
1430 ImGui::TableSetupColumn(
"Name", ImGuiTableColumnFlags_WidthFixed);
1431 ImGui::TableSetupColumn(
"Bit Offset", ImGuiTableColumnFlags_WidthFixed);
1432 ImGui::TableSetupColumn(
"Format", ImGuiTableColumnFlags_WidthFixed);
1433 ImGui::TableSetupColumn(
"Description", ImGuiTableColumnFlags_WidthFixed);
1434 ImGui::TableHeadersRow();
1436 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"AttitudeQuality");
1437 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"0");
1438 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"2 bits");
1439 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Provides an indication of the quality of the attitude solution.\n0 - Excellent\n1 - Good\n2 - Bad\n3 - Not tracking");
1441 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"GyroSaturation");
1442 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"2");
1443 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1 bits");
1444 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"At least one gyro axis is currently saturated.");
1446 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"GyroSaturationRecovery");
1447 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"3");
1448 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1 bits");
1449 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Filter is in the process of recovering from a gyro\nsaturation event.");
1451 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"MagDisturbance");
1452 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"4");
1453 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"2 bits");
1454 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"A magnetic DC disturbance has been detected.\n0 - No magnetic disturbance\n1 to 3 - Magnetic disturbance is present.");
1456 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"MagSaturation");
1457 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"6");
1458 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1 bits");
1459 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"At least one magnetometer axis is currently saturated.");
1461 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"AccDisturbance");
1462 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"7");
1463 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"2 bits");
1464 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"A strong acceleration disturbance has been detected.\n0 - No acceleration disturbance.\n1 to 3 - Acceleration disturbance has been detected.");
1466 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"AccSaturation");
1467 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"9");
1468 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1 bits");
1469 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"At least one accelerometer axis is currently saturated.");
1471 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Reserved");
1472 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"10");
1473 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1 bits");
1474 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Reserved for internal use. May change state at run- time.");
1476 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"KnownMagDisturbance");
1477 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"11");
1478 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1 bits");
1479 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"A known magnetic disturbance has been reported by\nthe user and the magnetometer is currently tuned out.");
1481 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"KnownAccelDisturbance");
1482 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"12");
1483 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1 bits");
1484 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"A known acceleration disturbance has been reported by\nthe user and the accelerometer is currently tuned out.");
1486 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Reserved");
1487 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"13");
1488 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"3 bits");
1489 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Reserved for future use.");
1493 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN100_VN110; } },
1494 {
"YawPitchRoll", vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YAWPITCHROLL,
1495 []() { ImGui::TextUnformatted(
"Yaw Pitch Roll\n\nThe estimated attitude Yaw, Pitch, and Roll angles measured in degrees. The attitude is given as a 3,2,1\nEuler angle sequence describing the body frame with respect to the local North East Down (NED) frame.\n\nYaw [+/- 180°]\nPitch [+/- 90°]\nRoll [+/- 180°]"); },
1496 [](VectorNavModel ,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return true; },
1497 [](
VectorNavSensor* sensor, vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { (
static_cast<vn::protocol::uart::AttitudeGroup
>(binaryField) & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YAWPITCHROLL) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS)
1498 && ((sensor->_sensorModel == VectorNavModel::VN310) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)); } },
1499 {
"Quaternion", vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_QUATERNION,
1500 []() { ImGui::TextUnformatted(
"Quaternion\n\nThe estimated attitude quaternion. The last term is the scalar value. The attitude is given as the body\nframe with respect to the local North East Down (NED) frame."); },
1501 [](VectorNavModel ,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return true; },
1502 [](
VectorNavSensor* sensor, vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { (
static_cast<vn::protocol::uart::AttitudeGroup
>(binaryField) & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_QUATERNION) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS)
1503 && ((sensor->_sensorModel == VectorNavModel::VN310) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)); } },
1504 {
"DCM", vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_DCM,
1505 []() { ImGui::TextUnformatted(
"Directional Cosine Matrix\n\nThe estimated attitude directional cosine matrix given in column major order. The DCM maps vectors\nfrom the North East Down (NED) frame into the body frame."); },
1506 [](VectorNavModel ,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return true; },
1507 [](
VectorNavSensor* sensor, vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { (
static_cast<vn::protocol::uart::AttitudeGroup
>(binaryField) & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_DCM) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS)
1508 && ((sensor->_sensorModel == VectorNavModel::VN310) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)); } },
1509 {
"MagNed", vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_MAGNED,
1510 []() { ImGui::TextUnformatted(
"Compensated magnetic (NED)\n\nThe current estimated magnetic field (Gauss), given in the North East Down (NED) frame. The current\nattitude solution is used to map the measurement from the measured body frame to the inertial (NED)\nframe. This measurement is compensated by both the static calibration (individual factory calibration\nstored in flash), and the dynamic calibration such as the user or onboard Hard/Soft Iron compensation\nregisters."); },
1511 [](VectorNavModel ,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return true; },
1512 [](
VectorNavSensor* sensor, vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { (
static_cast<vn::protocol::uart::AttitudeGroup
>(binaryField) & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_MAGNED) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS)
1513 && ((sensor->_sensorModel == VectorNavModel::VN310) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)); } },
1514 {
"AccelNed", vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_ACCELNED,
1515 []() { ImGui::TextUnformatted(
"Compensated acceleration (NED)\n\nThe estimated acceleration (with gravity) reported in m/s^2, given in the North East Down (NED) frame.\nThe acceleration measurement has been bias compensated by the onboard INS filter. This measurement\nis attitude dependent, since the attitude is used to map the measurement from the body frame into the\ninertial (NED) frame. If the device is stationary and the INS filter is tracking, the measurement should be\nnominally equivalent to the gravity reference vector in the inertial frame (NED)."); },
1516 [](VectorNavModel ,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return true; },
1517 [](
VectorNavSensor* sensor, vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { (
static_cast<vn::protocol::uart::AttitudeGroup
>(binaryField) & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_ACCELNED) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS)
1518 && ((sensor->_sensorModel == VectorNavModel::VN310) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)); } },
1519 {
"LinearAccelBody", vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELBODY,
1520 []() { ImGui::TextUnformatted(
"Compensated linear acceleration (no gravity)\n\nThe estimated linear acceleration (without gravity) reported in m/s^2, and given in the body frame. The\nacceleration measurement has been bias compensated by the onboard INS filter, and the gravity\ncomponent has been removed using the current gravity reference vector model. This measurement is\nattitude dependent, since the attitude solution is required to map the gravity reference vector (known in\nthe inertial NED frame), into the body frame so that it can be removed from the measurement. If the\ndevice is stationary and the onboard INS filter is tracking, the measurement nominally will read 0 in all\nthree axes."); },
1521 [](VectorNavModel ,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return true; },
1522 [](
VectorNavSensor* sensor, vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { (
static_cast<vn::protocol::uart::AttitudeGroup
>(binaryField) & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELBODY) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS)
1523 && ((sensor->_sensorModel == VectorNavModel::VN310) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)); } },
1524 {
"LinearAccelNed", vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELNED,
1525 []() { ImGui::TextUnformatted(
"Compensated linear acceleration (no gravity) (NED)\n\nThe estimated linear acceleration (without gravity) reported in m/s^2, and given in the North East Down\n(NED) frame. This measurement is attitude dependent as the attitude solution is used to map the\nmeasurement from the body frame into the inertial (NED) frame. This acceleration measurement has\nbeen bias compensated by the onboard INS filter, and the gravity component has been removed using the\ncurrent gravity reference vector estimate. If the device is stationary and the onboard INS filter is tracking,\nthe measurement nominally will read 0 in all three axes."); },
1526 [](VectorNavModel ,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return true; },
1527 [](
VectorNavSensor* sensor, vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { (
static_cast<vn::protocol::uart::AttitudeGroup
>(binaryField) & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELNED) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS)
1528 && ((sensor->_sensorModel == VectorNavModel::VN310) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)); } },
1529 {
"YprU", vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YPRU,
1530 []() { ImGui::TextUnformatted(
"Yaw Pitch Roll uncertainty\n\nThe estimated attitude (Yaw, Pitch, Roll) uncertainty (1 Sigma), reported in degrees.\n\nThe estimated attitude (YprU) field is not valid when the INS Scenario mode in the INS Basic\nConfiguration register is set to AHRS mode. See the INS Basic Configuration Register in the INS\nsection for more details."); },
1531 [](VectorNavModel ,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return true; },
1532 [](
VectorNavSensor* sensor, vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { (
static_cast<vn::protocol::uart::AttitudeGroup
>(binaryField) & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YPRU) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS)
1533 && ((sensor->_sensorModel == VectorNavModel::VN310) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)); } },
1537 {
"InsStatus", vn::protocol::uart::InsGroup::INSGROUP_INSSTATUS,
1538 []() { ImGui::TextUnformatted(
"Ins Status bitfield:");
1539 if (ImGui::BeginTable(
"VectorNavInsStatusTooltip", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
1541 ImGui::TableSetupColumn(
"Name", ImGuiTableColumnFlags_WidthFixed);
1542 ImGui::TableSetupColumn(
"Bit Offset", ImGuiTableColumnFlags_WidthFixed);
1543 ImGui::TableSetupColumn(
"Format", ImGuiTableColumnFlags_WidthFixed);
1544 ImGui::TableSetupColumn(
"Description", ImGuiTableColumnFlags_WidthFixed);
1545 ImGui::TableHeadersRow();
1547 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Mode");
1548 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"0");
1549 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"2 bits");
1550 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Indicates the current mode of the INS filter.\n\n0 = Not tracking. GNSS Compass is initializing. Output heading is based on\nmagnetometer measurements.\n1 = Aligning.\nINS Filter is dynamically aligning.\nFor a stationary startup: GNSS Compass has initialized and INS Filter is\naligning from the magnetic heading to the GNSS Compass heading.\nFor a dynamic startup: INS Filter has initialized and is dynamically aligning to\nTrue North heading.\nIn operation, if the INS Filter drops from INS Mode 2 back down to 1, the\nattitude uncertainty has increased above 2 degrees.\n2 = Tracking. The INS Filter is tracking and operating within specification.\n3 = Loss of GNSS. A GNSS outage has lasted more than 45 seconds. The INS\nFilter will no longer update the position and velocity outputs, but the attitude\nremains valid.");
1552 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"GpsFix");
1553 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"2");
1554 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1 bits");
1555 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Indicates whether the GNSS has a proper fix.");
1557 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Error");
1558 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"3");
1559 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"4 bits");
1560 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Sensor measurement error code. See table below.\n0 = No errors detected.");
1562 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Reserved");
1563 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"7");
1564 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1 bits");
1565 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Reserved for internal use. May toggle state during runtime and should be ignored.");
1567 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"GpsHeadingIns");
1568 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"8");
1569 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1 bits");
1570 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"In stationary operation, if set the INS Filter has fully aligned to the GNSS\nCompass solution.\nIn dynamic operation, the GNSS Compass solution is currently aiding the INS\nFilter heading solution.");
1572 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"GpsCompass");
1573 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"9");
1574 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"1 bits");
1575 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Indicates if the GNSS compass is operational and reporting a heading\nsolution.");
1577 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Reserved");
1578 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"10");
1579 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"6 bits");
1580 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Reserved for internal use. These bits will toggle state and should be ignored.");
1584 ImGui::TextUnformatted(
"\nError Bitfield:");
1585 if (ImGui::BeginTable(
"VectorNavInsStatusTooltipError", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F)))
1587 ImGui::TableSetupColumn(
"Name");
1588 ImGui::TableSetupColumn(
"Description");
1589 ImGui::TableHeadersRow();
1591 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Reserved");
1592 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Reserved for future use and not currently used.");
1594 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"IMU Error");
1595 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"High if IMU communication error is detected.");
1597 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"Mag/Pres Error");
1598 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"High if Magnetometer or Pressure sensor error is detected.");
1600 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"GNSS Error");
1601 ImGui::TableNextColumn(); ImGui::TextUnformatted(
"High if GNSS communication error is detected.");
1605 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; },
1606 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { (
static_cast<vn::protocol::uart::InsGroup
>(binaryField) & vn::protocol::uart::InsGroup::INSGROUP_INSSTATUS) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW); } },
1607 {
"PosLla", vn::protocol::uart::InsGroup::INSGROUP_POSLLA,
1608 []() { ImGui::TextUnformatted(
"Ins Position (latitude, longitude, altitude)\n\nThe estimated position given as latitude, longitude, and altitude given in [deg, deg, m] respectively."); },
1609 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; },
1610 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { (
static_cast<vn::protocol::uart::InsGroup
>(binaryField) & vn::protocol::uart::InsGroup::INSGROUP_POSLLA) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW); } },
1611 {
"PosEcef", vn::protocol::uart::InsGroup::INSGROUP_POSECEF,
1612 []() { ImGui::TextUnformatted(
"Ins Position (ECEF)\n\nThe estimated position given in the Earth centered Earth fixed (ECEF) frame, reported in meters."); },
1613 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; },
1614 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { (
static_cast<vn::protocol::uart::InsGroup
>(binaryField) & vn::protocol::uart::InsGroup::INSGROUP_POSECEF) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW); } },
1615 {
"VelBody", vn::protocol::uart::InsGroup::INSGROUP_VELBODY,
1616 []() { ImGui::TextUnformatted(
"Ins Velocity (Body)\n\nThe estimated velocity in the body frame, given in m/s."); },
1617 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; },
1618 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { (
static_cast<vn::protocol::uart::InsGroup
>(binaryField) & vn::protocol::uart::InsGroup::INSGROUP_VELBODY) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW); } },
1619 {
"VelNed", vn::protocol::uart::InsGroup::INSGROUP_VELNED,
1620 []() { ImGui::TextUnformatted(
"Ins Velocity (NED)\n\nThe estimated velocity in the North East Down (NED) frame, given in m/s."); },
1621 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; },
1622 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { (
static_cast<vn::protocol::uart::InsGroup
>(binaryField) & vn::protocol::uart::InsGroup::INSGROUP_VELNED) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW); } },
1623 {
"VelEcef", vn::protocol::uart::InsGroup::INSGROUP_VELECEF,
1624 []() { ImGui::TextUnformatted(
"Ins Velocity (ECEF)\n\nThe estimated velocity in the Earth centered Earth fixed (ECEF) frame, given in m/s."); },
1625 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; },
1626 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { (
static_cast<vn::protocol::uart::InsGroup
>(binaryField) & vn::protocol::uart::InsGroup::INSGROUP_VELECEF) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW); } },
1627 {
"MagEcef", vn::protocol::uart::InsGroup::INSGROUP_MAGECEF,
1628 []() { ImGui::TextUnformatted(
"Compensated magnetic (ECEF)\n\nThe compensated magnetic measurement in the Earth centered Earth fixed (ECEF) frame, given in Gauss."); },
1629 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; },
1630 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { (
static_cast<vn::protocol::uart::InsGroup
>(binaryField) & vn::protocol::uart::InsGroup::INSGROUP_MAGECEF) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW); } },
1631 {
"AccelEcef", vn::protocol::uart::InsGroup::INSGROUP_ACCELECEF,
1632 []() { ImGui::TextUnformatted(
"Compensated acceleration (ECEF)\n\nThe estimated acceleration (with gravity) reported in m/s^2, given in the Earth centered Earth fixed (ECEF)\nframe. The acceleration measurement has been bias compensated by the onboard INS filter. This\nmeasurement is attitude dependent, since the attitude is used to map the measurement from the body frame\ninto the inertial (ECEF) frame. If the device is stationary and the INS filter is tracking, the measurement\nshould be nominally equivalent to the gravity reference vector in the inertial frame (ECEF)."); },
1633 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; },
1634 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { (
static_cast<vn::protocol::uart::InsGroup
>(binaryField) & vn::protocol::uart::InsGroup::INSGROUP_ACCELECEF) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW); } },
1635 {
"LinearAccelEcef", vn::protocol::uart::InsGroup::INSGROUP_LINEARACCELECEF,
1636 []() { ImGui::TextUnformatted(
"Compensated linear acceleration (no gravity) (ECEF)\n\nThe estimated linear acceleration (without gravity) reported in m/s^2, and given in the Earth centered Earth\nfixed (ECEF) frame. This measurement is attitude dependent as the attitude solution is used to map the\nmeasurement from the body frame into the inertial (ECEF) frame. This acceleration measurement has been\nbias compensated by the onboard INS filter, and the gravity component has been removed using the current\ngravity reference vector estimate. If the device is stationary and the onboard INS filter is tracking, the\nmeasurement will nominally read 0 in all three axes."); },
1637 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; },
1638 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { (
static_cast<vn::protocol::uart::InsGroup
>(binaryField) & vn::protocol::uart::InsGroup::INSGROUP_LINEARACCELECEF) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW); } },
1639 {
"PosU", vn::protocol::uart::InsGroup::INSGROUP_POSU,
1640 []() { ImGui::TextUnformatted(
"Ins Position Uncertainty\n\nThe estimated uncertainty (1 Sigma) in the current position estimate, given in meters."); },
1641 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; },
1642 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { (
static_cast<vn::protocol::uart::InsGroup
>(binaryField) & vn::protocol::uart::InsGroup::INSGROUP_POSU) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW); } },
1643 {
"VelU", vn::protocol::uart::InsGroup::INSGROUP_VELU,
1644 []() { ImGui::TextUnformatted(
"Ins Velocity Uncertainty\n\nThe estimated uncertainty (1 Sigma) in the current velocity estimate, given in m/s."); },
1645 [](VectorNavModel sensorModel,
const vn::sensors::BinaryOutputRegister& , uint32_t ) {
return sensorModel == VectorNavModel::VN310; },
1646 [](
VectorNavSensor* , vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { (
static_cast<vn::protocol::uart::InsGroup
>(binaryField) & vn::protocol::uart::InsGroup::INSGROUP_VELU) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW); } },
1666 std::map<int, int, std::greater<>> divFreq;
1671 if (!divFreq.contains(divider)
1674 divFreq[divider] = freq;
1677 std::vector<uint16_t> divs;
1678 std::vector<std::string> freqs;
1679 for (
auto& [divider, freq] : divFreq)
1681 divs.push_back(
static_cast<uint16_t
>(divider));
1682 freqs.push_back(std::to_string(freq) +
" Hz");
1683 LOG_DATA(
"VectorNavSensor: RateDivisor {} = {}", divs.back(), freqs.back());
1685 return std::make_pair(divs, freqs);
1696 return "VectorNavSensor";
1706 return "Data Provider";
1712 ImGui::Combo(
"Sensor", &sensorModel,
"VN-100 / VN-110\0VN-310\0\0"))
1752 if (i == 0 || i == 9 ) {
continue; }
1755 if ((i == 2 || i == 3 )
1757 && binaryOutput.timeField & vn::protocol::uart::TIMEGROUP_TIMESTARTUP
1760 binaryOutput.timeField |= vn::protocol::uart::TimeGroup(item.flagsValue);
1764 if (!item.isEnabled(
_sensorModel, binaryOutput,
static_cast<uint32_t
>(binaryOutput.timeField)))
1766 binaryOutput.timeField &=
~vn::protocol::uart::TimeGroup(item.flagsValue);
1771 if (!item.isEnabled(
_sensorModel, binaryOutput,
static_cast<uint32_t
>(binaryOutput.imuField)))
1773 binaryOutput.imuField &=
~vn::protocol::uart::ImuGroup(item.flagsValue);
1778 if (!item.isEnabled(
_sensorModel, binaryOutput,
static_cast<uint32_t
>(binaryOutput.gpsField)))
1780 binaryOutput.gpsField &=
~vn::protocol::uart::GpsGroup(item.flagsValue);
1782 if (!item.isEnabled(
_sensorModel, binaryOutput,
static_cast<uint32_t
>(binaryOutput.gps2Field)))
1784 binaryOutput.gps2Field &=
~vn::protocol::uart::GpsGroup(item.flagsValue);
1789 if (!item.isEnabled(
_sensorModel, binaryOutput,
static_cast<uint32_t
>(binaryOutput.attitudeField)))
1791 binaryOutput.attitudeField &=
~vn::protocol::uart::AttitudeGroup(item.flagsValue);
1796 if (!item.isEnabled(
_sensorModel, binaryOutput,
static_cast<uint32_t
>(binaryOutput.insField)))
1798 binaryOutput.insField &=
~vn::protocol::uart::InsGroup(item.flagsValue);
1815 "- \"COM1\" (Windows format for physical and virtual (USB) serial port)\n"
1816 "- \"/dev/ttyS1\" (Linux format for physical serial port)\n"
1817 "- \"/dev/ttyUSB0\" (Linux format for virtual (USB) serial port)\n"
1818 "- \"/dev/tty.usbserial-FTXXXXXX\" (Mac OS X format for virtual (USB) serial port)\n"
1819 "- \"/dev/ttyS0\" (CYGWIN format. Usually the Windows COM port number minus 1. This would connect to COM1)");
1822 if (!isNodeInitialized)
1824 ImGui::BeginDisabled();
1826 if (ImGui::Button(
"Write settings"))
1830 _vs.writeSettings();
1832 catch (
const std::exception& e)
1834 LOG_ERROR(
"{}: Write settings threw an exception: {}",
nameId(), e.what());
1837 if (!isNodeInitialized)
1839 ImGui::EndDisabled();
1841 if (ImGui::IsItemHovered())
1843 ImGui::SetTooltip(
"This command will write the current register settings into non-volatile memory. Once the settings are stored\n"
1844 "in non-volatile (Flash) memory, the VN-310E module can be power cycled or reset, and the register will be\n"
1845 "reloaded from non-volatile memory.\n\n"
1846 "Due to limitations in the flash write speed the write settings command takes ~ 500ms to\n"
1847 "complete. Any commands that are sent to the sensor during this time will be responded to after\n"
1848 "the operation is complete.\n\n"
1849 "The sensor must be stationary when issuing a Write Settings Command otherwise a Reset\n"
1850 "command must also be issued to prevent the Kalman Filter from diverging during the write\n"
1851 "settings process.\n\n"
1852 "A write settings command is automatically send after initializing the node.");
1855 if (!isNodeInitialized)
1857 ImGui::BeginDisabled();
1859 if (ImGui::Button(
"Restore factory settings"))
1863 _vs.restoreFactorySettings();
1865 catch (
const std::exception& e)
1867 LOG_ERROR(
"{}: Restore factory settings threw an exception: {}",
nameId(), e.what());
1870 if (!isNodeInitialized)
1872 ImGui::EndDisabled();
1874 if (ImGui::IsItemHovered())
1876 ImGui::SetTooltip(
"This command will restore the VN-310E module's factory default settings and will reset the module. There\n"
1877 "are no parameters for this command. The module will respond to this command before restoring the factory\n"
1881 if (!isNodeInitialized)
1883 ImGui::BeginDisabled();
1885 if (ImGui::Button(
"Reset sensor"))
1891 catch (
const std::exception& e)
1893 LOG_ERROR(
"{}: Resetting threw an exception: {}",
nameId(), e.what());
1896 if (!isNodeInitialized)
1898 ImGui::EndDisabled();
1900 if (ImGui::IsItemHovered())
1902 ImGui::SetTooltip(
"This command will reset the module. There are no parameters required for this command. The module will\n"
1903 "first respond to the command and will then perform a reset. Upon a reset all registers will be reloaded with\n"
1904 "the values saved in non-volatile memory. If no values are stored in non-volatile memory, the device will default\n"
1905 "to factory settings. Also upon reset the VN-310E will re-initialize its Kalman filter, thus the filter will take a\n"
1906 "few seconds to completely converge on the correct attitude and correct for gyro bias.");
1913 ImGui::SetNextItemOpen(
true, ImGuiCond_FirstUseEver);
1914 if (ImGui::CollapsingHeader(fmt::format(
"System Module##{}",
size_t(
id)).c_str()))
1918 std::array<const char*, 10> items = {
"Fastest",
"9600",
"19200",
"38400",
"57600",
"115200",
"128000",
"230400",
"460800",
"921600" };
1926 if (ImGui::TreeNode(fmt::format(
"Async Ascii Output##{}",
size_t(
id)).c_str()))
1928 std::vector<std::pair<vn::protocol::uart::AsciiAsync, const char*>> asciiAsyncItems{
1929 { vn::protocol::uart::AsciiAsync::VNOFF,
"Asynchronous output turned off" },
1930 { vn::protocol::uart::AsciiAsync::VNYPR,
"Yaw, Pitch, Roll" },
1931 { vn::protocol::uart::AsciiAsync::VNQTN,
"Quaternion" },
1932 { vn::protocol::uart::AsciiAsync::VNQMR,
"Quaternion, Magnetic, Acceleration and Angular Rates" },
1933 { vn::protocol::uart::AsciiAsync::VNMAG,
"Magnetic Measurements" },
1934 { vn::protocol::uart::AsciiAsync::VNACC,
"Acceleration Measurements" },
1935 { vn::protocol::uart::AsciiAsync::VNGYR,
"Angular Rate Measurements" },
1936 { vn::protocol::uart::AsciiAsync::VNMAR,
"Magnetic, Acceleration, and Angular Rate Measurements" },
1937 { vn::protocol::uart::AsciiAsync::VNYMR,
"Yaw, Pitch, Roll, Magnetic, Acceleration, and Angular Rate Measurements" },
1938 { vn::protocol::uart::AsciiAsync::VNYBA,
"Yaw, Pitch, Roll, Body True Acceleration, and Angular Rates" },
1939 { vn::protocol::uart::AsciiAsync::VNYIA,
"Yaw, Pitch, Roll, Inertial True Acceleration, and Angular Rates" },
1940 { vn::protocol::uart::AsciiAsync::VNIMU,
"IMU Measurements" }
1944 asciiAsyncItems.emplace_back(vn::protocol::uart::AsciiAsync::VNGPS,
"GNSS LLA");
1945 asciiAsyncItems.emplace_back(vn::protocol::uart::AsciiAsync::VNGPE,
"GNSS ECEF");
1946 asciiAsyncItems.emplace_back(vn::protocol::uart::AsciiAsync::VNINS,
"INS LLA");
1947 asciiAsyncItems.emplace_back(vn::protocol::uart::AsciiAsync::VNINE,
"INS ECEF");
1948 asciiAsyncItems.emplace_back(vn::protocol::uart::AsciiAsync::VNISL,
"INS LLA 2");
1949 asciiAsyncItems.emplace_back(vn::protocol::uart::AsciiAsync::VNISE,
"INS ECEF 2");
1951 asciiAsyncItems.emplace_back(vn::protocol::uart::AsciiAsync::VNDTV,
"Delta theta and delta velocity");
1954 asciiAsyncItems.emplace_back(vn::protocol::uart::AsciiAsync::VNG2S,
"GNSS2 LLA");
1955 asciiAsyncItems.emplace_back(vn::protocol::uart::AsciiAsync::VNG2E,
"GNSS2 ECEF");
1958 if (ImGui::BeginCombo(fmt::format(
"Async Ascii Output Type##{}",
size_t(
id)).c_str(), vn::protocol::uart::str(
_asyncDataOutputType).c_str()))
1960 for (
const auto& asciiAsyncItem : asciiAsyncItems)
1963 if (ImGui::Selectable(vn::protocol::uart::str(asciiAsyncItem.first).c_str(), isSelected))
1974 catch (
const std::exception& e)
1976 LOG_ERROR(
"{}: Could not configure the asyncDataOutputType: {}",
nameId(), e.what());
1985 if (ImGui::IsItemHovered())
1987 ImGui::BeginTooltip();
1988 ImGui::TextUnformatted(asciiAsyncItem.second);
1989 ImGui::EndTooltip();
1995 ImGui::SetItemDefaultFocus();
2001 gui::widgets::HelpMarker(
"This register controls the type of data that will be asynchronously outputted by the module. With this "
2002 "register, the user can specify which data register will be automatically outputted when it gets updated "
2003 "with a new reading. The table below lists which registers can be set to asynchronously output, the value "
2004 "to specify which register to output, and the header of the asynchronous data packet. Asynchronous data "
2005 "output can be disabled by setting this register to zero. The asynchronous data output will be sent out "
2006 "automatically at a frequency specified by the Async Data Output Frequency Register.");
2008 if (ImGui::SliderInt(fmt::format(
"Async Ascii Output Frequency##{}",
size_t(
id)).c_str(),
2022 catch (
const std::exception& e)
2024 LOG_ERROR(
"{}: Could not configure the asyncDataOutputFrequency: {}",
nameId(), e.what());
2034 gui::widgets::HelpMarker(
"Asynchronous data output frequency.\nThe ADOF will be changed for the active serial port.");
2036 if (ImGui::DragInt(fmt::format(
"Async Ascii Output buffer size##{}",
size_t(
id)).c_str(), &
_asciiOutputBufferSize, 1.0F, 0, INT32_MAX / 2))
2043 std::string messages;
2046 messages.append(msg);
2048 ImGui::TextUnformatted(
"Async Ascii Messages:");
2049 ImGui::BeginChild(fmt::format(
"##Ascii Mesages {}",
size_t(
id)).c_str(), ImVec2(0, 300),
true);
2050 ImGui::PushTextWrapPos();
2051 ImGui::TextUnformatted(messages.c_str());
2052 ImGui::PopTextWrapPos();
2058 if (ImGui::TreeNode(fmt::format(
"Synchronization Control##{}",
size_t(
id)).c_str()))
2060 ImGui::TextUnformatted(
"Contains parameters which allow the timing of the VN-310E to be\n"
2061 "synchronized with external devices.");
2063 if (ImGui::Checkbox(fmt::format(
"Show SyncIn Pin##{}",
size_t(
id)).c_str(), &
_syncInPin))
2082 static constexpr std::array<std::pair<vn::protocol::uart::SyncInMode, const char*>, 4> synchronizationControlSyncInModes = {
2083 { { vn::protocol::uart::SyncInMode::SYNCINMODE_COUNT,
"Count number of trigger events on SYNC_IN" },
2084 { vn::protocol::uart::SyncInMode::SYNCINMODE_IMU,
"Start IMU sampling on trigger of SYNC_IN" },
2085 { vn::protocol::uart::SyncInMode::SYNCINMODE_ASYNC,
"Output asynchronous message on trigger of SYNC_IN" },
2086 { vn::protocol::uart::SyncInMode::SYNCINMODE_ASYNC3,
"Output asynchronous or binary messages configured with a rate of 0 to output on trigger of SYNC_IN\n\n"
2087 "In ASYNC3 mode messages configured with an output rate = 0 are output each time the appropriate\n"
2088 "transistion edge of the SyncIn pin is captured according to the edge settings in the SyncInEdge field.\n"
2089 "Messages configured with output rate > 0 are not affected by the SyncIn pulse. This applies to the ASCII\n"
2090 "Async message set by the Async Data Output Register, the user configurate binary output messages set\n"
2091 "by the Binary Output Registers, as well as the NMEA messages configured by the NMEA Output Registers." } }
2095 ImGui::BeginDisabled();
2098 if (ImGui::BeginCombo(fmt::format(
"SyncIn Mode##{}",
size_t(
id)).c_str(), vn::protocol::uart::str(
_synchronizationControlRegister.syncInMode).c_str()))
2100 for (
const auto& synchronizationControlSyncInMode : synchronizationControlSyncInModes)
2103 if (ImGui::Selectable(vn::protocol::uart::str(synchronizationControlSyncInMode.first).c_str(), isSelected))
2114 catch (
const std::exception& e)
2116 LOG_ERROR(
"{}: Could not configure the synchronizationControlRegister: {}",
nameId(), e.what());
2125 if (ImGui::IsItemHovered())
2127 ImGui::BeginTooltip();
2128 ImGui::TextUnformatted(synchronizationControlSyncInMode.second);
2129 ImGui::EndTooltip();
2134 ImGui::SetItemDefaultFocus();
2140 gui::widgets::HelpMarker(
"The SyncInMode register controls the behavior of the SyncIn event. If the mode is set to COUNT then the "
2141 "internal clock will be used to control the IMU sampling. If SyncInMode is set to IMU then the IMU sampling "
2142 "loop will run on a SyncIn event. The relationship between the SyncIn event and a SyncIn trigger is defined "
2143 "by the SyncInEdge and SyncInSkipFactor parameters. If set to ASYNC then the VN-100 will output "
2144 "asynchronous serial messages upon each trigger event.");
2147 ImGui::EndDisabled();
2150 static constexpr std::array<std::pair<vn::protocol::uart::SyncInEdge, const char*>, 2> synchronizationControlSyncInEdges = {
2151 { { vn::protocol::uart::SyncInEdge::SYNCINEDGE_RISING,
"Trigger on rising edge" },
2152 { vn::protocol::uart::SyncInEdge::SYNCINEDGE_FALLING,
"Trigger on falling edge" } }
2154 if (ImGui::BeginCombo(fmt::format(
"SyncIn Edge##{}",
size_t(
id)).c_str(), vn::protocol::uart::str(
_synchronizationControlRegister.syncInEdge).c_str()))
2156 for (
const auto& synchronizationControlSyncInEdge : synchronizationControlSyncInEdges)
2159 if (ImGui::Selectable(vn::protocol::uart::str(synchronizationControlSyncInEdge.first).c_str(), isSelected))
2170 catch (
const std::exception& e)
2172 LOG_ERROR(
"{}: Could not configure the synchronizationControlRegister: {}",
nameId(), e.what());
2181 if (ImGui::IsItemHovered())
2183 ImGui::BeginTooltip();
2184 ImGui::TextUnformatted(synchronizationControlSyncInEdge.second);
2185 ImGui::EndTooltip();
2190 ImGui::SetItemDefaultFocus();
2197 "The factory default state is to trigger on a rising edge.");
2200 if (ImGui::InputInt(fmt::format(
"SyncIn Skip Factor##{}",
size_t(
id)).c_str(), &syncInSkipFactor))
2202 if (syncInSkipFactor < 0)
2204 syncInSkipFactor = 0;
2206 else if (syncInSkipFactor > std::numeric_limits<uint16_t>::max())
2208 syncInSkipFactor = std::numeric_limits<uint16_t>::max();
2219 catch (
const std::exception& e)
2221 LOG_ERROR(
"{}: Could not configure the synchronizationControlRegister: {}",
nameId(), e.what());
2231 gui::widgets::HelpMarker(
"The SyncInSkipFactor defines how many times trigger edges defined by SyncInEdge should occur prior to "
2232 "triggering a SyncIn event. The action performed on a SyncIn event is determined by the SyncIn mode. As an "
2233 "example if the SyncInSkipFactor was set to 4 and a 1 kHz signal was attached to the SyncIn pin, then the "
2234 "SyncIn event would only occur at 200 Hz.");
2236 static constexpr std::array<std::pair<vn::protocol::uart::SyncOutMode, const char*>, 5> synchronizationControlSyncOutModes = {
2237 { { vn::protocol::uart::SyncOutMode::SYNCOUTMODE_NONE,
"None" },
2238 { vn::protocol::uart::SyncOutMode::SYNCOUTMODE_IMUSTART,
"Trigger at start of IMU sampling" },
2239 { vn::protocol::uart::SyncOutMode::SYNCOUTMODE_IMUREADY,
"Trigger when IMU measurements are available" },
2240 { vn::protocol::uart::SyncOutMode::SYNCOUTMODE_INS,
"Trigger when attitude measurements are available" },
2241 { vn::protocol::uart::SyncOutMode::SYNCOUTMODE_GPSPPS,
"Trigger on a GPS PPS event (1 Hz) when a 3D fix is valid." } }
2243 if (ImGui::BeginCombo(fmt::format(
"SyncOut Mode##{}",
size_t(
id)).c_str(), vn::protocol::uart::str(
_synchronizationControlRegister.syncOutMode).c_str()))
2245 for (
const auto& synchronizationControlSyncOutMode : synchronizationControlSyncOutModes)
2248 if (ImGui::Selectable(vn::protocol::uart::str(synchronizationControlSyncOutMode.first).c_str(), isSelected))
2271 catch (
const std::exception& e)
2273 LOG_ERROR(
"{}: Could not configure the synchronizationControlRegister: {}",
nameId(), e.what());
2282 if (ImGui::IsItemHovered())
2284 ImGui::BeginTooltip();
2285 ImGui::TextUnformatted(synchronizationControlSyncOutMode.second);
2286 ImGui::EndTooltip();
2291 ImGui::SetItemDefaultFocus();
2297 gui::widgets::HelpMarker(
"The SyncOutMode register controls the behavior of the SyncOut pin. If this is set to IMU then the SyncOut "
2298 "will start the pulse when the internal IMU sample loop starts. This mode is used to make a sensor the Master "
2299 "in a multi-sensor network array. If this is set to IMU_READY mode then the pulse will start when IMU "
2300 "measurements become available. If this is set to INS mode then the pulse will start when attitude "
2301 "measurements are made available. Changes to this register take effect immediately.");
2303 static constexpr std::array<std::pair<vn::protocol::uart::SyncOutPolarity, const char*>, 2> synchronizationControlSyncOutPolarities = {
2304 { { vn::protocol::uart::SyncOutPolarity::SYNCOUTPOLARITY_NEGATIVE,
"Negative Pulse" },
2305 { vn::protocol::uart::SyncOutPolarity::SYNCOUTPOLARITY_POSITIVE,
"Positive Pulse" } }
2307 if (ImGui::BeginCombo(fmt::format(
"SyncOut Polarity##{}",
size_t(
id)).c_str(), vn::protocol::uart::str(
_synchronizationControlRegister.syncOutPolarity).c_str()))
2309 for (
const auto& synchronizationControlSyncOutPolarity : synchronizationControlSyncOutPolarities)
2312 if (ImGui::Selectable(vn::protocol::uart::str(synchronizationControlSyncOutPolarity.first).c_str(), isSelected))
2323 catch (
const std::exception& e)
2325 LOG_ERROR(
"{}: Could not configure the synchronizationControlRegister: {}",
nameId(), e.what());
2334 if (ImGui::IsItemHovered())
2336 ImGui::BeginTooltip();
2337 ImGui::TextUnformatted(synchronizationControlSyncOutPolarity.second);
2338 ImGui::EndTooltip();
2343 ImGui::SetItemDefaultFocus();
2349 gui::widgets::HelpMarker(
"The SyncOutPolarity register controls the polarity of the output pulse on the SyncOut pin.\n"
2350 "Changes to this register take effect immediately.");
2353 if (ImGui::InputInt(fmt::format(
"SyncOut Skip Factor##{}",
size_t(
id)).c_str(), &syncOutSkipFactor))
2355 if (syncOutSkipFactor < 0)
2357 syncOutSkipFactor = 0;
2359 else if (syncOutSkipFactor > std::numeric_limits<uint16_t>::max())
2361 syncOutSkipFactor = std::numeric_limits<uint16_t>::max();
2372 catch (
const std::exception& e)
2374 LOG_ERROR(
"{}: Could not configure the synchronizationControlRegister: {}",
nameId(), e.what());
2384 gui::widgets::HelpMarker(
"The SyncOutSkipFactor defines how many times the sync out event should be skipped before actually triggering the SyncOut pin.");
2387 if (ImGui::InputInt(fmt::format(
"SyncOut Pulse Width##{}",
size_t(
id)).c_str(), &syncOutPulseWidth))
2389 syncOutPulseWidth = std::max(syncOutPulseWidth, 0);
2399 catch (
const std::exception& e)
2401 LOG_ERROR(
"{}: Could not configure the synchronizationControlRegister: {}",
nameId(), e.what());
2412 "The default value is 100,000,000 (100 ms).");
2417 if (ImGui::TreeNode(fmt::format(
"Communication Protocol Control##{}",
size_t(
id)).c_str()))
2419 ImGui::TextUnformatted(
"Contains parameters that controls the communication protocol used by the sensor.");
2421 static constexpr std::array<std::pair<vn::protocol::uart::CountMode, const char*>, 5> communicationProtocolControlSerialCounts = {
2422 { { vn::protocol::uart::CountMode::COUNTMODE_NONE,
"OFF" },
2423 { vn::protocol::uart::CountMode::COUNTMODE_SYNCINCOUNT,
"SyncIn Counter" },
2424 { vn::protocol::uart::CountMode::COUNTMODE_SYNCINTIME,
"SyncIn Time" },
2425 { vn::protocol::uart::CountMode::COUNTMODE_SYNCOUTCOUNTER,
"SyncOut Counter" },
2426 { vn::protocol::uart::CountMode::COUNTMODE_GPSPPS,
"Gps Pps Time" } }
2430 for (
const auto& communicationProtocolControlSerialCount : communicationProtocolControlSerialCounts)
2433 if (ImGui::Selectable(vn::protocol::uart::str(communicationProtocolControlSerialCount.first).c_str(), isSelected))
2444 catch (
const std::exception& e)
2446 LOG_ERROR(
"{}: Could not configure the communicationProtocolControlRegister: {}",
nameId(), e.what());
2455 if (ImGui::IsItemHovered())
2457 ImGui::BeginTooltip();
2458 ImGui::TextUnformatted(communicationProtocolControlSerialCount.second);
2459 ImGui::EndTooltip();
2464 ImGui::SetItemDefaultFocus();
2470 gui::widgets::HelpMarker(
"The SerialCount field provides a means of appending a time or counter to the end of all asynchronous "
2471 "communication messages transmitted on the serial interface. The values for each of these counters come "
2472 "directly from the Synchronization Status Register in the System subsystem.\n\n"
2473 "With the SerialCount field set to OFF a typical serial asynchronous message would appear as the following:\n"
2474 "$VNYPR,+010.071,+000.278,-002.026*60\n\n"
2475 "With the SerialCount field set to one of the non-zero values the same asynchronous message would appear "
2477 "$VNYPR,+010.071,+000.278,-002.026,T1162704*2F\n\n"
2478 "When the SerialCount field is enabled the counter will always be appended to the end of the message just "
2479 "prior to the checksum. The counter will be preceded by the T character to distinguish it from the status field.");
2481 static constexpr std::array<std::pair<vn::protocol::uart::StatusMode, const char*>, 3> communicationProtocolControlSerialStatuses = {
2482 { { vn::protocol::uart::StatusMode::STATUSMODE_OFF,
"OFF" },
2483 { vn::protocol::uart::StatusMode::STATUSMODE_VPESTATUS,
"VPE Status" },
2484 { vn::protocol::uart::StatusMode::STATUSMODE_INSSTATUS,
"INS Status" } }
2488 for (
const auto& communicationProtocolControlSerialStatus : communicationProtocolControlSerialStatuses)
2491 if (ImGui::Selectable(vn::protocol::uart::str(communicationProtocolControlSerialStatus.first).c_str(), isSelected))
2502 catch (
const std::exception& e)
2504 LOG_ERROR(
"{}: Could not configure the communicationProtocolControlRegister: {}",
nameId(), e.what());
2513 if (ImGui::IsItemHovered())
2515 ImGui::BeginTooltip();
2516 ImGui::TextUnformatted(communicationProtocolControlSerialStatus.second);
2517 ImGui::EndTooltip();
2522 ImGui::SetItemDefaultFocus();
2528 gui::widgets::HelpMarker(
"The SerialStatus field provides a means of tracking real-time status information pertain to the overall state "
2529 "of the sensor measurements and onboard filtering algorithm. As with the SerialCount, a typical serial "
2530 "asynchronous message would appear as the following:\n"
2531 "$VNYPR,+010.071,+000.278,-002.026*60\n\n"
2532 "With the SerialStatus field set to one of the non-zero values, the same asynchronous message would appear "
2534 "$VNYPR,+010.071,+000.278,-002.026,S0000*1F\n\n"
2535 "When the SerialStatus field is enabled the status will always be appended to the end of the message just "
2536 "prior to the checksum. If both the SerialCount and SerialStatus are enabled then the SerialStatus will be "
2537 "displayed first. The counter will be preceded by the S character to distinguish it from the counter field. The "
2538 "status consists of 4 hexadecimal characters.");
2544 for (
const auto& communicationProtocolControlSpiCount : communicationProtocolControlSerialCounts)
2547 if (ImGui::Selectable(vn::protocol::uart::str(communicationProtocolControlSpiCount.first).c_str(), isSelected))
2558 catch (
const std::exception& e)
2560 LOG_ERROR(
"{}: Could not configure the communicationProtocolControlRegister: {}",
nameId(), e.what());
2569 if (ImGui::IsItemHovered())
2571 ImGui::BeginTooltip();
2572 ImGui::TextUnformatted(communicationProtocolControlSpiCount.second);
2573 ImGui::EndTooltip();
2578 ImGui::SetItemDefaultFocus();
2584 gui::widgets::HelpMarker(
"The SPICount field provides a means of appending a time or counter to the end of all SPI packets. The "
2585 "values for each of these counters come directly from the Synchronization Status Register.");
2592 for (
const auto& communicationProtocolControlSpiStatus : communicationProtocolControlSerialStatuses)
2595 if (ImGui::Selectable(vn::protocol::uart::str(communicationProtocolControlSpiStatus.first).c_str(), isSelected))
2606 catch (
const std::exception& e)
2608 LOG_ERROR(
"{}: Could not configure the communicationProtocolControlRegister: {}",
nameId(), e.what());
2617 if (ImGui::IsItemHovered())
2619 ImGui::BeginTooltip();
2620 ImGui::TextUnformatted(communicationProtocolControlSpiStatus.second);
2621 ImGui::EndTooltip();
2626 ImGui::SetItemDefaultFocus();
2632 gui::widgets::HelpMarker(
"The AsyncStatus field provides a means of tracking real-time status information pertaining to the overall "
2633 "state of the sensor measurements and onboard filtering algorithm. This information is very useful in "
2634 "situations where action must be taken when certain crucial events happen such as the detection of gyro "
2635 "saturation or magnetic interference.");
2638 static constexpr std::array<std::pair<vn::protocol::uart::ChecksumMode, const char*>, 2> communicationProtocolControlSerialChecksums = {
2639 { { vn::protocol::uart::ChecksumMode::CHECKSUMMODE_CHECKSUM,
"8-Bit Checksum" },
2640 { vn::protocol::uart::ChecksumMode::CHECKSUMMODE_CRC,
"16-Bit CRC" } }
2644 for (
const auto& communicationProtocolControlSerialChecksum : communicationProtocolControlSerialChecksums)
2647 if (ImGui::Selectable(vn::protocol::uart::str(communicationProtocolControlSerialChecksum.first).c_str(), isSelected))
2658 catch (
const std::exception& e)
2660 LOG_ERROR(
"{}: Could not configure the communicationProtocolControlRegister: {}",
nameId(), e.what());
2669 if (ImGui::IsItemHovered())
2671 ImGui::BeginTooltip();
2672 ImGui::TextUnformatted(communicationProtocolControlSerialChecksum.second);
2673 ImGui::EndTooltip();
2678 ImGui::SetItemDefaultFocus();
2684 gui::widgets::HelpMarker(
"This field controls the type of checksum used for the serial communications. Normally the VN-310E uses an "
2685 "8-bit checksum identical to the type used for normal GPS NMEA packets. This form of checksum however "
2686 "offers only a limited means of error checking. As an alternative a full 16-bit CRC (CRC16-CCITT with "
2687 "polynomial = 0x07) is also offered. The 2-byte CRC value is printed using 4 hexadecimal digits.");
2691 static constexpr std::array<std::pair<vn::protocol::uart::ChecksumMode, const char*>, 3> communicationProtocolControlSpiChecksums = {
2692 { { vn::protocol::uart::ChecksumMode::CHECKSUMMODE_OFF,
"OFF" },
2693 { vn::protocol::uart::ChecksumMode::CHECKSUMMODE_CHECKSUM,
"8-Bit Checksum" },
2694 { vn::protocol::uart::ChecksumMode::CHECKSUMMODE_CRC,
"16-Bit CRC" } }
2698 for (
const auto& communicationProtocolControlSpiChecksum : communicationProtocolControlSpiChecksums)
2701 if (ImGui::Selectable(vn::protocol::uart::str(communicationProtocolControlSpiChecksum.first).c_str(), isSelected))
2712 catch (
const std::exception& e)
2714 LOG_ERROR(
"{}: Could not configure the communicationProtocolControlRegister: {}",
nameId(), e.what());
2723 if (ImGui::IsItemHovered())
2725 ImGui::BeginTooltip();
2726 ImGui::TextUnformatted(communicationProtocolControlSpiChecksum.second);
2727 ImGui::EndTooltip();
2732 ImGui::SetItemDefaultFocus();
2738 gui::widgets::HelpMarker(
"This field controls the type of checksum used for the SPI communications. The checksum is appended to "
2739 "the end of the binary data packet. The 16-bit CRC is identical to the one described above for the "
2743 static constexpr std::array<std::pair<vn::protocol::uart::ErrorMode, const char*>, 3> communicationProtocolControlErrorModes = {
2744 { { vn::protocol::uart::ErrorMode::ERRORMODE_IGNORE,
"Ignore Error" },
2745 { vn::protocol::uart::ErrorMode::ERRORMODE_SEND,
"Send Error" },
2746 { vn::protocol::uart::ErrorMode::ERRORMODE_SENDANDOFF,
"Send Error and set ADOR register to OFF" } }
2750 for (
const auto& communicationProtocolControlErrorMode : communicationProtocolControlErrorModes)
2753 if (ImGui::Selectable(vn::protocol::uart::str(communicationProtocolControlErrorMode.first).c_str(), isSelected))
2764 catch (
const std::exception& e)
2766 LOG_ERROR(
"{}: Could not configure the communicationProtocolControlRegister: {}",
nameId(), e.what());
2775 if (ImGui::IsItemHovered())
2777 ImGui::BeginTooltip();
2778 ImGui::TextUnformatted(communicationProtocolControlErrorMode.second);
2779 ImGui::EndTooltip();
2784 ImGui::SetItemDefaultFocus();
2790 gui::widgets::HelpMarker(
"This field controls the type of action taken by the VectorNav when an error event occurs. If the send error "
2791 "mode is enabled then a message similar to the one shown below will be sent on the serial bus when an error "
2794 "Regardless of the state of the ErrorMode, the number of error events is always recorded and is made available "
2795 "in the SysErrors field of the Communication Protocol Status Register in the System subsystem.");
2797 if (ImGui::TreeNode(fmt::format(
"Example Async Messages##{}",
size_t(
id)).c_str()))
2799 ImGui::TextUnformatted(
"The following table shows example asynchronous messages with the\nAsyncCount and the AsyncStatus values appended to the end.");
2801 if (ImGui::BeginTable(
"Example Async Messages Table", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F)))
2803 ImGui::TableSetupColumn(
"Example Type");
2804 ImGui::TableSetupColumn(
"Message");
2805 ImGui::TableHeadersRow();
2807 ImGui::TableNextColumn();
2808 ImGui::TextUnformatted(
"Async Message with\nAsyncCount Enabled");
2809 ImGui::TableNextColumn();
2810 ImGui::TextUnformatted(
"$VNYPR,+010.071,+000.278,-002.026,T1162704*2F");
2812 ImGui::TableNextColumn();
2813 ImGui::TextUnformatted(
"Async Message with\nAsyncStatus Enabled");
2814 ImGui::TableNextColumn();
2815 ImGui::TextUnformatted(
"$VNYPR,+010.071,+000.278,-002.026,S0000*1F");
2817 ImGui::TableNextColumn();
2818 ImGui::TextUnformatted(
"Async Message with\nAsyncCount and\nAsyncStatus Enabled");
2819 ImGui::TableNextColumn();
2820 ImGui::TextUnformatted(
"$VNYPR,+010.071,+000.278,-002.026,T1162704,S0000*50");
2833 if (ImGui::TreeNode(fmt::format(
"Binary Output {}##{}", b + 1,
size_t(
id)).c_str()))
2835 static constexpr std::array<std::pair<vn::protocol::uart::AsyncMode, const char*>, 4> asyncModes = {
2836 { { vn::protocol::uart::AsyncMode::ASYNCMODE_NONE,
" User message is not automatically sent out either serial port" },
2837 { vn::protocol::uart::AsyncMode::ASYNCMODE_PORT1,
"Message is sent out serial port 1 at a fixed rate" },
2838 { vn::protocol::uart::AsyncMode::ASYNCMODE_PORT2,
"Message is sent out serial port 2 at a fixed rate" },
2839 { vn::protocol::uart::AsyncMode::ASYNCMODE_BOTH,
"Message is sent out both serial ports at a fixed rate" } }
2845 ImGui::BeginDisabled();
2848 if (ImGui::BeginCombo(fmt::format(
"Async Mode##{}",
size_t(
id)).c_str(), vn::protocol::uart::str(
_binaryOutputRegister.at(b).asyncMode).c_str()))
2850 for (
const auto& asyncMode : asyncModes)
2853 if (ImGui::Selectable(vn::protocol::uart::str(asyncMode.first).c_str(), isSelected))
2858 std::vector<size_t> binaryOutputRegistersToUpdate;
2859 binaryOutputRegistersToUpdate.push_back(b);
2864 binaryOutputRegistersToUpdate.push_back(1);
2871 binaryOutputRegistersToUpdate.push_back(2);
2877 for (
const auto& binUpdate : binaryOutputRegistersToUpdate)
2896 catch (
const std::exception& e)
2898 LOG_ERROR(
"{}: Could not configure the binaryOutputRegister {}: {}",
nameId(), binUpdate + 1, e.what());
2908 if (ImGui::IsItemHovered())
2910 ImGui::BeginTooltip();
2911 ImGui::TextUnformatted(asyncMode.second);
2912 ImGui::EndTooltip();
2917 ImGui::SetItemDefaultFocus();
2924 "out on the serial port(s) at a fixed rate.");
2930 ImGui::SliderInt(fmt::format(
"Frequency##{} {}",
size_t(
id), b).c_str(),
2940 if (
_binaryOutputRegister.at(b).imuField & (vn::protocol::uart::IMUGROUP_ACCEL | vn::protocol::uart::IMUGROUP_UNCOMPACCEL))
2944 if (
_binaryOutputRegister.at(b).imuField & (vn::protocol::uart::IMUGROUP_ANGULARRATE | vn::protocol::uart::IMUGROUP_UNCOMPGYRO))
2948 if (
_binaryOutputRegister.at(b).imuField & (vn::protocol::uart::IMUGROUP_MAG | vn::protocol::uart::IMUGROUP_UNCOMPMAG))
2952 if (
_binaryOutputRegister.at(b).imuField & (vn::protocol::uart::IMUGROUP_MAG | vn::protocol::uart::IMUGROUP_UNCOMPMAG))
2964 LOG_DATA(
"{}: Frequency of ImuFilter matches output frequency (coupled 'rateDivisor' and 'windowSize' of moving average filter.)",
nameId());
2972 catch (
const std::exception& e)
2974 LOG_ERROR(
"{}: Could not configure the imuFilteringConfigurationRegister: {}",
nameId(), e.what());
2984 std::vector<size_t> binaryOutputRegistersToUpdate;
2985 binaryOutputRegistersToUpdate.push_back(b);
2991 binaryOutputRegistersToUpdate.push_back(1);
2999 binaryOutputRegistersToUpdate.push_back(2);
3005 for (
const auto& binUpdate : binaryOutputRegistersToUpdate)
3024 catch (
const std::exception& e)
3026 LOG_ERROR(
"{}: Could not configure the binaryOutputRegister {}: {}",
nameId(), binUpdate + 1, e.what());
3040 ImGui::EndDisabled();
3043 if (ImGui::BeginTable(fmt::format(
"##VectorNavSensorConfig ({})",
size_t(
id)).c_str(), 6,
3044 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
3047 ImGui::TableSetupColumn(
"Time", ImGuiTableColumnFlags_WidthFixed);
3048 ImGui::TableSetupColumn(
"IMU", ImGuiTableColumnFlags_WidthFixed);
3049 ImGui::TableSetupColumn(
"GNSS1", ImGuiTableColumnFlags_WidthFixed);
3050 ImGui::TableSetupColumn(
"Attitude", ImGuiTableColumnFlags_WidthFixed);
3051 ImGui::TableSetupColumn(
"INS", ImGuiTableColumnFlags_WidthFixed);
3052 ImGui::TableSetupColumn(
"GNSS2", ImGuiTableColumnFlags_WidthFixed);
3053 ImGui::TableHeadersRow();
3055 auto CheckboxFlags = [&,
this](
int index,
const char* label,
int* flags,
int flags_value,
bool enabled, void (*toggleFields)(
VectorNavSensor*, vn::sensors::BinaryOutputRegister&, uint32_t&)) {
3056 ImGui::TableSetColumnIndex(index);
3060 ImGui::BeginDisabled();
3063 if (ImGui::CheckboxFlags(label, flags, flags_value))
3065 LOG_DEBUG(
"{}: Field '{}' of Binary Group {} is now {}",
nameId(), std::string(label).substr(0, std::string(label).find(
'#')), b + 1, (*flags & flags_value) ?
"checked" :
"unchecked");
3088 for (
auto& link :
outputPins.at(b + 2).links)
3090 if (
auto* connectedPin = link.getConnectedPin())
3092 outputPins.at(b + 2).recreateLink(*connectedPin);
3096 catch (
const std::exception& e)
3098 LOG_ERROR(
"{}: Could not configure the binaryOutputRegister {}: {}",
nameId(), b + 1, e.what());
3110 ImGui::EndDisabled();
3114 for (
size_t i = 0; i < 16; i++)
3119 ImGui::TableNextRow();
3139 CheckboxFlags(0, fmt::format(
"{}##Time {} {}", binaryGroupItem.name,
size_t(
id), b).c_str(),
3141 binaryGroupItem.flagsValue,
3143 binaryGroupItem.toggleFields);
3144 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && binaryGroupItem.tooltip !=
nullptr)
3146 ImGui::BeginTooltip();
3147 binaryGroupItem.tooltip();
3148 ImGui::EndTooltip();
3154 CheckboxFlags(1, fmt::format(
"{}##IMU {} {}", binaryGroupItem.name,
size_t(
id), b).c_str(),
3156 binaryGroupItem.flagsValue,
3158 binaryGroupItem.toggleFields);
3159 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && binaryGroupItem.tooltip !=
nullptr)
3161 ImGui::BeginTooltip();
3162 binaryGroupItem.tooltip();
3163 ImGui::EndTooltip();
3169 CheckboxFlags(2, fmt::format(
"{}##GNSS1 {} {}", binaryGroupItem.name,
size_t(
id), b).c_str(),
3171 binaryGroupItem.flagsValue,
3173 binaryGroupItem.toggleFields);
3174 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && binaryGroupItem.tooltip !=
nullptr)
3176 ImGui::BeginTooltip();
3177 binaryGroupItem.tooltip();
3178 ImGui::EndTooltip();
3184 CheckboxFlags(3, fmt::format(
"{}##Attitude {} {}", binaryGroupItem.name,
size_t(
id), b).c_str(),
3186 binaryGroupItem.flagsValue,
3188 binaryGroupItem.toggleFields);
3189 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && binaryGroupItem.tooltip !=
nullptr)
3191 ImGui::BeginTooltip();
3192 binaryGroupItem.tooltip();
3193 ImGui::EndTooltip();
3199 CheckboxFlags(4, fmt::format(
"{}##INS {} {}", binaryGroupItem.name,
size_t(
id), b).c_str(),
3201 binaryGroupItem.flagsValue,
3203 binaryGroupItem.toggleFields);
3204 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && binaryGroupItem.tooltip !=
nullptr)
3206 ImGui::BeginTooltip();
3207 binaryGroupItem.tooltip();
3208 ImGui::EndTooltip();
3214 CheckboxFlags(5, fmt::format(
"{}##GNSS2 {} {}", binaryGroupItem.name,
size_t(
id), b).c_str(),
3216 binaryGroupItem.flagsValue,
3218 binaryGroupItem.toggleFields);
3219 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && binaryGroupItem.tooltip !=
nullptr)
3221 ImGui::BeginTooltip();
3222 binaryGroupItem.tooltip();
3223 ImGui::EndTooltip();
3236 ImGui::Combo(fmt::format(
"Merge Binary outputs").c_str(), &binaryOutputRegisterMerge,
"None\0"
3277 NAV::gui::widgets::HelpMarker(
"VectorNav sensors have a buffer overflow if packages get too big (SatInfo/RawMeas selected and a lot of satellites). "
3278 "A workaround is, to split the data into different Binary Outputs. "
3279 "This option merges the outputs into a single observation.");
3288 ImGui::SetNextItemOpen(
true, ImGuiCond_FirstUseEver);
3289 if (ImGui::CollapsingHeader(fmt::format(
"IMU Subsystem##{}",
size_t(
id)).c_str()))
3291 if (ImGui::TreeNode(fmt::format(
"Reference Frame Rotation##{}",
size_t(
id)).c_str()))
3293 ImGui::TextUnformatted(
"Allows the measurements of the VN-310E to be rotated into a different reference frame.");
3295 gui::widgets::HelpMarker(
"This register contains a transformation matrix that allows for the transformation of measured acceleration, "
3296 "magnetic, and angular rates from the body frame of the VN-310E to any other arbitrary frame of reference. "
3297 "The use of this register allows for the sensor to be placed in any arbitrary orientation with respect to the "
3298 "user's desired body coordinate frame. This register can also be used to correct for any orientation errors due "
3299 "to mounting the VN-310E on the user's vehicle or platform.\n\n"
3300 "(X Y Z)_U = C * (X Y Z)_B\n\n"
3301 "The variables (X Y Z)_B are a measured parameter such as acceleration in the body reference frame with "
3302 "respect to the VectorNav. The variables (X Y Z)_U are a measured parameter such as acceleration in the user's "
3303 "frame of reference. The reference frame rotation register Thus needs to be loaded with the transformation "
3304 "matrix that will transform measurements from the body reference frame of the VectorNav to the desired user "
3305 "frame of reference.");
3309 gui::widgets::HelpMarker(
"The reference frame rotation is performed on all vector measurements prior to entering the INS "
3310 "filter. As such, changing this register while the attitude filter is running will lead to unexpected "
3311 "behavior in the INS output. To prevent this, the register is cached on startup and changes will "
3312 "not take effect during runtime. After setting the reference frame rotation register to its new value, "
3313 "send a write settings command and then reset the VN-310E. This will allow the INS filter to "
3314 "startup with the newly set reference frame rotation.",
3318 gui::widgets::HelpMarker(
"The matrix C in the Reference Frame Rotation Register must be an orthonormal, right-handed"
3319 " matrix. The sensor will output an error if the tolerance is not within 1e-5. The sensor will also"
3320 " report an error if any of the parameters are greater than 1 or less than -1.",
3323 ImGui::TextUnformatted(
"Rotation Angles [deg]");
3328 Eigen::Matrix3d dcm;
3332 auto b_Quat_p = Eigen::Quaterniond(dcm);
3335 std::array<float, 3> imuRot = {
static_cast<float>(eulerRot.x()),
static_cast<float>(eulerRot.y()),
static_cast<float>(eulerRot.z()) };
3336 if (ImGui::InputFloat3(fmt::format(
"##rotationAngles{}",
size_t(
id)).c_str(), imuRot.data()))
3339 imuRot.at(0) = std::max(imuRot.at(0), -179.9999F);
3340 imuRot.at(0) = std::min(imuRot.at(0), 180.0F);
3341 imuRot.at(1) = std::max(imuRot.at(1), -89.9999F);
3342 imuRot.at(1) = std::min(imuRot.at(1), 90.0F);
3343 imuRot.at(2) = std::max(imuRot.at(2), -179.9999F);
3344 imuRot.at(2) = std::min(imuRot.at(2), 180.0F);
3348 dcmf(1, 0), dcmf(1, 1), dcmf(1, 2),
3349 dcmf(2, 0), dcmf(2, 1), dcmf(2, 2));
3358 catch (
const std::exception& e)
3360 LOG_ERROR(
"{}: Could not configure the referenceFrameRotationMatrix: {}",
nameId(), e.what());
3371 ImGui::TextUnformatted(
"Rotation Matrix C");
3375 if (ImGui::InputFloat3(fmt::format(
"##referenceFrameRotationMatrix row 0 {}",
size_t(
id)).c_str(), row.data(),
"%.2f"))
3388 catch (
const std::exception& e)
3390 LOG_ERROR(
"{}: Could not configure the referenceFrameRotationMatrix: {}",
nameId(), e.what());
3400 if (ImGui::InputFloat3(fmt::format(
"##referenceFrameRotationMatrix row 1 {}",
size_t(
id)).c_str(), row.data(),
"%.2f"))
3413 catch (
const std::exception& e)
3415 LOG_ERROR(
"{}: Could not configure the referenceFrameRotationMatrix: {}",
nameId(), e.what());
3425 if (ImGui::InputFloat3(fmt::format(
"##referenceFrameRotationMatrix row 2 {}",
size_t(
id)).c_str(), row.data(),
"%.2f"))
3438 catch (
const std::exception& e)
3440 LOG_ERROR(
"{}: Could not configure the referenceFrameRotationMatrix: {}",
nameId(), e.what());
3454 if (ImGui::TreeNode(fmt::format(
"IMU Filtering Configuration##{}",
size_t(
id)).c_str()))
3456 ImGui::TextUnformatted(
"This register allows the user to configure the FIR filtering which is applied to the IMU measurements.\n"
3457 "The filter is a uniformly-weighted moving window (boxcar) filter, also known as a 'moving-average' filter.\n"
3458 "Its window size can be adjusted with respect to the internal IMU frequency (800 Hz).");
3460 if (ImGui::Checkbox(fmt::format(
"Couple the Imu-Filter's rate to the output rate##{}",
size_t(
id)).c_str(), &
_coupleImuRateOutput))
3467 "divisor, some samples are lost. This results in a low output rate that still contains "
3468 "noise due to high frequencies. Therefore, it is recommended to couple the ImuFilter's "
3469 "rate to the output rate.");
3474 ImGui::BeginDisabled();
3476 if (ImGui::InputInt(fmt::format(
"Mag Window Size##{}",
size_t(
id)).c_str(), &magWindowSize))
3478 if (magWindowSize < 0)
3482 else if (magWindowSize > std::numeric_limits<uint16_t>::max())
3484 magWindowSize = std::numeric_limits<uint16_t>::max();
3495 catch (
const std::exception& e)
3497 LOG_ERROR(
"{}: Could not configure the imuFilteringConfigurationRegister: {}",
nameId(), e.what());
3507 gui::widgets::HelpMarker(
"The WindowSize parameters for each sensor define the number of samples at the IMU rate (default 800Hz) "
3508 "which will be averaged for each output measurement.");
3511 if (ImGui::InputInt(fmt::format(
"Accel Window Size##{}",
size_t(
id)).c_str(), &accelWindowSize))
3513 if (accelWindowSize < 0)
3515 accelWindowSize = 0;
3517 else if (accelWindowSize > std::numeric_limits<uint16_t>::max())
3519 accelWindowSize = std::numeric_limits<uint16_t>::max();
3530 catch (
const std::exception& e)
3532 LOG_ERROR(
"{}: Could not configure the imuFilteringConfigurationRegister: {}",
nameId(), e.what());
3542 gui::widgets::HelpMarker(
"The WindowSize parameters for each sensor define the number of samples at the IMU rate (default 800Hz) "
3543 "which will be averaged for each output measurement.");
3546 if (ImGui::InputInt(fmt::format(
"Gyro Window Size##{}",
size_t(
id)).c_str(), &gyroWindowSize))
3548 if (gyroWindowSize < 0)
3552 else if (gyroWindowSize > std::numeric_limits<uint16_t>::max())
3554 gyroWindowSize = std::numeric_limits<uint16_t>::max();
3565 catch (
const std::exception& e)
3567 LOG_ERROR(
"{}: Could not configure the imuFilteringConfigurationRegister: {}",
nameId(), e.what());
3577 gui::widgets::HelpMarker(
"The WindowSize parameters for each sensor define the number of samples at the IMU rate (default 800Hz) "
3578 "which will be averaged for each output measurement.");
3581 if (ImGui::InputInt(fmt::format(
"Temp Window Size##{}",
size_t(
id)).c_str(), &tempWindowSize))
3583 if (tempWindowSize < 0)
3587 else if (tempWindowSize > std::numeric_limits<uint16_t>::max())
3589 tempWindowSize = std::numeric_limits<uint16_t>::max();
3600 catch (
const std::exception& e)
3602 LOG_ERROR(
"{}: Could not configure the imuFilteringConfigurationRegister: {}",
nameId(), e.what());
3612 gui::widgets::HelpMarker(
"The WindowSize parameters for each sensor define the number of samples at the IMU rate (default 800Hz) "
3613 "which will be averaged for each output measurement.");
3616 if (ImGui::InputInt(fmt::format(
"Pres Window Size##{}",
size_t(
id)).c_str(), &presWindowSize))
3618 if (presWindowSize < 0)
3622 else if (presWindowSize > std::numeric_limits<uint16_t>::max())
3624 presWindowSize = std::numeric_limits<uint16_t>::max();
3635 catch (
const std::exception& e)
3637 LOG_ERROR(
"{}: Could not configure the imuFilteringConfigurationRegister: {}",
nameId(), e.what());
3647 gui::widgets::HelpMarker(
"The WindowSize parameters for each sensor define the number of samples at the IMU rate (default 800Hz) "
3648 "which will be averaged for each output measurement.");
3651 ImGui::EndDisabled();
3654 static constexpr std::array<std::pair<vn::protocol::uart::FilterMode, const char*>, 4> imuFilteringConfigurationFilterModes = {
3655 { { vn::protocol::uart::FilterMode::FILTERMODE_NOFILTERING,
"No Filtering" },
3656 { vn::protocol::uart::FilterMode::FILTERMODE_ONLYRAW,
"Filtering performed only on raw uncompensated IMU measurements." },
3657 { vn::protocol::uart::FilterMode::FILTERMODE_ONLYCOMPENSATED,
"Filtering performed only on compensated IMU measurements." },
3658 { vn::protocol::uart::FilterMode::FILTERMODE_BOTH,
"Filtering performed on both uncompensated and compensated IMU measurements." } }
3662 for (
const auto& imuFilteringConfigurationFilterMode : imuFilteringConfigurationFilterModes)
3665 if (ImGui::Selectable(vn::protocol::uart::str(imuFilteringConfigurationFilterMode.first).c_str(), isSelected))
3676 catch (
const std::exception& e)
3678 LOG_ERROR(
"{}: Could not configure the imuFilteringConfigurationRegister: {}",
nameId(), e.what());
3687 if (ImGui::IsItemHovered())
3689 ImGui::BeginTooltip();
3690 ImGui::TextUnformatted(imuFilteringConfigurationFilterMode.second);
3691 ImGui::EndTooltip();
3696 ImGui::SetItemDefaultFocus();
3702 gui::widgets::HelpMarker(
"The FilterMode parameters for each sensor select which output quantities the filtering should be applied to. "
3703 "Filtering can be applied to either the uncompensated IMU measurements, compensated (HSI and biases "
3704 "compensated by onboard filters, if applicable), or both.");
3706 if (ImGui::BeginCombo(fmt::format(
"Accel Filter Mode##{}",
size_t(
id)).c_str(), vn::protocol::uart::str(
_imuFilteringConfigurationRegister.accelFilterMode).c_str()))
3708 for (
const auto& imuFilteringConfigurationFilterMode : imuFilteringConfigurationFilterModes)
3711 if (ImGui::Selectable(vn::protocol::uart::str(imuFilteringConfigurationFilterMode.first).c_str(), isSelected))
3722 catch (
const std::exception& e)
3724 LOG_ERROR(
"{}: Could not configure the imuFilteringConfigurationRegister: {}",
nameId(), e.what());
3733 if (ImGui::IsItemHovered())
3735 ImGui::BeginTooltip();
3736 ImGui::TextUnformatted(imuFilteringConfigurationFilterMode.second);
3737 ImGui::EndTooltip();
3742 ImGui::SetItemDefaultFocus();
3748 gui::widgets::HelpMarker(
"The FilterMode parameters for each sensor select which output quantities the filtering should be applied to. "
3749 "Filtering can be applied to either the uncompensated IMU measurements, compensated (HSI and biases "
3750 "compensated by onboard filters, if applicable), or both.");
3754 for (
const auto& imuFilteringConfigurationFilterMode : imuFilteringConfigurationFilterModes)
3757 if (ImGui::Selectable(vn::protocol::uart::str(imuFilteringConfigurationFilterMode.first).c_str(), isSelected))
3768 catch (
const std::exception& e)
3770 LOG_ERROR(
"{}: Could not configure the imuFilteringConfigurationRegister: {}",
nameId(), e.what());
3779 if (ImGui::IsItemHovered())
3781 ImGui::BeginTooltip();
3782 ImGui::TextUnformatted(imuFilteringConfigurationFilterMode.second);
3783 ImGui::EndTooltip();
3788 ImGui::SetItemDefaultFocus();
3794 gui::widgets::HelpMarker(
"The FilterMode parameters for each sensor select which output quantities the filtering should be applied to. "
3795 "Filtering can be applied to either the uncompensated IMU measurements, compensated (HSI and biases "
3796 "compensated by onboard filters, if applicable), or both.");
3800 for (
const auto& imuFilteringConfigurationFilterMode : imuFilteringConfigurationFilterModes)
3803 if (ImGui::Selectable(vn::protocol::uart::str(imuFilteringConfigurationFilterMode.first).c_str(), isSelected))
3814 catch (
const std::exception& e)
3816 LOG_ERROR(
"{}: Could not configure the imuFilteringConfigurationRegister: {}",
nameId(), e.what());
3825 if (ImGui::IsItemHovered())
3827 ImGui::BeginTooltip();
3828 ImGui::TextUnformatted(imuFilteringConfigurationFilterMode.second);
3829 ImGui::EndTooltip();
3834 ImGui::SetItemDefaultFocus();
3840 gui::widgets::HelpMarker(
"The FilterMode parameters for each sensor select which output quantities the filtering should be applied to. "
3841 "Filtering can be applied to either the uncompensated IMU measurements, compensated (HSI and biases "
3842 "compensated by onboard filters, if applicable), or both.");
3846 for (
const auto& imuFilteringConfigurationFilterMode : imuFilteringConfigurationFilterModes)
3849 if (ImGui::Selectable(vn::protocol::uart::str(imuFilteringConfigurationFilterMode.first).c_str(), isSelected))
3860 catch (
const std::exception& e)
3862 LOG_ERROR(
"{}: Could not configure the imuFilteringConfigurationRegister: {}",
nameId(), e.what());
3871 if (ImGui::IsItemHovered())
3873 ImGui::BeginTooltip();
3874 ImGui::TextUnformatted(imuFilteringConfigurationFilterMode.second);
3875 ImGui::EndTooltip();
3880 ImGui::SetItemDefaultFocus();
3886 gui::widgets::HelpMarker(
"The FilterMode parameters for each sensor select which output quantities the filtering should be applied to. "
3887 "Filtering can be applied to either the uncompensated IMU measurements, compensated (HSI and biases "
3888 "compensated by onboard filters, if applicable), or both.");
3893 if (ImGui::TreeNode(fmt::format(
"Delta Theta and Delta Velocity Configuration##{}",
size_t(
id)).c_str()))
3895 ImGui::TextUnformatted(
"The Delta Theta and Delta Velocity Configuration register allows configuration of the onboard coning and\n"
3896 "sculling used to generate integrated motion values from the angular rate and acceleration IMU quantities.\n"
3897 "The fully-coupled coning and sculling integrals are computed at the IMU sample rate (nominal 400 Hz).");
3899 static constexpr std::array<std::pair<vn::protocol::uart::IntegrationFrame, const char*>, 2> deltaThetaAndDeltaVelocityConfigurationIntegrationFrames = {
3900 { { vn::protocol::uart::IntegrationFrame::INTEGRATIONFRAME_BODY,
"Body frame" },
3901 { vn::protocol::uart::IntegrationFrame::INTEGRATIONFRAME_NED,
"NED frame" } }
3905 for (
const auto& deltaThetaAndDeltaVelocityConfigurationIntegrationFrame : deltaThetaAndDeltaVelocityConfigurationIntegrationFrames)
3908 if (ImGui::Selectable(vn::protocol::uart::str(deltaThetaAndDeltaVelocityConfigurationIntegrationFrame.first).c_str(), isSelected))
3919 catch (
const std::exception& e)
3921 LOG_ERROR(
"{}: Could not configure the deltaThetaAndDeltaVelocityConfigurationRegister: {}",
nameId(), e.what());
3930 if (ImGui::IsItemHovered())
3932 ImGui::BeginTooltip();
3933 ImGui::TextUnformatted(deltaThetaAndDeltaVelocityConfigurationIntegrationFrame.second);
3934 ImGui::EndTooltip();
3939 ImGui::SetItemDefaultFocus();
3945 gui::widgets::HelpMarker(
"The IntegrationFrame register setting selects the reference frame used for coning and sculling. Note that "
3946 "using any frame other than the body frame will rely on the onboard Kalman filter's attitude estimate. The "
3947 "factory default state is to integrate in the sensor body frame.");
3949 static constexpr std::array<std::pair<vn::protocol::uart::CompensationMode, const char*>, 2> deltaThetaAndDeltaVelocityConfigurationGyroCompensationModes = {
3950 { { vn::protocol::uart::CompensationMode::COMPENSATIONMODE_NONE,
"None" },
3951 { vn::protocol::uart::CompensationMode::COMPENSATIONMODE_BIAS,
"Bias" } }
3955 for (
const auto& deltaThetaAndDeltaVelocityConfigurationGyroCompensationMode : deltaThetaAndDeltaVelocityConfigurationGyroCompensationModes)
3958 if (ImGui::Selectable(vn::protocol::uart::str(deltaThetaAndDeltaVelocityConfigurationGyroCompensationMode.first).c_str(), isSelected))
3969 catch (
const std::exception& e)
3971 LOG_ERROR(
"{}: Could not configure the deltaThetaAndDeltaVelocityConfigurationRegister: {}",
nameId(), e.what());
3980 if (ImGui::IsItemHovered())
3982 ImGui::BeginTooltip();
3983 ImGui::TextUnformatted(deltaThetaAndDeltaVelocityConfigurationGyroCompensationMode.second);
3984 ImGui::EndTooltip();
3989 ImGui::SetItemDefaultFocus();
3995 gui::widgets::HelpMarker(
"The GyroCompensation register setting selects the compensation to be applied to the angular rate "
3996 "measurements before integration. If bias compensation is selected, the onboard Kalman filter’s real-time "
3997 "estimate of the gyro biases will be used to compensate the IMU measurements before integration. The "
3998 "factory default state is to integrate the uncompensated angular rates from the IMU.");
4000 static constexpr std::array<std::pair<vn::protocol::uart::AccCompensationMode, const char*>, 2> deltaThetaAndDeltaVelocityConfigurationAccelCompensationModes = {
4001 { { vn::protocol::uart::AccCompensationMode::ACCCOMPENSATIONMODE_NONE,
"None" },
4002 { vn::protocol::uart::AccCompensationMode::ACCCOMPENSATIONMODE_BIAS,
"Bias" } }
4006 for (
const auto& deltaThetaAndDeltaVelocityConfigurationAccelCompensationMode : deltaThetaAndDeltaVelocityConfigurationAccelCompensationModes)
4009 if (ImGui::Selectable(vn::protocol::uart::str(deltaThetaAndDeltaVelocityConfigurationAccelCompensationMode.first).c_str(), isSelected))
4020 catch (
const std::exception& e)
4022 LOG_ERROR(
"{}: Could not configure the deltaThetaAndDeltaVelocityConfigurationRegister: {}",
nameId(), e.what());
4031 if (ImGui::IsItemHovered())
4033 ImGui::BeginTooltip();
4034 ImGui::TextUnformatted(deltaThetaAndDeltaVelocityConfigurationAccelCompensationMode.second);
4035 ImGui::EndTooltip();
4040 ImGui::SetItemDefaultFocus();
4046 gui::widgets::HelpMarker(
"The AccelCompensation register setting selects the compensation to be applied to the acceleration "
4047 "measurements before integration. If bias compensation is selected, the onboard Kalman filter’s real-time "
4048 "estimate of the accel biases will be used to compensate the IMU measurements before integration. The "
4049 "factory default state is to integrate the uncompensated acceleration from the IMU.");
4061 ImGui::SetNextItemOpen(
true, ImGuiCond_FirstUseEver);
4062 if (ImGui::CollapsingHeader(fmt::format(
"GNSS Subsystem##{}",
size_t(
id)).c_str()))
4064 if (ImGui::TreeNode(fmt::format(
"GNSS Configuration##{}",
size_t(
id)).c_str()))
4066 static constexpr std::array<std::pair<vn::protocol::uart::GpsMode, const char*>, 3> gpsConfigurationModes = {
4067 { { vn::protocol::uart::GpsMode::GPSMODE_ONBOARDGPS,
"Use onboard GNSS" },
4068 { vn::protocol::uart::GpsMode::GPSMODE_EXTERNALGPS,
"Use external GNSS" },
4069 { vn::protocol::uart::GpsMode::GPSMODE_EXTERNALVN200GPS,
"Use external VectorNav sensor as the GNSS" } }
4071 if (ImGui::BeginCombo(fmt::format(
"Mode##{}",
size_t(
id)).c_str(), vn::protocol::uart::str(
_gpsConfigurationRegister.mode).c_str()))
4073 for (
const auto& gpsConfigurationMode : gpsConfigurationModes)
4076 if (ImGui::Selectable(vn::protocol::uart::str(gpsConfigurationMode.first).c_str(), isSelected))
4087 catch (
const std::exception& e)
4089 LOG_ERROR(
"{}: Could not configure the gpsConfigurationRegister: {}",
nameId(), e.what());
4098 if (ImGui::IsItemHovered())
4100 ImGui::BeginTooltip();
4101 ImGui::TextUnformatted(gpsConfigurationMode.second);
4102 ImGui::EndTooltip();
4107 ImGui::SetItemDefaultFocus();
4113 static constexpr std::array<std::pair<vn::protocol::uart::PpsSource, const char*>, 4> gpsConfigurationPpsSources = {
4114 { { vn::protocol::uart::PpsSource::PPSSOURCE_GPSPPSRISING,
"GNSS PPS signal is present on the GNSS_PPS pin (pin 24) and should trigger on a rising edge." },
4115 { vn::protocol::uart::PpsSource::PPSSOURCE_GPSPPSFALLING,
"GNSS PPS signal is present on the GNSS_PPS pin (pin 24) and should trigger on a falling edge" },
4116 { vn::protocol::uart::PpsSource::PPSSOURCE_SYNCINRISING,
"GNSS PPS signal is present on the SyncIn pin (pin 22) and should trigger on a rising edge" },
4117 { vn::protocol::uart::PpsSource::PPSSOURCE_SYNCINFALLING,
"GNSS PPS signal is present on the SyncIn pin (pin 22) and should trigger on a falling edge" } }
4119 if (ImGui::BeginCombo(fmt::format(
"PPS Source##{}",
size_t(
id)).c_str(), vn::protocol::uart::str(
_gpsConfigurationRegister.ppsSource).c_str()))
4121 for (
const auto& gpsConfigurationPpsSource : gpsConfigurationPpsSources)
4124 if (ImGui::Selectable(vn::protocol::uart::str(gpsConfigurationPpsSource.first).c_str(), isSelected))
4135 catch (
const std::exception& e)
4137 LOG_ERROR(
"{}: Could not configure the gpsConfigurationRegister: {}",
nameId(), e.what());
4146 if (ImGui::IsItemHovered())
4148 ImGui::BeginTooltip();
4149 ImGui::TextUnformatted(gpsConfigurationPpsSource.second);
4150 ImGui::EndTooltip();
4155 ImGui::SetItemDefaultFocus();
4161 static constexpr std::array<vn::protocol::uart::GpsRate, 1> gpsConfigurationRates = {
4163 vn::protocol::uart::GpsRate::GPSRATE_5HZ }
4165 if (ImGui::BeginCombo(fmt::format(
"Rate##{}",
size_t(
id)).c_str(), vn::protocol::uart::str(
_gpsConfigurationRegister.rate).c_str()))
4167 for (
const auto& gpsConfigurationRate : gpsConfigurationRates)
4170 if (ImGui::Selectable(vn::protocol::uart::str(gpsConfigurationRate).c_str(), isSelected))
4181 catch (
const std::exception& e)
4183 LOG_ERROR(
"{}: Could not configure the gpsConfigurationRegister: {}",
nameId(), e.what());
4195 ImGui::SetItemDefaultFocus();
4203 static constexpr std::array<std::pair<vn::protocol::uart::AntPower, const char*>, 3> gpsConfigurationAntPowers = {
4204 { { vn::protocol::uart::AntPower::ANTPOWER_OFFRESV,
"Disable antenna power supply." },
4205 { vn::protocol::uart::AntPower::ANTPOWER_INTERNAL,
"Use internal antenna power supply (3V, 50mA combined)." },
4206 { vn::protocol::uart::AntPower::ANTPOWER_EXTERNAL,
"Use external antenna power supply (VANT pin, up to 5V and 100mA combined)" } }
4208 if (ImGui::BeginCombo(fmt::format(
"Ant Power##{}",
size_t(
id)).c_str(), vn::protocol::uart::str(
_gpsConfigurationRegister.antPow).c_str()))
4210 for (
const auto& gpsConfigurationAntPower : gpsConfigurationAntPowers)
4213 if (ImGui::Selectable(vn::protocol::uart::str(gpsConfigurationAntPower.first).c_str(), isSelected))
4224 catch (
const std::exception& e)
4226 LOG_ERROR(
"{}: Could not configure the gpsConfigurationRegister: {}",
nameId(), e.what());
4235 if (ImGui::IsItemHovered())
4237 ImGui::BeginTooltip();
4238 ImGui::TextUnformatted(gpsConfigurationAntPower.second);
4239 ImGui::EndTooltip();
4244 ImGui::SetItemDefaultFocus();
4255 if (ImGui::TreeNode(fmt::format(
"GNSS Antenna A Offset##{}",
size_t(
id)).c_str()))
4257 ImGui::TextUnformatted(
"The position of the GNSS antenna A relative to the sensor in the vehicle coordinate frame\n"
4258 "also referred to as the GNSS antenna lever arm.");
4260 if (ImGui::InputFloat3(fmt::format(
"##gpsAntennaOffset {}",
size_t(
id)).c_str(),
_gpsAntennaOffset.c,
"%.6f"))
4270 catch (
const std::exception& e)
4272 LOG_ERROR(
"{}: Could not configure the gpsAntennaOffset: {}",
nameId(), e.what());
4285 if (ImGui::TreeNode(fmt::format(
"GNSS Compass Baseline##{}",
size_t(
id)).c_str()))
4287 ImGui::TextUnformatted(
"Configures the position offset and measurement uncertainty of the second GNSS\n"
4288 "antenna relative to the first GNSS antenna in the vehicle reference frame.");
4300 catch (
const std::exception& e)
4302 LOG_ERROR(
"{}: Could not configure the gpsCompassBaselineRegister: {}",
nameId(), e.what());
4313 "The accuracy of the estimated heading is dependent upon the accuracy of the measured baseline "
4314 "between the two GNSS antennas. The factory default baseline is {1.0m, 0.0m, 0.0m}. If any other "
4315 "baseline is used, it is extremely important that the user acurately measures this baseline to ensure "
4316 "accurate heading estimates.\n"
4317 "The heading accuracy is linearly proportional to the measurement accuracy of the position of "
4318 "GNSS antenna B with respect to GNSS antenna A, and inversely proportional to the baseline "
4320 "Heading Error [deg] ~= 0.57 * (Baseline Error [cm]) / (Baseline Length [m])\n\n"
4321 "On a 1 meter baseline, a 1 cm measurement error equates to heading error of 0.6 degrees.",
4324 if (ImGui::InputFloat3(fmt::format(
"Uncertainty [m]##{}",
size_t(
id)).c_str(),
_gpsCompassBaselineRegister.uncertainty.c,
"%.3f"))
4334 catch (
const std::exception& e)
4336 LOG_ERROR(
"{}: Could not configure the gpsCompassBaselineRegister: {}",
nameId(), e.what());
4347 "For the VN-310E to function properly it is very important that the user supplies a reasonable "
4348 "measurement uncertainty that is greater than the actual uncertainty in the baseline measurement. "
4349 "The VN-310E uses the uncertainty supplied by the user to validate measurements that it receives "
4350 "from the GNSS receivers. If the user inputs an uncertainty that is lower than the actual error in "
4351 "the baseline measurement between the two antennas, the VN-310E will no longer be able to derive "
4352 "heading estimates from the GNSS.\n\n"
4353 "It is recommended that you set the uncertainty equal to twice what you expect the worst case "
4354 "error to be in your baseline measurements. In many applications it is easier to measure more "
4355 "accurately in one direction than another. It is recommended that you set each of the X, Y, & Z "
4356 "uncertainties seperately to reflect this, as opposed to using a single large value.",
4368 ImGui::SetNextItemOpen(
true, ImGuiCond_FirstUseEver);
4369 if (ImGui::CollapsingHeader(fmt::format(
"Attitude Subsystem##{}",
size_t(
id)).c_str()))
4371 if (ImGui::TreeNode(fmt::format(
"VPE Basic Control##{}",
size_t(
id)).c_str()))
4373 ImGui::TextUnformatted(
"Provides control over various features relating to the onboard attitude filtering algorithm.");
4375 static constexpr std::array<vn::protocol::uart::VpeEnable, 2> vpeBasicControlEnables = {
4376 { vn::protocol::uart::VpeEnable::VPEENABLE_DISABLE,
4377 vn::protocol::uart::VpeEnable::VPEENABLE_ENABLE }
4379 if (ImGui::BeginCombo(fmt::format(
"Enable##{}",
size_t(
id)).c_str(), vn::protocol::uart::str(
_vpeBasicControlRegister.enable).c_str()))
4381 for (
const auto& vpeBasicControlEnable : vpeBasicControlEnables)
4384 if (ImGui::Selectable(vn::protocol::uart::str(vpeBasicControlEnable).c_str(), isSelected))
4395 catch (
const std::exception& e)
4397 LOG_ERROR(
"{}: Could not configure the vpeBasicControlRegister: {}",
nameId(), e.what());
4409 ImGui::SetItemDefaultFocus();
4415 static constexpr std::array<vn::protocol::uart::HeadingMode, 3> vpeBasicControlHeadingModes = {
4416 { vn::protocol::uart::HeadingMode::HEADINGMODE_ABSOLUTE,
4417 vn::protocol::uart::HeadingMode::HEADINGMODE_RELATIVE,
4418 vn::protocol::uart::HeadingMode::HEADINGMODE_INDOOR }
4420 if (ImGui::BeginCombo(fmt::format(
"Heading Mode##{}",
size_t(
id)).c_str(), vn::protocol::uart::str(
_vpeBasicControlRegister.headingMode).c_str()))
4422 for (
const auto& vpeBasicControlHeadingMode : vpeBasicControlHeadingModes)
4425 if (ImGui::Selectable(vn::protocol::uart::str(vpeBasicControlHeadingMode).c_str(), isSelected))
4436 catch (
const std::exception& e)
4438 LOG_ERROR(
"{}: Could not configure the vpeBasicControlRegister: {}",
nameId(), e.what());
4450 ImGui::SetItemDefaultFocus();
4456 static constexpr std::array<vn::protocol::uart::VpeMode, 2> vpeBasicControlModes = {
4457 { vn::protocol::uart::VpeMode::VPEMODE_OFF,
4458 vn::protocol::uart::VpeMode::VPEMODE_MODE1 }
4460 if (ImGui::BeginCombo(fmt::format(
"Filtering Mode##{}",
size_t(
id)).c_str(), vn::protocol::uart::str(
_vpeBasicControlRegister.filteringMode).c_str()))
4462 for (
const auto& vpeBasicControlMode : vpeBasicControlModes)
4465 if (ImGui::Selectable(vn::protocol::uart::str(vpeBasicControlMode).c_str(), isSelected))
4476 catch (
const std::exception& e)
4478 LOG_ERROR(
"{}: Could not configure the vpeBasicControlRegister: {}",
nameId(), e.what());
4490 ImGui::SetItemDefaultFocus();
4496 if (ImGui::BeginCombo(fmt::format(
"Tuning Mode##{}",
size_t(
id)).c_str(), vn::protocol::uart::str(
_vpeBasicControlRegister.tuningMode).c_str()))
4498 for (
const auto& vpeBasicControlMode : vpeBasicControlModes)
4501 if (ImGui::Selectable(vn::protocol::uart::str(vpeBasicControlMode).c_str(), isSelected))
4512 catch (
const std::exception& e)
4514 LOG_ERROR(
"{}: Could not configure the vpeBasicControlRegister: {}",
nameId(), e.what());
4526 ImGui::SetItemDefaultFocus();
4537 if (ImGui::TreeNode(fmt::format(
"VPE Magnetometer Basic Tuning##{}",
size_t(
id)).c_str()))
4539 ImGui::TextUnformatted(
"Provides basic control of the adaptive filtering and tuning for the magnetometer.");
4551 catch (
const std::exception& e)
4553 LOG_ERROR(
"{}: Could not configure the vpeMagnetometerBasicTuningRegister: {}",
nameId(), e.what());
4563 gui::widgets::HelpMarker(
"This sets the level of confidence placed in the magnetometer when no disturbances are present. "
4564 "A larger number provides better heading accuracy, but with more sensitivity to magnetic interference.");
4576 catch (
const std::exception& e)
4578 LOG_ERROR(
"{}: Could not configure the vpeMagnetometerBasicTuningRegister: {}",
nameId(), e.what());
4588 if (ImGui::DragFloat3(fmt::format(
"Adaptive Filtering Level##{}",
size_t(
id)).c_str(),
_vpeMagnetometerBasicTuningRegister.adaptiveFiltering.c, 0.1F, 0.0F, 10.0F,
"%.1f"))
4598 catch (
const std::exception& e)
4600 LOG_ERROR(
"{}: Could not configure the vpeMagnetometerBasicTuningRegister: {}",
nameId(), e.what());
4613 if (ImGui::TreeNode(fmt::format(
"VPE Accelerometer Basic Tuning##{}",
size_t(
id)).c_str()))
4615 ImGui::TextUnformatted(
"Provides basic control of the adaptive filtering and tuning for the accelerometer.");
4627 catch (
const std::exception& e)
4629 LOG_ERROR(
"{}: Could not configure the vpeAccelerometerBasicTuningRegister: {}",
nameId(), e.what());
4639 gui::widgets::HelpMarker(
"This sets the level of confidence placed in the accelerometer when no disturbances are present. "
4640 "A larger number provides better pitch/roll heading accuracy, but with more sensitivity to acceleration interference.");
4652 catch (
const std::exception& e)
4654 LOG_ERROR(
"{}: Could not configure the vpeAccelerometerBasicTuningRegister: {}",
nameId(), e.what());
4674 catch (
const std::exception& e)
4676 LOG_ERROR(
"{}: Could not configure the vpeAccelerometerBasicTuningRegister: {}",
nameId(), e.what());
4689 if (ImGui::TreeNode(fmt::format(
"VPE Gyro Basic Tuning##{}",
size_t(
id)).c_str()))
4691 ImGui::TextUnformatted(
"Provides basic control of the adaptive filtering and tuning for the gyroscope.");
4693 if (ImGui::DragFloat3(fmt::format(
"Base Tuning Level##{}",
size_t(
id)).c_str(),
_vpeGyroBasicTuningRegister.baseTuning.c, 0.1F, 0.0F, 10.0F,
"%.1f"))
4703 catch (
const std::exception& e)
4705 LOG_ERROR(
"{}: Could not configure the vpeGyroBasicTuningRegister: {}",
nameId(), e.what());
4717 if (ImGui::DragFloat3(fmt::format(
"Adaptive Tuning Level##{}",
size_t(
id)).c_str(),
_vpeGyroBasicTuningRegister.adaptiveTuning.c, 0.1F, 0.0F, 10.0F,
"%.1f"))
4727 catch (
const std::exception& e)
4729 LOG_ERROR(
"{}: Could not configure the vpeGyroBasicTuningRegister: {}",
nameId(), e.what());
4739 if (ImGui::DragFloat3(fmt::format(
"Variance - Angular Walk##{}",
size_t(
id)).c_str(),
_vpeGyroBasicTuningRegister.angularWalkVariance.c, 0.1F, 0.0F, 10.0F,
"%.1f"))
4749 catch (
const std::exception& e)
4751 LOG_ERROR(
"{}: Could not configure the vpeGyroBasicTuningRegister: {}",
nameId(), e.what());
4764 if (ImGui::TreeNode(fmt::format(
"Filter Startup Gyro Bias##{}",
size_t(
id)).c_str()))
4766 ImGui::TextUnformatted(
"The filter gyro bias estimate used at startup [rad/s].");
4768 if (ImGui::InputFloat3(fmt::format(
"## FilterStartupGyroBias {}",
size_t(
id)).c_str(),
_filterStartupGyroBias.c,
"%.1f"))
4778 catch (
const std::exception& e)
4780 LOG_ERROR(
"{}: Could not configure the filterStartupGyroBias: {}",
nameId(), e.what());
4801 ImGui::SetNextItemOpen(
true, ImGuiCond_FirstUseEver);
4802 if (ImGui::CollapsingHeader(fmt::format(
"INS Subsystem##{}",
size_t(
id)).c_str()))
4804 if (ImGui::TreeNode(fmt::format(
"INS Basic Configuration##{}",
size_t(
id)).c_str()))
4806 static constexpr std::array<std::pair<vn::protocol::uart::Scenario, const char*>, 3> insBasicConfigurationRegisterVn300Scenarios = {
4807 { { vn::protocol::uart::Scenario::SCENARIO_INSWITHPRESSURE,
"General purpose INS with barometric pressure sensor" },
4808 { vn::protocol::uart::Scenario::SCENARIO_INSWITHOUTPRESSURE,
"General purpose INS without barometric pressure sensor" },
4809 { vn::protocol::uart::Scenario::SCENARIO_GPSMOVINGBASELINEDYNAMIC,
"GNSS moving baseline for dynamic applications" } }
4813 for (
const auto& insBasicConfigurationRegisterVn300Scenario : insBasicConfigurationRegisterVn300Scenarios)
4816 if (ImGui::Selectable(vn::protocol::uart::str(insBasicConfigurationRegisterVn300Scenario.first).c_str(), isSelected))
4827 catch (
const std::exception& e)
4829 LOG_ERROR(
"{}: Could not configure the insBasicConfigurationRegisterVn300: {}",
nameId(), e.what());
4838 if (ImGui::IsItemHovered())
4840 ImGui::BeginTooltip();
4841 ImGui::TextUnformatted(insBasicConfigurationRegisterVn300Scenario.second);
4842 ImGui::EndTooltip();
4847 ImGui::SetItemDefaultFocus();
4863 catch (
const std::exception& e)
4865 LOG_ERROR(
"{}: Could not configure the insBasicConfigurationRegisterVn300: {}",
nameId(), e.what());
4876 "the ability to switch to using the magnetometer to "
4877 "stabilize heading during times when the device is "
4878 "stationary and the GNSS compass is not available. "
4879 "AHRS aiding also helps to eliminate large updates in "
4880 "the attitude solution during times when heading is "
4881 "weakly observable, such as at startup.");
4893 catch (
const std::exception& e)
4895 LOG_ERROR(
"{}: Could not configure the insBasicConfigurationRegisterVn300: {}",
nameId(), e.what());
4910 if (ImGui::TreeNode(fmt::format(
"Startup Filter Bias Estimate##{}",
size_t(
id)).c_str()))
4912 ImGui::TextUnformatted(
"Sets the initial estimate for the filter bias states");
4924 catch (
const std::exception& e)
4926 LOG_ERROR(
"{}: Could not configure the startupFilterBiasEstimateRegister: {}",
nameId(), e.what());
4946 catch (
const std::exception& e)
4948 LOG_ERROR(
"{}: Could not configure the startupFilterBiasEstimateRegister: {}",
nameId(), e.what());
4968 catch (
const std::exception& e)
4970 LOG_ERROR(
"{}: Could not configure the startupFilterBiasEstimateRegister: {}",
nameId(), e.what());
4989 ImGui::SetNextItemOpen(
true, ImGuiCond_FirstUseEver);
4990 if (ImGui::CollapsingHeader(fmt::format(
"Hard/Soft Iron Estimator Subsystem##{}",
size_t(
id)).c_str()))
4992 if (ImGui::TreeNode(fmt::format(
"Magnetometer Calibration Control##{}",
size_t(
id)).c_str()))
4994 ImGui::TextUnformatted(
"Controls the magnetometer real-time calibration algorithm.");
4998 gui::widgets::HelpMarker(
"On the PRODUCT the magnetometer is only used to provide a coarse heading estimate at startup "
4999 "and is completely tuned out of the INS filter during normal operation. A Hard/Soft Iron calibration "
5000 "may be performed to try and improve the startup magnetic heading, but is not required for nominal "
5005 static constexpr std::array<std::pair<vn::protocol::uart::HsiMode, const char*>, 3> magnetometerCalibrationControlHsiModes = {
5006 { { vn::protocol::uart::HsiMode::HSIMODE_OFF,
"Real-time hard/soft iron calibration algorithm is turned off" },
5007 { vn::protocol::uart::HsiMode::HSIMODE_RUN,
"Runs the real-time hard/soft iron calibration. The algorithm will continue using its existing solution.\n"
5008 "The algorithm can be started and stopped at any time by switching between the HSI_OFF and HSI_RUN state." },
5009 { vn::protocol::uart::HsiMode::HSIMODE_RESET,
"Resets the real-time hard/soft iron solution" } }
5013 for (
const auto& magnetometerCalibrationControlHsiMode : magnetometerCalibrationControlHsiModes)
5016 if (ImGui::Selectable(vn::protocol::uart::str(magnetometerCalibrationControlHsiMode.first).c_str(), isSelected))
5027 catch (
const std::exception& e)
5029 LOG_ERROR(
"{}: Could not configure the magnetometerCalibrationControlRegister: {}",
nameId(), e.what());
5038 if (ImGui::IsItemHovered())
5040 ImGui::BeginTooltip();
5041 ImGui::TextUnformatted(magnetometerCalibrationControlHsiMode.second);
5042 ImGui::EndTooltip();
5047 ImGui::SetItemDefaultFocus();
5053 gui::widgets::HelpMarker(
"Controls the mode of operation for the onboard real-time magnetometer hard/soft iron compensation algorithm.");
5055 static constexpr std::array<std::pair<vn::protocol::uart::HsiOutput, const char*>, 2> magnetometerCalibrationControlHsiOutputs = {
5056 { { vn::protocol::uart::HsiOutput::HSIOUTPUT_NOONBOARD,
"Onboard HSI is not applied to the magnetic measurements" },
5057 { vn::protocol::uart::HsiOutput::HSIOUTPUT_USEONBOARD,
"Onboard HSI is applied to the magnetic measurements" } }
5061 for (
const auto& [magnetometerCalibrationControlHsiOutputMode, magnetometerCalibrationControlHsiOutputDescription] : magnetometerCalibrationControlHsiOutputs)
5064 if (ImGui::Selectable(vn::protocol::uart::str(magnetometerCalibrationControlHsiOutputMode).c_str(), isSelected))
5075 catch (
const std::exception& e)
5077 LOG_ERROR(
"{}: Could not configure the magnetometerCalibrationControlRegister: {}",
nameId(), e.what());
5086 if (ImGui::IsItemHovered())
5088 ImGui::BeginTooltip();
5089 ImGui::TextUnformatted(magnetometerCalibrationControlHsiOutputDescription);
5090 ImGui::EndTooltip();
5095 ImGui::SetItemDefaultFocus();
5102 "outputs from the magnetometer sensor and also "
5103 "subsequently used in the attitude filter.");
5106 if (ImGui::SliderInt(fmt::format(
"Converge Rate##{}",
size_t(
id)).c_str(), &convergeRate, 0, 5))
5117 catch (
const std::exception& e)
5119 LOG_ERROR(
"{}: Could not configure the magnetometerCalibrationControlRegister: {}",
nameId(), e.what());
5130 "to converge onto a new solution. The slower the "
5131 "convergence the more accurate the estimate of the "
5132 "hard/soft iron solution. A quicker convergence will provide "
5133 "a less accurate estimate of the hard/soft iron parameters, "
5134 "but for applications where the hard/soft iron changes "
5135 "rapidly may provide a more accurate attitude estimate.\n\n"
5137 "1 = Solution converges slowly over approximately 60-90 seconds.\n"
5138 "5 = Solution converges rapidly over approximately 15-20 seconds.");
5148 ImGui::SetNextItemOpen(
true, ImGuiCond_FirstUseEver);
5149 if (ImGui::CollapsingHeader(fmt::format(
"World Magnetic & Gravity Module##{}",
size_t(
id)).c_str()))
5151 if (ImGui::TreeNode(fmt::format(
"Magnetic and Gravity Reference Vectors##{}",
size_t(
id)).c_str()))
5153 ImGui::TextUnformatted(
"Magnetic and gravity reference vectors");
5155 gui::widgets::HelpMarker(
"This register contains the reference vectors for the magnetic and gravitational fields as used by the "
5156 "onboard filter. The values map to either the user-set values or the results of calculations of the onboard "
5157 "reference models (see the Reference Vector Configuration Register in the IMU subsystem). When the "
5158 "reference values come from the onboard model(s), those values are read-only. When the reference models "
5159 "are disabled, the values reflect the user reference vectors and will be writable. For example, if the onboard "
5160 "World Magnetic Model is enabled and the onboard Gravitational Model is disabled, only the gravity "
5161 "reference values will be modified on a register write. Note that the user reference vectors will not be "
5162 "overwritten by the onboard models, but will retain their previous values for when the onboard models are "
5175 catch (
const std::exception& e)
5177 LOG_ERROR(
"{}: Could not configure the magneticAndGravityReferenceVectorsRegister: {}",
nameId(), e.what());
5197 catch (
const std::exception& e)
5199 LOG_ERROR(
"{}: Could not configure the magneticAndGravityReferenceVectorsRegister: {}",
nameId(), e.what());
5212 if (ImGui::TreeNode(fmt::format(
"Reference Vector Configuration##{}",
size_t(
id)).c_str()))
5214 ImGui::TextUnformatted(
"Control register for both the onboard world magnetic and gravity model corrections");
5216 gui::widgets::HelpMarker(
"This register allows configuration of the onboard spherical harmonic models used to calculate the local "
5217 "magnetic and gravitational reference values. Having accurate magnetic reference values improves the "
5218 "accuracy of heading when using the magnetometer and accounts for magnetic declination. Having accurate "
5219 "gravitational reference values improves accuracy by allowing the INS filter to more accurately estimate the "
5220 "accelerometer biases. The VectorNav currently includes the EGM96 gravitational model and the WMM2010 "
5221 "magnetic model. The models are upgradable to allow updating to future models when available.\n\n"
5222 "The magnetic and gravity models can be individually enabled or disabled using the UseMagModel and "
5223 "UseGravityModel parameters, respectively. When disabled, the corresponding values set by the user in the "
5224 "Reference Vector Register in the IMU subsystem will be used instead of values calculated by the onboard "
5226 "The VectorNav starts up with the user configured reference vector values. Shortly after startup (and if the "
5227 "models are enabled), the location and time set in this register will be used to update the reference vectors. "
5228 "When a 3D GNSS fix is available, the location and time reported by the GNSS will be used to update the model. "
5229 "If GNSS is lost, the reference vectors will hold their last valid values. The model values will be recalculated "
5230 "whenever the current position has changed by the RecaclThreshold or the date has changed by more than "
5231 "approximately 8 hours, whichever comes first.");
5243 catch (
const std::exception& e)
5245 LOG_ERROR(
"{}: Could not configure the referenceVectorConfigurationRegister: {}",
nameId(), e.what());
5265 catch (
const std::exception& e)
5267 LOG_ERROR(
"{}: Could not configure the referenceVectorConfigurationRegister: {}",
nameId(), e.what());
5278 if (ImGui::InputInt(fmt::format(
"Recalc Threshold [m]##{}",
size_t(
id)).c_str(), &recalcThreshold))
5289 catch (
const std::exception& e)
5291 LOG_ERROR(
"{}: Could not configure the referenceVectorConfigurationRegister: {}",
nameId(), e.what());
5301 gui::widgets::HelpMarker(
"Maximum distance traveled before magnetic and gravity models are recalculated for the new position.");
5313 catch (
const std::exception& e)
5315 LOG_ERROR(
"{}: Could not configure the referenceVectorConfigurationRegister: {}",
nameId(), e.what());
5325 gui::widgets::HelpMarker(
"The reference date expressed as a decimal year. Used for both the magnetic and gravity models.");
5337 catch (
const std::exception& e)
5339 LOG_ERROR(
"{}: Could not configure the referenceVectorConfigurationRegister: {}",
nameId(), e.what());
5361 catch (
const std::exception& e)
5363 LOG_ERROR(
"{}: Could not configure the referenceVectorConfigurationRegister: {}",
nameId(), e.what());
5385 catch (
const std::exception& e)
5387 LOG_ERROR(
"{}: Could not configure the referenceVectorConfigurationRegister: {}",
nameId(), e.what());
5409 ImGui::SetNextItemOpen(
true, ImGuiCond_FirstUseEver);
5410 if (ImGui::CollapsingHeader(fmt::format(
"Velocity Aiding##{}",
size_t(
id)).c_str()))
5412 if (ImGui::TreeNode(fmt::format(
"Velocity Compensation Control##{}",
size_t(
id)).c_str()))
5414 ImGui::TextUnformatted(
"Provides control over the velocity compensation feature for the attitude filter.");
5416 static constexpr std::array<vn::protocol::uart::VelocityCompensationMode, 2> velocityCompensationControlModes = {
5417 { vn::protocol::uart::VelocityCompensationMode::VELOCITYCOMPENSATIONMODE_DISABLED,
5418 vn::protocol::uart::VelocityCompensationMode::VELOCITYCOMPENSATIONMODE_BODYMEASUREMENT }
5422 for (
const auto& velocityCompensationControlMode : velocityCompensationControlModes)
5425 if (ImGui::Selectable(vn::protocol::uart::str(velocityCompensationControlMode).c_str(), isSelected))
5436 catch (
const std::exception& e)
5438 LOG_ERROR(
"{}: Could not configure the velocityCompensationControlRegister: {}",
nameId(), e.what());
5450 ImGui::SetItemDefaultFocus();
5468 catch (
const std::exception& e)
5470 LOG_ERROR(
"{}: Could not configure the velocityCompensationControlRegister: {}",
nameId(), e.what());
5492 catch (
const std::exception& e)
5494 LOG_ERROR(
"{}: Could not configure the velocityCompensationControlRegister: {}",
nameId(), e.what());
5532 for (
size_t b = 0; b < 3; b++)
5598 if (j.contains(
"UartSensor"))
5602 if (j.contains(
"sensorModel"))
5611 if (j.contains(
"asyncDataOutputType"))
5615 if (j.contains(
"asyncDataOutputFrequency"))
5621 if (j.contains(
"asciiOutputBufferSize"))
5626 if (j.contains(
"syncInPin"))
5634 if (j.contains(
"synchronizationControlRegister"))
5643 if (j.contains(
"communicationProtocolControlRegister"))
5647 if (j.contains(
"binaryOutputRegisterMerge"))
5664 for (
size_t b = 0; b < 3; b++)
5666 if (j.contains(fmt::format(
"binaryOutputRegister{}", b + 1)))
5670 if (j.contains(fmt::format(
"binaryOutputRegister{}-Frequency", b + 1)))
5672 std::string frequency;
5673 j.at(fmt::format(
"binaryOutputRegister{}-Frequency", b + 1)).get_to(frequency);
5689 if (j.contains(
"referenceFrameRotationMatrix"))
5693 if (j.contains(
"imuFilteringConfigurationRegister"))
5697 if (j.contains(
"deltaThetaAndDeltaVelocityConfigurationRegister"))
5701 if (j.contains(
"coupleImuRateOutput"))
5710 if (j.contains(
"gpsConfigurationRegister"))
5714 if (j.contains(
"gpsAntennaOffset"))
5718 if (j.contains(
"gpsCompassBaselineRegister"))
5727 if (j.contains(
"vpeBasicControlRegister"))
5731 if (j.contains(
"vpeMagnetometerBasicTuningRegister"))
5735 if (j.contains(
"vpeAccelerometerBasicTuningRegister"))
5739 if (j.contains(
"vpeGyroBasicTuningRegister"))
5743 if (j.contains(
"filterStartupGyroBias"))
5752 if (j.contains(
"insBasicConfigurationRegisterVn300"))
5756 if (j.contains(
"startupFilterBiasEstimateRegister"))
5765 if (j.contains(
"magnetometerCalibrationControlRegister"))
5774 if (j.contains(
"magneticAndGravityReferenceVectorsRegister"))
5778 if (j.contains(
"referenceVectorConfigurationRegister"))
5787 if (j.contains(
"velocityCompensationControlRegister"))
5820 ?
static_cast<Baudrate>(vn::sensors::VnSensor::supportedBaudrates()[vn::sensors::VnSensor::supportedBaudrates().size() - 1])
5827 size_t maxTries = std::filesystem::exists(
_sensorPort) ? 5 : 0;
5828 for (
size_t i = 0; i < maxTries; ++i)
5830 if (int32_t foundBaudrate = 0;
5831 vn::sensors::Searcher::search(
_sensorPort, &foundBaudrate))
5834 connectedBaudrate =
static_cast<Baudrate>(foundBaudrate);
5836 LOG_DEBUG(
"{}: Found VectorNav sensor on specified port '{}' with baudrate {} (it took {} attempts to connect)",
5849 for (
size_t i = 0; i < 5; ++i)
5856 if (std::vector<std::pair<std::string, uint32_t>> foundSensors = vn::sensors::Searcher::search();
5857 !foundSensors.empty())
5859 for (
const auto& [port, baudrate] : foundSensors)
5861 _vs.connect(port, baudrate);
5862 std::string modelNumber =
_vs.readModelNumber();
5865 LOG_DEBUG(
"{}: Found VectorNav sensor '{}' on port '{}' with baudrate {} ({} VN sensors connected in total)",
5866 nameId(), modelNumber, port, baudrate, foundSensors.size());
5870 if (modelNumber.find(searchString) != std::string::npos)
5873 connectedBaudrate =
static_cast<Baudrate>(baudrate);
5875 LOG_DEBUG(
"{}: Selected VectorNav sensor '{}' on port '{}' (it took {} attempts to connect)",
5876 nameId(), modelNumber, port, i + 1);
5884 LOG_ERROR(
"{}: Could not connect. Is the sensor connected and do you have read permissions?",
nameId());
5894 catch (
const std::exception& e)
5896 LOG_ERROR(
"{}: Failed to connect to sensor on port '{}' with baudrate {} with error: {}",
nameId(),
5903 if (!
_vs.verifySensorConnectivity())
5905 LOG_ERROR(
"{}: Connected to sensor on port '{}' with baudrate {} but sensor does not answer",
nameId(),
5910 catch (
const std::exception& e)
5912 LOG_ERROR(
"{}: Connected to sensor on port '{}' with baudrate {} but sensor threw an exception: {}",
nameId(),
5918 auto modelNumber =
_vs.readModelNumber();
5923 LOG_ERROR(
"{}: VN100/VN110 configured, but sensor identifies as {}",
nameId(), modelNumber);
5929 LOG_ERROR(
"{}: VN310 configured, but sensor identifies as {}",
nameId(), modelNumber);
5939 if (targetBaudrate != connectedBaudrate)
5941 auto suppBaud = vn::sensors::VnSensor::supportedBaudrates();
5942 if (std::ranges::find(suppBaud, targetBaudrate) != suppBaud.end())
5944 _vs.changeBaudRate(targetBaudrate);
5945 LOG_DEBUG(
"{}: Baudrate changed to {}",
nameId(),
static_cast<size_t>(targetBaudrate));
5949 LOG_ERROR(
"{}: Does not support baudrate {}",
nameId(),
static_cast<size_t>(targetBaudrate));
5953 if (
_vs.readSerialBaudRate() != targetBaudrate)
5955 LOG_ERROR(
"{}: Changing the baudrate from {} to {} was not successfull",
nameId(),
_vs.readSerialBaudRate(), targetBaudrate);
5961 if (
auto vnSynchronizationControlRegister =
_vs.readSynchronizationControl();
5970 LOG_ERROR(
"{}: Writing the synchronizationControlRegister was not successfull.\n"
5971 "Target: syncInMode = {}, syncInEdge = {}, syncInSkipFactor = {}, syncOutMode = {}, syncOutPolarity = {}, syncOutSkipFactor = {}, syncOutPulseWidth = {}\n"
5972 "Sensor: syncInMode = {}, syncInEdge = {}, syncInSkipFactor = {}, syncOutMode = {}, syncOutPolarity = {}, syncOutSkipFactor = {}, syncOutPulseWidth = {}",
5975 vnSynchronizationControlRegister.syncInMode, vnSynchronizationControlRegister.syncInEdge, vnSynchronizationControlRegister.syncInSkipFactor, vnSynchronizationControlRegister.syncOutMode, vnSynchronizationControlRegister.syncOutPolarity, vnSynchronizationControlRegister.syncOutSkipFactor, vnSynchronizationControlRegister.syncOutPulseWidth);
5981 if (
auto vnCommunicationProtocolControlRegister =
_vs.readCommunicationProtocolControl();
5990 LOG_ERROR(
"{}: Writing the communicationProtocolControlRegister was not successfull.\n"
5991 "Target: serialCount = {}, serialStatus = {}, spiCount = {}, spiStatus = {}, serialChecksum = {}, spiChecksum = {}, errorMode = {}\n"
5992 "Sensor: serialCount = {}, serialStatus = {}, spiCount = {}, spiStatus = {}, serialChecksum = {}, spiChecksum = {}, errorMode = {}",
5995 vnCommunicationProtocolControlRegister.serialCount, vnCommunicationProtocolControlRegister.serialStatus, vnCommunicationProtocolControlRegister.spiCount, vnCommunicationProtocolControlRegister.spiStatus, vnCommunicationProtocolControlRegister.serialChecksum, vnCommunicationProtocolControlRegister.spiChecksum, vnCommunicationProtocolControlRegister.errorMode);
6011 if (
auto vnReferenceFrameRotationMatrix =
_vs.readReferenceFrameRotation();
6014 LOG_ERROR(
"{}: Writing the referenceFrameRotationMatrix was not successfull.\n"
6015 "Target: DCM = {}\n"
6023 if (
auto vnImuFilteringConfigurationRegister =
_vs.readImuFilteringConfiguration();
6035 LOG_ERROR(
"{}: Writing the imuFilteringConfigurationRegister was not successfull.\n"
6036 "Target: magWindowSize = {}, accelWindowSize = {}, gyroWindowSize = {}, tempWindowSize = {}, presWindowSize = {}, magFilterMode = {}, accelFilterMode = {}, gyroFilterMode = {}, tempFilterMode = {}, presFilterMode = {}\n"
6037 "Sensor: magWindowSize = {}, accelWindowSize = {}, gyroWindowSize = {}, tempWindowSize = {}, presWindowSize = {}, magFilterMode = {}, accelFilterMode = {}, gyroFilterMode = {}, tempFilterMode = {}, presFilterMode = {}",
6039 _imuFilteringConfigurationRegister.magWindowSize,
_imuFilteringConfigurationRegister.accelWindowSize,
_imuFilteringConfigurationRegister.gyroWindowSize,
_imuFilteringConfigurationRegister.tempWindowSize,
_imuFilteringConfigurationRegister.presWindowSize,
_imuFilteringConfigurationRegister.magFilterMode,
_imuFilteringConfigurationRegister.accelFilterMode,
_imuFilteringConfigurationRegister.gyroFilterMode,
_imuFilteringConfigurationRegister.tempFilterMode,
_imuFilteringConfigurationRegister.presFilterMode,
6040 vnImuFilteringConfigurationRegister.magWindowSize, vnImuFilteringConfigurationRegister.accelWindowSize, vnImuFilteringConfigurationRegister.gyroWindowSize, vnImuFilteringConfigurationRegister.tempWindowSize, vnImuFilteringConfigurationRegister.presWindowSize, vnImuFilteringConfigurationRegister.magFilterMode, vnImuFilteringConfigurationRegister.accelFilterMode, vnImuFilteringConfigurationRegister.gyroFilterMode, vnImuFilteringConfigurationRegister.tempFilterMode, vnImuFilteringConfigurationRegister.presFilterMode);
6046 if (
auto vnDeltaThetaAndDeltaVelocityConfigurationRegister =
_vs.readDeltaThetaAndDeltaVelocityConfiguration();
6052 LOG_ERROR(
"{}: Writing the deltaThetaAndDeltaVelocityConfigurationRegister was not successfull.\n"
6053 "Target: integrationFrame = {}, gyroCompensation = {}, accelCompensation = {}, earthRateCorrection = {}\n"
6054 "Sensor: integrationFrame = {}, gyroCompensation = {}, accelCompensation = {}, earthRateCorrection = {}",
6057 vnDeltaThetaAndDeltaVelocityConfigurationRegister.integrationFrame, vnDeltaThetaAndDeltaVelocityConfigurationRegister.gyroCompensation, vnDeltaThetaAndDeltaVelocityConfigurationRegister.accelCompensation, vnDeltaThetaAndDeltaVelocityConfigurationRegister.earthRateCorrection);
6069 if (
auto vnGpsConfigurationRegister =
_vs.readGpsConfiguration();
6075 LOG_ERROR(
"{}: Writing the gpsConfigurationRegister was not successfull.\n"
6076 "Target: mode = {}, ppsSource = {}, rate = {}, antPow = {}\n"
6077 "Sensor: mode = {}, ppsSource = {}, rate = {}, antPow = {}",
6080 vnGpsConfigurationRegister.mode, vnGpsConfigurationRegister.ppsSource, vnGpsConfigurationRegister.rate, vnGpsConfigurationRegister.antPow);
6086 if (
auto vnGpsAntennaOffset =
_vs.readGpsAntennaOffset();
6089 LOG_ERROR(
"{}: Writing the gpsAntennaOffset was not successfull.\n"
6094 vnGpsAntennaOffset);
6100 if (
auto vnGpsCompassBaselineRegister =
_vs.readGpsCompassBaseline();
6104 LOG_ERROR(
"{}: Writing the gpsCompassBaselineRegister was not successfull.\n"
6105 "Target: position = {}, uncertainty = {}\n"
6106 "Sensor: position = {}, uncertainty = {}",
6109 vnGpsCompassBaselineRegister.position, vnGpsCompassBaselineRegister.uncertainty);
6129 if (
auto vnVpeBasicControlRegister =
_vs.readVpeBasicControl();
6135 LOG_ERROR(
"{}: Writing the vpeBasicControlRegister was not successfull.\n"
6136 "Target: enable = {}, headingMode = {}, filteringMode = {}, tuningMode = {}\n"
6137 "Sensor: enable = {}, headingMode = {}, filteringMode = {}, tuningMode = {}",
6140 vnVpeBasicControlRegister.enable, vnVpeBasicControlRegister.headingMode, vnVpeBasicControlRegister.filteringMode, vnVpeBasicControlRegister.tuningMode);
6148 if (
auto vnVpeMagnetometerBasicTuningRegister =
_vs.readVpeMagnetometerBasicTuning();
6153 LOG_ERROR(
"{}: Writing the vpeMagnetometerBasicTuningRegister was not successfull.\n"
6154 "Target: baseTuning = {}, adaptiveTuning = {}, adaptiveFiltering = {}\n"
6155 "Sensor: baseTuning = {}, adaptiveTuning = {}, adaptiveFiltering = {}",
6158 vnVpeMagnetometerBasicTuningRegister.baseTuning, vnVpeMagnetometerBasicTuningRegister.adaptiveTuning, vnVpeMagnetometerBasicTuningRegister.adaptiveFiltering);
6164 if (
auto vnVpeAccelerometerBasicTuningRegister =
_vs.readVpeAccelerometerBasicTuning();
6169 LOG_ERROR(
"{}: Writing the vpeAccelerometerBasicTuningRegister was not successfull.\n"
6170 "Target: baseTuning = {}, adaptiveTuning = {}, adaptiveFiltering = {}\n"
6171 "Sensor: baseTuning = {}, adaptiveTuning = {}, adaptiveFiltering = {}",
6174 vnVpeAccelerometerBasicTuningRegister.baseTuning, vnVpeAccelerometerBasicTuningRegister.adaptiveTuning, vnVpeAccelerometerBasicTuningRegister.adaptiveFiltering);
6180 if (
auto vnFilterStartupGyroBias =
_vs.readFilterStartupGyroBias();
6183 LOG_ERROR(
"{}: Writing the filterStartupGyroBias was not successfull.\n"
6188 vnFilterStartupGyroBias);
6194 if (
auto vnVpeGyroBasicTuningRegister =
_vs.readVpeGyroBasicTuning();
6199 LOG_ERROR(
"{}: Writing the vpeGyroBasicTuningRegister was not successfull.\n"
6200 "Target: angularWalkVariance = {}, baseTuning = {}, adaptiveTuning = {}\n"
6201 "Sensor: angularWalkVariance = {}, baseTuning = {}, adaptiveTuning = {}",
6204 vnVpeGyroBasicTuningRegister.angularWalkVariance, vnVpeGyroBasicTuningRegister.baseTuning, vnVpeGyroBasicTuningRegister.adaptiveTuning);
6217 if (
auto vnInsBasicConfigurationRegisterVn300 =
_vs.readInsBasicConfigurationVn300();
6222 LOG_ERROR(
"{}: Writing the insBasicConfigurationRegisterVn300 was not successfull.\n"
6223 "Target: scenario = {}, ahrsAiding = {}, estBaseline = {}\n"
6224 "Sensor: scenario = {}, ahrsAiding = {}, estBaseline = {}",
6227 vnInsBasicConfigurationRegisterVn300.scenario, vnInsBasicConfigurationRegisterVn300.ahrsAiding, vnInsBasicConfigurationRegisterVn300.estBaseline);
6233 if (
auto vnStartupFilterBiasEstimateRegister =
_vs.readStartupFilterBiasEstimate();
6238 LOG_ERROR(
"{}: Writing the startupFilterBiasEstimateRegister was not successfull.\n"
6239 "Target: gyroBias = {}, accelBias = {}, pressureBias = {}\n"
6240 "Sensor: gyroBias = {}, accelBias = {}, pressureBias = {}",
6243 vnStartupFilterBiasEstimateRegister.gyroBias, vnStartupFilterBiasEstimateRegister.accelBias, vnStartupFilterBiasEstimateRegister.pressureBias);
6254 if (
auto vnMagnetometerCalibrationControlRegister =
_vs.readMagnetometerCalibrationControl();
6259 LOG_ERROR(
"{}: Writing the magnetometerCalibrationControlRegister was not successfull.\n"
6260 "Target: hsiMode = {}, hsiOutput = {}, convergeRate = {}\n"
6261 "Sensor: hsiMode = {}, hsiOutput = {}, convergeRate = {}",
6264 vnMagnetometerCalibrationControlRegister.hsiMode, vnMagnetometerCalibrationControlRegister.hsiOutput, vnMagnetometerCalibrationControlRegister.convergeRate);
6274 if (
auto vnMagneticAndGravityReferenceVectorsRegister =
_vs.readMagneticAndGravityReferenceVectors();
6278 LOG_ERROR(
"{}: Writing the magneticAndGravityReferenceVectorsRegister was not successfull.\n"
6279 "Target: magRef = {}, accRef = {}\n"
6280 "Sensor: magRef = {}, accRef = {}",
6283 vnMagneticAndGravityReferenceVectorsRegister.magRef, vnMagneticAndGravityReferenceVectorsRegister.accRef);
6289 if (
auto vnReferenceVectorConfigurationRegister =
_vs.readReferenceVectorConfiguration();
6296 LOG_ERROR(
"{}: Writing the referenceVectorConfigurationRegister was not successfull.\n"
6297 "Target: useMagModel = {}, useGravityModel = {}, recalcThreshold = {}, year = {}, position = {}\n"
6298 "Sensor: useMagModel = {}, useGravityModel = {}, recalcThreshold = {}, year = {}, position = {}",
6301 vnReferenceVectorConfigurationRegister.useMagModel, vnReferenceVectorConfigurationRegister.useGravityModel, vnReferenceVectorConfigurationRegister.recalcThreshold, vnReferenceVectorConfigurationRegister.year, vnReferenceVectorConfigurationRegister.position);
6313 if (
auto vnVelocityCompensationControlRegister =
_vs.readVelocityCompensationControl();
6318 LOG_ERROR(
"{}: Writing the velocityCompensationControlRegister was not successfull.\n"
6319 "Target: mode = {}, velocityTuning = {}, rateTuning = {}\n"
6320 "Sensor: mode = {}, velocityTuning = {}, rateTuning = {}",
6323 vnVelocityCompensationControlRegister.mode, vnVelocityCompensationControlRegister.velocityTuning, vnVelocityCompensationControlRegister.rateTuning);
6336 if (
auto vnAsyncDataOutputType =
_vs.readAsyncDataOutputType();
6339 LOG_ERROR(
"{}: Writing the asyncDataOutputType was not successfull.\n"
6344 vnAsyncDataOutputType);
6352 if (
auto vnAsyncDataOutputFrequency =
_vs.readAsyncDataOutputType();
6355 LOG_ERROR(
"{}: Writing the asyncDataOutputFrequency was not successfull.\n"
6360 vnAsyncDataOutputFrequency);
6366 [[maybe_unused]]
size_t binaryOutputRegisterCounter = 1;
6400 binaryOutputRegisterCounter++;
6408 binaryOutputRegisterCounter++;
6416 catch (
const std::exception& e)
6418 LOG_ERROR(
"{}: Could not configure binary output register {}: {}",
nameId(), binaryOutputRegisterCounter, e.what());
6425 _vs.writeSettings();
6427 LOG_DEBUG(
"{}: Resetting device to apply permenent settings",
nameId());
6446 if (
_vs.isConnected())
6450 _vs.unregisterAsyncPacketReceivedHandler();
6452 catch (
const std::exception& e)
6454 LOG_WARN(
"{}: Could not unregisterAsyncPacketReceivedHandler ({})",
nameId(), e.what());
6459 vn::sensors::BinaryOutputRegister bor{
6460 vn::protocol::uart::AsyncMode::ASYNCMODE_NONE,
6462 vn::protocol::uart::CommonGroup::COMMONGROUP_NONE,
6463 vn::protocol::uart::TimeGroup::TIMEGROUP_NONE,
6464 vn::protocol::uart::ImuGroup::IMUGROUP_NONE,
6465 vn::protocol::uart::GpsGroup::GPSGROUP_NONE,
6466 vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_NONE,
6467 vn::protocol::uart::InsGroup::INSGROUP_NONE,
6468 vn::protocol::uart::GpsGroup::GPSGROUP_NONE
6471 _vs.writeBinaryOutput1(bor);
6472 _vs.writeBinaryOutput2(bor);
6473 _vs.writeBinaryOutput3(bor);
6474 _vs.writeAsyncDataOutputType(vn::protocol::uart::AsciiAsync::VNOFF);
6476 _vs.writeSettings();
6479 catch (
const std::exception& e)
6481 LOG_WARN(
"{}: Could not turn off sensor output ({})",
nameId(), e.what());
6489 catch (
const std::exception& e)
6495 catch (
const std::exception& e)
6497 LOG_WARN(
"{}: Unhandled exception while deinitializing sensor ({})",
nameId(), e.what());
6503 target->insTime = !target->insTime.empty() ? target->insTime : source->insTime;
6505 if (!target->timeOutputs && source->timeOutputs)
6507 target->timeOutputs = source->timeOutputs;
6509 else if (target->timeOutputs && source->timeOutputs)
6511 target->timeOutputs->timeStartup = target->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP ? target->timeOutputs->timeStartup : source->timeOutputs->timeStartup;
6512 target->timeOutputs->timeGps = target->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEGPS ? target->timeOutputs->timeGps : source->timeOutputs->timeGps;
6513 target->timeOutputs->gpsTow = target->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW ? target->timeOutputs->gpsTow : source->timeOutputs->gpsTow;
6514 target->timeOutputs->gpsWeek = target->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK ? target->timeOutputs->gpsWeek : source->timeOutputs->gpsWeek;
6515 target->timeOutputs->timeSyncIn = target->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESYNCIN ? target->timeOutputs->timeSyncIn : source->timeOutputs->timeSyncIn;
6516 target->timeOutputs->timePPS = target->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEGPSPPS ? target->timeOutputs->timePPS : source->timeOutputs->timePPS;
6518 target->timeOutputs->syncInCnt = target->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_SYNCINCNT ? target->timeOutputs->syncInCnt : source->timeOutputs->syncInCnt;
6519 target->timeOutputs->syncOutCnt = target->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_SYNCOUTCNT ? target->timeOutputs->syncOutCnt : source->timeOutputs->syncOutCnt;
6520 target->timeOutputs->timeStatus = target->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS ? target->timeOutputs->timeStatus : source->timeOutputs->timeStatus;
6522 target->timeOutputs->timeField |= source->timeOutputs->timeField;
6525 if (!target->imuOutputs && source->imuOutputs)
6527 target->imuOutputs = source->imuOutputs;
6529 else if (target->imuOutputs && source->imuOutputs)
6531 target->imuOutputs->imuStatus = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_IMUSTATUS ? target->imuOutputs->imuStatus : source->imuOutputs->imuStatus;
6532 target->imuOutputs->uncompMag = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPMAG ? target->imuOutputs->uncompMag : source->imuOutputs->uncompMag;
6533 target->imuOutputs->uncompAccel = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPACCEL ? target->imuOutputs->uncompAccel : source->imuOutputs->uncompAccel;
6534 target->imuOutputs->uncompGyro = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPGYRO ? target->imuOutputs->uncompGyro : source->imuOutputs->uncompGyro;
6535 target->imuOutputs->temp = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_TEMP ? target->imuOutputs->temp : source->imuOutputs->temp;
6536 target->imuOutputs->pres = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_PRES ? target->imuOutputs->pres : source->imuOutputs->pres;
6537 target->imuOutputs->deltaTime = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTATHETA ? target->imuOutputs->deltaTime : source->imuOutputs->deltaTime;
6538 target->imuOutputs->deltaTheta = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTATHETA ? target->imuOutputs->deltaTheta : source->imuOutputs->deltaTheta;
6539 target->imuOutputs->deltaV = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTAVEL ? target->imuOutputs->deltaV : source->imuOutputs->deltaV;
6540 target->imuOutputs->mag = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_MAG ? target->imuOutputs->mag : source->imuOutputs->mag;
6541 target->imuOutputs->accel = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ACCEL ? target->imuOutputs->accel : source->imuOutputs->accel;
6542 target->imuOutputs->angularRate = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ANGULARRATE ? target->imuOutputs->angularRate : source->imuOutputs->angularRate;
6544 target->imuOutputs->imuField |= source->imuOutputs->imuField;
6547 if (!target->gnss1Outputs && source->gnss1Outputs)
6549 target->gnss1Outputs = source->gnss1Outputs;
6551 else if (target->gnss1Outputs && source->gnss1Outputs)
6554 target->gnss1Outputs->tow = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_TOW ? target->gnss1Outputs->tow : source->gnss1Outputs->tow;
6555 target->gnss1Outputs->week = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_WEEK ? target->gnss1Outputs->week : source->gnss1Outputs->week;
6556 target->gnss1Outputs->numSats = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_NUMSATS ? target->gnss1Outputs->numSats : source->gnss1Outputs->numSats;
6557 target->gnss1Outputs->fix = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_FIX ? target->gnss1Outputs->fix : source->gnss1Outputs->fix;
6558 target->gnss1Outputs->posLla = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_POSLLA ? target->gnss1Outputs->posLla : source->gnss1Outputs->posLla;
6559 target->gnss1Outputs->posEcef = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_POSECEF ? target->gnss1Outputs->posEcef : source->gnss1Outputs->posEcef;
6560 target->gnss1Outputs->velNed = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_VELNED ? target->gnss1Outputs->velNed : source->gnss1Outputs->velNed;
6561 target->gnss1Outputs->velEcef = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_VELECEF ? target->gnss1Outputs->velEcef : source->gnss1Outputs->velEcef;
6562 target->gnss1Outputs->posU = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_POSU ? target->gnss1Outputs->posU : source->gnss1Outputs->posU;
6563 target->gnss1Outputs->velU = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_VELU ? target->gnss1Outputs->velU : source->gnss1Outputs->velU;
6564 target->gnss1Outputs->timeU = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_TIMEU ? target->gnss1Outputs->timeU : source->gnss1Outputs->timeU;
6565 target->gnss1Outputs->timeInfo = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO ? target->gnss1Outputs->timeInfo : source->gnss1Outputs->timeInfo;
6566 target->gnss1Outputs->dop = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_DOP ? target->gnss1Outputs->dop : source->gnss1Outputs->dop;
6567 target->gnss1Outputs->satInfo = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_SATINFO ? target->gnss1Outputs->satInfo : source->gnss1Outputs->satInfo;
6568 target->gnss1Outputs->raw = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_RAWMEAS ? target->gnss1Outputs->raw : source->gnss1Outputs->raw;
6570 target->gnss1Outputs->gnssField |= source->gnss1Outputs->gnssField;
6573 if (!target->attitudeOutputs && source->attitudeOutputs)
6575 target->attitudeOutputs = source->attitudeOutputs;
6577 else if (target->attitudeOutputs && source->attitudeOutputs)
6579 target->attitudeOutputs->vpeStatus = target->attitudeOutputs->attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_VPESTATUS ? target->attitudeOutputs->vpeStatus : source->attitudeOutputs->vpeStatus;
6580 target->attitudeOutputs->ypr = target->attitudeOutputs->attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YAWPITCHROLL ? target->attitudeOutputs->ypr : source->attitudeOutputs->ypr;
6581 target->attitudeOutputs->qtn = target->attitudeOutputs->attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_QUATERNION ? target->attitudeOutputs->qtn : source->attitudeOutputs->qtn;
6582 target->attitudeOutputs->dcm = target->attitudeOutputs->attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_DCM ? target->attitudeOutputs->dcm : source->attitudeOutputs->dcm;
6583 target->attitudeOutputs->magNed = target->attitudeOutputs->attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_MAGNED ? target->attitudeOutputs->magNed : source->attitudeOutputs->magNed;
6584 target->attitudeOutputs->accelNed = target->attitudeOutputs->attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_ACCELNED ? target->attitudeOutputs->accelNed : source->attitudeOutputs->accelNed;
6585 target->attitudeOutputs->linearAccelBody = target->attitudeOutputs->attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELBODY ? target->attitudeOutputs->linearAccelBody : source->attitudeOutputs->linearAccelBody;
6586 target->attitudeOutputs->linearAccelNed = target->attitudeOutputs->attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELNED ? target->attitudeOutputs->linearAccelNed : source->attitudeOutputs->linearAccelNed;
6587 target->attitudeOutputs->yprU = target->attitudeOutputs->attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YPRU ? target->attitudeOutputs->yprU : source->attitudeOutputs->yprU;
6589 target->attitudeOutputs->attitudeField |= source->attitudeOutputs->attitudeField;
6592 if (!target->insOutputs && source->insOutputs)
6594 target->insOutputs = source->insOutputs;
6596 else if (target->insOutputs && source->insOutputs)
6598 target->insOutputs->insStatus = target->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_INSSTATUS ? target->insOutputs->insStatus : source->insOutputs->insStatus;
6599 target->insOutputs->posLla = target->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_POSLLA ? target->insOutputs->posLla : source->insOutputs->posLla;
6600 target->insOutputs->posEcef = target->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_POSECEF ? target->insOutputs->posEcef : source->insOutputs->posEcef;
6601 target->insOutputs->velBody = target->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_VELBODY ? target->insOutputs->velBody : source->insOutputs->velBody;
6602 target->insOutputs->velNed = target->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_VELNED ? target->insOutputs->velNed : source->insOutputs->velNed;
6603 target->insOutputs->velEcef = target->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_VELECEF ? target->insOutputs->velEcef : source->insOutputs->velEcef;
6604 target->insOutputs->magEcef = target->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_MAGECEF ? target->insOutputs->magEcef : source->insOutputs->magEcef;
6605 target->insOutputs->accelEcef = target->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_ACCELECEF ? target->insOutputs->accelEcef : source->insOutputs->accelEcef;
6606 target->insOutputs->linearAccelEcef = target->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_LINEARACCELECEF ? target->insOutputs->linearAccelEcef : source->insOutputs->linearAccelEcef;
6607 target->insOutputs->posU = target->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_POSU ? target->insOutputs->posU : source->insOutputs->posU;
6608 target->insOutputs->velU = target->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_VELU ? target->insOutputs->velU : source->insOutputs->velU;
6610 target->insOutputs->insField |= source->insOutputs->insField;
6613 if (!target->gnss2Outputs && source->gnss2Outputs)
6615 target->gnss2Outputs = source->gnss2Outputs;
6617 else if (target->gnss2Outputs && source->gnss2Outputs)
6620 target->gnss2Outputs->tow = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_TOW ? target->gnss2Outputs->tow : source->gnss2Outputs->tow;
6621 target->gnss2Outputs->week = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_WEEK ? target->gnss2Outputs->week : source->gnss2Outputs->week;
6622 target->gnss2Outputs->numSats = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_NUMSATS ? target->gnss2Outputs->numSats : source->gnss2Outputs->numSats;
6623 target->gnss2Outputs->fix = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_FIX ? target->gnss2Outputs->fix : source->gnss2Outputs->fix;
6624 target->gnss2Outputs->posLla = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_POSLLA ? target->gnss2Outputs->posLla : source->gnss2Outputs->posLla;
6625 target->gnss2Outputs->posEcef = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_POSECEF ? target->gnss2Outputs->posEcef : source->gnss2Outputs->posEcef;
6626 target->gnss2Outputs->velNed = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_VELNED ? target->gnss2Outputs->velNed : source->gnss2Outputs->velNed;
6627 target->gnss2Outputs->velEcef = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_VELECEF ? target->gnss2Outputs->velEcef : source->gnss2Outputs->velEcef;
6628 target->gnss2Outputs->posU = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_POSU ? target->gnss2Outputs->posU : source->gnss2Outputs->posU;
6629 target->gnss2Outputs->velU = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_VELU ? target->gnss2Outputs->velU : source->gnss2Outputs->velU;
6630 target->gnss2Outputs->timeU = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_TIMEU ? target->gnss2Outputs->timeU : source->gnss2Outputs->timeU;
6631 target->gnss2Outputs->timeInfo = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO ? target->gnss2Outputs->timeInfo : source->gnss2Outputs->timeInfo;
6632 target->gnss2Outputs->dop = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_DOP ? target->gnss2Outputs->dop : source->gnss2Outputs->dop;
6633 target->gnss2Outputs->satInfo = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_SATINFO ? target->gnss2Outputs->satInfo : source->gnss2Outputs->satInfo;
6634 target->gnss2Outputs->raw = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_RAWMEAS ? target->gnss2Outputs->raw : source->gnss2Outputs->raw;
6636 target->gnss2Outputs->gnssField |= source->gnss2Outputs->gnssField;
6644 LOG_DATA(
"{}: Received message", vnSensor->nameId());
6646 if (p.getPacketLength() > 2500)
6648 LOG_ERROR(
"{} Packet size is {} bytes. VectorNav internal buffer overflows happen if the size is > 2550 bytes. "
6649 "You potentially already lost packages without noticing. "
6650 "Consider splitting the packet to different Binary outputs.",
6651 vnSensor->nameId(), p.getPacketLength());
6653 else if (p.getPacketLength() > 2200)
6655 LOG_WARN(
"{} Packet size is {} bytes. VectorNav internal buffer overflows happen if the size is > 2550 bytes. "
6656 "Consider splitting the packet to different Binary outputs.",
6657 vnSensor->nameId(), p.getPacketLength());
6660 if (p.type() == vn::protocol::uart::Packet::TYPE_BINARY)
6662 for (
size_t b = 0; b < 3; b++)
6665 if (p.isCompatible(vnSensor->_binaryOutputRegister.at(b).commonField,
6666 vnSensor->_binaryOutputRegister.at(b).timeField,
6667 vnSensor->_binaryOutputRegister.at(b).imuField,
6668 vnSensor->_binaryOutputRegister.at(b).gpsField,
6669 vnSensor->_binaryOutputRegister.at(b).attitudeField,
6670 vnSensor->_binaryOutputRegister.at(b).insField,
6671 vnSensor->_binaryOutputRegister.at(b).gps2Field))
6673 auto obs = std::make_shared<VectorNavBinaryOutput>(vnSensor->_imuPos);
6676 if (vnSensor->_binaryOutputRegister.at(b).timeField != vn::protocol::uart::TimeGroup::TIMEGROUP_NONE)
6678 if (!obs->timeOutputs)
6680 obs->timeOutputs = std::make_shared<NAV::vendor::vectornav::TimeOutputs>();
6681 obs->timeOutputs->timeField |= vnSensor->_binaryOutputRegister.at(b).timeField;
6684 if (vnSensor->_binaryOutputRegister.at(b).timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP)
6686 obs->timeOutputs->timeStartup = p.extractUint64();
6688 if (vnSensor->_binaryOutputRegister.at(b).timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEGPS)
6690 obs->timeOutputs->timeGps = p.extractUint64();
6692 if (vnSensor->_binaryOutputRegister.at(b).timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)
6694 obs->timeOutputs->gpsTow = p.extractUint64();
6696 if (vnSensor->_binaryOutputRegister.at(b).timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK)
6698 obs->timeOutputs->gpsWeek = p.extractUint16();
6700 if (vnSensor->_binaryOutputRegister.at(b).timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESYNCIN)
6702 obs->timeOutputs->timeSyncIn = p.extractUint64();
6704 if (vnSensor->_binaryOutputRegister.at(b).timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEGPSPPS)
6706 obs->timeOutputs->timePPS = p.extractUint64();
6718 if (vnSensor->_binaryOutputRegister.at(b).timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_SYNCINCNT)
6720 obs->timeOutputs->syncInCnt = p.extractUint32();
6722 if (vnSensor->_binaryOutputRegister.at(b).timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_SYNCOUTCNT)
6724 obs->timeOutputs->syncOutCnt = p.extractUint32();
6726 if (vnSensor->_binaryOutputRegister.at(b).timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS)
6728 obs->timeOutputs->timeStatus = p.extractUint8();
6732 if (vnSensor->_binaryOutputRegister.at(b).imuField != vn::protocol::uart::ImuGroup::IMUGROUP_NONE)
6734 if (!obs->imuOutputs)
6736 obs->imuOutputs = std::make_shared<NAV::vendor::vectornav::ImuOutputs>();
6737 obs->imuOutputs->imuField |= vnSensor->_binaryOutputRegister.at(b).imuField;
6740 if (vnSensor->_binaryOutputRegister.at(b).imuField & vn::protocol::uart::ImuGroup::IMUGROUP_IMUSTATUS)
6742 obs->imuOutputs->imuStatus = p.extractUint16();
6744 if (vnSensor->_binaryOutputRegister.at(b).imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPMAG)
6746 auto vec = p.extractVec3f();
6747 obs->imuOutputs->uncompMag = { vec.x, vec.y, vec.z };
6749 if (vnSensor->_binaryOutputRegister.at(b).imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPACCEL)
6751 auto vec = p.extractVec3f();
6752 obs->imuOutputs->uncompAccel = { vec.x, vec.y, vec.z };
6754 if (vnSensor->_binaryOutputRegister.at(b).imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPGYRO)
6756 auto vec = p.extractVec3f();
6757 obs->imuOutputs->uncompGyro = { vec.x, vec.y, vec.z };
6759 if (vnSensor->_binaryOutputRegister.at(b).imuField & vn::protocol::uart::ImuGroup::IMUGROUP_TEMP)
6761 obs->imuOutputs->temp = p.extractFloat();
6763 if (vnSensor->_binaryOutputRegister.at(b).imuField & vn::protocol::uart::ImuGroup::IMUGROUP_PRES)
6765 obs->imuOutputs->pres = p.extractFloat();
6767 if (vnSensor->_binaryOutputRegister.at(b).imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTATHETA)
6769 obs->imuOutputs->deltaTime = p.extractFloat();
6770 auto vec = p.extractVec3f();
6771 obs->imuOutputs->deltaTheta = { vec.x, vec.y, vec.z };
6773 if (vnSensor->_binaryOutputRegister.at(b).imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTAVEL)
6775 auto vec = p.extractVec3f();
6776 obs->imuOutputs->deltaV = { vec.x, vec.y, vec.z };
6778 if (vnSensor->_binaryOutputRegister.at(b).imuField & vn::protocol::uart::ImuGroup::IMUGROUP_MAG)
6780 auto vec = p.extractVec3f();
6781 obs->imuOutputs->mag = { vec.x, vec.y, vec.z };
6783 if (vnSensor->_binaryOutputRegister.at(b).imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ACCEL)
6785 auto vec = p.extractVec3f();
6786 obs->imuOutputs->accel = { vec.x, vec.y, vec.z };
6788 if (vnSensor->_binaryOutputRegister.at(b).imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ANGULARRATE)
6790 auto vec = p.extractVec3f();
6791 obs->imuOutputs->angularRate = { vec.x, vec.y, vec.z };
6795 if (vnSensor->_binaryOutputRegister.at(b).gpsField != vn::protocol::uart::GpsGroup::GPSGROUP_NONE)
6797 if (!obs->gnss1Outputs)
6799 obs->gnss1Outputs = std::make_shared<NAV::vendor::vectornav::GnssOutputs>();
6800 obs->gnss1Outputs->gnssField |= vnSensor->_binaryOutputRegister.at(b).gpsField;
6813 if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_TOW)
6815 obs->gnss1Outputs->tow = p.extractUint64();
6817 if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_WEEK)
6819 obs->gnss1Outputs->week = p.extractUint16();
6821 if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_NUMSATS)
6823 obs->gnss1Outputs->numSats = p.extractUint8();
6825 if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_FIX)
6827 obs->gnss1Outputs->fix = p.extractUint8();
6829 if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_POSLLA)
6831 auto vec = p.extractVec3d();
6832 obs->gnss1Outputs->posLla = { vec.x, vec.y, vec.z };
6834 if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_POSECEF)
6836 auto vec = p.extractVec3d();
6837 obs->gnss1Outputs->posEcef = { vec.x, vec.y, vec.z };
6839 if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_VELNED)
6841 auto vec = p.extractVec3f();
6842 obs->gnss1Outputs->velNed = { vec.x, vec.y, vec.z };
6844 if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_VELECEF)
6846 auto vec = p.extractVec3f();
6847 obs->gnss1Outputs->velEcef = { vec.x, vec.y, vec.z };
6849 if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_POSU)
6851 auto vec = p.extractVec3f();
6852 obs->gnss1Outputs->posU = { vec.x, vec.y, vec.z };
6854 if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_VELU)
6856 obs->gnss1Outputs->velU = p.extractFloat();
6858 if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_TIMEU)
6860 obs->gnss1Outputs->timeU = p.extractFloat();
6862 if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO)
6864 obs->gnss1Outputs->timeInfo.status = p.extractUint8();
6865 obs->gnss1Outputs->timeInfo.leapSeconds = p.extractInt8();
6867 if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_DOP)
6869 obs->gnss1Outputs->dop.gDop = p.extractFloat();
6870 obs->gnss1Outputs->dop.pDop = p.extractFloat();
6871 obs->gnss1Outputs->dop.tDop = p.extractFloat();
6872 obs->gnss1Outputs->dop.vDop = p.extractFloat();
6873 obs->gnss1Outputs->dop.hDop = p.extractFloat();
6874 obs->gnss1Outputs->dop.nDop = p.extractFloat();
6875 obs->gnss1Outputs->dop.eDop = p.extractFloat();
6877 if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_SATINFO)
6879 obs->gnss1Outputs->satInfo.numSats = p.extractUint8();
6882 LOG_DATA(
"{}: SatInfo: numSats {}", vnSensor->nameId(), obs->gnss1Outputs->satInfo.numSats);
6883 for (
size_t i = 0; i < obs->gnss1Outputs->satInfo.numSats; i++)
6885 auto sys = p.extractInt8();
6886 auto svId = p.extractUint8();
6887 auto flags = p.extractUint8();
6888 auto cno = p.extractUint8();
6889 auto qi = p.extractUint8();
6890 auto el = p.extractInt8();
6891 auto az = p.extractInt16();
6892 obs->gnss1Outputs->satInfo.satellites.emplace_back(sys, svId, flags, cno, qi, el, az);
6893 LOG_DATA(
"{}: SatInfo: sys {}, svId {}, flags {}, cno {}, qi {}, el {}, az {}", vnSensor->nameId(),
6894 sys, svId, flags, cno, qi, el, az);
6897 if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_RAWMEAS)
6899 obs->gnss1Outputs->raw.tow = p.extractDouble();
6900 obs->gnss1Outputs->raw.week = p.extractUint16();
6901 obs->gnss1Outputs->raw.numSats = p.extractUint8();
6903 LOG_DATA(
"{}: RawMeas: tow {}, week {}, numSats {}", vnSensor->nameId(),
6904 obs->gnss1Outputs->raw.tow, obs->gnss1Outputs->raw.week, obs->gnss1Outputs->raw.numSats);
6906 for (
size_t i = 0; i < obs->gnss1Outputs->raw.numSats; i++)
6908 auto sys = p.extractUint8();
6909 auto svId = p.extractUint8();
6910 auto freq = p.extractUint8();
6911 auto chan = p.extractUint8();
6912 auto slot = p.extractInt8();
6913 auto cno = p.extractUint8();
6914 auto flags = p.extractUint16();
6915 auto pr = p.extractDouble();
6916 auto cp = p.extractDouble();
6917 auto dp = p.extractFloat();
6918 obs->gnss1Outputs->raw.satellites.emplace_back(sys, svId, freq, chan, slot, cno, flags, pr, cp, dp);
6919 LOG_DATA(
"{}: RawMeas: sys {}, svId {}, freq {}, chan {}, slot {}, cno {}, flags {}, pr {}, cp {}, dp {}",
6920 vnSensor->nameId(),
static_cast<int>(sys),
static_cast<int>(svId),
static_cast<int>(freq),
static_cast<int>(chan),
6921 static_cast<int>(slot),
static_cast<int>(cno),
static_cast<int>(flags), pr, cp, dp);
6926 if (vnSensor->_binaryOutputRegister.at(b).attitudeField != vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_NONE)
6928 if (!obs->attitudeOutputs)
6930 obs->attitudeOutputs = std::make_shared<NAV::vendor::vectornav::AttitudeOutputs>();
6931 obs->attitudeOutputs->attitudeField |= vnSensor->_binaryOutputRegister.at(b).attitudeField;
6934 if (vnSensor->_binaryOutputRegister.at(b).attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_VPESTATUS)
6936 obs->attitudeOutputs->vpeStatus = p.extractUint16();
6938 if (vnSensor->_binaryOutputRegister.at(b).attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YAWPITCHROLL)
6940 auto vec = p.extractVec3f();
6941 obs->attitudeOutputs->ypr = { vec.x, vec.y, vec.z };
6943 if (vnSensor->_binaryOutputRegister.at(b).attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_QUATERNION)
6945 auto vec = p.extractVec4f();
6946 obs->attitudeOutputs->qtn = { vec.w, vec.x, vec.y, vec.z };
6948 if (vnSensor->_binaryOutputRegister.at(b).attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_DCM)
6950 auto col0 = p.extractVec3f();
6951 auto col1 = p.extractVec3f();
6952 auto col2 = p.extractVec3f();
6953 obs->attitudeOutputs->dcm << col0.x, col1.x, col2.x,
6954 col0.y, col1.y, col2.y,
6955 col0.z, col1.z, col2.z;
6957 if (vnSensor->_binaryOutputRegister.at(b).attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_MAGNED)
6959 auto vec = p.extractVec3f();
6960 obs->attitudeOutputs->magNed = { vec.x, vec.y, vec.z };
6962 if (vnSensor->_binaryOutputRegister.at(b).attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_ACCELNED)
6964 auto vec = p.extractVec3f();
6965 obs->attitudeOutputs->accelNed = { vec.x, vec.y, vec.z };
6967 if (vnSensor->_binaryOutputRegister.at(b).attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELBODY)
6969 auto vec = p.extractVec3f();
6970 obs->attitudeOutputs->linearAccelBody = { vec.x, vec.y, vec.z };
6972 if (vnSensor->_binaryOutputRegister.at(b).attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELNED)
6974 auto vec = p.extractVec3f();
6975 obs->attitudeOutputs->linearAccelNed = { vec.x, vec.y, vec.z };
6977 if (vnSensor->_binaryOutputRegister.at(b).attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YPRU)
6979 auto vec = p.extractVec3f();
6980 obs->attitudeOutputs->yprU = { vec.x, vec.y, vec.z };
6984 if (vnSensor->_binaryOutputRegister.at(b).insField != vn::protocol::uart::InsGroup::INSGROUP_NONE)
6986 if (!obs->insOutputs)
6988 obs->insOutputs = std::make_shared<NAV::vendor::vectornav::InsOutputs>();
6989 obs->insOutputs->insField |= vnSensor->_binaryOutputRegister.at(b).insField;
6992 if (vnSensor->_binaryOutputRegister.at(b).insField & vn::protocol::uart::InsGroup::INSGROUP_INSSTATUS)
6994 obs->insOutputs->insStatus = p.extractUint16();
6996 if (vnSensor->_binaryOutputRegister.at(b).insField & vn::protocol::uart::InsGroup::INSGROUP_POSLLA)
6998 auto vec = p.extractVec3d();
6999 obs->insOutputs->posLla = { vec.x, vec.y, vec.z };
7001 if (vnSensor->_binaryOutputRegister.at(b).insField & vn::protocol::uart::InsGroup::INSGROUP_POSECEF)
7003 auto vec = p.extractVec3d();
7004 obs->insOutputs->posEcef = { vec.x, vec.y, vec.z };
7006 if (vnSensor->_binaryOutputRegister.at(b).insField & vn::protocol::uart::InsGroup::INSGROUP_VELBODY)
7008 auto vec = p.extractVec3f();
7009 obs->insOutputs->velBody = { vec.x, vec.y, vec.z };
7011 if (vnSensor->_binaryOutputRegister.at(b).insField & vn::protocol::uart::InsGroup::INSGROUP_VELNED)
7013 auto vec = p.extractVec3f();
7014 obs->insOutputs->velNed = { vec.x, vec.y, vec.z };
7016 if (vnSensor->_binaryOutputRegister.at(b).insField & vn::protocol::uart::InsGroup::INSGROUP_VELECEF)
7018 auto vec = p.extractVec3f();
7019 obs->insOutputs->velEcef = { vec.x, vec.y, vec.z };
7021 if (vnSensor->_binaryOutputRegister.at(b).insField & vn::protocol::uart::InsGroup::INSGROUP_MAGECEF)
7023 auto vec = p.extractVec3f();
7024 obs->insOutputs->magEcef = { vec.x, vec.y, vec.z };
7026 if (vnSensor->_binaryOutputRegister.at(b).insField & vn::protocol::uart::InsGroup::INSGROUP_ACCELECEF)
7028 auto vec = p.extractVec3f();
7029 obs->insOutputs->accelEcef = { vec.x, vec.y, vec.z };
7031 if (vnSensor->_binaryOutputRegister.at(b).insField & vn::protocol::uart::InsGroup::INSGROUP_LINEARACCELECEF)
7033 auto vec = p.extractVec3f();
7034 obs->insOutputs->linearAccelEcef = { vec.x, vec.y, vec.z };
7036 if (vnSensor->_binaryOutputRegister.at(b).insField & vn::protocol::uart::InsGroup::INSGROUP_POSU)
7038 obs->insOutputs->posU = p.extractFloat();
7040 if (vnSensor->_binaryOutputRegister.at(b).insField & vn::protocol::uart::InsGroup::INSGROUP_VELU)
7042 obs->insOutputs->velU = p.extractFloat();
7046 if (vnSensor->_binaryOutputRegister.at(b).gps2Field != vn::protocol::uart::GpsGroup::GPSGROUP_NONE)
7048 if (!obs->gnss2Outputs)
7050 obs->gnss2Outputs = std::make_shared<NAV::vendor::vectornav::GnssOutputs>();
7051 obs->gnss2Outputs->gnssField |= vnSensor->_binaryOutputRegister.at(b).gps2Field;
7064 if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_TOW)
7066 obs->gnss2Outputs->tow = p.extractUint64();
7068 if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_WEEK)
7070 obs->gnss2Outputs->week = p.extractUint16();
7072 if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_NUMSATS)
7074 obs->gnss2Outputs->numSats = p.extractUint8();
7076 if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_FIX)
7078 obs->gnss2Outputs->fix = p.extractUint8();
7080 if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_POSLLA)
7082 auto vec = p.extractVec3d();
7083 obs->gnss2Outputs->posLla = { vec.x, vec.y, vec.z };
7085 if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_POSECEF)
7087 auto vec = p.extractVec3d();
7088 obs->gnss2Outputs->posEcef = { vec.x, vec.y, vec.z };
7090 if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_VELNED)
7092 auto vec = p.extractVec3f();
7093 obs->gnss2Outputs->velNed = { vec.x, vec.y, vec.z };
7095 if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_VELECEF)
7097 auto vec = p.extractVec3f();
7098 obs->gnss2Outputs->velEcef = { vec.x, vec.y, vec.z };
7100 if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_POSU)
7102 auto vec = p.extractVec3f();
7103 obs->gnss2Outputs->posU = { vec.x, vec.y, vec.z };
7105 if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_VELU)
7107 obs->gnss2Outputs->velU = p.extractFloat();
7109 if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_TIMEU)
7111 obs->gnss2Outputs->timeU = p.extractFloat();
7113 if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO)
7115 obs->gnss2Outputs->timeInfo.status = p.extractUint8();
7116 obs->gnss2Outputs->timeInfo.leapSeconds = p.extractInt8();
7118 if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_DOP)
7120 obs->gnss2Outputs->dop.gDop = p.extractFloat();
7121 obs->gnss2Outputs->dop.pDop = p.extractFloat();
7122 obs->gnss2Outputs->dop.tDop = p.extractFloat();
7123 obs->gnss2Outputs->dop.vDop = p.extractFloat();
7124 obs->gnss2Outputs->dop.hDop = p.extractFloat();
7125 obs->gnss2Outputs->dop.nDop = p.extractFloat();
7126 obs->gnss2Outputs->dop.eDop = p.extractFloat();
7128 if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_SATINFO)
7130 obs->gnss2Outputs->satInfo.numSats = p.extractUint8();
7132 for (
size_t i = 0; i < obs->gnss2Outputs->satInfo.numSats; i++)
7134 auto sys = p.extractInt8();
7135 auto svId = p.extractUint8();
7136 auto flags = p.extractUint8();
7137 auto cno = p.extractUint8();
7138 auto qi = p.extractUint8();
7139 auto el = p.extractInt8();
7140 auto az = p.extractInt16();
7141 obs->gnss2Outputs->satInfo.satellites.emplace_back(sys, svId, flags, cno, qi, el, az);
7144 if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_RAWMEAS)
7146 obs->gnss2Outputs->raw.tow = p.extractDouble();
7147 obs->gnss2Outputs->raw.week = p.extractUint16();
7148 obs->gnss2Outputs->raw.numSats = p.extractUint8();
7150 for (
size_t i = 0; i < obs->gnss2Outputs->raw.numSats; i++)
7152 auto sys = p.extractUint8();
7153 auto svId = p.extractUint8();
7154 auto freq = p.extractUint8();
7155 auto chan = p.extractUint8();
7156 auto slot = p.extractInt8();
7157 auto cno = p.extractUint8();
7158 auto flags = p.extractUint16();
7159 auto pr = p.extractDouble();
7160 auto cp = p.extractDouble();
7161 auto dp = p.extractFloat();
7162 obs->gnss2Outputs->raw.satellites.emplace_back(sys, svId, freq, chan, slot, cno, flags, pr, cp, dp);
7167 if (p.getCurExtractLoc() != p.getPacketLength() - 2)
7169 LOG_DEBUG(
"{}: Only {} of {} bytes were extracted from the Binary Output {}", vnSensor->nameId(), p.getCurExtractLoc(), p.getPacketLength(), b + 1);
7173 auto updateSyncOut = [vnSensor, obs](
const InsTime& ppsTime) {
7174 if (vnSensor->_synchronizationControlRegister.syncOutMode == vn::protocol::uart::SYNCOUTMODE_GPSPPS
7175 && (obs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_SYNCOUTCNT))
7177 if (obs->timeOutputs->syncOutCnt > 0)
7179 if (vnSensor->_timeSyncOut.syncOutCnt == 0)
7181 LOG_INFO(
"{}: Found PPS time {} and is providing it to its connected nodes", vnSensor->nameId(), ppsTime.toYMDHMS(
GPST));
7183 if (vnSensor->_timeSyncOut.ppsTime != ppsTime || vnSensor->_timeSyncOut.syncOutCnt != obs->timeOutputs->syncOutCnt)
7185 LOG_DATA(
"{}: SyncOut time {}, pps {}, syncOutCnt {}",
7186 vnSensor->nameId(), obs->insTime.toYMDHMS(
GPST),
7187 ppsTime.toYMDHMS(
GPST), obs->timeOutputs->syncOutCnt);
7189 vnSensor->_timeSyncOut.ppsTime = ppsTime;
7190 vnSensor->_timeSyncOut.syncOutCnt = obs->timeOutputs->syncOutCnt;
7196 if (obs->timeOutputs && (obs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS))
7198 if (obs->timeOutputs->timeStatus.dateOk())
7200 if (obs->timeOutputs->timeStatus.timeOk()
7201 && (obs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)
7202 && (obs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK))
7205 updateSyncOut(
InsTime(0, obs->timeOutputs->gpsWeek, std::floor(obs->timeOutputs->gpsTow * 1e-9L)));
7207 else if (obs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEGPS)
7209 auto secondsSinceEpoche =
static_cast<long double>(obs->timeOutputs->timeGps) * 1e-9L;
7214 updateSyncOut(
InsTime(0, week, std::floor(tow)));
7219 if (obs->insTime.empty()
7220 && (obs->timeOutputs->timeField & vn::protocol::uart::TIMEGROUP_SYNCINCNT)
7221 && (obs->timeOutputs->timeField & vn::protocol::uart::TIMEGROUP_TIMESYNCIN)
7222 && vnSensor->_syncInPin && vnSensor->inputPins.front().isPinLinked())
7224 if (
auto timeSyncMaster = vnSensor->getInputValue<
TimeSync>(0);
7231 int64_t syncCntDiff = obs->timeOutputs->syncInCnt - timeSyncMaster->v->syncOutCnt - vnSensor->_syncCntOffset;
7233 if (std::abs(syncCntDiff) > 1)
7235 vnSensor->_syncCntOffset = obs->timeOutputs->syncInCnt - timeSyncMaster->v->syncOutCnt;
7236 syncCntDiff -= vnSensor->_syncCntOffset;
7237 LOG_DEBUG(
"{}: Counters did not start at the same time (_syncCntOffset = {})", vnSensor->nameId(), vnSensor->_syncCntOffset);
7239 vnSensor->_lastSyncOutCnt = timeSyncMaster->v->syncOutCnt;
7240 vnSensor->_lastSyncInCnt = obs->timeOutputs->syncInCnt;
7242 obs->insTime = timeSyncMaster->v->ppsTime + std::chrono::nanoseconds(obs->timeOutputs->timeSyncIn)
7243 + std::chrono::seconds(syncCntDiff);
7244 LOG_DATA(
"{}: SyncIn time {}, pps {}, syncOutCnt {}, syncInCnt {}, syncCntDiff {}",
7245 vnSensor->nameId(), obs->insTime.toYMDHMS(
GPST), timeSyncMaster->v->ppsTime.toYMDHMS(
GPST),
7246 timeSyncMaster->v->syncOutCnt, obs->timeOutputs->syncInCnt, syncCntDiff);
7254 if (obs->insTime.empty()
7255 && !vnSensor->_lastMessageTime.at(b).empty()
7256 && obs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP)
7258 obs->insTime = vnSensor->_lastMessageTime.at(b) + std::chrono::nanoseconds(obs->timeOutputs->timeStartup - vnSensor->_lastMessageTimeSinceStartup.at(b));
7261 if (obs->insTime.empty()
7262 && !(obs->timeOutputs
7263 && (obs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS)
7264 && (obs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)
7265 && (obs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK)))
7267 if (
InsTime currentTime = util::time::GetCurrentInsTime();
7268 !currentTime.
empty())
7270 obs->insTime = currentTime;
7274 if (!obs->insTime.empty())
7276 if (!vnSensor->_lastMessageTime.at(b).empty())
7280 if (obs->insTime - vnSensor->_lastMessageTime.at(b) >= std::chrono::duration<double>(1.5 * (vnSensor->_binaryOutputRegister.at(b).rateDivisor /
IMU_DEFAULT_FREQUENCY)))
7282 LOG_WARN(
"{}: Potentially lost a message. dt = {:.4} s, expect {} s. (Previous message at [{}], current message [{}])", vnSensor->nameId(),
7283 static_cast<double>((obs->insTime - vnSensor->_lastMessageTime.at(b)).count()),
7285 vnSensor->_lastMessageTime.at(b), obs->insTime);
7288 vnSensor->_lastMessageTime.at(b) = obs->insTime;
7289 if (obs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP)
7291 vnSensor->_lastMessageTimeSinceStartup.at(b) = obs->timeOutputs->timeStartup;
7299 if (vnSensor->_binaryOutputRegisterMergeObservation ==
nullptr)
7301 std::stringstream sstream;
7302 if (!obs->insTime.empty())
7304 sstream << obs->insTime;
7308 sstream << obs->timeOutputs->timeStartup;
7310 LOG_DATA(
"{}: {} - Storing message with time {}", vnSensor->nameId(), b, sstream.str());
7312 vnSensor->_binaryOutputRegisterMergeObservation = obs;
7313 vnSensor->_binaryOutputRegisterMergeIndex = b;
7317 auto allowedTimeDiff = std::chrono::microseconds(
static_cast<int>(0.5 * (vnSensor->_binaryOutputRegister.at(b).rateDivisor /
IMU_DEFAULT_FREQUENCY) * 1e6));
7318 if (vnSensor->_binaryOutputRegisterMergeIndex != b
7319 && ((!obs->insTime.empty() && !vnSensor->_binaryOutputRegisterMergeObservation->insTime.empty()
7320 && (obs->insTime - vnSensor->_binaryOutputRegisterMergeObservation->insTime < allowedTimeDiff))
7321 || (obs->timeOutputs !=
nullptr && vnSensor->_binaryOutputRegisterMergeObservation->timeOutputs !=
nullptr
7322 && obs->timeOutputs->timeField & vn::protocol::uart::TIMEGROUP_TIMESTARTUP
7323 && vnSensor->_binaryOutputRegisterMergeObservation->timeOutputs->timeField & vn::protocol::uart::TIMEGROUP_TIMESTARTUP
7324 && (std::chrono::nanoseconds(obs->timeOutputs->timeStartup - vnSensor->_binaryOutputRegisterMergeObservation->timeOutputs->timeStartup) < allowedTimeDiff))))
7328 vnSensor->_binaryOutputRegisterMergeObservation =
nullptr;
7330 std::stringstream sstream;
7331 if (!obs->insTime.empty())
7333 sstream << obs->insTime;
7337 sstream << obs->timeOutputs->timeStartup;
7339 LOG_DATA(
"{}: {} - Merged message with time {}", vnSensor->nameId(), b, sstream.str());
7341 vnSensor->invokeCallbacks(std::min(b, vnSensor->_binaryOutputRegisterMergeIndex) + 1, obs);
7345 [[maybe_unused]]
long double timeDiff = 0.0L;
7346 std::stringstream sstreamOld;
7347 std::stringstream sstreamNew;
7348 if (!obs->insTime.empty() && !vnSensor->_binaryOutputRegisterMergeObservation->insTime.empty())
7350 timeDiff = (obs->insTime - vnSensor->_binaryOutputRegisterMergeObservation->insTime).count();
7351 sstreamOld << vnSensor->_binaryOutputRegisterMergeObservation->insTime;
7352 sstreamNew << obs->insTime;
7356 sstreamOld << vnSensor->_binaryOutputRegisterMergeObservation->timeOutputs->timeStartup;
7357 sstreamNew << obs->timeOutputs->timeStartup;
7358 timeDiff =
static_cast<double>(obs->timeOutputs->timeStartup
7359 - vnSensor->_binaryOutputRegisterMergeObservation->timeOutputs->timeStartup)
7363 LOG_WARN(
"{}: Merging failed, because timestamps do not match. Potentially lost a message (diff {} sec, old ({}) {}, new ({}) {})",
7364 vnSensor->nameId(), timeDiff, vnSensor->_binaryOutputRegisterMergeIndex, sstreamOld.str(), b, sstreamNew.str());
7367 vnSensor->invokeCallbacks(vnSensor->_binaryOutputRegisterMergeIndex + 1, vnSensor->_binaryOutputRegisterMergeObservation);
7368 vnSensor->_binaryOutputRegisterMergeObservation = obs;
7369 vnSensor->_binaryOutputRegisterMergeIndex = b;
7375 if (!obs->insTime.empty())
7377 LOG_DATA(
"{}: {} - Normal message with time {}", vnSensor->nameId(), b, obs->insTime);
7380 vnSensor->invokeCallbacks(b + 1, obs);
7385 else if (p.type() == vn::protocol::uart::Packet::TYPE_ASCII)
7387 LOG_DATA(
"{} received an ASCII Async message: {}", vnSensor->nameId(), p.datastr());
7388 vnSensor->_asciiOutputBuffer.push_back(p.datastr());
7390 auto obs = std::make_shared<StringObs>(p.datastr());
7392 if (
InsTime currentTime = util::time::GetCurrentInsTime();
7393 !currentTime.
empty())
7395 obs->insTime = currentTime;
Transformation collection.
nlohmann::json json
json namespace
Text Help Marker (?) with Tooltip.
Utility class for logging to console and file.
#define LOG_DEBUG
Debug information. Should not be called on functions which receive observations (spamming)
#define LOG_DATA
All output which occurs repeatedly every time observations are received.
#define LOG_ERROR
Error occurred, which stops part of the program to work, but not everything.
#define LOG_WARN
Error occurred, but a fallback option exists and program continues to work normally.
#define LOG_INFO
Info to the user on the state of the program.
#define LOG_TRACE
Detailled info to trace the execution of the program. Should not be called on functions which receive...
Wrapper for String Messages.
Keeps track of the current real/simulation time.
Type Definitions for VectorNav messages.
Imu(const Imu &)=delete
Copy constructor.
The class is responsible for all time-related tasks.
constexpr bool empty() const
Checks if the Time object has a value.
void reset()
Resets the InsTime object.
bool isInitialized() const
Checks if the node is initialized.
bool doDeinitialize(bool wait=false)
Asks the node worker to deinitialize the node.
ImVec2 _guiConfigDefaultWindowSize
std::vector< OutputPin > outputPins
List of output pins.
bool DeleteOutputPin(size_t pinIndex)
Deletes the output pin. Invalidates the pin reference given.
std::vector< InputPin > inputPins
List of input pins.
OutputPin * CreateOutputPin(const char *name, Pin::Type pinType, const std::vector< std::string > &dataIdentifier, OutputPin::PinData data=static_cast< void * >(nullptr), int idx=-1)
Create an Output Pin object.
std::string nameId() const
Node name and id.
std::string name
Name of the Node.
bool _onlyRealTime
Whether the node can run in post-processing or only real-time.
InputPin * CreateInputPin(const char *name, Pin::Type pinType, const std::vector< std::string > &dataIdentifier={}, InputPin::Callback callback=static_cast< InputPin::FlowFirableCallbackFunc >(nullptr), InputPin::FlowFirableCheckFunc firable=nullptr, int priority=0, int idx=-1)
Create an Input Pin object.
bool DeleteInputPin(size_t pinIndex)
Deletes the input pin. Invalidates the pin reference given.
bool _hasConfig
Flag if the config window should be shown.
static std::string type()
Returns the type of the data class.
int _selectedBaudrate
Baudrate for the sensor.
Baudrate
Available Baudrates.
@ BAUDRATE_115200
Baudrate with 115200 symbols per second [Baud].
@ BAUDRATE_FASTEST
Fastest possible Baudrate will be automatically chosen.
void restore(const json &j)
Restores the node from a json object.
Baudrate sensorBaudrate() const
Returns the Baudrate for the element Selected by the GUI.
json save() const
Saves the node into a json object.
static std::string type()
Returns the type of the data class.
static constexpr size_t OUTPUT_PORT_INDEX_ASCII_OUTPUT
Flow (StringObs)
std::array< vn::sensors::BinaryOutputRegister, 3 > _binaryOutputRegister
Binary Output Register 1 - 3.
int64_t _lastSyncOutCnt
Last received syncOutCnt.
vn::sensors::MagnetometerCalibrationControlRegister _magnetometerCalibrationControlRegister
Magnetometer Calibration Control.
static std::string typeStatic()
String representation of the Class Type.
std::array< uint64_t, 3 > _lastMessageTimeSinceStartup
Stores the time of the last received message.
static std::string category()
String representation of the Class Category.
vn::sensors::VpeAccelerometerBasicTuningRegister _vpeAccelerometerBasicTuningRegister
VPE Accelerometer Basic Tuning.
json save() const override
Saves the node into a json object.
vn::sensors::MagneticAndGravityReferenceVectorsRegister _magneticAndGravityReferenceVectorsRegister
Magnetic and Gravity Reference Vectors.
static constexpr std::array _possibleAsyncDataOutputFrequency
Possible values for the Async Data Output Frequency Register.
int _asyncDataOutputFrequencySelected
Selected Frequency of the Async Ascii Output in the GUI.
std::array< InsTime, 3 > _lastMessageTime
Stores the time of the last received message.
static const std::array< BinaryGroupData, 10 > _binaryGroupTime
Binary group 1 contains a wide assortment of commonly used data required for most applications.
vn::math::vec3f _filterStartupGyroBias
Filter Startup Gyro Bias.
std::string type() const override
String representation of the Class Type.
static const std::array< BinaryGroupData, 11 > _binaryGroupIMU
Binary group 3 provides all outputs which are dependent upon the measurements collected from the onbo...
VectorNavModel _sensorModel
The sensor model which is selected in the GUI.
bool _coupleImuRateOutput
Couple the ImuFilter's rate (window size of moving-average filter) to the output rate (rateDivisor)
static void coupleImuFilterRates(NAV::VectorNavSensor *sensor, vn::sensors::BinaryOutputRegister &bor, uint32_t &binaryField)
Updates the ImuFilter's rate when pressing the checkbox button.
@ Output1_Output2
Merge Output 1 and 2.
@ Output2_Output3
Merge Output 2 and 3.
@ Output1_Output3
Merge Output 1 and 3.
vn::sensors::DeltaThetaAndDeltaVelocityConfigurationRegister _deltaThetaAndDeltaVelocityConfigurationRegister
Delta Theta and Delta Velocity Configuration.
std::shared_ptr< VectorNavBinaryOutput > _binaryOutputRegisterMergeObservation
First observation received, which should be merged together.
void guiConfig() override
ImGui config window which is shown on double click.
vn::sensors::VnSensor _vs
VnSensor Object.
std::string _connectedSensorPort
Connected sensor port.
~VectorNavSensor() override
Destructor.
ScrollingBuffer< std::string > _asciiOutputBuffer
Buffer to store Ascii Output Messages.
vn::sensors::VpeGyroBasicTuningRegister _vpeGyroBasicTuningRegister
VPE Gyro Basic Tuning.
std::array< size_t, 3 > _binaryOutputSelectedFrequency
Selected Frequency of the Binary Outputs in the GUI.
vn::math::mat3f _referenceFrameRotationMatrix
Reference Frame Rotation.
vn::protocol::uart::AsciiAsync _asyncDataOutputType
Async Data Output Type Register.
vn::sensors::ImuFilteringConfigurationRegister _imuFilteringConfigurationRegister
IMU Filtering Configuration.
vn::sensors::GpsCompassBaselineRegister _gpsCompassBaselineRegister
GNSS Compass Baseline.
vn::sensors::StartupFilterBiasEstimateRegister _startupFilterBiasEstimateRegister
Startup Filter Bias Estimate.
vn::sensors::GpsConfigurationRegister _gpsConfigurationRegister
GNSS Configuration.
struct NAV::VectorNavSensor::@061131263266062172247357061343017357216211246313 _gnssTimeCounter
Last received GNSS time.
VectorNavSensor()
Default constructor.
void restore(const json &j) override
Restores the node from a json object.
static const std::array< BinaryGroupData, 11 > _binaryGroupINS
Binary group 6 provides all estimated outputs which are dependent upon the onboard INS state solution...
static const std::array< BinaryGroupData, 9 > _binaryGroupAttitude
Binary group 5 provides all estimated outputs which are dependent upon the estimated attitude solutio...
@ VN310
VN-310/E (Tactical-Grade GNSS/INS with Integrated GNSS-Compass)
vn::sensors::VpeMagnetometerBasicTuningRegister _vpeMagnetometerBasicTuningRegister
VPE Magnetometer Basic Tuning.
bool initialize() override
Initialize the node.
int _asciiOutputBufferSize
Max size of the Ascii Output.
vn::math::vec3f _gpsAntennaOffset
GNSS Antenna A Offset.
static constexpr double IMU_DEFAULT_FREQUENCY
Internal Frequency of the Sensor.
int64_t _syncCntOffset
Offset between syncIn and syncOut.
vn::sensors::SynchronizationControlRegister _synchronizationControlRegister
Synchronization Control.
vn::sensors::VpeBasicControlRegister _vpeBasicControlRegister
VPE Basic Control.
void deinitialize() override
Deinitialize the node.
static void asciiOrBinaryAsyncMessageReceived(void *userData, vn::protocol::uart::Packet &p, size_t index)
Callback handler for notifications of new asynchronous data packets received.
vn::sensors::CommunicationProtocolControlRegister _communicationProtocolControlRegister
Communication Protocol Control.
TimeSync _timeSyncOut
Time synchronization for master sensors.
uint32_t _asyncDataOutputFrequency
Async Data Output Frequency Register.
BinaryRegisterMerge _binaryOutputRegisterMerge
Merge binary output registers together. This has to be done because VectorNav sensors have a buffer o...
vn::sensors::ReferenceVectorConfigurationRegister _referenceVectorConfigurationRegister
Reference Vector Configuration.
bool _syncInPin
Show the SyncIn Pin.
vn::sensors::InsBasicConfigurationRegisterVn300 _insBasicConfigurationRegisterVn300
INS Basic Configuration.
std::pair< std::vector< uint16_t >, std::vector< std::string > > _dividerFrequency
First: List of RateDividers, Second: List of Matching Frequencies.
int64_t _lastSyncInCnt
Last received syncInCnt.
bool resetNode() override
Resets the node. It is guaranteed that the node is initialized when this is called.
static const std::array< BinaryGroupData, 16 > _binaryGroupGNSS
Binary group 4 provides all outputs which are dependent upon the measurements collected from the prim...
vn::sensors::VelocityCompensationControlRegister _velocityCompensationControlRegister
Velocity Compensation Control.
static void mergeVectorNavBinaryObservations(const std::shared_ptr< VectorNavBinaryOutput > &target, const std::shared_ptr< VectorNavBinaryOutput > &source)
Merges the content of the two observations into one.
constexpr int32_t SECONDS_PER_DAY
Seconds / Day.
constexpr int32_t DAYS_PER_WEEK
Days / Week.
void ApplyChanges()
Signals that there have been changes to the flow.
Eigen::Quaternion< Scalar > b_Quat_p(Scalar mountingAngleX, Scalar mountingAngleY, Scalar mountingAngleZ)
Quaternion for rotations from platform to body frame.
Eigen::Vector3< typename Derived::Scalar > quat2eulerZYX(const Eigen::QuaternionBase< Derived > &q)
Converts the quaternion to Euler rotation angles with rotation sequence ZYX.
constexpr auto deg2rad(const T °)
Convert Degree to Radians.
constexpr auto rad2deg(const T &rad)
Convert Radians to Degree.
static void from_json(const json &j, vn::math::vec3f &vec)
static void to_json(json &j, const vn::math::vec3f &vec)
static void from_json(const json &j, SynchronizationControlRegister &synchronizationControlRegister)
static void to_json(json &j, const SynchronizationControlRegister &synchronizationControlRegister)
GPS week and time of week in GPS standard time [GPST].
Information needed to sync Master/Slave sensors.
InsTime ppsTime
Time of the last message with GNSS Time available (or empty otherwise)