39 return "MultiImuFile";
49 return "Data Provider";
62 ImGui::SetNextItemWidth(columnWidth);
72 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");
85 bool showRotation =
true;
88 ImGui::SetNextItemOpen(showRotation, ImGuiCond_FirstUseEver);
89 if (i == 0) { showRotation =
false; }
90 if (ImGui::TreeNode(fmt::format(
"Imu #{} Position & Rotation##{}", i + 1,
size_t(
id)).c_str()))
92 ImGui::BeginDisabled();
93 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()) };
94 if (ImGui::InputFloat3(fmt::format(
"Position [m]##{}",
size_t(
id)).c_str(), imuPos.data()))
97 _imuPosAll[i]._b_positionIMU_p = Eigen::Vector3d(imuPos.at(0), imuPos.at(1), imuPos.at(2));
101 gui::widgets::HelpMarker(
"Position of the IMU sensor relative to the vehicle center of mass in the body coordinate frame.");
104 std::array<float, 3> imuRot = {
static_cast<float>(eulerAnglesIMU.x()),
static_cast<float>(eulerAnglesIMU.y()),
static_cast<float>(eulerAnglesIMU.z()) };
105 if (ImGui::InputFloat3(fmt::format(
"Rotation [deg]##{}",
size_t(
id)).c_str(), imuRot.data()))
108 imuRot.at(0) = std::max(imuRot.at(0), -179.9999F);
109 imuRot.at(0) = std::min(imuRot.at(0), 180.0F);
110 imuRot.at(1) = std::max(imuRot.at(1), -89.9999F);
111 imuRot.at(1) = std::min(imuRot.at(1), 90.0F);
112 imuRot.at(2) = std::max(imuRot.at(2), -179.9999F);
113 imuRot.at(2) = std::min(imuRot.at(2), 180.0F);
143 if (j.contains(
"FileReader"))
147 if (j.contains(
"imuPos"))
151 if (j.contains(
"nmeaType"))
155 if (j.contains(
"startTime"))
159 if (j.contains(
"delim"))
161 j.at(
"delim").get_to(
_delim);
229 const char* gpzda =
"GPZDA";
230 const char* gpgga =
"GPGGA";
241 line.erase(std::ranges::find_if(line, [](
int ch) {
return std::iscntrl(ch); }), line.end());
243 if ((line.find(gpzda)) != std::string::npos)
255 std::stringstream lineStream(line);
261 if (std::getline(lineStream, cell,
','))
264 cell.erase(std::ranges::find_if(cell, [](
int ch) {
return std::iscntrl(ch); }), cell.end());
267 std::getline(lineStream, cell,
',');
270 if (col ==
"nmeaMsgType")
275 if (col ==
"UTC_HMS")
277 hour = std::stoi(cell.substr(0, 2));
278 min = std::stoi(cell.substr(2, 2));
279 sec = std::stold(cell.substr(4, 5));
284 day = std::stoi(cell);
289 month = std::stoi(cell);
294 year = std::stoi(cell);
304 if (line.find(gpgga) != std::string::npos)
308 else if ((std::find_if(line.begin(), line.begin() + 1, [](
int ch) { return std::isdigit(ch); }) != (std::begin(line) + 1)) && (
_gpggaFound ||
_gpzdaFound))
311 seekg(len, std::ios_base::beg);
318 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());
323 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());
331 std::shared_ptr<ImuObs> obs =
nullptr;
335 obs =
_messages.at(pinIdx).begin()->second;
350 line.erase(line.begin(), std::ranges::find_if(line, [](
int ch) { return std::isgraph(ch); }));
358 std::stringstream lineStream(line);
363 double timeNumerator{};
364 double timeDenominator{};
365 std::optional<double> accelX;
366 std::optional<double> accelY;
367 std::optional<double> accelZ;
368 std::optional<double> gyroX;
369 std::optional<double> gyroY;
370 std::optional<double> gyroZ;
375 if (std::getline(lineStream, cell,
_delim))
378 cell.erase(std::ranges::find_if(cell, [](
int ch) {
return std::iscntrl(ch); }), cell.end());
381 std::getline(lineStream, cell,
' ');
384 if (col ==
"sensorId")
386 sensorId = std::stoul(cell);
388 else if (col ==
"gpsSecond")
390 gpsSecond = std::stod(cell);
396 else if (col ==
"timeNumerator")
398 timeNumerator = std::stod(cell);
400 else if (col ==
"timeDenominator")
402 timeDenominator = std::stod(cell);
404 else if (col ==
"accelX")
406 accelX = 0.001 * std::stod(cell);
408 else if (col ==
"accelY")
410 accelY = 0.001 * std::stod(cell);
412 else if (col ==
"accelZ")
414 accelZ = 0.001 * std::stod(cell);
416 else if (col ==
"gyroX")
418 gyroX =
deg2rad(std::stod(cell) / 131);
420 else if (col ==
"gyroY")
422 gyroY =
deg2rad(std::stod(cell)) / 131;
424 else if (col ==
"gyroZ")
426 gyroZ =
deg2rad(std::stod(cell)) / 131;
431 auto timeStamp = gpsSecond + timeNumerator / timeDenominator -
_startupGpsSecond;
438 obs = std::make_shared<ImuObs>(
_imuPosAll[sensorId - 1]);
440 obs->insTime =
_startTime + std::chrono::duration<double>(timeStamp);
442 if (!accelX || !accelY || !accelZ)
444 LOG_ERROR(
"{}: Fields 'accelX', 'accelY', 'accelZ' are needed.",
nameId());
447 if (!gyroX || !gyroY || !gyroZ)
449 LOG_ERROR(
"{}: Fields 'gyroX', 'gyroY', 'gyroZ' are needed.",
nameId());
453 obs->p_acceleration = { accelX.value(), accelY.value(), accelZ.value() };
454 obs->p_angularRate = { gyroX.value(), gyroY.value(), gyroZ.value() };
456 if (sensorId - 1 != pinIdx)
459 _messages.at(sensorId - 1).insert(std::make_pair(obs->insTime, obs));
466 _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.
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.
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.
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.