41 return "MultiImuFile";
51 return "Data Provider";
64 ImGui::SetNextItemWidth(columnWidth);
74 gui::widgets::HelpMarker(
"Until June 2023, NMEA messages in the Multi-IMU file's header were of the 'GPGGA' type. Since this type does not provide an absolute time reference, it was changed to 'GPZDA'.\n\n");
87 bool showRotation =
true;
90 ImGui::SetNextItemOpen(showRotation, ImGuiCond_FirstUseEver);
91 if (i == 0) { showRotation =
false; }
92 if (ImGui::TreeNode(fmt::format(
"Imu #{} Position & Rotation##{}", i + 1,
size_t(
id)).c_str()))
94 ImGui::BeginDisabled();
95 std::array<float, 3> imuPos = {
static_cast<float>(
_imuPosAll[i].b_positionIMU_p().x()),
static_cast<float>(
_imuPosAll[i].b_positionIMU_p().y()),
static_cast<float>(
_imuPosAll[i].b_positionIMU_p().z()) };
96 if (ImGui::InputFloat3(fmt::format(
"Position [m]##{}",
size_t(
id)).c_str(), imuPos.data()))
99 _imuPosAll[i]._b_positionIMU_p = Eigen::Vector3d(imuPos.at(0), imuPos.at(1), imuPos.at(2));
101 ImGui::EndDisabled();
103 gui::widgets::HelpMarker(
"Position of the IMU sensor relative to the vehicle center of mass in the body coordinate frame.");
106 std::array<float, 3> imuRot = {
static_cast<float>(eulerAnglesIMU.x()),
static_cast<float>(eulerAnglesIMU.y()),
static_cast<float>(eulerAnglesIMU.z()) };
107 if (ImGui::InputFloat3(fmt::format(
"Rotation [deg]##{}",
size_t(
id)).c_str(), imuRot.data()))
110 imuRot.at(0) = std::max(imuRot.at(0), -179.9999F);
111 imuRot.at(0) = std::min(imuRot.at(0), 180.0F);
112 imuRot.at(1) = std::max(imuRot.at(1), -89.9999F);
113 imuRot.at(1) = std::min(imuRot.at(1), 90.0F);
114 imuRot.at(2) = std::max(imuRot.at(2), -179.9999F);
115 imuRot.at(2) = std::min(imuRot.at(2), 180.0F);
145 if (j.contains(
"FileReader"))
149 if (j.contains(
"imuPos"))
153 if (j.contains(
"nmeaType"))
157 if (j.contains(
"startTime"))
161 if (j.contains(
"delim"))
163 j.at(
"delim").get_to(
_delim);
231 const char* gpzda =
"GPZDA";
232 const char* gpgga =
"GPGGA";
243 line.erase(std::ranges::find_if(line, [](
int ch) {
return std::iscntrl(ch); }), line.end());
245 if ((line.find(gpzda)) != std::string::npos)
257 std::stringstream lineStream(line);
263 if (std::getline(lineStream, cell,
','))
266 cell.erase(std::ranges::find_if(cell, [](
int ch) {
return std::iscntrl(ch); }), cell.end());
269 std::getline(lineStream, cell,
',');
272 if (col ==
"nmeaMsgType")
277 if (col ==
"UTC_HMS")
279 hour = std::stoi(cell.substr(0, 2));
280 min = std::stoi(cell.substr(2, 2));
281 sec = std::stold(cell.substr(4, 5));
286 day = std::stoi(cell);
291 month = std::stoi(cell);
296 year = std::stoi(cell);
306 if (line.find(gpgga) != std::string::npos)
310 else if ((std::find_if(line.begin(), line.begin() + 1, [](
int ch) { return std::isdigit(ch); }) != (std::begin(line) + 1)) && (
_gpggaFound ||
_gpzdaFound))
313 seekg(len, std::ios_base::beg);
320 LOG_WARN(
"{}: NMEA message type was set to 'GPZDA', but the file contains only 'GPGGA'. Make sure that the absolute time reference is set correctly.",
nameId());
325 LOG_WARN(
"{}: NMEA message type was set to 'GPGGA', but the file contains 'GPZDA'. The absolute time reference was read from the header, not the GUI input.",
nameId());
333 std::shared_ptr<ImuObs> obs =
nullptr;
337 obs =
_messages.at(pinIdx).begin()->second;
352 line.erase(line.begin(), std::ranges::find_if(line, [](
int ch) { return std::isgraph(ch); }));
360 std::stringstream lineStream(line);
365 double timeNumerator{};
366 double timeDenominator{};
367 std::optional<double> accelX;
368 std::optional<double> accelY;
369 std::optional<double> accelZ;
370 std::optional<double> gyroX;
371 std::optional<double> gyroY;
372 std::optional<double> gyroZ;
377 if (std::getline(lineStream, cell,
_delim))
380 cell.erase(std::ranges::find_if(cell, [](
int ch) {
return std::iscntrl(ch); }), cell.end());
383 std::getline(lineStream, cell,
' ');
386 if (col ==
"sensorId")
388 sensorId = std::stoul(cell);
390 else if (col ==
"gpsSecond")
392 gpsSecond = std::stod(cell);
398 else if (col ==
"timeNumerator")
400 timeNumerator = std::stod(cell);
402 else if (col ==
"timeDenominator")
404 timeDenominator = std::stod(cell);
406 else if (col ==
"accelX")
408 accelX = 0.001 * std::stod(cell);
410 else if (col ==
"accelY")
412 accelY = 0.001 * std::stod(cell);
414 else if (col ==
"accelZ")
416 accelZ = 0.001 * std::stod(cell);
418 else if (col ==
"gyroX")
420 gyroX =
deg2rad(std::stod(cell) / 131);
422 else if (col ==
"gyroY")
424 gyroY =
deg2rad(std::stod(cell)) / 131;
426 else if (col ==
"gyroZ")
428 gyroZ =
deg2rad(std::stod(cell)) / 131;
433 auto timeStamp = gpsSecond + timeNumerator / timeDenominator -
_startupGpsSecond;
440 obs = std::make_shared<ImuObs>(
_imuPosAll[sensorId - 1]);
442 obs->insTime =
_startTime + std::chrono::duration<double>(timeStamp);
444 if (!accelX || !accelY || !accelZ)
446 LOG_ERROR(
"{}: Fields 'accelX', 'accelY', 'accelZ' are needed.",
nameId());
449 if (!gyroX || !gyroY || !gyroZ)
451 LOG_ERROR(
"{}: Fields 'gyroX', 'gyroY', 'gyroZ' are needed.",
nameId());
455 obs->p_acceleration = { accelX.value(), accelY.value(), accelZ.value() };
456 obs->p_angularRate = { gyroX.value(), gyroY.value(), gyroZ.value() };
458 if (sensorId - 1 != pinIdx)
461 _messages.at(sensorId - 1).insert(std::make_pair(obs->insTime, obs));
468 _messages.at(pinIdx).insert(std::make_pair(obs->insTime, obs));
Transformation collection.
Combo representing an enumeration.
nlohmann::json json
json namespace
Text Help Marker (?) with Tooltip.
Utility class for logging to console and file.
#define LOG_DEBUG
Debug information. Should not be called on functions which receive observations (spamming)
#define LOG_ERROR
Error occurred, which stops part of the program to work, but not everything.
#define LOG_WARN
Error occurred, but a fallback option exists and program continues to work normally.
#define LOG_TRACE
Detailled info to trace the execution of the program. Should not be called on functions which receive...
File reader for Multi-IMU data log files.
bool initialize()
Initialize the file reader.
void restore(const json &j)
Restores the node from a json object.
auto peek()
Looking ahead in the stream.
bool good() const
Fast error checking.
FileType
File Type Enumeration.
std::filesystem::path getFilepath()
Returns the path of the file.
std::streampos tellg()
Getting the current read position.
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.
auto & seekg(std::streamoff pos, std::ios_base::seekdir dir)
Changing the current read position.
void deinitialize()
Deinitialize the file reader.
The class is responsible for all time-related tasks.
char _delim
Delimiter: ',' for GPZDA and ' ' for GPGGA messages (NMEA)
std::vector< std::string > _headerColumns
Container of header column names.
NmeaType _nmeaType
Selected NMEA type in the GUI.
std::vector< std::string > _columns
Container of column names.
MultiImuFile()
Default constructor.
bool resetNode() override
Resets the node. Moves the read cursor to the start.
size_t _lineCounter
Counter for lines.
std::vector< std::map< InsTime, std::shared_ptr< ImuObs > > > _messages
Read messages. Vector idx: Sensor Id,.
static std::string category()
String representation of the Class Category.
void updateNumberOfOutputPins()
Adds/Deletes Output Pins depending on the variable _nOutputPins.
InsTime _startTime
Absolute start time.
bool _gpggaFound
Flag that indicates whether a 'GPGGA' message was found in the Multi-IMU-Logs header.
std::shared_ptr< const NodeData > pollData(size_t pinIdx, bool peek)
Polls data from the file.
static std::string typeStatic()
String representation of the Class Type.
std::vector< size_t > _messageCnt
Counter for messages.
double _gpsRate
GPS data rate [Hz].
json save() const override
Saves the node into a json object.
void restore(const json &j) override
Restores the node from a json object.
std::vector< ImuPos > _imuPosAll
Container for individual sensor orientations of a Multi-IMU.
gui::widgets::TimeEditFormat _startTimeEditFormat
Time Format to input the init time with.
bool initialize() override
Initialize the node.
size_t _nSensors
Number of connected sensors.
~MultiImuFile() override
Destructor.
InsTime _lastFiltObs
Previous observation (for timestamp)
void guiConfig() override
ImGui config window which is shown on double click.
@ GPGGA
NMEA message type.
@ GPZDA
NMEA message type.
std::string type() const override
String representation of the Class Type.
bool _gpzdaFound
Flag that indicates whether a 'GPZDA' message was found in the Multi-IMU-Logs header.
NAV::FileReader::FileType determineFileType() override
Function to determine the File Type.
void deinitialize() override
Deinitialize the node.
double _startupGpsSecond
First 'gpsSecond', s.t. measurements start at time = 0.
void readHeader() override
Function to read the Header of a file.
bool doDeinitialize(bool wait=false)
Asks the node worker to deinitialize the node.
ImVec2 _guiConfigDefaultWindowSize
std::vector< OutputPin > outputPins
List of output pins.
Node(std::string name)
Constructor.
std::string nameId() const
Node name and id.
std::string name
Name of the Node.
void invokeCallbacks(size_t portIndex, const std::shared_ptr< const NodeData > &data)
Calls all registered callbacks on the specified output port.
bool _hasConfig
Flag if the config window should be shown.
static float windowFontRatio()
Ratio to multiply for GUI window elements.
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.
Eigen::Quaternion< Scalar > b_Quat_p(Scalar mountingAngleX, Scalar mountingAngleY, Scalar mountingAngleZ)
Quaternion for rotations from platform to body frame.
Eigen::Vector3< typename Derived::Scalar > quat2eulerZYX(const Eigen::QuaternionBase< Derived > &q)
Converts the quaternion to Euler rotation angles with rotation sequence ZYX.
@ UTC
Coordinated Universal Time.
constexpr auto deg2rad(const T °)
Convert Degree to Radians.
constexpr auto rad2deg(const T &rad)
Convert Radians to Degree.