INSTINCT Code Coverage Report


Directory: src/
File: Nodes/DataProcessor/Integrator/ImuIntegrator.cpp
Date: 2025-06-02 15:19:59
Exec Total Coverage
Lines: 20 66 30.3%
Functions: 5 13 38.5%
Branches: 19 122 15.6%

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 "ImuIntegrator.hpp"
10
11 #include "util/Logger.hpp"
12
13 #include "NodeData/IMU/ImuObs.hpp"
14 #include "NodeData/IMU/ImuObsWDelta.hpp"
15 #include "NodeData/State/PosVelAtt.hpp"
16
17 #include "Navigation/Constants.hpp"
18 #include "Navigation/Math/Math.hpp"
19
20 #include "internal/gui/widgets/HelpMarker.hpp"
21 #include <imgui_internal.h>
22
23 #include "util/Eigen.hpp"
24
25 #include "NodeRegistry.hpp"
26 #include "internal/NodeManager.hpp"
27 namespace nm = NAV::NodeManager;
28 #include "internal/FlowManager.hpp"
29
30 #include <algorithm>
31
32 113 NAV::ImuIntegrator::ImuIntegrator()
33
3/6
✓ Branch 1 taken 113 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 113 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 113 times.
✗ Branch 9 not taken.
113 : Node(typeStatic())
34 {
35 LOG_TRACE("{}: called", name);
36
37 113 _hasConfig = true;
38 113 _guiConfigDefaultWindowSize = { 422, 146 };
39
40
4/8
✓ Branch 2 taken 113 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 113 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 226 times.
✓ Branch 10 taken 113 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
565 nm::CreateInputPin(this, "ImuObs", Pin::Type::Flow, { NAV::ImuObs::type(), NAV::ImuObsWDelta::type() }, &ImuIntegrator::recvObservation,
41 [](const Node* node, const InputPin& inputPin) {
42 const auto* imuIntegrator = static_cast<const ImuIntegrator*>(node); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
43 return !inputPin.queue.empty() && imuIntegrator->_inertialIntegrator.hasInitialPosition();
44 });
45
4/8
✓ Branch 1 taken 113 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 113 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 113 times.
✓ Branch 9 taken 113 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
339 nm::CreateInputPin(this, "PosVelAttInit", Pin::Type::Flow, { NAV::PosVelAtt::type() }, &ImuIntegrator::recvPosVelAttInit, nullptr, 1);
46
47
4/8
✓ Branch 2 taken 113 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 113 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 113 times.
✓ Branch 10 taken 113 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
452 nm::CreateOutputPin(this, "PosVelAtt", Pin::Type::Flow, { NAV::PosVelAtt::type() });
48 452 }
49
50 228 NAV::ImuIntegrator::~ImuIntegrator()
51 {
52 LOG_TRACE("{}: called", nameId());
53 228 }
54
55 225 std::string NAV::ImuIntegrator::typeStatic()
56 {
57
1/2
✓ Branch 1 taken 225 times.
✗ Branch 2 not taken.
450 return "ImuIntegrator";
58 }
59
60 std::string NAV::ImuIntegrator::type() const
61 {
62 return typeStatic();
63 }
64
65 112 std::string NAV::ImuIntegrator::category()
66 {
67
1/2
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
224 return "Data Processor";
68 }
69
70 void NAV::ImuIntegrator::guiConfig()
71 {
72 if (InertialIntegratorGui(std::to_string(size_t(id)).c_str(), _inertialIntegrator, _preferAccelerationOverDeltaMeasurements))
73 {
74 flow::ApplyChanges();
75 }
76 }
77
78 [[nodiscard]] json NAV::ImuIntegrator::save() const
79 {
80 LOG_TRACE("{}: called", nameId());
81
82 json j;
83
84 j["inertialIntegrator"] = _inertialIntegrator;
85 j["preferAccelerationOverDeltaMeasurements"] = _preferAccelerationOverDeltaMeasurements;
86
87 return j;
88 }
89
90 1 void NAV::ImuIntegrator::restore(json const& j)
91 {
92 LOG_TRACE("{}: called", nameId());
93
94
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (j.contains("inertialIntegrator"))
95 {
96 1 j.at("inertialIntegrator").get_to(_inertialIntegrator);
97 }
98
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (j.contains("preferAccelerationOverDeltaMeasurements"))
99 {
100 1 j.at("preferAccelerationOverDeltaMeasurements").get_to(_preferAccelerationOverDeltaMeasurements);
101 }
102 1 }
103
104 bool NAV::ImuIntegrator::initialize()
105 {
106 LOG_TRACE("{}: called", nameId());
107
108 _inertialIntegrator.reset();
109
110 LOG_DEBUG("ImuIntegrator initialized");
111
112 return true;
113 }
114
115 void NAV::ImuIntegrator::deinitialize()
116 {
117 LOG_TRACE("{}: called", nameId());
118 }
119
120 void NAV::ImuIntegrator::recvObservation(NAV::InputPin::NodeDataQueue& queue, size_t /* pinIdx */)
121 {
122 auto nodeData = queue.extract_front();
123 if (nodeData->insTime.empty())
124 {
125 LOG_ERROR("{}: Can't set new imuObs__t0 because the observation has no time tag (insTime)", nameId());
126 return;
127 }
128
129 std::shared_ptr<NAV::PosVelAtt> integratedPosVelAtt = nullptr;
130
131 if (!_preferAccelerationOverDeltaMeasurements
132 && NAV::NodeRegistry::NodeDataTypeAnyIsChildOf(inputPins.at(INPUT_PORT_INDEX_IMU_OBS).link.getConnectedPin()->dataIdentifier, { ImuObsWDelta::type() }))
133 {
134 auto obs = std::static_pointer_cast<const ImuObsWDelta>(nodeData);
135 LOG_DATA("{}: recvImuObsWDelta at time [{}]", nameId(), obs->insTime.toYMDHMS());
136
137 integratedPosVelAtt = _inertialIntegrator.calcInertialSolutionDelta(obs->insTime, obs->dtime, obs->dvel, obs->dtheta, obs->imuPos, nameId().c_str());
138 }
139 else
140 {
141 auto obs = std::static_pointer_cast<const ImuObs>(nodeData);
142 LOG_DATA("{}: recvImuObs at time [{}]", nameId(), obs->insTime.toYMDHMS());
143
144 integratedPosVelAtt = _inertialIntegrator.calcInertialSolution(obs->insTime, obs->p_acceleration, obs->p_angularRate, obs->imuPos, nameId().c_str());
145 }
146
147 if (integratedPosVelAtt)
148 {
149 LOG_DATA("{}: e_position = {}", nameId(), integratedPosVelAtt->e_position().transpose());
150 LOG_DATA("{}: e_velocity = {}", nameId(), integratedPosVelAtt->e_velocity().transpose());
151 LOG_DATA("{}: rollPitchYaw = {}", nameId(), rad2deg(integratedPosVelAtt->rollPitchYaw()).transpose());
152 invokeCallbacks(OUTPUT_PORT_INDEX_INERTIAL_NAV_SOL, integratedPosVelAtt);
153 }
154 }
155
156 void NAV::ImuIntegrator::recvPosVelAttInit(NAV::InputPin::NodeDataQueue& queue, size_t /* pinIdx */)
157 {
158 auto posVelAtt = std::static_pointer_cast<const PosVelAtt>(queue.extract_front());
159 inputPins[INPUT_PORT_INDEX_POS_VEL_ATT_INIT].queueBlocked = true;
160 inputPins[INPUT_PORT_INDEX_POS_VEL_ATT_INIT].queue.clear();
161
162 LOG_DATA("{}: recvPosVelAttInit at time [{}]", nameId(), posVelAtt->insTime.toYMDHMS());
163
164 if (!_inertialIntegrator.hasInitialPosition())
165 {
166 _inertialIntegrator.setInitialState(*posVelAtt, nameId().c_str());
167 LOG_DATA("{}: e_position = {}", nameId(), posVelAtt->e_position().transpose());
168 LOG_DATA("{}: e_velocity = {}", nameId(), posVelAtt->e_velocity().transpose());
169 LOG_DATA("{}: rollPitchYaw = {}", nameId(), rad2deg(posVelAtt->rollPitchYaw()).transpose());
170
171 invokeCallbacks(OUTPUT_PORT_INDEX_INERTIAL_NAV_SOL, posVelAtt);
172 }
173 }
174