0.4.1
Loading...
Searching...
No Matches
ImuFile.cpp
Go to the documentation of this file.
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 "ImuFile.hpp"
10
11#include "util/Logger.hpp"
12#include "util/StringUtil.hpp"
13
15
17namespace nm = NAV::NodeManager;
19
22
24 : Imu(typeStatic())
25{
26 LOG_TRACE("{}: called", name);
27
28 _hasConfig = true;
29 _guiConfigDefaultWindowSize = { 377, 201 };
30
32 nm::CreateOutputPin(this, "Header Columns", Pin::Type::Object, { "std::vector<std::string>" }, &_headerColumns);
33}
34
36{
37 LOG_TRACE("{}: called", nameId());
38}
39
41{
42 return "ImuFile";
43}
44
45std::string NAV::ImuFile::type() const
46{
47 return typeStatic();
48}
49
51{
52 return "Data Provider";
53}
54
56{
57 if (auto res = FileReader::guiConfig(".csv,.*", { ".csv" }, size_t(id), nameId()))
58 {
59 LOG_DEBUG("{}: Path changed to {}", nameId(), _path);
61 if (res == FileReader::PATH_CHANGED)
62 {
64 }
65 else
66 {
68 }
69 }
70
72
73 // Header info
74 if (ImGui::BeginTable(fmt::format("##ImuHeaders ({})", id.AsPointer()).c_str(), 3,
75 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
76 {
77 ImGui::TableSetupColumn("Time", ImGuiTableColumnFlags_WidthFixed);
78 ImGui::TableSetupColumn("IMU", ImGuiTableColumnFlags_WidthFixed);
79 ImGui::TableSetupColumn("Delta IMU", ImGuiTableColumnFlags_WidthFixed);
80 ImGui::TableHeadersRow();
81
82 auto TextColoredIfExists = [this](int index, const char* displayText, const char* searchText, bool alwaysNormal = false) {
83 ImGui::TableSetColumnIndex(index);
84 if (alwaysNormal
85 || std::ranges::find_if(_headerColumns, [&searchText](const std::string& header) {
86 return header.starts_with(searchText);
87 }) != _headerColumns.end())
88 {
89 ImGui::TextUnformatted(displayText);
90 }
91 else
92 {
93 ImGui::TextDisabled("%s", displayText);
94 }
95 };
96
97 ImGui::TableNextRow();
98 TextColoredIfExists(0, "GpsCycle", "GpsCycle");
99 TextColoredIfExists(1, "Mag", "MagX");
100 TextColoredIfExists(2, "DeltaTime", "DeltaTime");
101 ImGui::TableNextRow();
102 TextColoredIfExists(0, "GpsWeek", "GpsWeek");
103 TextColoredIfExists(1, "Acc", "AccX");
104 TextColoredIfExists(2, "DeltaTheta", "DeltaThetaX");
105 ImGui::TableNextRow();
106 TextColoredIfExists(0, "GpsToW", "GpsToW");
107 TextColoredIfExists(1, "Gyro", "GyroX");
108 TextColoredIfExists(2, "DeltaVel", "DeltaVelX");
109 ImGui::TableNextRow();
110 TextColoredIfExists(0, "TimeStartup", "TimeStartup");
111 TextColoredIfExists(1, "Temperature", "Temperature");
112
113 ImGui::EndTable();
114 }
115}
116
117[[nodiscard]] json NAV::ImuFile::save() const
118{
119 LOG_TRACE("{}: called", nameId());
120
121 json j;
122
123 j["FileReader"] = FileReader::save();
124 j["Imu"] = Imu::save();
125
126 return j;
127}
128
130{
131 LOG_TRACE("{}: called", nameId());
132
133 if (j.contains("FileReader"))
134 {
135 FileReader::restore(j.at("FileReader"));
136 }
137 if (j.contains("Imu"))
138 {
139 Imu::restore(j.at("Imu"));
140 }
141}
142
144{
145 LOG_TRACE("{}: called", nameId());
146
148 {
149 for (auto& col : _headerColumns)
150 {
151 str::replace(col, "GpsTow", "GpsToW");
152 }
153
154 size_t nDelta = 0;
155 for (const auto& col : _headerColumns)
156 {
157 if (col.starts_with("DeltaTime")
158 || col.starts_with("DeltaThetaX") || col.starts_with("DeltaThetaY") || col.starts_with("DeltaThetaZ")
159 || col.starts_with("DeltaVelX") || col.starts_with("DeltaVelY") || col.starts_with("DeltaVelZ"))
160 {
161 nDelta++;
162 }
163 }
164
165 _withDelta = nDelta == 7;
166
167 outputPins[OUTPUT_PORT_INDEX_IMU_OBS].dataIdentifier = _withDelta ? std::vector{ NAV::ImuObsWDelta::type() } : std::vector{ NAV::ImuObs::type() };
168 return true;
169 }
170
172
173 for (auto& link : outputPins[OUTPUT_PORT_INDEX_IMU_OBS].links)
174 {
175 if (auto* pin = link.getConnectedPin())
176 {
177 outputPins[OUTPUT_PORT_INDEX_IMU_OBS].recreateLink(*pin);
178 }
179 }
180
181 return false;
182}
183
185{
186 LOG_TRACE("{}: called", nameId());
187
189}
190
192{
194
195 return true;
196}
197
198std::shared_ptr<const NAV::NodeData> NAV::ImuFile::pollData()
199{
200 std::shared_ptr<ImuObs> obs;
201 if (_withDelta) { obs = std::make_shared<ImuObsWDelta>(_imuPos); }
202 else { obs = std::make_shared<ImuObs>(_imuPos); }
203
204 // Read line
205 std::string line;
206 getline(line);
207 // Remove any starting non text characters
208 line.erase(line.begin(), std::ranges::find_if(line, [](int ch) { return std::isgraph(ch); }));
209
210 if (line.empty())
211 {
212 return nullptr;
213 }
214
215 // Convert line into stream
216 std::stringstream lineStream(line);
217 std::string cell;
218
219 std::optional<uint16_t> gpsCycle = 0;
220 std::optional<uint16_t> gpsWeek;
221 std::optional<long double> gpsToW;
222 std::optional<double> magX;
223 std::optional<double> magY;
224 std::optional<double> magZ;
225 std::optional<double> accelX;
226 std::optional<double> accelY;
227 std::optional<double> accelZ;
228 std::optional<double> gyroX;
229 std::optional<double> gyroY;
230 std::optional<double> gyroZ;
231
232 std::optional<double> deltaTime;
233 std::optional<double> deltaThetaX;
234 std::optional<double> deltaThetaY;
235 std::optional<double> deltaThetaZ;
236 std::optional<double> deltaVelX;
237 std::optional<double> deltaVelY;
238 std::optional<double> deltaVelZ;
239
240 // Split line at comma
241 for (const auto& column : _headerColumns)
242 {
243 if (std::getline(lineStream, cell, ','))
244 {
245 // Remove any trailing non text characters
246 cell.erase(std::ranges::find_if(cell, [](int ch) { return std::iscntrl(ch); }), cell.end());
247
248 if (cell.empty()) { continue; }
249
250 if (column.starts_with("GpsCycle"))
251 {
252 gpsCycle = static_cast<uint16_t>(std::stoul(cell));
253 }
254 else if (column.starts_with("GpsWeek"))
255 {
256 gpsWeek = static_cast<uint16_t>(std::stoul(cell));
257 }
258 else if (column.starts_with("GpsToW"))
259 {
260 gpsToW = std::stold(cell);
261 }
262 else if (column.starts_with("MagX"))
263 {
264 magX = std::stod(cell);
265 }
266 else if (column.starts_with("MagY"))
267 {
268 magY = std::stod(cell);
269 }
270 else if (column.starts_with("MagZ"))
271 {
272 magZ = std::stod(cell);
273 }
274 else if (column.starts_with("AccX"))
275 {
276 accelX = std::stod(cell);
277 }
278 else if (column.starts_with("AccY"))
279 {
280 accelY = std::stod(cell);
281 }
282 else if (column.starts_with("AccZ"))
283 {
284 accelZ = std::stod(cell);
285 }
286 else if (column.starts_with("GyroX"))
287 {
288 gyroX = std::stod(cell);
289 }
290 else if (column.starts_with("GyroY"))
291 {
292 gyroY = std::stod(cell);
293 }
294 else if (column.starts_with("GyroZ"))
295 {
296 gyroZ = std::stod(cell);
297 }
298 else if (column.starts_with("Temperature"))
299 {
300 obs->temperature.emplace(std::stod(cell));
301 }
302 else if (column.starts_with("DeltaTime"))
303 {
304 deltaTime = std::stod(cell);
305 }
306 else if (column.starts_with("DeltaThetaX"))
307 {
308 deltaThetaX = std::stod(cell);
309 }
310 else if (column.starts_with("DeltaThetaY"))
311 {
312 deltaThetaY = std::stod(cell);
313 }
314 else if (column.starts_with("DeltaThetaZ"))
315 {
316 deltaThetaZ = std::stod(cell);
317 }
318 else if (column.starts_with("DeltaVelX"))
319 {
320 deltaVelX = std::stod(cell);
321 }
322 else if (column.starts_with("DeltaVelY"))
323 {
324 deltaVelY = std::stod(cell);
325 }
326 else if (column.starts_with("DeltaVelZ"))
327 {
328 deltaVelZ = std::stod(cell);
329 }
330 }
331 }
332
333 if (_withDelta)
334 {
335 if (deltaTime && deltaThetaX && deltaThetaY && deltaThetaZ && deltaVelX && deltaVelY && deltaVelZ)
336 {
337 if (auto obsWDelta = std::reinterpret_pointer_cast<ImuObsWDelta>(obs))
338 {
339 obsWDelta->dtime = deltaTime.value();
340 obsWDelta->dtheta = { deltaThetaX.value(), deltaThetaY.value(), deltaThetaZ.value() };
341 obsWDelta->dvel = { deltaVelX.value(), deltaVelY.value(), deltaVelZ.value() };
342 }
343 }
344 else
345 {
346 LOG_ERROR("{}: Columns 'DeltaTime', 'DeltaThetaX', 'DeltaThetaY', 'DeltaThetaZ', 'DeltaVelX', 'DeltaVelY', 'DeltaVelZ' are needed.", nameId());
347 return nullptr;
348 }
349 }
350
351 if (!gpsCycle || !gpsWeek || !gpsToW)
352 {
353 LOG_ERROR("{}: Fields 'GpsCycle', 'GpsWeek', 'GpsToW' are needed.", nameId());
354 return nullptr;
355 }
356 if (!accelX || !accelY || !accelZ)
357 {
358 LOG_ERROR("{}: Fields 'AccX', 'AccY', 'AccZ' are needed.", nameId());
359 return nullptr;
360 }
361 if (!gyroX || !gyroY || !gyroZ)
362 {
363 LOG_ERROR("{}: Fields 'GyroX', 'GyroY', 'GyroZ' are needed.", nameId());
364 return nullptr;
365 }
366
367 obs->insTime = InsTime(gpsCycle.value(), gpsWeek.value(), gpsToW.value());
368 obs->p_acceleration = { accelX.value(), accelY.value(), accelZ.value() };
369 obs->p_angularRate = { gyroX.value(), gyroY.value(), gyroZ.value() };
370
371 if (magX && magY && magZ)
372 {
373 obs->p_magneticField.emplace(magX.value(), magY.value(), magZ.value());
374 }
375
377 return obs;
378}
Transformation collection.
Save/Load the Nodes.
nlohmann::json json
json namespace
File Reader for Imu log files.
Data storage class for one VectorNavImu observation.
Parent Class for all IMU Observations.
Utility class for logging to console and file.
#define LOG_DEBUG
Debug information. Should not be called on functions which receive observations (spamming)
Definition Logger.hpp:67
#define LOG_ERROR
Error occurred, which stops part of the program to work, but not everything.
Definition Logger.hpp:73
#define LOG_TRACE
Detailled info to trace the execution of the program. Should not be called on functions which receive...
Definition Logger.hpp:65
Manages all Nodes.
Utility functions for working with std::strings.
bool initialize()
Initialize the file reader.
void restore(const json &j)
Restores the node from a json object.
std::string _path
Path to the file.
@ PATH_CHANGED
The path changed and exists.
std::vector< std::string > _headerColumns
Header Columns of a CSV file.
GuiResult guiConfig(const char *vFilters, const std::vector< std::string > &extensions, size_t id, const std::string &nameId)
ImGui config.
void resetReader()
Moves the read cursor to the start.
auto & getline(std::string &str)
Reads a line from the filestream.
json save() const
Saves the node into a json object.
void deinitialize()
Deinitialize the file reader.
void restore(const json &j) override
Restores the node from a json object.
Definition ImuFile.cpp:129
void deinitialize() override
Deinitialize the node.
Definition ImuFile.cpp:184
std::string type() const override
String representation of the Class Type.
Definition ImuFile.cpp:45
void guiConfig() override
ImGui config window which is shown on double click.
Definition ImuFile.cpp:55
static std::string category()
String representation of the Class Category.
Definition ImuFile.cpp:50
bool resetNode() override
Resets the node. Moves the read cursor to the start.
Definition ImuFile.cpp:191
std::shared_ptr< const NodeData > pollData()
Polls data from the file.
Definition ImuFile.cpp:198
json save() const override
Saves the node into a json object.
Definition ImuFile.cpp:117
static constexpr size_t OUTPUT_PORT_INDEX_IMU_OBS
Flow (ImuObs)
Definition ImuFile.hpp:62
bool initialize() override
Initialize the node.
Definition ImuFile.cpp:143
~ImuFile() override
Destructor.
Definition ImuFile.cpp:35
static std::string typeStatic()
String representation of the Class Type.
Definition ImuFile.cpp:40
ImuFile()
Default constructor.
Definition ImuFile.cpp:23
bool _withDelta
Flag if the header has delta values.
Definition ImuFile.hpp:65
static std::string type()
Returns the type of the data class.
static std::string type()
Returns the type of the data class.
Definition ImuObs.hpp:33
json save() const override
Saves the node into a json object.
Definition Imu.cpp:93
void restore(const json &j) override
Restores the node from a json object.
Definition Imu.cpp:104
void guiConfig() override
ImGui config window which is shown on double click.
Definition Imu.cpp:55
Imu(const Imu &)=delete
Copy constructor.
ImuPos _imuPos
Position and rotation information for conversion from platform to body frame.
Definition Imu.hpp:57
The class is responsible for all time-related tasks.
Definition InsTime.hpp:710
bool doDeinitialize(bool wait=false)
Asks the node worker to deinitialize the node.
Definition Node.cpp:395
ImVec2 _guiConfigDefaultWindowSize
Definition Node.hpp:410
std::vector< OutputPin > outputPins
List of output pins.
Definition Node.hpp:399
std::string nameId() const
Node name and id.
Definition Node.cpp:253
std::string name
Name of the Node.
Definition Node.hpp:395
bool doReinitialize(bool wait=false)
Asks the node worker to reinitialize the node.
Definition Node.cpp:350
void invokeCallbacks(size_t portIndex, const std::shared_ptr< const NodeData > &data)
Calls all registered callbacks on the specified output port.
Definition Node.cpp:180
bool _hasConfig
Flag if the config window should be shown.
Definition Node.hpp:413
OutputPin * CreateOutputPin(Node *node, const char *name, Pin::Type pinType, const std::vector< std::string > &dataIdentifier, OutputPin::PinData data=static_cast< void * >(nullptr), int idx=-1)
Create an Output Pin object.
void ApplyChanges()
Signals that there have been changes to the flow.
static bool replace(std::string &str, const std::string &from, const std::string &to, CaseSensitivity cs=RespectCase)
Replaces the first occurrence of a search pattern with another sequence.
@ Flow
NodeData Trigger.
Definition Pin.hpp:52
@ Object
Generic Object.
Definition Pin.hpp:57