0.5.1
Loading...
Searching...
No Matches
Demo.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 "Demo.hpp"
10#include <cstddef>
11#include <imgui.h>
12#include <optional>
13
14#include "util/Logger.hpp"
15
17
21
23
24#include <chrono>
25#include <thread>
26#include <random>
27
28namespace NAV
29{
30namespace
31{
32InsTime getCurrentInsTime()
33{
34 std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
35 auto* t = std::localtime(&now); // NOLINT(concurrency-mt-unsafe)
36
37 return { static_cast<uint16_t>(t->tm_year + 1900),
38 static_cast<uint16_t>(t->tm_mon),
39 static_cast<uint16_t>(t->tm_mday),
40 static_cast<uint16_t>(t->tm_hour),
41 static_cast<uint16_t>(t->tm_min),
42 static_cast<long double>(t->tm_sec) };
43}
44} // namespace
45
46/// @brief Write info to a json object
47/// @param[out] j Json output
48/// @param[in] data Object to read info from
49static void to_json(json& j, const Demo::DemoData& data) // NOLINT(misc-use-anonymous-namespace)
50{
51 j = json{
52 { "boolean", data.boolean },
53 { "integer", data.integer },
54 };
55}
56/// @brief Read info from a json object
57/// @param[in] j Json variable to read info from
58/// @param[out] data Output object
59static void from_json(const json& j, Demo::DemoData& data) // NOLINT(misc-use-anonymous-namespace)
60{
61 if (j.contains("boolean"))
62 {
63 j.at("boolean").get_to(data.boolean);
64 }
65 if (j.contains("integer"))
66 {
67 j.at("integer").get_to(data.integer);
68 }
69}
70
71} // namespace NAV
72
74 : Node(typeStatic())
75{
76 LOG_TRACE("{}: called", name);
77
78 _onlyRealTime = false; // Set this to true if you have a sensor, network stream, ...
79 _hasConfig = true;
81 _guiConfigDefaultWindowSize = { 630, 410 };
82
83 // Pins are usually created by calling the following functions in the constructor
86
87 // To create or delete pins depending on GUI options we use a function as it needs to be called from multiple places
88 updatePins();
89}
90
92{
93 LOG_TRACE("{}: called", nameId());
94}
95
97{
98 return "Demo";
99}
100
101std::string NAV::Demo::type() const
102{
103 return typeStatic();
104}
105
107{
108 return "Utility";
109}
110
112{
113 if (ImGui::BeginTable("##DemoValues", 3, ImGuiTableFlags_Borders))
114 {
115 ImGui::TableSetupColumn("Enable");
116 ImGui::TableSetupColumn("Input");
117 ImGui::TableSetupColumn("Output");
118 ImGui::TableHeadersRow();
119
120 /* ----------------------------------------------- Delegate ----------------------------------------------- */
121 ImGui::TableNextRow();
122 ImGui::TableSetColumnIndex(0);
123 if (ImGui::Checkbox(fmt::format("Delegate##enable {}", size_t(id)).c_str(), &_enableDelegate))
124 {
125 updatePins();
127 }
128 if (_enableDelegate)
129 {
130 ImGui::TableSetColumnIndex(1);
131 {
132 // The returned type automatically blocks editing on the other side of the link. Like a scoped_lock for mutexes
133 auto connectedNode = getInputValue<Demo>(getPinIdx(DemoPins::Delegate).value());
134 ImGui::Text("Delegate: %s", connectedNode ? connectedNode->v->nameId().c_str() : "N/A");
135 }
136 }
137 /* ------------------------------------------------ Flow ------------------------------------------------ */
138 ImGui::TableNextRow();
139 ImGui::TableSetColumnIndex(0);
140 if (ImGui::Checkbox(fmt::format("Flow##enable {}", size_t(id)).c_str(), &_enableFlow))
141 {
142 updatePins();
144 }
145 if (_enableFlow)
146 {
147 ImGui::TableSetColumnIndex(1);
148 ImGui::Text("Flow Data Count: %d", _receivedDataCnt);
149 ImGui::TableSetColumnIndex(2);
150 if (ImGui::Checkbox(fmt::format("Simulate File Reader##{}", size_t(id)).c_str(), &_fileReaderInsteadSensor))
151 {
153 {
154 if (_timer.is_running()) { _timer.stop(); }
155 }
156 else
157 {
158 if (isInitialized() && !_timer.is_running())
159 {
160 int outputInterval = static_cast<int>(1.0 / static_cast<double>(_outputFrequency) * 1000.0);
161 _timer.start(outputInterval, readSensorDataThread, this);
162 }
163 }
166 }
168 {
169 ImGui::SetNextItemWidth(100.0F);
170 if (ImGui::InputInt(fmt::format("FileReader Obs Count##{}", size_t(id)).c_str(), &_nPollData))
171 {
173 }
174 }
175 else
176 {
177 if (ImGui::SliderInt(fmt::format("Frequency##{}", size_t(id)).c_str(), &_outputFrequency, 1, 10))
178 {
179 int outputInterval = static_cast<int>(1.0 / static_cast<double>(_outputFrequency) * 1000.0);
180 _timer.setInterval(outputInterval);
182 }
183 }
184 }
185 /* ------------------------------------------------- Bool ------------------------------------------------- */
186 ImGui::TableNextRow();
187 ImGui::TableSetColumnIndex(0);
188 if (ImGui::Checkbox(fmt::format("Bool##enable {}", size_t(id)).c_str(), &_enableBool))
189 {
190 updatePins();
192 }
193 if (_enableBool)
194 {
195 ImGui::TableSetColumnIndex(1);
196 {
197 auto connectedBool = getInputValue<bool>(getPinIdx(DemoPins::Bool).value());
198 ImGui::Text("Bool: %s", connectedBool ? (connectedBool->v ? "true" : "false") : "N/A");
199 }
200
201 ImGui::TableSetColumnIndex(2);
202 {
203 auto guard = requestOutputValueLock(getPinIdx(DemoPins::Bool).value());
204 if (ImGui::Checkbox(fmt::format("Bool##{}", size_t(id)).c_str(), &_valueBool))
205 {
207 }
208 }
209 }
210 /* -------------------------------------------------- Int ------------------------------------------------- */
211 ImGui::TableNextRow();
212 ImGui::TableSetColumnIndex(0);
213 if (ImGui::Checkbox(fmt::format("Int##enable {}", size_t(id)).c_str(), &_enableInt))
214 {
215 updatePins();
217 }
218 if (_enableInt)
219 {
220 ImGui::TableSetColumnIndex(1);
221 if (auto connectedInt = getInputValue<int>(getPinIdx(DemoPins::Int).value()))
222 {
223 ImGui::Text("Int: %d", *connectedInt->v);
224 }
225 else
226 {
227 ImGui::TextUnformatted("Int: N/A");
228 }
229
230 ImGui::TableSetColumnIndex(2);
231 {
232 auto guard = requestOutputValueLock(getPinIdx(DemoPins::Int).value());
233 if (ImGui::InputInt(fmt::format("Int##{}", size_t(id)).c_str(), &_valueInt)) // Returns true if a change was made
234 {
235 // Limit the values to [-2,5]
236 _valueInt = std::max(_valueInt, -2);
237 _valueInt = std::min(_valueInt, 5);
238
240 }
241 }
242 }
243 /* ------------------------------------------------- Float ------------------------------------------------ */
244 ImGui::TableNextRow();
245 ImGui::TableSetColumnIndex(0);
246 if (ImGui::Checkbox(fmt::format("Float##enable {}", size_t(id)).c_str(), &_enableFloat))
247 {
248 updatePins();
250 }
251 if (_enableFloat)
252 {
253 ImGui::TableSetColumnIndex(1);
254 if (auto connectedFloat = getInputValue<float>(getPinIdx(DemoPins::Float).value()))
255 {
256 ImGui::Text("Float: %.3f", *connectedFloat->v);
257 }
258 else
259 {
260 ImGui::TextUnformatted("Float: N/A");
261 }
262
263 ImGui::TableSetColumnIndex(2);
264 {
265 auto guard = requestOutputValueLock(getPinIdx(DemoPins::Float).value());
266 if (ImGui::DragFloat(fmt::format("Float##{}", size_t(id)).c_str(), &_valueFloat))
267 {
269 }
270 }
271 }
272 /* ------------------------------------------------ Double ------------------------------------------------ */
273 ImGui::TableNextRow();
274 ImGui::TableSetColumnIndex(0);
275 if (ImGui::Checkbox(fmt::format("Double##enable {}", size_t(id)).c_str(), &_enableDouble))
276 {
277 updatePins();
279 }
280 if (_enableDouble)
281 {
282 ImGui::TableSetColumnIndex(1);
283 if (auto connectedDouble = getInputValue<double>(getPinIdx(DemoPins::Double).value()))
284 {
285 ImGui::Text("Double : %.3f", *connectedDouble->v);
286 }
287 else
288 {
289 ImGui::TextUnformatted("Double: N/A");
290 }
291
292 ImGui::TableSetColumnIndex(2);
293 {
295 if (ImGui::DragDouble(fmt::format("Double##{}", size_t(id)).c_str(), &_valueDouble))
296 {
298 }
299 }
300 }
301 /* ------------------------------------------------ String ------------------------------------------------ */
302 ImGui::TableNextRow();
303 ImGui::TableSetColumnIndex(0);
304 if (ImGui::Checkbox(fmt::format("String##enable {}", size_t(id)).c_str(), &_enableString))
305 {
306 updatePins();
308 }
309 if (_enableString)
310 {
311 ImGui::TableSetColumnIndex(1);
312 if (auto connectedString = getInputValue<std::string>(getPinIdx(DemoPins::String).value()))
313 {
314 ImGui::Text("String: %s", connectedString->v->c_str());
315 }
316 else
317 {
318 ImGui::TextUnformatted("String: N/A");
319 }
320 ImGui::Text("The String was updated %lu time%s", _stringUpdateCounter, _stringUpdateCounter > 1 || _stringUpdateCounter == 0 ? "s" : "");
321
322 ImGui::TableSetColumnIndex(2);
323 {
324 // Before accessing and changing the value. A lock has to be requested to ensure it is not changed before all linked nodes received the value.
326 if (ImGui::InputText(fmt::format("String##{}", size_t(id)).c_str(), &_valueString))
327 {
329 const auto& outputPin = outputPins[getPinIdx(DemoPins::String).value()];
330 if (outputPin.isPinLinked())
331 {
332 if (!isInitialized()) { LOG_WARN("{}: Notifying connected nodes requires this node to be initialized.", nameId()); }
333 else if (!callbacksEnabled) { LOG_WARN("{}: Notifying connected nodes requires enabled callbacks on this node. Do this by running the flow.", nameId()); }
334 else if (std::ranges::none_of(outputPin.links, [](const OutputPin::OutgoingLink& link) { return link.connectedNode->isInitialized(); }))
335 {
336 LOG_WARN("{}: Notifying connected nodes requires at least one connected node to be initialized.", nameId());
337 }
338 }
339 notifyOutputValueChanged(getPinIdx(DemoPins::String).value(), getCurrentInsTime(), std::move(guard));
340 }
341 }
342 ImGui::SameLine();
343 gui::widgets::HelpMarker("The string notifies about changes.\nInitialize both nodes for this to work.");
344 }
345 /* ------------------------------------------------ Object ------------------------------------------------ */
346 ImGui::TableNextRow();
347 ImGui::TableSetColumnIndex(0);
348 if (ImGui::Checkbox(fmt::format("Object##enable {}", size_t(id)).c_str(), &_enableObject))
349 {
350 updatePins();
352 }
353 if (_enableObject)
354 {
355 ImGui::TableSetColumnIndex(1);
356 if (auto connectedObject = getInputValue<DemoData>(getPinIdx(DemoPins::Object).value()))
357 {
358 ImGui::Text("Object: [%d, %d, %d], %s", connectedObject->v->integer.at(0), connectedObject->v->integer.at(1), connectedObject->v->integer.at(2),
359 connectedObject->v->boolean ? "true" : "false");
360 }
361 else
362 {
363 ImGui::TextUnformatted("Object: N/A");
364 }
365
366 ImGui::TableSetColumnIndex(2);
367 {
369 if (ImGui::InputInt3(fmt::format("##object.integer {}", size_t(id)).c_str(), _valueObject.integer.data()))
370 {
372 }
373 ImGui::SameLine();
374 if (ImGui::Checkbox(fmt::format("Object##{}", size_t(id)).c_str(), &_valueObject.boolean))
375 {
377 }
378 }
379 }
380 /* ------------------------------------------------ Matrix ------------------------------------------------ */
381 ImGui::TableNextRow();
382 ImGui::TableSetColumnIndex(0);
383 if (ImGui::Checkbox(fmt::format("Matrix##enable {}", size_t(id)).c_str(), &_enableMatrix))
384 {
385 updatePins();
387 }
388 if (_enableMatrix)
389 {
390 ImGui::TableSetColumnIndex(1);
391 if (auto connectedMatrix = getInputValue<Eigen::MatrixXd>(getPinIdx(DemoPins::Matrix).value()))
392 {
393 gui::widgets::MatrixView("Current Matrix", connectedMatrix->v, GuiMatrixViewFlags_Header, ImGuiTableFlags_Borders | ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_SizingFixedFit, "%.1f");
394 }
395 else
396 {
397 ImGui::TextUnformatted("Matrix: N/A");
398 }
399
400 ImGui::TableSetColumnIndex(2);
401 {
403 if (gui::widgets::InputMatrix(fmt::format("Init Matrix##{}", size_t(id)).c_str(), &_valueMatrix, GuiMatrixViewFlags_Header, ImGuiTableFlags_Borders | ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_SizingFixedFit, 30.0F, 0.0, 0.0, "%.1f"))
404 {
406 }
407 }
408 }
409
410 ImGui::EndTable();
411 }
412}
413
414[[nodiscard]] json NAV::Demo::save() const
415{
416 LOG_TRACE("{}: called", nameId());
417
418 json j;
419
420 return {
421 { "outputFrequency", _outputFrequency },
422 { "nPollData", _nPollData },
423 { "enableDelegate", _enableDelegate },
424 { "enableFlow", _enableFlow },
425 { "enableBool", _enableBool },
426 { "enableInt", _enableInt },
427 { "enableFloat", _enableFloat },
428 { "enableDouble", _enableDouble },
429 { "enableString", _enableString },
430 { "enableObject", _enableObject },
431 { "enableMatrix", _enableMatrix },
432 { "valueBool", _valueBool },
433 { "valueInt", _valueInt },
434 { "valueFloat", _valueFloat },
435 { "valueDouble", _valueDouble },
436 { "valueString", _valueString },
437 { "valueObject", _valueObject },
438 { "valueMatrix", _valueMatrix },
439 { "fileReaderInsteadSensor", _fileReaderInsteadSensor },
440 };
441}
442
444{
445 LOG_TRACE("{}: called", nameId());
446
447 if (j.contains("outputFrequency")) { j.at("outputFrequency").get_to(_outputFrequency); }
448 if (j.contains("nPollData")) { j.at("nPollData").get_to(_nPollData); }
449 if (j.contains("enableDelegate")) { j.at("enableDelegate").get_to(_enableDelegate); }
450 if (j.contains("enableFlow")) { j.at("enableFlow").get_to(_enableFlow); }
451 if (j.contains("enableBool")) { j.at("enableBool").get_to(_enableBool); }
452 if (j.contains("enableInt")) { j.at("enableInt").get_to(_enableInt); }
453 if (j.contains("enableFloat")) { j.at("enableFloat").get_to(_enableFloat); }
454 if (j.contains("enableDouble")) { j.at("enableDouble").get_to(_enableDouble); }
455 if (j.contains("enableString")) { j.at("enableString").get_to(_enableString); }
456 if (j.contains("enableObject")) { j.at("enableObject").get_to(_enableObject); }
457 if (j.contains("enableMatrix")) { j.at("enableMatrix").get_to(_enableMatrix); }
458 if (j.contains("valueBool")) { j.at("valueBool").get_to(_valueBool); }
459 if (j.contains("valueInt")) { j.at("valueInt").get_to(_valueInt); }
460 if (j.contains("valueFloat")) { j.at("valueFloat").get_to(_valueFloat); }
461 if (j.contains("valueDouble")) { j.at("valueDouble").get_to(_valueDouble); }
462 if (j.contains("valueString")) { j.at("valueString").get_to(_valueString); }
463 if (j.contains("valueObject")) { j.at("valueObject").get_to(_valueObject); }
464 if (j.contains("valueMatrix")) { j.at("valueMatrix").get_to(_valueMatrix); }
465 if (j.contains("fileReaderInsteadSensor"))
466 {
467 j.at("fileReaderInsteadSensor").get_to(_fileReaderInsteadSensor);
469 }
470 updatePins();
471}
472
474{
475 LOG_TRACE("{}: called", nameId());
476
477 // To Show the Initialization in the GUI
478 std::this_thread::sleep_for(std::chrono::milliseconds(2000));
479
481
483
485 {
486 // The Timer is used to simulate a sensor reader
487 int outputInterval = static_cast<int>(1.0 / static_cast<double>(_outputFrequency) * 1000.0);
488 _timer.start(outputInterval, readSensorDataThread, this);
489 }
490
491 return true;
492}
493
495{
496 LOG_TRACE("{}: called", nameId());
497
498 if (_timer.is_running())
499 {
500 _timer.stop();
501 }
502
503 // To Show the Deinitialization in the GUI
504 std::this_thread::sleep_for(std::chrono::milliseconds(1000));
505}
506
508{
509 size_t pinIdx = 0;
510
511 auto updatePin = [&](bool pinExists, bool enabled,
512 const char* pinName, Pin::Type pinType, const std::vector<std::string>& dataIdentifier = {}, // BUG: Bug in clang-format, so we need to disable formatting
513 OutputPin::PinData data = static_cast<void*>(nullptr), // clang-format off
514 void(NAV::Demo::*notifyFunc)(const InsTime&, size_t) = nullptr) { // clang-format on
515 if (!pinExists && enabled)
516 {
517 CreateInputPin(pinName, pinType, dataIdentifier, notifyFunc, static_cast<int>(pinIdx));
518 CreateOutputPin(pinName, pinType, dataIdentifier, data, static_cast<int>(pinIdx));
519 }
520 else if (pinExists && !enabled)
521 {
522 DeleteInputPin(pinIdx);
523 DeleteOutputPin(pinIdx);
524 }
525 if (enabled) { pinIdx++; }
526 };
527
529 "Demo Node", Pin::Type::Delegate, { typeStatic() }, this);
530 // CreateInputPin("Demo Node", Pin::Type::Delegate, { typeStatic() });
531 // CreateOutputPin("", Pin::Type::Delegate, { typeStatic() }, this, 0);
532
533 {
535 if (!pinExists && _enableFlow)
536 {
538 CreateOutputPin("Sensor\nData", Pin::Type::Flow, { NAV::ImuObs::type() });
539 }
540 else if (pinExists && !_enableFlow)
541 {
542 DeleteInputPin(pinIdx);
543 DeleteOutputPin(pinIdx);
544 }
545 if (_enableFlow) { pinIdx++; }
546 }
547
549 "Bool", Pin::Type::Bool, { "" }, &_valueBool);
550 // CreateInputPin("Bool", Pin::Type::Bool);
551 // CreateOutputPin("Bool", Pin::Type::Bool, { "" }, &_valueBool);
552
554 "Int", Pin::Type::Int, { "" }, &_valueInt);
555 // CreateInputPin("Int", Pin::Type::Int);
556 // CreateOutputPin("Int", Pin::Type::Int, { "" }, &_valueInt);
557
559 "Float", Pin::Type::Float, { "Float" }, &_valueFloat);
560 // CreateInputPin("Float", Pin::Type::Float);
561 // CreateOutputPin("Float", Pin::Type::Float, { "" }, &_valueFloat);
562
564 "Double", Pin::Type::Float, { "Double" }, &_valueDouble);
565 // CreateInputPin("Double", Pin::Type::Float);
566 // CreateOutputPin("Double", Pin::Type::Float, { "" }, &_valueDouble);
567
570 // CreateInputPin("String", Pin::Type::String, {}, &Demo::stringUpdatedNotifyFunction);
571 // CreateOutputPin("String", Pin::Type::String, { "" }, &_valueString);
572
574 "Object", Pin::Type::Object, { "Demo::DemoData" }, &_valueObject);
575 // CreateInputPin("Object", Pin::Type::Object, { "Demo::DemoData" });
576 // CreateOutputPin("Object", Pin::Type::Object, { "Demo::DemoData" }, &_valueObject);
577
579 "Matrix", Pin::Type::Matrix, { "Eigen::MatrixXd" }, &_valueMatrix);
580 // CreateInputPin("Matrix", Pin::Type::Matrix, { "Eigen::MatrixXd" });
581 // CreateOutputPin("Matrix", Pin::Type::Matrix, { "Eigen::MatrixXd" }, &_valueMatrix);
582}
583
584std::optional<size_t> NAV::Demo::getPinIdx(DemoPins pinType) const
585{
586 for (size_t i = 0; i < inputPins.size(); i++)
587 {
588 switch (pinType)
589 {
591 if (inputPins.at(i).type == Pin::Type::Delegate) { return i; }
592 break;
593 case DemoPins::Flow:
594 if (inputPins.at(i).type == Pin::Type::Flow) { return i; }
595 break;
596 case DemoPins::Bool:
597 if (inputPins.at(i).type == Pin::Type::Bool) { return i; }
598 break;
599 case DemoPins::Int:
600 if (inputPins.at(i).type == Pin::Type::Int) { return i; }
601 break;
602 case DemoPins::Float:
603 if (inputPins.at(i).type == Pin::Type::Float && inputPins.at(i).dataIdentifier.front() == "Float") { return i; }
604 break;
605 case DemoPins::Double:
606 if (inputPins.at(i).type == Pin::Type::Float && inputPins.at(i).dataIdentifier.front() == "Double") { return i; }
607 break;
608 case DemoPins::String:
609 if (inputPins.at(i).type == Pin::Type::String) { return i; }
610 break;
611 case DemoPins::Object:
612 if (inputPins.at(i).type == Pin::Type::Object) { return i; }
613 break;
614 case DemoPins::Matrix:
615 if (inputPins.at(i).type == Pin::Type::Matrix) { return i; }
616 break;
617 }
618 }
619
620 return std::nullopt;
621}
622
624{
625 LOG_TRACE("{}: called", nameId());
626 // Here you could reset a FileReader
627 _iPollData = 0;
629
630 return true;
631}
632
634{
635 size_t flowPinIdx = getPinIdx(DemoPins::Flow).value();
636 std::vector<ax::NodeEditor::PinId> connectedPins;
637 for (const auto& link : outputPins.at(flowPinIdx).links)
638 {
639 connectedPins.push_back(link.connectedPinId);
640 }
641 DeleteOutputPin(flowPinIdx);
643 {
644 CreateOutputPin("FileReader\n Data", Pin::Type::Flow, { NAV::NodeData::type() }, &Demo::pollData, static_cast<int>(flowPinIdx));
645 }
646 else
647 {
648 CreateOutputPin("Sensor\nData", Pin::Type::Flow, { NAV::ImuObs::type() }, static_cast<void*>(nullptr), static_cast<int>(flowPinIdx));
649 }
650 for (const auto& pinId : connectedPins)
651 {
652 if (auto* targetPin = flow::FindInputPin(pinId))
653 {
654 if (outputPins.at(flowPinIdx).canCreateLink(*targetPin))
655 {
656 outputPins.at(flowPinIdx).createLink(*targetPin);
657 }
658 }
659 }
660}
661
662bool NAV::Demo::onCreateLink([[maybe_unused]] OutputPin& startPin, [[maybe_unused]] InputPin& endPin)
663{
664 LOG_TRACE("{}: called for {} ==> {}", nameId(), size_t(startPin.id), size_t(endPin.id));
665
666 if (_enableFlow && outputPins.at(getPinIdx(DemoPins::Flow).value()).isPinLinked())
667 {
669 }
670
671 return true;
672}
673
674void NAV::Demo::afterDeleteLink([[maybe_unused]] OutputPin& startPin, [[maybe_unused]] InputPin& endPin)
675{
676 LOG_TRACE("{}: called for {} ==> {}", nameId(), size_t(startPin.id), size_t(endPin.id));
677
678 if (_enableFlow && !outputPins.at(getPinIdx(DemoPins::Flow).value()).isPinLinked())
679 {
680 _onlyRealTime = false;
681 }
682}
683
685{
686 std::shared_ptr<const NAV::NodeData> obs = queue.extract_front(); // Either 'extract_front()' or 'pop_front()' needs to be called
688
689 LOG_DEBUG("{}: received {} data at [{} GPST]", nameId(), _receivedDataCnt, obs->insTime.toYMDHMS(GPST));
690}
691
693{
694 auto* node = static_cast<Demo*>(userData);
695
696 if (!node->_enableFlow || !node->getPinIdx(DemoPins::Flow).has_value()) { return; }
697
698 if (!node->outputPins.at(node->getPinIdx(DemoPins::Flow).value()).isPinLinked() || !node->callbacksEnabled)
699 {
700 return;
701 }
702
703 if (node->getMode() == Mode::POST_PROCESSING)
704 {
705 LOG_WARN("{}: Flow contains nodes which can only do post-processing. Sensor output is suppressed.");
706
707 return;
708 }
709
710 auto imuPos = ImuPos();
711 auto obs = std::make_shared<ImuObs>(imuPos);
712
713 std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
714 auto* t = std::gmtime(&now); // NOLINT(concurrency-mt-unsafe)
715
716 obs->insTime = InsTime(static_cast<uint16_t>(t->tm_year + 1900), static_cast<uint16_t>(t->tm_mon) + 1, static_cast<uint16_t>(t->tm_mday),
717 static_cast<uint16_t>(t->tm_hour), static_cast<uint16_t>(t->tm_min), static_cast<long double>(t->tm_sec), GPST);
718
719 std::random_device rd;
720 std::default_random_engine generator(rd());
721
722 std::uniform_real_distribution<double> distribution(-9.0, 9.0);
723 obs->p_acceleration = Eigen::Vector3d(distribution(generator), distribution(generator), distribution(generator));
724
725 distribution = std::uniform_real_distribution<double>(-3.0, 3.0);
726 obs->p_angularRate = Eigen::Vector3d(distribution(generator), distribution(generator), distribution(generator));
727
728 distribution = std::uniform_real_distribution<double>(-1.0, 1.0);
729 obs->p_magneticField = Eigen::Vector3d(distribution(generator), distribution(generator), distribution(generator));
730
731 distribution = std::uniform_real_distribution<double>(15.0, 25.0);
732 obs->temperature = distribution(generator);
733
734 LOG_INFO("{}: Sending Sensor data with time [{} GPST]", node->nameId(), obs->insTime.toYMDHMS(GPST));
735
736 node->invokeCallbacks(node->getPinIdx(DemoPins::Flow).value(), obs);
737}
738
739std::shared_ptr<const NAV::NodeData> NAV::Demo::peekPollData(bool peek)
740{
741 // This function is only an example of how to implement peek/poll logic. It is not used in this node.
742 if (_iPollData >= _nPollData)
743 {
744 return nullptr;
745 }
746
747 if (peek) // Early return with time to let the Node sort the observations
748 {
749 auto obs = std::make_shared<NodeData>(); // Construct the real observation (here in example also from type NodeData)
750 obs->insTime = InsTime(2000, 1, 1, 0, 0, _iPollData);
751 return obs;
752 }
753
754 auto obs = std::make_shared<NodeData>(); // Construct the real observation (here in example also from type NodeData)
755 obs->insTime = InsTime(2000, 1, 1, 0, 0, _iPollData);
756
757 _iPollData++;
758 // Calls all the callbacks
760
761 return obs;
762}
763
764std::shared_ptr<const NAV::NodeData> NAV::Demo::pollData()
765{
766 if (_iPollData >= _nPollData)
767 {
768 return nullptr; // Tells the node that the last message was read
769 }
770
771 auto obs = std::make_shared<NodeData>(); // Construct the real observation (here in example also from type NodeData)
772 obs->insTime = InsTime(2000, 1, 1, 0, 0, _iPollData);
773
774 _iPollData++;
775
776 invokeCallbacks(getPinIdx(DemoPins::Flow).value(), obs); // Calls all the callbacks
777 return obs;
778}
779
780void NAV::Demo::stringUpdatedNotifyFunction([[maybe_unused]] const InsTime& insTime, size_t pinIdx)
781{
783
784 if (auto value = getInputValue<std::string>(pinIdx))
785 {
786 LOG_DEBUG("String value updated to '{}' at time {}", *value->v, insTime);
787 }
788}
Demo Node which demonstrates all capabilities.
Save/Load the Nodes.
nlohmann::json json
json namespace
Text Help Marker (?) with Tooltip.
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_WARN
Error occurred, but a fallback option exists and program continues to work normally.
Definition Logger.hpp:71
#define LOG_INFO
Info to the user on the state of the program.
Definition Logger.hpp:69
#define LOG_TRACE
Detailled info to trace the execution of the program. Should not be called on functions which receive...
Definition Logger.hpp:65
Widgets related to Matrices.
@ GuiMatrixViewFlags_Header
Print all Header.
Definition Matrix.hpp:29
Demonstrates the basic GUI functionality of nodes.
Definition Demo.hpp:28
bool _fileReaderInsteadSensor
Whether to have a file reader instead of a sensor output pin.
Definition Demo.hpp:133
int _iPollData
Counter for data Reading.
Definition Demo.hpp:148
bool _valueBool
Value which is represented over the Bool pin.
Definition Demo.hpp:162
bool _enableInt
Switch to enable the int pin.
Definition Demo.hpp:155
void afterDeleteLink(OutputPin &startPin, InputPin &endPin) override
Called when a link was deleted.
Definition Demo.cpp:674
bool onCreateLink(OutputPin &startPin, InputPin &endPin) override
Called when a new link is to be established.
Definition Demo.cpp:662
CallbackTimer _timer
Timer object to handle async data requests.
Definition Demo.hpp:136
bool _enableFlow
Switch to enable the flow pin.
Definition Demo.hpp:153
int _receivedDataCnt
Counter how often data was received.
Definition Demo.hpp:145
bool _enableDouble
Switch to enable the double pin.
Definition Demo.hpp:157
std::optional< size_t > getPinIdx(DemoPins pinType) const
Calculates the pin index for the given type.
Definition Demo.cpp:584
bool _enableObject
Switch to enable the object pin.
Definition Demo.hpp:159
float _valueFloat
Value which is represented over the Float pin.
Definition Demo.hpp:164
bool _enableString
Switch to enable the string pin.
Definition Demo.hpp:158
bool initialize() override
Initialize the node.
Definition Demo.cpp:473
bool _enableFloat
Switch to enable the float pin.
Definition Demo.hpp:156
void updatePins()
Update the pins depending on the GUI.
Definition Demo.cpp:507
bool _enableBool
Switch to enable the bool pin.
Definition Demo.hpp:154
size_t _stringUpdateCounter
Counter of how often the string was updated.
Definition Demo.hpp:169
bool resetNode() override
Resets the node. It is guaranteed that the node is initialized when this is called.
Definition Demo.cpp:623
static void readSensorDataThread(void *userData)
Function which performs the async data reading.
Definition Demo.cpp:692
void stringUpdatedNotifyFunction(const InsTime &insTime, size_t pinIdx)
Function to call when the string is updated.
Definition Demo.cpp:780
void restore(const json &j) override
Restores the node from a json object.
Definition Demo.cpp:443
void updateOutputFlowPin()
Updates the output flow pin depending on the GUI selection.
Definition Demo.cpp:633
std::shared_ptr< const NodeData > peekPollData(bool peek=false)
Polls data from the file. This function is needed, if we have multiple output pins,...
Definition Demo.cpp:739
static std::string typeStatic()
String representation of the Class Type.
Definition Demo.cpp:96
int _valueInt
Value which is represented over the Int pin.
Definition Demo.hpp:163
Eigen::MatrixXd _valueMatrix
Value which is represented over the Matrix pin.
Definition Demo.hpp:168
void deinitialize() override
Deinitialize the node.
Definition Demo.cpp:494
int _nPollData
Amount of Observations to be read.
Definition Demo.hpp:150
std::shared_ptr< const NodeData > pollData()
Polls data from the file.
Definition Demo.cpp:764
bool _enableMatrix
Switch to enable the matrix pin.
Definition Demo.hpp:160
std::string type() const override
String representation of the Class Type.
Definition Demo.cpp:101
DemoPins
Pin types used in this demo.
Definition Demo.hpp:97
@ Int
Integer numbers.
Definition Demo.hpp:101
@ Float
Float numbers.
Definition Demo.hpp:102
@ Delegate
Delegate pins giving access to the complete connected node.
Definition Demo.hpp:98
@ String
Strings.
Definition Demo.hpp:104
@ Object
Custom objects.
Definition Demo.hpp:105
@ Bool
Booleans.
Definition Demo.hpp:100
@ Double
Double numbers.
Definition Demo.hpp:103
@ Flow
Flow pins transmitting data as timestamped shared pointers.
Definition Demo.hpp:99
@ Matrix
Matrix objects.
Definition Demo.hpp:106
int _outputFrequency
Output frequency for the simulated sensor data.
Definition Demo.hpp:143
void receiveData(InputPin::NodeDataQueue &queue, size_t pinIdx)
Receive callback on the Flow pin.
Definition Demo.cpp:684
std::string _valueString
Value which is represented over the String pin.
Definition Demo.hpp:166
static std::string category()
String representation of the Class Category.
Definition Demo.cpp:106
bool _enableDelegate
Switch to enable the delegate pin.
Definition Demo.hpp:152
void guiConfig() override
ImGui config window which is shown on double click.
Definition Demo.cpp:111
Demo()
Default constructor.
Definition Demo.cpp:73
json save() const override
Saves the node into a json object.
Definition Demo.cpp:414
DemoData _valueObject
Value which is represented over the Object pin.
Definition Demo.hpp:167
double _valueDouble
Value which is represented over the Double pin.
Definition Demo.hpp:165
~Demo() override
Destructor.
Definition Demo.cpp:91
static std::string type()
Returns the type of the data class.
Definition ImuObs.hpp:33
IMU Position.
Definition ImuPos.hpp:26
Input pins of nodes.
Definition Pin.hpp:491
TsDeque< std::shared_ptr< const NAV::NodeData > > NodeDataQueue
Node data queue type.
Definition Pin.hpp:707
The class is responsible for all time-related tasks.
Definition InsTime.hpp:710
static std::string type()
Returns the type of the data class.
Definition NodeData.hpp:45
bool isInitialized() const
Checks if the node is initialized.
Definition Node.cpp:574
ImVec2 _guiConfigDefaultWindowSize
Definition Node.hpp:522
void notifyOutputValueChanged(size_t pinIdx, const InsTime &insTime, const std::scoped_lock< std::mutex > &&guard)
Notifies connected nodes about the change.
Definition Node.cpp:92
std::vector< OutputPin > outputPins
List of output pins.
Definition Node.hpp:511
Node(std::string name)
Constructor.
Definition Node.cpp:29
bool DeleteOutputPin(size_t pinIndex)
Deletes the output pin. Invalidates the pin reference given.
Definition Node.cpp:298
std::optional< InputPin::IncomingLink::ValueWrapper< T > > getInputValue(size_t portIndex) const
Get Input Value connected on the pin. Only const data types.
Definition Node.hpp:290
std::vector< InputPin > inputPins
List of input pins.
Definition Node.hpp:509
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
@ POST_PROCESSING
Node running in post-processing mode.
Definition Node.hpp:192
bool callbacksEnabled
Enables the callbacks.
Definition Node.hpp:514
std::string nameId() const
Node name and id.
Definition Node.cpp:323
bool _lockConfigDuringRun
Lock the config when executing post-processing.
Definition Node.hpp:528
std::string name
Name of the Node.
Definition Node.hpp:507
bool _onlyRealTime
Whether the node can run in post-processing or only real-time.
Definition Node.hpp:531
InputPin * CreateInputPin(const char *name, Pin::Type pinType, const std::vector< std::string > &dataIdentifier={}, InputPin::Callback callback=static_cast< InputPin::FlowFirableCallbackFunc >(nullptr), InputPin::FlowFirableCheckFunc firable=nullptr, int priority=0, int idx=-1)
Create an Input Pin object.
Definition Node.cpp:252
std::scoped_lock< std::mutex > requestOutputValueLock(size_t pinIdx)
Blocks the thread till the output values was read by all connected nodes.
Definition Node.cpp:132
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 DeleteInputPin(size_t pinIndex)
Deletes the input pin. Invalidates the pin reference given.
Definition Node.cpp:310
bool _hasConfig
Flag if the config window should be shown.
Definition Node.hpp:525
Output pins of nodes.
Definition Pin.hpp:338
std::variant< const void *, const bool *, const int *, const float *, const double *, const std::string *, PeekPollDataFunc, PollDataFunc > PinData
Possible Types represented by an output pin.
Definition Pin.hpp:448
auto extract_front()
Returns a copy of the first element in the container and removes it from the container.
Definition TsDeque.hpp:494
ImGui extensions.
bool DragDouble(const char *label, double *v, float v_speed, double v_min, double v_max, const char *format, ImGuiSliderFlags flags)
Shows a Drag GUI element for 'double'.
Definition imgui_ex.cpp:19
InputPin * FindInputPin(ax::NodeEditor::PinId id)
Finds the Pin for the PinId.
void ApplyChanges()
Signals that there have been changes to the flow.
void MatrixView(const char *label, const Eigen::Matrix< _Scalar, _Rows, _Cols > *matrix, GuiMatrixViewFlags flags=GuiMatrixViewFlags_None, ImGuiTableFlags tableFlags=ImGuiTableFlags_None, const char *format="%.6f")
Shows GUI elements to display the coefficients of a matrix.
Definition Matrix.hpp:49
bool InputMatrix(const char *label, Eigen::Matrix< _Scalar, _Rows, _Cols > *matrix, GuiMatrixViewFlags flags=GuiMatrixViewFlags_None, ImGuiTableFlags tableFlags=ImGuiTableFlags_None, float inputTextWidth=50.0F, double step=0.0, double step_fast=0.0, const char *format="%.6f", ImGuiInputTextFlags inputTextFlags=ImGuiInputTextFlags_None)
Shows GUI elements to modify the coefficients of a matrix with.
Definition Matrix.hpp:105
void HelpMarker(const char *desc, const char *symbol="(?)")
Text Help Marker, e.g. '(?)', with Tooltip.
@ GPST
GPS Time.
void to_json(json &j, const Node &node)
Converts the provided node into a json object.
Definition Node.cpp:1060
void from_json(const json &j, Node &node)
Converts the provided json object into a node object.
Definition Node.cpp:1077
Data struct transmitted over an output port.
Definition Demo.hpp:79
bool boolean
Boolean inside the DemoData.
Definition Demo.hpp:81
std::array< int, 3 > integer
Integer inside the DemoData.
Definition Demo.hpp:80
Type of the data on the Pin.
Definition Pin.hpp:47
@ Delegate
Reference to the Node object.
Definition Pin.hpp:59
@ Matrix
Matrix Object.
Definition Pin.hpp:58
@ Int
Integer Number.
Definition Pin.hpp:54
@ Float
Floating Point Number.
Definition Pin.hpp:55
@ String
std::string
Definition Pin.hpp:56
@ Flow
NodeData Trigger.
Definition Pin.hpp:52
@ Bool
Boolean.
Definition Pin.hpp:53
@ Object
Generic Object.
Definition Pin.hpp:57