0.5.1
Loading...
Searching...
No Matches
SkydelNetworkStream.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
10
11#include <thread>
12#include <string>
13#include <vector>
14#include <chrono>
15#include <cmath>
16#include <sstream>
17
18#include "util/Logger.hpp"
25
26using boost::asio::ip::udp;
27
28namespace NAV::experimental
29{
30
41
46
48{
49 return "SkydelNetworkStream";
50}
51
52std::string SkydelNetworkStream::type() const
53{
54 return typeStatic();
55}
56
58{
59 return "Data Provider";
60}
61
63{
64 std::string str;
65
67 {
68 str = "(loading)";
69 }
70 else
71 {
72 std::ostringstream strs;
73 strs << _dataRate;
74 str = strs.str();
75 }
76
77 ImGui::LabelText(str.c_str(), "data rate [Hz]");
78 ImGui::SameLine();
79 gui::widgets::HelpMarker("The data rate can be adjusted in Skydel: Settings/Plug-ins/<Plug-in-name>/Plug-in UI. Make sure to enable either WiFi or a LAN connection. Enabling both can lead to loss of data, because Skydel only knows one ip address.");
80}
81
83{
84 return true;
85}
86
88{
89 _socket.async_receive_from(
90 boost::asio::buffer(_data, _maxLength), _senderEndpoint,
91 [this](boost::system::error_code errorRcvd, std::size_t bytesRcvd) {
92 if ((!errorRcvd) && (bytesRcvd > 0))
93 {
94 // Splitting the incoming string analogous to 'ImuFile.cpp'
95 std::stringstream lineStream(std::string(_data.begin(), _data.end()));
96 std::string cell;
97 auto obsG = std::make_shared<PosVelAtt>();
98 auto obs = std::make_shared<ImuObs>(this->_imuPos);
99
100 // Inits for simulated measurement variables
101 uint64_t timeSinceStartup = 0;
102
103 double posX = 0.0;
104 double posY = 0.0;
105 double posZ = 0.0;
106 double attRoll = 0.0;
107 double attPitch = 0.0;
108 double attYaw = 0.0;
109
110 double accelX = 0.0;
111 double accelY = 0.0;
112 double accelZ = 0.0;
113 double gyroX = 0.0;
114 double gyroY = 0.0;
115 double gyroZ = 0.0;
116
117 for (size_t i = 0; i < 13; i++)
118 {
119 // Reading string from csv
120 if (std::getline(lineStream, cell, ','))
121 {
122 switch (i)
123 {
124 case 0:
125 timeSinceStartup = static_cast<uint64_t>(std::stod(cell) * 1e6); // [ns] = [ms] * 1e6
126 break;
127 case 1:
128 posX = std::stod(cell);
129 break;
130 case 2:
131 posY = std::stod(cell);
132 break;
133 case 3:
134 posZ = std::stod(cell);
135 break;
136 case 4:
137 attRoll = std::stod(cell);
138 break;
139 case 5:
140 attPitch = std::stod(cell);
141 break;
142 case 6:
143 attYaw = std::stod(cell);
144 break;
145 case 7:
146 accelX = std::stod(cell);
147 break;
148 case 8:
149 accelY = std::stod(cell);
150 break;
151 case 9:
152 accelZ = std::stod(cell);
153 break;
154 case 10:
155 gyroX = std::stod(cell);
156 break;
157 case 11:
158 gyroY = std::stod(cell);
159 break;
160 case 12:
161 gyroZ = std::stod(cell);
162 break;
163
164 default:
165 LOG_ERROR("Error in network stream: Cell index is out of bounds");
166 break;
167 }
168 }
169 else
170 {
171 LOG_ERROR("Error in IMU stream: Reading a string from csv failed");
172 return;
173 }
174 }
175
176 // Set GNSS values
177 Eigen::Vector3d e_position{ posX, posY, posZ };
178 Eigen::Vector3d lla_position = trafo::ecef2lla_WGS84(e_position);
179 Eigen::Quaterniond e_Quat_b;
180 e_Quat_b = trafo::e_Quat_n(lla_position(0), lla_position(1)) * trafo::n_Quat_b(attRoll, attPitch, attYaw);
181
182 obsG->setPosition_e(e_position);
183 Eigen::Vector3d velDummy{ 0, 0, 0 }; // TODO: Add velocity output in Skydel API and NetStream
184 obsG->setVelocity_e(velDummy);
185 obsG->setAttitude_e_Quat_b(e_Quat_b); // Attitude MUST BE set after Position, because the n- to e-sys trafo depends on lla_position
186
187 // Set IMU values
188 obs->p_acceleration = { accelX, accelY, accelZ };
189 obs->p_angularRate = { gyroX, gyroY, gyroZ };
190 // TODO: Add magnetometer model to Skydel API 'InstinctDataStream'
191
192 InsTime currentTime = util::time::GetCurrentInsTime();
193 if (!currentTime.empty())
194 {
195 obs->insTime = currentTime;
196 obsG->insTime = currentTime;
197 }
198
200 {
201 // FIXME: This seems like a bug in clang-tidy. Check if it is working in future versions of clang-tidy
202 // NOLINTNEXTLINE(hicpp-use-nullptr, modernize-use-nullptr)
203 if (timeSinceStartup - _lastMessageTime >= static_cast<uint64_t>(1.5 / _dataRate * 1e9))
204 {
205 LOG_WARN("{}: Potentially lost a message. Previous message was at {} and current message at {} which is a time difference of {} seconds.", nameId(),
206 _lastMessageTime, timeSinceStartup, static_cast<double>(timeSinceStartup - _lastMessageTime) * 1e-9);
207 }
208 }
209 _lastMessageTime = timeSinceStartup;
210
213
214 // Data rate (for visualization in GUI)
216
218 {
219 _packageCount = 0;
221 }
222
223 if (_packageCount == 1)
224 {
225 _startPoint = std::chrono::steady_clock::now();
226 }
227 else if (_packageCount == _packagesNumber)
228 {
229 std::chrono::duration<double> elapsed_seconds = std::chrono::steady_clock::now() - _startPoint;
230 _dataRate = static_cast<double>(_packagesNumber - 1) / elapsed_seconds.count();
231
232 // Dynamic adaptation of data rate to a human-readable display update rate in GUI (~ 1 Hz)
233 if ((_dataRate > 2) && (_dataRate < 1001)) // restriction on 'reasonable' sensor data rates (Skydel max. is 1000 Hz)
234 {
235 _packagesNumber = static_cast<int>(_dataRate);
236 }
237 else if (_dataRate >= 1001)
238 {
239 _packagesNumber = 1000;
240 }
241
242 _packageCount = 0;
243
244 LOG_DATA("Elapsed Seconds = {}", elapsed_seconds.count());
245 LOG_DATA("SkydelNetworkStream: dataRate = {}", _dataRate);
246 }
247 }
248 else
249 {
250 LOG_ERROR("Error receiving the network stream from Skydel");
251 }
252
253 if (!_stop)
254 {
255 do_receive();
256 }
257 });
258}
259
261{
262 LOG_TRACE("{}: called", nameId());
263
264 _stop = false;
265 _packageCount = 0;
266 _startCounter = 0;
267 _packagesNumber = 2;
268
270
271 do_receive();
272
273 if (_isStartup)
274 {
275 _testThread = std::thread([this]() {
276 _ioservice.run();
277 });
278 }
279 else
280 {
281 _testThread = std::thread([this]() {
282 _ioservice.restart();
283 _ioservice.run();
284 });
285 }
286
287 _isStartup = false;
288
289 return true;
290}
291
293{
294 LOG_TRACE("{}: called", nameId());
295
296 _stop = true;
297 _ioservice.stop();
298 _testThread.join();
299}
300
301} // namespace NAV::experimental
Transformation collection.
Save/Load the Nodes.
Text Help Marker (?) with Tooltip.
Parent Class for all IMU Observations.
Utility class for logging to console and file.
#define LOG_DATA
All output which occurs repeatedly every time observations are received.
Definition Logger.hpp:29
#define LOG_ERROR
Error occurred, which stops part of the program to work, but not everything.
Definition Logger.hpp:73
#define LOG_WARN
Error occurred, but a fallback option exists and program continues to work normally.
Definition Logger.hpp:71
#define LOG_TRACE
Detailled info to trace the execution of the program. Should not be called on functions which receive...
Definition Logger.hpp:65
Position, Velocity and Attitude Storage Class.
Node receiving UDP packages from the Skydel GNSS simulator Instinct plugin.
Keeps track of the current real/simulation time.
static std::string type()
Returns the type of the data class.
Definition ImuObs.hpp:33
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
constexpr bool empty() const
Checks if the Time object has a value.
Definition InsTime.hpp:1089
ImVec2 _guiConfigDefaultWindowSize
Definition Node.hpp:522
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
bool _onlyRealTime
Whether the node can run in post-processing or only real-time.
Definition Node.hpp:531
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
static std::string type()
Returns the type of the data class.
Definition PosVelAtt.hpp:29
std::thread _testThread
Thread for receiver fct.
std::string type() const override
String representation of the Class Type.
void deinitialize() override
Deinitialize the node.
bool initialize() override
Initialize the node.
void guiConfig() override
ImGui config window which is shown on double click.
boost::asio::ip::udp::endpoint _senderEndpoint
Boost udp endpoint.
int _startCounter
Counter for packages that are skipped until data rate is shown.
bool resetNode() override
Resets the node. It is guaranteed that the node is initialized when this is called.
static constexpr size_t OUTPUT_PORT_INDEX_IMU_OBS
Port number of the Skydel-ImuObs output.
static constexpr size_t OUTPUT_PORT_INDEX_GNSS_OBS
Port number of the Skydel-GnssObs output.
bool _isStartup
Startup handler: used in 'initialize()' to differentiate between startup and re-initialization.
int _packageCount
Counter for received packages.
static std::string category()
String representation of the Class Category.
bool _stop
Stop handler: once true, the asynchronous receive function stops.
static std::string typeStatic()
String representation of the Class Type.
boost::asio::io_context _ioservice
Asynchronous receive fct.
std::array< char, _maxLength > _data
Network data stream array.
uint64_t _lastMessageTime
Stores the time of the last received message.
boost::asio::ip::udp::socket _socket
Boost udp socket.
std::chrono::steady_clock::time_point _startPoint
Time point where the first package has been received.
double _dataRate
Data rate of the received network stream [Hz].
static constexpr unsigned int _maxLength
Network data stream buffer size (boost::asio)
void do_receive()
Receive Skydel network stream data.
void HelpMarker(const char *desc, const char *symbol="(?)")
Text Help Marker, e.g. '(?)', with Tooltip.
Eigen::Vector3< typename Derived::Scalar > ecef2lla_WGS84(const Eigen::MatrixBase< Derived > &e_position)
Converts Earth-centered-Earth-fixed coordinates into latitude, longitude and altitude using WGS84.
Eigen::Quaternion< Scalar > e_Quat_n(const Scalar &latitude, const Scalar &longitude)
Quaternion for rotations from navigation to Earth-fixed frame.
Eigen::Quaternion< Scalar > n_Quat_b(Scalar roll, Scalar pitch, Scalar yaw)
Quaternion for rotations from body to navigation frame.
@ Flow
NodeData Trigger.
Definition Pin.hpp:52