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