VOXL OpenVINS Server 0.7.0
Visual Inertial Odometry Server for VOXL Platform
Loading...
Searching...
No Matches
VoxlVars.cpp
Go to the documentation of this file.
1/**
2 * @file VoxlVars.cpp
3 * @brief Global variable definitions for VOXL OpenVINS server
4 * @author Joao Leonardo Silva Cotta (@zauberflote1)
5 * @date 2025
6 * @version 1.0
7 *
8 * This file contains the definitions of all global variables declared in VoxlVars.h.
9 * It provides the actual storage for system state, configuration parameters,
10 * and operational variables used throughout the VIO system.
11 */
12
13#include "VoxlVars.h"
14#include "VoxlCommon.h"
15#include <atomic>
16#include <memory>
17#include <mutex>
18#include <vector>
19#include <string>
20#include <cmath>
21#include <algorithm>
22
23// ============================================================================
24// CORE VIO MANAGER
25// ============================================================================
26
27/** @brief VIO manager options */
28ov_msckf::VioManagerOptions vio_manager_options;
29
30/** @brief Main VIO manager instance */
31std::unique_ptr<ov_msckf::VioManager> vio_manager;
32
33// ============================================================================
34// ATOMIC STATE VARIABLES
35// ============================================================================
36
37/** @brief Main process running flag */
38volatile int main_running = 1;
39
40/** @brief Current VIO state (initializing, tracking, etc.) */
41std::atomic<uint8_t> vio_state(0);
42
43/** @brief VIO error codes */
44std::atomic<uint32_t> vio_error_codes(0);
45
46/** @brief Flag indicating that system should reset */
47std::atomic<bool> reset_requested(false);
48
49/** @brief Flag indicating that a front-end-preserving SOFT reset was requested */
50std::atomic<bool> soft_reset_requested(false);
51
52/** @brief Flag indicating if system is currently resetting */
53std::atomic<bool> is_resetting(false);
54
55/** @brief Counter which increments on resets (hard + soft) */
56std::atomic<uint32_t> reset_num_counter{0};
57
58/** @brief Counter which increments only on SOFT (front-end-preserving) resets, so field logs can
59 * distinguish soft from hard (hard count = reset_num_counter - soft_reset_num_counter). */
60std::atomic<uint32_t> soft_reset_num_counter{0};
61
62/** @brief Number of callbacks inside the system */
63std::atomic<uint32_t> active_callbacks{0};
64
65/** @brief Mutex used by reset thread */
66std::mutex reset_mtx;
67
68/** @brief Reset conditional variable */
69std::condition_variable reset_cv;
70
71/** @brief Flag indicating if system is armed */
72
73/** @brief Flag indicating if camera is connected */
74std::atomic<bool> is_cam_connected(false);
75
76/** @brief Flag indicating if IMU is connected */
77std::atomic<bool> is_imu_connected(false);
78
79// ============================================================================
80// SERVER CONFIGURATION VARIABLES
81// ============================================================================
82
83/** @brief Enable automatic reset functionality */
85
86/** @brief Maximum velocity threshold for auto reset */
88
89/** @brief Maximum velocity covariance for instant reset */
90
91/** @brief Maximum velocity covariance for timeout reset */
92
93/** @brief Timeout duration for velocity covariance reset (seconds) */
95
96/** @brief Minimum number of features for auto reset */
98
99/** @brief Minimum feature timeout for auto reset (seconds) */
101
102/** @brief Minimum amount of time after initialization that quality is held low (CEP) */
104
105/** @brief Auto fallback timeout (seconds) */
106
107/** @brief Minimum velocity for auto fallback */
108
109/** @brief Enable continuous yaw checks */
110
111/** @brief Fast yaw threshold */
112float fast_yaw_thresh = 0.0f;
113
114/** @brief Fast yaw timeout (seconds) */
116
117// ============================================================================
118// QUALITY HYSTERESIS THRESHOLD CONFIGURATION
119// ============================================================================
120
121/** @brief Quality low threshold for INITIAL state */
123
124/** @brief Quality low threshold for GOOD state */
126
127/** @brief Quality high threshold for recovery */
129
130/** @brief Consecutive samples for INITIAL→BAD transition */
132
133/** @brief Consecutive samples for INITIAL→GOOD transition */
135
136/** @brief Consecutive samples for BAD→GOOD transition */
138
139/** @brief Consecutive samples for GOOD→BAD transition */
141
142/** @brief using_stereo */
144
145/** @brief Base folder for yaml configuration files */
146char folder_base[CHAR_BUF_SIZE] = "/etc/modalai/VoxlConfig/starling2";
147
148/** @brief Enable debug output */
149int en_debug = 0;
150
151/** @brief Enable verbose output */
153
154/** @brief Configuration only mode */
156
157/** @brief Enable IMU body measurements */
158bool en_imu_body = false;
159
160// ============================================================================
161// SENSOR CONFIGURATION VARIABLES
162// ============================================================================
163
164/** @brief IMU device name */
165char imu_name[64];
166
167/** @brief Active IMU model */
168imu_model_t imu_model = IMU_MODEL_UNKNOWN;
169
170/** @brief Vector of camera configuration information */
171std::vector<cam_info> cam_info_vec;
172
173// ============================================================================
174// IMU-SPECIFIC VARIABLES
175// ============================================================================
176
177/** @brief Timestamp of last IMU data (nanoseconds) */
178volatile int64_t last_imu_timestamp_ns = 0;
179
180/** @brief Global frame transform instance */
182
183// ============================================================================
184// CAMERA-SPECIFIC VARIABLES
185// ============================================================================
186
187/** @brief Timestamp of last camera data (nanoseconds) */
188volatile int64_t last_cam_time = 0;
189
190/** @brief Number of cameras currently in use */
192
193/** @brief Altitude z */
194std::atomic<float> alt_z(0.0f);
195
196/** @brief Takeoff altitude threshold */
198
199/** @brief Occlude stereo left */
201
202/** @brief Occlude stereo right */
204
205/** @brief Fusion rate in milliseconds */
206
207// ============================================================================
208// PIPE COMMUNICATION VARIABLES
209// ============================================================================
210
211/** @brief Camera pipe channels array */
213
214// ============================================================================
215// IMAGE PROCESSING VARIABLES
216// ============================================================================
217
218bool sync_config = true; ///< Flag to indicate if configuration synchronization is enabled
219
220// Stereo-matcher depth bounds (populated by VoxlConfigure)
221float stereo_z_min = 0.10f;
222float stereo_z_max = 100.0f;
223modal_flow::StereoCalib g_stereo_calib{};
224bool g_stereo_calib_valid = false;
225
226// Server-side IMU frame-transform bring-up gate (degrees). If >= 0, the server holds the sensor feed to
227// the estimator until the measured gravity tilt is within this angle (opt-in "must be level" boot gate).
228// Default -1 => ANY attitude: feed immediately so the ceres-free S2 dynamic init can (re)init/reset at any
229// attitude. Keep this in sync with (and generally >=) the estimator's init_gravity_max_angle.
231
232// ============================================================================
233// FRAME TRANSFORM IMPLEMENTATION
234// ============================================================================
235
236void voxl::FrameTransform::update(const imu_data_t &data)
237{
238 static bool warned_no_imu_body = false;
239 if (!en_imu_body && !warned_no_imu_body)
240 {
241 // once, not per IMU sample -- update() runs at IMU rate
242 printf("[WARN] IMU body measurements are disabled, THIS WON'T WORK AS EXPECTED.\n");
243 warned_no_imu_body = true;
244 }
245
246 if (is_initialized)
247 {
248 detectJerk(data);
249 return; // CHECK IF WE HAVE ALREADY DONE THIS
250 }
251
252 // Frame-transform bring-up. We only need a plausible gravity sample to START STREAMING sensor data to
253 // the estimator; ATTITUDE IS NOT A GATE HERE. The ceres-free S2 dynamic initializer (re)initializes at
254 // ANY attitude, and the estimator's static path applies its own tight gravity gate downstream -- so
255 // blocking the IMU/camera feed here on a "must be level" assumption would silently defeat any-attitude
256 // (re)init and reset: a pitched boot would never feed data and VIO would never start. The gravity axis
257 // is assumed Z-down (IMU mounted body-aligned); the measured angle is reported for diagnostics only.
258 Eigen::Vector3d accel(data.accl_ms2[0], data.accl_ms2[1], data.accl_ms2[2]);
259 double amag = accel.norm();
260 if (amag < 1e-6)
261 {
262 // Degenerate/garbage sample (no gravity signal) -- wait for a valid one, do not initialize on it.
263 return;
264 }
265 Eigen::Vector3d accel_n = accel / amag;
266 Eigen::Vector3d grav_versor_expected = -Eigen::Vector3d::UnitZ();
267 double dot_product = std::max(-1.0, std::min(1.0, accel_n.dot(grav_versor_expected)));
268 double angle_deg = std::acos(dot_product) * 180.0 / M_PI;
269 gravity_axis = Axis::Z;
270 gravity_direction = Direction::NEGATIVE;
271
272 // Opt-in level requirement: ONLY a platform that explicitly sets imu_init_max_gravity_angle_deg >= 0
273 // holds the feed until it is within that tilt. Default (-1) => any attitude, feed immediately (required
274 // for SFM any-attitude (re)init/reset). This is the single, config-driven server-side gravity gate --
275 // it must stay in sync with (and generally wider than) the estimator's init_gravity_max_angle.
276 if (imu_init_max_gravity_angle_deg >= 0.0f && angle_deg > (double)imu_init_max_gravity_angle_deg)
277 {
278 printf("[WARN] IMU init: gravity angle %.2f deg > imu_init_max_gravity_angle_deg %.2f deg -- holding "
279 "sensor feed (opt-in level gate; set <0 for any-attitude)\n",
280 angle_deg, (double)imu_init_max_gravity_angle_deg);
281 is_initialized = false;
282 return;
283 }
284
285 is_initialized = true;
286 printf("[INFO] Frame transform initialized (gravity angle %.2f deg, axis Z-, any-attitude feed enabled)\n", angle_deg);
287}
288void voxl::FrameTransform::detectJerk(const imu_data_t &data)
289{
290 // C++17 Real-time optimization: Construct vectors in-place, avoid temporaries
291 const Eigen::Vector3d acc_sample(data.accl_ms2[0], data.accl_ms2[1], data.accl_ms2[2]);
292 const Eigen::Vector3d gyro_sample(data.gyro_rad[0], data.gyro_rad[1], data.gyro_rad[2]);
293
294 // Accumulate data for jerk detection
295 if (current_total_samples <= expected_total_samples * 0.5f)
296 {
297 avg_acc_1t0 += acc_sample;
298 avg_gyro_1t0 += gyro_sample;
299 acc1t0_samples.push_back(acc_sample);
300 gyro1t0_samples.push_back(gyro_sample);
301 current_total_samples += 1.0f;
302 return;
303 }
304 else if (current_total_samples > expected_total_samples * 0.5f && current_total_samples < expected_total_samples)
305 {
306 // In the second half of the window
307 avg_acc_2t1 += acc_sample;
308 avg_gyro_2t1 += gyro_sample;
309 acc2t1_samples.push_back(acc_sample);
310 gyro2t1_samples.push_back(gyro_sample);
311 current_total_samples += 1.0f;
312 }
313 else if (current_total_samples >= expected_total_samples)
314 {
315 // already have enough samples for this window, now compute variance per window segment
316
317 double var_acc1t0 = 0.0, var_gyro1t0 = 0.0, var_acc2t1 = 0.0, var_gyro2t1 = 0.0;
318
319 avg_acc_1t0 /= acc1t0_samples.size();
320 avg_gyro_1t0 /= gyro1t0_samples.size();
321 avg_acc_2t1 /= acc2t1_samples.size();
322 avg_gyro_2t1 /= gyro2t1_samples.size();
323
324 // note that the # of samples for the same segment is the same for acc and gyro
325 for (size_t i = 0; i < acc1t0_samples.size(); ++i)
326 {
327 var_acc1t0 += (acc1t0_samples[i] - avg_acc_1t0).dot(acc1t0_samples[i] - avg_acc_1t0);
328 var_gyro1t0 += (gyro1t0_samples[i] - avg_gyro_1t0).dot(gyro1t0_samples[i] - avg_gyro_1t0);
329 }
330 var_acc1t0 = std::sqrt(var_acc1t0 / (acc1t0_samples.size() - 1));
331 var_gyro1t0 = std::sqrt(var_gyro1t0 / (gyro1t0_samples.size() - 1));
332
333 for (size_t i = 0; i < acc2t1_samples.size(); ++i)
334 {
335 var_acc2t1 += (acc2t1_samples[i] - avg_acc_2t1).dot(acc2t1_samples[i] - avg_acc_2t1);
336 var_gyro2t1 += (gyro2t1_samples[i] - avg_gyro_2t1).dot(gyro2t1_samples[i] - avg_gyro_2t1);
337 }
338 var_acc2t1 = std::sqrt(var_acc2t1 / (acc2t1_samples.size() - 1));
339 var_gyro2t1 = std::sqrt(var_gyro2t1 / (gyro2t1_samples.size() - 1));
340 if (en_debug)
341 {
342 printf("Accelerometer variance: %f, %f\n", var_acc1t0, var_acc2t1);
343 printf("Gyroscope variance: %f, %f\n", var_gyro1t0, var_gyro2t1);
344 }
345 // C++17: Use structured bindings conceptually - evaluate jerk conditions
346 bool accel_jerk_detected = false;
347 bool gyro_jerk_detected = false;
348
349 switch (jerk_opt)
350 {
351 case JerkOption::ACCEL_ONLY:
352 accel_jerk_detected = (var_acc1t0 > ACC_VAR_THRESHOLD || var_acc2t1 > ACC_VAR_THRESHOLD);
353 break;
354 case JerkOption::GYRO_ONLY:
355 gyro_jerk_detected = (var_gyro1t0 > GYRO_VAR_THRESHOLD || var_gyro2t1 > GYRO_VAR_THRESHOLD);
356 break;
357 case JerkOption::ACCEL_AND_GYRO:
358 accel_jerk_detected = (var_acc1t0 > ACC_VAR_THRESHOLD || var_acc2t1 > ACC_VAR_THRESHOLD);
359 gyro_jerk_detected = (var_gyro1t0 > GYRO_VAR_THRESHOLD || var_gyro2t1 > GYRO_VAR_THRESHOLD);
360 break;
361 case JerkOption::NONE:
362 // Jerk detection disabled - report as jerked (non-static)
363 resetJerkDetection();
364 return;
365 }
366
367 // FIX: Report jerk status but DON'T reset counters - allows detection to continue
368 // This prevents infinite reset loops on first initialization
369 has_acc_jerk.store(accel_jerk_detected, std::memory_order_release);
370 non_static.store(accel_jerk_detected || gyro_jerk_detected, std::memory_order_release);
371 avg_acc_1t0.setZero(); // avg_acc_2t1;
372 avg_gyro_1t0.setZero(); // avg_gyro_2t1;
373 avg_acc_2t1.setZero();
374 avg_gyro_2t1.setZero();
375 current_total_samples = 0; // static_cast<float>(acc2t1_samples.size());
376 acc1t0_samples.clear(); // acc2t1_samples;
377 gyro1t0_samples.clear(); // gyro2t1_samples;
378 acc2t1_samples.clear(); // acc2t1_samples;
379 gyro2t1_samples.clear(); // gyro2t1_samples;
380
381 return;
382 }
383}
384
385void voxl::FrameTransform::resetJerkDetection()
386{
387 has_acc_jerk.store(true, std::memory_order_release);
388 non_static.store(true, std::memory_order_release);
389 // reset for next window
390 // note that we do not reset the entirity of the window, but only the second half
391 avg_acc_1t0.setZero(); // avg_acc_2t1;
392 avg_gyro_1t0.setZero(); // avg_gyro_2t1;
393 avg_acc_2t1.setZero();
394 avg_gyro_2t1.setZero();
395 current_total_samples = 0; // static_cast<float>(acc2t1_samples.size());
396 acc1t0_samples.clear(); // acc2t1_samples;
397 gyro1t0_samples.clear(); // gyro2t1_samples;
398 acc2t1_samples.clear();
399 gyro2t1_samples.clear();
400}
401// ============================================================================
402// JERK DETECTION VARIABLES
403// ============================================================================
404
405/**
406 * @brief Flag indicating if accelerometer jerk is detected
407 */
408std::atomic<bool> has_acc_jerk(false);
409
410/**
411 * @brief Non-static flag for jerk detection
412 */
413std::atomic<bool> non_static(false);
Common definitions and utilities for the VOXL OpenVINS server.
int en_verbose
Enable verbose output.
Definition VoxlVars.cpp:152
bool occlude_stereo_right
Occlude stereo right.
Definition VoxlVars.cpp:203
int cameras_used
Number of cameras currently in use.
Definition VoxlVars.cpp:191
volatile int64_t last_cam_time
Timestamp of last camera data (nanoseconds)
Definition VoxlVars.cpp:188
volatile int64_t last_imu_timestamp_ns
Timestamp of last IMU data (nanoseconds)
Definition VoxlVars.cpp:178
int camera_pipe_channels[MAX_CAM_CNT]
Fusion rate in milliseconds.
Definition VoxlVars.cpp:212
volatile int main_running
Main process running flag.
Definition VoxlVars.cpp:38
char folder_base[CHAR_BUF_SIZE]
Base folder for yaml configuration files.
Definition VoxlVars.cpp:146
std::atomic< uint32_t > active_callbacks
Number of callbacks inside the system.
Definition VoxlVars.cpp:63
ov_msckf::VioManagerOptions vio_manager_options
VIO manager options.
Definition VoxlVars.cpp:28
int quality_initial_to_bad_count
Consecutive samples for INITIAL→BAD transition.
Definition VoxlVars.cpp:131
int quality_low_thresh_initial
Quality low threshold for INITIAL state.
Definition VoxlVars.cpp:122
int quality_bad_to_good_count
Consecutive samples for BAD→GOOD transition.
Definition VoxlVars.cpp:137
float fast_yaw_thresh
Auto fallback timeout (seconds)
Definition VoxlVars.cpp:112
int en_auto_reset
Enable automatic reset functionality.
Definition VoxlVars.cpp:84
float auto_reset_max_velocity
Maximum velocity threshold for auto reset.
Definition VoxlVars.cpp:87
float stereo_z_max
far depth bound for epipolar search (m)
Definition VoxlVars.cpp:222
char imu_name[64]
IMU device name.
Definition VoxlVars.cpp:165
voxl::FrameTransform frame_transform
Global frame transform instance.
Definition VoxlVars.cpp:181
modal_flow::StereoCalib g_stereo_calib
composed by VoxlConfigure
Definition VoxlVars.cpp:223
bool occlude_stereo_left
Occlude stereo left.
Definition VoxlVars.cpp:200
int quality_good_to_bad_count
Consecutive samples for GOOD→BAD transition.
Definition VoxlVars.cpp:140
float auto_reset_max_v_cov_timeout_s
Maximum velocity covariance for instant reset.
Definition VoxlVars.cpp:94
float stereo_z_min
near depth bound for epipolar search (m)
Definition VoxlVars.cpp:221
std::mutex reset_mtx
Mutex used by reset thread.
Definition VoxlVars.cpp:66
int using_stereo
using_stereo
Definition VoxlVars.cpp:143
float imu_init_max_gravity_angle_deg
Server-side IMU frame-transform bring-up gravity gate (degrees)
Definition VoxlVars.cpp:230
float ok_state_grace_timeout_s
Minimum amount of time after initialization that quality is held low (CEP)
Definition VoxlVars.cpp:103
bool en_imu_body
Enable IMU body measurements.
Definition VoxlVars.cpp:158
float auto_reset_min_feature_timeout_s
Minimum feature timeout for auto reset (seconds)
Definition VoxlVars.cpp:100
float takeoff_alt_threshold
Takeoff altitude threshold.
Definition VoxlVars.cpp:197
imu_model_t imu_model
Active IMU model.
Definition VoxlVars.cpp:168
std::atomic< uint32_t > soft_reset_num_counter
Counter which increments only on SOFT (front-end-preserving) resets, so field logs can distinguish so...
Definition VoxlVars.cpp:60
std::atomic< uint32_t > reset_num_counter
Counter which increments on resets (hard + soft)
Definition VoxlVars.cpp:56
float fast_yaw_timeout_s
Fast yaw timeout (seconds)
Definition VoxlVars.cpp:115
int auto_reset_min_features
Minimum number of features for auto reset.
Definition VoxlVars.cpp:97
std::unique_ptr< ov_msckf::VioManager > vio_manager
Main VIO manager instance.
Definition VoxlVars.cpp:31
int quality_high_thresh
Quality high threshold for recovery.
Definition VoxlVars.cpp:128
int en_debug
Enable debug output.
Definition VoxlVars.cpp:149
std::vector< cam_info > cam_info_vec
Vector of camera configuration information.
Definition VoxlVars.cpp:171
int quality_low_thresh_good
Quality low threshold for GOOD state.
Definition VoxlVars.cpp:125
int quality_initial_to_good_count
Consecutive samples for INITIAL→GOOD transition.
Definition VoxlVars.cpp:134
int config_only
Configuration only mode.
Definition VoxlVars.cpp:155
std::condition_variable reset_cv
Reset conditional variable.
Definition VoxlVars.cpp:69
bool sync_config
Flag to indicate if configuration synchronization is enabled.
Definition VoxlVars.cpp:218
Global variable declarations and constants for VOXL OpenVINS server.
std::atomic< bool > non_static
Non-static flag for jerk detection.
std::atomic< bool > is_resetting
VIO reset state flag.
std::atomic< uint8_t > vio_state
Current VIO system state.
std::atomic< float > alt_z
Altitude z.
std::atomic< bool > has_acc_jerk
Flag indicating if accelerometer jerk is detected.
std::atomic< uint32_t > vio_error_codes
VIO error codes.
#define ACC_VAR_THRESHOLD
Accelerometer variance threshold for motion detection.
Definition VoxlVars.h:46
imu_model_t
Enumeration of supported IMU models.
Definition VoxlVars.h:574
std::atomic< bool > is_imu_connected
IMU connection state.
std::atomic< bool > reset_requested
Should reset floag.
std::atomic< bool > soft_reset_requested
Flag indicating that a front-end-preserving SOFT reset was requested.
std::atomic< bool > is_cam_connected
Camera connection state.
#define CHAR_BUF_SIZE
Standard character buffer size.
Definition VoxlVars.h:256
#define GYRO_VAR_THRESHOLD
Gyro variance threshold for motion detection.
Definition VoxlVars.h:45
#define MAX_CAM_CNT
Maximum number of cameras supported by VOXL2.
Definition VoxlVars.h:249
Structure for handling IMU frame transformations.
Definition VoxlVars.h:82