Line | Branch | Exec | Source |
---|---|---|---|
1 | // This file is part of INSTINCT, the INS Toolkit for Integrated | ||
2 | // Navigation Concepts and Training by the Institute of Navigation of | ||
3 | // the University of Stuttgart, Germany. | ||
4 | // | ||
5 | // This Source Code Form is subject to the terms of the Mozilla Public | ||
6 | // License, v. 2.0. If a copy of the MPL was not distributed with this | ||
7 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. | ||
8 | |||
9 | #include "VectorNavSensor.hpp" | ||
10 | |||
11 | #include "util/Logger.hpp" | ||
12 | #include "vn/searcher.h" | ||
13 | #include "vn/util.h" | ||
14 | #include "util/Vendor/VectorNav/VectorNavTypes.hpp" | ||
15 | |||
16 | #include "internal/gui/widgets/HelpMarker.hpp" | ||
17 | |||
18 | #include "internal/NodeManager.hpp" | ||
19 | namespace nm = NAV::NodeManager; | ||
20 | #include "internal/FlowManager.hpp" | ||
21 | |||
22 | #include <imgui_internal.h> | ||
23 | |||
24 | #include "NodeData/General/StringObs.hpp" | ||
25 | |||
26 | #include "util/Time/TimeBase.hpp" | ||
27 | #include "Navigation/Transformations/CoordinateFrames.hpp" | ||
28 | #include "Navigation/Transformations/Units.hpp" | ||
29 | |||
30 | #include <map> | ||
31 | |||
32 | // to_json / from_json | ||
33 | namespace vn | ||
34 | { | ||
35 | namespace math | ||
36 | { | ||
37 | ✗ | static void to_json(json& j, const vn::math::vec3f& vec) // NOLINT(misc-use-anonymous-namespace) | |
38 | { | ||
39 | ✗ | j = vec.c; | |
40 | ✗ | } | |
41 | ✗ | static void from_json(const json& j, vn::math::vec3f& vec) // NOLINT(misc-use-anonymous-namespace) | |
42 | { | ||
43 | ✗ | j.get_to(vec.c); | |
44 | ✗ | } | |
45 | ✗ | static void to_json(json& j, const vn::math::vec3d& vec) // NOLINT(misc-use-anonymous-namespace) | |
46 | { | ||
47 | ✗ | j = vec.c; | |
48 | ✗ | } | |
49 | ✗ | static void from_json(const json& j, vn::math::vec3d& vec) // NOLINT(misc-use-anonymous-namespace) | |
50 | { | ||
51 | ✗ | j.get_to(vec.c); | |
52 | ✗ | } | |
53 | ✗ | static void to_json(json& j, const vn::math::mat3f& mat) // NOLINT(misc-use-anonymous-namespace) | |
54 | { | ||
55 | ✗ | j = mat.e; | |
56 | ✗ | } | |
57 | ✗ | static void from_json(const json& j, vn::math::mat3f& mat) // NOLINT(misc-use-anonymous-namespace) | |
58 | { | ||
59 | ✗ | j.get_to(mat.e); | |
60 | ✗ | } | |
61 | } // namespace math | ||
62 | |||
63 | namespace sensors | ||
64 | { | ||
65 | // ########################################################################################################### | ||
66 | // SYSTEM MODULE | ||
67 | // ########################################################################################################### | ||
68 | |||
69 | ✗ | static void to_json(json& j, const SynchronizationControlRegister& synchronizationControlRegister) // NOLINT(misc-use-anonymous-namespace) | |
70 | { | ||
71 | ✗ | j = json{ | |
72 | ✗ | { "syncInMode", synchronizationControlRegister.syncInMode }, | |
73 | ✗ | { "syncInEdge", synchronizationControlRegister.syncInEdge }, | |
74 | ✗ | { "syncInSkipFactor", synchronizationControlRegister.syncInSkipFactor }, | |
75 | ✗ | { "syncOutMode", synchronizationControlRegister.syncOutMode }, | |
76 | ✗ | { "syncOutPolarity", synchronizationControlRegister.syncOutPolarity }, | |
77 | ✗ | { "syncOutSkipFactor", synchronizationControlRegister.syncOutSkipFactor }, | |
78 | ✗ | { "syncOutPulseWidth", synchronizationControlRegister.syncOutPulseWidth }, | |
79 | ✗ | }; | |
80 | ✗ | } | |
81 | ✗ | static void from_json(const json& j, SynchronizationControlRegister& synchronizationControlRegister) // NOLINT(misc-use-anonymous-namespace) | |
82 | { | ||
83 | ✗ | if (j.contains("syncInMode")) | |
84 | { | ||
85 | ✗ | j.at("syncInMode").get_to(synchronizationControlRegister.syncInMode); | |
86 | } | ||
87 | ✗ | if (j.contains("syncInEdge")) | |
88 | { | ||
89 | ✗ | j.at("syncInEdge").get_to(synchronizationControlRegister.syncInEdge); | |
90 | } | ||
91 | ✗ | if (j.contains("syncInSkipFactor")) | |
92 | { | ||
93 | ✗ | j.at("syncInSkipFactor").get_to(synchronizationControlRegister.syncInSkipFactor); | |
94 | } | ||
95 | ✗ | if (j.contains("syncOutMode")) | |
96 | { | ||
97 | ✗ | j.at("syncOutMode").get_to(synchronizationControlRegister.syncOutMode); | |
98 | } | ||
99 | ✗ | if (j.contains("syncOutPolarity")) | |
100 | { | ||
101 | ✗ | j.at("syncOutPolarity").get_to(synchronizationControlRegister.syncOutPolarity); | |
102 | } | ||
103 | ✗ | if (j.contains("syncOutSkipFactor")) | |
104 | { | ||
105 | ✗ | j.at("syncOutSkipFactor").get_to(synchronizationControlRegister.syncOutSkipFactor); | |
106 | } | ||
107 | ✗ | if (j.contains("syncOutPulseWidth")) | |
108 | { | ||
109 | ✗ | j.at("syncOutPulseWidth").get_to(synchronizationControlRegister.syncOutPulseWidth); | |
110 | } | ||
111 | ✗ | } | |
112 | |||
113 | ✗ | static void to_json(json& j, const CommunicationProtocolControlRegister& communicationProtocolControlRegister) // NOLINT(misc-use-anonymous-namespace) | |
114 | { | ||
115 | ✗ | j = json{ | |
116 | ✗ | { "serialCount", communicationProtocolControlRegister.serialCount }, | |
117 | ✗ | { "serialStatus", communicationProtocolControlRegister.serialStatus }, | |
118 | ✗ | { "spiCount", communicationProtocolControlRegister.spiCount }, | |
119 | ✗ | { "spiStatus", communicationProtocolControlRegister.spiStatus }, | |
120 | ✗ | { "serialChecksum", communicationProtocolControlRegister.serialChecksum }, | |
121 | ✗ | { "spiChecksum", communicationProtocolControlRegister.spiChecksum }, | |
122 | ✗ | { "errorMode", communicationProtocolControlRegister.errorMode }, | |
123 | ✗ | }; | |
124 | ✗ | } | |
125 | ✗ | static void from_json(const json& j, CommunicationProtocolControlRegister& communicationProtocolControlRegister) // NOLINT(misc-use-anonymous-namespace) | |
126 | { | ||
127 | ✗ | if (j.contains("serialCount")) | |
128 | { | ||
129 | ✗ | j.at("serialCount").get_to(communicationProtocolControlRegister.serialCount); | |
130 | } | ||
131 | ✗ | if (j.contains("serialStatus")) | |
132 | { | ||
133 | ✗ | j.at("serialStatus").get_to(communicationProtocolControlRegister.serialStatus); | |
134 | } | ||
135 | ✗ | if (j.contains("spiCount")) | |
136 | { | ||
137 | ✗ | j.at("spiCount").get_to(communicationProtocolControlRegister.spiCount); | |
138 | } | ||
139 | ✗ | if (j.contains("spiStatus")) | |
140 | { | ||
141 | ✗ | j.at("spiStatus").get_to(communicationProtocolControlRegister.spiStatus); | |
142 | } | ||
143 | ✗ | if (j.contains("serialChecksum")) | |
144 | { | ||
145 | ✗ | j.at("serialChecksum").get_to(communicationProtocolControlRegister.serialChecksum); | |
146 | } | ||
147 | ✗ | if (j.contains("spiChecksum")) | |
148 | { | ||
149 | ✗ | j.at("spiChecksum").get_to(communicationProtocolControlRegister.spiChecksum); | |
150 | } | ||
151 | ✗ | if (j.contains("errorMode")) | |
152 | { | ||
153 | ✗ | j.at("errorMode").get_to(communicationProtocolControlRegister.errorMode); | |
154 | } | ||
155 | ✗ | } | |
156 | |||
157 | ✗ | static void to_json(json& j, const BinaryOutputRegister& binaryOutputRegister) // NOLINT(misc-use-anonymous-namespace) | |
158 | { | ||
159 | ✗ | j = json{ | |
160 | ✗ | { "asyncMode", binaryOutputRegister.asyncMode }, | |
161 | ✗ | { "rateDivisor", binaryOutputRegister.rateDivisor }, | |
162 | ✗ | { "commonField", binaryOutputRegister.commonField }, | |
163 | ✗ | { "timeField", binaryOutputRegister.timeField }, | |
164 | ✗ | { "imuField", binaryOutputRegister.imuField }, | |
165 | ✗ | { "gpsField", binaryOutputRegister.gpsField }, | |
166 | ✗ | { "attitudeField", binaryOutputRegister.attitudeField }, | |
167 | ✗ | { "insField", binaryOutputRegister.insField }, | |
168 | ✗ | { "gps2Field", binaryOutputRegister.gps2Field }, | |
169 | ✗ | }; | |
170 | ✗ | } | |
171 | ✗ | static void from_json(const json& j, BinaryOutputRegister& binaryOutputRegister) // NOLINT(misc-use-anonymous-namespace) | |
172 | { | ||
173 | ✗ | if (j.contains("asyncMode")) | |
174 | { | ||
175 | ✗ | j.at("asyncMode").get_to(binaryOutputRegister.asyncMode); | |
176 | } | ||
177 | ✗ | if (j.contains("rateDivisor")) | |
178 | { | ||
179 | ✗ | j.at("rateDivisor").get_to(binaryOutputRegister.rateDivisor); | |
180 | } | ||
181 | ✗ | if (j.contains("commonField")) | |
182 | { | ||
183 | ✗ | j.at("commonField").get_to(binaryOutputRegister.commonField); | |
184 | } | ||
185 | ✗ | if (j.contains("timeField")) | |
186 | { | ||
187 | ✗ | j.at("timeField").get_to(binaryOutputRegister.timeField); | |
188 | } | ||
189 | ✗ | if (j.contains("imuField")) | |
190 | { | ||
191 | ✗ | j.at("imuField").get_to(binaryOutputRegister.imuField); | |
192 | } | ||
193 | ✗ | if (j.contains("gpsField")) | |
194 | { | ||
195 | ✗ | j.at("gpsField").get_to(binaryOutputRegister.gpsField); | |
196 | } | ||
197 | ✗ | if (j.contains("attitudeField")) | |
198 | { | ||
199 | ✗ | j.at("attitudeField").get_to(binaryOutputRegister.attitudeField); | |
200 | } | ||
201 | ✗ | if (j.contains("insField")) | |
202 | { | ||
203 | ✗ | j.at("insField").get_to(binaryOutputRegister.insField); | |
204 | } | ||
205 | ✗ | if (j.contains("gps2Field")) | |
206 | { | ||
207 | ✗ | j.at("gps2Field").get_to(binaryOutputRegister.gps2Field); | |
208 | } | ||
209 | ✗ | } | |
210 | |||
211 | // ########################################################################################################### | ||
212 | // IMU SUBSYSTEM | ||
213 | // ########################################################################################################### | ||
214 | |||
215 | ✗ | static void to_json(json& j, const ImuFilteringConfigurationRegister& imuFilteringConfigurationRegister) // NOLINT(misc-use-anonymous-namespace) | |
216 | { | ||
217 | ✗ | j = json{ | |
218 | ✗ | { "magWindowSize", imuFilteringConfigurationRegister.magWindowSize }, | |
219 | ✗ | { "accelWindowSize", imuFilteringConfigurationRegister.accelWindowSize }, | |
220 | ✗ | { "gyroWindowSize", imuFilteringConfigurationRegister.gyroWindowSize }, | |
221 | ✗ | { "tempWindowSize", imuFilteringConfigurationRegister.tempWindowSize }, | |
222 | ✗ | { "presWindowSize", imuFilteringConfigurationRegister.presWindowSize }, | |
223 | ✗ | { "magFilterMode", imuFilteringConfigurationRegister.magFilterMode }, | |
224 | ✗ | { "accelFilterMode", imuFilteringConfigurationRegister.accelFilterMode }, | |
225 | ✗ | { "gyroFilterMode", imuFilteringConfigurationRegister.gyroFilterMode }, | |
226 | ✗ | { "tempFilterMode", imuFilteringConfigurationRegister.tempFilterMode }, | |
227 | ✗ | { "presFilterMode", imuFilteringConfigurationRegister.presFilterMode }, | |
228 | ✗ | }; | |
229 | ✗ | } | |
230 | ✗ | static void from_json(const json& j, ImuFilteringConfigurationRegister& imuFilteringConfigurationRegister) // NOLINT(misc-use-anonymous-namespace) | |
231 | { | ||
232 | ✗ | if (j.contains("magWindowSize")) | |
233 | { | ||
234 | ✗ | j.at("magWindowSize").get_to(imuFilteringConfigurationRegister.magWindowSize); | |
235 | } | ||
236 | ✗ | if (j.contains("accelWindowSize")) | |
237 | { | ||
238 | ✗ | j.at("accelWindowSize").get_to(imuFilteringConfigurationRegister.accelWindowSize); | |
239 | } | ||
240 | ✗ | if (j.contains("gyroWindowSize")) | |
241 | { | ||
242 | ✗ | j.at("gyroWindowSize").get_to(imuFilteringConfigurationRegister.gyroWindowSize); | |
243 | } | ||
244 | ✗ | if (j.contains("tempWindowSize")) | |
245 | { | ||
246 | ✗ | j.at("tempWindowSize").get_to(imuFilteringConfigurationRegister.tempWindowSize); | |
247 | } | ||
248 | ✗ | if (j.contains("presWindowSize")) | |
249 | { | ||
250 | ✗ | j.at("presWindowSize").get_to(imuFilteringConfigurationRegister.presWindowSize); | |
251 | } | ||
252 | ✗ | if (j.contains("magFilterMode")) | |
253 | { | ||
254 | ✗ | j.at("magFilterMode").get_to(imuFilteringConfigurationRegister.magFilterMode); | |
255 | } | ||
256 | ✗ | if (j.contains("accelFilterMode")) | |
257 | { | ||
258 | ✗ | j.at("accelFilterMode").get_to(imuFilteringConfigurationRegister.accelFilterMode); | |
259 | } | ||
260 | ✗ | if (j.contains("gyroFilterMode")) | |
261 | { | ||
262 | ✗ | j.at("gyroFilterMode").get_to(imuFilteringConfigurationRegister.gyroFilterMode); | |
263 | } | ||
264 | ✗ | if (j.contains("tempFilterMode")) | |
265 | { | ||
266 | ✗ | j.at("tempFilterMode").get_to(imuFilteringConfigurationRegister.tempFilterMode); | |
267 | } | ||
268 | ✗ | if (j.contains("presFilterMode")) | |
269 | { | ||
270 | ✗ | j.at("presFilterMode").get_to(imuFilteringConfigurationRegister.presFilterMode); | |
271 | } | ||
272 | ✗ | } | |
273 | |||
274 | ✗ | static void to_json(json& j, const DeltaThetaAndDeltaVelocityConfigurationRegister& deltaThetaAndDeltaVelocityConfigurationRegister) // NOLINT(misc-use-anonymous-namespace) | |
275 | { | ||
276 | ✗ | j = json{ | |
277 | ✗ | { "integrationFrame", deltaThetaAndDeltaVelocityConfigurationRegister.integrationFrame }, | |
278 | ✗ | { "gyroCompensation", deltaThetaAndDeltaVelocityConfigurationRegister.gyroCompensation }, | |
279 | ✗ | { "accelCompensation", deltaThetaAndDeltaVelocityConfigurationRegister.accelCompensation }, | |
280 | ✗ | { "earthRateCorrection", deltaThetaAndDeltaVelocityConfigurationRegister.earthRateCorrection }, | |
281 | ✗ | }; | |
282 | ✗ | } | |
283 | ✗ | static void from_json(const json& j, DeltaThetaAndDeltaVelocityConfigurationRegister& deltaThetaAndDeltaVelocityConfigurationRegister) // NOLINT(misc-use-anonymous-namespace) | |
284 | { | ||
285 | ✗ | if (j.contains("integrationFrame")) | |
286 | { | ||
287 | ✗ | j.at("integrationFrame").get_to(deltaThetaAndDeltaVelocityConfigurationRegister.integrationFrame); | |
288 | } | ||
289 | ✗ | if (j.contains("gyroCompensation")) | |
290 | { | ||
291 | ✗ | j.at("gyroCompensation").get_to(deltaThetaAndDeltaVelocityConfigurationRegister.gyroCompensation); | |
292 | } | ||
293 | ✗ | if (j.contains("accelCompensation")) | |
294 | { | ||
295 | ✗ | j.at("accelCompensation").get_to(deltaThetaAndDeltaVelocityConfigurationRegister.accelCompensation); | |
296 | } | ||
297 | ✗ | if (j.contains("earthRateCorrection")) | |
298 | { | ||
299 | ✗ | j.at("earthRateCorrection").get_to(deltaThetaAndDeltaVelocityConfigurationRegister.earthRateCorrection); | |
300 | } | ||
301 | ✗ | } | |
302 | |||
303 | // ########################################################################################################### | ||
304 | // GNSS SUBSYSTEM | ||
305 | // ########################################################################################################### | ||
306 | |||
307 | ✗ | static void to_json(json& j, const GpsConfigurationRegister& gpsConfigurationRegister) // NOLINT(misc-use-anonymous-namespace) | |
308 | { | ||
309 | ✗ | j = json{ | |
310 | ✗ | { "mode", gpsConfigurationRegister.mode }, | |
311 | ✗ | { "ppsSource", gpsConfigurationRegister.ppsSource }, | |
312 | ✗ | { "rate", gpsConfigurationRegister.rate }, | |
313 | ✗ | { "antPow", gpsConfigurationRegister.antPow }, | |
314 | ✗ | }; | |
315 | ✗ | } | |
316 | ✗ | static void from_json(const json& j, GpsConfigurationRegister& gpsConfigurationRegister) // NOLINT(misc-use-anonymous-namespace) | |
317 | { | ||
318 | ✗ | if (j.contains("mode")) | |
319 | { | ||
320 | ✗ | j.at("mode").get_to(gpsConfigurationRegister.mode); | |
321 | } | ||
322 | ✗ | if (j.contains("ppsSource")) | |
323 | { | ||
324 | ✗ | j.at("ppsSource").get_to(gpsConfigurationRegister.ppsSource); | |
325 | } | ||
326 | ✗ | if (j.contains("rate")) | |
327 | { | ||
328 | ✗ | j.at("rate").get_to(gpsConfigurationRegister.rate); | |
329 | } | ||
330 | ✗ | if (j.contains("antPow")) | |
331 | { | ||
332 | ✗ | j.at("antPow").get_to(gpsConfigurationRegister.antPow); | |
333 | } | ||
334 | ✗ | } | |
335 | |||
336 | ✗ | static void to_json(json& j, const GpsCompassBaselineRegister& gpsCompassBaselineRegister) // NOLINT(misc-use-anonymous-namespace) | |
337 | { | ||
338 | ✗ | j = json{ | |
339 | ✗ | { "position", gpsCompassBaselineRegister.position }, | |
340 | ✗ | { "uncertainty", gpsCompassBaselineRegister.uncertainty }, | |
341 | ✗ | }; | |
342 | ✗ | } | |
343 | ✗ | static void from_json(const json& j, GpsCompassBaselineRegister& gpsCompassBaselineRegister) // NOLINT(misc-use-anonymous-namespace) | |
344 | { | ||
345 | ✗ | if (j.contains("position")) | |
346 | { | ||
347 | ✗ | j.at("position").get_to(gpsCompassBaselineRegister.position); | |
348 | } | ||
349 | ✗ | if (j.contains("uncertainty")) | |
350 | { | ||
351 | ✗ | j.at("uncertainty").get_to(gpsCompassBaselineRegister.uncertainty); | |
352 | } | ||
353 | ✗ | } | |
354 | |||
355 | // ########################################################################################################### | ||
356 | // ATTITUDE SUBSYSTEM | ||
357 | // ########################################################################################################### | ||
358 | |||
359 | ✗ | static void to_json(json& j, const VpeBasicControlRegister& vpeBasicControlRegister) // NOLINT(misc-use-anonymous-namespace) | |
360 | { | ||
361 | ✗ | j = json{ | |
362 | ✗ | { "enable", vpeBasicControlRegister.enable }, | |
363 | ✗ | { "headingMode", vpeBasicControlRegister.headingMode }, | |
364 | ✗ | { "filteringMode", vpeBasicControlRegister.filteringMode }, | |
365 | ✗ | { "tuningMode", vpeBasicControlRegister.tuningMode }, | |
366 | ✗ | }; | |
367 | ✗ | } | |
368 | ✗ | static void from_json(const json& j, VpeBasicControlRegister& vpeBasicControlRegister) // NOLINT(misc-use-anonymous-namespace) | |
369 | { | ||
370 | ✗ | if (j.contains("enable")) | |
371 | { | ||
372 | ✗ | j.at("enable").get_to(vpeBasicControlRegister.enable); | |
373 | } | ||
374 | ✗ | if (j.contains("headingMode")) | |
375 | { | ||
376 | ✗ | j.at("headingMode").get_to(vpeBasicControlRegister.headingMode); | |
377 | } | ||
378 | ✗ | if (j.contains("filteringMode")) | |
379 | { | ||
380 | ✗ | j.at("filteringMode").get_to(vpeBasicControlRegister.filteringMode); | |
381 | } | ||
382 | ✗ | if (j.contains("tuningMode")) | |
383 | { | ||
384 | ✗ | j.at("tuningMode").get_to(vpeBasicControlRegister.tuningMode); | |
385 | } | ||
386 | ✗ | } | |
387 | |||
388 | ✗ | static void to_json(json& j, const VpeMagnetometerBasicTuningRegister& vpeMagnetometerBasicTuningRegister) // NOLINT(misc-use-anonymous-namespace) | |
389 | { | ||
390 | ✗ | j = json{ | |
391 | ✗ | { "baseTuning", vpeMagnetometerBasicTuningRegister.baseTuning }, | |
392 | ✗ | { "adaptiveTuning", vpeMagnetometerBasicTuningRegister.adaptiveTuning }, | |
393 | ✗ | { "adaptiveFiltering", vpeMagnetometerBasicTuningRegister.adaptiveFiltering }, | |
394 | ✗ | }; | |
395 | ✗ | } | |
396 | ✗ | static void from_json(const json& j, VpeMagnetometerBasicTuningRegister& vpeMagnetometerBasicTuningRegister) // NOLINT(misc-use-anonymous-namespace) | |
397 | { | ||
398 | ✗ | if (j.contains("baseTuning")) | |
399 | { | ||
400 | ✗ | j.at("baseTuning").get_to(vpeMagnetometerBasicTuningRegister.baseTuning); | |
401 | } | ||
402 | ✗ | if (j.contains("adaptiveTuning")) | |
403 | { | ||
404 | ✗ | j.at("adaptiveTuning").get_to(vpeMagnetometerBasicTuningRegister.adaptiveTuning); | |
405 | } | ||
406 | ✗ | if (j.contains("adaptiveFiltering")) | |
407 | { | ||
408 | ✗ | j.at("adaptiveFiltering").get_to(vpeMagnetometerBasicTuningRegister.adaptiveFiltering); | |
409 | } | ||
410 | ✗ | } | |
411 | |||
412 | ✗ | static void to_json(json& j, const VpeAccelerometerBasicTuningRegister& vpeAccelerometerBasicTuningRegister) // NOLINT(misc-use-anonymous-namespace) | |
413 | { | ||
414 | ✗ | j = json{ | |
415 | ✗ | { "baseTuning", vpeAccelerometerBasicTuningRegister.baseTuning }, | |
416 | ✗ | { "adaptiveTuning", vpeAccelerometerBasicTuningRegister.adaptiveTuning }, | |
417 | ✗ | { "adaptiveFiltering", vpeAccelerometerBasicTuningRegister.adaptiveFiltering }, | |
418 | ✗ | }; | |
419 | ✗ | } | |
420 | ✗ | static void from_json(const json& j, VpeAccelerometerBasicTuningRegister& vpeAccelerometerBasicTuningRegister) // NOLINT(misc-use-anonymous-namespace) | |
421 | { | ||
422 | ✗ | if (j.contains("baseTuning")) | |
423 | { | ||
424 | ✗ | j.at("baseTuning").get_to(vpeAccelerometerBasicTuningRegister.baseTuning); | |
425 | } | ||
426 | ✗ | if (j.contains("adaptiveTuning")) | |
427 | { | ||
428 | ✗ | j.at("adaptiveTuning").get_to(vpeAccelerometerBasicTuningRegister.adaptiveTuning); | |
429 | } | ||
430 | ✗ | if (j.contains("adaptiveFiltering")) | |
431 | { | ||
432 | ✗ | j.at("adaptiveFiltering").get_to(vpeAccelerometerBasicTuningRegister.adaptiveFiltering); | |
433 | } | ||
434 | ✗ | } | |
435 | |||
436 | ✗ | static void to_json(json& j, const VpeGyroBasicTuningRegister& vpeGyroBasicTuningRegister) // NOLINT(misc-use-anonymous-namespace) | |
437 | { | ||
438 | ✗ | j = json{ | |
439 | ✗ | { "angularWalkVariance", vpeGyroBasicTuningRegister.angularWalkVariance }, | |
440 | ✗ | { "baseTuning", vpeGyroBasicTuningRegister.baseTuning }, | |
441 | ✗ | { "adaptiveTuning", vpeGyroBasicTuningRegister.adaptiveTuning }, | |
442 | ✗ | }; | |
443 | ✗ | } | |
444 | ✗ | static void from_json(const json& j, VpeGyroBasicTuningRegister& vpeGyroBasicTuningRegister) // NOLINT(misc-use-anonymous-namespace) | |
445 | { | ||
446 | ✗ | if (j.contains("angularWalkVariance")) | |
447 | { | ||
448 | ✗ | j.at("angularWalkVariance").get_to(vpeGyroBasicTuningRegister.angularWalkVariance); | |
449 | } | ||
450 | ✗ | if (j.contains("baseTuning")) | |
451 | { | ||
452 | ✗ | j.at("baseTuning").get_to(vpeGyroBasicTuningRegister.baseTuning); | |
453 | } | ||
454 | ✗ | if (j.contains("adaptiveTuning")) | |
455 | { | ||
456 | ✗ | j.at("adaptiveTuning").get_to(vpeGyroBasicTuningRegister.adaptiveTuning); | |
457 | } | ||
458 | ✗ | } | |
459 | |||
460 | // ########################################################################################################### | ||
461 | // INS SUBSYSTEM | ||
462 | // ########################################################################################################### | ||
463 | |||
464 | ✗ | static void to_json(json& j, const InsBasicConfigurationRegisterVn300& insBasicConfigurationRegisterVn300) // NOLINT(misc-use-anonymous-namespace) | |
465 | { | ||
466 | ✗ | j = json{ | |
467 | ✗ | { "scenario", insBasicConfigurationRegisterVn300.scenario }, | |
468 | ✗ | { "ahrsAiding", insBasicConfigurationRegisterVn300.ahrsAiding }, | |
469 | ✗ | { "estBaseline", insBasicConfigurationRegisterVn300.estBaseline }, | |
470 | ✗ | }; | |
471 | ✗ | } | |
472 | ✗ | static void from_json(const json& j, InsBasicConfigurationRegisterVn300& insBasicConfigurationRegisterVn300) // NOLINT(misc-use-anonymous-namespace) | |
473 | { | ||
474 | ✗ | if (j.contains("scenario")) | |
475 | { | ||
476 | ✗ | j.at("scenario").get_to(insBasicConfigurationRegisterVn300.scenario); | |
477 | } | ||
478 | ✗ | if (j.contains("ahrsAiding")) | |
479 | { | ||
480 | ✗ | j.at("ahrsAiding").get_to(insBasicConfigurationRegisterVn300.ahrsAiding); | |
481 | } | ||
482 | ✗ | if (j.contains("estBaseline")) | |
483 | { | ||
484 | ✗ | j.at("estBaseline").get_to(insBasicConfigurationRegisterVn300.estBaseline); | |
485 | } | ||
486 | ✗ | } | |
487 | |||
488 | ✗ | static void to_json(json& j, const StartupFilterBiasEstimateRegister& startupFilterBiasEstimateRegister) // NOLINT(misc-use-anonymous-namespace) | |
489 | { | ||
490 | ✗ | j = json{ | |
491 | ✗ | { "gyroBias", startupFilterBiasEstimateRegister.gyroBias }, | |
492 | ✗ | { "accelBias", startupFilterBiasEstimateRegister.accelBias }, | |
493 | ✗ | { "pressureBias", startupFilterBiasEstimateRegister.pressureBias }, | |
494 | ✗ | }; | |
495 | ✗ | } | |
496 | ✗ | static void from_json(const json& j, StartupFilterBiasEstimateRegister& startupFilterBiasEstimateRegister) // NOLINT(misc-use-anonymous-namespace) | |
497 | { | ||
498 | ✗ | if (j.contains("gyroBias")) | |
499 | { | ||
500 | ✗ | j.at("gyroBias").get_to(startupFilterBiasEstimateRegister.gyroBias); | |
501 | } | ||
502 | ✗ | if (j.contains("accelBias")) | |
503 | { | ||
504 | ✗ | j.at("accelBias").get_to(startupFilterBiasEstimateRegister.accelBias); | |
505 | } | ||
506 | ✗ | if (j.contains("pressureBias")) | |
507 | { | ||
508 | ✗ | j.at("pressureBias").get_to(startupFilterBiasEstimateRegister.pressureBias); | |
509 | } | ||
510 | ✗ | } | |
511 | |||
512 | // ########################################################################################################### | ||
513 | // HARD/SOFT IRON ESTIMATOR SUBSYSTEM | ||
514 | // ########################################################################################################### | ||
515 | |||
516 | ✗ | static void to_json(json& j, const MagnetometerCalibrationControlRegister& magnetometerCalibrationControlRegister) // NOLINT(misc-use-anonymous-namespace) | |
517 | { | ||
518 | ✗ | j = json{ | |
519 | ✗ | { "hsiMode", magnetometerCalibrationControlRegister.hsiMode }, | |
520 | ✗ | { "hsiOutput", magnetometerCalibrationControlRegister.hsiOutput }, | |
521 | ✗ | { "convergeRate", magnetometerCalibrationControlRegister.convergeRate }, | |
522 | ✗ | }; | |
523 | ✗ | } | |
524 | ✗ | static void from_json(const json& j, MagnetometerCalibrationControlRegister& magnetometerCalibrationControlRegister) // NOLINT(misc-use-anonymous-namespace) | |
525 | { | ||
526 | ✗ | if (j.contains("hsiMode")) | |
527 | { | ||
528 | ✗ | j.at("hsiMode").get_to(magnetometerCalibrationControlRegister.hsiMode); | |
529 | } | ||
530 | ✗ | if (j.contains("hsiOutput")) | |
531 | { | ||
532 | ✗ | j.at("hsiOutput").get_to(magnetometerCalibrationControlRegister.hsiOutput); | |
533 | } | ||
534 | ✗ | if (j.contains("convergeRate")) | |
535 | { | ||
536 | ✗ | j.at("convergeRate").get_to(magnetometerCalibrationControlRegister.convergeRate); | |
537 | } | ||
538 | ✗ | } | |
539 | |||
540 | // ########################################################################################################### | ||
541 | // WORLD MAGNETIC & GRAVITY MODULE | ||
542 | // ########################################################################################################### | ||
543 | |||
544 | ✗ | static void to_json(json& j, const MagneticAndGravityReferenceVectorsRegister& magneticAndGravityReferenceVectorsRegister) // NOLINT(misc-use-anonymous-namespace) | |
545 | { | ||
546 | ✗ | j = json{ | |
547 | ✗ | { "magRef", magneticAndGravityReferenceVectorsRegister.magRef }, | |
548 | ✗ | { "accRef", magneticAndGravityReferenceVectorsRegister.accRef }, | |
549 | ✗ | }; | |
550 | ✗ | } | |
551 | ✗ | static void from_json(const json& j, MagneticAndGravityReferenceVectorsRegister& magneticAndGravityReferenceVectorsRegister) // NOLINT(misc-use-anonymous-namespace) | |
552 | { | ||
553 | ✗ | if (j.contains("magRef")) | |
554 | { | ||
555 | ✗ | j.at("magRef").get_to(magneticAndGravityReferenceVectorsRegister.magRef); | |
556 | } | ||
557 | ✗ | if (j.contains("accRef")) | |
558 | { | ||
559 | ✗ | j.at("accRef").get_to(magneticAndGravityReferenceVectorsRegister.accRef); | |
560 | } | ||
561 | ✗ | } | |
562 | |||
563 | ✗ | static void to_json(json& j, const ReferenceVectorConfigurationRegister& referenceVectorConfigurationRegister) // NOLINT(misc-use-anonymous-namespace) | |
564 | { | ||
565 | ✗ | j = json{ | |
566 | ✗ | { "useMagModel", referenceVectorConfigurationRegister.useMagModel }, | |
567 | ✗ | { "useGravityModel", referenceVectorConfigurationRegister.useGravityModel }, | |
568 | ✗ | { "recalcThreshold", referenceVectorConfigurationRegister.recalcThreshold }, | |
569 | ✗ | { "year", referenceVectorConfigurationRegister.year }, | |
570 | ✗ | { "position", referenceVectorConfigurationRegister.position }, | |
571 | ✗ | }; | |
572 | ✗ | } | |
573 | ✗ | static void from_json(const json& j, ReferenceVectorConfigurationRegister& referenceVectorConfigurationRegister) // NOLINT(misc-use-anonymous-namespace) | |
574 | { | ||
575 | ✗ | if (j.contains("useMagModel")) | |
576 | { | ||
577 | ✗ | j.at("useMagModel").get_to(referenceVectorConfigurationRegister.useMagModel); | |
578 | } | ||
579 | ✗ | if (j.contains("useGravityModel")) | |
580 | { | ||
581 | ✗ | j.at("useGravityModel").get_to(referenceVectorConfigurationRegister.useGravityModel); | |
582 | } | ||
583 | ✗ | if (j.contains("recalcThreshold")) | |
584 | { | ||
585 | ✗ | j.at("recalcThreshold").get_to(referenceVectorConfigurationRegister.recalcThreshold); | |
586 | } | ||
587 | ✗ | if (j.contains("year")) | |
588 | { | ||
589 | ✗ | j.at("year").get_to(referenceVectorConfigurationRegister.year); | |
590 | } | ||
591 | ✗ | if (j.contains("position")) | |
592 | { | ||
593 | ✗ | j.at("position").get_to(referenceVectorConfigurationRegister.position); | |
594 | } | ||
595 | ✗ | } | |
596 | |||
597 | // ########################################################################################################### | ||
598 | // VELOCITY AIDING | ||
599 | // ########################################################################################################### | ||
600 | |||
601 | ✗ | static void to_json(json& j, const VelocityCompensationControlRegister& velocityCompensationControlRegister) // NOLINT(misc-use-anonymous-namespace) | |
602 | { | ||
603 | ✗ | j = json{ | |
604 | ✗ | { "mode", velocityCompensationControlRegister.mode }, | |
605 | ✗ | { "velocityTuning", velocityCompensationControlRegister.velocityTuning }, | |
606 | ✗ | { "rateTuning", velocityCompensationControlRegister.rateTuning }, | |
607 | ✗ | }; | |
608 | ✗ | } | |
609 | ✗ | static void from_json(const json& j, VelocityCompensationControlRegister& velocityCompensationControlRegister) // NOLINT(misc-use-anonymous-namespace) | |
610 | { | ||
611 | ✗ | if (j.contains("mode")) | |
612 | { | ||
613 | ✗ | j.at("mode").get_to(velocityCompensationControlRegister.mode); | |
614 | } | ||
615 | ✗ | if (j.contains("velocityTuning")) | |
616 | { | ||
617 | ✗ | j.at("velocityTuning").get_to(velocityCompensationControlRegister.velocityTuning); | |
618 | } | ||
619 | ✗ | if (j.contains("rateTuning")) | |
620 | { | ||
621 | ✗ | j.at("rateTuning").get_to(velocityCompensationControlRegister.rateTuning); | |
622 | } | ||
623 | ✗ | } | |
624 | |||
625 | } // namespace sensors | ||
626 | } // namespace vn | ||
627 | |||
628 | ✗ | void NAV::VectorNavSensor::coupleImuFilterRates(NAV::VectorNavSensor* sensor, vn::sensors::BinaryOutputRegister& bor, uint32_t& /* binaryField */) | |
629 | { | ||
630 | // Set 'TimeStartup' and 'TimeStatus' always | ||
631 | ✗ | (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS); | |
632 | |||
633 | ✗ | if (sensor->_sensorModel == VectorNavModel::VN310) | |
634 | { | ||
635 | ✗ | (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK); | |
636 | } | ||
637 | |||
638 | ✗ | if (sensor->_coupleImuRateOutput) | |
639 | { | ||
640 | ✗ | if (bor.imuField & (vn::protocol::uart::IMUGROUP_ACCEL | vn::protocol::uart::IMUGROUP_UNCOMPACCEL)) | |
641 | { | ||
642 | ✗ | sensor->_imuFilteringConfigurationRegister.accelWindowSize = bor.rateDivisor; | |
643 | } | ||
644 | ✗ | if (bor.imuField & (vn::protocol::uart::IMUGROUP_ANGULARRATE | vn::protocol::uart::IMUGROUP_UNCOMPGYRO)) | |
645 | { | ||
646 | ✗ | sensor->_imuFilteringConfigurationRegister.gyroWindowSize = bor.rateDivisor; | |
647 | } | ||
648 | ✗ | if (bor.imuField & (vn::protocol::uart::IMUGROUP_MAG | vn::protocol::uart::IMUGROUP_UNCOMPMAG)) | |
649 | { | ||
650 | ✗ | sensor->_imuFilteringConfigurationRegister.magWindowSize = bor.rateDivisor; | |
651 | } | ||
652 | ✗ | if (bor.imuField & (vn::protocol::uart::IMUGROUP_MAG | vn::protocol::uart::IMUGROUP_UNCOMPMAG)) | |
653 | { | ||
654 | ✗ | sensor->_imuFilteringConfigurationRegister.magWindowSize = bor.rateDivisor; | |
655 | } | ||
656 | ✗ | if (bor.imuField & vn::protocol::uart::IMUGROUP_TEMP) | |
657 | { | ||
658 | ✗ | sensor->_imuFilteringConfigurationRegister.tempWindowSize = bor.rateDivisor; | |
659 | } | ||
660 | ✗ | if (bor.imuField & vn::protocol::uart::IMUGROUP_PRES) | |
661 | { | ||
662 | ✗ | sensor->_imuFilteringConfigurationRegister.presWindowSize = bor.rateDivisor; | |
663 | } | ||
664 | LOG_DATA("Frequency of ImuFilter matches output frequency (coupled 'rateDivisor' and 'windowSize' of moving average filter.)"); | ||
665 | |||
666 | ✗ | if (sensor->isInitialized() && sensor->_vs.isConnected() && sensor->_vs.verifySensorConnectivity()) | |
667 | { | ||
668 | try | ||
669 | { | ||
670 | ✗ | sensor->_vs.writeImuFilteringConfiguration(sensor->_imuFilteringConfigurationRegister); | |
671 | } | ||
672 | ✗ | catch (const std::exception& e) | |
673 | { | ||
674 | ✗ | LOG_ERROR("Could not configure the imuFilteringConfigurationRegister: {}", e.what()); | |
675 | ✗ | sensor->doDeinitialize(); | |
676 | ✗ | } | |
677 | } | ||
678 | else | ||
679 | { | ||
680 | ✗ | sensor->doDeinitialize(); | |
681 | } | ||
682 | } | ||
683 | ✗ | }; | |
684 | |||
685 | // NOLINTBEGIN | ||
686 | |||
687 | // const std::array<NAV::VectorNavSensor::BinaryGroupData, 15> NAV::VectorNavSensor::_binaryGroupCommon = { { | ||
688 | // { /* 0 */ "TimeStartup", vn::protocol::uart::CommonGroup::COMMONGROUP_TIMESTARTUP, | ||
689 | // []() { 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). This field is\nequivalent to the TimeStartup field in group 2."); } }, | ||
690 | // { /* 1 */ "TimeGps", vn::protocol::uart::CommonGroup::COMMONGROUP_TIMEGPS, | ||
691 | // []() { ImGui::TextUnformatted("GPS time.\n\nThe absolute GPS time since start of GPS epoch 1980 expressed in nano seconds. This field is equivalent to\nthe TimeGps field in group 2."); }, | ||
692 | // [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | ||
693 | // [](VectorNavSensor* /* sensor */, vn::sensors::BinaryOutputRegister& bor, uint32_t& /* binaryField */) { (bor.commonField & vn::protocol::uart::CommonGroup::COMMONGROUP_TIMEGPS) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS); } }, | ||
694 | // { /* 2 */ "TimeSyncIn", vn::protocol::uart::CommonGroup::COMMONGROUP_TIMESYNCIN, | ||
695 | // []() { ImGui::TextUnformatted("Time since last SyncIn trigger.\n\nThe time since the last SyncIn trigger event expressed in nano seconds. This field is equivalent to the\nTimeSyncIn field in group 2."); } }, | ||
696 | // { /* 3 */ "YawPitchRoll", vn::protocol::uart::CommonGroup::COMMONGROUP_YAWPITCHROLL, | ||
697 | // []() { ImGui::TextUnformatted("Estimated attitude as yaw pitch and roll angles.\n\nThe estimated attitude Yaw, Pitch, and Roll angles measured in degrees. The attitude is given as a 3,2,1 Euler\nangle sequence describing the body frame with respect to the local North East Down (NED) frame. This field\nis equivalent to the YawPitchRoll field in group 5.\n\nYaw [+/- 180°]\nPitch [+/- 90°]\nRoll [+/- 180°]"); } }, | ||
698 | // { /* 4 */ "Quaternion", vn::protocol::uart::CommonGroup::COMMONGROUP_QUATERNION, | ||
699 | // []() { ImGui::TextUnformatted("Estimated attitude as a quaternion.\n\nThe estimated attitude quaternion. The last term is the scalar value. The attitude is given as the body frame\nwith respect to the local North East Down (NED) frame. This field is equivalent to the Quaternion field in\ngroup 5."); } }, | ||
700 | // { /* 5 */ "AngularRate", vn::protocol::uart::CommonGroup::COMMONGROUP_ANGULARRATE, | ||
701 | // []() { ImGui::TextUnformatted("Compensated angular rate.\n\nThe estimated angular rate measured in rad/s. The angular rates are compensated by the onboard filter bias\nestimates. The angular rate is expressed in the body frame. This field is equivalent to the AngularRate field\nin group 3."); } }, | ||
702 | // { /* 6 */ "Position", vn::protocol::uart::CommonGroup::COMMONGROUP_POSITION, | ||
703 | // []() { ImGui::TextUnformatted("Estimated position. (LLA)\n\nThe estimated position given as latitude, longitude, and altitude given in [deg, deg, m] respectively. This field\nis equivalent to the PosLla field in group 6."); }, | ||
704 | // [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | ||
705 | // [](VectorNavSensor* /* sensor */, vn::sensors::BinaryOutputRegister& bor, uint32_t& /* binaryField */) { (bor.commonField & vn::protocol::uart::CommonGroup::COMMONGROUP_POSITION) && (bor.commonField |= vn::protocol::uart::CommonGroup::COMMONGROUP_INSSTATUS); } }, | ||
706 | // { /* 7 */ "Velocity", vn::protocol::uart::CommonGroup::COMMONGROUP_VELOCITY, | ||
707 | // []() { ImGui::TextUnformatted("Estimated velocity. (NED)\n\nThe estimated velocity in the North East Down (NED) frame, given in m/s. This field is equivalent to the\nVelNed field in group 6."); }, | ||
708 | // [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | ||
709 | // [](VectorNavSensor* /* sensor */, vn::sensors::BinaryOutputRegister& bor, uint32_t& /* binaryField */) { (bor.commonField & vn::protocol::uart::CommonGroup::COMMONGROUP_VELOCITY) && (bor.commonField |= vn::protocol::uart::CommonGroup::COMMONGROUP_INSSTATUS); } }, | ||
710 | // { /* 8 */ "Accel", vn::protocol::uart::CommonGroup::COMMONGROUP_ACCEL, | ||
711 | // []() { ImGui::TextUnformatted("Estimated acceleration (compensated). (Body)\n\nThe estimated acceleration in the body frame, given in m/s^2. This acceleration includes gravity and has\nbeen bias compensated by the onboard INS Kalman filter. This field is equivalent to the Accel field in group 3."); } }, | ||
712 | // { /* 9 */ "Imu", vn::protocol::uart::CommonGroup::COMMONGROUP_IMU, | ||
713 | // []() { ImGui::TextUnformatted("Calibrated uncompensated gyro and accelerometer measurements.\n\nThe uncompensated IMU acceleration and angular rate measurements. The acceleration is given in m/s^2,\nand the angular rate is given in rad/s. These measurements correspond to the calibrated angular rate and\nacceleration measurements straight from the IMU. The measurements have not been corrected for bias\noffset by the onboard Kalman filter. These are equivalent to the UncompAccel and UncompGyro fields in\ngroup 3."); } }, | ||
714 | // { /* 10 */ "MagPres", vn::protocol::uart::CommonGroup::COMMONGROUP_MAGPRES, | ||
715 | // []() { ImGui::TextUnformatted("Calibrated magnetic (compensated), temperature, and pressure measurements.\n\nThe compensated magnetic, temperature, and pressure measurements from the IMU. The magnetic\nmeasurement is given in Gauss, and has been corrected for hard/soft iron corrections (if enabled). The\ntemperature measurement is given in Celsius. The pressure measurement is given in kPa. This field is\nequivalent to the Mag, Temp, and Pres fields in group 3.\n\nThe IP-68 enclosure on the tactical series forms an airtight (hermetic) seal isolating the internal\nsensors from the external environment. The pressure sensor is internal to this seal, and as such\nwill not measure the outside environment atmospheric pressure. It will instead read the pressure\ninside the sealed enclosure. The purpose of this sensor is to provide a means of ensuring the\nseal integrity over the lifetime of the product. Based on the Ideal Gas Law the ratio of pressure\ndivided by temperature should remain constant over both time and environmental temperature.\nWhen this is no longer the case, it can be assumed that the seal integrity has been compromised."); } }, | ||
716 | // { /* 11 */ "DeltaTheta", vn::protocol::uart::CommonGroup::COMMONGROUP_DELTATHETA, | ||
717 | // []() { ImGui::TextUnformatted("Delta time, theta, and velocity.\n\nThe delta time, angle, and velocity measurements. The delta time (dtime) is the time interval that the delta\nangle and velocities are integrated over. The delta theta (dtheta) is the delta rotation angles incurred due to\nrotation, by the local body reference frame, since the last time the values were outputted by the device. The\ndelta velocity (dvel) is the delta velocity incurred due to motion, by the local body reference frame, since the\nlast time the values were outputted by the device. The frame of reference of these delta measurements are\ndetermined by the IntegrationFrame field in the Delta Theta and Delta Velocity Configuration Register\n(Register 82). These delta angles and delta velocities are calculated based upon the onboard coning and\nsculling integration performed onboard the sensor at the full IMU rate (default 800Hz). The integration for\nboth the delta angles and velocities are reset each time either of the values are either polled or sent out due\nto a scheduled asynchronous ASCII or binary output. Delta Theta and Delta Velocity values correctly capture\nthe nonlinearities involved in measuring motion from a rotating strapdown platform (as opposed to the older\nmechanically inertial navigation systems), thus providing you with the ability to integrate velocity and angular\nrate at much lower speeds (say for example 10 Hz, reducing bandwidth and computational complexity), while\nstill maintaining the same numeric precision as if you had performed the integration at the full IMU\nmeasurement rate of 800Hz. This field is equivalent to the DeltaTheta and DeltaVel fields in group 3 with the\ninclusion of the additional delta time parameter."); } }, | ||
718 | // { /* 12 */ "Ins/VpeStatus", vn::protocol::uart::CommonGroup::COMMONGROUP_INSSTATUS, | ||
719 | // []() { ImGui::TextUnformatted("INS status (VN310).\n\nThe INS status bitfield. This field is equivalent to the InsSatus field in group 6.\nSee INS Solution LLA Register for more information on the individual bits in this field."); | ||
720 | // ImGui::Separator(); | ||
721 | // ImGui::TextUnformatted("VPE Status (VN100).\n\nThe VPE status bitfield. This field is equivalent to the VpeStatus field in group 5.\nSee Group 5 - VPE for more information on the individual bits in this field."); }, | ||
722 | // [](VectorNavModel /* sensorModel */, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t binaryField) { return !(static_cast<vn::protocol::uart::CommonGroup>(binaryField) & vn::protocol::uart::CommonGroup::COMMONGROUP_POSITION) && !(static_cast<vn::protocol::uart::CommonGroup>(binaryField) & vn::protocol::uart::CommonGroup::COMMONGROUP_VELOCITY); } }, | ||
723 | // { /* 13 */ "SyncInCnt", vn::protocol::uart::CommonGroup::COMMONGROUP_SYNCINCNT, | ||
724 | // []() { ImGui::TextUnformatted("SyncIn count.\n\nThe number of SyncIn trigger events that have occurred. This field is equivalent to the SyncInCnt field in\ngroup 2."); } }, | ||
725 | // { /* 14 */ "TimeGpsPps", vn::protocol::uart::CommonGroup::COMMONGROUP_TIMEGPSPPS, | ||
726 | // []() { ImGui::TextUnformatted("Time since last GNSS PPS trigger.\n\nThe time since the last GPS PPS trigger event expressed in nano seconds. This field is equivalent to the\nTimePPS field in group 2."); }, | ||
727 | // [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; } }, | ||
728 | // } }; | ||
729 | |||
730 | const std::array<NAV::VectorNavSensor::BinaryGroupData, 10> NAV::VectorNavSensor::_binaryGroupTime = { { | ||
731 | { /* 0 */ "TimeStartup", vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP, | ||
732 | ✗ | []() { 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)."); }, | |
733 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& bor, uint32_t /* binaryField */) { return (sensorModel != VectorNavModel::VN310 | |
734 | ✗ | || !((bor.gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_TOW) | |
735 | ✗ | || (bor.gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_WEEK) | |
736 | ✗ | || (bor.gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_TOW) | |
737 | ✗ | || (bor.gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_WEEK))) | |
738 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPMAG) | |
739 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPACCEL) | |
740 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPGYRO) | |
741 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_TEMP) | |
742 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_PRES) | |
743 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTATHETA) | |
744 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTAVEL) | |
745 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_MAG) | |
746 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ACCEL) | |
747 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ANGULARRATE) | |
748 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YAWPITCHROLL) | |
749 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_QUATERNION) | |
750 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_DCM) | |
751 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_MAGNED) | |
752 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_ACCELNED) | |
753 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELBODY) | |
754 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELNED) | |
755 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YPRU) | |
756 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_INSSTATUS) | |
757 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_POSLLA) | |
758 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_POSECEF) | |
759 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELBODY) | |
760 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELNED) | |
761 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELECEF) | |
762 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_MAGECEF) | |
763 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_ACCELECEF) | |
764 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_LINEARACCELECEF) | |
765 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_POSU) | |
766 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELU); } }, | |
767 | { /* 1 */ "TimeGps", vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEGPS, | ||
768 | ✗ | []() { ImGui::TextUnformatted("Absolute GPS time.\n\nThe absolute GPS time since start of GPS epoch 1980 expressed in nano seconds."); }, | |
769 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | |
770 | ✗ | [](VectorNavSensor* /* sensor */, vn::sensors::BinaryOutputRegister& bor, uint32_t& /* binaryField */) { (bor.timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEGPS) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS); } }, | |
771 | { /* 2 */ "GpsTow", vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW, | ||
772 | ✗ | []() { ImGui::TextUnformatted("Time since start of GPS week.\n\nThe time since the start of the current GPS time week expressed in nano seconds."); }, | |
773 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& bor, uint32_t /* binaryField */) { return (sensorModel == VectorNavModel::VN310) | |
774 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPMAG) | |
775 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPACCEL) | |
776 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPGYRO) | |
777 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_TEMP) | |
778 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_PRES) | |
779 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTATHETA) | |
780 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTAVEL) | |
781 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_MAG) | |
782 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ACCEL) | |
783 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ANGULARRATE) | |
784 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YAWPITCHROLL) | |
785 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_QUATERNION) | |
786 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_DCM) | |
787 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_MAGNED) | |
788 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_ACCELNED) | |
789 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELBODY) | |
790 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELNED) | |
791 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YPRU) | |
792 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_INSSTATUS) | |
793 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_POSLLA) | |
794 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_POSECEF) | |
795 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELBODY) | |
796 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELNED) | |
797 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELECEF) | |
798 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_MAGECEF) | |
799 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_ACCELECEF) | |
800 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_LINEARACCELECEF) | |
801 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_POSU) | |
802 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELU); }, | |
803 | ✗ | [](VectorNavSensor* /* sensor */, vn::sensors::BinaryOutputRegister& bor, uint32_t& /* binaryField */) { (bor.timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS); } }, | |
804 | { /* 3 */ "GpsWeek", vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK, | ||
805 | ✗ | []() { ImGui::TextUnformatted("GPS week.\n\nThe current GPS week."); }, | |
806 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& bor, uint32_t /* binaryField */) { return (sensorModel == VectorNavModel::VN310) | |
807 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPMAG) | |
808 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPACCEL) | |
809 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPGYRO) | |
810 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_TEMP) | |
811 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_PRES) | |
812 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTATHETA) | |
813 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTAVEL) | |
814 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_MAG) | |
815 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ACCEL) | |
816 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ANGULARRATE) | |
817 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YAWPITCHROLL) | |
818 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_QUATERNION) | |
819 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_DCM) | |
820 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_MAGNED) | |
821 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_ACCELNED) | |
822 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELBODY) | |
823 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELNED) | |
824 | ✗ | && !(bor.attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YPRU) | |
825 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_INSSTATUS) | |
826 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_POSLLA) | |
827 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_POSECEF) | |
828 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELBODY) | |
829 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELNED) | |
830 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELECEF) | |
831 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_MAGECEF) | |
832 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_ACCELECEF) | |
833 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_LINEARACCELECEF) | |
834 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_POSU) | |
835 | ✗ | && !(bor.insField & vn::protocol::uart::InsGroup::INSGROUP_VELU); }, | |
836 | ✗ | [](VectorNavSensor* /* sensor */, vn::sensors::BinaryOutputRegister& bor, uint32_t& /* binaryField */) { (bor.timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS); } }, | |
837 | { /* 4 */ "TimeSyncIn", vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESYNCIN, | ||
838 | ✗ | []() { ImGui::TextUnformatted("Time since last SyncIn trigger.\n\nThe time since the last SyncIn event trigger expressed in nano seconds."); } }, | |
839 | { /* 5 */ "TimeGpsPps", vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEGPSPPS, | ||
840 | ✗ | []() { ImGui::TextUnformatted("Time since last GPS PPS trigger.\n\nThe time since the last GPS PPS trigger event expressed in nano seconds."); }, | |
841 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; } }, | |
842 | { /* 6 */ "TimeUTC", vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEUTC, | ||
843 | ✗ | []() { 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."); }, | |
844 | ✗ | [](VectorNavModel /* sensorModel */, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return false; }, | |
845 | ✗ | [](VectorNavSensor* /* sensor */, vn::sensors::BinaryOutputRegister& bor, uint32_t& /* binaryField */) { (bor.timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEUTC) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS); } }, | |
846 | { /* 7 */ "SyncInCnt", vn::protocol::uart::TimeGroup::TIMEGROUP_SYNCINCNT, | ||
847 | ✗ | []() { ImGui::TextUnformatted("SyncIn trigger count.\n\nThe number of SyncIn trigger events that have occurred."); } }, | |
848 | { /* 8 */ "SyncOutCnt", vn::protocol::uart::TimeGroup::TIMEGROUP_SYNCOUTCNT, | ||
849 | ✗ | []() { ImGui::TextUnformatted("SyncOut trigger count.\n\nThe number of SyncOut trigger events that have occurred."); } }, | |
850 | { /* 9 */ "TimeStatus", vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS, | ||
851 | ✗ | []() { ImGui::TextUnformatted("Time valid status flags."); | |
852 | ✗ | if (ImGui::BeginTable("VectorNavTimeStatusTooltip", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) | |
853 | { | ||
854 | ✗ | ImGui::TableSetupColumn("Bit Offset", ImGuiTableColumnFlags_WidthFixed); | |
855 | ✗ | ImGui::TableSetupColumn("Field", ImGuiTableColumnFlags_WidthFixed); | |
856 | ✗ | ImGui::TableSetupColumn("Description", ImGuiTableColumnFlags_WidthFixed); | |
857 | ✗ | ImGui::TableHeadersRow(); | |
858 | |||
859 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("0"); | |
860 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("timeOk"); | |
861 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1 - GpsTow is valid"); | |
862 | |||
863 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1"); | |
864 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("dateOk"); | |
865 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1 - TimeGps and GpsWeek are valid"); | |
866 | |||
867 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("2"); | |
868 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("utcTimeValid"); | |
869 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1 - UTC time is valid"); | |
870 | |||
871 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("3 - 7"); | |
872 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("resv"); | |
873 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Reserved for future use"); | |
874 | |||
875 | ✗ | ImGui::EndTable(); | |
876 | ✗ | } }, | |
877 | ✗ | [](VectorNavModel /* sensorModel */, const vn::sensors::BinaryOutputRegister& bor, uint32_t /* binaryField */) { return !(bor.commonField & vn::protocol::uart::CommonGroup::COMMONGROUP_TIMEGPS) | |
878 | ✗ | && !(bor.timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW) | |
879 | ✗ | && !(bor.timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) | |
880 | ✗ | && !(bor.timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEGPS) | |
881 | ✗ | && !(bor.timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEUTC) | |
882 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPMAG) | |
883 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPACCEL) | |
884 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPGYRO) | |
885 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_TEMP) | |
886 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_PRES) | |
887 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTATHETA) | |
888 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTAVEL) | |
889 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_MAG) | |
890 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ACCEL) | |
891 | ✗ | && !(bor.imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ANGULARRATE); } }, | |
892 | } }; | ||
893 | |||
894 | const std::array<NAV::VectorNavSensor::BinaryGroupData, 11> NAV::VectorNavSensor::_binaryGroupIMU{ { | ||
895 | { /* 0 */ "ImuStatus", vn::protocol::uart::ImuGroup::IMUGROUP_IMUSTATUS, | ||
896 | ✗ | []() { ImGui::TextUnformatted("Status is reserved for future use. Not currently used in the current code, as such will always report 0."); }, | |
897 | ✗ | [](VectorNavModel /* sensorModel */, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return false; } }, | |
898 | { /* 1 */ "UncompMag", vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPMAG, | ||
899 | ✗ | []() { 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."); }, | |
900 | ✗ | [](VectorNavModel /* sensorModel */, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return true; }, coupleImuFilterRates }, | |
901 | { /* 2 */ "UncompAccel", vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPACCEL, | ||
902 | ✗ | []() { 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."); }, | |
903 | ✗ | [](VectorNavModel /* sensorModel */, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return true; }, coupleImuFilterRates }, | |
904 | { /* 3 */ "UncompGyro", vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPGYRO, | ||
905 | ✗ | []() { 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."); }, | |
906 | ✗ | [](VectorNavModel /* sensorModel */, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return true; }, coupleImuFilterRates }, | |
907 | { /* 4 */ "Temp", vn::protocol::uart::ImuGroup::IMUGROUP_TEMP, | ||
908 | ✗ | []() { ImGui::TextUnformatted("Temperature measurement.\n\nThe IMU temperature measured in units of Celsius."); }, | |
909 | ✗ | [](VectorNavModel /* sensorModel */, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return true; }, coupleImuFilterRates }, | |
910 | { /* 5 */ "Pres", vn::protocol::uart::ImuGroup::IMUGROUP_PRES, | ||
911 | ✗ | []() { 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."); }, | |
912 | ✗ | [](VectorNavModel /* sensorModel */, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return true; }, coupleImuFilterRates }, | |
913 | { /* 6 */ "DeltaTheta", vn::protocol::uart::ImuGroup::IMUGROUP_DELTATHETA, | ||
914 | ✗ | []() { 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."); } }, | |
915 | { /* 7 */ "DeltaVel", vn::protocol::uart::ImuGroup::IMUGROUP_DELTAVEL, | ||
916 | ✗ | []() { 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."); } }, | |
917 | { /* 8 */ "Mag", vn::protocol::uart::ImuGroup::IMUGROUP_MAG, | ||
918 | ✗ | []() { 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."); }, | |
919 | ✗ | [](VectorNavModel /* sensorModel */, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return true; }, coupleImuFilterRates }, | |
920 | { /* 9 */ "Accel", vn::protocol::uart::ImuGroup::IMUGROUP_ACCEL, | ||
921 | ✗ | []() { 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."); }, | |
922 | ✗ | [](VectorNavModel /* sensorModel */, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return true; }, coupleImuFilterRates }, | |
923 | { /* 10 */ "AngularRate", vn::protocol::uart::ImuGroup::IMUGROUP_ANGULARRATE, | ||
924 | ✗ | []() { 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."); }, | |
925 | ✗ | [](VectorNavModel /* sensorModel */, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return true; }, coupleImuFilterRates }, | |
926 | } }; | ||
927 | |||
928 | const std::array<NAV::VectorNavSensor::BinaryGroupData, 16> NAV::VectorNavSensor::_binaryGroupGNSS{ { | ||
929 | { /* 0 */ "UTC", vn::protocol::uart::GpsGroup::GPSGROUP_UTC, | ||
930 | ✗ | []() { 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."); }, | |
931 | ✗ | [](VectorNavModel /* sensorModel */, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return false; }, | |
932 | ✗ | [](VectorNavSensor* /* sensor */, vn::sensors::BinaryOutputRegister& /* bor */, uint32_t& binaryField) { (static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_UTC) && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO); } }, | |
933 | { /* 1 */ "Tow", vn::protocol::uart::GpsGroup::GPSGROUP_TOW, | ||
934 | ✗ | []() { ImGui::TextUnformatted("GPS time of week\n\nThe GPS time of week given in nano seconds."); }, | |
935 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t binaryField) { return sensorModel == VectorNavModel::VN310 | |
936 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSLLA) | |
937 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSECEF) | |
938 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELNED) | |
939 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELECEF) | |
940 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSU) | |
941 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELU); }, | |
942 | ✗ | [](VectorNavSensor* /* sensor */, 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)); } }, | |
943 | { /* 2 */ "Week", vn::protocol::uart::GpsGroup::GPSGROUP_WEEK, | ||
944 | ✗ | []() { ImGui::TextUnformatted("GPS week\n\nThe current GPS week."); }, | |
945 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t binaryField) { return sensorModel == VectorNavModel::VN310 | |
946 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSLLA) | |
947 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSECEF) | |
948 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELNED) | |
949 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELECEF) | |
950 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSU) | |
951 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELU); }, | |
952 | ✗ | [](VectorNavSensor* /* sensor */, 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)); } }, | |
953 | { /* 3 */ "NumSats", vn::protocol::uart::GpsGroup::GPSGROUP_NUMSATS, | ||
954 | ✗ | []() { ImGui::TextUnformatted("Number of tracked satellites\n\nThe number of tracked GNSS satellites."); }, | |
955 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; } }, | |
956 | { /* 4 */ "Fix", vn::protocol::uart::GpsGroup::GPSGROUP_FIX, | ||
957 | ✗ | []() { ImGui::TextUnformatted("GNSS fix\n\nThe current GNSS fix."); | |
958 | ✗ | if (ImGui::BeginTable("VectorNavFixTooltip", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) | |
959 | { | ||
960 | ✗ | ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthFixed); | |
961 | ✗ | ImGui::TableSetupColumn("Description", ImGuiTableColumnFlags_WidthFixed); | |
962 | ✗ | ImGui::TableHeadersRow(); | |
963 | |||
964 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("0"); | |
965 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("No fix"); | |
966 | |||
967 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1"); | |
968 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Time only"); | |
969 | |||
970 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("2"); | |
971 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("2D"); | |
972 | |||
973 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("3"); | |
974 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("3D"); | |
975 | |||
976 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("4"); | |
977 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("SBAS"); | |
978 | |||
979 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("7"); | |
980 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("RTK Float (only GNSS1)"); | |
981 | |||
982 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("8"); | |
983 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("RTK Fixed (only GNSS1)"); | |
984 | |||
985 | ✗ | ImGui::EndTable(); | |
986 | ✗ | } }, | |
987 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t binaryField) { return sensorModel == VectorNavModel::VN310 | |
988 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSLLA) | |
989 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSECEF) | |
990 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELNED) | |
991 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELECEF) | |
992 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSU) | |
993 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELU); } }, | |
994 | { /* 5 */ "PosLla", vn::protocol::uart::GpsGroup::GPSGROUP_POSLLA, | ||
995 | ✗ | []() { 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."); }, | |
996 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | |
997 | ✗ | [](VectorNavSensor* /* sensor */, vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { | |
998 | ✗ | (static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSLLA) | |
999 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_FIX) | |
1000 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TOW) | |
1001 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_WEEK) | |
1002 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO); | |
1003 | ✗ | bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP; | |
1004 | ✗ | } }, | |
1005 | { /* 6 */ "PosEcef", vn::protocol::uart::GpsGroup::GPSGROUP_POSECEF, | ||
1006 | ✗ | []() { ImGui::TextUnformatted("GNSS position (ECEF)\n\nThe current GNSS position given in the Earth centered Earth fixed (ECEF) coordinate frame, given in meters."); }, | |
1007 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | |
1008 | ✗ | [](VectorNavSensor* /* sensor */, vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { | |
1009 | ✗ | (static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSECEF) | |
1010 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_FIX) | |
1011 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TOW) | |
1012 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_WEEK) | |
1013 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO); | |
1014 | ✗ | bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP; | |
1015 | ✗ | } }, | |
1016 | { /* 7 */ "VelNed", vn::protocol::uart::GpsGroup::GPSGROUP_VELNED, | ||
1017 | ✗ | []() { ImGui::TextUnformatted("GNSS velocity (NED)\n\nThe current GNSS velocity in the North East Down (NED) coordinate frame, given in m/s."); }, | |
1018 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | |
1019 | ✗ | [](VectorNavSensor* /* sensor */, vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { | |
1020 | ✗ | (static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELNED) | |
1021 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_FIX) | |
1022 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TOW) | |
1023 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_WEEK) | |
1024 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO); | |
1025 | ✗ | bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP; | |
1026 | ✗ | } }, | |
1027 | { /* 8 */ "VelEcef", vn::protocol::uart::GpsGroup::GPSGROUP_VELECEF, | ||
1028 | ✗ | []() { ImGui::TextUnformatted("GNSS velocity (ECEF)\n\nThe current GNSS velocity in the Earth centered Earth fixed (ECEF) coordinate frame, given in m/s."); }, | |
1029 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | |
1030 | ✗ | [](VectorNavSensor* /* sensor */, vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { | |
1031 | ✗ | (static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELECEF) | |
1032 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_FIX) | |
1033 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TOW) | |
1034 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_WEEK) | |
1035 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO); | |
1036 | ✗ | bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP; | |
1037 | ✗ | } }, | |
1038 | { /* 9 */ "PosU", vn::protocol::uart::GpsGroup::GPSGROUP_POSU, | ||
1039 | ✗ | []() { 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)."); }, | |
1040 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | |
1041 | ✗ | [](VectorNavSensor* /* sensor */, vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { | |
1042 | ✗ | (static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_POSU) | |
1043 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_FIX) | |
1044 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TOW) | |
1045 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_WEEK) | |
1046 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO); | |
1047 | ✗ | bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP; | |
1048 | ✗ | } }, | |
1049 | { /* 10 */ "VelU", vn::protocol::uart::GpsGroup::GPSGROUP_VELU, | ||
1050 | ✗ | []() { ImGui::TextUnformatted("GNSS velocity uncertainty\n\nThe current GNSS velocity uncertainty, given in m/s (1 Sigma)."); }, | |
1051 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | |
1052 | ✗ | [](VectorNavSensor* /* sensor */, vn::sensors::BinaryOutputRegister& bor, uint32_t& binaryField) { | |
1053 | ✗ | (static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_VELU) | |
1054 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_FIX) | |
1055 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TOW) | |
1056 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_WEEK) | |
1057 | ✗ | && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO); | |
1058 | ✗ | bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP; | |
1059 | ✗ | } }, | |
1060 | { /* 11 */ "TimeU", vn::protocol::uart::GpsGroup::GPSGROUP_TIMEU, | ||
1061 | ✗ | []() { ImGui::TextUnformatted("GNSS time uncertainty\n\nThe current GPS time uncertainty, given in seconds (1 Sigma)."); }, | |
1062 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | |
1063 | ✗ | [](VectorNavSensor* /* sensor */, vn::sensors::BinaryOutputRegister& /* bor */, uint32_t& binaryField) { (static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_TIMEU) && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO); } }, | |
1064 | { /* 12 */ "TimeInfo", vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO, | ||
1065 | ✗ | []() { ImGui::TextUnformatted("GNSS time status and leap seconds\n\nFlags for valid GPS TOW, week number and UTC and current leap seconds."); | |
1066 | ✗ | if (ImGui::BeginTable("VectorNavTimeInfoTooltip", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F))) | |
1067 | { | ||
1068 | ✗ | ImGui::TableSetupColumn("Bit Offset"); | |
1069 | ✗ | ImGui::TableSetupColumn("Field"); | |
1070 | ✗ | ImGui::TableSetupColumn("Description"); | |
1071 | ✗ | ImGui::TableHeadersRow(); | |
1072 | |||
1073 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("0"); | |
1074 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("timeOk"); | |
1075 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1 - GpsTow is valid"); | |
1076 | |||
1077 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1"); | |
1078 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("dateOk"); | |
1079 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1 - TimeGps and GpsWeek are valid"); | |
1080 | |||
1081 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("2"); | |
1082 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("utcTimeValid"); | |
1083 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1 - UTC time is valid"); | |
1084 | |||
1085 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("3 - 7"); | |
1086 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("resv"); | |
1087 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Reserved for future use"); | |
1088 | |||
1089 | ✗ | ImGui::EndTable(); | |
1090 | ✗ | } }, | |
1091 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t binaryField) { return sensorModel == VectorNavModel::VN310 | |
1092 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_TOW) | |
1093 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_WEEK) | |
1094 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_UTC) | |
1095 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_TIMEU) | |
1096 | ✗ | && !(static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_RAWMEAS); } }, | |
1097 | { /* 13 */ "DOP", vn::protocol::uart::GpsGroup::GPSGROUP_DOP, | ||
1098 | ✗ | []() { ImGui::TextUnformatted("Dilution of precision"); }, | |
1099 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; } }, | |
1100 | { /* 14 */ "SatInfo", vn::protocol::uart::GpsGroup::GPSGROUP_SATINFO, | ||
1101 | ✗ | []() { ImGui::TextUnformatted("Satellite Information\n\nInformation and measurements pertaining to each GNSS satellite in view.\n\nSatInfo Element:"); | |
1102 | ✗ | if (ImGui::BeginTable("VectorNavSatInfoTooltip", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F))) | |
1103 | { | ||
1104 | ✗ | ImGui::TableSetupColumn("Name"); | |
1105 | ✗ | ImGui::TableSetupColumn("Description"); | |
1106 | ✗ | ImGui::TableHeadersRow(); | |
1107 | |||
1108 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("sys"); | |
1109 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("GNSS constellation indicator. See table below for details."); | |
1110 | |||
1111 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("svId"); | |
1112 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Space vehicle Id"); | |
1113 | |||
1114 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("flags"); | |
1115 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Tracking info flags. See table below for details."); | |
1116 | |||
1117 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("cno"); | |
1118 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Carrier-to-noise density ratio (signal strength) [dB-Hz]"); | |
1119 | |||
1120 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("qi"); | |
1121 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Quality Indicator. See table below for details."); | |
1122 | |||
1123 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("el"); | |
1124 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Elevation in degrees"); | |
1125 | |||
1126 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("az"); | |
1127 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Azimuth angle in degrees"); | |
1128 | |||
1129 | ✗ | ImGui::EndTable(); | |
1130 | } | ||
1131 | ✗ | ImGui::BeginChild("VectorNavSatInfoTooltipGNSSConstelationChild", ImVec2(230, 217)); | |
1132 | ✗ | ImGui::TextUnformatted("\nGNSS constellation indicator:"); | |
1133 | ✗ | if (ImGui::BeginTable("VectorNavSatInfoTooltipGNSSConstelation", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F))) | |
1134 | { | ||
1135 | ✗ | ImGui::TableSetupColumn("Value"); | |
1136 | ✗ | ImGui::TableSetupColumn("Description"); | |
1137 | ✗ | ImGui::TableHeadersRow(); | |
1138 | |||
1139 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("0"); | |
1140 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("GPS"); | |
1141 | |||
1142 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1"); | |
1143 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("SBAS"); | |
1144 | |||
1145 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("2"); | |
1146 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Galileo"); | |
1147 | |||
1148 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("3"); | |
1149 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("BeiDou"); | |
1150 | |||
1151 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("4"); | |
1152 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("IMES"); | |
1153 | |||
1154 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("5"); | |
1155 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("QZSS"); | |
1156 | |||
1157 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("6"); | |
1158 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("GLONASS"); | |
1159 | |||
1160 | ✗ | ImGui::EndTable(); | |
1161 | } | ||
1162 | ✗ | ImGui::EndChild(); | |
1163 | ✗ | ImGui::SameLine(); | |
1164 | ✗ | ImGui::BeginChild("VectorNavSatInfoTooltipFlagsChild", ImVec2(260, 217)); | |
1165 | ✗ | ImGui::TextUnformatted("\nTracking info flags:"); | |
1166 | ✗ | if (ImGui::BeginTable("VectorNavSatInfoTooltipFlags", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F))) | |
1167 | { | ||
1168 | ✗ | ImGui::TableSetupColumn("Bit Offset"); | |
1169 | ✗ | ImGui::TableSetupColumn("Description"); | |
1170 | ✗ | ImGui::TableHeadersRow(); | |
1171 | |||
1172 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("0"); | |
1173 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Healthy"); | |
1174 | |||
1175 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1"); | |
1176 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Almanac"); | |
1177 | |||
1178 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("2"); | |
1179 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Ephemeris"); | |
1180 | |||
1181 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("3"); | |
1182 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Differential Correction"); | |
1183 | |||
1184 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("4"); | |
1185 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Used for Navigation"); | |
1186 | |||
1187 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("5"); | |
1188 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Azimuth / Elevation Valid"); | |
1189 | |||
1190 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("6"); | |
1191 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Used for RTK"); | |
1192 | |||
1193 | ✗ | ImGui::EndTable(); | |
1194 | } | ||
1195 | ✗ | ImGui::EndChild(); | |
1196 | ✗ | ImGui::TextUnformatted("\nQuality Indicators:"); | |
1197 | ✗ | if (ImGui::BeginTable("VectorNavSatInfoTooltipQuality", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F))) | |
1198 | { | ||
1199 | ✗ | ImGui::TableSetupColumn("Value"); | |
1200 | ✗ | ImGui::TableSetupColumn("Description"); | |
1201 | ✗ | ImGui::TableHeadersRow(); | |
1202 | |||
1203 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("0"); | |
1204 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("No signal"); | |
1205 | |||
1206 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1"); | |
1207 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Searching signal"); | |
1208 | |||
1209 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("2"); | |
1210 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Signal acquired"); | |
1211 | |||
1212 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("3"); | |
1213 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Signal detected but unstable"); | |
1214 | |||
1215 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("4"); | |
1216 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Code locked and time synchronized"); | |
1217 | |||
1218 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("5, 6, 7"); | |
1219 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Code and carrier locked and time synchronized"); | |
1220 | |||
1221 | ✗ | ImGui::EndTable(); | |
1222 | ✗ | } }, | |
1223 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; } }, | |
1224 | { /* 15 */ "RawMeas", vn::protocol::uart::GpsGroup::GPSGROUP_RAWMEAS, | ||
1225 | ✗ | []() { ImGui::TextUnformatted("GNSS Raw Measurements.\n\nSatRaw Element:"); | |
1226 | ✗ | if (ImGui::BeginTable("VectorNavSatRawTooltip", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F))) | |
1227 | { | ||
1228 | ✗ | ImGui::TableSetupColumn("Name"); | |
1229 | ✗ | ImGui::TableSetupColumn("Description"); | |
1230 | ✗ | ImGui::TableHeadersRow(); | |
1231 | |||
1232 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("sys"); | |
1233 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("GNSS constellation indicator. See table below for details."); | |
1234 | |||
1235 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("svId"); | |
1236 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Space vehicle Id"); | |
1237 | |||
1238 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("freq"); | |
1239 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Frequency indicator. See table below for details."); | |
1240 | |||
1241 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("chan"); | |
1242 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Channel Indicator. See table below for details."); | |
1243 | |||
1244 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("slot"); | |
1245 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Slot Id"); | |
1246 | |||
1247 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("cno"); | |
1248 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Carrier-to-noise density ratio (signal strength) [dB-Hz]"); | |
1249 | |||
1250 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("flags"); | |
1251 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Tracking info flags. See table below for details."); | |
1252 | |||
1253 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("pr"); | |
1254 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Pseudorange measurement in meters."); | |
1255 | |||
1256 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("cp"); | |
1257 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Carrier phase measurement in cycles."); | |
1258 | |||
1259 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("dp"); | |
1260 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Doppler measurement in Hz. Positive sign for approaching satellites."); | |
1261 | |||
1262 | ✗ | ImGui::EndTable(); | |
1263 | } | ||
1264 | ✗ | ImGui::BeginChild("VectorNavSatRawTooltipGNSSConstelationChild", ImVec2(180, 217)); | |
1265 | ✗ | ImGui::TextUnformatted("\nConstellation indicator:"); | |
1266 | ✗ | if (ImGui::BeginTable("VectorNavSatRawTooltipGNSSConstelation", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F))) | |
1267 | { | ||
1268 | ✗ | ImGui::TableSetupColumn("Value"); | |
1269 | ✗ | ImGui::TableSetupColumn("Description"); | |
1270 | ✗ | ImGui::TableHeadersRow(); | |
1271 | |||
1272 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("0"); | |
1273 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("GPS"); | |
1274 | |||
1275 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1"); | |
1276 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("SBAS"); | |
1277 | |||
1278 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("2"); | |
1279 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Galileo"); | |
1280 | |||
1281 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("3"); | |
1282 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("BeiDou"); | |
1283 | |||
1284 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("4"); | |
1285 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("IMES"); | |
1286 | |||
1287 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("5"); | |
1288 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("QZSS"); | |
1289 | |||
1290 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("6"); | |
1291 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("GLONASS"); | |
1292 | |||
1293 | ✗ | ImGui::EndTable(); | |
1294 | } | ||
1295 | ✗ | ImGui::EndChild(); | |
1296 | ✗ | ImGui::SameLine(); | |
1297 | ✗ | ImGui::BeginChild("VectorNavSatRawTooltipFreqChild", ImVec2(270, 235)); | |
1298 | ✗ | ImGui::TextUnformatted("\nFrequency indicator:"); | |
1299 | ✗ | if (ImGui::BeginTable("VectorNavSatRawTooltipFreq", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F))) | |
1300 | { | ||
1301 | ✗ | ImGui::TableSetupColumn("Value"); | |
1302 | ✗ | ImGui::TableSetupColumn("Description"); | |
1303 | ✗ | ImGui::TableHeadersRow(); | |
1304 | |||
1305 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("0"); | |
1306 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Rx Channel"); | |
1307 | |||
1308 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1"); | |
1309 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("L1(GPS,QZSS,SBAS), G1(GLO),\nE2-L1-E1(GAL), B1(BDS)"); | |
1310 | |||
1311 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("2"); | |
1312 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("L2(GPS,QZSS), G2(GLO)"); | |
1313 | |||
1314 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("3"); | |
1315 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("L5(GPS,QZSS,SBAS), E5a(GAL)"); | |
1316 | |||
1317 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("4"); | |
1318 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("E6(GAL), LEX(QZSS), B3(BDS)"); | |
1319 | |||
1320 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("5"); | |
1321 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("E5b(GAL), B2(BDS)"); | |
1322 | |||
1323 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("6"); | |
1324 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("E5a+b(GAL)"); | |
1325 | |||
1326 | ✗ | ImGui::EndTable(); | |
1327 | } | ||
1328 | ✗ | ImGui::EndChild(); | |
1329 | ✗ | ImGui::SameLine(); | |
1330 | ✗ | ImGui::BeginChild("VectorNavSatRawTooltipFlagChild", ImVec2(255, 260)); | |
1331 | ✗ | ImGui::TextUnformatted("\nTracking info flags:"); | |
1332 | ✗ | if (ImGui::BeginTable("VectorNavSatRawTooltipFlags", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F))) | |
1333 | { | ||
1334 | ✗ | ImGui::TableSetupColumn("Bit Offset"); | |
1335 | ✗ | ImGui::TableSetupColumn("Description"); | |
1336 | ✗ | ImGui::TableHeadersRow(); | |
1337 | |||
1338 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("0"); | |
1339 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Searching"); | |
1340 | |||
1341 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1"); | |
1342 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Tracking"); | |
1343 | |||
1344 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("2"); | |
1345 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Time Valid"); | |
1346 | |||
1347 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("3"); | |
1348 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Code Lock"); | |
1349 | |||
1350 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("4"); | |
1351 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Phase Lock"); | |
1352 | |||
1353 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("5"); | |
1354 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Phase Half Ambiguity"); | |
1355 | |||
1356 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("6"); | |
1357 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Phase Half Sub"); | |
1358 | |||
1359 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("7"); | |
1360 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Phase Slip"); | |
1361 | |||
1362 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("8"); | |
1363 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Pseudorange Smoothed"); | |
1364 | |||
1365 | ✗ | ImGui::EndTable(); | |
1366 | } | ||
1367 | ✗ | ImGui::EndChild(); | |
1368 | ✗ | ImGui::TextUnformatted("\nChannel indicator:"); | |
1369 | ✗ | if (ImGui::BeginTable("VectorNavSatRawTooltipChan", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F))) | |
1370 | { | ||
1371 | ✗ | ImGui::TableSetupColumn("Value"); | |
1372 | ✗ | ImGui::TableSetupColumn("Description"); | |
1373 | ✗ | ImGui::TableHeadersRow(); | |
1374 | |||
1375 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("0"); | |
1376 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("P-code (GPS,GLO)"); | |
1377 | |||
1378 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1"); | |
1379 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("C/A-code (GPS,GLO,SBAS,QZSS), C chan (GAL)"); | |
1380 | |||
1381 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("2"); | |
1382 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("semi-codeless (GPS)"); | |
1383 | |||
1384 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("3"); | |
1385 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Y-code (GPS)"); | |
1386 | |||
1387 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("4"); | |
1388 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("M-code (GPS)"); | |
1389 | |||
1390 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("5"); | |
1391 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("codeless (GPS)"); | |
1392 | |||
1393 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("6"); | |
1394 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("A chan (GAL)"); | |
1395 | |||
1396 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("7"); | |
1397 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("B chan (GAL)"); | |
1398 | |||
1399 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("8"); | |
1400 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("I chan (GPS,GAL,QZSS,BDS)"); | |
1401 | |||
1402 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("9"); | |
1403 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Q chan (GPS,GAL,QZSS,BDS)"); | |
1404 | |||
1405 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("10"); | |
1406 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("M chan (L2CGPS, L2CQZSS), D chan (GPS,QZSS)"); | |
1407 | |||
1408 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("11"); | |
1409 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("L chan (L2CGPS, L2CQZSS), P chan (GPS,QZSS)"); | |
1410 | |||
1411 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("12"); | |
1412 | ✗ | 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 | |||
1414 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("13"); | |
1415 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("based on Z-tracking (GPS)"); | |
1416 | |||
1417 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("14"); | |
1418 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("A+B+C (GAL)"); | |
1419 | |||
1420 | ✗ | ImGui::EndTable(); | |
1421 | ✗ | } }, | |
1422 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | |
1423 | ✗ | [](VectorNavSensor* /* sensor */, vn::sensors::BinaryOutputRegister& /* bor */, uint32_t& binaryField) { (static_cast<vn::protocol::uart::GpsGroup>(binaryField) & vn::protocol::uart::GpsGroup::GPSGROUP_RAWMEAS) && (binaryField |= vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO); } }, | |
1424 | } }; | ||
1425 | |||
1426 | const std::array<NAV::VectorNavSensor::BinaryGroupData, 9> NAV::VectorNavSensor::_binaryGroupAttitude{ { | ||
1427 | { /* 0 */ "VpeStatus", vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_VPESTATUS, | ||
1428 | ✗ | []() { ImGui::TextUnformatted("VPE Status bitfield\n\n"); | |
1429 | ✗ | if (ImGui::BeginTable("VectorNavSatRawTooltipChan", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) | |
1430 | { | ||
1431 | ✗ | ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed); | |
1432 | ✗ | ImGui::TableSetupColumn("Bit Offset", ImGuiTableColumnFlags_WidthFixed); | |
1433 | ✗ | ImGui::TableSetupColumn("Format", ImGuiTableColumnFlags_WidthFixed); | |
1434 | ✗ | ImGui::TableSetupColumn("Description", ImGuiTableColumnFlags_WidthFixed); | |
1435 | ✗ | ImGui::TableHeadersRow(); | |
1436 | |||
1437 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("AttitudeQuality"); | |
1438 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("0"); | |
1439 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("2 bits"); | |
1440 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Provides an indication of the quality of the attitude solution.\n0 - Excellent\n1 - Good\n2 - Bad\n3 - Not tracking"); | |
1441 | |||
1442 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("GyroSaturation"); | |
1443 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("2"); | |
1444 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1 bits"); | |
1445 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("At least one gyro axis is currently saturated."); | |
1446 | |||
1447 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("GyroSaturationRecovery"); | |
1448 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("3"); | |
1449 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1 bits"); | |
1450 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Filter is in the process of recovering from a gyro\nsaturation event."); | |
1451 | |||
1452 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("MagDisturbance"); | |
1453 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("4"); | |
1454 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("2 bits"); | |
1455 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("A magnetic DC disturbance has been detected.\n0 - No magnetic disturbance\n1 to 3 - Magnetic disturbance is present."); | |
1456 | |||
1457 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("MagSaturation"); | |
1458 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("6"); | |
1459 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1 bits"); | |
1460 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("At least one magnetometer axis is currently saturated."); | |
1461 | |||
1462 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("AccDisturbance"); | |
1463 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("7"); | |
1464 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("2 bits"); | |
1465 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("A strong acceleration disturbance has been detected.\n0 - No acceleration disturbance.\n1 to 3 - Acceleration disturbance has been detected."); | |
1466 | |||
1467 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("AccSaturation"); | |
1468 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("9"); | |
1469 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1 bits"); | |
1470 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("At least one accelerometer axis is currently saturated."); | |
1471 | |||
1472 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Reserved"); | |
1473 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("10"); | |
1474 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1 bits"); | |
1475 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Reserved for internal use. May change state at run- time."); | |
1476 | |||
1477 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("KnownMagDisturbance"); | |
1478 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("11"); | |
1479 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1 bits"); | |
1480 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("A known magnetic disturbance has been reported by\nthe user and the magnetometer is currently tuned out."); | |
1481 | |||
1482 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("KnownAccelDisturbance"); | |
1483 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("12"); | |
1484 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1 bits"); | |
1485 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("A known acceleration disturbance has been reported by\nthe user and the accelerometer is currently tuned out."); | |
1486 | |||
1487 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Reserved"); | |
1488 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("13"); | |
1489 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("3 bits"); | |
1490 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Reserved for future use."); | |
1491 | |||
1492 | ✗ | ImGui::EndTable(); | |
1493 | ✗ | } }, | |
1494 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN100_VN110; } }, | |
1495 | { /* 1 */ "YawPitchRoll", vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YAWPITCHROLL, | ||
1496 | ✗ | []() { 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°]"); }, | |
1497 | ✗ | [](VectorNavModel /* sensorModel */, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return true; }, | |
1498 | ✗ | [](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) | |
1499 | ✗ | && ((sensor->_sensorModel == VectorNavModel::VN310) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)); } }, | |
1500 | { /* 2 */ "Quaternion", vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_QUATERNION, | ||
1501 | ✗ | []() { 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."); }, | |
1502 | ✗ | [](VectorNavModel /* sensorModel */, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return true; }, | |
1503 | ✗ | [](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) | |
1504 | ✗ | && ((sensor->_sensorModel == VectorNavModel::VN310) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)); } }, | |
1505 | { /* 3 */ "DCM", vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_DCM, | ||
1506 | ✗ | []() { 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."); }, | |
1507 | ✗ | [](VectorNavModel /* sensorModel */, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return true; }, | |
1508 | ✗ | [](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) | |
1509 | ✗ | && ((sensor->_sensorModel == VectorNavModel::VN310) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)); } }, | |
1510 | { /* 4 */ "MagNed", vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_MAGNED, | ||
1511 | ✗ | []() { 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."); }, | |
1512 | ✗ | [](VectorNavModel /* sensorModel */, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return true; }, | |
1513 | ✗ | [](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) | |
1514 | ✗ | && ((sensor->_sensorModel == VectorNavModel::VN310) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)); } }, | |
1515 | { /* 5 */ "AccelNed", vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_ACCELNED, | ||
1516 | ✗ | []() { 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)."); }, | |
1517 | ✗ | [](VectorNavModel /* sensorModel */, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return true; }, | |
1518 | ✗ | [](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) | |
1519 | ✗ | && ((sensor->_sensorModel == VectorNavModel::VN310) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)); } }, | |
1520 | { /* 6 */ "LinearAccelBody", vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELBODY, | ||
1521 | ✗ | []() { 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."); }, | |
1522 | ✗ | [](VectorNavModel /* sensorModel */, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return true; }, | |
1523 | ✗ | [](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) | |
1524 | ✗ | && ((sensor->_sensorModel == VectorNavModel::VN310) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)); } }, | |
1525 | { /* 7 */ "LinearAccelNed", vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELNED, | ||
1526 | ✗ | []() { 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."); }, | |
1527 | ✗ | [](VectorNavModel /* sensorModel */, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return true; }, | |
1528 | ✗ | [](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) | |
1529 | ✗ | && ((sensor->_sensorModel == VectorNavModel::VN310) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)); } }, | |
1530 | { /* 8 */ "YprU", vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YPRU, | ||
1531 | ✗ | []() { 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."); }, | |
1532 | ✗ | [](VectorNavModel /* sensorModel */, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return true; }, | |
1533 | ✗ | [](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) | |
1534 | ✗ | && ((sensor->_sensorModel == VectorNavModel::VN310) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) && (bor.timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW)); } }, | |
1535 | } }; | ||
1536 | |||
1537 | const std::array<NAV::VectorNavSensor::BinaryGroupData, 11> NAV::VectorNavSensor::_binaryGroupINS{ { | ||
1538 | { /* 0 */ "InsStatus", vn::protocol::uart::InsGroup::INSGROUP_INSSTATUS, | ||
1539 | ✗ | []() { ImGui::TextUnformatted("Ins Status bitfield:"); | |
1540 | ✗ | if (ImGui::BeginTable("VectorNavInsStatusTooltip", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) | |
1541 | { | ||
1542 | ✗ | ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed); | |
1543 | ✗ | ImGui::TableSetupColumn("Bit Offset", ImGuiTableColumnFlags_WidthFixed); | |
1544 | ✗ | ImGui::TableSetupColumn("Format", ImGuiTableColumnFlags_WidthFixed); | |
1545 | ✗ | ImGui::TableSetupColumn("Description", ImGuiTableColumnFlags_WidthFixed); | |
1546 | ✗ | ImGui::TableHeadersRow(); | |
1547 | |||
1548 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Mode"); | |
1549 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("0"); | |
1550 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("2 bits"); | |
1551 | ✗ | 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 | |||
1553 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("GpsFix"); | |
1554 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("2"); | |
1555 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1 bits"); | |
1556 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Indicates whether the GNSS has a proper fix."); | |
1557 | |||
1558 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Error"); | |
1559 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("3"); | |
1560 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("4 bits"); | |
1561 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Sensor measurement error code. See table below.\n0 = No errors detected."); | |
1562 | |||
1563 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Reserved"); | |
1564 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("7"); | |
1565 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1 bits"); | |
1566 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Reserved for internal use. May toggle state during runtime and should be ignored."); | |
1567 | |||
1568 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("GpsHeadingIns"); | |
1569 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("8"); | |
1570 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1 bits"); | |
1571 | ✗ | 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 | |||
1573 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("GpsCompass"); | |
1574 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("9"); | |
1575 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("1 bits"); | |
1576 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Indicates if the GNSS compass is operational and reporting a heading\nsolution."); | |
1577 | |||
1578 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Reserved"); | |
1579 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("10"); | |
1580 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("6 bits"); | |
1581 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Reserved for internal use. These bits will toggle state and should be ignored."); | |
1582 | |||
1583 | ✗ | ImGui::EndTable(); | |
1584 | } | ||
1585 | ✗ | ImGui::TextUnformatted("\nError Bitfield:"); | |
1586 | ✗ | if (ImGui::BeginTable("VectorNavInsStatusTooltipError", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F))) | |
1587 | { | ||
1588 | ✗ | ImGui::TableSetupColumn("Name"); | |
1589 | ✗ | ImGui::TableSetupColumn("Description"); | |
1590 | ✗ | ImGui::TableHeadersRow(); | |
1591 | |||
1592 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Reserved"); | |
1593 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Reserved for future use and not currently used."); | |
1594 | |||
1595 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("IMU Error"); | |
1596 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("High if IMU communication error is detected."); | |
1597 | |||
1598 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("Mag/Pres Error"); | |
1599 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("High if Magnetometer or Pressure sensor error is detected."); | |
1600 | |||
1601 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("GNSS Error"); | |
1602 | ✗ | ImGui::TableNextColumn(); ImGui::TextUnformatted("High if GNSS communication error is detected."); | |
1603 | |||
1604 | ✗ | ImGui::EndTable(); | |
1605 | ✗ | } }, | |
1606 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | |
1607 | ✗ | [](VectorNavSensor* /* sensor */, 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); } }, | |
1608 | { /* 1 */ "PosLla", vn::protocol::uart::InsGroup::INSGROUP_POSLLA, | ||
1609 | ✗ | []() { ImGui::TextUnformatted("Ins Position (latitude, longitude, altitude)\n\nThe estimated position given as latitude, longitude, and altitude given in [deg, deg, m] respectively."); }, | |
1610 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | |
1611 | ✗ | [](VectorNavSensor* /* sensor */, 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); } }, | |
1612 | { /* 2 */ "PosEcef", vn::protocol::uart::InsGroup::INSGROUP_POSECEF, | ||
1613 | ✗ | []() { ImGui::TextUnformatted("Ins Position (ECEF)\n\nThe estimated position given in the Earth centered Earth fixed (ECEF) frame, reported in meters."); }, | |
1614 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | |
1615 | ✗ | [](VectorNavSensor* /* sensor */, 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); } }, | |
1616 | { /* 3 */ "VelBody", vn::protocol::uart::InsGroup::INSGROUP_VELBODY, | ||
1617 | ✗ | []() { ImGui::TextUnformatted("Ins Velocity (Body)\n\nThe estimated velocity in the body frame, given in m/s."); }, | |
1618 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | |
1619 | ✗ | [](VectorNavSensor* /* sensor */, 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); } }, | |
1620 | { /* 4 */ "VelNed", vn::protocol::uart::InsGroup::INSGROUP_VELNED, | ||
1621 | ✗ | []() { ImGui::TextUnformatted("Ins Velocity (NED)\n\nThe estimated velocity in the North East Down (NED) frame, given in m/s."); }, | |
1622 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | |
1623 | ✗ | [](VectorNavSensor* /* sensor */, 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); } }, | |
1624 | { /* 5 */ "VelEcef", vn::protocol::uart::InsGroup::INSGROUP_VELECEF, | ||
1625 | ✗ | []() { ImGui::TextUnformatted("Ins Velocity (ECEF)\n\nThe estimated velocity in the Earth centered Earth fixed (ECEF) frame, given in m/s."); }, | |
1626 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | |
1627 | ✗ | [](VectorNavSensor* /* sensor */, 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); } }, | |
1628 | { /* 6 */ "MagEcef", vn::protocol::uart::InsGroup::INSGROUP_MAGECEF, | ||
1629 | ✗ | []() { ImGui::TextUnformatted("Compensated magnetic (ECEF)\n\nThe compensated magnetic measurement in the Earth centered Earth fixed (ECEF) frame, given in Gauss."); }, | |
1630 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | |
1631 | ✗ | [](VectorNavSensor* /* sensor */, 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); } }, | |
1632 | { /* 7 */ "AccelEcef", vn::protocol::uart::InsGroup::INSGROUP_ACCELECEF, | ||
1633 | ✗ | []() { 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)."); }, | |
1634 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | |
1635 | ✗ | [](VectorNavSensor* /* sensor */, 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); } }, | |
1636 | { /* 8 */ "LinearAccelEcef", vn::protocol::uart::InsGroup::INSGROUP_LINEARACCELECEF, | ||
1637 | ✗ | []() { 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."); }, | |
1638 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | |
1639 | ✗ | [](VectorNavSensor* /* sensor */, 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); } }, | |
1640 | { /* 9 */ "PosU", vn::protocol::uart::InsGroup::INSGROUP_POSU, | ||
1641 | ✗ | []() { ImGui::TextUnformatted("Ins Position Uncertainty\n\nThe estimated uncertainty (1 Sigma) in the current position estimate, given in meters."); }, | |
1642 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | |
1643 | ✗ | [](VectorNavSensor* /* sensor */, 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); } }, | |
1644 | { /* 10 */ "VelU", vn::protocol::uart::InsGroup::INSGROUP_VELU, | ||
1645 | ✗ | []() { ImGui::TextUnformatted("Ins Velocity Uncertainty\n\nThe estimated uncertainty (1 Sigma) in the current velocity estimate, given in m/s."); }, | |
1646 | ✗ | [](VectorNavModel sensorModel, const vn::sensors::BinaryOutputRegister& /* bor */, uint32_t /* binaryField */) { return sensorModel == VectorNavModel::VN310; }, | |
1647 | ✗ | [](VectorNavSensor* /* sensor */, 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); } }, | |
1648 | } }; | ||
1649 | |||
1650 | // NOLINTEND | ||
1651 | |||
1652 | 112 | NAV::VectorNavSensor::VectorNavSensor() | |
1653 |
4/8✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 112 times.
✗ Branch 5 not taken.
✓ Branch 9 taken 112 times.
✗ Branch 10 not taken.
✓ Branch 15 taken 112 times.
✗ Branch 16 not taken.
|
112 | : Imu(typeStatic()) |
1654 | { | ||
1655 | LOG_TRACE("{}: called", name); | ||
1656 | |||
1657 | 112 | _onlyRealTime = true; | |
1658 | 112 | _hasConfig = true; | |
1659 | 112 | _guiConfigDefaultWindowSize = { 954, 783 }; | |
1660 | |||
1661 |
4/8✓ Branch 2 taken 112 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 112 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 112 times.
✓ Branch 10 taken 112 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
|
448 | nm::CreateOutputPin(this, "Ascii Output", Pin::Type::Flow, { NAV::StringObs::type() }); |
1662 |
4/8✓ Branch 2 taken 112 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 112 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 112 times.
✓ Branch 10 taken 112 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
|
448 | nm::CreateOutputPin(this, "Binary Output 1", Pin::Type::Flow, { NAV::VectorNavBinaryOutput::type() }); |
1663 |
4/8✓ Branch 2 taken 112 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 112 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 112 times.
✓ Branch 10 taken 112 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
|
448 | nm::CreateOutputPin(this, "Binary Output 2", Pin::Type::Flow, { NAV::VectorNavBinaryOutput::type() }); |
1664 |
4/8✓ Branch 2 taken 112 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 112 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 112 times.
✓ Branch 10 taken 112 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
|
448 | nm::CreateOutputPin(this, "Binary Output 3", Pin::Type::Flow, { NAV::VectorNavBinaryOutput::type() }); |
1665 | |||
1666 | ✗ | _dividerFrequency = []() { | |
1667 | 112 | std::map<int, int, std::greater<>> divFreq; | |
1668 |
2/2✓ Branch 0 taken 89600 times.
✓ Branch 1 taken 112 times.
|
89712 | for (int freq = 1; freq <= IMU_DEFAULT_FREQUENCY; freq++) |
1669 | { | ||
1670 | 89600 | int divider = static_cast<int>(std::round(IMU_DEFAULT_FREQUENCY / freq)); | |
1671 | |||
1672 |
1/2✓ Branch 1 taken 89600 times.
✗ Branch 2 not taken.
|
89600 | if (!divFreq.contains(divider) |
1673 |
7/8✓ Branch 0 taken 83328 times.
✓ Branch 1 taken 6272 times.
✓ Branch 4 taken 83328 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 51296 times.
✓ Branch 8 taken 32032 times.
✓ Branch 9 taken 57568 times.
✓ Branch 10 taken 32032 times.
|
89600 | || std::abs(divider - IMU_DEFAULT_FREQUENCY / freq) < std::abs(divider - IMU_DEFAULT_FREQUENCY / divFreq.at(divider))) |
1674 | { | ||
1675 |
1/2✓ Branch 1 taken 57568 times.
✗ Branch 2 not taken.
|
57568 | divFreq[divider] = freq; |
1676 | } | ||
1677 | } | ||
1678 | 112 | std::vector<uint16_t> divs; | |
1679 | 112 | std::vector<std::string> freqs; | |
1680 |
2/2✓ Branch 6 taken 6272 times.
✓ Branch 7 taken 112 times.
|
6384 | for (auto& [divider, freq] : divFreq) |
1681 | { | ||
1682 |
1/2✓ Branch 1 taken 6272 times.
✗ Branch 2 not taken.
|
6272 | divs.push_back(static_cast<uint16_t>(divider)); |
1683 |
2/4✓ Branch 2 taken 6272 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 6272 times.
✗ Branch 6 not taken.
|
6272 | freqs.push_back(std::to_string(freq) + " Hz"); |
1684 | LOG_DATA("VectorNavSensor: RateDivisor {} = {}", divs.back(), freqs.back()); | ||
1685 | } | ||
1686 |
1/2✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
|
224 | return std::make_pair(divs, freqs); |
1687 |
1/2✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
|
224 | }(); |
1688 | 560 | } | |
1689 | |||
1690 | 224 | NAV::VectorNavSensor::~VectorNavSensor() | |
1691 | { | ||
1692 | LOG_TRACE("{}: called", nameId()); | ||
1693 | 224 | } | |
1694 | |||
1695 | 224 | std::string NAV::VectorNavSensor::typeStatic() | |
1696 | { | ||
1697 |
1/2✓ Branch 1 taken 224 times.
✗ Branch 2 not taken.
|
448 | return "VectorNavSensor"; |
1698 | } | ||
1699 | |||
1700 | ✗ | std::string NAV::VectorNavSensor::type() const | |
1701 | { | ||
1702 | ✗ | return typeStatic(); | |
1703 | } | ||
1704 | |||
1705 | 112 | std::string NAV::VectorNavSensor::category() | |
1706 | { | ||
1707 |
1/2✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
|
224 | return "Data Provider"; |
1708 | } | ||
1709 | |||
1710 | ✗ | void NAV::VectorNavSensor::guiConfig() | |
1711 | { | ||
1712 | ✗ | if (auto sensorModel = static_cast<int>(_sensorModel); | |
1713 | ✗ | ImGui::Combo("Sensor", &sensorModel, "VN-100 / VN-110\0VN-310\0\0")) | |
1714 | { | ||
1715 | ✗ | _sensorModel = static_cast<decltype(_sensorModel)>(sensorModel); | |
1716 | ✗ | LOG_DEBUG("{}: Sensor changed to {}", nameId(), fmt::underlying(_sensorModel)); | |
1717 | ✗ | flow::ApplyChanges(); | |
1718 | ✗ | doDeinitialize(); | |
1719 | |||
1720 | ✗ | if (_sensorModel != VectorNavModel::VN310 | |
1721 | ✗ | && (_asyncDataOutputType == vn::protocol::uart::AsciiAsync::VNGPS | |
1722 | ✗ | || _asyncDataOutputType == vn::protocol::uart::AsciiAsync::VNGPE | |
1723 | ✗ | || _asyncDataOutputType == vn::protocol::uart::AsciiAsync::VNINS | |
1724 | ✗ | || _asyncDataOutputType == vn::protocol::uart::AsciiAsync::VNINE | |
1725 | ✗ | || _asyncDataOutputType == vn::protocol::uart::AsciiAsync::VNISL | |
1726 | ✗ | || _asyncDataOutputType == vn::protocol::uart::AsciiAsync::VNISE | |
1727 | ✗ | || _asyncDataOutputType == vn::protocol::uart::AsciiAsync::VNG2S | |
1728 | ✗ | || _asyncDataOutputType == vn::protocol::uart::AsciiAsync::VNG2E)) | |
1729 | { | ||
1730 | ✗ | _asyncDataOutputType = vn::protocol::uart::AsciiAsync::VNOFF; | |
1731 | } | ||
1732 | |||
1733 | ✗ | if (_sensorModel == VectorNavModel::VN310) | |
1734 | { | ||
1735 | ✗ | _communicationProtocolControlRegister.spiCount = vn::protocol::uart::CountMode::COUNTMODE_NONE; | |
1736 | ✗ | _communicationProtocolControlRegister.spiStatus = vn::protocol::uart::StatusMode::STATUSMODE_OFF; | |
1737 | ✗ | _communicationProtocolControlRegister.spiChecksum = vn::protocol::uart::ChecksumMode::CHECKSUMMODE_OFF; | |
1738 | } | ||
1739 | |||
1740 | ✗ | for (auto& binaryOutput : _binaryOutputRegister) | |
1741 | { | ||
1742 | // for (const auto& item : _binaryGroupCommon) | ||
1743 | // { | ||
1744 | // if (!item.isEnabled(_sensorModel, binaryOutput, static_cast<uint32_t>(binaryOutput.commonField))) | ||
1745 | // { | ||
1746 | // binaryOutput.commonField &= ~vn::protocol::uart::CommonGroup(item.flagsValue); | ||
1747 | // } | ||
1748 | // } | ||
1749 | ✗ | for (size_t i = 0; i < _binaryGroupTime.size(); i++) | |
1750 | { | ||
1751 | ✗ | const auto& item = _binaryGroupTime.at(i); | |
1752 | |||
1753 | ✗ | if (i == 0 /* TimeStartup */ || i == 9 /* TimeStatus */) { continue; } // Do not reset the field | |
1754 | |||
1755 | // Check the fields if conditions are met | ||
1756 | ✗ | if ((i == 2 /* GpsTow */ || i == 3 /* GpsWeek */) | |
1757 | ✗ | && _sensorModel == VectorNavModel::VN310 | |
1758 | ✗ | && binaryOutput.timeField & vn::protocol::uart::TIMEGROUP_TIMESTARTUP | |
1759 | ✗ | && !_binaryGroupTime.at(0).isEnabled(_sensorModel, binaryOutput, static_cast<uint32_t>(binaryOutput.timeField))) | |
1760 | { | ||
1761 | ✗ | binaryOutput.timeField |= vn::protocol::uart::TimeGroup(item.flagsValue); | |
1762 | ✗ | continue; | |
1763 | } | ||
1764 | |||
1765 | ✗ | if (!item.isEnabled(_sensorModel, binaryOutput, static_cast<uint32_t>(binaryOutput.timeField))) | |
1766 | { | ||
1767 | ✗ | binaryOutput.timeField &= ~vn::protocol::uart::TimeGroup(item.flagsValue); | |
1768 | } | ||
1769 | } | ||
1770 | ✗ | for (const auto& item : _binaryGroupIMU) | |
1771 | { | ||
1772 | ✗ | if (!item.isEnabled(_sensorModel, binaryOutput, static_cast<uint32_t>(binaryOutput.imuField))) | |
1773 | { | ||
1774 | ✗ | binaryOutput.imuField &= ~vn::protocol::uart::ImuGroup(item.flagsValue); | |
1775 | } | ||
1776 | } | ||
1777 | ✗ | for (const auto& item : _binaryGroupGNSS) | |
1778 | { | ||
1779 | ✗ | if (!item.isEnabled(_sensorModel, binaryOutput, static_cast<uint32_t>(binaryOutput.gpsField))) | |
1780 | { | ||
1781 | ✗ | binaryOutput.gpsField &= ~vn::protocol::uart::GpsGroup(item.flagsValue); | |
1782 | } | ||
1783 | ✗ | if (!item.isEnabled(_sensorModel, binaryOutput, static_cast<uint32_t>(binaryOutput.gps2Field))) | |
1784 | { | ||
1785 | ✗ | binaryOutput.gps2Field &= ~vn::protocol::uart::GpsGroup(item.flagsValue); | |
1786 | } | ||
1787 | } | ||
1788 | ✗ | for (const auto& item : _binaryGroupAttitude) | |
1789 | { | ||
1790 | ✗ | if (!item.isEnabled(_sensorModel, binaryOutput, static_cast<uint32_t>(binaryOutput.attitudeField))) | |
1791 | { | ||
1792 | ✗ | binaryOutput.attitudeField &= ~vn::protocol::uart::AttitudeGroup(item.flagsValue); | |
1793 | } | ||
1794 | } | ||
1795 | ✗ | for (const auto& item : _binaryGroupINS) | |
1796 | { | ||
1797 | ✗ | if (!item.isEnabled(_sensorModel, binaryOutput, static_cast<uint32_t>(binaryOutput.insField))) | |
1798 | { | ||
1799 | ✗ | binaryOutput.insField &= ~vn::protocol::uart::InsGroup(item.flagsValue); | |
1800 | } | ||
1801 | } | ||
1802 | } | ||
1803 | } | ||
1804 | |||
1805 | ✗ | if (ImGui::InputTextWithHint("SensorPort", _connectedSensorPort.empty() ? "/dev/ttyUSB0" : _connectedSensorPort.c_str(), &_sensorPort)) | |
1806 | { | ||
1807 | ✗ | LOG_DEBUG("{}: SensorPort changed to {}", nameId(), _sensorPort); | |
1808 | ✗ | flow::ApplyChanges(); | |
1809 | ✗ | if (isInitialized()) | |
1810 | { | ||
1811 | ✗ | doDeinitialize(); | |
1812 | } | ||
1813 | } | ||
1814 | ✗ | ImGui::SameLine(); | |
1815 | ✗ | gui::widgets::HelpMarker("COM port where the sensor is attached to\n" | |
1816 | "- \"COM1\" (Windows format for physical and virtual (USB) serial port)\n" | ||
1817 | "- \"/dev/ttyS1\" (Linux format for physical serial port)\n" | ||
1818 | "- \"/dev/ttyUSB0\" (Linux format for virtual (USB) serial port)\n" | ||
1819 | "- \"/dev/tty.usbserial-FTXXXXXX\" (Mac OS X format for virtual (USB) serial port)\n" | ||
1820 | "- \"/dev/ttyS0\" (CYGWIN format. Usually the Windows COM port number minus 1. This would connect to COM1)"); | ||
1821 | |||
1822 | ✗ | bool isNodeInitialized = isInitialized(); | |
1823 | ✗ | if (!isNodeInitialized) | |
1824 | { | ||
1825 | ✗ | ImGui::BeginDisabled(); | |
1826 | } | ||
1827 | ✗ | if (ImGui::Button("Write settings")) | |
1828 | { | ||
1829 | try | ||
1830 | { | ||
1831 | ✗ | _vs.writeSettings(); | |
1832 | } | ||
1833 | ✗ | catch (const std::exception& e) | |
1834 | { | ||
1835 | ✗ | LOG_ERROR("{}: Write settings threw an exception: {}", nameId(), e.what()); | |
1836 | ✗ | } | |
1837 | } | ||
1838 | ✗ | if (!isNodeInitialized) | |
1839 | { | ||
1840 | ✗ | ImGui::EndDisabled(); | |
1841 | } | ||
1842 | ✗ | if (ImGui::IsItemHovered()) | |
1843 | { | ||
1844 | ✗ | ImGui::SetTooltip("This command will write the current register settings into non-volatile memory. Once the settings are stored\n" | |
1845 | "in non-volatile (Flash) memory, the VN-310E module can be power cycled or reset, and the register will be\n" | ||
1846 | "reloaded from non-volatile memory.\n\n" | ||
1847 | "Due to limitations in the flash write speed the write settings command takes ~ 500ms to\n" | ||
1848 | "complete. Any commands that are sent to the sensor during this time will be responded to after\n" | ||
1849 | "the operation is complete.\n\n" | ||
1850 | "The sensor must be stationary when issuing a Write Settings Command otherwise a Reset\n" | ||
1851 | "command must also be issued to prevent the Kalman Filter from diverging during the write\n" | ||
1852 | "settings process.\n\n" | ||
1853 | "A write settings command is automatically send after initializing the node."); | ||
1854 | } | ||
1855 | ✗ | ImGui::SameLine(); | |
1856 | ✗ | if (!isNodeInitialized) | |
1857 | { | ||
1858 | ✗ | ImGui::BeginDisabled(); | |
1859 | } | ||
1860 | ✗ | if (ImGui::Button("Restore factory settings")) | |
1861 | { | ||
1862 | try | ||
1863 | { | ||
1864 | ✗ | _vs.restoreFactorySettings(); | |
1865 | } | ||
1866 | ✗ | catch (const std::exception& e) | |
1867 | { | ||
1868 | ✗ | LOG_ERROR("{}: Restore factory settings threw an exception: {}", nameId(), e.what()); | |
1869 | ✗ | } | |
1870 | } | ||
1871 | ✗ | if (!isNodeInitialized) | |
1872 | { | ||
1873 | ✗ | ImGui::EndDisabled(); | |
1874 | } | ||
1875 | ✗ | if (ImGui::IsItemHovered()) | |
1876 | { | ||
1877 | ✗ | ImGui::SetTooltip("This command will restore the VN-310E module's factory default settings and will reset the module. There\n" | |
1878 | "are no parameters for this command. The module will respond to this command before restoring the factory\n" | ||
1879 | "settings."); | ||
1880 | } | ||
1881 | ✗ | ImGui::SameLine(); | |
1882 | ✗ | if (!isNodeInitialized) | |
1883 | { | ||
1884 | ✗ | ImGui::BeginDisabled(); | |
1885 | } | ||
1886 | ✗ | if (ImGui::Button("Reset sensor")) | |
1887 | { | ||
1888 | try | ||
1889 | { | ||
1890 | ✗ | _vs.reset(); | |
1891 | } | ||
1892 | ✗ | catch (const std::exception& e) | |
1893 | { | ||
1894 | ✗ | LOG_ERROR("{}: Resetting threw an exception: {}", nameId(), e.what()); | |
1895 | ✗ | } | |
1896 | } | ||
1897 | ✗ | if (!isNodeInitialized) | |
1898 | { | ||
1899 | ✗ | ImGui::EndDisabled(); | |
1900 | } | ||
1901 | ✗ | if (ImGui::IsItemHovered()) | |
1902 | { | ||
1903 | ✗ | ImGui::SetTooltip("This command will reset the module. There are no parameters required for this command. The module will\n" | |
1904 | "first respond to the command and will then perform a reset. Upon a reset all registers will be reloaded with\n" | ||
1905 | "the values saved in non-volatile memory. If no values are stored in non-volatile memory, the device will default\n" | ||
1906 | "to factory settings. Also upon reset the VN-310E will re-initialize its Kalman filter, thus the filter will take a\n" | ||
1907 | "few seconds to completely converge on the correct attitude and correct for gyro bias."); | ||
1908 | } | ||
1909 | |||
1910 | // ########################################################################################################### | ||
1911 | // SYSTEM MODULE | ||
1912 | // ########################################################################################################### | ||
1913 | |||
1914 | ✗ | ImGui::SetNextItemOpen(true, ImGuiCond_FirstUseEver); | |
1915 | ✗ | if (ImGui::CollapsingHeader(fmt::format("System Module##{}", size_t(id)).c_str())) | |
1916 | { | ||
1917 | // ------------------------------------------- Serial Baud Rate ---------------------------------------------- | ||
1918 | |||
1919 | ✗ | std::array<const char*, 10> items = { "Fastest", "9600", "19200", "38400", "57600", "115200", "128000", "230400", "460800", "921600" }; | |
1920 | ✗ | if (ImGui::Combo("Baudrate", &_selectedBaudrate, items.data(), items.size())) | |
1921 | { | ||
1922 | ✗ | LOG_DEBUG("{}: Baudrate changed to {}", nameId(), sensorBaudrate()); | |
1923 | ✗ | flow::ApplyChanges(); | |
1924 | ✗ | doDeinitialize(); | |
1925 | } | ||
1926 | |||
1927 | ✗ | if (ImGui::TreeNode(fmt::format("Async Ascii Output##{}", size_t(id)).c_str())) | |
1928 | { | ||
1929 | std::vector<std::pair<vn::protocol::uart::AsciiAsync, const char*>> asciiAsyncItems{ | ||
1930 | { vn::protocol::uart::AsciiAsync::VNOFF, "Asynchronous output turned off" }, | ||
1931 | { vn::protocol::uart::AsciiAsync::VNYPR, "Yaw, Pitch, Roll" }, | ||
1932 | { vn::protocol::uart::AsciiAsync::VNQTN, "Quaternion" }, | ||
1933 | { vn::protocol::uart::AsciiAsync::VNQMR, "Quaternion, Magnetic, Acceleration and Angular Rates" }, | ||
1934 | { vn::protocol::uart::AsciiAsync::VNMAG, "Magnetic Measurements" }, | ||
1935 | { vn::protocol::uart::AsciiAsync::VNACC, "Acceleration Measurements" }, | ||
1936 | { vn::protocol::uart::AsciiAsync::VNGYR, "Angular Rate Measurements" }, | ||
1937 | { vn::protocol::uart::AsciiAsync::VNMAR, "Magnetic, Acceleration, and Angular Rate Measurements" }, | ||
1938 | { vn::protocol::uart::AsciiAsync::VNYMR, "Yaw, Pitch, Roll, Magnetic, Acceleration, and Angular Rate Measurements" }, | ||
1939 | { vn::protocol::uart::AsciiAsync::VNYBA, "Yaw, Pitch, Roll, Body True Acceleration, and Angular Rates" }, | ||
1940 | { vn::protocol::uart::AsciiAsync::VNYIA, "Yaw, Pitch, Roll, Inertial True Acceleration, and Angular Rates" }, | ||
1941 | { vn::protocol::uart::AsciiAsync::VNIMU, "IMU Measurements" } | ||
1942 | ✗ | }; | |
1943 | ✗ | if (_sensorModel == VectorNavModel::VN310) | |
1944 | { | ||
1945 | ✗ | asciiAsyncItems.emplace_back(vn::protocol::uart::AsciiAsync::VNGPS, "GNSS LLA"); | |
1946 | ✗ | asciiAsyncItems.emplace_back(vn::protocol::uart::AsciiAsync::VNGPE, "GNSS ECEF"); | |
1947 | ✗ | asciiAsyncItems.emplace_back(vn::protocol::uart::AsciiAsync::VNINS, "INS LLA"); | |
1948 | ✗ | asciiAsyncItems.emplace_back(vn::protocol::uart::AsciiAsync::VNINE, "INS ECEF"); | |
1949 | ✗ | asciiAsyncItems.emplace_back(vn::protocol::uart::AsciiAsync::VNISL, "INS LLA 2"); | |
1950 | ✗ | asciiAsyncItems.emplace_back(vn::protocol::uart::AsciiAsync::VNISE, "INS ECEF 2"); | |
1951 | } | ||
1952 | ✗ | asciiAsyncItems.emplace_back(vn::protocol::uart::AsciiAsync::VNDTV, "Delta theta and delta velocity"); | |
1953 | ✗ | if (_sensorModel == VectorNavModel::VN310) | |
1954 | { | ||
1955 | ✗ | asciiAsyncItems.emplace_back(vn::protocol::uart::AsciiAsync::VNG2S, "GNSS2 LLA"); | |
1956 | ✗ | asciiAsyncItems.emplace_back(vn::protocol::uart::AsciiAsync::VNG2E, "GNSS2 ECEF"); | |
1957 | } | ||
1958 | |||
1959 | ✗ | if (ImGui::BeginCombo(fmt::format("Async Ascii Output Type##{}", size_t(id)).c_str(), vn::protocol::uart::str(_asyncDataOutputType).c_str())) | |
1960 | { | ||
1961 | ✗ | for (const auto& asciiAsyncItem : asciiAsyncItems) | |
1962 | { | ||
1963 | ✗ | const bool isSelected = (_asyncDataOutputType == asciiAsyncItem.first); | |
1964 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(asciiAsyncItem.first).c_str(), isSelected)) | |
1965 | { | ||
1966 | ✗ | _asyncDataOutputType = asciiAsyncItem.first; | |
1967 | ✗ | LOG_DEBUG("{}: _asyncDataOutputType changed to {}", nameId(), vn::protocol::uart::str(_asyncDataOutputType)); | |
1968 | ✗ | flow::ApplyChanges(); | |
1969 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
1970 | { | ||
1971 | try | ||
1972 | { | ||
1973 | ✗ | _vs.writeAsyncDataOutputType(_asyncDataOutputType); | |
1974 | } | ||
1975 | ✗ | catch (const std::exception& e) | |
1976 | { | ||
1977 | ✗ | LOG_ERROR("{}: Could not configure the asyncDataOutputType: {}", nameId(), e.what()); | |
1978 | ✗ | doDeinitialize(); | |
1979 | ✗ | } | |
1980 | } | ||
1981 | else | ||
1982 | { | ||
1983 | ✗ | doDeinitialize(); | |
1984 | } | ||
1985 | } | ||
1986 | ✗ | if (ImGui::IsItemHovered()) | |
1987 | { | ||
1988 | ✗ | ImGui::BeginTooltip(); | |
1989 | ✗ | ImGui::TextUnformatted(asciiAsyncItem.second); | |
1990 | ✗ | ImGui::EndTooltip(); | |
1991 | } | ||
1992 | |||
1993 | // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | ||
1994 | ✗ | if (isSelected) | |
1995 | { | ||
1996 | ✗ | ImGui::SetItemDefaultFocus(); | |
1997 | } | ||
1998 | } | ||
1999 | ✗ | ImGui::EndCombo(); | |
2000 | } | ||
2001 | ✗ | ImGui::SameLine(); | |
2002 | ✗ | gui::widgets::HelpMarker("This register controls the type of data that will be asynchronously outputted by the module. With this " | |
2003 | "register, the user can specify which data register will be automatically outputted when it gets updated " | ||
2004 | "with a new reading. The table below lists which registers can be set to asynchronously output, the value " | ||
2005 | "to specify which register to output, and the header of the asynchronous data packet. Asynchronous data " | ||
2006 | "output can be disabled by setting this register to zero. The asynchronous data output will be sent out " | ||
2007 | "automatically at a frequency specified by the Async Data Output Frequency Register."); | ||
2008 | |||
2009 | ✗ | if (ImGui::SliderInt(fmt::format("Async Ascii Output Frequency##{}", size_t(id)).c_str(), | |
2010 | &_asyncDataOutputFrequencySelected, | ||
2011 | ✗ | 0, _possibleAsyncDataOutputFrequency.size() - 1, | |
2012 | ✗ | fmt::format("{} Hz", _possibleAsyncDataOutputFrequency.at(static_cast<size_t>(_asyncDataOutputFrequencySelected))).c_str())) | |
2013 | { | ||
2014 | ✗ | _asyncDataOutputFrequency = static_cast<uint32_t>(_possibleAsyncDataOutputFrequency.at(static_cast<size_t>(_asyncDataOutputFrequencySelected))); | |
2015 | ✗ | LOG_DEBUG("{}: asyncDataOutputFrequency changed to {} Hz", nameId(), _asyncDataOutputFrequency); | |
2016 | ✗ | flow::ApplyChanges(); | |
2017 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
2018 | { | ||
2019 | try | ||
2020 | { | ||
2021 | ✗ | _vs.writeAsyncDataOutputFrequency(_asyncDataOutputFrequency); | |
2022 | } | ||
2023 | ✗ | catch (const std::exception& e) | |
2024 | { | ||
2025 | ✗ | LOG_ERROR("{}: Could not configure the asyncDataOutputFrequency: {}", nameId(), e.what()); | |
2026 | ✗ | doDeinitialize(); | |
2027 | ✗ | } | |
2028 | } | ||
2029 | else | ||
2030 | { | ||
2031 | ✗ | doDeinitialize(); | |
2032 | } | ||
2033 | } | ||
2034 | ✗ | ImGui::SameLine(); | |
2035 | ✗ | gui::widgets::HelpMarker("Asynchronous data output frequency.\nThe ADOF will be changed for the active serial port."); | |
2036 | |||
2037 | ✗ | if (ImGui::DragInt(fmt::format("Async Ascii Output buffer size##{}", size_t(id)).c_str(), &_asciiOutputBufferSize, 1.0F, 0, INT32_MAX / 2)) | |
2038 | { | ||
2039 | ✗ | _asciiOutputBuffer.resize(static_cast<size_t>(_asciiOutputBufferSize)); | |
2040 | ✗ | LOG_DEBUG("{}: asciiOutputBufferSize changed to {}", nameId(), _asciiOutputBufferSize); | |
2041 | ✗ | flow::ApplyChanges(); | |
2042 | } | ||
2043 | |||
2044 | ✗ | std::string messages; | |
2045 | ✗ | for (const auto& msg : _asciiOutputBuffer) | |
2046 | { | ||
2047 | ✗ | messages.append(msg); | |
2048 | } | ||
2049 | ✗ | ImGui::TextUnformatted("Async Ascii Messages:"); | |
2050 | ✗ | ImGui::BeginChild(fmt::format("##Ascii Mesages {}", size_t(id)).c_str(), ImVec2(0, 300), true); | |
2051 | ✗ | ImGui::PushTextWrapPos(); | |
2052 | ✗ | ImGui::TextUnformatted(messages.c_str()); | |
2053 | ✗ | ImGui::PopTextWrapPos(); | |
2054 | ✗ | ImGui::EndChild(); | |
2055 | |||
2056 | ✗ | ImGui::TreePop(); | |
2057 | ✗ | } | |
2058 | |||
2059 | ✗ | if (ImGui::TreeNode(fmt::format("Synchronization Control##{}", size_t(id)).c_str())) | |
2060 | { | ||
2061 | ✗ | ImGui::TextUnformatted("Contains parameters which allow the timing of the VN-310E to be\n" | |
2062 | "synchronized with external devices."); | ||
2063 | |||
2064 | ✗ | if (ImGui::Checkbox(fmt::format("Show SyncIn Pin##{}", size_t(id)).c_str(), &_syncInPin)) | |
2065 | { | ||
2066 | ✗ | LOG_DEBUG("{}: syncInPin changed to {}", nameId(), _syncInPin); | |
2067 | ✗ | if (_syncInPin) | |
2068 | { | ||
2069 | ✗ | _synchronizationControlRegister.syncInMode = vn::protocol::uart::SyncInMode::SYNCINMODE_COUNT; | |
2070 | ✗ | LOG_DEBUG("{}: synchronizationControlRegister.syncInMode changed to {}", nameId(), vn::protocol::uart::str(_synchronizationControlRegister.syncInMode)); | |
2071 | } | ||
2072 | ✗ | flow::ApplyChanges(); | |
2073 | ✗ | if (_syncInPin && inputPins.empty()) | |
2074 | { | ||
2075 | ✗ | nm::CreateInputPin(this, "SyncIn", Pin::Type::Object, { "TimeSync" }); | |
2076 | } | ||
2077 | ✗ | else if (!_syncInPin && !inputPins.empty()) | |
2078 | { | ||
2079 | ✗ | nm::DeleteInputPin(inputPins.front()); | |
2080 | } | ||
2081 | } | ||
2082 | |||
2083 | static constexpr std::array<std::pair<vn::protocol::uart::SyncInMode, const char*>, 4> synchronizationControlSyncInModes = { | ||
2084 | { { vn::protocol::uart::SyncInMode::SYNCINMODE_COUNT, "Count number of trigger events on SYNC_IN" }, | ||
2085 | { vn::protocol::uart::SyncInMode::SYNCINMODE_IMU, "Start IMU sampling on trigger of SYNC_IN" }, | ||
2086 | { vn::protocol::uart::SyncInMode::SYNCINMODE_ASYNC, "Output asynchronous message on trigger of SYNC_IN" }, | ||
2087 | { 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" | ||
2088 | "In ASYNC3 mode messages configured with an output rate = 0 are output each time the appropriate\n" | ||
2089 | "transistion edge of the SyncIn pin is captured according to the edge settings in the SyncInEdge field.\n" | ||
2090 | "Messages configured with output rate > 0 are not affected by the SyncIn pulse. This applies to the ASCII\n" | ||
2091 | "Async message set by the Async Data Output Register, the user configurate binary output messages set\n" | ||
2092 | "by the Binary Output Registers, as well as the NMEA messages configured by the NMEA Output Registers." } } | ||
2093 | }; | ||
2094 | ✗ | if (_syncInPin) | |
2095 | { | ||
2096 | ✗ | ImGui::BeginDisabled(); | |
2097 | } | ||
2098 | |||
2099 | ✗ | if (ImGui::BeginCombo(fmt::format("SyncIn Mode##{}", size_t(id)).c_str(), vn::protocol::uart::str(_synchronizationControlRegister.syncInMode).c_str())) | |
2100 | { | ||
2101 | ✗ | for (const auto& synchronizationControlSyncInMode : synchronizationControlSyncInModes) | |
2102 | { | ||
2103 | ✗ | const bool isSelected = (_synchronizationControlRegister.syncInMode == synchronizationControlSyncInMode.first); | |
2104 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(synchronizationControlSyncInMode.first).c_str(), isSelected)) | |
2105 | { | ||
2106 | ✗ | _synchronizationControlRegister.syncInMode = synchronizationControlSyncInMode.first; | |
2107 | ✗ | LOG_DEBUG("{}: synchronizationControlRegister.syncInMode changed to {}", nameId(), vn::protocol::uart::str(_synchronizationControlRegister.syncInMode)); | |
2108 | ✗ | flow::ApplyChanges(); | |
2109 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
2110 | { | ||
2111 | try | ||
2112 | { | ||
2113 | ✗ | _vs.writeSynchronizationControl(_synchronizationControlRegister); | |
2114 | } | ||
2115 | ✗ | catch (const std::exception& e) | |
2116 | { | ||
2117 | ✗ | LOG_ERROR("{}: Could not configure the synchronizationControlRegister: {}", nameId(), e.what()); | |
2118 | ✗ | doDeinitialize(); | |
2119 | ✗ | } | |
2120 | } | ||
2121 | else | ||
2122 | { | ||
2123 | ✗ | doDeinitialize(); | |
2124 | } | ||
2125 | } | ||
2126 | ✗ | if (ImGui::IsItemHovered()) | |
2127 | { | ||
2128 | ✗ | ImGui::BeginTooltip(); | |
2129 | ✗ | ImGui::TextUnformatted(synchronizationControlSyncInMode.second); | |
2130 | ✗ | ImGui::EndTooltip(); | |
2131 | } | ||
2132 | |||
2133 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
2134 | { | ||
2135 | ✗ | ImGui::SetItemDefaultFocus(); | |
2136 | } | ||
2137 | } | ||
2138 | ✗ | ImGui::EndCombo(); | |
2139 | } | ||
2140 | ✗ | ImGui::SameLine(); | |
2141 | ✗ | gui::widgets::HelpMarker("The SyncInMode register controls the behavior of the SyncIn event. If the mode is set to COUNT then the " | |
2142 | "internal clock will be used to control the IMU sampling. If SyncInMode is set to IMU then the IMU sampling " | ||
2143 | "loop will run on a SyncIn event. The relationship between the SyncIn event and a SyncIn trigger is defined " | ||
2144 | "by the SyncInEdge and SyncInSkipFactor parameters. If set to ASYNC then the VN-100 will output " | ||
2145 | "asynchronous serial messages upon each trigger event."); | ||
2146 | ✗ | if (_syncInPin) | |
2147 | { | ||
2148 | ✗ | ImGui::EndDisabled(); | |
2149 | } | ||
2150 | |||
2151 | static constexpr std::array<std::pair<vn::protocol::uart::SyncInEdge, const char*>, 2> synchronizationControlSyncInEdges = { | ||
2152 | { { vn::protocol::uart::SyncInEdge::SYNCINEDGE_RISING, "Trigger on rising edge" }, | ||
2153 | { vn::protocol::uart::SyncInEdge::SYNCINEDGE_FALLING, "Trigger on falling edge" } } | ||
2154 | }; | ||
2155 | ✗ | if (ImGui::BeginCombo(fmt::format("SyncIn Edge##{}", size_t(id)).c_str(), vn::protocol::uart::str(_synchronizationControlRegister.syncInEdge).c_str())) | |
2156 | { | ||
2157 | ✗ | for (const auto& synchronizationControlSyncInEdge : synchronizationControlSyncInEdges) | |
2158 | { | ||
2159 | ✗ | const bool isSelected = (_synchronizationControlRegister.syncInEdge == synchronizationControlSyncInEdge.first); | |
2160 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(synchronizationControlSyncInEdge.first).c_str(), isSelected)) | |
2161 | { | ||
2162 | ✗ | _synchronizationControlRegister.syncInEdge = synchronizationControlSyncInEdge.first; | |
2163 | ✗ | LOG_DEBUG("{}: synchronizationControlRegister.syncInEdge changed to {}", nameId(), vn::protocol::uart::str(_synchronizationControlRegister.syncInEdge)); | |
2164 | ✗ | flow::ApplyChanges(); | |
2165 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
2166 | { | ||
2167 | try | ||
2168 | { | ||
2169 | ✗ | _vs.writeSynchronizationControl(_synchronizationControlRegister); | |
2170 | } | ||
2171 | ✗ | catch (const std::exception& e) | |
2172 | { | ||
2173 | ✗ | LOG_ERROR("{}: Could not configure the synchronizationControlRegister: {}", nameId(), e.what()); | |
2174 | ✗ | doDeinitialize(); | |
2175 | ✗ | } | |
2176 | } | ||
2177 | else | ||
2178 | { | ||
2179 | ✗ | doDeinitialize(); | |
2180 | } | ||
2181 | } | ||
2182 | ✗ | if (ImGui::IsItemHovered()) | |
2183 | { | ||
2184 | ✗ | ImGui::BeginTooltip(); | |
2185 | ✗ | ImGui::TextUnformatted(synchronizationControlSyncInEdge.second); | |
2186 | ✗ | ImGui::EndTooltip(); | |
2187 | } | ||
2188 | |||
2189 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
2190 | { | ||
2191 | ✗ | ImGui::SetItemDefaultFocus(); | |
2192 | } | ||
2193 | } | ||
2194 | ✗ | ImGui::EndCombo(); | |
2195 | } | ||
2196 | ✗ | ImGui::SameLine(); | |
2197 | ✗ | gui::widgets::HelpMarker("The SyncInEdge register controls the type of edge the signal is set to trigger on.\n" | |
2198 | "The factory default state is to trigger on a rising edge."); | ||
2199 | |||
2200 | ✗ | int syncInSkipFactor = _synchronizationControlRegister.syncInSkipFactor; | |
2201 | ✗ | if (ImGui::InputInt(fmt::format("SyncIn Skip Factor##{}", size_t(id)).c_str(), &syncInSkipFactor)) | |
2202 | { | ||
2203 | ✗ | if (syncInSkipFactor < 0) | |
2204 | { | ||
2205 | ✗ | syncInSkipFactor = 0; | |
2206 | } | ||
2207 | ✗ | else if (syncInSkipFactor > std::numeric_limits<uint16_t>::max()) | |
2208 | { | ||
2209 | ✗ | syncInSkipFactor = std::numeric_limits<uint16_t>::max(); | |
2210 | } | ||
2211 | ✗ | _synchronizationControlRegister.syncInSkipFactor = static_cast<uint16_t>(syncInSkipFactor); | |
2212 | ✗ | LOG_DEBUG("{}: synchronizationControlRegister.syncInSkipFactor changed to {}", nameId(), _synchronizationControlRegister.syncInSkipFactor); | |
2213 | ✗ | flow::ApplyChanges(); | |
2214 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
2215 | { | ||
2216 | try | ||
2217 | { | ||
2218 | ✗ | _vs.writeSynchronizationControl(_synchronizationControlRegister); | |
2219 | } | ||
2220 | ✗ | catch (const std::exception& e) | |
2221 | { | ||
2222 | ✗ | LOG_ERROR("{}: Could not configure the synchronizationControlRegister: {}", nameId(), e.what()); | |
2223 | ✗ | doDeinitialize(); | |
2224 | ✗ | } | |
2225 | } | ||
2226 | else | ||
2227 | { | ||
2228 | ✗ | doDeinitialize(); | |
2229 | } | ||
2230 | } | ||
2231 | ✗ | ImGui::SameLine(); | |
2232 | ✗ | gui::widgets::HelpMarker("The SyncInSkipFactor defines how many times trigger edges defined by SyncInEdge should occur prior to " | |
2233 | "triggering a SyncIn event. The action performed on a SyncIn event is determined by the SyncIn mode. As an " | ||
2234 | "example if the SyncInSkipFactor was set to 4 and a 1 kHz signal was attached to the SyncIn pin, then the " | ||
2235 | "SyncIn event would only occur at 200 Hz."); | ||
2236 | |||
2237 | static constexpr std::array<std::pair<vn::protocol::uart::SyncOutMode, const char*>, 5> synchronizationControlSyncOutModes = { | ||
2238 | { { vn::protocol::uart::SyncOutMode::SYNCOUTMODE_NONE, "None" }, | ||
2239 | { vn::protocol::uart::SyncOutMode::SYNCOUTMODE_IMUSTART, "Trigger at start of IMU sampling" }, | ||
2240 | { vn::protocol::uart::SyncOutMode::SYNCOUTMODE_IMUREADY, "Trigger when IMU measurements are available" }, | ||
2241 | { vn::protocol::uart::SyncOutMode::SYNCOUTMODE_INS, "Trigger when attitude measurements are available" }, | ||
2242 | { vn::protocol::uart::SyncOutMode::SYNCOUTMODE_GPSPPS, "Trigger on a GPS PPS event (1 Hz) when a 3D fix is valid." } } | ||
2243 | }; | ||
2244 | ✗ | if (ImGui::BeginCombo(fmt::format("SyncOut Mode##{}", size_t(id)).c_str(), vn::protocol::uart::str(_synchronizationControlRegister.syncOutMode).c_str())) | |
2245 | { | ||
2246 | ✗ | for (const auto& synchronizationControlSyncOutMode : synchronizationControlSyncOutModes) | |
2247 | { | ||
2248 | ✗ | const bool isSelected = (_synchronizationControlRegister.syncOutMode == synchronizationControlSyncOutMode.first); | |
2249 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(synchronizationControlSyncOutMode.first).c_str(), isSelected)) | |
2250 | { | ||
2251 | ✗ | _synchronizationControlRegister.syncOutMode = synchronizationControlSyncOutMode.first; | |
2252 | ✗ | LOG_DEBUG("{}: synchronizationControlRegister.syncOutMode changed to {}", nameId(), vn::protocol::uart::str(_synchronizationControlRegister.syncOutMode)); | |
2253 | |||
2254 | ✗ | if (_synchronizationControlRegister.syncOutMode == vn::protocol::uart::SyncOutMode::SYNCOUTMODE_GPSPPS | |
2255 | ✗ | && outputPins.size() <= 4) | |
2256 | { | ||
2257 | ✗ | nm::CreateOutputPin(this, "SyncOut", Pin::Type::Object, { "TimeSync" }, &_timeSyncOut); | |
2258 | } | ||
2259 | ✗ | else if (_synchronizationControlRegister.syncOutMode != vn::protocol::uart::SyncOutMode::SYNCOUTMODE_GPSPPS | |
2260 | ✗ | && outputPins.size() == 5) | |
2261 | { | ||
2262 | ✗ | nm::DeleteOutputPin(outputPins.at(4)); | |
2263 | } | ||
2264 | |||
2265 | ✗ | flow::ApplyChanges(); | |
2266 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
2267 | { | ||
2268 | try | ||
2269 | { | ||
2270 | ✗ | _vs.writeSynchronizationControl(_synchronizationControlRegister); | |
2271 | } | ||
2272 | ✗ | catch (const std::exception& e) | |
2273 | { | ||
2274 | ✗ | LOG_ERROR("{}: Could not configure the synchronizationControlRegister: {}", nameId(), e.what()); | |
2275 | ✗ | doDeinitialize(); | |
2276 | ✗ | } | |
2277 | } | ||
2278 | else | ||
2279 | { | ||
2280 | ✗ | doDeinitialize(); | |
2281 | } | ||
2282 | } | ||
2283 | ✗ | if (ImGui::IsItemHovered()) | |
2284 | { | ||
2285 | ✗ | ImGui::BeginTooltip(); | |
2286 | ✗ | ImGui::TextUnformatted(synchronizationControlSyncOutMode.second); | |
2287 | ✗ | ImGui::EndTooltip(); | |
2288 | } | ||
2289 | |||
2290 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
2291 | { | ||
2292 | ✗ | ImGui::SetItemDefaultFocus(); | |
2293 | } | ||
2294 | } | ||
2295 | ✗ | ImGui::EndCombo(); | |
2296 | } | ||
2297 | ✗ | ImGui::SameLine(); | |
2298 | ✗ | gui::widgets::HelpMarker("The SyncOutMode register controls the behavior of the SyncOut pin. If this is set to IMU then the SyncOut " | |
2299 | "will start the pulse when the internal IMU sample loop starts. This mode is used to make a sensor the Master " | ||
2300 | "in a multi-sensor network array. If this is set to IMU_READY mode then the pulse will start when IMU " | ||
2301 | "measurements become available. If this is set to INS mode then the pulse will start when attitude " | ||
2302 | "measurements are made available. Changes to this register take effect immediately."); | ||
2303 | |||
2304 | static constexpr std::array<std::pair<vn::protocol::uart::SyncOutPolarity, const char*>, 2> synchronizationControlSyncOutPolarities = { | ||
2305 | { { vn::protocol::uart::SyncOutPolarity::SYNCOUTPOLARITY_NEGATIVE, "Negative Pulse" }, | ||
2306 | { vn::protocol::uart::SyncOutPolarity::SYNCOUTPOLARITY_POSITIVE, "Positive Pulse" } } | ||
2307 | }; | ||
2308 | ✗ | if (ImGui::BeginCombo(fmt::format("SyncOut Polarity##{}", size_t(id)).c_str(), vn::protocol::uart::str(_synchronizationControlRegister.syncOutPolarity).c_str())) | |
2309 | { | ||
2310 | ✗ | for (const auto& synchronizationControlSyncOutPolarity : synchronizationControlSyncOutPolarities) | |
2311 | { | ||
2312 | ✗ | const bool isSelected = (_synchronizationControlRegister.syncOutPolarity == synchronizationControlSyncOutPolarity.first); | |
2313 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(synchronizationControlSyncOutPolarity.first).c_str(), isSelected)) | |
2314 | { | ||
2315 | ✗ | _synchronizationControlRegister.syncOutPolarity = synchronizationControlSyncOutPolarity.first; | |
2316 | ✗ | LOG_DEBUG("{}: synchronizationControlRegister.syncOutPolarity changed to {}", nameId(), vn::protocol::uart::str(_synchronizationControlRegister.syncOutPolarity)); | |
2317 | ✗ | flow::ApplyChanges(); | |
2318 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
2319 | { | ||
2320 | try | ||
2321 | { | ||
2322 | ✗ | _vs.writeSynchronizationControl(_synchronizationControlRegister); | |
2323 | } | ||
2324 | ✗ | catch (const std::exception& e) | |
2325 | { | ||
2326 | ✗ | LOG_ERROR("{}: Could not configure the synchronizationControlRegister: {}", nameId(), e.what()); | |
2327 | ✗ | doDeinitialize(); | |
2328 | ✗ | } | |
2329 | } | ||
2330 | else | ||
2331 | { | ||
2332 | ✗ | doDeinitialize(); | |
2333 | } | ||
2334 | } | ||
2335 | ✗ | if (ImGui::IsItemHovered()) | |
2336 | { | ||
2337 | ✗ | ImGui::BeginTooltip(); | |
2338 | ✗ | ImGui::TextUnformatted(synchronizationControlSyncOutPolarity.second); | |
2339 | ✗ | ImGui::EndTooltip(); | |
2340 | } | ||
2341 | |||
2342 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
2343 | { | ||
2344 | ✗ | ImGui::SetItemDefaultFocus(); | |
2345 | } | ||
2346 | } | ||
2347 | ✗ | ImGui::EndCombo(); | |
2348 | } | ||
2349 | ✗ | ImGui::SameLine(); | |
2350 | ✗ | gui::widgets::HelpMarker("The SyncOutPolarity register controls the polarity of the output pulse on the SyncOut pin.\n" | |
2351 | "Changes to this register take effect immediately."); | ||
2352 | |||
2353 | ✗ | int syncOutSkipFactor = _synchronizationControlRegister.syncOutSkipFactor; | |
2354 | ✗ | if (ImGui::InputInt(fmt::format("SyncOut Skip Factor##{}", size_t(id)).c_str(), &syncOutSkipFactor)) | |
2355 | { | ||
2356 | ✗ | if (syncOutSkipFactor < 0) | |
2357 | { | ||
2358 | ✗ | syncOutSkipFactor = 0; | |
2359 | } | ||
2360 | ✗ | else if (syncOutSkipFactor > std::numeric_limits<uint16_t>::max()) | |
2361 | { | ||
2362 | ✗ | syncOutSkipFactor = std::numeric_limits<uint16_t>::max(); | |
2363 | } | ||
2364 | ✗ | _synchronizationControlRegister.syncOutSkipFactor = static_cast<uint16_t>(syncOutSkipFactor); | |
2365 | ✗ | LOG_DEBUG("{}: synchronizationControlRegister.syncOutSkipFactor changed to {}", nameId(), _synchronizationControlRegister.syncOutSkipFactor); | |
2366 | ✗ | flow::ApplyChanges(); | |
2367 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
2368 | { | ||
2369 | try | ||
2370 | { | ||
2371 | ✗ | _vs.writeSynchronizationControl(_synchronizationControlRegister); | |
2372 | } | ||
2373 | ✗ | catch (const std::exception& e) | |
2374 | { | ||
2375 | ✗ | LOG_ERROR("{}: Could not configure the synchronizationControlRegister: {}", nameId(), e.what()); | |
2376 | ✗ | doDeinitialize(); | |
2377 | ✗ | } | |
2378 | } | ||
2379 | else | ||
2380 | { | ||
2381 | ✗ | doDeinitialize(); | |
2382 | } | ||
2383 | } | ||
2384 | ✗ | ImGui::SameLine(); | |
2385 | ✗ | gui::widgets::HelpMarker("The SyncOutSkipFactor defines how many times the sync out event should be skipped before actually triggering the SyncOut pin."); | |
2386 | |||
2387 | ✗ | int syncOutPulseWidth = static_cast<int>(_synchronizationControlRegister.syncOutPulseWidth); | |
2388 | ✗ | if (ImGui::InputInt(fmt::format("SyncOut Pulse Width##{}", size_t(id)).c_str(), &syncOutPulseWidth)) | |
2389 | { | ||
2390 | ✗ | syncOutPulseWidth = std::max(syncOutPulseWidth, 0); | |
2391 | ✗ | _synchronizationControlRegister.syncOutPulseWidth = static_cast<uint32_t>(syncOutPulseWidth); | |
2392 | ✗ | LOG_DEBUG("{}: synchronizationControlRegister.syncOutPulseWidth changed to {}", nameId(), _synchronizationControlRegister.syncOutPulseWidth); | |
2393 | ✗ | flow::ApplyChanges(); | |
2394 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
2395 | { | ||
2396 | try | ||
2397 | { | ||
2398 | ✗ | _vs.writeSynchronizationControl(_synchronizationControlRegister); | |
2399 | } | ||
2400 | ✗ | catch (const std::exception& e) | |
2401 | { | ||
2402 | ✗ | LOG_ERROR("{}: Could not configure the synchronizationControlRegister: {}", nameId(), e.what()); | |
2403 | ✗ | doDeinitialize(); | |
2404 | ✗ | } | |
2405 | } | ||
2406 | else | ||
2407 | { | ||
2408 | ✗ | doDeinitialize(); | |
2409 | } | ||
2410 | } | ||
2411 | ✗ | ImGui::SameLine(); | |
2412 | ✗ | gui::widgets::HelpMarker("The SyncOutPulseWidth field controls the desired width of the SyncOut pulse.\n" | |
2413 | "The default value is 100,000,000 (100 ms)."); | ||
2414 | |||
2415 | ✗ | ImGui::TreePop(); | |
2416 | } | ||
2417 | |||
2418 | ✗ | if (ImGui::TreeNode(fmt::format("Communication Protocol Control##{}", size_t(id)).c_str())) | |
2419 | { | ||
2420 | ✗ | ImGui::TextUnformatted("Contains parameters that controls the communication protocol used by the sensor."); | |
2421 | |||
2422 | static constexpr std::array<std::pair<vn::protocol::uart::CountMode, const char*>, 5> communicationProtocolControlSerialCounts = { | ||
2423 | { { vn::protocol::uart::CountMode::COUNTMODE_NONE, "OFF" }, | ||
2424 | { vn::protocol::uart::CountMode::COUNTMODE_SYNCINCOUNT, "SyncIn Counter" }, | ||
2425 | { vn::protocol::uart::CountMode::COUNTMODE_SYNCINTIME, "SyncIn Time" }, | ||
2426 | { vn::protocol::uart::CountMode::COUNTMODE_SYNCOUTCOUNTER, "SyncOut Counter" }, | ||
2427 | { vn::protocol::uart::CountMode::COUNTMODE_GPSPPS, "Gps Pps Time" } } | ||
2428 | }; | ||
2429 | ✗ | if (ImGui::BeginCombo(fmt::format("Serial Count Mode##{}", size_t(id)).c_str(), vn::protocol::uart::str(_communicationProtocolControlRegister.serialCount).c_str())) | |
2430 | { | ||
2431 | ✗ | for (const auto& communicationProtocolControlSerialCount : communicationProtocolControlSerialCounts) | |
2432 | { | ||
2433 | ✗ | const bool isSelected = (_communicationProtocolControlRegister.serialCount == communicationProtocolControlSerialCount.first); | |
2434 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(communicationProtocolControlSerialCount.first).c_str(), isSelected)) | |
2435 | { | ||
2436 | ✗ | _communicationProtocolControlRegister.serialCount = communicationProtocolControlSerialCount.first; | |
2437 | ✗ | LOG_DEBUG("{}: communicationProtocolControlRegister.serialCount changed to {}", nameId(), vn::protocol::uart::str(_communicationProtocolControlRegister.serialCount)); | |
2438 | ✗ | flow::ApplyChanges(); | |
2439 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
2440 | { | ||
2441 | try | ||
2442 | { | ||
2443 | ✗ | _vs.writeCommunicationProtocolControl(_communicationProtocolControlRegister); | |
2444 | } | ||
2445 | ✗ | catch (const std::exception& e) | |
2446 | { | ||
2447 | ✗ | LOG_ERROR("{}: Could not configure the communicationProtocolControlRegister: {}", nameId(), e.what()); | |
2448 | ✗ | doDeinitialize(); | |
2449 | ✗ | } | |
2450 | } | ||
2451 | else | ||
2452 | { | ||
2453 | ✗ | doDeinitialize(); | |
2454 | } | ||
2455 | } | ||
2456 | ✗ | if (ImGui::IsItemHovered()) | |
2457 | { | ||
2458 | ✗ | ImGui::BeginTooltip(); | |
2459 | ✗ | ImGui::TextUnformatted(communicationProtocolControlSerialCount.second); | |
2460 | ✗ | ImGui::EndTooltip(); | |
2461 | } | ||
2462 | |||
2463 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
2464 | { | ||
2465 | ✗ | ImGui::SetItemDefaultFocus(); | |
2466 | } | ||
2467 | } | ||
2468 | ✗ | ImGui::EndCombo(); | |
2469 | } | ||
2470 | ✗ | ImGui::SameLine(); | |
2471 | ✗ | gui::widgets::HelpMarker("The SerialCount field provides a means of appending a time or counter to the end of all asynchronous " | |
2472 | "communication messages transmitted on the serial interface. The values for each of these counters come " | ||
2473 | "directly from the Synchronization Status Register in the System subsystem.\n\n" | ||
2474 | "With the SerialCount field set to OFF a typical serial asynchronous message would appear as the following:\n" | ||
2475 | "$VNYPR,+010.071,+000.278,-002.026*60\n\n" | ||
2476 | "With the SerialCount field set to one of the non-zero values the same asynchronous message would appear " | ||
2477 | "instead as:\n" | ||
2478 | "$VNYPR,+010.071,+000.278,-002.026,T1162704*2F\n\n" | ||
2479 | "When the SerialCount field is enabled the counter will always be appended to the end of the message just " | ||
2480 | "prior to the checksum. The counter will be preceded by the T character to distinguish it from the status field."); | ||
2481 | |||
2482 | static constexpr std::array<std::pair<vn::protocol::uart::StatusMode, const char*>, 3> communicationProtocolControlSerialStatuses = { | ||
2483 | { { vn::protocol::uart::StatusMode::STATUSMODE_OFF, "OFF" }, | ||
2484 | { vn::protocol::uart::StatusMode::STATUSMODE_VPESTATUS, "VPE Status" }, | ||
2485 | { vn::protocol::uart::StatusMode::STATUSMODE_INSSTATUS, "INS Status" } } | ||
2486 | }; | ||
2487 | ✗ | if (ImGui::BeginCombo(fmt::format("Serial Status##{}", size_t(id)).c_str(), vn::protocol::uart::str(_communicationProtocolControlRegister.serialStatus).c_str())) | |
2488 | { | ||
2489 | ✗ | for (const auto& communicationProtocolControlSerialStatus : communicationProtocolControlSerialStatuses) | |
2490 | { | ||
2491 | ✗ | const bool isSelected = (_communicationProtocolControlRegister.serialStatus == communicationProtocolControlSerialStatus.first); | |
2492 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(communicationProtocolControlSerialStatus.first).c_str(), isSelected)) | |
2493 | { | ||
2494 | ✗ | _communicationProtocolControlRegister.serialStatus = communicationProtocolControlSerialStatus.first; | |
2495 | ✗ | LOG_DEBUG("{}: communicationProtocolControlRegister.serialStatus changed to {}", nameId(), vn::protocol::uart::str(_communicationProtocolControlRegister.serialStatus)); | |
2496 | ✗ | flow::ApplyChanges(); | |
2497 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
2498 | { | ||
2499 | try | ||
2500 | { | ||
2501 | ✗ | _vs.writeCommunicationProtocolControl(_communicationProtocolControlRegister); | |
2502 | } | ||
2503 | ✗ | catch (const std::exception& e) | |
2504 | { | ||
2505 | ✗ | LOG_ERROR("{}: Could not configure the communicationProtocolControlRegister: {}", nameId(), e.what()); | |
2506 | ✗ | doDeinitialize(); | |
2507 | ✗ | } | |
2508 | } | ||
2509 | else | ||
2510 | { | ||
2511 | ✗ | doDeinitialize(); | |
2512 | } | ||
2513 | } | ||
2514 | ✗ | if (ImGui::IsItemHovered()) | |
2515 | { | ||
2516 | ✗ | ImGui::BeginTooltip(); | |
2517 | ✗ | ImGui::TextUnformatted(communicationProtocolControlSerialStatus.second); | |
2518 | ✗ | ImGui::EndTooltip(); | |
2519 | } | ||
2520 | |||
2521 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
2522 | { | ||
2523 | ✗ | ImGui::SetItemDefaultFocus(); | |
2524 | } | ||
2525 | } | ||
2526 | ✗ | ImGui::EndCombo(); | |
2527 | } | ||
2528 | ✗ | ImGui::SameLine(); | |
2529 | ✗ | gui::widgets::HelpMarker("The SerialStatus field provides a means of tracking real-time status information pertain to the overall state " | |
2530 | "of the sensor measurements and onboard filtering algorithm. As with the SerialCount, a typical serial " | ||
2531 | "asynchronous message would appear as the following:\n" | ||
2532 | "$VNYPR,+010.071,+000.278,-002.026*60\n\n" | ||
2533 | "With the SerialStatus field set to one of the non-zero values, the same asynchronous message would appear " | ||
2534 | "instead as:\n" | ||
2535 | "$VNYPR,+010.071,+000.278,-002.026,S0000*1F\n\n" | ||
2536 | "When the SerialStatus field is enabled the status will always be appended to the end of the message just " | ||
2537 | "prior to the checksum. If both the SerialCount and SerialStatus are enabled then the SerialStatus will be " | ||
2538 | "displayed first. The counter will be preceded by the S character to distinguish it from the counter field. The " | ||
2539 | "status consists of 4 hexadecimal characters."); | ||
2540 | |||
2541 | ✗ | if (_sensorModel == VectorNavModel::VN100_VN110) | |
2542 | { | ||
2543 | ✗ | if (ImGui::BeginCombo(fmt::format("SPI Count##{}", size_t(id)).c_str(), vn::protocol::uart::str(_communicationProtocolControlRegister.spiCount).c_str())) | |
2544 | { | ||
2545 | ✗ | for (const auto& communicationProtocolControlSpiCount : communicationProtocolControlSerialCounts) | |
2546 | { | ||
2547 | ✗ | const bool isSelected = (_communicationProtocolControlRegister.spiCount == communicationProtocolControlSpiCount.first); | |
2548 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(communicationProtocolControlSpiCount.first).c_str(), isSelected)) | |
2549 | { | ||
2550 | ✗ | _communicationProtocolControlRegister.spiCount = communicationProtocolControlSpiCount.first; | |
2551 | ✗ | LOG_DEBUG("{}: communicationProtocolControlRegister.spiCount changed to {}", nameId(), vn::protocol::uart::str(_communicationProtocolControlRegister.spiCount)); | |
2552 | ✗ | flow::ApplyChanges(); | |
2553 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
2554 | { | ||
2555 | try | ||
2556 | { | ||
2557 | ✗ | _vs.writeCommunicationProtocolControl(_communicationProtocolControlRegister); | |
2558 | } | ||
2559 | ✗ | catch (const std::exception& e) | |
2560 | { | ||
2561 | ✗ | LOG_ERROR("{}: Could not configure the communicationProtocolControlRegister: {}", nameId(), e.what()); | |
2562 | ✗ | doDeinitialize(); | |
2563 | ✗ | } | |
2564 | } | ||
2565 | else | ||
2566 | { | ||
2567 | ✗ | doDeinitialize(); | |
2568 | } | ||
2569 | } | ||
2570 | ✗ | if (ImGui::IsItemHovered()) | |
2571 | { | ||
2572 | ✗ | ImGui::BeginTooltip(); | |
2573 | ✗ | ImGui::TextUnformatted(communicationProtocolControlSpiCount.second); | |
2574 | ✗ | ImGui::EndTooltip(); | |
2575 | } | ||
2576 | |||
2577 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
2578 | { | ||
2579 | ✗ | ImGui::SetItemDefaultFocus(); | |
2580 | } | ||
2581 | } | ||
2582 | ✗ | ImGui::EndCombo(); | |
2583 | } | ||
2584 | ✗ | ImGui::SameLine(); | |
2585 | ✗ | gui::widgets::HelpMarker("The SPICount field provides a means of appending a time or counter to the end of all SPI packets. The " | |
2586 | "values for each of these counters come directly from the Synchronization Status Register."); | ||
2587 | } | ||
2588 | |||
2589 | ✗ | if (_sensorModel == VectorNavModel::VN100_VN110) | |
2590 | { | ||
2591 | ✗ | if (ImGui::BeginCombo(fmt::format("SPI Status##{}", size_t(id)).c_str(), vn::protocol::uart::str(_communicationProtocolControlRegister.spiStatus).c_str())) | |
2592 | { | ||
2593 | ✗ | for (const auto& communicationProtocolControlSpiStatus : communicationProtocolControlSerialStatuses) | |
2594 | { | ||
2595 | ✗ | const bool isSelected = (_communicationProtocolControlRegister.spiStatus == communicationProtocolControlSpiStatus.first); | |
2596 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(communicationProtocolControlSpiStatus.first).c_str(), isSelected)) | |
2597 | { | ||
2598 | ✗ | _communicationProtocolControlRegister.spiStatus = communicationProtocolControlSpiStatus.first; | |
2599 | ✗ | LOG_DEBUG("{}: communicationProtocolControlRegister.spiStatus changed to {}", nameId(), vn::protocol::uart::str(_communicationProtocolControlRegister.spiStatus)); | |
2600 | ✗ | flow::ApplyChanges(); | |
2601 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
2602 | { | ||
2603 | try | ||
2604 | { | ||
2605 | ✗ | _vs.writeCommunicationProtocolControl(_communicationProtocolControlRegister); | |
2606 | } | ||
2607 | ✗ | catch (const std::exception& e) | |
2608 | { | ||
2609 | ✗ | LOG_ERROR("{}: Could not configure the communicationProtocolControlRegister: {}", nameId(), e.what()); | |
2610 | ✗ | doDeinitialize(); | |
2611 | ✗ | } | |
2612 | } | ||
2613 | else | ||
2614 | { | ||
2615 | ✗ | doDeinitialize(); | |
2616 | } | ||
2617 | } | ||
2618 | ✗ | if (ImGui::IsItemHovered()) | |
2619 | { | ||
2620 | ✗ | ImGui::BeginTooltip(); | |
2621 | ✗ | ImGui::TextUnformatted(communicationProtocolControlSpiStatus.second); | |
2622 | ✗ | ImGui::EndTooltip(); | |
2623 | } | ||
2624 | |||
2625 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
2626 | { | ||
2627 | ✗ | ImGui::SetItemDefaultFocus(); | |
2628 | } | ||
2629 | } | ||
2630 | ✗ | ImGui::EndCombo(); | |
2631 | } | ||
2632 | ✗ | ImGui::SameLine(); | |
2633 | ✗ | gui::widgets::HelpMarker("The AsyncStatus field provides a means of tracking real-time status information pertaining to the overall " | |
2634 | "state of the sensor measurements and onboard filtering algorithm. This information is very useful in " | ||
2635 | "situations where action must be taken when certain crucial events happen such as the detection of gyro " | ||
2636 | "saturation or magnetic interference."); | ||
2637 | } | ||
2638 | |||
2639 | static constexpr std::array<std::pair<vn::protocol::uart::ChecksumMode, const char*>, 2> communicationProtocolControlSerialChecksums = { | ||
2640 | { { vn::protocol::uart::ChecksumMode::CHECKSUMMODE_CHECKSUM, "8-Bit Checksum" }, | ||
2641 | { vn::protocol::uart::ChecksumMode::CHECKSUMMODE_CRC, "16-Bit CRC" } } | ||
2642 | }; | ||
2643 | ✗ | if (ImGui::BeginCombo(fmt::format("Serial Checksum##{}", size_t(id)).c_str(), vn::protocol::uart::str(_communicationProtocolControlRegister.serialChecksum).c_str())) | |
2644 | { | ||
2645 | ✗ | for (const auto& communicationProtocolControlSerialChecksum : communicationProtocolControlSerialChecksums) | |
2646 | { | ||
2647 | ✗ | const bool isSelected = (_communicationProtocolControlRegister.serialChecksum == communicationProtocolControlSerialChecksum.first); | |
2648 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(communicationProtocolControlSerialChecksum.first).c_str(), isSelected)) | |
2649 | { | ||
2650 | ✗ | _communicationProtocolControlRegister.serialChecksum = communicationProtocolControlSerialChecksum.first; | |
2651 | ✗ | LOG_DEBUG("{}: communicationProtocolControlRegister.serialChecksum changed to {}", nameId(), vn::protocol::uart::str(_communicationProtocolControlRegister.serialChecksum)); | |
2652 | ✗ | flow::ApplyChanges(); | |
2653 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
2654 | { | ||
2655 | try | ||
2656 | { | ||
2657 | ✗ | _vs.writeCommunicationProtocolControl(_communicationProtocolControlRegister); | |
2658 | } | ||
2659 | ✗ | catch (const std::exception& e) | |
2660 | { | ||
2661 | ✗ | LOG_ERROR("{}: Could not configure the communicationProtocolControlRegister: {}", nameId(), e.what()); | |
2662 | ✗ | doDeinitialize(); | |
2663 | ✗ | } | |
2664 | } | ||
2665 | else | ||
2666 | { | ||
2667 | ✗ | doDeinitialize(); | |
2668 | } | ||
2669 | } | ||
2670 | ✗ | if (ImGui::IsItemHovered()) | |
2671 | { | ||
2672 | ✗ | ImGui::BeginTooltip(); | |
2673 | ✗ | ImGui::TextUnformatted(communicationProtocolControlSerialChecksum.second); | |
2674 | ✗ | ImGui::EndTooltip(); | |
2675 | } | ||
2676 | |||
2677 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
2678 | { | ||
2679 | ✗ | ImGui::SetItemDefaultFocus(); | |
2680 | } | ||
2681 | } | ||
2682 | ✗ | ImGui::EndCombo(); | |
2683 | } | ||
2684 | ✗ | ImGui::SameLine(); | |
2685 | ✗ | gui::widgets::HelpMarker("This field controls the type of checksum used for the serial communications. Normally the VN-310E uses an " | |
2686 | "8-bit checksum identical to the type used for normal GPS NMEA packets. This form of checksum however " | ||
2687 | "offers only a limited means of error checking. As an alternative a full 16-bit CRC (CRC16-CCITT with " | ||
2688 | "polynomial = 0x07) is also offered. The 2-byte CRC value is printed using 4 hexadecimal digits."); | ||
2689 | |||
2690 | ✗ | if (_sensorModel == VectorNavModel::VN100_VN110) | |
2691 | { | ||
2692 | static constexpr std::array<std::pair<vn::protocol::uart::ChecksumMode, const char*>, 3> communicationProtocolControlSpiChecksums = { | ||
2693 | { { vn::protocol::uart::ChecksumMode::CHECKSUMMODE_OFF, "OFF" }, | ||
2694 | { vn::protocol::uart::ChecksumMode::CHECKSUMMODE_CHECKSUM, "8-Bit Checksum" }, | ||
2695 | { vn::protocol::uart::ChecksumMode::CHECKSUMMODE_CRC, "16-Bit CRC" } } | ||
2696 | }; | ||
2697 | ✗ | if (ImGui::BeginCombo(fmt::format("SPI Checksum##{}", size_t(id)).c_str(), vn::protocol::uart::str(_communicationProtocolControlRegister.spiChecksum).c_str())) | |
2698 | { | ||
2699 | ✗ | for (const auto& communicationProtocolControlSpiChecksum : communicationProtocolControlSpiChecksums) | |
2700 | { | ||
2701 | ✗ | const bool isSelected = (_communicationProtocolControlRegister.spiChecksum == communicationProtocolControlSpiChecksum.first); | |
2702 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(communicationProtocolControlSpiChecksum.first).c_str(), isSelected)) | |
2703 | { | ||
2704 | ✗ | _communicationProtocolControlRegister.spiChecksum = communicationProtocolControlSpiChecksum.first; | |
2705 | ✗ | LOG_DEBUG("{}: communicationProtocolControlRegister.spiChecksum changed to {}", nameId(), vn::protocol::uart::str(_communicationProtocolControlRegister.spiChecksum)); | |
2706 | ✗ | flow::ApplyChanges(); | |
2707 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
2708 | { | ||
2709 | try | ||
2710 | { | ||
2711 | ✗ | _vs.writeCommunicationProtocolControl(_communicationProtocolControlRegister); | |
2712 | } | ||
2713 | ✗ | catch (const std::exception& e) | |
2714 | { | ||
2715 | ✗ | LOG_ERROR("{}: Could not configure the communicationProtocolControlRegister: {}", nameId(), e.what()); | |
2716 | ✗ | doDeinitialize(); | |
2717 | ✗ | } | |
2718 | } | ||
2719 | else | ||
2720 | { | ||
2721 | ✗ | doDeinitialize(); | |
2722 | } | ||
2723 | } | ||
2724 | ✗ | if (ImGui::IsItemHovered()) | |
2725 | { | ||
2726 | ✗ | ImGui::BeginTooltip(); | |
2727 | ✗ | ImGui::TextUnformatted(communicationProtocolControlSpiChecksum.second); | |
2728 | ✗ | ImGui::EndTooltip(); | |
2729 | } | ||
2730 | |||
2731 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
2732 | { | ||
2733 | ✗ | ImGui::SetItemDefaultFocus(); | |
2734 | } | ||
2735 | } | ||
2736 | ✗ | ImGui::EndCombo(); | |
2737 | } | ||
2738 | ✗ | ImGui::SameLine(); | |
2739 | ✗ | gui::widgets::HelpMarker("This field controls the type of checksum used for the SPI communications. The checksum is appended to " | |
2740 | "the end of the binary data packet. The 16-bit CRC is identical to the one described above for the " | ||
2741 | "SerialChecksum."); | ||
2742 | } | ||
2743 | |||
2744 | static constexpr std::array<std::pair<vn::protocol::uart::ErrorMode, const char*>, 3> communicationProtocolControlErrorModes = { | ||
2745 | { { vn::protocol::uart::ErrorMode::ERRORMODE_IGNORE, "Ignore Error" }, | ||
2746 | { vn::protocol::uart::ErrorMode::ERRORMODE_SEND, "Send Error" }, | ||
2747 | { vn::protocol::uart::ErrorMode::ERRORMODE_SENDANDOFF, "Send Error and set ADOR register to OFF" } } | ||
2748 | }; | ||
2749 | ✗ | if (ImGui::BeginCombo(fmt::format("Error Mode##{}", size_t(id)).c_str(), vn::protocol::uart::str(_communicationProtocolControlRegister.errorMode).c_str())) | |
2750 | { | ||
2751 | ✗ | for (const auto& communicationProtocolControlErrorMode : communicationProtocolControlErrorModes) | |
2752 | { | ||
2753 | ✗ | const bool isSelected = (_communicationProtocolControlRegister.errorMode == communicationProtocolControlErrorMode.first); | |
2754 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(communicationProtocolControlErrorMode.first).c_str(), isSelected)) | |
2755 | { | ||
2756 | ✗ | _communicationProtocolControlRegister.errorMode = communicationProtocolControlErrorMode.first; | |
2757 | ✗ | LOG_DEBUG("{}: communicationProtocolControlRegister.errorMode changed to {}", nameId(), vn::protocol::uart::str(_communicationProtocolControlRegister.errorMode)); | |
2758 | ✗ | flow::ApplyChanges(); | |
2759 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
2760 | { | ||
2761 | try | ||
2762 | { | ||
2763 | ✗ | _vs.writeCommunicationProtocolControl(_communicationProtocolControlRegister); | |
2764 | } | ||
2765 | ✗ | catch (const std::exception& e) | |
2766 | { | ||
2767 | ✗ | LOG_ERROR("{}: Could not configure the communicationProtocolControlRegister: {}", nameId(), e.what()); | |
2768 | ✗ | doDeinitialize(); | |
2769 | ✗ | } | |
2770 | } | ||
2771 | else | ||
2772 | { | ||
2773 | ✗ | doDeinitialize(); | |
2774 | } | ||
2775 | } | ||
2776 | ✗ | if (ImGui::IsItemHovered()) | |
2777 | { | ||
2778 | ✗ | ImGui::BeginTooltip(); | |
2779 | ✗ | ImGui::TextUnformatted(communicationProtocolControlErrorMode.second); | |
2780 | ✗ | ImGui::EndTooltip(); | |
2781 | } | ||
2782 | |||
2783 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
2784 | { | ||
2785 | ✗ | ImGui::SetItemDefaultFocus(); | |
2786 | } | ||
2787 | } | ||
2788 | ✗ | ImGui::EndCombo(); | |
2789 | } | ||
2790 | ✗ | ImGui::SameLine(); | |
2791 | ✗ | gui::widgets::HelpMarker("This field controls the type of action taken by the VectorNav when an error event occurs. If the send error " | |
2792 | "mode is enabled then a message similar to the one shown below will be sent on the serial bus when an error " | ||
2793 | "event occurs.\n\n" | ||
2794 | "$VNERR,03*72\n\n" | ||
2795 | "Regardless of the state of the ErrorMode, the number of error events is always recorded and is made available " | ||
2796 | "in the SysErrors field of the Communication Protocol Status Register in the System subsystem."); | ||
2797 | |||
2798 | ✗ | if (ImGui::TreeNode(fmt::format("Example Async Messages##{}", size_t(id)).c_str())) | |
2799 | { | ||
2800 | ✗ | ImGui::TextUnformatted("The following table shows example asynchronous messages with the\nAsyncCount and the AsyncStatus values appended to the end."); | |
2801 | |||
2802 | ✗ | if (ImGui::BeginTable("Example Async Messages Table", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX, ImVec2(0.0F, 0.0F))) | |
2803 | { | ||
2804 | ✗ | ImGui::TableSetupColumn("Example Type"); | |
2805 | ✗ | ImGui::TableSetupColumn("Message"); | |
2806 | ✗ | ImGui::TableHeadersRow(); | |
2807 | |||
2808 | ✗ | ImGui::TableNextColumn(); | |
2809 | ✗ | ImGui::TextUnformatted("Async Message with\nAsyncCount Enabled"); | |
2810 | ✗ | ImGui::TableNextColumn(); | |
2811 | ✗ | ImGui::TextUnformatted("$VNYPR,+010.071,+000.278,-002.026,T1162704*2F"); | |
2812 | |||
2813 | ✗ | ImGui::TableNextColumn(); | |
2814 | ✗ | ImGui::TextUnformatted("Async Message with\nAsyncStatus Enabled"); | |
2815 | ✗ | ImGui::TableNextColumn(); | |
2816 | ✗ | ImGui::TextUnformatted("$VNYPR,+010.071,+000.278,-002.026,S0000*1F"); | |
2817 | |||
2818 | ✗ | ImGui::TableNextColumn(); | |
2819 | ✗ | ImGui::TextUnformatted("Async Message with\nAsyncCount and\nAsyncStatus Enabled"); | |
2820 | ✗ | ImGui::TableNextColumn(); | |
2821 | ✗ | ImGui::TextUnformatted("$VNYPR,+010.071,+000.278,-002.026,T1162704,S0000*50"); | |
2822 | |||
2823 | ✗ | ImGui::EndTable(); | |
2824 | } | ||
2825 | |||
2826 | ✗ | ImGui::TreePop(); | |
2827 | } | ||
2828 | |||
2829 | ✗ | ImGui::TreePop(); | |
2830 | } | ||
2831 | |||
2832 | ✗ | for (size_t b = 0; b < _binaryOutputRegister.size(); b++) | |
2833 | { | ||
2834 | ✗ | if (ImGui::TreeNode(fmt::format("Binary Output {}##{}", b + 1, size_t(id)).c_str())) | |
2835 | { | ||
2836 | static constexpr std::array<std::pair<vn::protocol::uart::AsyncMode, const char*>, 4> asyncModes = { | ||
2837 | { { vn::protocol::uart::AsyncMode::ASYNCMODE_NONE, " User message is not automatically sent out either serial port" }, | ||
2838 | { vn::protocol::uart::AsyncMode::ASYNCMODE_PORT1, "Message is sent out serial port 1 at a fixed rate" }, | ||
2839 | { vn::protocol::uart::AsyncMode::ASYNCMODE_PORT2, "Message is sent out serial port 2 at a fixed rate" }, | ||
2840 | { vn::protocol::uart::AsyncMode::ASYNCMODE_BOTH, "Message is sent out both serial ports at a fixed rate" } } | ||
2841 | }; | ||
2842 | ✗ | if ((_binaryOutputRegisterMerge == BinaryRegisterMerge::Output1_Output2 && b == 1) | |
2843 | ✗ | || (_binaryOutputRegisterMerge == BinaryRegisterMerge::Output1_Output3 && b == 2) | |
2844 | ✗ | || (_binaryOutputRegisterMerge == BinaryRegisterMerge::Output2_Output3 && b == 2)) | |
2845 | { | ||
2846 | ✗ | ImGui::BeginDisabled(); | |
2847 | } | ||
2848 | |||
2849 | ✗ | if (ImGui::BeginCombo(fmt::format("Async Mode##{}", size_t(id)).c_str(), vn::protocol::uart::str(_binaryOutputRegister.at(b).asyncMode).c_str())) | |
2850 | { | ||
2851 | ✗ | for (const auto& asyncMode : asyncModes) | |
2852 | { | ||
2853 | ✗ | const bool isSelected = (_binaryOutputRegister.at(b).asyncMode == asyncMode.first); | |
2854 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(asyncMode.first).c_str(), isSelected)) | |
2855 | { | ||
2856 | ✗ | _binaryOutputRegister.at(b).asyncMode = asyncMode.first; | |
2857 | ✗ | LOG_DEBUG("{}: binaryOutputRegister.at({}).asyncMode changed to {}", nameId(), b, vn::protocol::uart::str(_binaryOutputRegister.at(b).asyncMode)); | |
2858 | |||
2859 | ✗ | std::vector<size_t> binaryOutputRegistersToUpdate; | |
2860 | ✗ | binaryOutputRegistersToUpdate.push_back(b); | |
2861 | ✗ | if (_binaryOutputRegisterMerge == BinaryRegisterMerge::Output1_Output2 && b == 0) | |
2862 | { | ||
2863 | ✗ | _binaryOutputRegister.at(1).asyncMode = asyncMode.first; | |
2864 | ✗ | LOG_DEBUG("{}: binaryOutputRegister.at({}).asyncMode changed to {}", nameId(), 1, vn::protocol::uart::str(_binaryOutputRegister.at(1).asyncMode)); | |
2865 | ✗ | binaryOutputRegistersToUpdate.push_back(1); | |
2866 | } | ||
2867 | ✗ | else if ((_binaryOutputRegisterMerge == BinaryRegisterMerge::Output1_Output3 && b == 0) | |
2868 | ✗ | || (_binaryOutputRegisterMerge == BinaryRegisterMerge::Output2_Output3 && b == 1)) | |
2869 | { | ||
2870 | ✗ | _binaryOutputRegister.at(2).asyncMode = asyncMode.first; | |
2871 | ✗ | LOG_DEBUG("{}: binaryOutputRegister.at({}).asyncMode changed to {}", nameId(), 2, vn::protocol::uart::str(_binaryOutputRegister.at(2).asyncMode)); | |
2872 | ✗ | binaryOutputRegistersToUpdate.push_back(2); | |
2873 | } | ||
2874 | ✗ | flow::ApplyChanges(); | |
2875 | |||
2876 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
2877 | { | ||
2878 | ✗ | for (const auto& binUpdate : binaryOutputRegistersToUpdate) | |
2879 | { | ||
2880 | try | ||
2881 | { | ||
2882 | ✗ | switch (binUpdate) | |
2883 | { | ||
2884 | ✗ | case 0: | |
2885 | ✗ | _vs.writeBinaryOutput1(_binaryOutputRegister.at(binUpdate)); | |
2886 | ✗ | break; | |
2887 | ✗ | case 1: | |
2888 | ✗ | _vs.writeBinaryOutput2(_binaryOutputRegister.at(binUpdate)); | |
2889 | ✗ | break; | |
2890 | ✗ | case 2: | |
2891 | ✗ | _vs.writeBinaryOutput3(_binaryOutputRegister.at(binUpdate)); | |
2892 | ✗ | break; | |
2893 | ✗ | default: | |
2894 | ✗ | break; | |
2895 | } | ||
2896 | } | ||
2897 | ✗ | catch (const std::exception& e) | |
2898 | { | ||
2899 | ✗ | LOG_ERROR("{}: Could not configure the binaryOutputRegister {}: {}", nameId(), binUpdate + 1, e.what()); | |
2900 | ✗ | doDeinitialize(); | |
2901 | ✗ | } | |
2902 | } | ||
2903 | } | ||
2904 | else | ||
2905 | { | ||
2906 | ✗ | doDeinitialize(); | |
2907 | } | ||
2908 | ✗ | } | |
2909 | ✗ | if (ImGui::IsItemHovered()) | |
2910 | { | ||
2911 | ✗ | ImGui::BeginTooltip(); | |
2912 | ✗ | ImGui::TextUnformatted(asyncMode.second); | |
2913 | ✗ | ImGui::EndTooltip(); | |
2914 | } | ||
2915 | |||
2916 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
2917 | { | ||
2918 | ✗ | ImGui::SetItemDefaultFocus(); | |
2919 | } | ||
2920 | } | ||
2921 | ✗ | ImGui::EndCombo(); | |
2922 | } | ||
2923 | ✗ | ImGui::SameLine(); | |
2924 | ✗ | gui::widgets::HelpMarker("Selects whether the output message should be sent " | |
2925 | "out on the serial port(s) at a fixed rate."); | ||
2926 | |||
2927 | ✗ | const char* frequencyText = _binaryOutputSelectedFrequency.at(b) < _dividerFrequency.first.size() | |
2928 | ✗ | ? _dividerFrequency.second.at(_binaryOutputSelectedFrequency.at(b)).c_str() | |
2929 | ✗ | : "Unknown"; | |
2930 | ✗ | if (auto freq = static_cast<int>(_binaryOutputSelectedFrequency.at(b)); | |
2931 | ✗ | ImGui::SliderInt(fmt::format("Frequency##{} {}", size_t(id), b).c_str(), | |
2932 | &freq, | ||
2933 | ✗ | 0, static_cast<int>(_dividerFrequency.second.size()) - 1, | |
2934 | frequencyText)) | ||
2935 | { | ||
2936 | ✗ | _binaryOutputSelectedFrequency.at(b) = static_cast<size_t>(freq); | |
2937 | ✗ | _binaryOutputRegister.at(b).rateDivisor = _dividerFrequency.first.at(_binaryOutputSelectedFrequency.at(b)); | |
2938 | ✗ | LOG_DEBUG("{}: Frequency of Binary Group {} changed to {}", nameId(), b + 1, _dividerFrequency.second.at(_binaryOutputSelectedFrequency.at(b))); | |
2939 | ✗ | if (_coupleImuRateOutput) | |
2940 | { | ||
2941 | ✗ | if (_binaryOutputRegister.at(b).imuField & (vn::protocol::uart::IMUGROUP_ACCEL | vn::protocol::uart::IMUGROUP_UNCOMPACCEL)) | |
2942 | { | ||
2943 | ✗ | _imuFilteringConfigurationRegister.accelWindowSize = _binaryOutputRegister.at(b).rateDivisor; | |
2944 | } | ||
2945 | ✗ | if (_binaryOutputRegister.at(b).imuField & (vn::protocol::uart::IMUGROUP_ANGULARRATE | vn::protocol::uart::IMUGROUP_UNCOMPGYRO)) | |
2946 | { | ||
2947 | ✗ | _imuFilteringConfigurationRegister.gyroWindowSize = _binaryOutputRegister.at(b).rateDivisor; | |
2948 | } | ||
2949 | ✗ | if (_binaryOutputRegister.at(b).imuField & (vn::protocol::uart::IMUGROUP_MAG | vn::protocol::uart::IMUGROUP_UNCOMPMAG)) | |
2950 | { | ||
2951 | ✗ | _imuFilteringConfigurationRegister.magWindowSize = _binaryOutputRegister.at(b).rateDivisor; | |
2952 | } | ||
2953 | ✗ | if (_binaryOutputRegister.at(b).imuField & (vn::protocol::uart::IMUGROUP_MAG | vn::protocol::uart::IMUGROUP_UNCOMPMAG)) | |
2954 | { | ||
2955 | ✗ | _imuFilteringConfigurationRegister.magWindowSize = _binaryOutputRegister.at(b).rateDivisor; | |
2956 | } | ||
2957 | ✗ | if (_binaryOutputRegister.at(b).imuField & vn::protocol::uart::IMUGROUP_TEMP) | |
2958 | { | ||
2959 | ✗ | _imuFilteringConfigurationRegister.tempWindowSize = _binaryOutputRegister.at(b).rateDivisor; | |
2960 | } | ||
2961 | ✗ | if (_binaryOutputRegister.at(b).imuField & vn::protocol::uart::IMUGROUP_PRES) | |
2962 | { | ||
2963 | ✗ | _imuFilteringConfigurationRegister.presWindowSize = _binaryOutputRegister.at(b).rateDivisor; | |
2964 | } | ||
2965 | LOG_DATA("{}: Frequency of ImuFilter matches output frequency (coupled 'rateDivisor' and 'windowSize' of moving average filter.)", nameId()); | ||
2966 | |||
2967 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
2968 | { | ||
2969 | try | ||
2970 | { | ||
2971 | ✗ | _vs.writeImuFilteringConfiguration(_imuFilteringConfigurationRegister); | |
2972 | } | ||
2973 | ✗ | catch (const std::exception& e) | |
2974 | { | ||
2975 | ✗ | LOG_ERROR("{}: Could not configure the imuFilteringConfigurationRegister: {}", nameId(), e.what()); | |
2976 | ✗ | doDeinitialize(); | |
2977 | ✗ | } | |
2978 | } | ||
2979 | else | ||
2980 | { | ||
2981 | ✗ | doDeinitialize(); | |
2982 | } | ||
2983 | } | ||
2984 | |||
2985 | ✗ | std::vector<size_t> binaryOutputRegistersToUpdate; | |
2986 | ✗ | binaryOutputRegistersToUpdate.push_back(b); | |
2987 | ✗ | if (_binaryOutputRegisterMerge == BinaryRegisterMerge::Output1_Output2 && b == 0) | |
2988 | { | ||
2989 | ✗ | _binaryOutputSelectedFrequency.at(1) = _binaryOutputSelectedFrequency.at(b); | |
2990 | ✗ | _binaryOutputRegister.at(1).rateDivisor = _dividerFrequency.first.at(_binaryOutputSelectedFrequency.at(1)); | |
2991 | ✗ | LOG_DEBUG("{}: Frequency of Binary Group {} changed to {}", nameId(), 1 + 1, _dividerFrequency.second.at(_binaryOutputSelectedFrequency.at(1))); | |
2992 | ✗ | binaryOutputRegistersToUpdate.push_back(1); | |
2993 | } | ||
2994 | ✗ | else if ((_binaryOutputRegisterMerge == BinaryRegisterMerge::Output1_Output3 && b == 0) | |
2995 | ✗ | || (_binaryOutputRegisterMerge == BinaryRegisterMerge::Output2_Output3 && b == 1)) | |
2996 | { | ||
2997 | ✗ | _binaryOutputSelectedFrequency.at(2) = _binaryOutputSelectedFrequency.at(b); | |
2998 | ✗ | _binaryOutputRegister.at(2).rateDivisor = _dividerFrequency.first.at(_binaryOutputSelectedFrequency.at(2)); | |
2999 | ✗ | LOG_DEBUG("{}: Frequency of Binary Group {} changed to {}", nameId(), 2 + 1, _dividerFrequency.second.at(_binaryOutputSelectedFrequency.at(2))); | |
3000 | ✗ | binaryOutputRegistersToUpdate.push_back(2); | |
3001 | } | ||
3002 | |||
3003 | ✗ | flow::ApplyChanges(); | |
3004 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
3005 | { | ||
3006 | ✗ | for (const auto& binUpdate : binaryOutputRegistersToUpdate) | |
3007 | { | ||
3008 | try | ||
3009 | { | ||
3010 | ✗ | switch (binUpdate) | |
3011 | { | ||
3012 | ✗ | case 0: | |
3013 | ✗ | _vs.writeBinaryOutput1(_binaryOutputRegister.at(binUpdate)); | |
3014 | ✗ | break; | |
3015 | ✗ | case 1: | |
3016 | ✗ | _vs.writeBinaryOutput2(_binaryOutputRegister.at(binUpdate)); | |
3017 | ✗ | break; | |
3018 | ✗ | case 2: | |
3019 | ✗ | _vs.writeBinaryOutput3(_binaryOutputRegister.at(binUpdate)); | |
3020 | ✗ | break; | |
3021 | ✗ | default: | |
3022 | ✗ | break; | |
3023 | } | ||
3024 | } | ||
3025 | ✗ | catch (const std::exception& e) | |
3026 | { | ||
3027 | ✗ | LOG_ERROR("{}: Could not configure the binaryOutputRegister {}: {}", nameId(), binUpdate + 1, e.what()); | |
3028 | ✗ | doDeinitialize(); | |
3029 | ✗ | } | |
3030 | } | ||
3031 | } | ||
3032 | else | ||
3033 | { | ||
3034 | ✗ | doDeinitialize(); | |
3035 | } | ||
3036 | ✗ | } | |
3037 | ✗ | if ((_binaryOutputRegisterMerge == BinaryRegisterMerge::Output1_Output2 && b == 1) | |
3038 | ✗ | || (_binaryOutputRegisterMerge == BinaryRegisterMerge::Output1_Output3 && b == 2) | |
3039 | ✗ | || (_binaryOutputRegisterMerge == BinaryRegisterMerge::Output2_Output3 && b == 2)) | |
3040 | { | ||
3041 | ✗ | ImGui::EndDisabled(); | |
3042 | } | ||
3043 | |||
3044 | ✗ | if (ImGui::BeginTable(fmt::format("##VectorNavSensorConfig ({})", size_t(id)).c_str(), 6, | |
3045 | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) | ||
3046 | { | ||
3047 | // ImGui::TableSetupColumn("Common", ImGuiTableColumnFlags_WidthFixed); | ||
3048 | ✗ | ImGui::TableSetupColumn("Time", ImGuiTableColumnFlags_WidthFixed); | |
3049 | ✗ | ImGui::TableSetupColumn("IMU", ImGuiTableColumnFlags_WidthFixed); | |
3050 | ✗ | ImGui::TableSetupColumn("GNSS1", ImGuiTableColumnFlags_WidthFixed); | |
3051 | ✗ | ImGui::TableSetupColumn("Attitude", ImGuiTableColumnFlags_WidthFixed); | |
3052 | ✗ | ImGui::TableSetupColumn("INS", ImGuiTableColumnFlags_WidthFixed); | |
3053 | ✗ | ImGui::TableSetupColumn("GNSS2", ImGuiTableColumnFlags_WidthFixed); | |
3054 | ✗ | ImGui::TableHeadersRow(); | |
3055 | |||
3056 | ✗ | auto CheckboxFlags = [&, this](int index, const char* label, int* flags, int flags_value, bool enabled, void (*toggleFields)(VectorNavSensor*, vn::sensors::BinaryOutputRegister&, uint32_t&)) { | |
3057 | ✗ | ImGui::TableSetColumnIndex(index); | |
3058 | |||
3059 | ✗ | if (!enabled) | |
3060 | { | ||
3061 | ✗ | ImGui::BeginDisabled(); | |
3062 | } | ||
3063 | |||
3064 | ✗ | if (ImGui::CheckboxFlags(label, flags, flags_value)) | |
3065 | { | ||
3066 | ✗ | 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"); | |
3067 | ✗ | if (toggleFields) | |
3068 | { | ||
3069 | ✗ | toggleFields(this, _binaryOutputRegister.at(b), *reinterpret_cast<uint32_t*>(flags)); | |
3070 | } | ||
3071 | ✗ | flow::ApplyChanges(); | |
3072 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
3073 | { | ||
3074 | try | ||
3075 | { | ||
3076 | ✗ | if (b == 0) | |
3077 | { | ||
3078 | ✗ | _vs.writeBinaryOutput1(_binaryOutputRegister.at(b)); | |
3079 | } | ||
3080 | ✗ | else if (b == 1) | |
3081 | { | ||
3082 | ✗ | _vs.writeBinaryOutput2(_binaryOutputRegister.at(b)); | |
3083 | } | ||
3084 | ✗ | else if (b == 2) | |
3085 | { | ||
3086 | ✗ | _vs.writeBinaryOutput3(_binaryOutputRegister.at(b)); | |
3087 | } | ||
3088 | |||
3089 | ✗ | for (auto& link : outputPins.at(b + 2).links) | |
3090 | { | ||
3091 | ✗ | if (auto* connectedPin = link.getConnectedPin()) | |
3092 | { | ||
3093 | ✗ | outputPins.at(b + 2).recreateLink(*connectedPin); | |
3094 | } | ||
3095 | } | ||
3096 | } | ||
3097 | ✗ | catch (const std::exception& e) | |
3098 | { | ||
3099 | ✗ | LOG_ERROR("{}: Could not configure the binaryOutputRegister {}: {}", nameId(), b + 1, e.what()); | |
3100 | ✗ | doDeinitialize(); | |
3101 | ✗ | } | |
3102 | } | ||
3103 | else | ||
3104 | { | ||
3105 | ✗ | doDeinitialize(); | |
3106 | } | ||
3107 | } | ||
3108 | |||
3109 | ✗ | if (!enabled) | |
3110 | { | ||
3111 | ✗ | ImGui::EndDisabled(); | |
3112 | } | ||
3113 | ✗ | }; | |
3114 | |||
3115 | ✗ | for (size_t i = 0; i < 16; i++) | |
3116 | { | ||
3117 | ✗ | if (i < std::max({ /* _binaryGroupCommon.size(), */ _binaryGroupTime.size(), _binaryGroupIMU.size(), | |
3118 | _binaryGroupGNSS.size(), _binaryGroupAttitude.size(), _binaryGroupINS.size() })) | ||
3119 | { | ||
3120 | ✗ | ImGui::TableNextRow(); | |
3121 | } | ||
3122 | // if (i < _binaryGroupCommon.size()) | ||
3123 | // { | ||
3124 | // const auto& binaryGroupItem = _binaryGroupCommon.at(i); | ||
3125 | // CheckboxFlags(0, fmt::format("{}##Common {} {}", binaryGroupItem.name, size_t(id), b).c_str(), | ||
3126 | // reinterpret_cast<int*>(&_binaryOutputRegister.at(b).commonField), | ||
3127 | // binaryGroupItem.flagsValue, | ||
3128 | // binaryGroupItem.isEnabled(_sensorModel, _binaryOutputRegister.at(b), static_cast<uint32_t>(_binaryOutputRegister.at(b).commonField)), | ||
3129 | // binaryGroupItem.toggleFields); | ||
3130 | // if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && binaryGroupItem.tooltip != nullptr) | ||
3131 | // { | ||
3132 | // ImGui::BeginTooltip(); | ||
3133 | // binaryGroupItem.tooltip(); | ||
3134 | // ImGui::EndTooltip(); | ||
3135 | // } | ||
3136 | // } | ||
3137 | ✗ | if (i < _binaryGroupTime.size()) | |
3138 | { | ||
3139 | ✗ | const auto& binaryGroupItem = _binaryGroupTime.at(i); | |
3140 | ✗ | CheckboxFlags(0, fmt::format("{}##Time {} {}", binaryGroupItem.name, size_t(id), b).c_str(), | |
3141 | ✗ | reinterpret_cast<int*>(&_binaryOutputRegister.at(b).timeField), | |
3142 | ✗ | binaryGroupItem.flagsValue, | |
3143 | ✗ | binaryGroupItem.isEnabled(_sensorModel, _binaryOutputRegister.at(b), static_cast<uint32_t>(_binaryOutputRegister.at(b).timeField)), | |
3144 | ✗ | binaryGroupItem.toggleFields); | |
3145 | ✗ | if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && binaryGroupItem.tooltip != nullptr) | |
3146 | { | ||
3147 | ✗ | ImGui::BeginTooltip(); | |
3148 | ✗ | binaryGroupItem.tooltip(); | |
3149 | ✗ | ImGui::EndTooltip(); | |
3150 | } | ||
3151 | } | ||
3152 | ✗ | if (i < _binaryGroupIMU.size()) | |
3153 | { | ||
3154 | ✗ | const auto& binaryGroupItem = _binaryGroupIMU.at(i); | |
3155 | ✗ | CheckboxFlags(1, fmt::format("{}##IMU {} {}", binaryGroupItem.name, size_t(id), b).c_str(), | |
3156 | ✗ | reinterpret_cast<int*>(&_binaryOutputRegister.at(b).imuField), | |
3157 | ✗ | binaryGroupItem.flagsValue, | |
3158 | ✗ | binaryGroupItem.isEnabled(_sensorModel, _binaryOutputRegister.at(b), static_cast<uint32_t>(_binaryOutputRegister.at(b).imuField)), | |
3159 | ✗ | binaryGroupItem.toggleFields); | |
3160 | ✗ | if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && binaryGroupItem.tooltip != nullptr) | |
3161 | { | ||
3162 | ✗ | ImGui::BeginTooltip(); | |
3163 | ✗ | binaryGroupItem.tooltip(); | |
3164 | ✗ | ImGui::EndTooltip(); | |
3165 | } | ||
3166 | } | ||
3167 | ✗ | if (i < _binaryGroupGNSS.size()) | |
3168 | { | ||
3169 | ✗ | const auto& binaryGroupItem = _binaryGroupGNSS.at(i); | |
3170 | ✗ | CheckboxFlags(2, fmt::format("{}##GNSS1 {} {}", binaryGroupItem.name, size_t(id), b).c_str(), | |
3171 | ✗ | reinterpret_cast<int*>(&_binaryOutputRegister.at(b).gpsField), | |
3172 | ✗ | binaryGroupItem.flagsValue, | |
3173 | ✗ | binaryGroupItem.isEnabled(_sensorModel, _binaryOutputRegister.at(b), static_cast<uint32_t>(_binaryOutputRegister.at(b).gpsField)), | |
3174 | ✗ | binaryGroupItem.toggleFields); | |
3175 | ✗ | if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && binaryGroupItem.tooltip != nullptr) | |
3176 | { | ||
3177 | ✗ | ImGui::BeginTooltip(); | |
3178 | ✗ | binaryGroupItem.tooltip(); | |
3179 | ✗ | ImGui::EndTooltip(); | |
3180 | } | ||
3181 | } | ||
3182 | ✗ | if (i < _binaryGroupAttitude.size()) | |
3183 | { | ||
3184 | ✗ | const auto& binaryGroupItem = _binaryGroupAttitude.at(i); | |
3185 | ✗ | CheckboxFlags(3, fmt::format("{}##Attitude {} {}", binaryGroupItem.name, size_t(id), b).c_str(), | |
3186 | ✗ | reinterpret_cast<int*>(&_binaryOutputRegister.at(b).attitudeField), | |
3187 | ✗ | binaryGroupItem.flagsValue, | |
3188 | ✗ | binaryGroupItem.isEnabled(_sensorModel, _binaryOutputRegister.at(b), static_cast<uint32_t>(_binaryOutputRegister.at(b).attitudeField)), | |
3189 | ✗ | binaryGroupItem.toggleFields); | |
3190 | ✗ | if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && binaryGroupItem.tooltip != nullptr) | |
3191 | { | ||
3192 | ✗ | ImGui::BeginTooltip(); | |
3193 | ✗ | binaryGroupItem.tooltip(); | |
3194 | ✗ | ImGui::EndTooltip(); | |
3195 | } | ||
3196 | } | ||
3197 | ✗ | if (i < _binaryGroupINS.size()) | |
3198 | { | ||
3199 | ✗ | const auto& binaryGroupItem = _binaryGroupINS.at(i); | |
3200 | ✗ | CheckboxFlags(4, fmt::format("{}##INS {} {}", binaryGroupItem.name, size_t(id), b).c_str(), | |
3201 | ✗ | reinterpret_cast<int*>(&_binaryOutputRegister.at(b).insField), | |
3202 | ✗ | binaryGroupItem.flagsValue, | |
3203 | ✗ | binaryGroupItem.isEnabled(_sensorModel, _binaryOutputRegister.at(b), static_cast<uint32_t>(_binaryOutputRegister.at(b).insField)), | |
3204 | ✗ | binaryGroupItem.toggleFields); | |
3205 | ✗ | if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && binaryGroupItem.tooltip != nullptr) | |
3206 | { | ||
3207 | ✗ | ImGui::BeginTooltip(); | |
3208 | ✗ | binaryGroupItem.tooltip(); | |
3209 | ✗ | ImGui::EndTooltip(); | |
3210 | } | ||
3211 | } | ||
3212 | ✗ | if (i < _binaryGroupGNSS.size()) | |
3213 | { | ||
3214 | ✗ | const auto& binaryGroupItem = _binaryGroupGNSS.at(i); | |
3215 | ✗ | CheckboxFlags(5, fmt::format("{}##GNSS2 {} {}", binaryGroupItem.name, size_t(id), b).c_str(), | |
3216 | ✗ | reinterpret_cast<int*>(&_binaryOutputRegister.at(b).gps2Field), | |
3217 | ✗ | binaryGroupItem.flagsValue, | |
3218 | ✗ | binaryGroupItem.isEnabled(_sensorModel, _binaryOutputRegister.at(b), static_cast<uint32_t>(_binaryOutputRegister.at(b).gps2Field)), | |
3219 | ✗ | binaryGroupItem.toggleFields); | |
3220 | ✗ | if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && binaryGroupItem.tooltip != nullptr) | |
3221 | { | ||
3222 | ✗ | ImGui::BeginTooltip(); | |
3223 | ✗ | binaryGroupItem.tooltip(); | |
3224 | ✗ | ImGui::EndTooltip(); | |
3225 | } | ||
3226 | } | ||
3227 | } | ||
3228 | |||
3229 | ✗ | ImGui::EndTable(); | |
3230 | } | ||
3231 | |||
3232 | ✗ | ImGui::TreePop(); | |
3233 | } | ||
3234 | } | ||
3235 | |||
3236 | ✗ | if (auto binaryOutputRegisterMerge = static_cast<int>(_binaryOutputRegisterMerge); | |
3237 | ✗ | ImGui::Combo(fmt::format("Merge Binary outputs").c_str(), &binaryOutputRegisterMerge, "None\0" | |
3238 | "1 <-> 2\0" | ||
3239 | "1 <-> 3\0" | ||
3240 | "2 <-> 3\0\0")) | ||
3241 | { | ||
3242 | ✗ | _binaryOutputRegisterMerge = static_cast<decltype(_binaryOutputRegisterMerge)>(binaryOutputRegisterMerge); | |
3243 | ✗ | flow::ApplyChanges(); | |
3244 | ✗ | switch (_binaryOutputRegisterMerge) | |
3245 | { | ||
3246 | ✗ | case BinaryRegisterMerge::Output1_Output2: | |
3247 | ✗ | _binaryOutputRegister.at(1).rateDivisor = _binaryOutputRegister.at(0).rateDivisor; | |
3248 | ✗ | _binaryOutputSelectedFrequency.at(1) = _binaryOutputSelectedFrequency.at(0); | |
3249 | ✗ | _binaryOutputRegister.at(1).asyncMode = _binaryOutputRegister.at(0).asyncMode; | |
3250 | ✗ | outputPins.at(2).deleteLinks(); | |
3251 | ✗ | outputPins.at(1).type = Pin::Type::Flow; | |
3252 | ✗ | outputPins.at(2).type = Pin::Type::None; | |
3253 | ✗ | outputPins.at(3).type = Pin::Type::Flow; | |
3254 | ✗ | break; | |
3255 | ✗ | case BinaryRegisterMerge::Output1_Output3: | |
3256 | ✗ | _binaryOutputRegister.at(2).rateDivisor = _binaryOutputRegister.at(0).rateDivisor; | |
3257 | ✗ | _binaryOutputSelectedFrequency.at(2) = _binaryOutputSelectedFrequency.at(0); | |
3258 | ✗ | _binaryOutputRegister.at(2).asyncMode = _binaryOutputRegister.at(0).asyncMode; | |
3259 | ✗ | outputPins.at(3).deleteLinks(); | |
3260 | ✗ | outputPins.at(1).type = Pin::Type::Flow; | |
3261 | ✗ | outputPins.at(2).type = Pin::Type::Flow; | |
3262 | ✗ | outputPins.at(3).type = Pin::Type::None; | |
3263 | ✗ | break; | |
3264 | ✗ | case BinaryRegisterMerge::Output2_Output3: | |
3265 | ✗ | _binaryOutputRegister.at(2).rateDivisor = _binaryOutputRegister.at(1).rateDivisor; | |
3266 | ✗ | _binaryOutputSelectedFrequency.at(2) = _binaryOutputSelectedFrequency.at(1); | |
3267 | ✗ | _binaryOutputRegister.at(2).asyncMode = _binaryOutputRegister.at(1).asyncMode; | |
3268 | ✗ | outputPins.at(3).deleteLinks(); | |
3269 | ✗ | outputPins.at(1).type = Pin::Type::Flow; | |
3270 | ✗ | outputPins.at(2).type = Pin::Type::Flow; | |
3271 | ✗ | outputPins.at(3).type = Pin::Type::None; | |
3272 | ✗ | break; | |
3273 | ✗ | default: | |
3274 | ✗ | break; | |
3275 | } | ||
3276 | } | ||
3277 | ✗ | ImGui::SameLine(); | |
3278 | ✗ | NAV::gui::widgets::HelpMarker("VectorNav sensors have a buffer overflow if packages get too big (SatInfo/RawMeas selected and a lot of satellites). " | |
3279 | "A workaround is, to split the data into different Binary Outputs. " | ||
3280 | "This option merges the outputs into a single observation."); | ||
3281 | |||
3282 | // TODO: Add Gui Config for NMEA output - User manual VN-310 - 8.2.14 (p 103) | ||
3283 | } | ||
3284 | |||
3285 | // ########################################################################################################### | ||
3286 | // IMU SUBSYSTEM | ||
3287 | // ########################################################################################################### | ||
3288 | |||
3289 | ✗ | ImGui::SetNextItemOpen(true, ImGuiCond_FirstUseEver); | |
3290 | ✗ | if (ImGui::CollapsingHeader(fmt::format("IMU Subsystem##{}", size_t(id)).c_str())) | |
3291 | { | ||
3292 | ✗ | if (ImGui::TreeNode(fmt::format("Reference Frame Rotation##{}", size_t(id)).c_str())) | |
3293 | { | ||
3294 | ✗ | ImGui::TextUnformatted("Allows the measurements of the VN-310E to be rotated into a different reference frame."); | |
3295 | ✗ | ImGui::SameLine(); | |
3296 | ✗ | gui::widgets::HelpMarker("This register contains a transformation matrix that allows for the transformation of measured acceleration, " | |
3297 | "magnetic, and angular rates from the body frame of the VN-310E to any other arbitrary frame of reference. " | ||
3298 | "The use of this register allows for the sensor to be placed in any arbitrary orientation with respect to the " | ||
3299 | "user's desired body coordinate frame. This register can also be used to correct for any orientation errors due " | ||
3300 | "to mounting the VN-310E on the user's vehicle or platform.\n\n" | ||
3301 | "(X Y Z)_U = C * (X Y Z)_B\n\n" | ||
3302 | "The variables (X Y Z)_B are a measured parameter such as acceleration in the body reference frame with " | ||
3303 | "respect to the VectorNav. The variables (X Y Z)_U are a measured parameter such as acceleration in the user's " | ||
3304 | "frame of reference. The reference frame rotation register Thus needs to be loaded with the transformation " | ||
3305 | "matrix that will transform measurements from the body reference frame of the VectorNav to the desired user " | ||
3306 | "frame of reference."); | ||
3307 | ✗ | if (_sensorModel == VectorNavModel::VN310) | |
3308 | { | ||
3309 | ✗ | ImGui::SameLine(); | |
3310 | ✗ | gui::widgets::HelpMarker("The reference frame rotation is performed on all vector measurements prior to entering the INS " | |
3311 | "filter. As such, changing this register while the attitude filter is running will lead to unexpected " | ||
3312 | "behavior in the INS output. To prevent this, the register is cached on startup and changes will " | ||
3313 | "not take effect during runtime. After setting the reference frame rotation register to its new value, " | ||
3314 | "send a write settings command and then reset the VN-310E. This will allow the INS filter to " | ||
3315 | "startup with the newly set reference frame rotation.", | ||
3316 | "(!)"); | ||
3317 | } | ||
3318 | ✗ | ImGui::SameLine(); | |
3319 | ✗ | gui::widgets::HelpMarker("The matrix C in the Reference Frame Rotation Register must be an orthonormal, right-handed" | |
3320 | " matrix. The sensor will output an error if the tolerance is not within 1e-5. The sensor will also" | ||
3321 | " report an error if any of the parameters are greater than 1 or less than -1.", | ||
3322 | "(!)"); | ||
3323 | |||
3324 | ✗ | ImGui::TextUnformatted("Rotation Angles [deg]"); | |
3325 | ✗ | ImGui::SameLine(); | |
3326 | ✗ | gui::widgets::HelpMarker("The rotation happens in ZYX Order"); | |
3327 | ✗ | ImGui::Indent(); | |
3328 | |||
3329 | ✗ | Eigen::Matrix3d dcm; | |
3330 | ✗ | dcm << _referenceFrameRotationMatrix.e00, _referenceFrameRotationMatrix.e01, _referenceFrameRotationMatrix.e02, | |
3331 | ✗ | _referenceFrameRotationMatrix.e10, _referenceFrameRotationMatrix.e11, _referenceFrameRotationMatrix.e12, | |
3332 | ✗ | _referenceFrameRotationMatrix.e20, _referenceFrameRotationMatrix.e21, _referenceFrameRotationMatrix.e22; | |
3333 | ✗ | auto b_Quat_p = Eigen::Quaterniond(dcm); | |
3334 | |||
3335 | ✗ | Eigen::Vector3d eulerRot = rad2deg(trafo::quat2eulerZYX(b_Quat_p.conjugate())); | |
3336 | ✗ | std::array<float, 3> imuRot = { static_cast<float>(eulerRot.x()), static_cast<float>(eulerRot.y()), static_cast<float>(eulerRot.z()) }; | |
3337 | ✗ | if (ImGui::InputFloat3(fmt::format("##rotationAngles{}", size_t(id)).c_str(), imuRot.data())) | |
3338 | { | ||
3339 | // (-180:180] x (-90:90] x (-180:180] | ||
3340 | ✗ | imuRot.at(0) = std::max(imuRot.at(0), -179.9999F); | |
3341 | ✗ | imuRot.at(0) = std::min(imuRot.at(0), 180.0F); | |
3342 | ✗ | imuRot.at(1) = std::max(imuRot.at(1), -89.9999F); | |
3343 | ✗ | imuRot.at(1) = std::min(imuRot.at(1), 90.0F); | |
3344 | ✗ | imuRot.at(2) = std::max(imuRot.at(2), -179.9999F); | |
3345 | ✗ | imuRot.at(2) = std::min(imuRot.at(2), 180.0F); | |
3346 | |||
3347 | ✗ | Eigen::Matrix3f dcmf = trafo::b_Quat_p(deg2rad(imuRot.at(0)), deg2rad(imuRot.at(1)), deg2rad(imuRot.at(2))).toRotationMatrix().cast<float>(); | |
3348 | ✗ | _referenceFrameRotationMatrix = vn::math::mat3f(dcmf(0, 0), dcmf(0, 1), dcmf(0, 2), | |
3349 | ✗ | dcmf(1, 0), dcmf(1, 1), dcmf(1, 2), | |
3350 | ✗ | dcmf(2, 0), dcmf(2, 1), dcmf(2, 2)); | |
3351 | ✗ | LOG_DEBUG("{}: referenceFrameRotationMatrix changed to {}", nameId(), _referenceFrameRotationMatrix); | |
3352 | ✗ | flow::ApplyChanges(); | |
3353 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
3354 | { | ||
3355 | try | ||
3356 | { | ||
3357 | ✗ | _vs.writeReferenceFrameRotation(_referenceFrameRotationMatrix); | |
3358 | } | ||
3359 | ✗ | catch (const std::exception& e) | |
3360 | { | ||
3361 | ✗ | LOG_ERROR("{}: Could not configure the referenceFrameRotationMatrix: {}", nameId(), e.what()); | |
3362 | ✗ | doDeinitialize(); | |
3363 | ✗ | } | |
3364 | } | ||
3365 | else | ||
3366 | { | ||
3367 | ✗ | doDeinitialize(); | |
3368 | } | ||
3369 | } | ||
3370 | |||
3371 | ✗ | ImGui::Unindent(); | |
3372 | ✗ | ImGui::TextUnformatted("Rotation Matrix C"); | |
3373 | ✗ | ImGui::Indent(); | |
3374 | |||
3375 | ✗ | std::array<float, 3> row = { _referenceFrameRotationMatrix.e00, _referenceFrameRotationMatrix.e01, _referenceFrameRotationMatrix.e02 }; | |
3376 | ✗ | if (ImGui::InputFloat3(fmt::format("##referenceFrameRotationMatrix row 0 {}", size_t(id)).c_str(), row.data(), "%.2f")) | |
3377 | { | ||
3378 | ✗ | _referenceFrameRotationMatrix.e00 = row.at(0); | |
3379 | ✗ | _referenceFrameRotationMatrix.e01 = row.at(1); | |
3380 | ✗ | _referenceFrameRotationMatrix.e02 = row.at(2); | |
3381 | ✗ | LOG_DEBUG("{}: referenceFrameRotationMatrix changed to {}", nameId(), _referenceFrameRotationMatrix); | |
3382 | ✗ | flow::ApplyChanges(); | |
3383 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
3384 | { | ||
3385 | try | ||
3386 | { | ||
3387 | ✗ | _vs.writeReferenceFrameRotation(_referenceFrameRotationMatrix); | |
3388 | } | ||
3389 | ✗ | catch (const std::exception& e) | |
3390 | { | ||
3391 | ✗ | LOG_ERROR("{}: Could not configure the referenceFrameRotationMatrix: {}", nameId(), e.what()); | |
3392 | ✗ | doDeinitialize(); | |
3393 | ✗ | } | |
3394 | } | ||
3395 | else | ||
3396 | { | ||
3397 | ✗ | doDeinitialize(); | |
3398 | } | ||
3399 | } | ||
3400 | ✗ | row = { _referenceFrameRotationMatrix.e10, _referenceFrameRotationMatrix.e11, _referenceFrameRotationMatrix.e12 }; | |
3401 | ✗ | if (ImGui::InputFloat3(fmt::format("##referenceFrameRotationMatrix row 1 {}", size_t(id)).c_str(), row.data(), "%.2f")) | |
3402 | { | ||
3403 | ✗ | _referenceFrameRotationMatrix.e10 = row.at(0); | |
3404 | ✗ | _referenceFrameRotationMatrix.e11 = row.at(1); | |
3405 | ✗ | _referenceFrameRotationMatrix.e12 = row.at(2); | |
3406 | ✗ | LOG_DEBUG("{}: referenceFrameRotationMatrix changed to {}", nameId(), _referenceFrameRotationMatrix); | |
3407 | ✗ | flow::ApplyChanges(); | |
3408 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
3409 | { | ||
3410 | try | ||
3411 | { | ||
3412 | ✗ | _vs.writeReferenceFrameRotation(_referenceFrameRotationMatrix); | |
3413 | } | ||
3414 | ✗ | catch (const std::exception& e) | |
3415 | { | ||
3416 | ✗ | LOG_ERROR("{}: Could not configure the referenceFrameRotationMatrix: {}", nameId(), e.what()); | |
3417 | ✗ | doDeinitialize(); | |
3418 | ✗ | } | |
3419 | } | ||
3420 | else | ||
3421 | { | ||
3422 | ✗ | doDeinitialize(); | |
3423 | } | ||
3424 | } | ||
3425 | ✗ | row = { _referenceFrameRotationMatrix.e20, _referenceFrameRotationMatrix.e21, _referenceFrameRotationMatrix.e22 }; | |
3426 | ✗ | if (ImGui::InputFloat3(fmt::format("##referenceFrameRotationMatrix row 2 {}", size_t(id)).c_str(), row.data(), "%.2f")) | |
3427 | { | ||
3428 | ✗ | _referenceFrameRotationMatrix.e20 = row.at(0); | |
3429 | ✗ | _referenceFrameRotationMatrix.e21 = row.at(1); | |
3430 | ✗ | _referenceFrameRotationMatrix.e22 = row.at(2); | |
3431 | ✗ | LOG_DEBUG("{}: referenceFrameRotationMatrix changed to {}", nameId(), _referenceFrameRotationMatrix); | |
3432 | ✗ | flow::ApplyChanges(); | |
3433 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
3434 | { | ||
3435 | try | ||
3436 | { | ||
3437 | ✗ | _vs.writeReferenceFrameRotation(_referenceFrameRotationMatrix); | |
3438 | } | ||
3439 | ✗ | catch (const std::exception& e) | |
3440 | { | ||
3441 | ✗ | LOG_ERROR("{}: Could not configure the referenceFrameRotationMatrix: {}", nameId(), e.what()); | |
3442 | ✗ | doDeinitialize(); | |
3443 | ✗ | } | |
3444 | } | ||
3445 | else | ||
3446 | { | ||
3447 | ✗ | doDeinitialize(); | |
3448 | } | ||
3449 | } | ||
3450 | |||
3451 | ✗ | ImGui::Unindent(); | |
3452 | ✗ | ImGui::TreePop(); | |
3453 | } | ||
3454 | |||
3455 | ✗ | if (ImGui::TreeNode(fmt::format("IMU Filtering Configuration##{}", size_t(id)).c_str())) | |
3456 | { | ||
3457 | ✗ | ImGui::TextUnformatted("This register allows the user to configure the FIR filtering which is applied to the IMU measurements.\n" | |
3458 | "The filter is a uniformly-weighted moving window (boxcar) filter, also known as a 'moving-average' filter.\n" | ||
3459 | "Its window size can be adjusted with respect to the internal IMU frequency (800 Hz)."); | ||
3460 | |||
3461 | ✗ | if (ImGui::Checkbox(fmt::format("Couple the Imu-Filter's rate to the output rate##{}", size_t(id)).c_str(), &_coupleImuRateOutput)) | |
3462 | { | ||
3463 | ✗ | LOG_DEBUG("{}: coupleImuRateOutput changed to {}", nameId(), _coupleImuRateOutput); | |
3464 | ✗ | flow::ApplyChanges(); | |
3465 | } | ||
3466 | ✗ | ImGui::SameLine(); | |
3467 | ✗ | gui::widgets::HelpMarker("If the window-size of the IMU's moving-average filter is smaller than the output rate " | |
3468 | "divisor, some samples are lost. This results in a low output rate that still contains " | ||
3469 | "noise due to high frequencies. Therefore, it is recommended to couple the ImuFilter's " | ||
3470 | "rate to the output rate."); | ||
3471 | |||
3472 | ✗ | int magWindowSize = _imuFilteringConfigurationRegister.magWindowSize; | |
3473 | ✗ | if (_coupleImuRateOutput) | |
3474 | { | ||
3475 | ✗ | ImGui::BeginDisabled(); | |
3476 | } | ||
3477 | ✗ | if (ImGui::InputInt(fmt::format("Mag Window Size##{}", size_t(id)).c_str(), &magWindowSize)) | |
3478 | { | ||
3479 | ✗ | if (magWindowSize < 0) | |
3480 | { | ||
3481 | ✗ | magWindowSize = 0; | |
3482 | } | ||
3483 | ✗ | else if (magWindowSize > std::numeric_limits<uint16_t>::max()) | |
3484 | { | ||
3485 | ✗ | magWindowSize = std::numeric_limits<uint16_t>::max(); | |
3486 | } | ||
3487 | ✗ | _imuFilteringConfigurationRegister.magWindowSize = static_cast<uint16_t>(magWindowSize); | |
3488 | ✗ | LOG_DEBUG("{}: imuFilteringConfigurationRegister.magWindowSize changed to {}", nameId(), _imuFilteringConfigurationRegister.magWindowSize); | |
3489 | ✗ | flow::ApplyChanges(); | |
3490 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
3491 | { | ||
3492 | try | ||
3493 | { | ||
3494 | ✗ | _vs.writeImuFilteringConfiguration(_imuFilteringConfigurationRegister); | |
3495 | } | ||
3496 | ✗ | catch (const std::exception& e) | |
3497 | { | ||
3498 | ✗ | LOG_ERROR("{}: Could not configure the imuFilteringConfigurationRegister: {}", nameId(), e.what()); | |
3499 | ✗ | doDeinitialize(); | |
3500 | ✗ | } | |
3501 | } | ||
3502 | else | ||
3503 | { | ||
3504 | ✗ | doDeinitialize(); | |
3505 | } | ||
3506 | } | ||
3507 | ✗ | ImGui::SameLine(); | |
3508 | ✗ | gui::widgets::HelpMarker("The WindowSize parameters for each sensor define the number of samples at the IMU rate (default 800Hz) " | |
3509 | "which will be averaged for each output measurement."); | ||
3510 | |||
3511 | ✗ | int accelWindowSize = _imuFilteringConfigurationRegister.accelWindowSize; | |
3512 | ✗ | if (ImGui::InputInt(fmt::format("Accel Window Size##{}", size_t(id)).c_str(), &accelWindowSize)) | |
3513 | { | ||
3514 | ✗ | if (accelWindowSize < 0) | |
3515 | { | ||
3516 | ✗ | accelWindowSize = 0; | |
3517 | } | ||
3518 | ✗ | else if (accelWindowSize > std::numeric_limits<uint16_t>::max()) | |
3519 | { | ||
3520 | ✗ | accelWindowSize = std::numeric_limits<uint16_t>::max(); | |
3521 | } | ||
3522 | ✗ | _imuFilteringConfigurationRegister.accelWindowSize = static_cast<uint16_t>(accelWindowSize); | |
3523 | ✗ | LOG_DEBUG("{}: imuFilteringConfigurationRegister.accelWindowSize changed to {}", nameId(), _imuFilteringConfigurationRegister.accelWindowSize); | |
3524 | ✗ | flow::ApplyChanges(); | |
3525 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
3526 | { | ||
3527 | try | ||
3528 | { | ||
3529 | ✗ | _vs.writeImuFilteringConfiguration(_imuFilteringConfigurationRegister); | |
3530 | } | ||
3531 | ✗ | catch (const std::exception& e) | |
3532 | { | ||
3533 | ✗ | LOG_ERROR("{}: Could not configure the imuFilteringConfigurationRegister: {}", nameId(), e.what()); | |
3534 | ✗ | doDeinitialize(); | |
3535 | ✗ | } | |
3536 | } | ||
3537 | else | ||
3538 | { | ||
3539 | ✗ | doDeinitialize(); | |
3540 | } | ||
3541 | } | ||
3542 | ✗ | ImGui::SameLine(); | |
3543 | ✗ | gui::widgets::HelpMarker("The WindowSize parameters for each sensor define the number of samples at the IMU rate (default 800Hz) " | |
3544 | "which will be averaged for each output measurement."); | ||
3545 | |||
3546 | ✗ | int gyroWindowSize = _imuFilteringConfigurationRegister.gyroWindowSize; | |
3547 | ✗ | if (ImGui::InputInt(fmt::format("Gyro Window Size##{}", size_t(id)).c_str(), &gyroWindowSize)) | |
3548 | { | ||
3549 | ✗ | if (gyroWindowSize < 0) | |
3550 | { | ||
3551 | ✗ | gyroWindowSize = 0; | |
3552 | } | ||
3553 | ✗ | else if (gyroWindowSize > std::numeric_limits<uint16_t>::max()) | |
3554 | { | ||
3555 | ✗ | gyroWindowSize = std::numeric_limits<uint16_t>::max(); | |
3556 | } | ||
3557 | ✗ | _imuFilteringConfigurationRegister.gyroWindowSize = static_cast<uint16_t>(gyroWindowSize); | |
3558 | ✗ | LOG_DEBUG("{}: imuFilteringConfigurationRegister.gyroWindowSize changed to {}", nameId(), _imuFilteringConfigurationRegister.gyroWindowSize); | |
3559 | ✗ | flow::ApplyChanges(); | |
3560 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
3561 | { | ||
3562 | try | ||
3563 | { | ||
3564 | ✗ | _vs.writeImuFilteringConfiguration(_imuFilteringConfigurationRegister); | |
3565 | } | ||
3566 | ✗ | catch (const std::exception& e) | |
3567 | { | ||
3568 | ✗ | LOG_ERROR("{}: Could not configure the imuFilteringConfigurationRegister: {}", nameId(), e.what()); | |
3569 | ✗ | doDeinitialize(); | |
3570 | ✗ | } | |
3571 | } | ||
3572 | else | ||
3573 | { | ||
3574 | ✗ | doDeinitialize(); | |
3575 | } | ||
3576 | } | ||
3577 | ✗ | ImGui::SameLine(); | |
3578 | ✗ | gui::widgets::HelpMarker("The WindowSize parameters for each sensor define the number of samples at the IMU rate (default 800Hz) " | |
3579 | "which will be averaged for each output measurement."); | ||
3580 | |||
3581 | ✗ | int tempWindowSize = _imuFilteringConfigurationRegister.tempWindowSize; | |
3582 | ✗ | if (ImGui::InputInt(fmt::format("Temp Window Size##{}", size_t(id)).c_str(), &tempWindowSize)) | |
3583 | { | ||
3584 | ✗ | if (tempWindowSize < 0) | |
3585 | { | ||
3586 | ✗ | tempWindowSize = 0; | |
3587 | } | ||
3588 | ✗ | else if (tempWindowSize > std::numeric_limits<uint16_t>::max()) | |
3589 | { | ||
3590 | ✗ | tempWindowSize = std::numeric_limits<uint16_t>::max(); | |
3591 | } | ||
3592 | ✗ | _imuFilteringConfigurationRegister.tempWindowSize = static_cast<uint16_t>(tempWindowSize); | |
3593 | ✗ | LOG_DEBUG("{}: imuFilteringConfigurationRegister.tempWindowSize changed to {}", nameId(), _imuFilteringConfigurationRegister.tempWindowSize); | |
3594 | ✗ | flow::ApplyChanges(); | |
3595 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
3596 | { | ||
3597 | try | ||
3598 | { | ||
3599 | ✗ | _vs.writeImuFilteringConfiguration(_imuFilteringConfigurationRegister); | |
3600 | } | ||
3601 | ✗ | catch (const std::exception& e) | |
3602 | { | ||
3603 | ✗ | LOG_ERROR("{}: Could not configure the imuFilteringConfigurationRegister: {}", nameId(), e.what()); | |
3604 | ✗ | doDeinitialize(); | |
3605 | ✗ | } | |
3606 | } | ||
3607 | else | ||
3608 | { | ||
3609 | ✗ | doDeinitialize(); | |
3610 | } | ||
3611 | } | ||
3612 | ✗ | ImGui::SameLine(); | |
3613 | ✗ | gui::widgets::HelpMarker("The WindowSize parameters for each sensor define the number of samples at the IMU rate (default 800Hz) " | |
3614 | "which will be averaged for each output measurement."); | ||
3615 | |||
3616 | ✗ | int presWindowSize = _imuFilteringConfigurationRegister.presWindowSize; | |
3617 | ✗ | if (ImGui::InputInt(fmt::format("Pres Window Size##{}", size_t(id)).c_str(), &presWindowSize)) | |
3618 | { | ||
3619 | ✗ | if (presWindowSize < 0) | |
3620 | { | ||
3621 | ✗ | presWindowSize = 0; | |
3622 | } | ||
3623 | ✗ | else if (presWindowSize > std::numeric_limits<uint16_t>::max()) | |
3624 | { | ||
3625 | ✗ | presWindowSize = std::numeric_limits<uint16_t>::max(); | |
3626 | } | ||
3627 | ✗ | _imuFilteringConfigurationRegister.presWindowSize = static_cast<uint16_t>(presWindowSize); | |
3628 | ✗ | LOG_DEBUG("{}: imuFilteringConfigurationRegister.presWindowSize changed to {}", nameId(), _imuFilteringConfigurationRegister.presWindowSize); | |
3629 | ✗ | flow::ApplyChanges(); | |
3630 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
3631 | { | ||
3632 | try | ||
3633 | { | ||
3634 | ✗ | _vs.writeImuFilteringConfiguration(_imuFilteringConfigurationRegister); | |
3635 | } | ||
3636 | ✗ | catch (const std::exception& e) | |
3637 | { | ||
3638 | ✗ | LOG_ERROR("{}: Could not configure the imuFilteringConfigurationRegister: {}", nameId(), e.what()); | |
3639 | ✗ | doDeinitialize(); | |
3640 | ✗ | } | |
3641 | } | ||
3642 | else | ||
3643 | { | ||
3644 | ✗ | doDeinitialize(); | |
3645 | } | ||
3646 | } | ||
3647 | ✗ | ImGui::SameLine(); | |
3648 | ✗ | gui::widgets::HelpMarker("The WindowSize parameters for each sensor define the number of samples at the IMU rate (default 800Hz) " | |
3649 | "which will be averaged for each output measurement."); | ||
3650 | ✗ | if (_coupleImuRateOutput) | |
3651 | { | ||
3652 | ✗ | ImGui::EndDisabled(); | |
3653 | } | ||
3654 | |||
3655 | static constexpr std::array<std::pair<vn::protocol::uart::FilterMode, const char*>, 4> imuFilteringConfigurationFilterModes = { | ||
3656 | { { vn::protocol::uart::FilterMode::FILTERMODE_NOFILTERING, "No Filtering" }, | ||
3657 | { vn::protocol::uart::FilterMode::FILTERMODE_ONLYRAW, "Filtering performed only on raw uncompensated IMU measurements." }, | ||
3658 | { vn::protocol::uart::FilterMode::FILTERMODE_ONLYCOMPENSATED, "Filtering performed only on compensated IMU measurements." }, | ||
3659 | { vn::protocol::uart::FilterMode::FILTERMODE_BOTH, "Filtering performed on both uncompensated and compensated IMU measurements." } } | ||
3660 | }; | ||
3661 | ✗ | if (ImGui::BeginCombo(fmt::format("Mag Filter Mode##{}", size_t(id)).c_str(), vn::protocol::uart::str(_imuFilteringConfigurationRegister.magFilterMode).c_str())) | |
3662 | { | ||
3663 | ✗ | for (const auto& imuFilteringConfigurationFilterMode : imuFilteringConfigurationFilterModes) | |
3664 | { | ||
3665 | ✗ | const bool isSelected = (_imuFilteringConfigurationRegister.magFilterMode == imuFilteringConfigurationFilterMode.first); | |
3666 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(imuFilteringConfigurationFilterMode.first).c_str(), isSelected)) | |
3667 | { | ||
3668 | ✗ | _imuFilteringConfigurationRegister.magFilterMode = imuFilteringConfigurationFilterMode.first; | |
3669 | ✗ | LOG_DEBUG("{}: imuFilteringConfigurationRegister.magFilterMode changed to {}", nameId(), vn::protocol::uart::str(_imuFilteringConfigurationRegister.magFilterMode)); | |
3670 | ✗ | flow::ApplyChanges(); | |
3671 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
3672 | { | ||
3673 | try | ||
3674 | { | ||
3675 | ✗ | _vs.writeImuFilteringConfiguration(_imuFilteringConfigurationRegister); | |
3676 | } | ||
3677 | ✗ | catch (const std::exception& e) | |
3678 | { | ||
3679 | ✗ | LOG_ERROR("{}: Could not configure the imuFilteringConfigurationRegister: {}", nameId(), e.what()); | |
3680 | ✗ | doDeinitialize(); | |
3681 | ✗ | } | |
3682 | } | ||
3683 | else | ||
3684 | { | ||
3685 | ✗ | doDeinitialize(); | |
3686 | } | ||
3687 | } | ||
3688 | ✗ | if (ImGui::IsItemHovered()) | |
3689 | { | ||
3690 | ✗ | ImGui::BeginTooltip(); | |
3691 | ✗ | ImGui::TextUnformatted(imuFilteringConfigurationFilterMode.second); | |
3692 | ✗ | ImGui::EndTooltip(); | |
3693 | } | ||
3694 | |||
3695 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
3696 | { | ||
3697 | ✗ | ImGui::SetItemDefaultFocus(); | |
3698 | } | ||
3699 | } | ||
3700 | ✗ | ImGui::EndCombo(); | |
3701 | } | ||
3702 | ✗ | ImGui::SameLine(); | |
3703 | ✗ | gui::widgets::HelpMarker("The FilterMode parameters for each sensor select which output quantities the filtering should be applied to. " | |
3704 | "Filtering can be applied to either the uncompensated IMU measurements, compensated (HSI and biases " | ||
3705 | "compensated by onboard filters, if applicable), or both."); | ||
3706 | |||
3707 | ✗ | if (ImGui::BeginCombo(fmt::format("Accel Filter Mode##{}", size_t(id)).c_str(), vn::protocol::uart::str(_imuFilteringConfigurationRegister.accelFilterMode).c_str())) | |
3708 | { | ||
3709 | ✗ | for (const auto& imuFilteringConfigurationFilterMode : imuFilteringConfigurationFilterModes) | |
3710 | { | ||
3711 | ✗ | const bool isSelected = (_imuFilteringConfigurationRegister.accelFilterMode == imuFilteringConfigurationFilterMode.first); | |
3712 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(imuFilteringConfigurationFilterMode.first).c_str(), isSelected)) | |
3713 | { | ||
3714 | ✗ | _imuFilteringConfigurationRegister.accelFilterMode = imuFilteringConfigurationFilterMode.first; | |
3715 | ✗ | LOG_DEBUG("{}: imuFilteringConfigurationRegister.accelFilterMode changed to {}", nameId(), vn::protocol::uart::str(_imuFilteringConfigurationRegister.accelFilterMode)); | |
3716 | ✗ | flow::ApplyChanges(); | |
3717 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
3718 | { | ||
3719 | try | ||
3720 | { | ||
3721 | ✗ | _vs.writeImuFilteringConfiguration(_imuFilteringConfigurationRegister); | |
3722 | } | ||
3723 | ✗ | catch (const std::exception& e) | |
3724 | { | ||
3725 | ✗ | LOG_ERROR("{}: Could not configure the imuFilteringConfigurationRegister: {}", nameId(), e.what()); | |
3726 | ✗ | doDeinitialize(); | |
3727 | ✗ | } | |
3728 | } | ||
3729 | else | ||
3730 | { | ||
3731 | ✗ | doDeinitialize(); | |
3732 | } | ||
3733 | } | ||
3734 | ✗ | if (ImGui::IsItemHovered()) | |
3735 | { | ||
3736 | ✗ | ImGui::BeginTooltip(); | |
3737 | ✗ | ImGui::TextUnformatted(imuFilteringConfigurationFilterMode.second); | |
3738 | ✗ | ImGui::EndTooltip(); | |
3739 | } | ||
3740 | |||
3741 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
3742 | { | ||
3743 | ✗ | ImGui::SetItemDefaultFocus(); | |
3744 | } | ||
3745 | } | ||
3746 | ✗ | ImGui::EndCombo(); | |
3747 | } | ||
3748 | ✗ | ImGui::SameLine(); | |
3749 | ✗ | gui::widgets::HelpMarker("The FilterMode parameters for each sensor select which output quantities the filtering should be applied to. " | |
3750 | "Filtering can be applied to either the uncompensated IMU measurements, compensated (HSI and biases " | ||
3751 | "compensated by onboard filters, if applicable), or both."); | ||
3752 | |||
3753 | ✗ | if (ImGui::BeginCombo(fmt::format("Gyro Filter Mode##{}", size_t(id)).c_str(), vn::protocol::uart::str(_imuFilteringConfigurationRegister.gyroFilterMode).c_str())) | |
3754 | { | ||
3755 | ✗ | for (const auto& imuFilteringConfigurationFilterMode : imuFilteringConfigurationFilterModes) | |
3756 | { | ||
3757 | ✗ | const bool isSelected = (_imuFilteringConfigurationRegister.gyroFilterMode == imuFilteringConfigurationFilterMode.first); | |
3758 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(imuFilteringConfigurationFilterMode.first).c_str(), isSelected)) | |
3759 | { | ||
3760 | ✗ | _imuFilteringConfigurationRegister.gyroFilterMode = imuFilteringConfigurationFilterMode.first; | |
3761 | ✗ | LOG_DEBUG("{}: imuFilteringConfigurationRegister.gyroFilterMode changed to {}", nameId(), vn::protocol::uart::str(_imuFilteringConfigurationRegister.gyroFilterMode)); | |
3762 | ✗ | flow::ApplyChanges(); | |
3763 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
3764 | { | ||
3765 | try | ||
3766 | { | ||
3767 | ✗ | _vs.writeImuFilteringConfiguration(_imuFilteringConfigurationRegister); | |
3768 | } | ||
3769 | ✗ | catch (const std::exception& e) | |
3770 | { | ||
3771 | ✗ | LOG_ERROR("{}: Could not configure the imuFilteringConfigurationRegister: {}", nameId(), e.what()); | |
3772 | ✗ | doDeinitialize(); | |
3773 | ✗ | } | |
3774 | } | ||
3775 | else | ||
3776 | { | ||
3777 | ✗ | doDeinitialize(); | |
3778 | } | ||
3779 | } | ||
3780 | ✗ | if (ImGui::IsItemHovered()) | |
3781 | { | ||
3782 | ✗ | ImGui::BeginTooltip(); | |
3783 | ✗ | ImGui::TextUnformatted(imuFilteringConfigurationFilterMode.second); | |
3784 | ✗ | ImGui::EndTooltip(); | |
3785 | } | ||
3786 | |||
3787 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
3788 | { | ||
3789 | ✗ | ImGui::SetItemDefaultFocus(); | |
3790 | } | ||
3791 | } | ||
3792 | ✗ | ImGui::EndCombo(); | |
3793 | } | ||
3794 | ✗ | ImGui::SameLine(); | |
3795 | ✗ | gui::widgets::HelpMarker("The FilterMode parameters for each sensor select which output quantities the filtering should be applied to. " | |
3796 | "Filtering can be applied to either the uncompensated IMU measurements, compensated (HSI and biases " | ||
3797 | "compensated by onboard filters, if applicable), or both."); | ||
3798 | |||
3799 | ✗ | if (ImGui::BeginCombo(fmt::format("Temp Filter Mode##{}", size_t(id)).c_str(), vn::protocol::uart::str(_imuFilteringConfigurationRegister.tempFilterMode).c_str())) | |
3800 | { | ||
3801 | ✗ | for (const auto& imuFilteringConfigurationFilterMode : imuFilteringConfigurationFilterModes) | |
3802 | { | ||
3803 | ✗ | const bool isSelected = (_imuFilteringConfigurationRegister.tempFilterMode == imuFilteringConfigurationFilterMode.first); | |
3804 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(imuFilteringConfigurationFilterMode.first).c_str(), isSelected)) | |
3805 | { | ||
3806 | ✗ | _imuFilteringConfigurationRegister.tempFilterMode = imuFilteringConfigurationFilterMode.first; | |
3807 | ✗ | LOG_DEBUG("{}: imuFilteringConfigurationRegister.tempFilterMode changed to {}", nameId(), vn::protocol::uart::str(_imuFilteringConfigurationRegister.tempFilterMode)); | |
3808 | ✗ | flow::ApplyChanges(); | |
3809 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
3810 | { | ||
3811 | try | ||
3812 | { | ||
3813 | ✗ | _vs.writeImuFilteringConfiguration(_imuFilteringConfigurationRegister); | |
3814 | } | ||
3815 | ✗ | catch (const std::exception& e) | |
3816 | { | ||
3817 | ✗ | LOG_ERROR("{}: Could not configure the imuFilteringConfigurationRegister: {}", nameId(), e.what()); | |
3818 | ✗ | doDeinitialize(); | |
3819 | ✗ | } | |
3820 | } | ||
3821 | else | ||
3822 | { | ||
3823 | ✗ | doDeinitialize(); | |
3824 | } | ||
3825 | } | ||
3826 | ✗ | if (ImGui::IsItemHovered()) | |
3827 | { | ||
3828 | ✗ | ImGui::BeginTooltip(); | |
3829 | ✗ | ImGui::TextUnformatted(imuFilteringConfigurationFilterMode.second); | |
3830 | ✗ | ImGui::EndTooltip(); | |
3831 | } | ||
3832 | |||
3833 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
3834 | { | ||
3835 | ✗ | ImGui::SetItemDefaultFocus(); | |
3836 | } | ||
3837 | } | ||
3838 | ✗ | ImGui::EndCombo(); | |
3839 | } | ||
3840 | ✗ | ImGui::SameLine(); | |
3841 | ✗ | gui::widgets::HelpMarker("The FilterMode parameters for each sensor select which output quantities the filtering should be applied to. " | |
3842 | "Filtering can be applied to either the uncompensated IMU measurements, compensated (HSI and biases " | ||
3843 | "compensated by onboard filters, if applicable), or both."); | ||
3844 | |||
3845 | ✗ | if (ImGui::BeginCombo(fmt::format("Pres Filter Mode##{}", size_t(id)).c_str(), vn::protocol::uart::str(_imuFilteringConfigurationRegister.presFilterMode).c_str())) | |
3846 | { | ||
3847 | ✗ | for (const auto& imuFilteringConfigurationFilterMode : imuFilteringConfigurationFilterModes) | |
3848 | { | ||
3849 | ✗ | const bool isSelected = (_imuFilteringConfigurationRegister.presFilterMode == imuFilteringConfigurationFilterMode.first); | |
3850 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(imuFilteringConfigurationFilterMode.first).c_str(), isSelected)) | |
3851 | { | ||
3852 | ✗ | _imuFilteringConfigurationRegister.presFilterMode = imuFilteringConfigurationFilterMode.first; | |
3853 | ✗ | LOG_DEBUG("{}: imuFilteringConfigurationRegister.presFilterMode changed to {}", nameId(), vn::protocol::uart::str(_imuFilteringConfigurationRegister.presFilterMode)); | |
3854 | ✗ | flow::ApplyChanges(); | |
3855 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
3856 | { | ||
3857 | try | ||
3858 | { | ||
3859 | ✗ | _vs.writeImuFilteringConfiguration(_imuFilteringConfigurationRegister); | |
3860 | } | ||
3861 | ✗ | catch (const std::exception& e) | |
3862 | { | ||
3863 | ✗ | LOG_ERROR("{}: Could not configure the imuFilteringConfigurationRegister: {}", nameId(), e.what()); | |
3864 | ✗ | doDeinitialize(); | |
3865 | ✗ | } | |
3866 | } | ||
3867 | else | ||
3868 | { | ||
3869 | ✗ | doDeinitialize(); | |
3870 | } | ||
3871 | } | ||
3872 | ✗ | if (ImGui::IsItemHovered()) | |
3873 | { | ||
3874 | ✗ | ImGui::BeginTooltip(); | |
3875 | ✗ | ImGui::TextUnformatted(imuFilteringConfigurationFilterMode.second); | |
3876 | ✗ | ImGui::EndTooltip(); | |
3877 | } | ||
3878 | |||
3879 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
3880 | { | ||
3881 | ✗ | ImGui::SetItemDefaultFocus(); | |
3882 | } | ||
3883 | } | ||
3884 | ✗ | ImGui::EndCombo(); | |
3885 | } | ||
3886 | ✗ | ImGui::SameLine(); | |
3887 | ✗ | gui::widgets::HelpMarker("The FilterMode parameters for each sensor select which output quantities the filtering should be applied to. " | |
3888 | "Filtering can be applied to either the uncompensated IMU measurements, compensated (HSI and biases " | ||
3889 | "compensated by onboard filters, if applicable), or both."); | ||
3890 | |||
3891 | ✗ | ImGui::TreePop(); | |
3892 | } | ||
3893 | |||
3894 | ✗ | if (ImGui::TreeNode(fmt::format("Delta Theta and Delta Velocity Configuration##{}", size_t(id)).c_str())) | |
3895 | { | ||
3896 | ✗ | ImGui::TextUnformatted("The Delta Theta and Delta Velocity Configuration register allows configuration of the onboard coning and\n" | |
3897 | "sculling used to generate integrated motion values from the angular rate and acceleration IMU quantities.\n" | ||
3898 | "The fully-coupled coning and sculling integrals are computed at the IMU sample rate (nominal 400 Hz)."); | ||
3899 | |||
3900 | static constexpr std::array<std::pair<vn::protocol::uart::IntegrationFrame, const char*>, 2> deltaThetaAndDeltaVelocityConfigurationIntegrationFrames = { | ||
3901 | { { vn::protocol::uart::IntegrationFrame::INTEGRATIONFRAME_BODY, "Body frame" }, | ||
3902 | { vn::protocol::uart::IntegrationFrame::INTEGRATIONFRAME_NED, "NED frame" } } | ||
3903 | }; | ||
3904 | ✗ | if (ImGui::BeginCombo(fmt::format("Integration Frame##{}", size_t(id)).c_str(), vn::protocol::uart::str(_deltaThetaAndDeltaVelocityConfigurationRegister.integrationFrame).c_str())) | |
3905 | { | ||
3906 | ✗ | for (const auto& deltaThetaAndDeltaVelocityConfigurationIntegrationFrame : deltaThetaAndDeltaVelocityConfigurationIntegrationFrames) | |
3907 | { | ||
3908 | ✗ | const bool isSelected = (_deltaThetaAndDeltaVelocityConfigurationRegister.integrationFrame == deltaThetaAndDeltaVelocityConfigurationIntegrationFrame.first); | |
3909 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(deltaThetaAndDeltaVelocityConfigurationIntegrationFrame.first).c_str(), isSelected)) | |
3910 | { | ||
3911 | ✗ | _deltaThetaAndDeltaVelocityConfigurationRegister.integrationFrame = deltaThetaAndDeltaVelocityConfigurationIntegrationFrame.first; | |
3912 | ✗ | LOG_DEBUG("{}: deltaThetaAndDeltaVelocityConfigurationRegister.integrationFrame changed to {}", nameId(), vn::protocol::uart::str(_deltaThetaAndDeltaVelocityConfigurationRegister.integrationFrame)); | |
3913 | ✗ | flow::ApplyChanges(); | |
3914 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
3915 | { | ||
3916 | try | ||
3917 | { | ||
3918 | ✗ | _vs.writeDeltaThetaAndDeltaVelocityConfiguration(_deltaThetaAndDeltaVelocityConfigurationRegister); | |
3919 | } | ||
3920 | ✗ | catch (const std::exception& e) | |
3921 | { | ||
3922 | ✗ | LOG_ERROR("{}: Could not configure the deltaThetaAndDeltaVelocityConfigurationRegister: {}", nameId(), e.what()); | |
3923 | ✗ | doDeinitialize(); | |
3924 | ✗ | } | |
3925 | } | ||
3926 | else | ||
3927 | { | ||
3928 | ✗ | doDeinitialize(); | |
3929 | } | ||
3930 | } | ||
3931 | ✗ | if (ImGui::IsItemHovered()) | |
3932 | { | ||
3933 | ✗ | ImGui::BeginTooltip(); | |
3934 | ✗ | ImGui::TextUnformatted(deltaThetaAndDeltaVelocityConfigurationIntegrationFrame.second); | |
3935 | ✗ | ImGui::EndTooltip(); | |
3936 | } | ||
3937 | |||
3938 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
3939 | { | ||
3940 | ✗ | ImGui::SetItemDefaultFocus(); | |
3941 | } | ||
3942 | } | ||
3943 | ✗ | ImGui::EndCombo(); | |
3944 | } | ||
3945 | ✗ | ImGui::SameLine(); | |
3946 | ✗ | gui::widgets::HelpMarker("The IntegrationFrame register setting selects the reference frame used for coning and sculling. Note that " | |
3947 | "using any frame other than the body frame will rely on the onboard Kalman filter's attitude estimate. The " | ||
3948 | "factory default state is to integrate in the sensor body frame."); | ||
3949 | |||
3950 | static constexpr std::array<std::pair<vn::protocol::uart::CompensationMode, const char*>, 2> deltaThetaAndDeltaVelocityConfigurationGyroCompensationModes = { | ||
3951 | { { vn::protocol::uart::CompensationMode::COMPENSATIONMODE_NONE, "None" }, | ||
3952 | { vn::protocol::uart::CompensationMode::COMPENSATIONMODE_BIAS, "Bias" } } | ||
3953 | }; | ||
3954 | ✗ | if (ImGui::BeginCombo(fmt::format("Gyro Compensation##{}", size_t(id)).c_str(), vn::protocol::uart::str(_deltaThetaAndDeltaVelocityConfigurationRegister.gyroCompensation).c_str())) | |
3955 | { | ||
3956 | ✗ | for (const auto& deltaThetaAndDeltaVelocityConfigurationGyroCompensationMode : deltaThetaAndDeltaVelocityConfigurationGyroCompensationModes) | |
3957 | { | ||
3958 | ✗ | const bool isSelected = (_deltaThetaAndDeltaVelocityConfigurationRegister.gyroCompensation == deltaThetaAndDeltaVelocityConfigurationGyroCompensationMode.first); | |
3959 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(deltaThetaAndDeltaVelocityConfigurationGyroCompensationMode.first).c_str(), isSelected)) | |
3960 | { | ||
3961 | ✗ | _deltaThetaAndDeltaVelocityConfigurationRegister.gyroCompensation = deltaThetaAndDeltaVelocityConfigurationGyroCompensationMode.first; | |
3962 | ✗ | LOG_DEBUG("{}: deltaThetaAndDeltaVelocityConfigurationRegister.gyroCompensation changed to {}", nameId(), vn::protocol::uart::str(_deltaThetaAndDeltaVelocityConfigurationRegister.gyroCompensation)); | |
3963 | ✗ | flow::ApplyChanges(); | |
3964 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
3965 | { | ||
3966 | try | ||
3967 | { | ||
3968 | ✗ | _vs.writeDeltaThetaAndDeltaVelocityConfiguration(_deltaThetaAndDeltaVelocityConfigurationRegister); | |
3969 | } | ||
3970 | ✗ | catch (const std::exception& e) | |
3971 | { | ||
3972 | ✗ | LOG_ERROR("{}: Could not configure the deltaThetaAndDeltaVelocityConfigurationRegister: {}", nameId(), e.what()); | |
3973 | ✗ | doDeinitialize(); | |
3974 | ✗ | } | |
3975 | } | ||
3976 | else | ||
3977 | { | ||
3978 | ✗ | doDeinitialize(); | |
3979 | } | ||
3980 | } | ||
3981 | ✗ | if (ImGui::IsItemHovered()) | |
3982 | { | ||
3983 | ✗ | ImGui::BeginTooltip(); | |
3984 | ✗ | ImGui::TextUnformatted(deltaThetaAndDeltaVelocityConfigurationGyroCompensationMode.second); | |
3985 | ✗ | ImGui::EndTooltip(); | |
3986 | } | ||
3987 | |||
3988 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
3989 | { | ||
3990 | ✗ | ImGui::SetItemDefaultFocus(); | |
3991 | } | ||
3992 | } | ||
3993 | ✗ | ImGui::EndCombo(); | |
3994 | } | ||
3995 | ✗ | ImGui::SameLine(); | |
3996 | ✗ | gui::widgets::HelpMarker("The GyroCompensation register setting selects the compensation to be applied to the angular rate " | |
3997 | "measurements before integration. If bias compensation is selected, the onboard Kalman filter’s real-time " | ||
3998 | "estimate of the gyro biases will be used to compensate the IMU measurements before integration. The " | ||
3999 | "factory default state is to integrate the uncompensated angular rates from the IMU."); | ||
4000 | |||
4001 | static constexpr std::array<std::pair<vn::protocol::uart::AccCompensationMode, const char*>, 2> deltaThetaAndDeltaVelocityConfigurationAccelCompensationModes = { | ||
4002 | { { vn::protocol::uart::AccCompensationMode::ACCCOMPENSATIONMODE_NONE, "None" }, | ||
4003 | { vn::protocol::uart::AccCompensationMode::ACCCOMPENSATIONMODE_BIAS, "Bias" } } | ||
4004 | }; | ||
4005 | ✗ | if (ImGui::BeginCombo(fmt::format("Accel Compensation##{}", size_t(id)).c_str(), vn::protocol::uart::str(_deltaThetaAndDeltaVelocityConfigurationRegister.accelCompensation).c_str())) | |
4006 | { | ||
4007 | ✗ | for (const auto& deltaThetaAndDeltaVelocityConfigurationAccelCompensationMode : deltaThetaAndDeltaVelocityConfigurationAccelCompensationModes) | |
4008 | { | ||
4009 | ✗ | const bool isSelected = (_deltaThetaAndDeltaVelocityConfigurationRegister.accelCompensation == deltaThetaAndDeltaVelocityConfigurationAccelCompensationMode.first); | |
4010 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(deltaThetaAndDeltaVelocityConfigurationAccelCompensationMode.first).c_str(), isSelected)) | |
4011 | { | ||
4012 | ✗ | _deltaThetaAndDeltaVelocityConfigurationRegister.accelCompensation = deltaThetaAndDeltaVelocityConfigurationAccelCompensationMode.first; | |
4013 | ✗ | LOG_DEBUG("{}: deltaThetaAndDeltaVelocityConfigurationRegister.accelCompensation changed to {}", nameId(), vn::protocol::uart::str(_deltaThetaAndDeltaVelocityConfigurationRegister.accelCompensation)); | |
4014 | ✗ | flow::ApplyChanges(); | |
4015 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4016 | { | ||
4017 | try | ||
4018 | { | ||
4019 | ✗ | _vs.writeDeltaThetaAndDeltaVelocityConfiguration(_deltaThetaAndDeltaVelocityConfigurationRegister); | |
4020 | } | ||
4021 | ✗ | catch (const std::exception& e) | |
4022 | { | ||
4023 | ✗ | LOG_ERROR("{}: Could not configure the deltaThetaAndDeltaVelocityConfigurationRegister: {}", nameId(), e.what()); | |
4024 | ✗ | doDeinitialize(); | |
4025 | ✗ | } | |
4026 | } | ||
4027 | else | ||
4028 | { | ||
4029 | ✗ | doDeinitialize(); | |
4030 | } | ||
4031 | } | ||
4032 | ✗ | if (ImGui::IsItemHovered()) | |
4033 | { | ||
4034 | ✗ | ImGui::BeginTooltip(); | |
4035 | ✗ | ImGui::TextUnformatted(deltaThetaAndDeltaVelocityConfigurationAccelCompensationMode.second); | |
4036 | ✗ | ImGui::EndTooltip(); | |
4037 | } | ||
4038 | |||
4039 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
4040 | { | ||
4041 | ✗ | ImGui::SetItemDefaultFocus(); | |
4042 | } | ||
4043 | } | ||
4044 | ✗ | ImGui::EndCombo(); | |
4045 | } | ||
4046 | ✗ | ImGui::SameLine(); | |
4047 | ✗ | gui::widgets::HelpMarker("The AccelCompensation register setting selects the compensation to be applied to the acceleration " | |
4048 | "measurements before integration. If bias compensation is selected, the onboard Kalman filter’s real-time " | ||
4049 | "estimate of the accel biases will be used to compensate the IMU measurements before integration. The " | ||
4050 | "factory default state is to integrate the uncompensated acceleration from the IMU."); | ||
4051 | |||
4052 | ✗ | ImGui::TreePop(); | |
4053 | } | ||
4054 | } | ||
4055 | |||
4056 | // ########################################################################################################### | ||
4057 | // GNSS SUBSYSTEM | ||
4058 | // ########################################################################################################### | ||
4059 | |||
4060 | ✗ | if (_sensorModel == VectorNavModel::VN310) | |
4061 | { | ||
4062 | ✗ | ImGui::SetNextItemOpen(true, ImGuiCond_FirstUseEver); | |
4063 | ✗ | if (ImGui::CollapsingHeader(fmt::format("GNSS Subsystem##{}", size_t(id)).c_str())) | |
4064 | { | ||
4065 | ✗ | if (ImGui::TreeNode(fmt::format("GNSS Configuration##{}", size_t(id)).c_str())) | |
4066 | { | ||
4067 | static constexpr std::array<std::pair<vn::protocol::uart::GpsMode, const char*>, 3> gpsConfigurationModes = { | ||
4068 | { { vn::protocol::uart::GpsMode::GPSMODE_ONBOARDGPS, "Use onboard GNSS" }, | ||
4069 | { vn::protocol::uart::GpsMode::GPSMODE_EXTERNALGPS, "Use external GNSS" }, | ||
4070 | { vn::protocol::uart::GpsMode::GPSMODE_EXTERNALVN200GPS, "Use external VectorNav sensor as the GNSS" } } | ||
4071 | }; | ||
4072 | ✗ | if (ImGui::BeginCombo(fmt::format("Mode##{}", size_t(id)).c_str(), vn::protocol::uart::str(_gpsConfigurationRegister.mode).c_str())) | |
4073 | { | ||
4074 | ✗ | for (const auto& gpsConfigurationMode : gpsConfigurationModes) | |
4075 | { | ||
4076 | ✗ | const bool isSelected = (_gpsConfigurationRegister.mode == gpsConfigurationMode.first); | |
4077 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(gpsConfigurationMode.first).c_str(), isSelected)) | |
4078 | { | ||
4079 | ✗ | _gpsConfigurationRegister.mode = gpsConfigurationMode.first; | |
4080 | ✗ | LOG_DEBUG("{}: gpsConfigurationRegister.mode changed to {}", nameId(), vn::protocol::uart::str(_gpsConfigurationRegister.mode)); | |
4081 | ✗ | flow::ApplyChanges(); | |
4082 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4083 | { | ||
4084 | try | ||
4085 | { | ||
4086 | ✗ | _vs.writeGpsConfiguration(_gpsConfigurationRegister); | |
4087 | } | ||
4088 | ✗ | catch (const std::exception& e) | |
4089 | { | ||
4090 | ✗ | LOG_ERROR("{}: Could not configure the gpsConfigurationRegister: {}", nameId(), e.what()); | |
4091 | ✗ | doDeinitialize(); | |
4092 | ✗ | } | |
4093 | } | ||
4094 | else | ||
4095 | { | ||
4096 | ✗ | doDeinitialize(); | |
4097 | } | ||
4098 | } | ||
4099 | ✗ | if (ImGui::IsItemHovered()) | |
4100 | { | ||
4101 | ✗ | ImGui::BeginTooltip(); | |
4102 | ✗ | ImGui::TextUnformatted(gpsConfigurationMode.second); | |
4103 | ✗ | ImGui::EndTooltip(); | |
4104 | } | ||
4105 | |||
4106 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
4107 | { | ||
4108 | ✗ | ImGui::SetItemDefaultFocus(); | |
4109 | } | ||
4110 | } | ||
4111 | ✗ | ImGui::EndCombo(); | |
4112 | } | ||
4113 | |||
4114 | static constexpr std::array<std::pair<vn::protocol::uart::PpsSource, const char*>, 4> gpsConfigurationPpsSources = { | ||
4115 | { { 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." }, | ||
4116 | { 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" }, | ||
4117 | { vn::protocol::uart::PpsSource::PPSSOURCE_SYNCINRISING, "GNSS PPS signal is present on the SyncIn pin (pin 22) and should trigger on a rising edge" }, | ||
4118 | { 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 | }; | ||
4120 | ✗ | if (ImGui::BeginCombo(fmt::format("PPS Source##{}", size_t(id)).c_str(), vn::protocol::uart::str(_gpsConfigurationRegister.ppsSource).c_str())) | |
4121 | { | ||
4122 | ✗ | for (const auto& gpsConfigurationPpsSource : gpsConfigurationPpsSources) | |
4123 | { | ||
4124 | ✗ | const bool isSelected = (_gpsConfigurationRegister.ppsSource == gpsConfigurationPpsSource.first); | |
4125 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(gpsConfigurationPpsSource.first).c_str(), isSelected)) | |
4126 | { | ||
4127 | ✗ | _gpsConfigurationRegister.ppsSource = gpsConfigurationPpsSource.first; | |
4128 | ✗ | LOG_DEBUG("{}: gpsConfigurationRegister.ppsSource changed to {}", nameId(), vn::protocol::uart::str(_gpsConfigurationRegister.ppsSource)); | |
4129 | ✗ | flow::ApplyChanges(); | |
4130 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4131 | { | ||
4132 | try | ||
4133 | { | ||
4134 | ✗ | _vs.writeGpsConfiguration(_gpsConfigurationRegister); | |
4135 | } | ||
4136 | ✗ | catch (const std::exception& e) | |
4137 | { | ||
4138 | ✗ | LOG_ERROR("{}: Could not configure the gpsConfigurationRegister: {}", nameId(), e.what()); | |
4139 | ✗ | doDeinitialize(); | |
4140 | ✗ | } | |
4141 | } | ||
4142 | else | ||
4143 | { | ||
4144 | ✗ | doDeinitialize(); | |
4145 | } | ||
4146 | } | ||
4147 | ✗ | if (ImGui::IsItemHovered()) | |
4148 | { | ||
4149 | ✗ | ImGui::BeginTooltip(); | |
4150 | ✗ | ImGui::TextUnformatted(gpsConfigurationPpsSource.second); | |
4151 | ✗ | ImGui::EndTooltip(); | |
4152 | } | ||
4153 | |||
4154 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
4155 | { | ||
4156 | ✗ | ImGui::SetItemDefaultFocus(); | |
4157 | } | ||
4158 | } | ||
4159 | ✗ | ImGui::EndCombo(); | |
4160 | } | ||
4161 | |||
4162 | static constexpr std::array<vn::protocol::uart::GpsRate, 1> gpsConfigurationRates = { | ||
4163 | { /* vn::protocol::uart::GpsRate::GPSRATE_1HZ, */ | ||
4164 | vn::protocol::uart::GpsRate::GPSRATE_5HZ } | ||
4165 | }; | ||
4166 | ✗ | if (ImGui::BeginCombo(fmt::format("Rate##{}", size_t(id)).c_str(), vn::protocol::uart::str(_gpsConfigurationRegister.rate).c_str())) | |
4167 | { | ||
4168 | ✗ | for (const auto& gpsConfigurationRate : gpsConfigurationRates) | |
4169 | { | ||
4170 | ✗ | const bool isSelected = (_gpsConfigurationRegister.rate == gpsConfigurationRate); | |
4171 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(gpsConfigurationRate).c_str(), isSelected)) | |
4172 | { | ||
4173 | ✗ | _gpsConfigurationRegister.rate = gpsConfigurationRate; | |
4174 | ✗ | LOG_DEBUG("{}: gpsConfigurationRegister.rate changed to {}", nameId(), vn::protocol::uart::str(_gpsConfigurationRegister.rate)); | |
4175 | ✗ | flow::ApplyChanges(); | |
4176 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4177 | { | ||
4178 | try | ||
4179 | { | ||
4180 | ✗ | _vs.writeGpsConfiguration(_gpsConfigurationRegister); | |
4181 | } | ||
4182 | ✗ | catch (const std::exception& e) | |
4183 | { | ||
4184 | ✗ | LOG_ERROR("{}: Could not configure the gpsConfigurationRegister: {}", nameId(), e.what()); | |
4185 | ✗ | doDeinitialize(); | |
4186 | ✗ | } | |
4187 | } | ||
4188 | else | ||
4189 | { | ||
4190 | ✗ | doDeinitialize(); | |
4191 | } | ||
4192 | } | ||
4193 | |||
4194 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
4195 | { | ||
4196 | ✗ | ImGui::SetItemDefaultFocus(); | |
4197 | } | ||
4198 | } | ||
4199 | ✗ | ImGui::EndCombo(); | |
4200 | } | ||
4201 | ✗ | ImGui::SameLine(); | |
4202 | ✗ | gui::widgets::HelpMarker("GNSS navigation rate. Value must be set to 5."); | |
4203 | |||
4204 | static constexpr std::array<std::pair<vn::protocol::uart::AntPower, const char*>, 3> gpsConfigurationAntPowers = { | ||
4205 | { { vn::protocol::uart::AntPower::ANTPOWER_OFFRESV, "Disable antenna power supply." }, | ||
4206 | { vn::protocol::uart::AntPower::ANTPOWER_INTERNAL, "Use internal antenna power supply (3V, 50mA combined)." }, | ||
4207 | { vn::protocol::uart::AntPower::ANTPOWER_EXTERNAL, "Use external antenna power supply (VANT pin, up to 5V and 100mA combined)" } } | ||
4208 | }; | ||
4209 | ✗ | if (ImGui::BeginCombo(fmt::format("Ant Power##{}", size_t(id)).c_str(), vn::protocol::uart::str(_gpsConfigurationRegister.antPow).c_str())) | |
4210 | { | ||
4211 | ✗ | for (const auto& gpsConfigurationAntPower : gpsConfigurationAntPowers) | |
4212 | { | ||
4213 | ✗ | const bool isSelected = (_gpsConfigurationRegister.antPow == gpsConfigurationAntPower.first); | |
4214 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(gpsConfigurationAntPower.first).c_str(), isSelected)) | |
4215 | { | ||
4216 | ✗ | _gpsConfigurationRegister.antPow = gpsConfigurationAntPower.first; | |
4217 | ✗ | LOG_DEBUG("{}: gpsConfigurationRegister.antPow changed to {}", nameId(), vn::protocol::uart::str(_gpsConfigurationRegister.antPow)); | |
4218 | ✗ | flow::ApplyChanges(); | |
4219 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4220 | { | ||
4221 | try | ||
4222 | { | ||
4223 | ✗ | _vs.writeGpsConfiguration(_gpsConfigurationRegister); | |
4224 | } | ||
4225 | ✗ | catch (const std::exception& e) | |
4226 | { | ||
4227 | ✗ | LOG_ERROR("{}: Could not configure the gpsConfigurationRegister: {}", nameId(), e.what()); | |
4228 | ✗ | doDeinitialize(); | |
4229 | ✗ | } | |
4230 | } | ||
4231 | else | ||
4232 | { | ||
4233 | ✗ | doDeinitialize(); | |
4234 | } | ||
4235 | } | ||
4236 | ✗ | if (ImGui::IsItemHovered()) | |
4237 | { | ||
4238 | ✗ | ImGui::BeginTooltip(); | |
4239 | ✗ | ImGui::TextUnformatted(gpsConfigurationAntPower.second); | |
4240 | ✗ | ImGui::EndTooltip(); | |
4241 | } | ||
4242 | |||
4243 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
4244 | { | ||
4245 | ✗ | ImGui::SetItemDefaultFocus(); | |
4246 | } | ||
4247 | } | ||
4248 | ✗ | ImGui::EndCombo(); | |
4249 | } | ||
4250 | ✗ | ImGui::SameLine(); | |
4251 | ✗ | gui::widgets::HelpMarker("GNSS navigation rate. Value must be set to 5."); | |
4252 | |||
4253 | ✗ | ImGui::TreePop(); | |
4254 | } | ||
4255 | |||
4256 | ✗ | if (ImGui::TreeNode(fmt::format("GNSS Antenna A Offset##{}", size_t(id)).c_str())) | |
4257 | { | ||
4258 | ✗ | ImGui::TextUnformatted("The position of the GNSS antenna A relative to the sensor in the vehicle coordinate frame\n" | |
4259 | "also referred to as the GNSS antenna lever arm."); | ||
4260 | |||
4261 | ✗ | if (ImGui::InputFloat3(fmt::format("##gpsAntennaOffset {}", size_t(id)).c_str(), _gpsAntennaOffset.c, "%.6f")) | |
4262 | { | ||
4263 | ✗ | LOG_DEBUG("{}: gpsAntennaOffset changed to {}", nameId(), _gpsAntennaOffset); | |
4264 | ✗ | flow::ApplyChanges(); | |
4265 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4266 | { | ||
4267 | try | ||
4268 | { | ||
4269 | ✗ | _vs.writeGpsAntennaOffset(_gpsAntennaOffset); | |
4270 | } | ||
4271 | ✗ | catch (const std::exception& e) | |
4272 | { | ||
4273 | ✗ | LOG_ERROR("{}: Could not configure the gpsAntennaOffset: {}", nameId(), e.what()); | |
4274 | ✗ | doDeinitialize(); | |
4275 | ✗ | } | |
4276 | } | ||
4277 | else | ||
4278 | { | ||
4279 | ✗ | doDeinitialize(); | |
4280 | } | ||
4281 | } | ||
4282 | |||
4283 | ✗ | ImGui::TreePop(); | |
4284 | } | ||
4285 | |||
4286 | ✗ | if (ImGui::TreeNode(fmt::format("GNSS Compass Baseline##{}", size_t(id)).c_str())) | |
4287 | { | ||
4288 | ✗ | ImGui::TextUnformatted("Configures the position offset and measurement uncertainty of the second GNSS\n" | |
4289 | "antenna relative to the first GNSS antenna in the vehicle reference frame."); | ||
4290 | |||
4291 | ✗ | if (ImGui::InputFloat3(fmt::format("Position [m]##{}", size_t(id)).c_str(), _gpsCompassBaselineRegister.position.c, "%.6f")) | |
4292 | { | ||
4293 | ✗ | LOG_DEBUG("{}: gpsCompassBaselineRegister.position changed to {}", nameId(), _gpsCompassBaselineRegister.position); | |
4294 | ✗ | flow::ApplyChanges(); | |
4295 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4296 | { | ||
4297 | try | ||
4298 | { | ||
4299 | ✗ | _vs.writeGpsCompassBaseline(_gpsCompassBaselineRegister); | |
4300 | } | ||
4301 | ✗ | catch (const std::exception& e) | |
4302 | { | ||
4303 | ✗ | LOG_ERROR("{}: Could not configure the gpsCompassBaselineRegister: {}", nameId(), e.what()); | |
4304 | ✗ | doDeinitialize(); | |
4305 | ✗ | } | |
4306 | } | ||
4307 | else | ||
4308 | { | ||
4309 | ✗ | doDeinitialize(); | |
4310 | } | ||
4311 | } | ||
4312 | ✗ | ImGui::SameLine(); | |
4313 | ✗ | gui::widgets::HelpMarker("HEADING ACCURACY\n\n" | |
4314 | "The accuracy of the estimated heading is dependent upon the accuracy of the measured baseline " | ||
4315 | "between the two GNSS antennas. The factory default baseline is {1.0m, 0.0m, 0.0m}. If any other " | ||
4316 | "baseline is used, it is extremely important that the user acurately measures this baseline to ensure " | ||
4317 | "accurate heading estimates.\n" | ||
4318 | "The heading accuracy is linearly proportional to the measurement accuracy of the position of " | ||
4319 | "GNSS antenna B with respect to GNSS antenna A, and inversely proportional to the baseline " | ||
4320 | "length.\n\n" | ||
4321 | "Heading Error [deg] ~= 0.57 * (Baseline Error [cm]) / (Baseline Length [m])\n\n" | ||
4322 | "On a 1 meter baseline, a 1 cm measurement error equates to heading error of 0.6 degrees.", | ||
4323 | "(!)"); | ||
4324 | |||
4325 | ✗ | if (ImGui::InputFloat3(fmt::format("Uncertainty [m]##{}", size_t(id)).c_str(), _gpsCompassBaselineRegister.uncertainty.c, "%.3f")) | |
4326 | { | ||
4327 | ✗ | LOG_DEBUG("{}: gpsCompassBaselineRegister.uncertainty changed to {}", nameId(), _gpsCompassBaselineRegister.uncertainty); | |
4328 | ✗ | flow::ApplyChanges(); | |
4329 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4330 | { | ||
4331 | try | ||
4332 | { | ||
4333 | ✗ | _vs.writeGpsCompassBaseline(_gpsCompassBaselineRegister); | |
4334 | } | ||
4335 | ✗ | catch (const std::exception& e) | |
4336 | { | ||
4337 | ✗ | LOG_ERROR("{}: Could not configure the gpsCompassBaselineRegister: {}", nameId(), e.what()); | |
4338 | ✗ | doDeinitialize(); | |
4339 | ✗ | } | |
4340 | } | ||
4341 | else | ||
4342 | { | ||
4343 | ✗ | doDeinitialize(); | |
4344 | } | ||
4345 | } | ||
4346 | ✗ | ImGui::SameLine(); | |
4347 | ✗ | gui::widgets::HelpMarker("MEASUREMENT UNCERTAINTY\n\n" | |
4348 | "For the VN-310E to function properly it is very important that the user supplies a reasonable " | ||
4349 | "measurement uncertainty that is greater than the actual uncertainty in the baseline measurement. " | ||
4350 | "The VN-310E uses the uncertainty supplied by the user to validate measurements that it receives " | ||
4351 | "from the GNSS receivers. If the user inputs an uncertainty that is lower than the actual error in " | ||
4352 | "the baseline measurement between the two antennas, the VN-310E will no longer be able to derive " | ||
4353 | "heading estimates from the GNSS.\n\n" | ||
4354 | "It is recommended that you set the uncertainty equal to twice what you expect the worst case " | ||
4355 | "error to be in your baseline measurements. In many applications it is easier to measure more " | ||
4356 | "accurately in one direction than another. It is recommended that you set each of the X, Y, & Z " | ||
4357 | "uncertainties seperately to reflect this, as opposed to using a single large value.", | ||
4358 | "(!)"); | ||
4359 | |||
4360 | ✗ | ImGui::TreePop(); | |
4361 | } | ||
4362 | } | ||
4363 | } | ||
4364 | |||
4365 | // ########################################################################################################### | ||
4366 | // ATTITUDE SUBSYSTEM | ||
4367 | // ########################################################################################################### | ||
4368 | |||
4369 | ✗ | ImGui::SetNextItemOpen(true, ImGuiCond_FirstUseEver); | |
4370 | ✗ | if (ImGui::CollapsingHeader(fmt::format("Attitude Subsystem##{}", size_t(id)).c_str())) | |
4371 | { | ||
4372 | ✗ | if (ImGui::TreeNode(fmt::format("VPE Basic Control##{}", size_t(id)).c_str())) | |
4373 | { | ||
4374 | ✗ | ImGui::TextUnformatted("Provides control over various features relating to the onboard attitude filtering algorithm."); | |
4375 | |||
4376 | static constexpr std::array<vn::protocol::uart::VpeEnable, 2> vpeBasicControlEnables = { | ||
4377 | { vn::protocol::uart::VpeEnable::VPEENABLE_DISABLE, | ||
4378 | vn::protocol::uart::VpeEnable::VPEENABLE_ENABLE } | ||
4379 | }; | ||
4380 | ✗ | if (ImGui::BeginCombo(fmt::format("Enable##{}", size_t(id)).c_str(), vn::protocol::uart::str(_vpeBasicControlRegister.enable).c_str())) | |
4381 | { | ||
4382 | ✗ | for (const auto& vpeBasicControlEnable : vpeBasicControlEnables) | |
4383 | { | ||
4384 | ✗ | const bool isSelected = (_vpeBasicControlRegister.enable == vpeBasicControlEnable); | |
4385 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(vpeBasicControlEnable).c_str(), isSelected)) | |
4386 | { | ||
4387 | ✗ | _vpeBasicControlRegister.enable = vpeBasicControlEnable; | |
4388 | ✗ | LOG_DEBUG("{}: vpeBasicControlRegister.enable changed to {}", nameId(), vn::protocol::uart::str(_vpeBasicControlRegister.enable)); | |
4389 | ✗ | flow::ApplyChanges(); | |
4390 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4391 | { | ||
4392 | try | ||
4393 | { | ||
4394 | ✗ | _vs.writeVpeBasicControl(_vpeBasicControlRegister); | |
4395 | } | ||
4396 | ✗ | catch (const std::exception& e) | |
4397 | { | ||
4398 | ✗ | LOG_ERROR("{}: Could not configure the vpeBasicControlRegister: {}", nameId(), e.what()); | |
4399 | ✗ | doDeinitialize(); | |
4400 | ✗ | } | |
4401 | } | ||
4402 | else | ||
4403 | { | ||
4404 | ✗ | doDeinitialize(); | |
4405 | } | ||
4406 | } | ||
4407 | |||
4408 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
4409 | { | ||
4410 | ✗ | ImGui::SetItemDefaultFocus(); | |
4411 | } | ||
4412 | } | ||
4413 | ✗ | ImGui::EndCombo(); | |
4414 | } | ||
4415 | |||
4416 | static constexpr std::array<vn::protocol::uart::HeadingMode, 3> vpeBasicControlHeadingModes = { | ||
4417 | { vn::protocol::uart::HeadingMode::HEADINGMODE_ABSOLUTE, | ||
4418 | vn::protocol::uart::HeadingMode::HEADINGMODE_RELATIVE, | ||
4419 | vn::protocol::uart::HeadingMode::HEADINGMODE_INDOOR } | ||
4420 | }; | ||
4421 | ✗ | if (ImGui::BeginCombo(fmt::format("Heading Mode##{}", size_t(id)).c_str(), vn::protocol::uart::str(_vpeBasicControlRegister.headingMode).c_str())) | |
4422 | { | ||
4423 | ✗ | for (const auto& vpeBasicControlHeadingMode : vpeBasicControlHeadingModes) | |
4424 | { | ||
4425 | ✗ | const bool isSelected = (_vpeBasicControlRegister.headingMode == vpeBasicControlHeadingMode); | |
4426 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(vpeBasicControlHeadingMode).c_str(), isSelected)) | |
4427 | { | ||
4428 | ✗ | _vpeBasicControlRegister.headingMode = vpeBasicControlHeadingMode; | |
4429 | ✗ | LOG_DEBUG("{}: vpeBasicControlRegister.headingMode changed to {}", nameId(), vn::protocol::uart::str(_vpeBasicControlRegister.headingMode)); | |
4430 | ✗ | flow::ApplyChanges(); | |
4431 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4432 | { | ||
4433 | try | ||
4434 | { | ||
4435 | ✗ | _vs.writeVpeBasicControl(_vpeBasicControlRegister); | |
4436 | } | ||
4437 | ✗ | catch (const std::exception& e) | |
4438 | { | ||
4439 | ✗ | LOG_ERROR("{}: Could not configure the vpeBasicControlRegister: {}", nameId(), e.what()); | |
4440 | ✗ | doDeinitialize(); | |
4441 | ✗ | } | |
4442 | } | ||
4443 | else | ||
4444 | { | ||
4445 | ✗ | doDeinitialize(); | |
4446 | } | ||
4447 | } | ||
4448 | |||
4449 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
4450 | { | ||
4451 | ✗ | ImGui::SetItemDefaultFocus(); | |
4452 | } | ||
4453 | } | ||
4454 | ✗ | ImGui::EndCombo(); | |
4455 | } | ||
4456 | |||
4457 | static constexpr std::array<vn::protocol::uart::VpeMode, 2> vpeBasicControlModes = { | ||
4458 | { vn::protocol::uart::VpeMode::VPEMODE_OFF, | ||
4459 | vn::protocol::uart::VpeMode::VPEMODE_MODE1 } | ||
4460 | }; | ||
4461 | ✗ | if (ImGui::BeginCombo(fmt::format("Filtering Mode##{}", size_t(id)).c_str(), vn::protocol::uart::str(_vpeBasicControlRegister.filteringMode).c_str())) | |
4462 | { | ||
4463 | ✗ | for (const auto& vpeBasicControlMode : vpeBasicControlModes) | |
4464 | { | ||
4465 | ✗ | const bool isSelected = (_vpeBasicControlRegister.filteringMode == vpeBasicControlMode); | |
4466 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(vpeBasicControlMode).c_str(), isSelected)) | |
4467 | { | ||
4468 | ✗ | _vpeBasicControlRegister.filteringMode = vpeBasicControlMode; | |
4469 | ✗ | LOG_DEBUG("{}: vpeBasicControlRegister.filteringMode changed to {}", nameId(), vn::protocol::uart::str(_vpeBasicControlRegister.filteringMode)); | |
4470 | ✗ | flow::ApplyChanges(); | |
4471 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4472 | { | ||
4473 | try | ||
4474 | { | ||
4475 | ✗ | _vs.writeVpeBasicControl(_vpeBasicControlRegister); | |
4476 | } | ||
4477 | ✗ | catch (const std::exception& e) | |
4478 | { | ||
4479 | ✗ | LOG_ERROR("{}: Could not configure the vpeBasicControlRegister: {}", nameId(), e.what()); | |
4480 | ✗ | doDeinitialize(); | |
4481 | ✗ | } | |
4482 | } | ||
4483 | else | ||
4484 | { | ||
4485 | ✗ | doDeinitialize(); | |
4486 | } | ||
4487 | } | ||
4488 | |||
4489 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
4490 | { | ||
4491 | ✗ | ImGui::SetItemDefaultFocus(); | |
4492 | } | ||
4493 | } | ||
4494 | ✗ | ImGui::EndCombo(); | |
4495 | } | ||
4496 | |||
4497 | ✗ | if (ImGui::BeginCombo(fmt::format("Tuning Mode##{}", size_t(id)).c_str(), vn::protocol::uart::str(_vpeBasicControlRegister.tuningMode).c_str())) | |
4498 | { | ||
4499 | ✗ | for (const auto& vpeBasicControlMode : vpeBasicControlModes) | |
4500 | { | ||
4501 | ✗ | const bool isSelected = (_vpeBasicControlRegister.tuningMode == vpeBasicControlMode); | |
4502 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(vpeBasicControlMode).c_str(), isSelected)) | |
4503 | { | ||
4504 | ✗ | _vpeBasicControlRegister.tuningMode = vpeBasicControlMode; | |
4505 | ✗ | LOG_DEBUG("{}: vpeBasicControlRegister.tuningMode changed to {}", nameId(), vn::protocol::uart::str(_vpeBasicControlRegister.tuningMode)); | |
4506 | ✗ | flow::ApplyChanges(); | |
4507 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4508 | { | ||
4509 | try | ||
4510 | { | ||
4511 | ✗ | _vs.writeVpeBasicControl(_vpeBasicControlRegister); | |
4512 | } | ||
4513 | ✗ | catch (const std::exception& e) | |
4514 | { | ||
4515 | ✗ | LOG_ERROR("{}: Could not configure the vpeBasicControlRegister: {}", nameId(), e.what()); | |
4516 | ✗ | doDeinitialize(); | |
4517 | ✗ | } | |
4518 | } | ||
4519 | else | ||
4520 | { | ||
4521 | ✗ | doDeinitialize(); | |
4522 | } | ||
4523 | } | ||
4524 | |||
4525 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
4526 | { | ||
4527 | ✗ | ImGui::SetItemDefaultFocus(); | |
4528 | } | ||
4529 | } | ||
4530 | ✗ | ImGui::EndCombo(); | |
4531 | } | ||
4532 | |||
4533 | ✗ | ImGui::TreePop(); | |
4534 | } | ||
4535 | |||
4536 | ✗ | if (_sensorModel == VectorNavModel::VN100_VN110) | |
4537 | { | ||
4538 | ✗ | if (ImGui::TreeNode(fmt::format("VPE Magnetometer Basic Tuning##{}", size_t(id)).c_str())) | |
4539 | { | ||
4540 | ✗ | ImGui::TextUnformatted("Provides basic control of the adaptive filtering and tuning for the magnetometer."); | |
4541 | |||
4542 | ✗ | if (ImGui::DragFloat3(fmt::format("Base Tuning Level##{}", size_t(id)).c_str(), _vpeMagnetometerBasicTuningRegister.baseTuning.c, 0.1F, 0.0F, 10.0F, "%.1f")) | |
4543 | { | ||
4544 | ✗ | LOG_DEBUG("{}: vpeMagnetometerBasicTuningRegister.baseTuning changed to {}", nameId(), _vpeMagnetometerBasicTuningRegister.baseTuning); | |
4545 | ✗ | flow::ApplyChanges(); | |
4546 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4547 | { | ||
4548 | try | ||
4549 | { | ||
4550 | ✗ | _vs.writeVpeMagnetometerBasicTuning(_vpeMagnetometerBasicTuningRegister); | |
4551 | } | ||
4552 | ✗ | catch (const std::exception& e) | |
4553 | { | ||
4554 | ✗ | LOG_ERROR("{}: Could not configure the vpeMagnetometerBasicTuningRegister: {}", nameId(), e.what()); | |
4555 | ✗ | doDeinitialize(); | |
4556 | ✗ | } | |
4557 | } | ||
4558 | else | ||
4559 | { | ||
4560 | ✗ | doDeinitialize(); | |
4561 | } | ||
4562 | } | ||
4563 | ✗ | ImGui::SameLine(); | |
4564 | ✗ | gui::widgets::HelpMarker("This sets the level of confidence placed in the magnetometer when no disturbances are present. " | |
4565 | "A larger number provides better heading accuracy, but with more sensitivity to magnetic interference."); | ||
4566 | |||
4567 | ✗ | if (ImGui::DragFloat3(fmt::format("Adaptive Tuning Level##{}", size_t(id)).c_str(), _vpeMagnetometerBasicTuningRegister.adaptiveTuning.c, 0.1F, 0.0F, 10.0F, "%.1f")) | |
4568 | { | ||
4569 | ✗ | LOG_DEBUG("{}: vpeMagnetometerBasicTuningRegister.adaptiveTuning changed to {}", nameId(), _vpeMagnetometerBasicTuningRegister.adaptiveTuning); | |
4570 | ✗ | flow::ApplyChanges(); | |
4571 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4572 | { | ||
4573 | try | ||
4574 | { | ||
4575 | ✗ | _vs.writeVpeMagnetometerBasicTuning(_vpeMagnetometerBasicTuningRegister); | |
4576 | } | ||
4577 | ✗ | catch (const std::exception& e) | |
4578 | { | ||
4579 | ✗ | LOG_ERROR("{}: Could not configure the vpeMagnetometerBasicTuningRegister: {}", nameId(), e.what()); | |
4580 | ✗ | doDeinitialize(); | |
4581 | ✗ | } | |
4582 | } | ||
4583 | else | ||
4584 | { | ||
4585 | ✗ | doDeinitialize(); | |
4586 | } | ||
4587 | } | ||
4588 | |||
4589 | ✗ | if (ImGui::DragFloat3(fmt::format("Adaptive Filtering Level##{}", size_t(id)).c_str(), _vpeMagnetometerBasicTuningRegister.adaptiveFiltering.c, 0.1F, 0.0F, 10.0F, "%.1f")) | |
4590 | { | ||
4591 | ✗ | LOG_DEBUG("{}: vpeMagnetometerBasicTuningRegister.adaptiveFiltering changed to {}", nameId(), _vpeMagnetometerBasicTuningRegister.adaptiveFiltering); | |
4592 | ✗ | flow::ApplyChanges(); | |
4593 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4594 | { | ||
4595 | try | ||
4596 | { | ||
4597 | ✗ | _vs.writeVpeMagnetometerBasicTuning(_vpeMagnetometerBasicTuningRegister); | |
4598 | } | ||
4599 | ✗ | catch (const std::exception& e) | |
4600 | { | ||
4601 | ✗ | LOG_ERROR("{}: Could not configure the vpeMagnetometerBasicTuningRegister: {}", nameId(), e.what()); | |
4602 | ✗ | doDeinitialize(); | |
4603 | ✗ | } | |
4604 | } | ||
4605 | else | ||
4606 | { | ||
4607 | ✗ | doDeinitialize(); | |
4608 | } | ||
4609 | } | ||
4610 | |||
4611 | ✗ | ImGui::TreePop(); | |
4612 | } | ||
4613 | |||
4614 | ✗ | if (ImGui::TreeNode(fmt::format("VPE Accelerometer Basic Tuning##{}", size_t(id)).c_str())) | |
4615 | { | ||
4616 | ✗ | ImGui::TextUnformatted("Provides basic control of the adaptive filtering and tuning for the accelerometer."); | |
4617 | |||
4618 | ✗ | if (ImGui::DragFloat3(fmt::format("Base Tuning Level##{}", size_t(id)).c_str(), _vpeAccelerometerBasicTuningRegister.baseTuning.c, 0.1F, 0.0F, 10.0F, "%.1f")) | |
4619 | { | ||
4620 | ✗ | LOG_DEBUG("{}: vpeAccelerometerBasicTuningRegister.baseTuning changed to {}", nameId(), _vpeAccelerometerBasicTuningRegister.baseTuning); | |
4621 | ✗ | flow::ApplyChanges(); | |
4622 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4623 | { | ||
4624 | try | ||
4625 | { | ||
4626 | ✗ | _vs.writeVpeAccelerometerBasicTuning(_vpeAccelerometerBasicTuningRegister); | |
4627 | } | ||
4628 | ✗ | catch (const std::exception& e) | |
4629 | { | ||
4630 | ✗ | LOG_ERROR("{}: Could not configure the vpeAccelerometerBasicTuningRegister: {}", nameId(), e.what()); | |
4631 | ✗ | doDeinitialize(); | |
4632 | ✗ | } | |
4633 | } | ||
4634 | else | ||
4635 | { | ||
4636 | ✗ | doDeinitialize(); | |
4637 | } | ||
4638 | } | ||
4639 | ✗ | ImGui::SameLine(); | |
4640 | ✗ | gui::widgets::HelpMarker("This sets the level of confidence placed in the accelerometer when no disturbances are present. " | |
4641 | "A larger number provides better pitch/roll heading accuracy, but with more sensitivity to acceleration interference."); | ||
4642 | |||
4643 | ✗ | if (ImGui::DragFloat3(fmt::format("Adaptive Tuning Level##{}", size_t(id)).c_str(), _vpeAccelerometerBasicTuningRegister.adaptiveTuning.c, 0.1F, 0.0F, 10.0F, "%.1f")) | |
4644 | { | ||
4645 | ✗ | LOG_DEBUG("{}: vpeAccelerometerBasicTuningRegister.adaptiveTuning changed to {}", nameId(), _vpeAccelerometerBasicTuningRegister.adaptiveTuning); | |
4646 | ✗ | flow::ApplyChanges(); | |
4647 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4648 | { | ||
4649 | try | ||
4650 | { | ||
4651 | ✗ | _vs.writeVpeAccelerometerBasicTuning(_vpeAccelerometerBasicTuningRegister); | |
4652 | } | ||
4653 | ✗ | catch (const std::exception& e) | |
4654 | { | ||
4655 | ✗ | LOG_ERROR("{}: Could not configure the vpeAccelerometerBasicTuningRegister: {}", nameId(), e.what()); | |
4656 | ✗ | doDeinitialize(); | |
4657 | ✗ | } | |
4658 | } | ||
4659 | else | ||
4660 | { | ||
4661 | ✗ | doDeinitialize(); | |
4662 | } | ||
4663 | } | ||
4664 | |||
4665 | ✗ | if (ImGui::DragFloat3(fmt::format("Adaptive Filtering Level##{}", size_t(id)).c_str(), _vpeAccelerometerBasicTuningRegister.adaptiveFiltering.c, 0.1F, 0.0F, 10.0F, "%.1f")) | |
4666 | { | ||
4667 | ✗ | LOG_DEBUG("{}: vpeAccelerometerBasicTuningRegister.adaptiveFiltering changed to {}", nameId(), _vpeAccelerometerBasicTuningRegister.adaptiveFiltering); | |
4668 | ✗ | flow::ApplyChanges(); | |
4669 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4670 | { | ||
4671 | try | ||
4672 | { | ||
4673 | ✗ | _vs.writeVpeAccelerometerBasicTuning(_vpeAccelerometerBasicTuningRegister); | |
4674 | } | ||
4675 | ✗ | catch (const std::exception& e) | |
4676 | { | ||
4677 | ✗ | LOG_ERROR("{}: Could not configure the vpeAccelerometerBasicTuningRegister: {}", nameId(), e.what()); | |
4678 | ✗ | doDeinitialize(); | |
4679 | ✗ | } | |
4680 | } | ||
4681 | else | ||
4682 | { | ||
4683 | ✗ | doDeinitialize(); | |
4684 | } | ||
4685 | } | ||
4686 | |||
4687 | ✗ | ImGui::TreePop(); | |
4688 | } | ||
4689 | |||
4690 | ✗ | if (ImGui::TreeNode(fmt::format("VPE Gyro Basic Tuning##{}", size_t(id)).c_str())) | |
4691 | { | ||
4692 | ✗ | ImGui::TextUnformatted("Provides basic control of the adaptive filtering and tuning for the gyroscope."); | |
4693 | |||
4694 | ✗ | if (ImGui::DragFloat3(fmt::format("Base Tuning Level##{}", size_t(id)).c_str(), _vpeGyroBasicTuningRegister.baseTuning.c, 0.1F, 0.0F, 10.0F, "%.1f")) | |
4695 | { | ||
4696 | ✗ | LOG_DEBUG("{}: vpeGyroBasicTuningRegister.baseTuning changed to {}", nameId(), _vpeGyroBasicTuningRegister.baseTuning); | |
4697 | ✗ | flow::ApplyChanges(); | |
4698 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4699 | { | ||
4700 | try | ||
4701 | { | ||
4702 | ✗ | _vs.writeVpeGyroBasicTuning(_vpeGyroBasicTuningRegister); | |
4703 | } | ||
4704 | ✗ | catch (const std::exception& e) | |
4705 | { | ||
4706 | ✗ | LOG_ERROR("{}: Could not configure the vpeGyroBasicTuningRegister: {}", nameId(), e.what()); | |
4707 | ✗ | doDeinitialize(); | |
4708 | ✗ | } | |
4709 | } | ||
4710 | else | ||
4711 | { | ||
4712 | ✗ | doDeinitialize(); | |
4713 | } | ||
4714 | } | ||
4715 | ✗ | ImGui::SameLine(); | |
4716 | ✗ | gui::widgets::HelpMarker("This sets the level of confidence placed in the gyro axes."); | |
4717 | |||
4718 | ✗ | if (ImGui::DragFloat3(fmt::format("Adaptive Tuning Level##{}", size_t(id)).c_str(), _vpeGyroBasicTuningRegister.adaptiveTuning.c, 0.1F, 0.0F, 10.0F, "%.1f")) | |
4719 | { | ||
4720 | ✗ | LOG_DEBUG("{}: vpeGyroBasicTuningRegister.adaptiveTuning changed to {}", nameId(), _vpeGyroBasicTuningRegister.adaptiveTuning); | |
4721 | ✗ | flow::ApplyChanges(); | |
4722 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4723 | { | ||
4724 | try | ||
4725 | { | ||
4726 | ✗ | _vs.writeVpeGyroBasicTuning(_vpeGyroBasicTuningRegister); | |
4727 | } | ||
4728 | ✗ | catch (const std::exception& e) | |
4729 | { | ||
4730 | ✗ | LOG_ERROR("{}: Could not configure the vpeGyroBasicTuningRegister: {}", nameId(), e.what()); | |
4731 | ✗ | doDeinitialize(); | |
4732 | ✗ | } | |
4733 | } | ||
4734 | else | ||
4735 | { | ||
4736 | ✗ | doDeinitialize(); | |
4737 | } | ||
4738 | } | ||
4739 | |||
4740 | ✗ | if (ImGui::DragFloat3(fmt::format("Variance - Angular Walk##{}", size_t(id)).c_str(), _vpeGyroBasicTuningRegister.angularWalkVariance.c, 0.1F, 0.0F, 10.0F, "%.1f")) | |
4741 | { | ||
4742 | ✗ | LOG_DEBUG("{}: vpeGyroBasicTuningRegister.angularWalkVariance changed to {}", nameId(), _vpeGyroBasicTuningRegister.angularWalkVariance); | |
4743 | ✗ | flow::ApplyChanges(); | |
4744 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4745 | { | ||
4746 | try | ||
4747 | { | ||
4748 | ✗ | _vs.writeVpeGyroBasicTuning(_vpeGyroBasicTuningRegister); | |
4749 | } | ||
4750 | ✗ | catch (const std::exception& e) | |
4751 | { | ||
4752 | ✗ | LOG_ERROR("{}: Could not configure the vpeGyroBasicTuningRegister: {}", nameId(), e.what()); | |
4753 | ✗ | doDeinitialize(); | |
4754 | ✗ | } | |
4755 | } | ||
4756 | else | ||
4757 | { | ||
4758 | ✗ | doDeinitialize(); | |
4759 | } | ||
4760 | } | ||
4761 | |||
4762 | ✗ | ImGui::TreePop(); | |
4763 | } | ||
4764 | |||
4765 | ✗ | if (ImGui::TreeNode(fmt::format("Filter Startup Gyro Bias##{}", size_t(id)).c_str())) | |
4766 | { | ||
4767 | ✗ | ImGui::TextUnformatted("The filter gyro bias estimate used at startup [rad/s]."); | |
4768 | |||
4769 | ✗ | if (ImGui::InputFloat3(fmt::format("## FilterStartupGyroBias {}", size_t(id)).c_str(), _filterStartupGyroBias.c, "%.1f")) | |
4770 | { | ||
4771 | ✗ | LOG_DEBUG("{}: filterStartupGyroBias changed to {}", nameId(), _filterStartupGyroBias); | |
4772 | ✗ | flow::ApplyChanges(); | |
4773 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4774 | { | ||
4775 | try | ||
4776 | { | ||
4777 | ✗ | _vs.writeFilterStartupGyroBias(_filterStartupGyroBias); | |
4778 | } | ||
4779 | ✗ | catch (const std::exception& e) | |
4780 | { | ||
4781 | ✗ | LOG_ERROR("{}: Could not configure the filterStartupGyroBias: {}", nameId(), e.what()); | |
4782 | ✗ | doDeinitialize(); | |
4783 | ✗ | } | |
4784 | } | ||
4785 | else | ||
4786 | { | ||
4787 | ✗ | doDeinitialize(); | |
4788 | } | ||
4789 | } | ||
4790 | |||
4791 | ✗ | ImGui::TreePop(); | |
4792 | } | ||
4793 | } | ||
4794 | } | ||
4795 | |||
4796 | // ########################################################################################################### | ||
4797 | // INS SUBSYSTEM | ||
4798 | // ########################################################################################################### | ||
4799 | |||
4800 | ✗ | if (_sensorModel == VectorNavModel::VN310) | |
4801 | { | ||
4802 | ✗ | ImGui::SetNextItemOpen(true, ImGuiCond_FirstUseEver); | |
4803 | ✗ | if (ImGui::CollapsingHeader(fmt::format("INS Subsystem##{}", size_t(id)).c_str())) | |
4804 | { | ||
4805 | ✗ | if (ImGui::TreeNode(fmt::format("INS Basic Configuration##{}", size_t(id)).c_str())) | |
4806 | { | ||
4807 | static constexpr std::array<std::pair<vn::protocol::uart::Scenario, const char*>, 3> insBasicConfigurationRegisterVn300Scenarios = { | ||
4808 | { { vn::protocol::uart::Scenario::SCENARIO_INSWITHPRESSURE, "General purpose INS with barometric pressure sensor" }, | ||
4809 | { vn::protocol::uart::Scenario::SCENARIO_INSWITHOUTPRESSURE, "General purpose INS without barometric pressure sensor" }, | ||
4810 | { vn::protocol::uart::Scenario::SCENARIO_GPSMOVINGBASELINEDYNAMIC, "GNSS moving baseline for dynamic applications" } } | ||
4811 | }; | ||
4812 | ✗ | if (ImGui::BeginCombo(fmt::format("Scenario##{}", size_t(id)).c_str(), vn::protocol::uart::str(_insBasicConfigurationRegisterVn300.scenario).c_str())) | |
4813 | { | ||
4814 | ✗ | for (const auto& insBasicConfigurationRegisterVn300Scenario : insBasicConfigurationRegisterVn300Scenarios) | |
4815 | { | ||
4816 | ✗ | const bool isSelected = (_insBasicConfigurationRegisterVn300.scenario == insBasicConfigurationRegisterVn300Scenario.first); | |
4817 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(insBasicConfigurationRegisterVn300Scenario.first).c_str(), isSelected)) | |
4818 | { | ||
4819 | ✗ | _insBasicConfigurationRegisterVn300.scenario = insBasicConfigurationRegisterVn300Scenario.first; | |
4820 | ✗ | LOG_DEBUG("{}: insBasicConfigurationRegisterVn300.scenario changed to {}", nameId(), vn::protocol::uart::str(_insBasicConfigurationRegisterVn300.scenario)); | |
4821 | ✗ | flow::ApplyChanges(); | |
4822 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4823 | { | ||
4824 | try | ||
4825 | { | ||
4826 | ✗ | _vs.writeInsBasicConfigurationVn300(_insBasicConfigurationRegisterVn300); | |
4827 | } | ||
4828 | ✗ | catch (const std::exception& e) | |
4829 | { | ||
4830 | ✗ | LOG_ERROR("{}: Could not configure the insBasicConfigurationRegisterVn300: {}", nameId(), e.what()); | |
4831 | ✗ | doDeinitialize(); | |
4832 | ✗ | } | |
4833 | } | ||
4834 | else | ||
4835 | { | ||
4836 | ✗ | doDeinitialize(); | |
4837 | } | ||
4838 | } | ||
4839 | ✗ | if (ImGui::IsItemHovered()) | |
4840 | { | ||
4841 | ✗ | ImGui::BeginTooltip(); | |
4842 | ✗ | ImGui::TextUnformatted(insBasicConfigurationRegisterVn300Scenario.second); | |
4843 | ✗ | ImGui::EndTooltip(); | |
4844 | } | ||
4845 | |||
4846 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
4847 | { | ||
4848 | ✗ | ImGui::SetItemDefaultFocus(); | |
4849 | } | ||
4850 | } | ||
4851 | ✗ | ImGui::EndCombo(); | |
4852 | } | ||
4853 | |||
4854 | ✗ | if (ImGui::Checkbox(fmt::format("Ahrs Aiding##{}", size_t(id)).c_str(), &_insBasicConfigurationRegisterVn300.ahrsAiding)) | |
4855 | { | ||
4856 | ✗ | LOG_DEBUG("{}: insBasicConfigurationRegisterVn300.ahrsAiding changed to {}", nameId(), _insBasicConfigurationRegisterVn300.ahrsAiding); | |
4857 | ✗ | flow::ApplyChanges(); | |
4858 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4859 | { | ||
4860 | try | ||
4861 | { | ||
4862 | ✗ | _vs.writeInsBasicConfigurationVn300(_insBasicConfigurationRegisterVn300); | |
4863 | } | ||
4864 | ✗ | catch (const std::exception& e) | |
4865 | { | ||
4866 | ✗ | LOG_ERROR("{}: Could not configure the insBasicConfigurationRegisterVn300: {}", nameId(), e.what()); | |
4867 | ✗ | doDeinitialize(); | |
4868 | ✗ | } | |
4869 | } | ||
4870 | else | ||
4871 | { | ||
4872 | ✗ | doDeinitialize(); | |
4873 | } | ||
4874 | } | ||
4875 | ✗ | ImGui::SameLine(); | |
4876 | ✗ | gui::widgets::HelpMarker("Enables AHRS attitude aiding. AHRS aiding provides " | |
4877 | "the ability to switch to using the magnetometer to " | ||
4878 | "stabilize heading during times when the device is " | ||
4879 | "stationary and the GNSS compass is not available. " | ||
4880 | "AHRS aiding also helps to eliminate large updates in " | ||
4881 | "the attitude solution during times when heading is " | ||
4882 | "weakly observable, such as at startup."); | ||
4883 | |||
4884 | ✗ | if (ImGui::Checkbox(fmt::format("Estimate Baseline##{}", size_t(id)).c_str(), &_insBasicConfigurationRegisterVn300.estBaseline)) | |
4885 | { | ||
4886 | ✗ | LOG_DEBUG("{}: insBasicConfigurationRegisterVn300.estBaseline changed to {}", nameId(), _insBasicConfigurationRegisterVn300.estBaseline); | |
4887 | ✗ | flow::ApplyChanges(); | |
4888 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4889 | { | ||
4890 | try | ||
4891 | { | ||
4892 | ✗ | _vs.writeInsBasicConfigurationVn300(_insBasicConfigurationRegisterVn300); | |
4893 | } | ||
4894 | ✗ | catch (const std::exception& e) | |
4895 | { | ||
4896 | ✗ | LOG_ERROR("{}: Could not configure the insBasicConfigurationRegisterVn300: {}", nameId(), e.what()); | |
4897 | ✗ | doDeinitialize(); | |
4898 | ✗ | } | |
4899 | } | ||
4900 | else | ||
4901 | { | ||
4902 | ✗ | doDeinitialize(); | |
4903 | } | ||
4904 | } | ||
4905 | ✗ | ImGui::SameLine(); | |
4906 | ✗ | gui::widgets::HelpMarker("Enables GNSS compass baseline estimation by INS"); | |
4907 | |||
4908 | ✗ | ImGui::TreePop(); | |
4909 | } | ||
4910 | |||
4911 | ✗ | if (ImGui::TreeNode(fmt::format("Startup Filter Bias Estimate##{}", size_t(id)).c_str())) | |
4912 | { | ||
4913 | ✗ | ImGui::TextUnformatted("Sets the initial estimate for the filter bias states"); | |
4914 | |||
4915 | ✗ | if (ImGui::InputFloat3(fmt::format("Gyro Bias [rad/s]##{}", size_t(id)).c_str(), _startupFilterBiasEstimateRegister.gyroBias.c, "%.1f")) | |
4916 | { | ||
4917 | ✗ | LOG_DEBUG("{}: startupFilterBiasEstimateRegister.gyroBias changed to {}", nameId(), _startupFilterBiasEstimateRegister.gyroBias); | |
4918 | ✗ | flow::ApplyChanges(); | |
4919 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4920 | { | ||
4921 | try | ||
4922 | { | ||
4923 | ✗ | _vs.writeStartupFilterBiasEstimate(_startupFilterBiasEstimateRegister); | |
4924 | } | ||
4925 | ✗ | catch (const std::exception& e) | |
4926 | { | ||
4927 | ✗ | LOG_ERROR("{}: Could not configure the startupFilterBiasEstimateRegister: {}", nameId(), e.what()); | |
4928 | ✗ | doDeinitialize(); | |
4929 | ✗ | } | |
4930 | } | ||
4931 | else | ||
4932 | { | ||
4933 | ✗ | doDeinitialize(); | |
4934 | } | ||
4935 | } | ||
4936 | |||
4937 | ✗ | if (ImGui::InputFloat3(fmt::format("Accel Bias [m/s^2]##{}", size_t(id)).c_str(), _startupFilterBiasEstimateRegister.accelBias.c, "%.1f")) | |
4938 | { | ||
4939 | ✗ | LOG_DEBUG("{}: startupFilterBiasEstimateRegister.accelBias changed to {}", nameId(), _startupFilterBiasEstimateRegister.accelBias); | |
4940 | ✗ | flow::ApplyChanges(); | |
4941 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4942 | { | ||
4943 | try | ||
4944 | { | ||
4945 | ✗ | _vs.writeStartupFilterBiasEstimate(_startupFilterBiasEstimateRegister); | |
4946 | } | ||
4947 | ✗ | catch (const std::exception& e) | |
4948 | { | ||
4949 | ✗ | LOG_ERROR("{}: Could not configure the startupFilterBiasEstimateRegister: {}", nameId(), e.what()); | |
4950 | ✗ | doDeinitialize(); | |
4951 | ✗ | } | |
4952 | } | ||
4953 | else | ||
4954 | { | ||
4955 | ✗ | doDeinitialize(); | |
4956 | } | ||
4957 | } | ||
4958 | |||
4959 | ✗ | if (ImGui::InputFloat(fmt::format("Pressure Bias [m]##{}", size_t(id)).c_str(), &_startupFilterBiasEstimateRegister.pressureBias)) | |
4960 | { | ||
4961 | ✗ | LOG_DEBUG("{}: startupFilterBiasEstimateRegister.pressureBias changed to {}", nameId(), _startupFilterBiasEstimateRegister.pressureBias); | |
4962 | ✗ | flow::ApplyChanges(); | |
4963 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
4964 | { | ||
4965 | try | ||
4966 | { | ||
4967 | ✗ | _vs.writeStartupFilterBiasEstimate(_startupFilterBiasEstimateRegister); | |
4968 | } | ||
4969 | ✗ | catch (const std::exception& e) | |
4970 | { | ||
4971 | ✗ | LOG_ERROR("{}: Could not configure the startupFilterBiasEstimateRegister: {}", nameId(), e.what()); | |
4972 | ✗ | doDeinitialize(); | |
4973 | ✗ | } | |
4974 | } | ||
4975 | else | ||
4976 | { | ||
4977 | ✗ | doDeinitialize(); | |
4978 | } | ||
4979 | } | ||
4980 | |||
4981 | ✗ | ImGui::TreePop(); | |
4982 | } | ||
4983 | } | ||
4984 | } | ||
4985 | |||
4986 | // ########################################################################################################### | ||
4987 | // HARD/SOFT IRON ESTIMATOR SUBSYSTEM | ||
4988 | // ########################################################################################################### | ||
4989 | |||
4990 | ✗ | ImGui::SetNextItemOpen(true, ImGuiCond_FirstUseEver); | |
4991 | ✗ | if (ImGui::CollapsingHeader(fmt::format("Hard/Soft Iron Estimator Subsystem##{}", size_t(id)).c_str())) | |
4992 | { | ||
4993 | ✗ | if (ImGui::TreeNode(fmt::format("Magnetometer Calibration Control##{}", size_t(id)).c_str())) | |
4994 | { | ||
4995 | ✗ | ImGui::TextUnformatted("Controls the magnetometer real-time calibration algorithm."); | |
4996 | ✗ | if (_sensorModel == VectorNavModel::VN310) | |
4997 | { | ||
4998 | ✗ | ImGui::SameLine(); | |
4999 | ✗ | gui::widgets::HelpMarker("On the PRODUCT the magnetometer is only used to provide a coarse heading estimate at startup " | |
5000 | "and is completely tuned out of the INS filter during normal operation. A Hard/Soft Iron calibration " | ||
5001 | "may be performed to try and improve the startup magnetic heading, but is not required for nominal " | ||
5002 | "operaiton.", | ||
5003 | "(!)"); | ||
5004 | } | ||
5005 | |||
5006 | static constexpr std::array<std::pair<vn::protocol::uart::HsiMode, const char*>, 3> magnetometerCalibrationControlHsiModes = { | ||
5007 | { { vn::protocol::uart::HsiMode::HSIMODE_OFF, "Real-time hard/soft iron calibration algorithm is turned off" }, | ||
5008 | { vn::protocol::uart::HsiMode::HSIMODE_RUN, "Runs the real-time hard/soft iron calibration. The algorithm will continue using its existing solution.\n" | ||
5009 | "The algorithm can be started and stopped at any time by switching between the HSI_OFF and HSI_RUN state." }, | ||
5010 | { vn::protocol::uart::HsiMode::HSIMODE_RESET, "Resets the real-time hard/soft iron solution" } } | ||
5011 | }; | ||
5012 | ✗ | if (ImGui::BeginCombo(fmt::format("HSI Mode##{}", size_t(id)).c_str(), vn::protocol::uart::str(_magnetometerCalibrationControlRegister.hsiMode).c_str())) | |
5013 | { | ||
5014 | ✗ | for (const auto& magnetometerCalibrationControlHsiMode : magnetometerCalibrationControlHsiModes) | |
5015 | { | ||
5016 | ✗ | const bool isSelected = (_magnetometerCalibrationControlRegister.hsiMode == magnetometerCalibrationControlHsiMode.first); | |
5017 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(magnetometerCalibrationControlHsiMode.first).c_str(), isSelected)) | |
5018 | { | ||
5019 | ✗ | _magnetometerCalibrationControlRegister.hsiMode = magnetometerCalibrationControlHsiMode.first; | |
5020 | ✗ | LOG_DEBUG("{}: magnetometerCalibrationControlRegister.hsiMode changed to {}", nameId(), vn::protocol::uart::str(_magnetometerCalibrationControlRegister.hsiMode)); | |
5021 | ✗ | flow::ApplyChanges(); | |
5022 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
5023 | { | ||
5024 | try | ||
5025 | { | ||
5026 | ✗ | _vs.writeMagnetometerCalibrationControl(_magnetometerCalibrationControlRegister); | |
5027 | } | ||
5028 | ✗ | catch (const std::exception& e) | |
5029 | { | ||
5030 | ✗ | LOG_ERROR("{}: Could not configure the magnetometerCalibrationControlRegister: {}", nameId(), e.what()); | |
5031 | ✗ | doDeinitialize(); | |
5032 | ✗ | } | |
5033 | } | ||
5034 | else | ||
5035 | { | ||
5036 | ✗ | doDeinitialize(); | |
5037 | } | ||
5038 | } | ||
5039 | ✗ | if (ImGui::IsItemHovered()) | |
5040 | { | ||
5041 | ✗ | ImGui::BeginTooltip(); | |
5042 | ✗ | ImGui::TextUnformatted(magnetometerCalibrationControlHsiMode.second); | |
5043 | ✗ | ImGui::EndTooltip(); | |
5044 | } | ||
5045 | |||
5046 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
5047 | { | ||
5048 | ✗ | ImGui::SetItemDefaultFocus(); | |
5049 | } | ||
5050 | } | ||
5051 | ✗ | ImGui::EndCombo(); | |
5052 | } | ||
5053 | ✗ | ImGui::SameLine(); | |
5054 | ✗ | gui::widgets::HelpMarker("Controls the mode of operation for the onboard real-time magnetometer hard/soft iron compensation algorithm."); | |
5055 | |||
5056 | static constexpr std::array<std::pair<vn::protocol::uart::HsiOutput, const char*>, 2> magnetometerCalibrationControlHsiOutputs = { | ||
5057 | { { vn::protocol::uart::HsiOutput::HSIOUTPUT_NOONBOARD, "Onboard HSI is not applied to the magnetic measurements" }, | ||
5058 | { vn::protocol::uart::HsiOutput::HSIOUTPUT_USEONBOARD, "Onboard HSI is applied to the magnetic measurements" } } | ||
5059 | }; | ||
5060 | ✗ | if (ImGui::BeginCombo(fmt::format("HSI Output##{}", size_t(id)).c_str(), vn::protocol::uart::str(_magnetometerCalibrationControlRegister.hsiOutput).c_str())) | |
5061 | { | ||
5062 | ✗ | for (const auto& [magnetometerCalibrationControlHsiOutputMode, magnetometerCalibrationControlHsiOutputDescription] : magnetometerCalibrationControlHsiOutputs) | |
5063 | { | ||
5064 | ✗ | const bool isSelected = (_magnetometerCalibrationControlRegister.hsiOutput == magnetometerCalibrationControlHsiOutputMode); | |
5065 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(magnetometerCalibrationControlHsiOutputMode).c_str(), isSelected)) | |
5066 | { | ||
5067 | ✗ | _magnetometerCalibrationControlRegister.hsiOutput = magnetometerCalibrationControlHsiOutputMode; | |
5068 | ✗ | LOG_DEBUG("{}: magnetometerCalibrationControlRegister.hsiOutput changed to {}", nameId(), vn::protocol::uart::str(_magnetometerCalibrationControlRegister.hsiOutput)); | |
5069 | ✗ | flow::ApplyChanges(); | |
5070 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
5071 | { | ||
5072 | try | ||
5073 | { | ||
5074 | ✗ | _vs.writeMagnetometerCalibrationControl(_magnetometerCalibrationControlRegister); | |
5075 | } | ||
5076 | ✗ | catch (const std::exception& e) | |
5077 | { | ||
5078 | ✗ | LOG_ERROR("{}: Could not configure the magnetometerCalibrationControlRegister: {}", nameId(), e.what()); | |
5079 | ✗ | doDeinitialize(); | |
5080 | ✗ | } | |
5081 | } | ||
5082 | else | ||
5083 | { | ||
5084 | ✗ | doDeinitialize(); | |
5085 | } | ||
5086 | } | ||
5087 | ✗ | if (ImGui::IsItemHovered()) | |
5088 | { | ||
5089 | ✗ | ImGui::BeginTooltip(); | |
5090 | ✗ | ImGui::TextUnformatted(magnetometerCalibrationControlHsiOutputDescription); | |
5091 | ✗ | ImGui::EndTooltip(); | |
5092 | } | ||
5093 | |||
5094 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
5095 | { | ||
5096 | ✗ | ImGui::SetItemDefaultFocus(); | |
5097 | } | ||
5098 | } | ||
5099 | ✗ | ImGui::EndCombo(); | |
5100 | } | ||
5101 | ✗ | ImGui::SameLine(); | |
5102 | ✗ | gui::widgets::HelpMarker("Controls the type of measurements that are provided as " | |
5103 | "outputs from the magnetometer sensor and also " | ||
5104 | "subsequently used in the attitude filter."); | ||
5105 | |||
5106 | ✗ | int convergeRate = _magnetometerCalibrationControlRegister.convergeRate; | |
5107 | ✗ | if (ImGui::SliderInt(fmt::format("Converge Rate##{}", size_t(id)).c_str(), &convergeRate, 0, 5)) | |
5108 | { | ||
5109 | ✗ | _magnetometerCalibrationControlRegister.convergeRate = static_cast<uint8_t>(convergeRate); | |
5110 | ✗ | LOG_DEBUG("{}: magnetometerCalibrationControlRegister.convergeRate changed to {}", nameId(), _magnetometerCalibrationControlRegister.convergeRate); | |
5111 | ✗ | flow::ApplyChanges(); | |
5112 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
5113 | { | ||
5114 | try | ||
5115 | { | ||
5116 | ✗ | _vs.writeMagnetometerCalibrationControl(_magnetometerCalibrationControlRegister); | |
5117 | } | ||
5118 | ✗ | catch (const std::exception& e) | |
5119 | { | ||
5120 | ✗ | LOG_ERROR("{}: Could not configure the magnetometerCalibrationControlRegister: {}", nameId(), e.what()); | |
5121 | ✗ | doDeinitialize(); | |
5122 | ✗ | } | |
5123 | } | ||
5124 | else | ||
5125 | { | ||
5126 | ✗ | doDeinitialize(); | |
5127 | } | ||
5128 | } | ||
5129 | ✗ | ImGui::SameLine(); | |
5130 | ✗ | gui::widgets::HelpMarker("Controls how quickly the hard/soft iron solution is allowed " | |
5131 | "to converge onto a new solution. The slower the " | ||
5132 | "convergence the more accurate the estimate of the " | ||
5133 | "hard/soft iron solution. A quicker convergence will provide " | ||
5134 | "a less accurate estimate of the hard/soft iron parameters, " | ||
5135 | "but for applications where the hard/soft iron changes " | ||
5136 | "rapidly may provide a more accurate attitude estimate.\n\n" | ||
5137 | "Range: 1 to 5\n" | ||
5138 | "1 = Solution converges slowly over approximately 60-90 seconds.\n" | ||
5139 | "5 = Solution converges rapidly over approximately 15-20 seconds."); | ||
5140 | |||
5141 | ✗ | ImGui::TreePop(); | |
5142 | } | ||
5143 | } | ||
5144 | |||
5145 | // ########################################################################################################### | ||
5146 | // WORLD MAGNETIC & GRAVITY MODULE | ||
5147 | // ########################################################################################################### | ||
5148 | |||
5149 | ✗ | ImGui::SetNextItemOpen(true, ImGuiCond_FirstUseEver); | |
5150 | ✗ | if (ImGui::CollapsingHeader(fmt::format("World Magnetic & Gravity Module##{}", size_t(id)).c_str())) | |
5151 | { | ||
5152 | ✗ | if (ImGui::TreeNode(fmt::format("Magnetic and Gravity Reference Vectors##{}", size_t(id)).c_str())) | |
5153 | { | ||
5154 | ✗ | ImGui::TextUnformatted("Magnetic and gravity reference vectors"); | |
5155 | ✗ | ImGui::SameLine(); | |
5156 | ✗ | gui::widgets::HelpMarker("This register contains the reference vectors for the magnetic and gravitational fields as used by the " | |
5157 | "onboard filter. The values map to either the user-set values or the results of calculations of the onboard " | ||
5158 | "reference models (see the Reference Vector Configuration Register in the IMU subsystem). When the " | ||
5159 | "reference values come from the onboard model(s), those values are read-only. When the reference models " | ||
5160 | "are disabled, the values reflect the user reference vectors and will be writable. For example, if the onboard " | ||
5161 | "World Magnetic Model is enabled and the onboard Gravitational Model is disabled, only the gravity " | ||
5162 | "reference values will be modified on a register write. Note that the user reference vectors will not be " | ||
5163 | "overwritten by the onboard models, but will retain their previous values for when the onboard models are " | ||
5164 | "disabled."); | ||
5165 | |||
5166 | ✗ | if (ImGui::InputFloat3(fmt::format("Magnetic Reference [Gauss]##{}", size_t(id)).c_str(), _magneticAndGravityReferenceVectorsRegister.magRef.c, "%.3f")) | |
5167 | { | ||
5168 | ✗ | LOG_DEBUG("{}: magneticAndGravityReferenceVectorsRegister.magRef changed to {}", nameId(), _magneticAndGravityReferenceVectorsRegister.magRef); | |
5169 | ✗ | flow::ApplyChanges(); | |
5170 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
5171 | { | ||
5172 | try | ||
5173 | { | ||
5174 | ✗ | _vs.writeMagneticAndGravityReferenceVectors(_magneticAndGravityReferenceVectorsRegister); | |
5175 | } | ||
5176 | ✗ | catch (const std::exception& e) | |
5177 | { | ||
5178 | ✗ | LOG_ERROR("{}: Could not configure the magneticAndGravityReferenceVectorsRegister: {}", nameId(), e.what()); | |
5179 | ✗ | doDeinitialize(); | |
5180 | ✗ | } | |
5181 | } | ||
5182 | else | ||
5183 | { | ||
5184 | ✗ | doDeinitialize(); | |
5185 | } | ||
5186 | } | ||
5187 | |||
5188 | ✗ | if (ImGui::InputFloat3(fmt::format("Gravity Reference [m/s^2]##{}", size_t(id)).c_str(), _magneticAndGravityReferenceVectorsRegister.accRef.c, "%.6f")) | |
5189 | { | ||
5190 | ✗ | LOG_DEBUG("{}: magneticAndGravityReferenceVectorsRegister.accRef changed to {}", nameId(), _magneticAndGravityReferenceVectorsRegister.accRef); | |
5191 | ✗ | flow::ApplyChanges(); | |
5192 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
5193 | { | ||
5194 | try | ||
5195 | { | ||
5196 | ✗ | _vs.writeMagneticAndGravityReferenceVectors(_magneticAndGravityReferenceVectorsRegister); | |
5197 | } | ||
5198 | ✗ | catch (const std::exception& e) | |
5199 | { | ||
5200 | ✗ | LOG_ERROR("{}: Could not configure the magneticAndGravityReferenceVectorsRegister: {}", nameId(), e.what()); | |
5201 | ✗ | doDeinitialize(); | |
5202 | ✗ | } | |
5203 | } | ||
5204 | else | ||
5205 | { | ||
5206 | ✗ | doDeinitialize(); | |
5207 | } | ||
5208 | } | ||
5209 | |||
5210 | ✗ | ImGui::TreePop(); | |
5211 | } | ||
5212 | |||
5213 | ✗ | if (ImGui::TreeNode(fmt::format("Reference Vector Configuration##{}", size_t(id)).c_str())) | |
5214 | { | ||
5215 | ✗ | ImGui::TextUnformatted("Control register for both the onboard world magnetic and gravity model corrections"); | |
5216 | ✗ | ImGui::SameLine(); | |
5217 | ✗ | gui::widgets::HelpMarker("This register allows configuration of the onboard spherical harmonic models used to calculate the local " | |
5218 | "magnetic and gravitational reference values. Having accurate magnetic reference values improves the " | ||
5219 | "accuracy of heading when using the magnetometer and accounts for magnetic declination. Having accurate " | ||
5220 | "gravitational reference values improves accuracy by allowing the INS filter to more accurately estimate the " | ||
5221 | "accelerometer biases. The VectorNav currently includes the EGM96 gravitational model and the WMM2010 " | ||
5222 | "magnetic model. The models are upgradable to allow updating to future models when available.\n\n" | ||
5223 | "The magnetic and gravity models can be individually enabled or disabled using the UseMagModel and " | ||
5224 | "UseGravityModel parameters, respectively. When disabled, the corresponding values set by the user in the " | ||
5225 | "Reference Vector Register in the IMU subsystem will be used instead of values calculated by the onboard " | ||
5226 | "model.\n\n" | ||
5227 | "The VectorNav starts up with the user configured reference vector values. Shortly after startup (and if the " | ||
5228 | "models are enabled), the location and time set in this register will be used to update the reference vectors. " | ||
5229 | "When a 3D GNSS fix is available, the location and time reported by the GNSS will be used to update the model. " | ||
5230 | "If GNSS is lost, the reference vectors will hold their last valid values. The model values will be recalculated " | ||
5231 | "whenever the current position has changed by the RecaclThreshold or the date has changed by more than " | ||
5232 | "approximately 8 hours, whichever comes first."); | ||
5233 | |||
5234 | ✗ | if (ImGui::Checkbox(fmt::format("Use Mag Model##{}", size_t(id)).c_str(), &_referenceVectorConfigurationRegister.useMagModel)) | |
5235 | { | ||
5236 | ✗ | LOG_DEBUG("{}: referenceVectorConfigurationRegister.useMagModel changed to {}", nameId(), _referenceVectorConfigurationRegister.useMagModel); | |
5237 | ✗ | flow::ApplyChanges(); | |
5238 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
5239 | { | ||
5240 | try | ||
5241 | { | ||
5242 | ✗ | _vs.writeReferenceVectorConfiguration(_referenceVectorConfigurationRegister); | |
5243 | } | ||
5244 | ✗ | catch (const std::exception& e) | |
5245 | { | ||
5246 | ✗ | LOG_ERROR("{}: Could not configure the referenceVectorConfigurationRegister: {}", nameId(), e.what()); | |
5247 | ✗ | doDeinitialize(); | |
5248 | ✗ | } | |
5249 | } | ||
5250 | else | ||
5251 | { | ||
5252 | ✗ | doDeinitialize(); | |
5253 | } | ||
5254 | } | ||
5255 | |||
5256 | ✗ | if (ImGui::Checkbox(fmt::format("Use Gravity Model##{}", size_t(id)).c_str(), &_referenceVectorConfigurationRegister.useGravityModel)) | |
5257 | { | ||
5258 | ✗ | LOG_DEBUG("{}: referenceVectorConfigurationRegister.useGravityModel changed to {}", nameId(), _referenceVectorConfigurationRegister.useGravityModel); | |
5259 | ✗ | flow::ApplyChanges(); | |
5260 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
5261 | { | ||
5262 | try | ||
5263 | { | ||
5264 | ✗ | _vs.writeReferenceVectorConfiguration(_referenceVectorConfigurationRegister); | |
5265 | } | ||
5266 | ✗ | catch (const std::exception& e) | |
5267 | { | ||
5268 | ✗ | LOG_ERROR("{}: Could not configure the referenceVectorConfigurationRegister: {}", nameId(), e.what()); | |
5269 | ✗ | doDeinitialize(); | |
5270 | ✗ | } | |
5271 | } | ||
5272 | else | ||
5273 | { | ||
5274 | ✗ | doDeinitialize(); | |
5275 | } | ||
5276 | } | ||
5277 | |||
5278 | ✗ | auto recalcThreshold = static_cast<int>(_referenceVectorConfigurationRegister.recalcThreshold); | |
5279 | ✗ | if (ImGui::InputInt(fmt::format("Recalc Threshold [m]##{}", size_t(id)).c_str(), &recalcThreshold)) | |
5280 | { | ||
5281 | ✗ | _referenceVectorConfigurationRegister.recalcThreshold = static_cast<uint32_t>(recalcThreshold); | |
5282 | ✗ | LOG_DEBUG("{}: referenceVectorConfigurationRegister.recalcThreshold changed to {}", nameId(), _referenceVectorConfigurationRegister.recalcThreshold); | |
5283 | ✗ | flow::ApplyChanges(); | |
5284 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
5285 | { | ||
5286 | try | ||
5287 | { | ||
5288 | ✗ | _vs.writeReferenceVectorConfiguration(_referenceVectorConfigurationRegister); | |
5289 | } | ||
5290 | ✗ | catch (const std::exception& e) | |
5291 | { | ||
5292 | ✗ | LOG_ERROR("{}: Could not configure the referenceVectorConfigurationRegister: {}", nameId(), e.what()); | |
5293 | ✗ | doDeinitialize(); | |
5294 | ✗ | } | |
5295 | } | ||
5296 | else | ||
5297 | { | ||
5298 | ✗ | doDeinitialize(); | |
5299 | } | ||
5300 | } | ||
5301 | ✗ | ImGui::SameLine(); | |
5302 | ✗ | gui::widgets::HelpMarker("Maximum distance traveled before magnetic and gravity models are recalculated for the new position."); | |
5303 | |||
5304 | ✗ | if (ImGui::InputFloat(fmt::format("Year##{}", size_t(id)).c_str(), &_referenceVectorConfigurationRegister.year)) | |
5305 | { | ||
5306 | ✗ | LOG_DEBUG("{}: referenceVectorConfigurationRegister.year changed to {}", nameId(), _referenceVectorConfigurationRegister.year); | |
5307 | ✗ | flow::ApplyChanges(); | |
5308 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
5309 | { | ||
5310 | try | ||
5311 | { | ||
5312 | ✗ | _vs.writeReferenceVectorConfiguration(_referenceVectorConfigurationRegister); | |
5313 | } | ||
5314 | ✗ | catch (const std::exception& e) | |
5315 | { | ||
5316 | ✗ | LOG_ERROR("{}: Could not configure the referenceVectorConfigurationRegister: {}", nameId(), e.what()); | |
5317 | ✗ | doDeinitialize(); | |
5318 | ✗ | } | |
5319 | } | ||
5320 | else | ||
5321 | { | ||
5322 | ✗ | doDeinitialize(); | |
5323 | } | ||
5324 | } | ||
5325 | ✗ | ImGui::SameLine(); | |
5326 | ✗ | gui::widgets::HelpMarker("The reference date expressed as a decimal year. Used for both the magnetic and gravity models."); | |
5327 | |||
5328 | ✗ | if (ImGui::InputDouble(fmt::format("Latitude [deg]##{}", size_t(id)).c_str(), &_referenceVectorConfigurationRegister.position[0])) | |
5329 | { | ||
5330 | ✗ | LOG_DEBUG("{}: referenceVectorConfigurationRegister.position.latitude changed to {}", nameId(), _referenceVectorConfigurationRegister.position[0]); | |
5331 | ✗ | flow::ApplyChanges(); | |
5332 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
5333 | { | ||
5334 | try | ||
5335 | { | ||
5336 | ✗ | _vs.writeReferenceVectorConfiguration(_referenceVectorConfigurationRegister); | |
5337 | } | ||
5338 | ✗ | catch (const std::exception& e) | |
5339 | { | ||
5340 | ✗ | LOG_ERROR("{}: Could not configure the referenceVectorConfigurationRegister: {}", nameId(), e.what()); | |
5341 | ✗ | doDeinitialize(); | |
5342 | ✗ | } | |
5343 | } | ||
5344 | else | ||
5345 | { | ||
5346 | ✗ | doDeinitialize(); | |
5347 | } | ||
5348 | } | ||
5349 | ✗ | ImGui::SameLine(); | |
5350 | ✗ | gui::widgets::HelpMarker("The reference latitude position in degrees."); | |
5351 | |||
5352 | ✗ | if (ImGui::InputDouble(fmt::format("Longitude [deg]##{}", size_t(id)).c_str(), &_referenceVectorConfigurationRegister.position[1])) | |
5353 | { | ||
5354 | ✗ | LOG_DEBUG("{}: referenceVectorConfigurationRegister.position.longitude changed to {}", nameId(), _referenceVectorConfigurationRegister.position[1]); | |
5355 | ✗ | flow::ApplyChanges(); | |
5356 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
5357 | { | ||
5358 | try | ||
5359 | { | ||
5360 | ✗ | _vs.writeReferenceVectorConfiguration(_referenceVectorConfigurationRegister); | |
5361 | } | ||
5362 | ✗ | catch (const std::exception& e) | |
5363 | { | ||
5364 | ✗ | LOG_ERROR("{}: Could not configure the referenceVectorConfigurationRegister: {}", nameId(), e.what()); | |
5365 | ✗ | doDeinitialize(); | |
5366 | ✗ | } | |
5367 | } | ||
5368 | else | ||
5369 | { | ||
5370 | ✗ | doDeinitialize(); | |
5371 | } | ||
5372 | } | ||
5373 | ✗ | ImGui::SameLine(); | |
5374 | ✗ | gui::widgets::HelpMarker("The reference longitude position in degrees."); | |
5375 | |||
5376 | ✗ | if (ImGui::InputDouble(fmt::format("Altitude [m]##{}", size_t(id)).c_str(), &_referenceVectorConfigurationRegister.position[2])) | |
5377 | { | ||
5378 | ✗ | LOG_DEBUG("{}: referenceVectorConfigurationRegister.position.altitude changed to {}", nameId(), _referenceVectorConfigurationRegister.position[2]); | |
5379 | ✗ | flow::ApplyChanges(); | |
5380 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
5381 | { | ||
5382 | try | ||
5383 | { | ||
5384 | ✗ | _vs.writeReferenceVectorConfiguration(_referenceVectorConfigurationRegister); | |
5385 | } | ||
5386 | ✗ | catch (const std::exception& e) | |
5387 | { | ||
5388 | ✗ | LOG_ERROR("{}: Could not configure the referenceVectorConfigurationRegister: {}", nameId(), e.what()); | |
5389 | ✗ | doDeinitialize(); | |
5390 | ✗ | } | |
5391 | } | ||
5392 | else | ||
5393 | { | ||
5394 | ✗ | doDeinitialize(); | |
5395 | } | ||
5396 | } | ||
5397 | ✗ | ImGui::SameLine(); | |
5398 | ✗ | gui::widgets::HelpMarker("The reference altitude above the reference ellipsoid in meters."); | |
5399 | |||
5400 | ✗ | ImGui::TreePop(); | |
5401 | } | ||
5402 | } | ||
5403 | |||
5404 | // ########################################################################################################### | ||
5405 | // VELOCITY AIDING | ||
5406 | // ########################################################################################################### | ||
5407 | |||
5408 | ✗ | if (_sensorModel == VectorNavModel::VN100_VN110) | |
5409 | { | ||
5410 | ✗ | ImGui::SetNextItemOpen(true, ImGuiCond_FirstUseEver); | |
5411 | ✗ | if (ImGui::CollapsingHeader(fmt::format("Velocity Aiding##{}", size_t(id)).c_str())) | |
5412 | { | ||
5413 | ✗ | if (ImGui::TreeNode(fmt::format("Velocity Compensation Control##{}", size_t(id)).c_str())) | |
5414 | { | ||
5415 | ✗ | ImGui::TextUnformatted("Provides control over the velocity compensation feature for the attitude filter."); | |
5416 | |||
5417 | static constexpr std::array<vn::protocol::uart::VelocityCompensationMode, 2> velocityCompensationControlModes = { | ||
5418 | { vn::protocol::uart::VelocityCompensationMode::VELOCITYCOMPENSATIONMODE_DISABLED, | ||
5419 | vn::protocol::uart::VelocityCompensationMode::VELOCITYCOMPENSATIONMODE_BODYMEASUREMENT } | ||
5420 | }; | ||
5421 | ✗ | if (ImGui::BeginCombo(fmt::format("Mode##{}", size_t(id)).c_str(), vn::protocol::uart::str(_velocityCompensationControlRegister.mode).c_str())) | |
5422 | { | ||
5423 | ✗ | for (const auto& velocityCompensationControlMode : velocityCompensationControlModes) | |
5424 | { | ||
5425 | ✗ | const bool isSelected = (_velocityCompensationControlRegister.mode == velocityCompensationControlMode); | |
5426 | ✗ | if (ImGui::Selectable(vn::protocol::uart::str(velocityCompensationControlMode).c_str(), isSelected)) | |
5427 | { | ||
5428 | ✗ | _velocityCompensationControlRegister.mode = velocityCompensationControlMode; | |
5429 | ✗ | LOG_DEBUG("{}: velocityCompensationControlRegister.mode changed to {}", nameId(), vn::protocol::uart::str(_velocityCompensationControlRegister.mode)); | |
5430 | ✗ | flow::ApplyChanges(); | |
5431 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
5432 | { | ||
5433 | try | ||
5434 | { | ||
5435 | ✗ | _vs.writeVelocityCompensationControl(_velocityCompensationControlRegister); | |
5436 | } | ||
5437 | ✗ | catch (const std::exception& e) | |
5438 | { | ||
5439 | ✗ | LOG_ERROR("{}: Could not configure the velocityCompensationControlRegister: {}", nameId(), e.what()); | |
5440 | ✗ | doDeinitialize(); | |
5441 | ✗ | } | |
5442 | } | ||
5443 | else | ||
5444 | { | ||
5445 | ✗ | doDeinitialize(); | |
5446 | } | ||
5447 | } | ||
5448 | |||
5449 | ✗ | if (isSelected) // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) | |
5450 | { | ||
5451 | ✗ | ImGui::SetItemDefaultFocus(); | |
5452 | } | ||
5453 | } | ||
5454 | ✗ | ImGui::EndCombo(); | |
5455 | } | ||
5456 | ✗ | ImGui::SameLine(); | |
5457 | ✗ | gui::widgets::HelpMarker("Selects the type of velocity compensation performed by the VPE"); | |
5458 | |||
5459 | ✗ | if (ImGui::InputFloat(fmt::format("Velocity Tuning##{}", size_t(id)).c_str(), &_velocityCompensationControlRegister.velocityTuning)) | |
5460 | { | ||
5461 | ✗ | LOG_DEBUG("{}: velocityCompensationControlRegister.velocityTuning changed to {}", nameId(), _velocityCompensationControlRegister.velocityTuning); | |
5462 | ✗ | flow::ApplyChanges(); | |
5463 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
5464 | { | ||
5465 | try | ||
5466 | { | ||
5467 | ✗ | _vs.writeVelocityCompensationControl(_velocityCompensationControlRegister); | |
5468 | } | ||
5469 | ✗ | catch (const std::exception& e) | |
5470 | { | ||
5471 | ✗ | LOG_ERROR("{}: Could not configure the velocityCompensationControlRegister: {}", nameId(), e.what()); | |
5472 | ✗ | doDeinitialize(); | |
5473 | ✗ | } | |
5474 | } | ||
5475 | else | ||
5476 | { | ||
5477 | ✗ | doDeinitialize(); | |
5478 | } | ||
5479 | } | ||
5480 | ✗ | ImGui::SameLine(); | |
5481 | ✗ | gui::widgets::HelpMarker("Tuning parameter for the velocity measurement"); | |
5482 | |||
5483 | ✗ | if (ImGui::InputFloat(fmt::format("Rate Tuning##{}", size_t(id)).c_str(), &_velocityCompensationControlRegister.rateTuning)) | |
5484 | { | ||
5485 | ✗ | LOG_DEBUG("{}: velocityCompensationControlRegister.rateTuning changed to {}", nameId(), _velocityCompensationControlRegister.rateTuning); | |
5486 | ✗ | flow::ApplyChanges(); | |
5487 | ✗ | if (isInitialized() && _vs.isConnected() && _vs.verifySensorConnectivity()) | |
5488 | { | ||
5489 | try | ||
5490 | { | ||
5491 | ✗ | _vs.writeVelocityCompensationControl(_velocityCompensationControlRegister); | |
5492 | } | ||
5493 | ✗ | catch (const std::exception& e) | |
5494 | { | ||
5495 | ✗ | LOG_ERROR("{}: Could not configure the velocityCompensationControlRegister: {}", nameId(), e.what()); | |
5496 | ✗ | doDeinitialize(); | |
5497 | ✗ | } | |
5498 | } | ||
5499 | else | ||
5500 | { | ||
5501 | ✗ | doDeinitialize(); | |
5502 | } | ||
5503 | } | ||
5504 | ✗ | ImGui::SameLine(); | |
5505 | ✗ | gui::widgets::HelpMarker("Tuning parameter for the angular rate measurement"); | |
5506 | |||
5507 | ✗ | ImGui::TreePop(); | |
5508 | } | ||
5509 | } | ||
5510 | } | ||
5511 | ✗ | } | |
5512 | |||
5513 | ✗ | [[nodiscard]] json NAV::VectorNavSensor::save() const | |
5514 | { | ||
5515 | LOG_TRACE("{}: called", nameId()); | ||
5516 | |||
5517 | ✗ | json j; | |
5518 | |||
5519 | ✗ | j["UartSensor"] = UartSensor::save(); | |
5520 | ✗ | j["sensorModel"] = _sensorModel; | |
5521 | |||
5522 | // ########################################################################################################### | ||
5523 | // SYSTEM MODULE | ||
5524 | // ########################################################################################################### | ||
5525 | |||
5526 | ✗ | j["asyncDataOutputType"] = _asyncDataOutputType; | |
5527 | ✗ | j["asyncDataOutputFrequency"] = _asyncDataOutputFrequency; | |
5528 | ✗ | j["asciiOutputBufferSize"] = _asciiOutputBufferSize; | |
5529 | ✗ | j["syncInPin"] = _syncInPin; | |
5530 | ✗ | j["synchronizationControlRegister"] = _synchronizationControlRegister; | |
5531 | ✗ | j["communicationProtocolControlRegister"] = _communicationProtocolControlRegister; | |
5532 | ✗ | j["binaryOutputRegisterMerge"] = _binaryOutputRegisterMerge; | |
5533 | ✗ | for (size_t b = 0; b < 3; b++) | |
5534 | { | ||
5535 | ✗ | j[fmt::format("binaryOutputRegister{}", b + 1)] = _binaryOutputRegister.at(b); | |
5536 | ✗ | j[fmt::format("binaryOutputRegister{}-Frequency", b + 1)] = _dividerFrequency.second.at(static_cast<size_t>(_binaryOutputSelectedFrequency.at(b))); | |
5537 | } | ||
5538 | |||
5539 | // ########################################################################################################### | ||
5540 | // IMU SUBSYSTEM | ||
5541 | // ########################################################################################################### | ||
5542 | |||
5543 | ✗ | j["referenceFrameRotationMatrix"] = _referenceFrameRotationMatrix; | |
5544 | ✗ | j["imuFilteringConfigurationRegister"] = _imuFilteringConfigurationRegister; | |
5545 | ✗ | j["deltaThetaAndDeltaVelocityConfigurationRegister"] = _deltaThetaAndDeltaVelocityConfigurationRegister; | |
5546 | ✗ | j["coupleImuRateOutput"] = _coupleImuRateOutput; | |
5547 | |||
5548 | // ########################################################################################################### | ||
5549 | // GNSS SUBSYSTEM | ||
5550 | // ########################################################################################################### | ||
5551 | |||
5552 | ✗ | j["gpsConfigurationRegister"] = _gpsConfigurationRegister; | |
5553 | ✗ | j["gpsAntennaOffset"] = _gpsAntennaOffset; | |
5554 | ✗ | j["gpsCompassBaselineRegister"] = _gpsCompassBaselineRegister; | |
5555 | |||
5556 | // ########################################################################################################### | ||
5557 | // ATTITUDE SUBSYSTEM | ||
5558 | // ########################################################################################################### | ||
5559 | |||
5560 | ✗ | j["vpeBasicControlRegister"] = _vpeBasicControlRegister; | |
5561 | ✗ | j["vpeMagnetometerBasicTuningRegister"] = _vpeMagnetometerBasicTuningRegister; | |
5562 | ✗ | j["vpeAccelerometerBasicTuningRegister"] = _vpeAccelerometerBasicTuningRegister; | |
5563 | ✗ | j["vpeGyroBasicTuningRegister"] = _vpeGyroBasicTuningRegister; | |
5564 | ✗ | j["filterStartupGyroBias"] = _filterStartupGyroBias; | |
5565 | |||
5566 | // ########################################################################################################### | ||
5567 | // INS SUBSYSTEM | ||
5568 | // ########################################################################################################### | ||
5569 | |||
5570 | ✗ | j["insBasicConfigurationRegisterVn300"] = _insBasicConfigurationRegisterVn300; | |
5571 | ✗ | j["startupFilterBiasEstimateRegister"] = _startupFilterBiasEstimateRegister; | |
5572 | |||
5573 | // ########################################################################################################### | ||
5574 | // HARD/SOFT IRON ESTIMATOR SUBSYSTEM | ||
5575 | // ########################################################################################################### | ||
5576 | |||
5577 | ✗ | j["magnetometerCalibrationControlRegister"] = _magnetometerCalibrationControlRegister; | |
5578 | |||
5579 | // ########################################################################################################### | ||
5580 | // WORLD MAGNETIC & GRAVITY MODULE | ||
5581 | // ########################################################################################################### | ||
5582 | |||
5583 | ✗ | j["magneticAndGravityReferenceVectorsRegister"] = _magneticAndGravityReferenceVectorsRegister; | |
5584 | ✗ | j["referenceVectorConfigurationRegister"] = _referenceVectorConfigurationRegister; | |
5585 | |||
5586 | // ########################################################################################################### | ||
5587 | // VELOCITY AIDING | ||
5588 | // ########################################################################################################### | ||
5589 | |||
5590 | ✗ | j["velocityCompensationControlRegister"] = _velocityCompensationControlRegister; | |
5591 | |||
5592 | ✗ | return j; | |
5593 | ✗ | } | |
5594 | |||
5595 | ✗ | void NAV::VectorNavSensor::restore(json const& j) | |
5596 | { | ||
5597 | LOG_TRACE("{}: called", nameId()); | ||
5598 | |||
5599 | ✗ | if (j.contains("UartSensor")) | |
5600 | { | ||
5601 | ✗ | UartSensor::restore(j.at("UartSensor")); | |
5602 | } | ||
5603 | ✗ | if (j.contains("sensorModel")) | |
5604 | { | ||
5605 | ✗ | j.at("sensorModel").get_to(_sensorModel); | |
5606 | } | ||
5607 | |||
5608 | // ########################################################################################################### | ||
5609 | // SYSTEM MODULE | ||
5610 | // ########################################################################################################### | ||
5611 | |||
5612 | ✗ | if (j.contains("asyncDataOutputType")) | |
5613 | { | ||
5614 | ✗ | j.at("asyncDataOutputType").get_to(_asyncDataOutputType); | |
5615 | } | ||
5616 | ✗ | if (j.contains("asyncDataOutputFrequency")) | |
5617 | { | ||
5618 | ✗ | j.at("asyncDataOutputFrequency").get_to(_asyncDataOutputFrequency); | |
5619 | ✗ | _asyncDataOutputFrequencySelected = static_cast<int>(std::ranges::find(_possibleAsyncDataOutputFrequency, static_cast<int>(_asyncDataOutputFrequency)) | |
5620 | ✗ | - _possibleAsyncDataOutputFrequency.begin()); | |
5621 | } | ||
5622 | ✗ | if (j.contains("asciiOutputBufferSize")) | |
5623 | { | ||
5624 | ✗ | j.at("asciiOutputBufferSize").get_to(_asciiOutputBufferSize); | |
5625 | ✗ | _asciiOutputBuffer.resize(static_cast<size_t>(_asciiOutputBufferSize)); | |
5626 | } | ||
5627 | ✗ | if (j.contains("syncInPin")) | |
5628 | { | ||
5629 | ✗ | j.at("syncInPin").get_to(_syncInPin); | |
5630 | ✗ | if (_syncInPin && inputPins.empty()) | |
5631 | { | ||
5632 | ✗ | nm::CreateInputPin(this, "SyncIn", Pin::Type::Object, { "TimeSync" }); | |
5633 | } | ||
5634 | } | ||
5635 | ✗ | if (j.contains("synchronizationControlRegister")) | |
5636 | { | ||
5637 | ✗ | j.at("synchronizationControlRegister").get_to(_synchronizationControlRegister); | |
5638 | ✗ | if (_synchronizationControlRegister.syncOutMode == vn::protocol::uart::SyncOutMode::SYNCOUTMODE_GPSPPS | |
5639 | ✗ | && outputPins.size() <= 4) | |
5640 | { | ||
5641 | ✗ | nm::CreateOutputPin(this, "SyncOut", Pin::Type::Object, { "TimeSync" }, &_timeSyncOut); | |
5642 | } | ||
5643 | } | ||
5644 | ✗ | if (j.contains("communicationProtocolControlRegister")) | |
5645 | { | ||
5646 | ✗ | j.at("communicationProtocolControlRegister").get_to(_communicationProtocolControlRegister); | |
5647 | } | ||
5648 | ✗ | if (j.contains("binaryOutputRegisterMerge")) | |
5649 | { | ||
5650 | ✗ | j.at("binaryOutputRegisterMerge").get_to(_binaryOutputRegisterMerge); | |
5651 | ✗ | if (_binaryOutputRegisterMerge == BinaryRegisterMerge::Output1_Output2) | |
5652 | { | ||
5653 | ✗ | outputPins.at(1).type = Pin::Type::Flow; | |
5654 | ✗ | outputPins.at(2).type = Pin::Type::None; | |
5655 | ✗ | outputPins.at(3).type = Pin::Type::Flow; | |
5656 | } | ||
5657 | ✗ | else if (_binaryOutputRegisterMerge == BinaryRegisterMerge::Output1_Output3 | |
5658 | ✗ | || _binaryOutputRegisterMerge == BinaryRegisterMerge::Output2_Output3) | |
5659 | { | ||
5660 | ✗ | outputPins.at(1).type = Pin::Type::Flow; | |
5661 | ✗ | outputPins.at(2).type = Pin::Type::Flow; | |
5662 | ✗ | outputPins.at(3).type = Pin::Type::None; | |
5663 | } | ||
5664 | } | ||
5665 | ✗ | for (size_t b = 0; b < 3; b++) | |
5666 | { | ||
5667 | ✗ | if (j.contains(fmt::format("binaryOutputRegister{}", b + 1))) | |
5668 | { | ||
5669 | ✗ | j.at(fmt::format("binaryOutputRegister{}", b + 1)).get_to(_binaryOutputRegister.at(b)); | |
5670 | } | ||
5671 | ✗ | if (j.contains(fmt::format("binaryOutputRegister{}-Frequency", b + 1))) | |
5672 | { | ||
5673 | ✗ | std::string frequency; | |
5674 | ✗ | j.at(fmt::format("binaryOutputRegister{}-Frequency", b + 1)).get_to(frequency); | |
5675 | ✗ | for (size_t i = 0; i < _dividerFrequency.second.size(); i++) | |
5676 | { | ||
5677 | ✗ | if (_dividerFrequency.second.at(i) == frequency) | |
5678 | { | ||
5679 | ✗ | _binaryOutputSelectedFrequency.at(b) = i; | |
5680 | ✗ | break; | |
5681 | } | ||
5682 | } | ||
5683 | ✗ | } | |
5684 | } | ||
5685 | |||
5686 | // ########################################################################################################### | ||
5687 | // IMU SUBSYSTEM | ||
5688 | // ########################################################################################################### | ||
5689 | |||
5690 | ✗ | if (j.contains("referenceFrameRotationMatrix")) | |
5691 | { | ||
5692 | ✗ | j.at("referenceFrameRotationMatrix").get_to(_referenceFrameRotationMatrix); | |
5693 | } | ||
5694 | ✗ | if (j.contains("imuFilteringConfigurationRegister")) | |
5695 | { | ||
5696 | ✗ | j.at("imuFilteringConfigurationRegister").get_to(_imuFilteringConfigurationRegister); | |
5697 | } | ||
5698 | ✗ | if (j.contains("deltaThetaAndDeltaVelocityConfigurationRegister")) | |
5699 | { | ||
5700 | ✗ | j.at("deltaThetaAndDeltaVelocityConfigurationRegister").get_to(_deltaThetaAndDeltaVelocityConfigurationRegister); | |
5701 | } | ||
5702 | ✗ | if (j.contains("coupleImuRateOutput")) | |
5703 | { | ||
5704 | ✗ | j.at("coupleImuRateOutput").get_to(_coupleImuRateOutput); | |
5705 | } | ||
5706 | |||
5707 | // ########################################################################################################### | ||
5708 | // GNSS SUBSYSTEM | ||
5709 | // ########################################################################################################### | ||
5710 | |||
5711 | ✗ | if (j.contains("gpsConfigurationRegister")) | |
5712 | { | ||
5713 | ✗ | j.at("gpsConfigurationRegister").get_to(_gpsConfigurationRegister); | |
5714 | } | ||
5715 | ✗ | if (j.contains("gpsAntennaOffset")) | |
5716 | { | ||
5717 | ✗ | j.at("gpsAntennaOffset").get_to(_gpsAntennaOffset); | |
5718 | } | ||
5719 | ✗ | if (j.contains("gpsCompassBaselineRegister")) | |
5720 | { | ||
5721 | ✗ | j.at("gpsCompassBaselineRegister").get_to(_gpsCompassBaselineRegister); | |
5722 | } | ||
5723 | |||
5724 | // ########################################################################################################### | ||
5725 | // ATTITUDE SUBSYSTEM | ||
5726 | // ########################################################################################################### | ||
5727 | |||
5728 | ✗ | if (j.contains("vpeBasicControlRegister")) | |
5729 | { | ||
5730 | ✗ | j.at("vpeBasicControlRegister").get_to(_vpeBasicControlRegister); | |
5731 | } | ||
5732 | ✗ | if (j.contains("vpeMagnetometerBasicTuningRegister")) | |
5733 | { | ||
5734 | ✗ | j.at("vpeMagnetometerBasicTuningRegister").get_to(_vpeMagnetometerBasicTuningRegister); | |
5735 | } | ||
5736 | ✗ | if (j.contains("vpeAccelerometerBasicTuningRegister")) | |
5737 | { | ||
5738 | ✗ | j.at("vpeAccelerometerBasicTuningRegister").get_to(_vpeAccelerometerBasicTuningRegister); | |
5739 | } | ||
5740 | ✗ | if (j.contains("vpeGyroBasicTuningRegister")) | |
5741 | { | ||
5742 | ✗ | j.at("vpeGyroBasicTuningRegister").get_to(_vpeGyroBasicTuningRegister); | |
5743 | } | ||
5744 | ✗ | if (j.contains("filterStartupGyroBias")) | |
5745 | { | ||
5746 | ✗ | j.at("filterStartupGyroBias").get_to(_filterStartupGyroBias); | |
5747 | } | ||
5748 | |||
5749 | // ########################################################################################################### | ||
5750 | // INS SUBSYSTEM | ||
5751 | // ########################################################################################################### | ||
5752 | |||
5753 | ✗ | if (j.contains("insBasicConfigurationRegisterVn300")) | |
5754 | { | ||
5755 | ✗ | j.at("insBasicConfigurationRegisterVn300").get_to(_insBasicConfigurationRegisterVn300); | |
5756 | } | ||
5757 | ✗ | if (j.contains("startupFilterBiasEstimateRegister")) | |
5758 | { | ||
5759 | ✗ | j.at("startupFilterBiasEstimateRegister").get_to(_startupFilterBiasEstimateRegister); | |
5760 | } | ||
5761 | |||
5762 | // ########################################################################################################### | ||
5763 | // HARD/SOFT IRON ESTIMATOR SUBSYSTEM | ||
5764 | // ########################################################################################################### | ||
5765 | |||
5766 | ✗ | if (j.contains("magnetometerCalibrationControlRegister")) | |
5767 | { | ||
5768 | ✗ | j.at("magnetometerCalibrationControlRegister").get_to(_magnetometerCalibrationControlRegister); | |
5769 | } | ||
5770 | |||
5771 | // ########################################################################################################### | ||
5772 | // WORLD MAGNETIC & GRAVITY MODULE | ||
5773 | // ########################################################################################################### | ||
5774 | |||
5775 | ✗ | if (j.contains("magneticAndGravityReferenceVectorsRegister")) | |
5776 | { | ||
5777 | ✗ | j.at("magneticAndGravityReferenceVectorsRegister").get_to(_magneticAndGravityReferenceVectorsRegister); | |
5778 | } | ||
5779 | ✗ | if (j.contains("referenceVectorConfigurationRegister")) | |
5780 | { | ||
5781 | ✗ | j.at("referenceVectorConfigurationRegister").get_to(_referenceVectorConfigurationRegister); | |
5782 | } | ||
5783 | |||
5784 | // ########################################################################################################### | ||
5785 | // VELOCITY AIDING | ||
5786 | // ########################################################################################################### | ||
5787 | |||
5788 | ✗ | if (j.contains("velocityCompensationControlRegister")) | |
5789 | { | ||
5790 | ✗ | j.at("velocityCompensationControlRegister").get_to(_velocityCompensationControlRegister); | |
5791 | } | ||
5792 | ✗ | } | |
5793 | |||
5794 | ✗ | bool NAV::VectorNavSensor::resetNode() | |
5795 | { | ||
5796 | ✗ | std::ranges::for_each(_lastMessageTime, [](InsTime& insTime) { insTime.reset(); }); | |
5797 | ✗ | std::ranges::for_each(_lastMessageTimeSinceStartup, [](uint64_t& value) { value = 0; }); | |
5798 | ✗ | _gnssTimeCounter = {}; | |
5799 | |||
5800 | ✗ | _timeSyncOut.ppsTime.reset(); | |
5801 | ✗ | _timeSyncOut.syncOutCnt = 0; | |
5802 | ✗ | _binaryOutputRegisterMergeObservation = nullptr; | |
5803 | |||
5804 | ✗ | return true; | |
5805 | } | ||
5806 | |||
5807 | ✗ | bool NAV::VectorNavSensor::initialize() | |
5808 | { | ||
5809 | LOG_TRACE("{}: called", nameId()); | ||
5810 | |||
5811 | // Some settings need to be wrote to the device and reset afterwards | ||
5812 | ✗ | bool deviceNeedsResetAfterInitialization = false; | |
5813 | |||
5814 | // ########################################################################################################### | ||
5815 | // Connecting | ||
5816 | // ########################################################################################################### | ||
5817 | |||
5818 | // Choose baudrate | ||
5819 | ✗ | Baudrate targetBaudrate = sensorBaudrate() == BAUDRATE_FASTEST | |
5820 | ✗ | ? static_cast<Baudrate>(vn::sensors::VnSensor::supportedBaudrates()[vn::sensors::VnSensor::supportedBaudrates().size() - 1]) | |
5821 | ✗ | : sensorBaudrate(); | |
5822 | |||
5823 | ✗ | Baudrate connectedBaudrate{}; | |
5824 | ✗ | _connectedSensorPort.clear(); | |
5825 | |||
5826 | // Search for the VectorNav Sensor | ||
5827 | ✗ | size_t maxTries = std::filesystem::exists(_sensorPort) ? 5 : 0; | |
5828 | ✗ | for (size_t i = 0; i < maxTries; ++i) | |
5829 | { | ||
5830 | ✗ | if (int32_t foundBaudrate = 0; | |
5831 | ✗ | vn::sensors::Searcher::search(_sensorPort, &foundBaudrate)) | |
5832 | { | ||
5833 | // Sensor was found at specified port with the baudrate 'foundBaudrate' | ||
5834 | ✗ | connectedBaudrate = static_cast<Baudrate>(foundBaudrate); | |
5835 | ✗ | _connectedSensorPort = _sensorPort; | |
5836 | ✗ | LOG_DEBUG("{}: Found VectorNav sensor on specified port '{}' with baudrate {} (it took {} attempts to connect)", | |
5837 | nameId(), _connectedSensorPort, foundBaudrate, i + 1); | ||
5838 | ✗ | break; | |
5839 | } | ||
5840 | } | ||
5841 | ✗ | if (_connectedSensorPort.empty()) | |
5842 | { | ||
5843 | ✗ | if (std::filesystem::exists(_sensorPort)) | |
5844 | { | ||
5845 | ✗ | LOG_ERROR("{}: Could not connect to VectorNav sensor on specified port '{}', but port exists.", nameId(), _sensorPort); | |
5846 | ✗ | return false; | |
5847 | } | ||
5848 | |||
5849 | ✗ | for (size_t i = 0; i < 5; ++i) | |
5850 | { | ||
5851 | ✗ | if (!_connectedSensorPort.empty()) | |
5852 | { | ||
5853 | ✗ | break; | |
5854 | } | ||
5855 | |||
5856 | ✗ | if (std::vector<std::pair<std::string, uint32_t>> foundSensors = vn::sensors::Searcher::search(); | |
5857 | ✗ | !foundSensors.empty()) | |
5858 | { | ||
5859 | ✗ | for (const auto& [port, baudrate] : foundSensors) | |
5860 | { | ||
5861 | ✗ | _vs.connect(port, baudrate); | |
5862 | ✗ | std::string modelNumber = _vs.readModelNumber(); | |
5863 | ✗ | _vs.disconnect(); | |
5864 | |||
5865 | ✗ | LOG_DEBUG("{}: Found VectorNav sensor '{}' on port '{}' with baudrate {} ({} VN sensors connected in total)", | |
5866 | nameId(), modelNumber, port, baudrate, foundSensors.size()); | ||
5867 | |||
5868 | // Identify the sensor by its model number | ||
5869 | ✗ | const std::string searchString = _sensorModel == VectorNavModel::VN100_VN110 ? "VN-1" : "VN-3"; | |
5870 | ✗ | if (modelNumber.find(searchString) != std::string::npos) | |
5871 | { | ||
5872 | ✗ | _connectedSensorPort = port; | |
5873 | ✗ | connectedBaudrate = static_cast<Baudrate>(baudrate); | |
5874 | |||
5875 | ✗ | LOG_DEBUG("{}: Selected VectorNav sensor '{}' on port '{}' (it took {} attempts to connect)", | |
5876 | nameId(), modelNumber, port, i + 1); | ||
5877 | ✗ | break; | |
5878 | } | ||
5879 | ✗ | } | |
5880 | ✗ | } | |
5881 | } | ||
5882 | ✗ | if (_connectedSensorPort.empty()) | |
5883 | { | ||
5884 | ✗ | LOG_ERROR("{}: Could not connect. Is the sensor connected and do you have read permissions?", nameId()); | |
5885 | ✗ | return false; | |
5886 | } | ||
5887 | } | ||
5888 | |||
5889 | try | ||
5890 | { | ||
5891 | // Connect to the sensor (vs.verifySensorConnectivity does not have to be called as sensor is already tested) | ||
5892 | ✗ | _vs.connect(_connectedSensorPort, connectedBaudrate); | |
5893 | } | ||
5894 | ✗ | catch (const std::exception& e) | |
5895 | { | ||
5896 | ✗ | LOG_ERROR("{}: Failed to connect to sensor on port '{}' with baudrate {} with error: {}", nameId(), | |
5897 | _connectedSensorPort, connectedBaudrate, e.what()); | ||
5898 | ✗ | return false; | |
5899 | ✗ | } | |
5900 | |||
5901 | try | ||
5902 | { | ||
5903 | ✗ | if (!_vs.verifySensorConnectivity()) | |
5904 | { | ||
5905 | ✗ | LOG_ERROR("{}: Connected to sensor on port '{}' with baudrate {} but sensor does not answer", nameId(), | |
5906 | _connectedSensorPort, connectedBaudrate); | ||
5907 | ✗ | return false; | |
5908 | } | ||
5909 | } | ||
5910 | ✗ | catch (const std::exception& e) | |
5911 | { | ||
5912 | ✗ | LOG_ERROR("{}: Connected to sensor on port '{}' with baudrate {} but sensor threw an exception: {}", nameId(), | |
5913 | _connectedSensorPort, connectedBaudrate, e.what()); | ||
5914 | ✗ | return false; | |
5915 | ✗ | } | |
5916 | |||
5917 | // Query the sensor's model number | ||
5918 | ✗ | auto modelNumber = _vs.readModelNumber(); | |
5919 | ✗ | LOG_DEBUG("{}: {} connected on port '{}' with baudrate {}", nameId(), _vs.readModelNumber(), _connectedSensorPort, connectedBaudrate); | |
5920 | |||
5921 | ✗ | if (_sensorModel == VectorNavModel::VN100_VN110 && (!modelNumber.starts_with("VN-100") && !modelNumber.starts_with("VN-110"))) | |
5922 | { | ||
5923 | ✗ | LOG_ERROR("{}: VN100/VN110 configured, but sensor identifies as {}", nameId(), modelNumber); | |
5924 | ✗ | doDeinitialize(); | |
5925 | ✗ | return false; | |
5926 | } | ||
5927 | ✗ | if (_sensorModel == VectorNavModel::VN310 && !modelNumber.starts_with("VN-310")) | |
5928 | { | ||
5929 | ✗ | LOG_ERROR("{}: VN310 configured, but sensor identifies as {}", nameId(), modelNumber); | |
5930 | ✗ | doDeinitialize(); | |
5931 | ✗ | return false; | |
5932 | } | ||
5933 | |||
5934 | // ########################################################################################################### | ||
5935 | // SYSTEM MODULE | ||
5936 | // ########################################################################################################### | ||
5937 | |||
5938 | // Change Connection Baudrate | ||
5939 | ✗ | if (targetBaudrate != connectedBaudrate) | |
5940 | { | ||
5941 | ✗ | auto suppBaud = vn::sensors::VnSensor::supportedBaudrates(); | |
5942 | ✗ | if (std::ranges::find(suppBaud, targetBaudrate) != suppBaud.end()) | |
5943 | { | ||
5944 | ✗ | _vs.changeBaudRate(targetBaudrate); | |
5945 | ✗ | LOG_DEBUG("{}: Baudrate changed to {}", nameId(), static_cast<size_t>(targetBaudrate)); | |
5946 | } | ||
5947 | else | ||
5948 | { | ||
5949 | ✗ | LOG_ERROR("{}: Does not support baudrate {}", nameId(), static_cast<size_t>(targetBaudrate)); | |
5950 | ✗ | return false; | |
5951 | } | ||
5952 | ✗ | } | |
5953 | ✗ | if (_vs.readSerialBaudRate() != targetBaudrate) | |
5954 | { | ||
5955 | ✗ | LOG_ERROR("{}: Changing the baudrate from {} to {} was not successfull", nameId(), _vs.readSerialBaudRate(), targetBaudrate); | |
5956 | ✗ | doDeinitialize(); | |
5957 | ✗ | return false; | |
5958 | } | ||
5959 | |||
5960 | ✗ | _vs.writeSynchronizationControl(_synchronizationControlRegister); | |
5961 | ✗ | if (auto vnSynchronizationControlRegister = _vs.readSynchronizationControl(); | |
5962 | ✗ | vnSynchronizationControlRegister.syncInMode != _synchronizationControlRegister.syncInMode | |
5963 | ✗ | || vnSynchronizationControlRegister.syncInEdge != _synchronizationControlRegister.syncInEdge | |
5964 | ✗ | || vnSynchronizationControlRegister.syncInSkipFactor != _synchronizationControlRegister.syncInSkipFactor | |
5965 | ✗ | || vnSynchronizationControlRegister.syncOutMode != _synchronizationControlRegister.syncOutMode | |
5966 | ✗ | || vnSynchronizationControlRegister.syncOutPolarity != _synchronizationControlRegister.syncOutPolarity | |
5967 | ✗ | || vnSynchronizationControlRegister.syncOutSkipFactor != _synchronizationControlRegister.syncOutSkipFactor | |
5968 | ✗ | || vnSynchronizationControlRegister.syncOutPulseWidth != _synchronizationControlRegister.syncOutPulseWidth) | |
5969 | { | ||
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 = {}", | ||
5973 | nameId(), | ||
5974 | _synchronizationControlRegister.syncInMode, _synchronizationControlRegister.syncInEdge, _synchronizationControlRegister.syncInSkipFactor, _synchronizationControlRegister.syncOutMode, _synchronizationControlRegister.syncOutPolarity, _synchronizationControlRegister.syncOutSkipFactor, _synchronizationControlRegister.syncOutPulseWidth, | ||
5975 | vnSynchronizationControlRegister.syncInMode, vnSynchronizationControlRegister.syncInEdge, vnSynchronizationControlRegister.syncInSkipFactor, vnSynchronizationControlRegister.syncOutMode, vnSynchronizationControlRegister.syncOutPolarity, vnSynchronizationControlRegister.syncOutSkipFactor, vnSynchronizationControlRegister.syncOutPulseWidth); | ||
5976 | ✗ | doDeinitialize(); | |
5977 | ✗ | return false; | |
5978 | } | ||
5979 | |||
5980 | ✗ | _vs.writeCommunicationProtocolControl(_communicationProtocolControlRegister); | |
5981 | ✗ | if (auto vnCommunicationProtocolControlRegister = _vs.readCommunicationProtocolControl(); | |
5982 | ✗ | vnCommunicationProtocolControlRegister.serialCount != _communicationProtocolControlRegister.serialCount | |
5983 | ✗ | || vnCommunicationProtocolControlRegister.serialStatus != _communicationProtocolControlRegister.serialStatus | |
5984 | ✗ | || vnCommunicationProtocolControlRegister.spiCount != _communicationProtocolControlRegister.spiCount | |
5985 | ✗ | || vnCommunicationProtocolControlRegister.spiStatus != _communicationProtocolControlRegister.spiStatus | |
5986 | ✗ | || vnCommunicationProtocolControlRegister.serialChecksum != _communicationProtocolControlRegister.serialChecksum | |
5987 | ✗ | || vnCommunicationProtocolControlRegister.spiChecksum != _communicationProtocolControlRegister.spiChecksum | |
5988 | ✗ | || vnCommunicationProtocolControlRegister.errorMode != _communicationProtocolControlRegister.errorMode) | |
5989 | { | ||
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 = {}", | ||
5993 | nameId(), | ||
5994 | _communicationProtocolControlRegister.serialCount, _communicationProtocolControlRegister.serialStatus, _communicationProtocolControlRegister.spiCount, _communicationProtocolControlRegister.spiStatus, _communicationProtocolControlRegister.serialChecksum, _communicationProtocolControlRegister.spiChecksum, _communicationProtocolControlRegister.errorMode, | ||
5995 | vnCommunicationProtocolControlRegister.serialCount, vnCommunicationProtocolControlRegister.serialStatus, vnCommunicationProtocolControlRegister.spiCount, vnCommunicationProtocolControlRegister.spiStatus, vnCommunicationProtocolControlRegister.serialChecksum, vnCommunicationProtocolControlRegister.spiChecksum, vnCommunicationProtocolControlRegister.errorMode); | ||
5996 | ✗ | doDeinitialize(); | |
5997 | ✗ | return false; | |
5998 | } | ||
5999 | |||
6000 | // _vs.writeSynchronizationStatus(vn::sensors::SynchronizationStatusRegister); // User manual VN-310 - 8.3.1 (p 105) / VN-100 - 5.3.1 (p 76) | ||
6001 | |||
6002 | // ########################################################################################################### | ||
6003 | // IMU SUBSYSTEM | ||
6004 | // ########################################################################################################### | ||
6005 | |||
6006 | // _vs.writeMagnetometerCompensation(vn::sensors::MagnetometerCompensationRegister()); // User manual VN-310 - 9.2.1 (p 111) / VN-100 - 6.2.1 (p 82) | ||
6007 | // _vs.writeAccelerationCompensation(vn::sensors::AccelerationCompensationRegister()); // User manual VN-310 - 9.2.2 (p 112) / VN-100 - 6.2.2 (p 83) | ||
6008 | // _vs.writeGyroCompensation(vn::sensors::GyroCompensationRegister()); // User manual VN-310 - 9.2.3 (p 113) / VN-100 - 6.2.3 (p 84) | ||
6009 | |||
6010 | ✗ | auto vnReferenceFrameRotationMatrix = _vs.readReferenceFrameRotation(); | |
6011 | ✗ | if (vnReferenceFrameRotationMatrix != _referenceFrameRotationMatrix) | |
6012 | { | ||
6013 | ✗ | deviceNeedsResetAfterInitialization = true; | |
6014 | } | ||
6015 | |||
6016 | ✗ | _vs.writeReferenceFrameRotation(_referenceFrameRotationMatrix); | |
6017 | ✗ | if (vnReferenceFrameRotationMatrix = _vs.readReferenceFrameRotation(); | |
6018 | ✗ | vnReferenceFrameRotationMatrix != _referenceFrameRotationMatrix) | |
6019 | { | ||
6020 | ✗ | LOG_ERROR("{}: Writing the referenceFrameRotationMatrix was not successfull.\n" | |
6021 | "Target: DCM = {}\n" | ||
6022 | "Sensor: DCM = {}", | ||
6023 | nameId(), _referenceFrameRotationMatrix, vnReferenceFrameRotationMatrix); | ||
6024 | ✗ | doDeinitialize(); | |
6025 | ✗ | return false; | |
6026 | } | ||
6027 | |||
6028 | ✗ | _vs.writeImuFilteringConfiguration(_imuFilteringConfigurationRegister); | |
6029 | ✗ | if (auto vnImuFilteringConfigurationRegister = _vs.readImuFilteringConfiguration(); | |
6030 | ✗ | vnImuFilteringConfigurationRegister.magWindowSize != _imuFilteringConfigurationRegister.magWindowSize | |
6031 | ✗ | || vnImuFilteringConfigurationRegister.accelWindowSize != _imuFilteringConfigurationRegister.accelWindowSize | |
6032 | ✗ | || vnImuFilteringConfigurationRegister.gyroWindowSize != _imuFilteringConfigurationRegister.gyroWindowSize | |
6033 | ✗ | || vnImuFilteringConfigurationRegister.tempWindowSize != _imuFilteringConfigurationRegister.tempWindowSize | |
6034 | ✗ | || vnImuFilteringConfigurationRegister.presWindowSize != _imuFilteringConfigurationRegister.presWindowSize | |
6035 | ✗ | || vnImuFilteringConfigurationRegister.magFilterMode != _imuFilteringConfigurationRegister.magFilterMode | |
6036 | ✗ | || vnImuFilteringConfigurationRegister.accelFilterMode != _imuFilteringConfigurationRegister.accelFilterMode | |
6037 | ✗ | || vnImuFilteringConfigurationRegister.gyroFilterMode != _imuFilteringConfigurationRegister.gyroFilterMode | |
6038 | ✗ | || vnImuFilteringConfigurationRegister.tempFilterMode != _imuFilteringConfigurationRegister.tempFilterMode | |
6039 | ✗ | || vnImuFilteringConfigurationRegister.presFilterMode != _imuFilteringConfigurationRegister.presFilterMode) | |
6040 | { | ||
6041 | ✗ | LOG_ERROR("{}: Writing the imuFilteringConfigurationRegister was not successfull.\n" | |
6042 | "Target: magWindowSize = {}, accelWindowSize = {}, gyroWindowSize = {}, tempWindowSize = {}, presWindowSize = {}, magFilterMode = {}, accelFilterMode = {}, gyroFilterMode = {}, tempFilterMode = {}, presFilterMode = {}\n" | ||
6043 | "Sensor: magWindowSize = {}, accelWindowSize = {}, gyroWindowSize = {}, tempWindowSize = {}, presWindowSize = {}, magFilterMode = {}, accelFilterMode = {}, gyroFilterMode = {}, tempFilterMode = {}, presFilterMode = {}", | ||
6044 | nameId(), | ||
6045 | _imuFilteringConfigurationRegister.magWindowSize, _imuFilteringConfigurationRegister.accelWindowSize, _imuFilteringConfigurationRegister.gyroWindowSize, _imuFilteringConfigurationRegister.tempWindowSize, _imuFilteringConfigurationRegister.presWindowSize, _imuFilteringConfigurationRegister.magFilterMode, _imuFilteringConfigurationRegister.accelFilterMode, _imuFilteringConfigurationRegister.gyroFilterMode, _imuFilteringConfigurationRegister.tempFilterMode, _imuFilteringConfigurationRegister.presFilterMode, | ||
6046 | vnImuFilteringConfigurationRegister.magWindowSize, vnImuFilteringConfigurationRegister.accelWindowSize, vnImuFilteringConfigurationRegister.gyroWindowSize, vnImuFilteringConfigurationRegister.tempWindowSize, vnImuFilteringConfigurationRegister.presWindowSize, vnImuFilteringConfigurationRegister.magFilterMode, vnImuFilteringConfigurationRegister.accelFilterMode, vnImuFilteringConfigurationRegister.gyroFilterMode, vnImuFilteringConfigurationRegister.tempFilterMode, vnImuFilteringConfigurationRegister.presFilterMode); | ||
6047 | ✗ | doDeinitialize(); | |
6048 | ✗ | return false; | |
6049 | } | ||
6050 | |||
6051 | ✗ | _vs.writeDeltaThetaAndDeltaVelocityConfiguration(_deltaThetaAndDeltaVelocityConfigurationRegister); | |
6052 | ✗ | if (auto vnDeltaThetaAndDeltaVelocityConfigurationRegister = _vs.readDeltaThetaAndDeltaVelocityConfiguration(); | |
6053 | ✗ | vnDeltaThetaAndDeltaVelocityConfigurationRegister.integrationFrame != _deltaThetaAndDeltaVelocityConfigurationRegister.integrationFrame | |
6054 | ✗ | || vnDeltaThetaAndDeltaVelocityConfigurationRegister.gyroCompensation != _deltaThetaAndDeltaVelocityConfigurationRegister.gyroCompensation | |
6055 | ✗ | || vnDeltaThetaAndDeltaVelocityConfigurationRegister.accelCompensation != _deltaThetaAndDeltaVelocityConfigurationRegister.accelCompensation | |
6056 | ✗ | || vnDeltaThetaAndDeltaVelocityConfigurationRegister.earthRateCorrection != _deltaThetaAndDeltaVelocityConfigurationRegister.earthRateCorrection) | |
6057 | { | ||
6058 | ✗ | LOG_ERROR("{}: Writing the deltaThetaAndDeltaVelocityConfigurationRegister was not successfull.\n" | |
6059 | "Target: integrationFrame = {}, gyroCompensation = {}, accelCompensation = {}, earthRateCorrection = {}\n" | ||
6060 | "Sensor: integrationFrame = {}, gyroCompensation = {}, accelCompensation = {}, earthRateCorrection = {}", | ||
6061 | nameId(), | ||
6062 | _deltaThetaAndDeltaVelocityConfigurationRegister.integrationFrame, _deltaThetaAndDeltaVelocityConfigurationRegister.gyroCompensation, _deltaThetaAndDeltaVelocityConfigurationRegister.accelCompensation, _deltaThetaAndDeltaVelocityConfigurationRegister.earthRateCorrection, | ||
6063 | vnDeltaThetaAndDeltaVelocityConfigurationRegister.integrationFrame, vnDeltaThetaAndDeltaVelocityConfigurationRegister.gyroCompensation, vnDeltaThetaAndDeltaVelocityConfigurationRegister.accelCompensation, vnDeltaThetaAndDeltaVelocityConfigurationRegister.earthRateCorrection); | ||
6064 | ✗ | doDeinitialize(); | |
6065 | ✗ | return false; | |
6066 | } | ||
6067 | |||
6068 | // ########################################################################################################### | ||
6069 | // GNSS SUBSYSTEM | ||
6070 | // ########################################################################################################### | ||
6071 | |||
6072 | ✗ | if (_sensorModel == VectorNavModel::VN310) | |
6073 | { | ||
6074 | ✗ | _vs.writeGpsConfiguration(_gpsConfigurationRegister); | |
6075 | ✗ | if (auto vnGpsConfigurationRegister = _vs.readGpsConfiguration(); | |
6076 | ✗ | vnGpsConfigurationRegister.mode != _gpsConfigurationRegister.mode | |
6077 | ✗ | || vnGpsConfigurationRegister.ppsSource != _gpsConfigurationRegister.ppsSource | |
6078 | ✗ | || vnGpsConfigurationRegister.rate != _gpsConfigurationRegister.rate | |
6079 | ✗ | || vnGpsConfigurationRegister.antPow != _gpsConfigurationRegister.antPow) | |
6080 | { | ||
6081 | ✗ | LOG_ERROR("{}: Writing the gpsConfigurationRegister was not successfull.\n" | |
6082 | "Target: mode = {}, ppsSource = {}, rate = {}, antPow = {}\n" | ||
6083 | "Sensor: mode = {}, ppsSource = {}, rate = {}, antPow = {}", | ||
6084 | nameId(), | ||
6085 | _gpsConfigurationRegister.mode, _gpsConfigurationRegister.ppsSource, _gpsConfigurationRegister.rate, _gpsConfigurationRegister.antPow, | ||
6086 | vnGpsConfigurationRegister.mode, vnGpsConfigurationRegister.ppsSource, vnGpsConfigurationRegister.rate, vnGpsConfigurationRegister.antPow); | ||
6087 | ✗ | doDeinitialize(); | |
6088 | ✗ | return false; | |
6089 | } | ||
6090 | |||
6091 | ✗ | _vs.writeGpsAntennaOffset(_gpsAntennaOffset); | |
6092 | ✗ | if (auto vnGpsAntennaOffset = _vs.readGpsAntennaOffset(); | |
6093 | ✗ | vnGpsAntennaOffset != _gpsAntennaOffset) | |
6094 | { | ||
6095 | ✗ | LOG_ERROR("{}: Writing the gpsAntennaOffset was not successfull.\n" | |
6096 | "Target: {}\n" | ||
6097 | "Sensor: {}", | ||
6098 | nameId(), | ||
6099 | _gpsAntennaOffset, | ||
6100 | vnGpsAntennaOffset); | ||
6101 | ✗ | doDeinitialize(); | |
6102 | ✗ | return false; | |
6103 | } | ||
6104 | |||
6105 | ✗ | _vs.writeGpsCompassBaseline(_gpsCompassBaselineRegister); | |
6106 | ✗ | if (auto vnGpsCompassBaselineRegister = _vs.readGpsCompassBaseline(); | |
6107 | ✗ | vnGpsCompassBaselineRegister.position != _gpsCompassBaselineRegister.position | |
6108 | ✗ | || vnGpsCompassBaselineRegister.uncertainty != _gpsCompassBaselineRegister.uncertainty) | |
6109 | { | ||
6110 | ✗ | LOG_ERROR("{}: Writing the gpsCompassBaselineRegister was not successfull.\n" | |
6111 | "Target: position = {}, uncertainty = {}\n" | ||
6112 | "Sensor: position = {}, uncertainty = {}", | ||
6113 | nameId(), | ||
6114 | _gpsCompassBaselineRegister.position, _gpsCompassBaselineRegister.uncertainty, | ||
6115 | vnGpsCompassBaselineRegister.position, vnGpsCompassBaselineRegister.uncertainty); | ||
6116 | ✗ | doDeinitialize(); | |
6117 | ✗ | return false; | |
6118 | } | ||
6119 | } | ||
6120 | |||
6121 | // ########################################################################################################### | ||
6122 | // ATTITUDE SUBSYSTEM | ||
6123 | // ########################################################################################################### | ||
6124 | ✗ | if (_sensorModel == VectorNavModel::VN100_VN110) | |
6125 | { | ||
6126 | // _vs.tare(); // User manual VN-100 - 7.1.1 (p 92) | ||
6127 | // _vs.magneticDisturbancePresent(bool); // User manual VN-100 - 7.1.2 (p 92) | ||
6128 | // _vs.accelerationDisturbancePresent(true); // User manual VN-100 - 7.1.3 (p 92f) | ||
6129 | } | ||
6130 | // _vs.setGyroBias(); // User manual VN-310 - 11.1.1 (p 148) / VN-100 - 7.1.4 (p 93) | ||
6131 | |||
6132 | // TODO: Implement in vnproglib: _vs.setInitialHeading() - User manual VN-310 - 11.1.2 (p 148) | ||
6133 | |||
6134 | ✗ | _vs.writeVpeBasicControl(_vpeBasicControlRegister); | |
6135 | ✗ | if (auto vnVpeBasicControlRegister = _vs.readVpeBasicControl(); | |
6136 | ✗ | vnVpeBasicControlRegister.enable != _vpeBasicControlRegister.enable | |
6137 | ✗ | || vnVpeBasicControlRegister.headingMode != _vpeBasicControlRegister.headingMode | |
6138 | ✗ | || vnVpeBasicControlRegister.filteringMode != _vpeBasicControlRegister.filteringMode | |
6139 | ✗ | || vnVpeBasicControlRegister.tuningMode != _vpeBasicControlRegister.tuningMode) | |
6140 | { | ||
6141 | ✗ | LOG_ERROR("{}: Writing the vpeBasicControlRegister was not successfull.\n" | |
6142 | "Target: enable = {}, headingMode = {}, filteringMode = {}, tuningMode = {}\n" | ||
6143 | "Sensor: enable = {}, headingMode = {}, filteringMode = {}, tuningMode = {}", | ||
6144 | nameId(), | ||
6145 | _vpeBasicControlRegister.enable, _vpeBasicControlRegister.headingMode, _vpeBasicControlRegister.filteringMode, _vpeBasicControlRegister.tuningMode, | ||
6146 | vnVpeBasicControlRegister.enable, vnVpeBasicControlRegister.headingMode, vnVpeBasicControlRegister.filteringMode, vnVpeBasicControlRegister.tuningMode); | ||
6147 | ✗ | doDeinitialize(); | |
6148 | ✗ | return false; | |
6149 | } | ||
6150 | |||
6151 | ✗ | if (_sensorModel == VectorNavModel::VN100_VN110) | |
6152 | { | ||
6153 | ✗ | _vs.writeVpeMagnetometerBasicTuning(_vpeMagnetometerBasicTuningRegister); | |
6154 | ✗ | if (auto vnVpeMagnetometerBasicTuningRegister = _vs.readVpeMagnetometerBasicTuning(); | |
6155 | ✗ | vnVpeMagnetometerBasicTuningRegister.baseTuning != _vpeMagnetometerBasicTuningRegister.baseTuning | |
6156 | ✗ | || vnVpeMagnetometerBasicTuningRegister.adaptiveTuning != _vpeMagnetometerBasicTuningRegister.adaptiveTuning | |
6157 | ✗ | || vnVpeMagnetometerBasicTuningRegister.adaptiveFiltering != _vpeMagnetometerBasicTuningRegister.adaptiveFiltering) | |
6158 | { | ||
6159 | ✗ | LOG_ERROR("{}: Writing the vpeMagnetometerBasicTuningRegister was not successfull.\n" | |
6160 | "Target: baseTuning = {}, adaptiveTuning = {}, adaptiveFiltering = {}\n" | ||
6161 | "Sensor: baseTuning = {}, adaptiveTuning = {}, adaptiveFiltering = {}", | ||
6162 | nameId(), | ||
6163 | _vpeMagnetometerBasicTuningRegister.baseTuning, _vpeMagnetometerBasicTuningRegister.adaptiveTuning, _vpeMagnetometerBasicTuningRegister.adaptiveFiltering, | ||
6164 | vnVpeMagnetometerBasicTuningRegister.baseTuning, vnVpeMagnetometerBasicTuningRegister.adaptiveTuning, vnVpeMagnetometerBasicTuningRegister.adaptiveFiltering); | ||
6165 | ✗ | doDeinitialize(); | |
6166 | ✗ | return false; | |
6167 | } | ||
6168 | |||
6169 | ✗ | _vs.writeVpeAccelerometerBasicTuning(_vpeAccelerometerBasicTuningRegister); | |
6170 | ✗ | if (auto vnVpeAccelerometerBasicTuningRegister = _vs.readVpeAccelerometerBasicTuning(); | |
6171 | ✗ | vnVpeAccelerometerBasicTuningRegister.baseTuning != _vpeAccelerometerBasicTuningRegister.baseTuning | |
6172 | ✗ | || vnVpeAccelerometerBasicTuningRegister.adaptiveTuning != _vpeAccelerometerBasicTuningRegister.adaptiveTuning | |
6173 | ✗ | || vnVpeAccelerometerBasicTuningRegister.adaptiveFiltering != _vpeAccelerometerBasicTuningRegister.adaptiveFiltering) | |
6174 | { | ||
6175 | ✗ | LOG_ERROR("{}: Writing the vpeAccelerometerBasicTuningRegister was not successfull.\n" | |
6176 | "Target: baseTuning = {}, adaptiveTuning = {}, adaptiveFiltering = {}\n" | ||
6177 | "Sensor: baseTuning = {}, adaptiveTuning = {}, adaptiveFiltering = {}", | ||
6178 | nameId(), | ||
6179 | _vpeAccelerometerBasicTuningRegister.baseTuning, _vpeAccelerometerBasicTuningRegister.adaptiveTuning, _vpeAccelerometerBasicTuningRegister.adaptiveFiltering, | ||
6180 | vnVpeAccelerometerBasicTuningRegister.baseTuning, vnVpeAccelerometerBasicTuningRegister.adaptiveTuning, vnVpeAccelerometerBasicTuningRegister.adaptiveFiltering); | ||
6181 | ✗ | doDeinitialize(); | |
6182 | ✗ | return false; | |
6183 | } | ||
6184 | |||
6185 | ✗ | _vs.writeFilterStartupGyroBias(_filterStartupGyroBias); | |
6186 | ✗ | if (auto vnFilterStartupGyroBias = _vs.readFilterStartupGyroBias(); | |
6187 | ✗ | vnFilterStartupGyroBias != _filterStartupGyroBias) | |
6188 | { | ||
6189 | ✗ | LOG_ERROR("{}: Writing the filterStartupGyroBias was not successfull.\n" | |
6190 | "Target: {}\n" | ||
6191 | "Sensor: {}", | ||
6192 | nameId(), | ||
6193 | _filterStartupGyroBias, | ||
6194 | vnFilterStartupGyroBias); | ||
6195 | ✗ | doDeinitialize(); | |
6196 | ✗ | return false; | |
6197 | } | ||
6198 | |||
6199 | ✗ | _vs.writeVpeGyroBasicTuning(_vpeGyroBasicTuningRegister); | |
6200 | ✗ | if (auto vnVpeGyroBasicTuningRegister = _vs.readVpeGyroBasicTuning(); | |
6201 | ✗ | vnVpeGyroBasicTuningRegister.angularWalkVariance != _vpeGyroBasicTuningRegister.angularWalkVariance | |
6202 | ✗ | || vnVpeGyroBasicTuningRegister.baseTuning != _vpeGyroBasicTuningRegister.baseTuning | |
6203 | ✗ | || vnVpeGyroBasicTuningRegister.adaptiveTuning != _vpeGyroBasicTuningRegister.adaptiveTuning) | |
6204 | { | ||
6205 | ✗ | LOG_ERROR("{}: Writing the vpeGyroBasicTuningRegister was not successfull.\n" | |
6206 | "Target: angularWalkVariance = {}, baseTuning = {}, adaptiveTuning = {}\n" | ||
6207 | "Sensor: angularWalkVariance = {}, baseTuning = {}, adaptiveTuning = {}", | ||
6208 | nameId(), | ||
6209 | _vpeGyroBasicTuningRegister.angularWalkVariance, _vpeGyroBasicTuningRegister.baseTuning, _vpeGyroBasicTuningRegister.adaptiveTuning, | ||
6210 | vnVpeGyroBasicTuningRegister.angularWalkVariance, vnVpeGyroBasicTuningRegister.baseTuning, vnVpeGyroBasicTuningRegister.adaptiveTuning); | ||
6211 | ✗ | doDeinitialize(); | |
6212 | ✗ | return false; | |
6213 | } | ||
6214 | } | ||
6215 | |||
6216 | // ########################################################################################################### | ||
6217 | // INS SUBSYSTEM | ||
6218 | // ########################################################################################################### | ||
6219 | |||
6220 | ✗ | if (_sensorModel == VectorNavModel::VN310) | |
6221 | { | ||
6222 | ✗ | _vs.writeInsBasicConfigurationVn300(_insBasicConfigurationRegisterVn300); | |
6223 | ✗ | if (auto vnInsBasicConfigurationRegisterVn300 = _vs.readInsBasicConfigurationVn300(); | |
6224 | ✗ | vnInsBasicConfigurationRegisterVn300.scenario != _insBasicConfigurationRegisterVn300.scenario | |
6225 | ✗ | || vnInsBasicConfigurationRegisterVn300.ahrsAiding != _insBasicConfigurationRegisterVn300.ahrsAiding | |
6226 | ✗ | || vnInsBasicConfigurationRegisterVn300.estBaseline != _insBasicConfigurationRegisterVn300.estBaseline) | |
6227 | { | ||
6228 | ✗ | LOG_ERROR("{}: Writing the insBasicConfigurationRegisterVn300 was not successfull.\n" | |
6229 | "Target: scenario = {}, ahrsAiding = {}, estBaseline = {}\n" | ||
6230 | "Sensor: scenario = {}, ahrsAiding = {}, estBaseline = {}", | ||
6231 | nameId(), | ||
6232 | _insBasicConfigurationRegisterVn300.scenario, _insBasicConfigurationRegisterVn300.ahrsAiding, _insBasicConfigurationRegisterVn300.estBaseline, | ||
6233 | vnInsBasicConfigurationRegisterVn300.scenario, vnInsBasicConfigurationRegisterVn300.ahrsAiding, vnInsBasicConfigurationRegisterVn300.estBaseline); | ||
6234 | ✗ | doDeinitialize(); | |
6235 | ✗ | return false; | |
6236 | } | ||
6237 | |||
6238 | ✗ | _vs.writeStartupFilterBiasEstimate(_startupFilterBiasEstimateRegister); | |
6239 | ✗ | if (auto vnStartupFilterBiasEstimateRegister = _vs.readStartupFilterBiasEstimate(); | |
6240 | ✗ | vnStartupFilterBiasEstimateRegister.gyroBias != _startupFilterBiasEstimateRegister.gyroBias | |
6241 | ✗ | || vnStartupFilterBiasEstimateRegister.accelBias != _startupFilterBiasEstimateRegister.accelBias | |
6242 | ✗ | || vnStartupFilterBiasEstimateRegister.pressureBias != _startupFilterBiasEstimateRegister.pressureBias) | |
6243 | { | ||
6244 | ✗ | LOG_ERROR("{}: Writing the startupFilterBiasEstimateRegister was not successfull.\n" | |
6245 | "Target: gyroBias = {}, accelBias = {}, pressureBias = {}\n" | ||
6246 | "Sensor: gyroBias = {}, accelBias = {}, pressureBias = {}", | ||
6247 | nameId(), | ||
6248 | _startupFilterBiasEstimateRegister.gyroBias, _startupFilterBiasEstimateRegister.accelBias, _startupFilterBiasEstimateRegister.pressureBias, | ||
6249 | vnStartupFilterBiasEstimateRegister.gyroBias, vnStartupFilterBiasEstimateRegister.accelBias, vnStartupFilterBiasEstimateRegister.pressureBias); | ||
6250 | ✗ | doDeinitialize(); | |
6251 | ✗ | return false; | |
6252 | } | ||
6253 | } | ||
6254 | |||
6255 | // ########################################################################################################### | ||
6256 | // HARD/SOFT IRON ESTIMATOR SUBSYSTEM | ||
6257 | // ########################################################################################################### | ||
6258 | |||
6259 | ✗ | _vs.writeMagnetometerCalibrationControl(_magnetometerCalibrationControlRegister); | |
6260 | ✗ | if (auto vnMagnetometerCalibrationControlRegister = _vs.readMagnetometerCalibrationControl(); | |
6261 | ✗ | vnMagnetometerCalibrationControlRegister.hsiMode != _magnetometerCalibrationControlRegister.hsiMode | |
6262 | ✗ | || vnMagnetometerCalibrationControlRegister.hsiOutput != _magnetometerCalibrationControlRegister.hsiOutput | |
6263 | ✗ | || vnMagnetometerCalibrationControlRegister.convergeRate != _magnetometerCalibrationControlRegister.convergeRate) | |
6264 | { | ||
6265 | ✗ | LOG_ERROR("{}: Writing the magnetometerCalibrationControlRegister was not successfull.\n" | |
6266 | "Target: hsiMode = {}, hsiOutput = {}, convergeRate = {}\n" | ||
6267 | "Sensor: hsiMode = {}, hsiOutput = {}, convergeRate = {}", | ||
6268 | nameId(), | ||
6269 | _magnetometerCalibrationControlRegister.hsiMode, _magnetometerCalibrationControlRegister.hsiOutput, _magnetometerCalibrationControlRegister.convergeRate, | ||
6270 | vnMagnetometerCalibrationControlRegister.hsiMode, vnMagnetometerCalibrationControlRegister.hsiOutput, vnMagnetometerCalibrationControlRegister.convergeRate); | ||
6271 | ✗ | doDeinitialize(); | |
6272 | ✗ | return false; | |
6273 | } | ||
6274 | |||
6275 | // ########################################################################################################### | ||
6276 | // WORLD MAGNETIC & GRAVITY MODULE | ||
6277 | // ########################################################################################################### | ||
6278 | |||
6279 | ✗ | _vs.writeMagneticAndGravityReferenceVectors(_magneticAndGravityReferenceVectorsRegister); | |
6280 | ✗ | if (auto vnMagneticAndGravityReferenceVectorsRegister = _vs.readMagneticAndGravityReferenceVectors(); | |
6281 | ✗ | (!_referenceVectorConfigurationRegister.useMagModel && vnMagneticAndGravityReferenceVectorsRegister.magRef != _magneticAndGravityReferenceVectorsRegister.magRef) | |
6282 | ✗ | || (!_referenceVectorConfigurationRegister.useGravityModel && vnMagneticAndGravityReferenceVectorsRegister.accRef != _magneticAndGravityReferenceVectorsRegister.accRef)) | |
6283 | { | ||
6284 | ✗ | LOG_ERROR("{}: Writing the magneticAndGravityReferenceVectorsRegister was not successfull.\n" | |
6285 | "Target: magRef = {}, accRef = {}\n" | ||
6286 | "Sensor: magRef = {}, accRef = {}", | ||
6287 | nameId(), | ||
6288 | _magneticAndGravityReferenceVectorsRegister.magRef, _magneticAndGravityReferenceVectorsRegister.accRef, | ||
6289 | vnMagneticAndGravityReferenceVectorsRegister.magRef, vnMagneticAndGravityReferenceVectorsRegister.accRef); | ||
6290 | ✗ | doDeinitialize(); | |
6291 | ✗ | return false; | |
6292 | } | ||
6293 | |||
6294 | ✗ | _vs.writeReferenceVectorConfiguration(_referenceVectorConfigurationRegister); | |
6295 | ✗ | if (auto vnReferenceVectorConfigurationRegister = _vs.readReferenceVectorConfiguration(); | |
6296 | ✗ | vnReferenceVectorConfigurationRegister.useMagModel != _referenceVectorConfigurationRegister.useMagModel | |
6297 | ✗ | || vnReferenceVectorConfigurationRegister.useGravityModel != _referenceVectorConfigurationRegister.useGravityModel | |
6298 | ✗ | || vnReferenceVectorConfigurationRegister.recalcThreshold != _referenceVectorConfigurationRegister.recalcThreshold | |
6299 | ✗ | || vnReferenceVectorConfigurationRegister.year != _referenceVectorConfigurationRegister.year | |
6300 | ✗ | || vnReferenceVectorConfigurationRegister.position != _referenceVectorConfigurationRegister.position) | |
6301 | { | ||
6302 | ✗ | LOG_ERROR("{}: Writing the referenceVectorConfigurationRegister was not successfull.\n" | |
6303 | "Target: useMagModel = {}, useGravityModel = {}, recalcThreshold = {}, year = {}, position = {}\n" | ||
6304 | "Sensor: useMagModel = {}, useGravityModel = {}, recalcThreshold = {}, year = {}, position = {}", | ||
6305 | nameId(), | ||
6306 | _referenceVectorConfigurationRegister.useMagModel, _referenceVectorConfigurationRegister.useGravityModel, _referenceVectorConfigurationRegister.recalcThreshold, _referenceVectorConfigurationRegister.year, _referenceVectorConfigurationRegister.position, | ||
6307 | vnReferenceVectorConfigurationRegister.useMagModel, vnReferenceVectorConfigurationRegister.useGravityModel, vnReferenceVectorConfigurationRegister.recalcThreshold, vnReferenceVectorConfigurationRegister.year, vnReferenceVectorConfigurationRegister.position); | ||
6308 | ✗ | doDeinitialize(); | |
6309 | ✗ | return false; | |
6310 | } | ||
6311 | |||
6312 | // ########################################################################################################### | ||
6313 | // Velocity Aiding | ||
6314 | // ########################################################################################################### | ||
6315 | |||
6316 | ✗ | if (_sensorModel == VectorNavModel::VN100_VN110) | |
6317 | { | ||
6318 | ✗ | _vs.writeVelocityCompensationControl(_velocityCompensationControlRegister); | |
6319 | ✗ | if (auto vnVelocityCompensationControlRegister = _vs.readVelocityCompensationControl(); | |
6320 | ✗ | vnVelocityCompensationControlRegister.mode != _velocityCompensationControlRegister.mode | |
6321 | ✗ | || vnVelocityCompensationControlRegister.velocityTuning != _velocityCompensationControlRegister.velocityTuning | |
6322 | ✗ | || vnVelocityCompensationControlRegister.rateTuning != _velocityCompensationControlRegister.rateTuning) | |
6323 | { | ||
6324 | ✗ | LOG_ERROR("{}: Writing the velocityCompensationControlRegister was not successfull.\n" | |
6325 | "Target: mode = {}, velocityTuning = {}, rateTuning = {}\n" | ||
6326 | "Sensor: mode = {}, velocityTuning = {}, rateTuning = {}", | ||
6327 | nameId(), | ||
6328 | _velocityCompensationControlRegister.mode, _velocityCompensationControlRegister.velocityTuning, _velocityCompensationControlRegister.rateTuning, | ||
6329 | vnVelocityCompensationControlRegister.mode, vnVelocityCompensationControlRegister.velocityTuning, vnVelocityCompensationControlRegister.rateTuning); | ||
6330 | ✗ | doDeinitialize(); | |
6331 | ✗ | return false; | |
6332 | } | ||
6333 | |||
6334 | // _vs.writeVelocityCompensationMeasurement(vn::math::vec3f); // User manual VN-100 - 10.3.1 (p 124) | ||
6335 | } | ||
6336 | |||
6337 | // ########################################################################################################### | ||
6338 | // Outputs | ||
6339 | // ########################################################################################################### | ||
6340 | |||
6341 | ✗ | _vs.writeAsyncDataOutputType(_asyncDataOutputType); | |
6342 | ✗ | if (auto vnAsyncDataOutputType = _vs.readAsyncDataOutputType(); | |
6343 | ✗ | vnAsyncDataOutputType != _asyncDataOutputType) | |
6344 | { | ||
6345 | ✗ | LOG_ERROR("{}: Writing the asyncDataOutputType was not successfull.\n" | |
6346 | "Target: {}\n" | ||
6347 | "Sensor: {}", | ||
6348 | nameId(), | ||
6349 | _asyncDataOutputType, | ||
6350 | vnAsyncDataOutputType); | ||
6351 | ✗ | doDeinitialize(); | |
6352 | ✗ | return false; | |
6353 | } | ||
6354 | |||
6355 | ✗ | if (_asyncDataOutputType != vn::protocol::uart::AsciiAsync::VNOFF) | |
6356 | { | ||
6357 | ✗ | _vs.writeAsyncDataOutputFrequency(_asyncDataOutputFrequency); | |
6358 | ✗ | if (auto vnAsyncDataOutputFrequency = _vs.readAsyncDataOutputType(); | |
6359 | ✗ | vnAsyncDataOutputFrequency != _asyncDataOutputFrequency) | |
6360 | { | ||
6361 | ✗ | LOG_ERROR("{}: Writing the asyncDataOutputFrequency was not successfull.\n" | |
6362 | "Target: {}\n" | ||
6363 | "Sensor: {}", | ||
6364 | nameId(), | ||
6365 | _asyncDataOutputFrequency, | ||
6366 | vnAsyncDataOutputFrequency); | ||
6367 | ✗ | doDeinitialize(); | |
6368 | ✗ | return false; | |
6369 | } | ||
6370 | } | ||
6371 | |||
6372 | ✗ | [[maybe_unused]] size_t binaryOutputRegisterCounter = 1; // To give a proper error message | |
6373 | try | ||
6374 | { | ||
6375 | // The sensor does somehow report wrong flags here, so we can't check if it actually worked | ||
6376 | |||
6377 | // auto checkBinaryRegister = [&](const vn::sensors::BinaryOutputRegister& current, const vn::sensors::BinaryOutputRegister& target) { | ||
6378 | // if (current.asyncMode != target.asyncMode | ||
6379 | // || current.rateDivisor != target.rateDivisor | ||
6380 | // || current.commonField != target.commonField | ||
6381 | // || current.timeField != target.timeField | ||
6382 | // || current.imuField != target.imuField | ||
6383 | // || current.gpsField != target.gpsField | ||
6384 | // || current.attitudeField != target.attitudeField | ||
6385 | // || current.insField != target.insField | ||
6386 | // || current.gps2Field != target.gps2Field) | ||
6387 | // { | ||
6388 | // LOG_ERROR("{}: Writing the binaryOutputRegister {} was not successfull.\n" | ||
6389 | // "Target: asyncMode = {}, rateDivisor = {}, commonField = {}, timeField = {}, imuField = {}, gpsField = {}, attitudeField = {}, insField = {}, gps2Field = {}\n" | ||
6390 | // "Sensor: asyncMode = {}, rateDivisor = {}, commonField = {}, timeField = {}, imuField = {}, gpsField = {}, attitudeField = {}, insField = {}, gps2Field = {}", | ||
6391 | // nameId(), binaryOutputRegisterCounter, | ||
6392 | // target.asyncMode, target.rateDivisor, target.commonField, target.timeField, target.imuField, target.gpsField, target.attitudeField, target.insField, target.gps2Field, | ||
6393 | // current.asyncMode, current.rateDivisor, current.commonField, current.timeField, current.imuField, current.gpsField, current.attitudeField, current.insField, current.gps2Field); | ||
6394 | // return false; | ||
6395 | // } | ||
6396 | // return true; | ||
6397 | // }; | ||
6398 | |||
6399 | ✗ | _vs.writeBinaryOutput1(_binaryOutputRegister.at(0)); | |
6400 | // if (!checkBinaryRegister(_vs.readBinaryOutput1(), _binaryOutputRegister.at(0))) | ||
6401 | // { | ||
6402 | // DoDeinitialize();; | ||
6403 | // return false; | ||
6404 | // } | ||
6405 | |||
6406 | ✗ | binaryOutputRegisterCounter++; | |
6407 | ✗ | _vs.writeBinaryOutput2(_binaryOutputRegister.at(1)); | |
6408 | // if (!checkBinaryRegister(_vs.readBinaryOutput2(), _binaryOutputRegister.at(1))) | ||
6409 | // { | ||
6410 | // DoDeinitialize();; | ||
6411 | // return false; | ||
6412 | // } | ||
6413 | |||
6414 | ✗ | binaryOutputRegisterCounter++; | |
6415 | ✗ | _vs.writeBinaryOutput3(_binaryOutputRegister.at(2)); | |
6416 | // if (!checkBinaryRegister(_vs.readBinaryOutput3(), _binaryOutputRegister.at(2))) | ||
6417 | // { | ||
6418 | // DoDeinitialize();; | ||
6419 | // return false; | ||
6420 | // } | ||
6421 | } | ||
6422 | ✗ | catch (const std::exception& e) | |
6423 | { | ||
6424 | ✗ | LOG_ERROR("{}: Could not configure binary output register {}: {}", nameId(), binaryOutputRegisterCounter, e.what()); | |
6425 | ✗ | doDeinitialize(); | |
6426 | ✗ | return false; | |
6427 | ✗ | } | |
6428 | |||
6429 | // Some changes need to be set at startup, therefore write the settings and reset the device | ||
6430 | ✗ | LOG_DEBUG("{}: writing settings", nameId()); | |
6431 | ✗ | _vs.writeSettings(); | |
6432 | |||
6433 | ✗ | if (deviceNeedsResetAfterInitialization) | |
6434 | { | ||
6435 | ✗ | LOG_DEBUG("{}: Resetting device to apply permenent settings", nameId()); | |
6436 | ✗ | _vs.reset(); | |
6437 | } | ||
6438 | |||
6439 | // TODO: Implement in vnproglib: _vs.writeNmeaOutput1(...) - User manual VN-310 - 8.2.14 (p 103) | ||
6440 | // TODO: Implement in vnproglib: _vs.writeNmeaOutput2(...) - User manual VN-310 - 8.2.15 (p 104) | ||
6441 | |||
6442 | ✗ | _vs.registerAsyncPacketReceivedHandler(this, asciiOrBinaryAsyncMessageReceived); | |
6443 | |||
6444 | ✗ | LOG_DEBUG("{}: successfully initialized", nameId()); | |
6445 | |||
6446 | ✗ | return true; | |
6447 | ✗ | } | |
6448 | |||
6449 | ✗ | void NAV::VectorNavSensor::deinitialize() | |
6450 | { | ||
6451 | LOG_TRACE("{}: called", nameId()); | ||
6452 | |||
6453 | try | ||
6454 | { | ||
6455 | ✗ | if (_vs.isConnected()) | |
6456 | { | ||
6457 | try | ||
6458 | { | ||
6459 | ✗ | _vs.unregisterAsyncPacketReceivedHandler(); | |
6460 | } | ||
6461 | ✗ | catch (const std::exception& e) | |
6462 | { | ||
6463 | ✗ | LOG_WARN("{}: Could not unregisterAsyncPacketReceivedHandler ({})", nameId(), e.what()); | |
6464 | ✗ | } | |
6465 | |||
6466 | try | ||
6467 | { | ||
6468 | vn::sensors::BinaryOutputRegister bor{ | ||
6469 | vn::protocol::uart::AsyncMode::ASYNCMODE_NONE, // AsyncMode | ||
6470 | 800, // RateDivisor | ||
6471 | vn::protocol::uart::CommonGroup::COMMONGROUP_NONE, // CommonGroup | ||
6472 | vn::protocol::uart::TimeGroup::TIMEGROUP_NONE, // TimeGroup | ||
6473 | vn::protocol::uart::ImuGroup::IMUGROUP_NONE, // IMUGroup | ||
6474 | vn::protocol::uart::GpsGroup::GPSGROUP_NONE, // GNSS1Group | ||
6475 | vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_NONE, // AttitudeGroup | ||
6476 | vn::protocol::uart::InsGroup::INSGROUP_NONE, // INSGroup | ||
6477 | vn::protocol::uart::GpsGroup::GPSGROUP_NONE // GNSS2Group | ||
6478 | ✗ | }; | |
6479 | |||
6480 | ✗ | _vs.writeBinaryOutput1(bor); | |
6481 | ✗ | _vs.writeBinaryOutput2(bor); | |
6482 | ✗ | _vs.writeBinaryOutput3(bor); | |
6483 | ✗ | _vs.writeAsyncDataOutputType(vn::protocol::uart::AsciiAsync::VNOFF); | |
6484 | ✗ | _vs.changeBaudRate(NAV::UartSensor::Baudrate::BAUDRATE_115200); | |
6485 | ✗ | _vs.writeSettings(); | |
6486 | ✗ | LOG_DEBUG("{}: Sensor output turned off", nameId()); | |
6487 | } | ||
6488 | ✗ | catch (const std::exception& e) | |
6489 | { | ||
6490 | ✗ | LOG_WARN("{}: Could not turn off sensor output ({})", nameId(), e.what()); | |
6491 | ✗ | } | |
6492 | |||
6493 | try | ||
6494 | { | ||
6495 | ✗ | _vs.disconnect(); | |
6496 | ✗ | LOG_DEBUG("{}: Sensor disconnected", nameId()); | |
6497 | } | ||
6498 | ✗ | catch (const std::exception& e) | |
6499 | { | ||
6500 | ✗ | LOG_WARN("{}: Could not disconnect ({})", nameId(), e.what()); | |
6501 | ✗ | } | |
6502 | } | ||
6503 | } | ||
6504 | ✗ | catch (const std::exception& e) | |
6505 | { | ||
6506 | ✗ | LOG_WARN("{}: Unhandled exception while deinitializing sensor ({})", nameId(), e.what()); | |
6507 | ✗ | } | |
6508 | ✗ | } | |
6509 | |||
6510 | ✗ | void NAV::VectorNavSensor::mergeVectorNavBinaryObservations(const std::shared_ptr<VectorNavBinaryOutput>& target, const std::shared_ptr<VectorNavBinaryOutput>& source) | |
6511 | { | ||
6512 | ✗ | target->insTime = !target->insTime.empty() ? target->insTime : source->insTime; | |
6513 | // Group 2 (Time) | ||
6514 | ✗ | if (!target->timeOutputs && source->timeOutputs) | |
6515 | { | ||
6516 | ✗ | target->timeOutputs = source->timeOutputs; | |
6517 | } | ||
6518 | ✗ | else if (target->timeOutputs && source->timeOutputs) | |
6519 | { | ||
6520 | ✗ | target->timeOutputs->timeStartup = target->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP ? target->timeOutputs->timeStartup : source->timeOutputs->timeStartup; | |
6521 | ✗ | target->timeOutputs->timeGps = target->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEGPS ? target->timeOutputs->timeGps : source->timeOutputs->timeGps; | |
6522 | ✗ | target->timeOutputs->gpsTow = target->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW ? target->timeOutputs->gpsTow : source->timeOutputs->gpsTow; | |
6523 | ✗ | target->timeOutputs->gpsWeek = target->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK ? target->timeOutputs->gpsWeek : source->timeOutputs->gpsWeek; | |
6524 | ✗ | target->timeOutputs->timeSyncIn = target->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESYNCIN ? target->timeOutputs->timeSyncIn : source->timeOutputs->timeSyncIn; | |
6525 | ✗ | target->timeOutputs->timePPS = target->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEGPSPPS ? target->timeOutputs->timePPS : source->timeOutputs->timePPS; | |
6526 | // target->timeOutputs->timeUtc = target->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEUTC ? target->timeOutputs->timeUtc : source->timeOutputs->timeUtc; | ||
6527 | ✗ | target->timeOutputs->syncInCnt = target->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_SYNCINCNT ? target->timeOutputs->syncInCnt : source->timeOutputs->syncInCnt; | |
6528 | ✗ | target->timeOutputs->syncOutCnt = target->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_SYNCOUTCNT ? target->timeOutputs->syncOutCnt : source->timeOutputs->syncOutCnt; | |
6529 | ✗ | target->timeOutputs->timeStatus = target->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS ? target->timeOutputs->timeStatus : source->timeOutputs->timeStatus; | |
6530 | |||
6531 | ✗ | target->timeOutputs->timeField |= source->timeOutputs->timeField; | |
6532 | } | ||
6533 | // Group 3 (IMU) | ||
6534 | ✗ | if (!target->imuOutputs && source->imuOutputs) | |
6535 | { | ||
6536 | ✗ | target->imuOutputs = source->imuOutputs; | |
6537 | } | ||
6538 | ✗ | else if (target->imuOutputs && source->imuOutputs) | |
6539 | { | ||
6540 | ✗ | target->imuOutputs->imuStatus = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_IMUSTATUS ? target->imuOutputs->imuStatus : source->imuOutputs->imuStatus; | |
6541 | ✗ | target->imuOutputs->uncompMag = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPMAG ? target->imuOutputs->uncompMag : source->imuOutputs->uncompMag; | |
6542 | ✗ | target->imuOutputs->uncompAccel = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPACCEL ? target->imuOutputs->uncompAccel : source->imuOutputs->uncompAccel; | |
6543 | ✗ | target->imuOutputs->uncompGyro = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPGYRO ? target->imuOutputs->uncompGyro : source->imuOutputs->uncompGyro; | |
6544 | ✗ | target->imuOutputs->temp = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_TEMP ? target->imuOutputs->temp : source->imuOutputs->temp; | |
6545 | ✗ | target->imuOutputs->pres = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_PRES ? target->imuOutputs->pres : source->imuOutputs->pres; | |
6546 | ✗ | target->imuOutputs->deltaTime = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTATHETA ? target->imuOutputs->deltaTime : source->imuOutputs->deltaTime; | |
6547 | ✗ | target->imuOutputs->deltaTheta = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTATHETA ? target->imuOutputs->deltaTheta : source->imuOutputs->deltaTheta; | |
6548 | ✗ | target->imuOutputs->deltaV = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTAVEL ? target->imuOutputs->deltaV : source->imuOutputs->deltaV; | |
6549 | ✗ | target->imuOutputs->mag = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_MAG ? target->imuOutputs->mag : source->imuOutputs->mag; | |
6550 | ✗ | target->imuOutputs->accel = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ACCEL ? target->imuOutputs->accel : source->imuOutputs->accel; | |
6551 | ✗ | target->imuOutputs->angularRate = target->imuOutputs->imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ANGULARRATE ? target->imuOutputs->angularRate : source->imuOutputs->angularRate; | |
6552 | |||
6553 | ✗ | target->imuOutputs->imuField |= source->imuOutputs->imuField; | |
6554 | } | ||
6555 | // Group 4 (GNSS1) | ||
6556 | ✗ | if (!target->gnss1Outputs && source->gnss1Outputs) | |
6557 | { | ||
6558 | ✗ | target->gnss1Outputs = source->gnss1Outputs; | |
6559 | } | ||
6560 | ✗ | else if (target->gnss1Outputs && source->gnss1Outputs) | |
6561 | { | ||
6562 | // target->gnss1Outputs->timeUtc = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_UTC ? target->gnss1Outputs->timeUtc : source->gnss1Outputs->timeUtc; | ||
6563 | ✗ | target->gnss1Outputs->tow = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_TOW ? target->gnss1Outputs->tow : source->gnss1Outputs->tow; | |
6564 | ✗ | target->gnss1Outputs->week = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_WEEK ? target->gnss1Outputs->week : source->gnss1Outputs->week; | |
6565 | ✗ | target->gnss1Outputs->numSats = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_NUMSATS ? target->gnss1Outputs->numSats : source->gnss1Outputs->numSats; | |
6566 | ✗ | target->gnss1Outputs->fix = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_FIX ? target->gnss1Outputs->fix : source->gnss1Outputs->fix; | |
6567 | ✗ | target->gnss1Outputs->posLla = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_POSLLA ? target->gnss1Outputs->posLla : source->gnss1Outputs->posLla; | |
6568 | ✗ | target->gnss1Outputs->posEcef = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_POSECEF ? target->gnss1Outputs->posEcef : source->gnss1Outputs->posEcef; | |
6569 | ✗ | target->gnss1Outputs->velNed = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_VELNED ? target->gnss1Outputs->velNed : source->gnss1Outputs->velNed; | |
6570 | ✗ | target->gnss1Outputs->velEcef = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_VELECEF ? target->gnss1Outputs->velEcef : source->gnss1Outputs->velEcef; | |
6571 | ✗ | target->gnss1Outputs->posU = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_POSU ? target->gnss1Outputs->posU : source->gnss1Outputs->posU; | |
6572 | ✗ | target->gnss1Outputs->velU = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_VELU ? target->gnss1Outputs->velU : source->gnss1Outputs->velU; | |
6573 | ✗ | target->gnss1Outputs->timeU = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_TIMEU ? target->gnss1Outputs->timeU : source->gnss1Outputs->timeU; | |
6574 | ✗ | target->gnss1Outputs->timeInfo = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO ? target->gnss1Outputs->timeInfo : source->gnss1Outputs->timeInfo; | |
6575 | ✗ | target->gnss1Outputs->dop = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_DOP ? target->gnss1Outputs->dop : source->gnss1Outputs->dop; | |
6576 | ✗ | target->gnss1Outputs->satInfo = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_SATINFO ? target->gnss1Outputs->satInfo : source->gnss1Outputs->satInfo; | |
6577 | ✗ | target->gnss1Outputs->raw = target->gnss1Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_RAWMEAS ? target->gnss1Outputs->raw : source->gnss1Outputs->raw; | |
6578 | |||
6579 | ✗ | target->gnss1Outputs->gnssField |= source->gnss1Outputs->gnssField; | |
6580 | } | ||
6581 | // Group 5 (Attitude) | ||
6582 | ✗ | if (!target->attitudeOutputs && source->attitudeOutputs) | |
6583 | { | ||
6584 | ✗ | target->attitudeOutputs = source->attitudeOutputs; | |
6585 | } | ||
6586 | ✗ | else if (target->attitudeOutputs && source->attitudeOutputs) | |
6587 | { | ||
6588 | ✗ | target->attitudeOutputs->vpeStatus = target->attitudeOutputs->attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_VPESTATUS ? target->attitudeOutputs->vpeStatus : source->attitudeOutputs->vpeStatus; | |
6589 | ✗ | target->attitudeOutputs->ypr = target->attitudeOutputs->attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YAWPITCHROLL ? target->attitudeOutputs->ypr : source->attitudeOutputs->ypr; | |
6590 | ✗ | target->attitudeOutputs->qtn = target->attitudeOutputs->attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_QUATERNION ? target->attitudeOutputs->qtn : source->attitudeOutputs->qtn; | |
6591 | ✗ | target->attitudeOutputs->dcm = target->attitudeOutputs->attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_DCM ? target->attitudeOutputs->dcm : source->attitudeOutputs->dcm; | |
6592 | ✗ | target->attitudeOutputs->magNed = target->attitudeOutputs->attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_MAGNED ? target->attitudeOutputs->magNed : source->attitudeOutputs->magNed; | |
6593 | ✗ | target->attitudeOutputs->accelNed = target->attitudeOutputs->attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_ACCELNED ? target->attitudeOutputs->accelNed : source->attitudeOutputs->accelNed; | |
6594 | ✗ | target->attitudeOutputs->linearAccelBody = target->attitudeOutputs->attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELBODY ? target->attitudeOutputs->linearAccelBody : source->attitudeOutputs->linearAccelBody; | |
6595 | ✗ | target->attitudeOutputs->linearAccelNed = target->attitudeOutputs->attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELNED ? target->attitudeOutputs->linearAccelNed : source->attitudeOutputs->linearAccelNed; | |
6596 | ✗ | target->attitudeOutputs->yprU = target->attitudeOutputs->attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YPRU ? target->attitudeOutputs->yprU : source->attitudeOutputs->yprU; | |
6597 | |||
6598 | ✗ | target->attitudeOutputs->attitudeField |= source->attitudeOutputs->attitudeField; | |
6599 | } | ||
6600 | // Group 6 (INS) | ||
6601 | ✗ | if (!target->insOutputs && source->insOutputs) | |
6602 | { | ||
6603 | ✗ | target->insOutputs = source->insOutputs; | |
6604 | } | ||
6605 | ✗ | else if (target->insOutputs && source->insOutputs) | |
6606 | { | ||
6607 | ✗ | target->insOutputs->insStatus = target->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_INSSTATUS ? target->insOutputs->insStatus : source->insOutputs->insStatus; | |
6608 | ✗ | target->insOutputs->posLla = target->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_POSLLA ? target->insOutputs->posLla : source->insOutputs->posLla; | |
6609 | ✗ | target->insOutputs->posEcef = target->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_POSECEF ? target->insOutputs->posEcef : source->insOutputs->posEcef; | |
6610 | ✗ | target->insOutputs->velBody = target->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_VELBODY ? target->insOutputs->velBody : source->insOutputs->velBody; | |
6611 | ✗ | target->insOutputs->velNed = target->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_VELNED ? target->insOutputs->velNed : source->insOutputs->velNed; | |
6612 | ✗ | target->insOutputs->velEcef = target->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_VELECEF ? target->insOutputs->velEcef : source->insOutputs->velEcef; | |
6613 | ✗ | target->insOutputs->magEcef = target->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_MAGECEF ? target->insOutputs->magEcef : source->insOutputs->magEcef; | |
6614 | ✗ | target->insOutputs->accelEcef = target->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_ACCELECEF ? target->insOutputs->accelEcef : source->insOutputs->accelEcef; | |
6615 | ✗ | target->insOutputs->linearAccelEcef = target->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_LINEARACCELECEF ? target->insOutputs->linearAccelEcef : source->insOutputs->linearAccelEcef; | |
6616 | ✗ | target->insOutputs->posU = target->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_POSU ? target->insOutputs->posU : source->insOutputs->posU; | |
6617 | ✗ | target->insOutputs->velU = target->insOutputs->insField & vn::protocol::uart::InsGroup::INSGROUP_VELU ? target->insOutputs->velU : source->insOutputs->velU; | |
6618 | |||
6619 | ✗ | target->insOutputs->insField |= source->insOutputs->insField; | |
6620 | } | ||
6621 | // Group 7 (GNSS2) | ||
6622 | ✗ | if (!target->gnss2Outputs && source->gnss2Outputs) | |
6623 | { | ||
6624 | ✗ | target->gnss2Outputs = source->gnss2Outputs; | |
6625 | } | ||
6626 | ✗ | else if (target->gnss2Outputs && source->gnss2Outputs) | |
6627 | { | ||
6628 | // target->gnss2Outputs->timeUtc = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_UTC ? target->gnss2Outputs->timeUtc : source->gnss2Outputs->timeUtc; | ||
6629 | ✗ | target->gnss2Outputs->tow = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_TOW ? target->gnss2Outputs->tow : source->gnss2Outputs->tow; | |
6630 | ✗ | target->gnss2Outputs->week = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_WEEK ? target->gnss2Outputs->week : source->gnss2Outputs->week; | |
6631 | ✗ | target->gnss2Outputs->numSats = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_NUMSATS ? target->gnss2Outputs->numSats : source->gnss2Outputs->numSats; | |
6632 | ✗ | target->gnss2Outputs->fix = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_FIX ? target->gnss2Outputs->fix : source->gnss2Outputs->fix; | |
6633 | ✗ | target->gnss2Outputs->posLla = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_POSLLA ? target->gnss2Outputs->posLla : source->gnss2Outputs->posLla; | |
6634 | ✗ | target->gnss2Outputs->posEcef = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_POSECEF ? target->gnss2Outputs->posEcef : source->gnss2Outputs->posEcef; | |
6635 | ✗ | target->gnss2Outputs->velNed = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_VELNED ? target->gnss2Outputs->velNed : source->gnss2Outputs->velNed; | |
6636 | ✗ | target->gnss2Outputs->velEcef = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_VELECEF ? target->gnss2Outputs->velEcef : source->gnss2Outputs->velEcef; | |
6637 | ✗ | target->gnss2Outputs->posU = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_POSU ? target->gnss2Outputs->posU : source->gnss2Outputs->posU; | |
6638 | ✗ | target->gnss2Outputs->velU = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_VELU ? target->gnss2Outputs->velU : source->gnss2Outputs->velU; | |
6639 | ✗ | target->gnss2Outputs->timeU = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_TIMEU ? target->gnss2Outputs->timeU : source->gnss2Outputs->timeU; | |
6640 | ✗ | target->gnss2Outputs->timeInfo = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO ? target->gnss2Outputs->timeInfo : source->gnss2Outputs->timeInfo; | |
6641 | ✗ | target->gnss2Outputs->dop = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_DOP ? target->gnss2Outputs->dop : source->gnss2Outputs->dop; | |
6642 | ✗ | target->gnss2Outputs->satInfo = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_SATINFO ? target->gnss2Outputs->satInfo : source->gnss2Outputs->satInfo; | |
6643 | ✗ | target->gnss2Outputs->raw = target->gnss2Outputs->gnssField & vn::protocol::uart::GpsGroup::GPSGROUP_RAWMEAS ? target->gnss2Outputs->raw : source->gnss2Outputs->raw; | |
6644 | |||
6645 | ✗ | target->gnss2Outputs->gnssField |= source->gnss2Outputs->gnssField; | |
6646 | } | ||
6647 | ✗ | } | |
6648 | |||
6649 | ✗ | void NAV::VectorNavSensor::asciiOrBinaryAsyncMessageReceived(void* userData, vn::protocol::uart::Packet& p, [[maybe_unused]] size_t index) | |
6650 | { | ||
6651 | ✗ | auto* vnSensor = static_cast<VectorNavSensor*>(userData); | |
6652 | |||
6653 | LOG_DATA("{}: Received message", vnSensor->nameId()); | ||
6654 | |||
6655 | ✗ | if (p.getPacketLength() > 2500) | |
6656 | { | ||
6657 | ✗ | LOG_ERROR("{} Packet size is {} bytes. VectorNav internal buffer overflows happen if the size is > 2550 bytes. " | |
6658 | "You potentially already lost packages without noticing. " | ||
6659 | "Consider splitting the packet to different Binary outputs.", | ||
6660 | vnSensor->nameId(), p.getPacketLength()); | ||
6661 | } | ||
6662 | ✗ | else if (p.getPacketLength() > 2200) | |
6663 | { | ||
6664 | ✗ | LOG_WARN("{} Packet size is {} bytes. VectorNav internal buffer overflows happen if the size is > 2550 bytes. " | |
6665 | "Consider splitting the packet to different Binary outputs.", | ||
6666 | vnSensor->nameId(), p.getPacketLength()); | ||
6667 | } | ||
6668 | |||
6669 | ✗ | if (p.type() == vn::protocol::uart::Packet::TYPE_BINARY) | |
6670 | { | ||
6671 | ✗ | for (size_t b = 0; b < 3; b++) | |
6672 | { | ||
6673 | // Make sure that the binary packet is from the type we expect | ||
6674 | ✗ | if (p.isCompatible(vnSensor->_binaryOutputRegister.at(b).commonField, | |
6675 | ✗ | vnSensor->_binaryOutputRegister.at(b).timeField, | |
6676 | ✗ | vnSensor->_binaryOutputRegister.at(b).imuField, | |
6677 | ✗ | vnSensor->_binaryOutputRegister.at(b).gpsField, | |
6678 | ✗ | vnSensor->_binaryOutputRegister.at(b).attitudeField, | |
6679 | ✗ | vnSensor->_binaryOutputRegister.at(b).insField, | |
6680 | ✗ | vnSensor->_binaryOutputRegister.at(b).gps2Field)) | |
6681 | { | ||
6682 | ✗ | auto obs = std::make_shared<VectorNavBinaryOutput>(vnSensor->_imuPos); | |
6683 | |||
6684 | // // Group 1 (Common) | ||
6685 | // if (vnSensor->_binaryOutputRegister.at(b).commonField != vn::protocol::uart::CommonGroup::COMMONGROUP_NONE) | ||
6686 | // { | ||
6687 | // if (vnSensor->_binaryOutputRegister.at(b).commonField & vn::protocol::uart::CommonGroup::COMMONGROUP_TIMESTARTUP) | ||
6688 | // { | ||
6689 | // if (!obs->timeOutputs) | ||
6690 | // { | ||
6691 | // obs->timeOutputs = std::make_shared<NAV::vendor::vectornav::TimeOutputs>(); | ||
6692 | // obs->timeOutputs->timeField |= vnSensor->_binaryOutputRegister.at(b).timeField; | ||
6693 | // } | ||
6694 | // obs->timeOutputs->timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP; | ||
6695 | // obs->timeOutputs->timeStartup = p.extractUint64(); | ||
6696 | // } | ||
6697 | // if (vnSensor->_binaryOutputRegister.at(b).commonField & vn::protocol::uart::CommonGroup::COMMONGROUP_TIMEGPS) | ||
6698 | // { | ||
6699 | // if (!obs->timeOutputs) | ||
6700 | // { | ||
6701 | // obs->timeOutputs = std::make_shared<NAV::vendor::vectornav::TimeOutputs>(); | ||
6702 | // obs->timeOutputs->timeField |= vnSensor->_binaryOutputRegister.at(b).timeField; | ||
6703 | // } | ||
6704 | // obs->timeOutputs->timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEGPS; | ||
6705 | // obs->timeOutputs->timeStartup = p.extractUint64(); | ||
6706 | // } | ||
6707 | // if (vnSensor->_binaryOutputRegister.at(b).commonField & vn::protocol::uart::CommonGroup::COMMONGROUP_TIMESYNCIN) | ||
6708 | // { | ||
6709 | // if (!obs->timeOutputs) | ||
6710 | // { | ||
6711 | // obs->timeOutputs = std::make_shared<NAV::vendor::vectornav::TimeOutputs>(); | ||
6712 | // obs->timeOutputs->timeField |= vnSensor->_binaryOutputRegister.at(b).timeField; | ||
6713 | // } | ||
6714 | // obs->timeOutputs->timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESYNCIN; | ||
6715 | // obs->timeOutputs->timeSyncIn = p.extractUint64(); | ||
6716 | // } | ||
6717 | // if (vnSensor->_binaryOutputRegister.at(b).commonField & vn::protocol::uart::CommonGroup::COMMONGROUP_YAWPITCHROLL) | ||
6718 | // { | ||
6719 | // if (!obs->attitudeOutputs) | ||
6720 | // { | ||
6721 | // obs->attitudeOutputs = std::make_shared<NAV::vendor::vectornav::AttitudeOutputs>(); | ||
6722 | // obs->attitudeOutputs->attitudeField |= vnSensor->_binaryOutputRegister.at(b).attitudeField; | ||
6723 | // } | ||
6724 | // obs->attitudeOutputs->attitudeField |= vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YAWPITCHROLL; | ||
6725 | // auto vec = p.extractVec3f(); | ||
6726 | // obs->attitudeOutputs->ypr = { vec.x, vec.y, vec.z }; | ||
6727 | // } | ||
6728 | // if (vnSensor->_binaryOutputRegister.at(b).commonField & vn::protocol::uart::CommonGroup::COMMONGROUP_QUATERNION) | ||
6729 | // { | ||
6730 | // if (!obs->attitudeOutputs) | ||
6731 | // { | ||
6732 | // obs->attitudeOutputs = std::make_shared<NAV::vendor::vectornav::AttitudeOutputs>(); | ||
6733 | // obs->attitudeOutputs->attitudeField |= vnSensor->_binaryOutputRegister.at(b).attitudeField; | ||
6734 | // } | ||
6735 | // obs->attitudeOutputs->attitudeField |= vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_QUATERNION; | ||
6736 | // auto vec = p.extractVec4f(); | ||
6737 | // obs->attitudeOutputs->qtn = { vec.w, vec.x, vec.y, vec.z }; | ||
6738 | // } | ||
6739 | // if (vnSensor->_binaryOutputRegister.at(b).commonField & vn::protocol::uart::CommonGroup::COMMONGROUP_ANGULARRATE) | ||
6740 | // { | ||
6741 | // if (!obs->imuOutputs) | ||
6742 | // { | ||
6743 | // obs->imuOutputs = std::make_shared<NAV::vendor::vectornav::ImuOutputs>(); | ||
6744 | // obs->imuOutputs->imuField |= vnSensor->_binaryOutputRegister.at(b).imuField; | ||
6745 | // } | ||
6746 | // obs->imuOutputs->imuField |= vn::protocol::uart::ImuGroup::IMUGROUP_ANGULARRATE; | ||
6747 | // auto vec = p.extractVec3f(); | ||
6748 | // obs->imuOutputs->angularRate = { vec.x, vec.y, vec.z }; | ||
6749 | // } | ||
6750 | // if (vnSensor->_binaryOutputRegister.at(b).commonField & vn::protocol::uart::CommonGroup::COMMONGROUP_POSITION) | ||
6751 | // { | ||
6752 | // if (!obs->insOutputs) | ||
6753 | // { | ||
6754 | // obs->insOutputs = std::make_shared<NAV::vendor::vectornav::InsOutputs>(); | ||
6755 | // obs->insOutputs->insField |= vnSensor->_binaryOutputRegister.at(b).insField; | ||
6756 | // } | ||
6757 | // obs->insOutputs->insField |= vn::protocol::uart::InsGroup::INSGROUP_POSLLA; | ||
6758 | // auto vec = p.extractVec3d(); | ||
6759 | // obs->insOutputs->posLla = { vec.x, vec.y, vec.z }; | ||
6760 | // } | ||
6761 | // if (vnSensor->_binaryOutputRegister.at(b).commonField & vn::protocol::uart::CommonGroup::COMMONGROUP_VELOCITY) | ||
6762 | // { | ||
6763 | // if (!obs->insOutputs) | ||
6764 | // { | ||
6765 | // obs->insOutputs = std::make_shared<NAV::vendor::vectornav::InsOutputs>(); | ||
6766 | // obs->insOutputs->insField |= vnSensor->_binaryOutputRegister.at(b).insField; | ||
6767 | // } | ||
6768 | // obs->insOutputs->insField |= vn::protocol::uart::InsGroup::INSGROUP_VELNED; | ||
6769 | // auto vec = p.extractVec3f(); | ||
6770 | // obs->insOutputs->velNed = { vec.x, vec.y, vec.z }; | ||
6771 | // } | ||
6772 | // if (vnSensor->_binaryOutputRegister.at(b).commonField & vn::protocol::uart::CommonGroup::COMMONGROUP_ACCEL) | ||
6773 | // { | ||
6774 | // if (!obs->imuOutputs) | ||
6775 | // { | ||
6776 | // obs->imuOutputs = std::make_shared<NAV::vendor::vectornav::ImuOutputs>(); | ||
6777 | // obs->imuOutputs->imuField |= vnSensor->_binaryOutputRegister.at(b).imuField; | ||
6778 | // } | ||
6779 | // obs->imuOutputs->imuField |= vn::protocol::uart::ImuGroup::IMUGROUP_ACCEL; | ||
6780 | // auto vec = p.extractVec3f(); | ||
6781 | // obs->imuOutputs->accel = { vec.x, vec.y, vec.z }; | ||
6782 | // } | ||
6783 | // if (vnSensor->_binaryOutputRegister.at(b).commonField & vn::protocol::uart::CommonGroup::COMMONGROUP_IMU) | ||
6784 | // { | ||
6785 | // if (!obs->imuOutputs) | ||
6786 | // { | ||
6787 | // obs->imuOutputs = std::make_shared<NAV::vendor::vectornav::ImuOutputs>(); | ||
6788 | // obs->imuOutputs->imuField |= vnSensor->_binaryOutputRegister.at(b).imuField; | ||
6789 | // } | ||
6790 | // obs->imuOutputs->imuField |= vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPACCEL; | ||
6791 | // auto vec = p.extractVec3f(); | ||
6792 | // obs->imuOutputs->uncompAccel = { vec.x, vec.y, vec.z }; | ||
6793 | // obs->imuOutputs->imuField |= vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPGYRO; | ||
6794 | // vec = p.extractVec3f(); | ||
6795 | // obs->imuOutputs->uncompGyro = { vec.x, vec.y, vec.z }; | ||
6796 | // } | ||
6797 | // if (vnSensor->_binaryOutputRegister.at(b).commonField & vn::protocol::uart::CommonGroup::COMMONGROUP_MAGPRES) | ||
6798 | // { | ||
6799 | // if (!obs->imuOutputs) | ||
6800 | // { | ||
6801 | // obs->imuOutputs = std::make_shared<NAV::vendor::vectornav::ImuOutputs>(); | ||
6802 | // obs->imuOutputs->imuField |= vnSensor->_binaryOutputRegister.at(b).imuField; | ||
6803 | // } | ||
6804 | // obs->imuOutputs->imuField |= vn::protocol::uart::ImuGroup::IMUGROUP_MAG; | ||
6805 | // auto vec = p.extractVec3f(); | ||
6806 | // obs->imuOutputs->mag = { vec.x, vec.y, vec.z }; | ||
6807 | // obs->imuOutputs->imuField |= vn::protocol::uart::ImuGroup::IMUGROUP_TEMP; | ||
6808 | // obs->imuOutputs->temp = p.extractFloat(); | ||
6809 | // obs->imuOutputs->imuField |= vn::protocol::uart::ImuGroup::IMUGROUP_PRES; | ||
6810 | // obs->imuOutputs->pres = p.extractFloat(); | ||
6811 | // } | ||
6812 | // if (vnSensor->_binaryOutputRegister.at(b).commonField & vn::protocol::uart::CommonGroup::COMMONGROUP_DELTATHETA) | ||
6813 | // { | ||
6814 | // if (!obs->imuOutputs) | ||
6815 | // { | ||
6816 | // obs->imuOutputs = std::make_shared<NAV::vendor::vectornav::ImuOutputs>(); | ||
6817 | // obs->imuOutputs->imuField |= vnSensor->_binaryOutputRegister.at(b).imuField; | ||
6818 | // } | ||
6819 | // obs->imuOutputs->imuField |= vn::protocol::uart::ImuGroup::IMUGROUP_DELTATHETA; | ||
6820 | // obs->imuOutputs->deltaTime = p.extractFloat(); | ||
6821 | // auto vec = p.extractVec3f(); | ||
6822 | // obs->imuOutputs->deltaTheta = { vec.x, vec.y, vec.z }; | ||
6823 | // obs->imuOutputs->imuField |= vn::protocol::uart::ImuGroup::IMUGROUP_DELTAVEL; | ||
6824 | // vec = p.extractVec3f(); | ||
6825 | // obs->imuOutputs->deltaV = { vec.x, vec.y, vec.z }; | ||
6826 | // } | ||
6827 | // if (vnSensor->_binaryOutputRegister.at(b).commonField & vn::protocol::uart::CommonGroup::COMMONGROUP_INSSTATUS) | ||
6828 | // { | ||
6829 | // if (!obs->insOutputs) | ||
6830 | // { | ||
6831 | // obs->insOutputs = std::make_shared<NAV::vendor::vectornav::InsOutputs>(); | ||
6832 | // obs->insOutputs->insField |= vnSensor->_binaryOutputRegister.at(b).insField; | ||
6833 | // } | ||
6834 | // obs->insOutputs->insField |= vn::protocol::uart::InsGroup::INSGROUP_INSSTATUS; | ||
6835 | // obs->insOutputs->insStatus = p.extractUint16(); | ||
6836 | // } | ||
6837 | // if (vnSensor->_binaryOutputRegister.at(b).commonField & vn::protocol::uart::CommonGroup::COMMONGROUP_TIMESYNCIN) | ||
6838 | // { | ||
6839 | // if (!obs->timeOutputs) | ||
6840 | // { | ||
6841 | // obs->timeOutputs = std::make_shared<NAV::vendor::vectornav::TimeOutputs>(); | ||
6842 | // obs->timeOutputs->timeField |= vnSensor->_binaryOutputRegister.at(b).timeField; | ||
6843 | // } | ||
6844 | // obs->timeOutputs->timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_SYNCINCNT; | ||
6845 | // obs->timeOutputs->syncInCnt = p.extractUint32(); | ||
6846 | // } | ||
6847 | // if (vnSensor->_binaryOutputRegister.at(b).commonField & vn::protocol::uart::CommonGroup::COMMONGROUP_TIMEGPSPPS) | ||
6848 | // { | ||
6849 | // if (!obs->timeOutputs) | ||
6850 | // { | ||
6851 | // obs->timeOutputs = std::make_shared<NAV::vendor::vectornav::TimeOutputs>(); | ||
6852 | // obs->timeOutputs->timeField |= vnSensor->_binaryOutputRegister.at(b).timeField; | ||
6853 | // } | ||
6854 | // obs->timeOutputs->timeField |= vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEGPSPPS; | ||
6855 | // obs->timeOutputs->timePPS = p.extractUint64(); | ||
6856 | // } | ||
6857 | // } | ||
6858 | |||
6859 | // Group 2 (Time) | ||
6860 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).timeField != vn::protocol::uart::TimeGroup::TIMEGROUP_NONE) | |
6861 | { | ||
6862 | ✗ | if (!obs->timeOutputs) | |
6863 | { | ||
6864 | ✗ | obs->timeOutputs = std::make_shared<NAV::vendor::vectornav::TimeOutputs>(); | |
6865 | ✗ | obs->timeOutputs->timeField |= vnSensor->_binaryOutputRegister.at(b).timeField; | |
6866 | } | ||
6867 | |||
6868 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) | |
6869 | { | ||
6870 | ✗ | obs->timeOutputs->timeStartup = p.extractUint64(); | |
6871 | } | ||
6872 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEGPS) | |
6873 | { | ||
6874 | ✗ | obs->timeOutputs->timeGps = p.extractUint64(); | |
6875 | } | ||
6876 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW) | |
6877 | { | ||
6878 | ✗ | obs->timeOutputs->gpsTow = p.extractUint64(); | |
6879 | } | ||
6880 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK) | |
6881 | { | ||
6882 | ✗ | obs->timeOutputs->gpsWeek = p.extractUint16(); | |
6883 | } | ||
6884 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESYNCIN) | |
6885 | { | ||
6886 | ✗ | obs->timeOutputs->timeSyncIn = p.extractUint64(); | |
6887 | } | ||
6888 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEGPSPPS) | |
6889 | { | ||
6890 | ✗ | obs->timeOutputs->timePPS = p.extractUint64(); | |
6891 | } | ||
6892 | // if (vnSensor->_binaryOutputRegister.at(b).timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEUTC) | ||
6893 | // { | ||
6894 | // obs->timeOutputs->timeUtc.year = p.extractInt8(); | ||
6895 | // obs->timeOutputs->timeUtc.month = p.extractUint8(); | ||
6896 | // obs->timeOutputs->timeUtc.day = p.extractUint8(); | ||
6897 | // obs->timeOutputs->timeUtc.hour = p.extractUint8(); | ||
6898 | // obs->timeOutputs->timeUtc.min = p.extractUint8(); | ||
6899 | // obs->timeOutputs->timeUtc.sec = p.extractUint8(); | ||
6900 | // obs->timeOutputs->timeUtc.ms = p.extractUint16(); | ||
6901 | // } | ||
6902 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_SYNCINCNT) | |
6903 | { | ||
6904 | ✗ | obs->timeOutputs->syncInCnt = p.extractUint32(); | |
6905 | } | ||
6906 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_SYNCOUTCNT) | |
6907 | { | ||
6908 | ✗ | obs->timeOutputs->syncOutCnt = p.extractUint32(); | |
6909 | } | ||
6910 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS) | |
6911 | { | ||
6912 | ✗ | obs->timeOutputs->timeStatus = p.extractUint8(); | |
6913 | } | ||
6914 | } | ||
6915 | // Group 3 (IMU) | ||
6916 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).imuField != vn::protocol::uart::ImuGroup::IMUGROUP_NONE) | |
6917 | { | ||
6918 | ✗ | if (!obs->imuOutputs) | |
6919 | { | ||
6920 | ✗ | obs->imuOutputs = std::make_shared<NAV::vendor::vectornav::ImuOutputs>(); | |
6921 | ✗ | obs->imuOutputs->imuField |= vnSensor->_binaryOutputRegister.at(b).imuField; | |
6922 | } | ||
6923 | |||
6924 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).imuField & vn::protocol::uart::ImuGroup::IMUGROUP_IMUSTATUS) | |
6925 | { | ||
6926 | ✗ | obs->imuOutputs->imuStatus = p.extractUint16(); | |
6927 | } | ||
6928 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPMAG) | |
6929 | { | ||
6930 | ✗ | auto vec = p.extractVec3f(); | |
6931 | ✗ | obs->imuOutputs->uncompMag = { vec.x, vec.y, vec.z }; | |
6932 | } | ||
6933 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPACCEL) | |
6934 | { | ||
6935 | ✗ | auto vec = p.extractVec3f(); | |
6936 | ✗ | obs->imuOutputs->uncompAccel = { vec.x, vec.y, vec.z }; | |
6937 | } | ||
6938 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).imuField & vn::protocol::uart::ImuGroup::IMUGROUP_UNCOMPGYRO) | |
6939 | { | ||
6940 | ✗ | auto vec = p.extractVec3f(); | |
6941 | ✗ | obs->imuOutputs->uncompGyro = { vec.x, vec.y, vec.z }; | |
6942 | } | ||
6943 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).imuField & vn::protocol::uart::ImuGroup::IMUGROUP_TEMP) | |
6944 | { | ||
6945 | ✗ | obs->imuOutputs->temp = p.extractFloat(); | |
6946 | } | ||
6947 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).imuField & vn::protocol::uart::ImuGroup::IMUGROUP_PRES) | |
6948 | { | ||
6949 | ✗ | obs->imuOutputs->pres = p.extractFloat(); | |
6950 | } | ||
6951 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTATHETA) | |
6952 | { | ||
6953 | ✗ | obs->imuOutputs->deltaTime = p.extractFloat(); | |
6954 | ✗ | auto vec = p.extractVec3f(); | |
6955 | ✗ | obs->imuOutputs->deltaTheta = { vec.x, vec.y, vec.z }; | |
6956 | } | ||
6957 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).imuField & vn::protocol::uart::ImuGroup::IMUGROUP_DELTAVEL) | |
6958 | { | ||
6959 | ✗ | auto vec = p.extractVec3f(); | |
6960 | ✗ | obs->imuOutputs->deltaV = { vec.x, vec.y, vec.z }; | |
6961 | } | ||
6962 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).imuField & vn::protocol::uart::ImuGroup::IMUGROUP_MAG) | |
6963 | { | ||
6964 | ✗ | auto vec = p.extractVec3f(); | |
6965 | ✗ | obs->imuOutputs->mag = { vec.x, vec.y, vec.z }; | |
6966 | } | ||
6967 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ACCEL) | |
6968 | { | ||
6969 | ✗ | auto vec = p.extractVec3f(); | |
6970 | ✗ | obs->imuOutputs->accel = { vec.x, vec.y, vec.z }; | |
6971 | } | ||
6972 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).imuField & vn::protocol::uart::ImuGroup::IMUGROUP_ANGULARRATE) | |
6973 | { | ||
6974 | ✗ | auto vec = p.extractVec3f(); | |
6975 | ✗ | obs->imuOutputs->angularRate = { vec.x, vec.y, vec.z }; | |
6976 | } | ||
6977 | } | ||
6978 | // Group 4 (GNSS1) | ||
6979 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gpsField != vn::protocol::uart::GpsGroup::GPSGROUP_NONE) | |
6980 | { | ||
6981 | ✗ | if (!obs->gnss1Outputs) | |
6982 | { | ||
6983 | ✗ | obs->gnss1Outputs = std::make_shared<NAV::vendor::vectornav::GnssOutputs>(); | |
6984 | ✗ | obs->gnss1Outputs->gnssField |= vnSensor->_binaryOutputRegister.at(b).gpsField; | |
6985 | } | ||
6986 | |||
6987 | // if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_UTC) | ||
6988 | // { | ||
6989 | // obs->gnss1Outputs->timeUtc.year = p.extractInt8(); | ||
6990 | // obs->gnss1Outputs->timeUtc.month = p.extractUint8(); | ||
6991 | // obs->gnss1Outputs->timeUtc.day = p.extractUint8(); | ||
6992 | // obs->gnss1Outputs->timeUtc.hour = p.extractUint8(); | ||
6993 | // obs->gnss1Outputs->timeUtc.min = p.extractUint8(); | ||
6994 | // obs->gnss1Outputs->timeUtc.sec = p.extractUint8(); | ||
6995 | // obs->gnss1Outputs->timeUtc.ms = p.extractUint16(); | ||
6996 | // } | ||
6997 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_TOW) | |
6998 | { | ||
6999 | ✗ | obs->gnss1Outputs->tow = p.extractUint64(); | |
7000 | } | ||
7001 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_WEEK) | |
7002 | { | ||
7003 | ✗ | obs->gnss1Outputs->week = p.extractUint16(); | |
7004 | } | ||
7005 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_NUMSATS) | |
7006 | { | ||
7007 | ✗ | obs->gnss1Outputs->numSats = p.extractUint8(); | |
7008 | } | ||
7009 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_FIX) | |
7010 | { | ||
7011 | ✗ | obs->gnss1Outputs->fix = p.extractUint8(); | |
7012 | } | ||
7013 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_POSLLA) | |
7014 | { | ||
7015 | ✗ | auto vec = p.extractVec3d(); | |
7016 | ✗ | obs->gnss1Outputs->posLla = { vec.x, vec.y, vec.z }; | |
7017 | } | ||
7018 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_POSECEF) | |
7019 | { | ||
7020 | ✗ | auto vec = p.extractVec3d(); | |
7021 | ✗ | obs->gnss1Outputs->posEcef = { vec.x, vec.y, vec.z }; | |
7022 | } | ||
7023 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_VELNED) | |
7024 | { | ||
7025 | ✗ | auto vec = p.extractVec3f(); | |
7026 | ✗ | obs->gnss1Outputs->velNed = { vec.x, vec.y, vec.z }; | |
7027 | } | ||
7028 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_VELECEF) | |
7029 | { | ||
7030 | ✗ | auto vec = p.extractVec3f(); | |
7031 | ✗ | obs->gnss1Outputs->velEcef = { vec.x, vec.y, vec.z }; | |
7032 | } | ||
7033 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_POSU) | |
7034 | { | ||
7035 | ✗ | auto vec = p.extractVec3f(); | |
7036 | ✗ | obs->gnss1Outputs->posU = { vec.x, vec.y, vec.z }; | |
7037 | } | ||
7038 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_VELU) | |
7039 | { | ||
7040 | ✗ | obs->gnss1Outputs->velU = p.extractFloat(); | |
7041 | } | ||
7042 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_TIMEU) | |
7043 | { | ||
7044 | ✗ | obs->gnss1Outputs->timeU = p.extractFloat(); | |
7045 | } | ||
7046 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO) | |
7047 | { | ||
7048 | ✗ | obs->gnss1Outputs->timeInfo.status = p.extractUint8(); | |
7049 | ✗ | obs->gnss1Outputs->timeInfo.leapSeconds = p.extractInt8(); | |
7050 | } | ||
7051 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_DOP) | |
7052 | { | ||
7053 | ✗ | obs->gnss1Outputs->dop.gDop = p.extractFloat(); | |
7054 | ✗ | obs->gnss1Outputs->dop.pDop = p.extractFloat(); | |
7055 | ✗ | obs->gnss1Outputs->dop.tDop = p.extractFloat(); | |
7056 | ✗ | obs->gnss1Outputs->dop.vDop = p.extractFloat(); | |
7057 | ✗ | obs->gnss1Outputs->dop.hDop = p.extractFloat(); | |
7058 | ✗ | obs->gnss1Outputs->dop.nDop = p.extractFloat(); | |
7059 | ✗ | obs->gnss1Outputs->dop.eDop = p.extractFloat(); | |
7060 | } | ||
7061 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_SATINFO) | |
7062 | { | ||
7063 | ✗ | obs->gnss1Outputs->satInfo.numSats = p.extractUint8(); | |
7064 | ✗ | p.extractUint8(); // Reserved for future use | |
7065 | |||
7066 | LOG_DATA("{}: SatInfo: numSats {}", vnSensor->nameId(), obs->gnss1Outputs->satInfo.numSats); | ||
7067 | ✗ | for (size_t i = 0; i < obs->gnss1Outputs->satInfo.numSats; i++) | |
7068 | { | ||
7069 | ✗ | auto sys = p.extractInt8(); | |
7070 | ✗ | auto svId = p.extractUint8(); | |
7071 | ✗ | auto flags = p.extractUint8(); | |
7072 | ✗ | auto cno = p.extractUint8(); | |
7073 | ✗ | auto qi = p.extractUint8(); | |
7074 | ✗ | auto el = p.extractInt8(); | |
7075 | ✗ | auto az = p.extractInt16(); | |
7076 | ✗ | obs->gnss1Outputs->satInfo.satellites.emplace_back(sys, svId, flags, cno, qi, el, az); | |
7077 | LOG_DATA("{}: SatInfo: sys {}, svId {}, flags {}, cno {}, qi {}, el {}, az {}", vnSensor->nameId(), | ||
7078 | sys, svId, flags, cno, qi, el, az); | ||
7079 | } | ||
7080 | } | ||
7081 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gpsField & vn::protocol::uart::GpsGroup::GPSGROUP_RAWMEAS) | |
7082 | { | ||
7083 | ✗ | obs->gnss1Outputs->raw.tow = p.extractDouble(); | |
7084 | ✗ | obs->gnss1Outputs->raw.week = p.extractUint16(); | |
7085 | ✗ | obs->gnss1Outputs->raw.numSats = p.extractUint8(); | |
7086 | ✗ | p.extractUint8(); // Reserved for future use | |
7087 | LOG_DATA("{}: RawMeas: tow {}, week {}, numSats {}", vnSensor->nameId(), | ||
7088 | obs->gnss1Outputs->raw.tow, obs->gnss1Outputs->raw.week, obs->gnss1Outputs->raw.numSats); | ||
7089 | |||
7090 | ✗ | for (size_t i = 0; i < obs->gnss1Outputs->raw.numSats; i++) | |
7091 | { | ||
7092 | ✗ | auto sys = p.extractUint8(); | |
7093 | ✗ | auto svId = p.extractUint8(); | |
7094 | ✗ | auto freq = p.extractUint8(); | |
7095 | ✗ | auto chan = p.extractUint8(); | |
7096 | ✗ | auto slot = p.extractInt8(); | |
7097 | ✗ | auto cno = p.extractUint8(); | |
7098 | ✗ | auto flags = p.extractUint16(); | |
7099 | ✗ | auto pr = p.extractDouble(); | |
7100 | ✗ | auto cp = p.extractDouble(); | |
7101 | ✗ | auto dp = p.extractFloat(); | |
7102 | ✗ | obs->gnss1Outputs->raw.satellites.emplace_back(sys, svId, freq, chan, slot, cno, flags, pr, cp, dp); | |
7103 | LOG_DATA("{}: RawMeas: sys {}, svId {}, freq {}, chan {}, slot {}, cno {}, flags {}, pr {}, cp {}, dp {}", | ||
7104 | vnSensor->nameId(), static_cast<int>(sys), static_cast<int>(svId), static_cast<int>(freq), static_cast<int>(chan), | ||
7105 | static_cast<int>(slot), static_cast<int>(cno), static_cast<int>(flags), pr, cp, dp); | ||
7106 | } | ||
7107 | } | ||
7108 | } | ||
7109 | // Group 5 (Attitude) | ||
7110 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).attitudeField != vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_NONE) | |
7111 | { | ||
7112 | ✗ | if (!obs->attitudeOutputs) | |
7113 | { | ||
7114 | ✗ | obs->attitudeOutputs = std::make_shared<NAV::vendor::vectornav::AttitudeOutputs>(); | |
7115 | ✗ | obs->attitudeOutputs->attitudeField |= vnSensor->_binaryOutputRegister.at(b).attitudeField; | |
7116 | } | ||
7117 | |||
7118 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_VPESTATUS) | |
7119 | { | ||
7120 | ✗ | obs->attitudeOutputs->vpeStatus = p.extractUint16(); | |
7121 | } | ||
7122 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YAWPITCHROLL) | |
7123 | { | ||
7124 | ✗ | auto vec = p.extractVec3f(); | |
7125 | ✗ | obs->attitudeOutputs->ypr = { vec.x, vec.y, vec.z }; | |
7126 | } | ||
7127 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_QUATERNION) | |
7128 | { | ||
7129 | ✗ | auto vec = p.extractVec4f(); | |
7130 | ✗ | obs->attitudeOutputs->qtn = { vec.w, vec.x, vec.y, vec.z }; | |
7131 | } | ||
7132 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_DCM) | |
7133 | { | ||
7134 | ✗ | auto col0 = p.extractVec3f(); | |
7135 | ✗ | auto col1 = p.extractVec3f(); | |
7136 | ✗ | auto col2 = p.extractVec3f(); | |
7137 | ✗ | obs->attitudeOutputs->dcm << col0.x, col1.x, col2.x, | |
7138 | ✗ | col0.y, col1.y, col2.y, | |
7139 | ✗ | col0.z, col1.z, col2.z; | |
7140 | } | ||
7141 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_MAGNED) | |
7142 | { | ||
7143 | ✗ | auto vec = p.extractVec3f(); | |
7144 | ✗ | obs->attitudeOutputs->magNed = { vec.x, vec.y, vec.z }; | |
7145 | } | ||
7146 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_ACCELNED) | |
7147 | { | ||
7148 | ✗ | auto vec = p.extractVec3f(); | |
7149 | ✗ | obs->attitudeOutputs->accelNed = { vec.x, vec.y, vec.z }; | |
7150 | } | ||
7151 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELBODY) | |
7152 | { | ||
7153 | ✗ | auto vec = p.extractVec3f(); | |
7154 | ✗ | obs->attitudeOutputs->linearAccelBody = { vec.x, vec.y, vec.z }; | |
7155 | } | ||
7156 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_LINEARACCELNED) | |
7157 | { | ||
7158 | ✗ | auto vec = p.extractVec3f(); | |
7159 | ✗ | obs->attitudeOutputs->linearAccelNed = { vec.x, vec.y, vec.z }; | |
7160 | } | ||
7161 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).attitudeField & vn::protocol::uart::AttitudeGroup::ATTITUDEGROUP_YPRU) | |
7162 | { | ||
7163 | ✗ | auto vec = p.extractVec3f(); | |
7164 | ✗ | obs->attitudeOutputs->yprU = { vec.x, vec.y, vec.z }; | |
7165 | } | ||
7166 | } | ||
7167 | // Group 6 (INS) | ||
7168 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).insField != vn::protocol::uart::InsGroup::INSGROUP_NONE) | |
7169 | { | ||
7170 | ✗ | if (!obs->insOutputs) | |
7171 | { | ||
7172 | ✗ | obs->insOutputs = std::make_shared<NAV::vendor::vectornav::InsOutputs>(); | |
7173 | ✗ | obs->insOutputs->insField |= vnSensor->_binaryOutputRegister.at(b).insField; | |
7174 | } | ||
7175 | |||
7176 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).insField & vn::protocol::uart::InsGroup::INSGROUP_INSSTATUS) | |
7177 | { | ||
7178 | ✗ | obs->insOutputs->insStatus = p.extractUint16(); | |
7179 | } | ||
7180 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).insField & vn::protocol::uart::InsGroup::INSGROUP_POSLLA) | |
7181 | { | ||
7182 | ✗ | auto vec = p.extractVec3d(); | |
7183 | ✗ | obs->insOutputs->posLla = { vec.x, vec.y, vec.z }; | |
7184 | } | ||
7185 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).insField & vn::protocol::uart::InsGroup::INSGROUP_POSECEF) | |
7186 | { | ||
7187 | ✗ | auto vec = p.extractVec3d(); | |
7188 | ✗ | obs->insOutputs->posEcef = { vec.x, vec.y, vec.z }; | |
7189 | } | ||
7190 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).insField & vn::protocol::uart::InsGroup::INSGROUP_VELBODY) | |
7191 | { | ||
7192 | ✗ | auto vec = p.extractVec3f(); | |
7193 | ✗ | obs->insOutputs->velBody = { vec.x, vec.y, vec.z }; | |
7194 | } | ||
7195 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).insField & vn::protocol::uart::InsGroup::INSGROUP_VELNED) | |
7196 | { | ||
7197 | ✗ | auto vec = p.extractVec3f(); | |
7198 | ✗ | obs->insOutputs->velNed = { vec.x, vec.y, vec.z }; | |
7199 | } | ||
7200 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).insField & vn::protocol::uart::InsGroup::INSGROUP_VELECEF) | |
7201 | { | ||
7202 | ✗ | auto vec = p.extractVec3f(); | |
7203 | ✗ | obs->insOutputs->velEcef = { vec.x, vec.y, vec.z }; | |
7204 | } | ||
7205 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).insField & vn::protocol::uart::InsGroup::INSGROUP_MAGECEF) | |
7206 | { | ||
7207 | ✗ | auto vec = p.extractVec3f(); | |
7208 | ✗ | obs->insOutputs->magEcef = { vec.x, vec.y, vec.z }; | |
7209 | } | ||
7210 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).insField & vn::protocol::uart::InsGroup::INSGROUP_ACCELECEF) | |
7211 | { | ||
7212 | ✗ | auto vec = p.extractVec3f(); | |
7213 | ✗ | obs->insOutputs->accelEcef = { vec.x, vec.y, vec.z }; | |
7214 | } | ||
7215 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).insField & vn::protocol::uart::InsGroup::INSGROUP_LINEARACCELECEF) | |
7216 | { | ||
7217 | ✗ | auto vec = p.extractVec3f(); | |
7218 | ✗ | obs->insOutputs->linearAccelEcef = { vec.x, vec.y, vec.z }; | |
7219 | } | ||
7220 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).insField & vn::protocol::uart::InsGroup::INSGROUP_POSU) | |
7221 | { | ||
7222 | ✗ | obs->insOutputs->posU = p.extractFloat(); | |
7223 | } | ||
7224 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).insField & vn::protocol::uart::InsGroup::INSGROUP_VELU) | |
7225 | { | ||
7226 | ✗ | obs->insOutputs->velU = p.extractFloat(); | |
7227 | } | ||
7228 | } | ||
7229 | // Group 7 (GNSS2) | ||
7230 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gps2Field != vn::protocol::uart::GpsGroup::GPSGROUP_NONE) | |
7231 | { | ||
7232 | ✗ | if (!obs->gnss2Outputs) | |
7233 | { | ||
7234 | ✗ | obs->gnss2Outputs = std::make_shared<NAV::vendor::vectornav::GnssOutputs>(); | |
7235 | ✗ | obs->gnss2Outputs->gnssField |= vnSensor->_binaryOutputRegister.at(b).gps2Field; | |
7236 | } | ||
7237 | |||
7238 | // if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_UTC) | ||
7239 | // { | ||
7240 | // obs->gnss2Outputs->timeUtc.year = p.extractInt8(); | ||
7241 | // obs->gnss2Outputs->timeUtc.month = p.extractUint8(); | ||
7242 | // obs->gnss2Outputs->timeUtc.day = p.extractUint8(); | ||
7243 | // obs->gnss2Outputs->timeUtc.hour = p.extractUint8(); | ||
7244 | // obs->gnss2Outputs->timeUtc.min = p.extractUint8(); | ||
7245 | // obs->gnss2Outputs->timeUtc.sec = p.extractUint8(); | ||
7246 | // obs->gnss2Outputs->timeUtc.ms = p.extractUint16(); | ||
7247 | // } | ||
7248 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_TOW) | |
7249 | { | ||
7250 | ✗ | obs->gnss2Outputs->tow = p.extractUint64(); | |
7251 | } | ||
7252 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_WEEK) | |
7253 | { | ||
7254 | ✗ | obs->gnss2Outputs->week = p.extractUint16(); | |
7255 | } | ||
7256 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_NUMSATS) | |
7257 | { | ||
7258 | ✗ | obs->gnss2Outputs->numSats = p.extractUint8(); | |
7259 | } | ||
7260 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_FIX) | |
7261 | { | ||
7262 | ✗ | obs->gnss2Outputs->fix = p.extractUint8(); | |
7263 | } | ||
7264 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_POSLLA) | |
7265 | { | ||
7266 | ✗ | auto vec = p.extractVec3d(); | |
7267 | ✗ | obs->gnss2Outputs->posLla = { vec.x, vec.y, vec.z }; | |
7268 | } | ||
7269 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_POSECEF) | |
7270 | { | ||
7271 | ✗ | auto vec = p.extractVec3d(); | |
7272 | ✗ | obs->gnss2Outputs->posEcef = { vec.x, vec.y, vec.z }; | |
7273 | } | ||
7274 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_VELNED) | |
7275 | { | ||
7276 | ✗ | auto vec = p.extractVec3f(); | |
7277 | ✗ | obs->gnss2Outputs->velNed = { vec.x, vec.y, vec.z }; | |
7278 | } | ||
7279 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_VELECEF) | |
7280 | { | ||
7281 | ✗ | auto vec = p.extractVec3f(); | |
7282 | ✗ | obs->gnss2Outputs->velEcef = { vec.x, vec.y, vec.z }; | |
7283 | } | ||
7284 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_POSU) | |
7285 | { | ||
7286 | ✗ | auto vec = p.extractVec3f(); | |
7287 | ✗ | obs->gnss2Outputs->posU = { vec.x, vec.y, vec.z }; | |
7288 | } | ||
7289 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_VELU) | |
7290 | { | ||
7291 | ✗ | obs->gnss2Outputs->velU = p.extractFloat(); | |
7292 | } | ||
7293 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_TIMEU) | |
7294 | { | ||
7295 | ✗ | obs->gnss2Outputs->timeU = p.extractFloat(); | |
7296 | } | ||
7297 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_TIMEINFO) | |
7298 | { | ||
7299 | ✗ | obs->gnss2Outputs->timeInfo.status = p.extractUint8(); | |
7300 | ✗ | obs->gnss2Outputs->timeInfo.leapSeconds = p.extractInt8(); | |
7301 | } | ||
7302 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_DOP) | |
7303 | { | ||
7304 | ✗ | obs->gnss2Outputs->dop.gDop = p.extractFloat(); | |
7305 | ✗ | obs->gnss2Outputs->dop.pDop = p.extractFloat(); | |
7306 | ✗ | obs->gnss2Outputs->dop.tDop = p.extractFloat(); | |
7307 | ✗ | obs->gnss2Outputs->dop.vDop = p.extractFloat(); | |
7308 | ✗ | obs->gnss2Outputs->dop.hDop = p.extractFloat(); | |
7309 | ✗ | obs->gnss2Outputs->dop.nDop = p.extractFloat(); | |
7310 | ✗ | obs->gnss2Outputs->dop.eDop = p.extractFloat(); | |
7311 | } | ||
7312 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_SATINFO) | |
7313 | { | ||
7314 | ✗ | obs->gnss2Outputs->satInfo.numSats = p.extractUint8(); | |
7315 | ✗ | p.extractUint8(); // Reserved for future use | |
7316 | ✗ | for (size_t i = 0; i < obs->gnss2Outputs->satInfo.numSats; i++) | |
7317 | { | ||
7318 | ✗ | auto sys = p.extractInt8(); | |
7319 | ✗ | auto svId = p.extractUint8(); | |
7320 | ✗ | auto flags = p.extractUint8(); | |
7321 | ✗ | auto cno = p.extractUint8(); | |
7322 | ✗ | auto qi = p.extractUint8(); | |
7323 | ✗ | auto el = p.extractInt8(); | |
7324 | ✗ | auto az = p.extractInt16(); | |
7325 | ✗ | obs->gnss2Outputs->satInfo.satellites.emplace_back(sys, svId, flags, cno, qi, el, az); | |
7326 | } | ||
7327 | } | ||
7328 | ✗ | if (vnSensor->_binaryOutputRegister.at(b).gps2Field & vn::protocol::uart::GpsGroup::GPSGROUP_RAWMEAS) | |
7329 | { | ||
7330 | ✗ | obs->gnss2Outputs->raw.tow = p.extractDouble(); | |
7331 | ✗ | obs->gnss2Outputs->raw.week = p.extractUint16(); | |
7332 | ✗ | obs->gnss2Outputs->raw.numSats = p.extractUint8(); | |
7333 | ✗ | p.extractUint8(); // Reserved for future use | |
7334 | ✗ | for (size_t i = 0; i < obs->gnss2Outputs->raw.numSats; i++) | |
7335 | { | ||
7336 | ✗ | auto sys = p.extractUint8(); | |
7337 | ✗ | auto svId = p.extractUint8(); | |
7338 | ✗ | auto freq = p.extractUint8(); | |
7339 | ✗ | auto chan = p.extractUint8(); | |
7340 | ✗ | auto slot = p.extractInt8(); | |
7341 | ✗ | auto cno = p.extractUint8(); | |
7342 | ✗ | auto flags = p.extractUint16(); | |
7343 | ✗ | auto pr = p.extractDouble(); | |
7344 | ✗ | auto cp = p.extractDouble(); | |
7345 | ✗ | auto dp = p.extractFloat(); | |
7346 | ✗ | obs->gnss2Outputs->raw.satellites.emplace_back(sys, svId, freq, chan, slot, cno, flags, pr, cp, dp); | |
7347 | } | ||
7348 | } | ||
7349 | } | ||
7350 | |||
7351 | ✗ | if (p.getCurExtractLoc() != p.getPacketLength() - 2) // 2 Bytes CRC should be left | |
7352 | { | ||
7353 | ✗ | LOG_DEBUG("{}: Only {} of {} bytes were extracted from the Binary Output {}", vnSensor->nameId(), p.getCurExtractLoc(), p.getPacketLength(), b + 1); | |
7354 | } | ||
7355 | |||
7356 | // --------------------------------------------- Fetch InsTime ----------------------------------------------- | ||
7357 | ✗ | auto updateSyncOut = [vnSensor, obs](const InsTime& ppsTime) { | |
7358 | ✗ | if (vnSensor->_synchronizationControlRegister.syncOutMode == vn::protocol::uart::SYNCOUTMODE_GPSPPS | |
7359 | ✗ | && (obs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_SYNCOUTCNT)) | |
7360 | { | ||
7361 | ✗ | if (obs->timeOutputs->syncOutCnt > 0) | |
7362 | { | ||
7363 | ✗ | if (vnSensor->_timeSyncOut.syncOutCnt == 0) | |
7364 | { | ||
7365 | ✗ | LOG_INFO("{}: Found PPS time {} and is providing it to its connected nodes", vnSensor->nameId(), ppsTime.toYMDHMS()); | |
7366 | } | ||
7367 | ✗ | vnSensor->_timeSyncOut.ppsTime = ppsTime; | |
7368 | ✗ | vnSensor->_timeSyncOut.syncOutCnt = obs->timeOutputs->syncOutCnt; | |
7369 | LOG_DATA("{}: Syncing time {}, pps {}, syncOutCnt {}", | ||
7370 | vnSensor->nameId(), obs->insTime.toGPSweekTow(), | ||
7371 | vnSensor->_timeSyncOut.ppsTime.toGPSweekTow(), vnSensor->_timeSyncOut.syncOutCnt); | ||
7372 | } | ||
7373 | } | ||
7374 | ✗ | }; | |
7375 | |||
7376 | // Group 2 (Time) | ||
7377 | ✗ | if (obs->timeOutputs && (obs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS)) | |
7378 | { | ||
7379 | ✗ | if (obs->timeOutputs->timeStatus.dateOk()) | |
7380 | { | ||
7381 | ✗ | if (obs->timeOutputs->timeStatus.timeOk() | |
7382 | ✗ | && (obs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW) | |
7383 | ✗ | && (obs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK)) | |
7384 | { | ||
7385 | ✗ | obs->insTime = InsTime(InsTime_GPSweekTow(0, obs->timeOutputs->gpsWeek, obs->timeOutputs->gpsTow * 1e-9L)); | |
7386 | ✗ | updateSyncOut(InsTime(0, obs->timeOutputs->gpsWeek, std::floor(obs->timeOutputs->gpsTow * 1e-9L))); | |
7387 | } | ||
7388 | ✗ | else if (obs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMEGPS) | |
7389 | { | ||
7390 | ✗ | auto secondsSinceEpoche = static_cast<long double>(obs->timeOutputs->timeGps) * 1e-9L; | |
7391 | ✗ | auto week = static_cast<uint16_t>(secondsSinceEpoche / static_cast<long double>(InsTimeUtil::SECONDS_PER_DAY * InsTimeUtil::DAYS_PER_WEEK)); | |
7392 | ✗ | auto tow = secondsSinceEpoche - week * InsTimeUtil::SECONDS_PER_DAY * InsTimeUtil::DAYS_PER_WEEK; | |
7393 | |||
7394 | ✗ | obs->insTime = InsTime(InsTime_GPSweekTow(0, week, tow)); | |
7395 | ✗ | updateSyncOut(InsTime(0, week, std::floor(tow))); | |
7396 | } | ||
7397 | } | ||
7398 | } | ||
7399 | |||
7400 | ✗ | if (obs->insTime.empty() // Look for master to give GNSS time | |
7401 | ✗ | && (obs->timeOutputs->timeField & vn::protocol::uart::TIMEGROUP_TIMESYNCIN) // We need syncin time for this | |
7402 | ✗ | && vnSensor->_syncInPin && vnSensor->inputPins.front().isPinLinked()) // Try to get a sync from the master | |
7403 | { | ||
7404 | ✗ | if (auto timeSyncMaster = vnSensor->getInputValue<TimeSync>(0); | |
7405 | ✗ | timeSyncMaster && !timeSyncMaster->v->ppsTime.empty()) | |
7406 | { | ||
7407 | // This can have the following values | ||
7408 | // - -1: PPS -> VN310 message -> VN100 message (which happened before the VN310 message) | ||
7409 | // - 0: PPS -> VN310 message -> VN100 message | ||
7410 | // - 1: PPS -> VN100 message -> VN310 message | ||
7411 | ✗ | int64_t syncCntDiff = obs->timeOutputs->syncInCnt - timeSyncMaster->v->syncOutCnt; | |
7412 | ✗ | obs->insTime = timeSyncMaster->v->ppsTime + std::chrono::nanoseconds(obs->timeOutputs->timeSyncIn) | |
7413 | ✗ | + std::chrono::seconds(syncCntDiff); | |
7414 | LOG_DATA("{}: Syncing time {}, pps {}, syncOutCnt {}, syncInCnt {}, syncCntDiff {}", | ||
7415 | vnSensor->nameId(), obs->insTime.toGPSweekTow(), timeSyncMaster->v->ppsTime.toGPSweekTow(), | ||
7416 | timeSyncMaster->v->syncOutCnt, obs->timeOutputs->syncInCnt, syncCntDiff); | ||
7417 | ✗ | } | |
7418 | } | ||
7419 | |||
7420 | ✗ | if (obs->insTime.empty() | |
7421 | ✗ | && !vnSensor->_lastMessageTime.at(b).empty() | |
7422 | ✗ | && obs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) | |
7423 | { | ||
7424 | ✗ | obs->insTime = vnSensor->_lastMessageTime.at(b) + std::chrono::nanoseconds(obs->timeOutputs->timeStartup - vnSensor->_lastMessageTimeSinceStartup.at(b)); | |
7425 | } | ||
7426 | |||
7427 | ✗ | if (obs->insTime.empty() // Look if other sensors have set a global time | |
7428 | ✗ | && !(obs->timeOutputs // but only if we did not request the time from the sensor via GNSS | |
7429 | ✗ | && (obs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTATUS) | |
7430 | ✗ | && (obs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSTOW) | |
7431 | ✗ | && (obs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_GPSWEEK))) | |
7432 | { | ||
7433 | ✗ | if (InsTime currentTime = util::time::GetCurrentInsTime(); | |
7434 | ✗ | !currentTime.empty()) | |
7435 | { | ||
7436 | ✗ | obs->insTime = currentTime; | |
7437 | } | ||
7438 | } | ||
7439 | |||
7440 | ✗ | if (!obs->insTime.empty()) | |
7441 | { | ||
7442 | ✗ | if (!vnSensor->_lastMessageTime.at(b).empty()) | |
7443 | { | ||
7444 | // FIXME: This seems like a bug in clang-tidy. Check if it is working in future versions of clang-tidy | ||
7445 | // NOLINTNEXTLINE(hicpp-use-nullptr, modernize-use-nullptr) | ||
7446 | ✗ | if (obs->insTime - vnSensor->_lastMessageTime.at(b) >= std::chrono::duration<double>(1.5 * (vnSensor->_binaryOutputRegister.at(b).rateDivisor / IMU_DEFAULT_FREQUENCY))) | |
7447 | { | ||
7448 | ✗ | LOG_WARN("{}: Potentially lost a message. dt = {:.4} s, expect {} s. (Previous message at [{}], current message [{}])", vnSensor->nameId(), | |
7449 | static_cast<double>((obs->insTime - vnSensor->_lastMessageTime.at(b)).count()), | ||
7450 | 1. / IMU_DEFAULT_FREQUENCY * vnSensor->_binaryOutputRegister.at(b).rateDivisor, | ||
7451 | vnSensor->_lastMessageTime.at(b), obs->insTime); | ||
7452 | } | ||
7453 | } | ||
7454 | ✗ | vnSensor->_lastMessageTime.at(b) = obs->insTime; | |
7455 | ✗ | if (obs->timeOutputs->timeField & vn::protocol::uart::TimeGroup::TIMEGROUP_TIMESTARTUP) | |
7456 | { | ||
7457 | ✗ | vnSensor->_lastMessageTimeSinceStartup.at(b) = obs->timeOutputs->timeStartup; | |
7458 | } | ||
7459 | } | ||
7460 | |||
7461 | ✗ | if ((vnSensor->_binaryOutputRegisterMerge == BinaryRegisterMerge::Output1_Output2 && (b == 0 || b == 1)) | |
7462 | ✗ | || (vnSensor->_binaryOutputRegisterMerge == BinaryRegisterMerge::Output1_Output3 && (b == 0 || b == 2)) | |
7463 | ✗ | || (vnSensor->_binaryOutputRegisterMerge == BinaryRegisterMerge::Output2_Output3 && (b == 1 || b == 2))) | |
7464 | { | ||
7465 | ✗ | if (vnSensor->_binaryOutputRegisterMergeObservation == nullptr) | |
7466 | { | ||
7467 | ✗ | std::stringstream sstream; | |
7468 | ✗ | if (!obs->insTime.empty()) | |
7469 | { | ||
7470 | ✗ | sstream << obs->insTime; | |
7471 | } | ||
7472 | else | ||
7473 | { | ||
7474 | ✗ | sstream << obs->timeOutputs->timeStartup; | |
7475 | } | ||
7476 | LOG_DATA("{}: {} - Storing message with time {}", vnSensor->nameId(), b, sstream.str()); | ||
7477 | |||
7478 | ✗ | vnSensor->_binaryOutputRegisterMergeObservation = obs; | |
7479 | ✗ | vnSensor->_binaryOutputRegisterMergeIndex = b; | |
7480 | ✗ | } | |
7481 | else | ||
7482 | { | ||
7483 | ✗ | auto allowedTimeDiff = std::chrono::microseconds(static_cast<int>(0.5 * (vnSensor->_binaryOutputRegister.at(b).rateDivisor / IMU_DEFAULT_FREQUENCY) * 1e6)); | |
7484 | ✗ | if (vnSensor->_binaryOutputRegisterMergeIndex != b | |
7485 | ✗ | && ((!obs->insTime.empty() && !vnSensor->_binaryOutputRegisterMergeObservation->insTime.empty() | |
7486 | ✗ | && (obs->insTime - vnSensor->_binaryOutputRegisterMergeObservation->insTime < allowedTimeDiff)) // NOLINT(hicpp-use-nullptr, modernize-use-nullptr) | |
7487 | ✗ | || (obs->timeOutputs != nullptr && vnSensor->_binaryOutputRegisterMergeObservation->timeOutputs != nullptr | |
7488 | ✗ | && obs->timeOutputs->timeField & vn::protocol::uart::TIMEGROUP_TIMESTARTUP | |
7489 | ✗ | && vnSensor->_binaryOutputRegisterMergeObservation->timeOutputs->timeField & vn::protocol::uart::TIMEGROUP_TIMESTARTUP | |
7490 | ✗ | && (std::chrono::nanoseconds(obs->timeOutputs->timeStartup - vnSensor->_binaryOutputRegisterMergeObservation->timeOutputs->timeStartup) < allowedTimeDiff)))) // NOLINT(hicpp-use-nullptr, modernize-use-nullptr) | |
7491 | { | ||
7492 | // Stored and new observation have same time, so merge them | ||
7493 | ✗ | mergeVectorNavBinaryObservations(obs, vnSensor->_binaryOutputRegisterMergeObservation); | |
7494 | ✗ | vnSensor->_binaryOutputRegisterMergeObservation = nullptr; | |
7495 | |||
7496 | ✗ | std::stringstream sstream; | |
7497 | ✗ | if (!obs->insTime.empty()) | |
7498 | { | ||
7499 | ✗ | sstream << obs->insTime; | |
7500 | } | ||
7501 | else | ||
7502 | { | ||
7503 | ✗ | sstream << obs->timeOutputs->timeStartup; | |
7504 | } | ||
7505 | LOG_DATA("{}: {} - Merged message with time {}", vnSensor->nameId(), b, sstream.str()); | ||
7506 | |||
7507 | ✗ | vnSensor->invokeCallbacks(std::min(b, vnSensor->_binaryOutputRegisterMergeIndex) + 1, obs); | |
7508 | ✗ | } | |
7509 | else | ||
7510 | { | ||
7511 | ✗ | [[maybe_unused]] long double timeDiff = 0.0L; | |
7512 | ✗ | std::stringstream sstreamOld; | |
7513 | ✗ | std::stringstream sstreamNew; | |
7514 | ✗ | if (!obs->insTime.empty() && !vnSensor->_binaryOutputRegisterMergeObservation->insTime.empty()) | |
7515 | { | ||
7516 | ✗ | timeDiff = (obs->insTime - vnSensor->_binaryOutputRegisterMergeObservation->insTime).count(); | |
7517 | ✗ | sstreamOld << vnSensor->_binaryOutputRegisterMergeObservation->insTime; | |
7518 | ✗ | sstreamNew << obs->insTime; | |
7519 | } | ||
7520 | else | ||
7521 | { | ||
7522 | ✗ | sstreamOld << vnSensor->_binaryOutputRegisterMergeObservation->timeOutputs->timeStartup; | |
7523 | ✗ | sstreamNew << obs->timeOutputs->timeStartup; | |
7524 | ✗ | timeDiff = static_cast<double>(obs->timeOutputs->timeStartup | |
7525 | ✗ | - vnSensor->_binaryOutputRegisterMergeObservation->timeOutputs->timeStartup) | |
7526 | ✗ | * 1e-9; | |
7527 | } | ||
7528 | |||
7529 | ✗ | LOG_WARN("{}: Merging failed, because timestamps do not match. Potentially lost a message (diff {} sec, old ({}) {}, new ({}) {})", | |
7530 | vnSensor->nameId(), timeDiff, vnSensor->_binaryOutputRegisterMergeIndex, sstreamOld.str(), b, sstreamNew.str()); | ||
7531 | |||
7532 | // Send out old message and save new one | ||
7533 | ✗ | vnSensor->invokeCallbacks(vnSensor->_binaryOutputRegisterMergeIndex + 1, vnSensor->_binaryOutputRegisterMergeObservation); | |
7534 | ✗ | vnSensor->_binaryOutputRegisterMergeObservation = obs; | |
7535 | ✗ | vnSensor->_binaryOutputRegisterMergeIndex = b; | |
7536 | ✗ | } | |
7537 | } | ||
7538 | ✗ | } | |
7539 | else | ||
7540 | { | ||
7541 | ✗ | if (!obs->insTime.empty()) | |
7542 | { | ||
7543 | LOG_DATA("{}: {} - Normal message with time {}", vnSensor->nameId(), b, obs->insTime); | ||
7544 | } | ||
7545 | // Calls all the callbacks | ||
7546 | ✗ | vnSensor->invokeCallbacks(b + 1, obs); | |
7547 | } | ||
7548 | ✗ | } | |
7549 | } | ||
7550 | } | ||
7551 | ✗ | else if (p.type() == vn::protocol::uart::Packet::TYPE_ASCII) | |
7552 | { | ||
7553 | LOG_DATA("{} received an ASCII Async message: {}", vnSensor->nameId(), p.datastr()); | ||
7554 | ✗ | vnSensor->_asciiOutputBuffer.push_back(p.datastr()); | |
7555 | |||
7556 | ✗ | auto obs = std::make_shared<StringObs>(p.datastr()); | |
7557 | |||
7558 | ✗ | if (InsTime currentTime = util::time::GetCurrentInsTime(); | |
7559 | ✗ | !currentTime.empty()) | |
7560 | { | ||
7561 | ✗ | obs->insTime = currentTime; | |
7562 | } | ||
7563 | // Calls all the callbacks | ||
7564 | ✗ | vnSensor->invokeCallbacks(VectorNavSensor::OUTPUT_PORT_INDEX_ASCII_OUTPUT, obs); | |
7565 | ✗ | } | |
7566 | ✗ | } | |
7567 |