VOXL OpenVINS Server 0.7.0
Visual Inertial Odometry Server for VOXL Platform
Loading...
Searching...
No Matches
ImuMinimal.cpp
Go to the documentation of this file.
1/**
2 * @file ImuMinimal.cpp
3 * @brief IMU interface and data handling implementation for VOXL OpenVINS
4 * @author Joao Leonardo Silva Cotta (@zauberflote1)
5 * @date 2025
6 * @version 1.0
7 *
8 * This file implements the IMU interface and callback functions for handling
9 * inertial measurement unit data in the VOXL OpenVINS system. It provides
10 * the connection to the IMU service and data processing capabilities.
11 *
12 * The implementation provides:
13 * - IMU data reception and validation
14 * - Frame transformation for different IMU orientations
15 * - Batch processing for efficient VIO integration
16 * - Camera-IMU synchronization
17 * - VIO state management and publishing
18 * - Thread-safe operations with mutex protection
19 */
20
21#include "ImuMinimal.h"
22#include <cstdio>
23#include <state/State.h>
24
25
26/** @brief Mutex for IMU data access synchronization */
27std::mutex imu_lock_mutex;
28
29/**
30 * @brief Handler for incoming IMU data
31 *
32 * This callback processes incoming IMU data, updates the system state,
33 * and triggers appropriate processing based on motion state. It serves
34 * as the primary entry point for all IMU data processing in the system.
35 *
36 * The function performs the following operations:
37 * - Validates and parses IMU data packets
38 * - Updates frame transformation based on gravity direction
39 * - Converts IMU data to OpenVINS format
40 * - Performs batch processing to reduce mutex operations
41 * - Feeds IMU data to the VIO manager
42 * - Synchronizes camera data with IMU timestamps
43 * - Triggers VIO processing and data publishing
44 *
45 * The function uses batch processing to minimize mutex contention
46 * at high IMU frequencies and ensures proper temporal synchronization
47 * between IMU and camera data.
48 *
49 * @param ch Channel number (unused)
50 * @param data Pointer to IMU data buffer
51 * @param bytes Size of data buffer in bytes
52 * @param context Context pointer (unused)
53 */
54void _imu_data_handler_cb(int ch, char *data, int bytes, void *context)
55{
56 int64_t t_start = _apps_time_monotonic_ns();
57 is_imu_connected.store(true, std::memory_order_release);
58
59 // ---- validate data ----
60 int n_packets = 0;
61 imu_data_t *arr = pipe_validate_imu_data_t(data, bytes, &n_packets);
62
63 active_callbacks.fetch_add(1, std::memory_order_acquire);
64 // acquire: pairs with the release store that clears is_resetting at the end of a reset, so
65 // the first post-reset callback also observes the bumped reset_num_counter -- a relaxed load
66 // could pair the NEW VioManager with the publisher's OLD quality/hysteresis statics for one
67 // packet (no happens-before edge from the reset thread otherwise)
68 if (is_resetting.load(std::memory_order_acquire))
69 {
70 active_callbacks.fetch_sub(1, std::memory_order_release);
71 return;
72 }
73 if (en_debug)
74 {
75 std::cout << "number of IMU packets: " << n_packets << std::endl;
76 }
77 if (!arr || n_packets <= 0)
78 {
79
80 vio_error_codes |= ERROR_CODE_IMU_MISSING;
81 active_callbacks.fetch_sub(1, std::memory_order_release);
82 return;
83 }
84
85 // ---- build batch ----
86 std::vector<ov_core::ImuData> imu_batch;
87 imu_batch.reserve(n_packets);
88
89 for (int i = 0; i < n_packets; ++i)
90 {
91 frame_transform.update(arr[i]);
92
93 ov_core::ImuData sample;
94 sample.timestamp = arr[i].timestamp_ns * 1e-9;
95 sample.wm = Eigen::Vector3d(arr[i].gyro_rad[0], arr[i].gyro_rad[1], arr[i].gyro_rad[2]);
96 sample.am = Eigen::Vector3d(arr[i].accl_ms2[0], arr[i].accl_ms2[1], arr[i].accl_ms2[2]);
97
98 if (last_imu_timestamp_ns != 0 &&
99 (sample.timestamp * 1e9 <= last_imu_timestamp_ns))
100 {
101 int64_t time_diff = last_imu_timestamp_ns - (sample.timestamp * 1e9);
102 if (time_diff > 1000000) // 1 ms
103 {
104 // No print here: this runs per-sample at IMU rate; HealthCheck reports the
105 // BAD_TIMESTAMP code edge-triggered instead
106 vio_error_codes |= ERROR_CODE_BAD_TIMESTAMP;
107 }
108 }
109 imu_batch.push_back(std::move(sample));
110 }
111
112 if (imu_batch.empty())
113 {
114 vio_error_codes |= ERROR_CODE_DROPPED_IMU;
115 if (active_callbacks.fetch_sub(1, std::memory_order_release) == 1)
116 {
117 std::lock_guard<std::mutex> lk(reset_mtx);
118 reset_cv.notify_one();
119 }
120 return;
121 }
122
123 // ---- feed IMU (this also releases + processes every camera frame whose global ordering the
124 // batch has decided: the lock-free per-camera ingest lives inside ov_msckf, and per-frame
125 // cl_mem release + publishing run through the VoxlVioIngest callback on this same thread) ----
126 int imu_batch_size = (imu_model == IMU_MODEL_BMI270) ? 800 : 330;
127 if (frame_transform.is_initialized) vio_manager->feed_measurement_batch_imu(imu_batch, imu_batch_size);
128 last_imu_timestamp_ns = imu_batch.back().timestamp * 1e9;
129
130 // ---- finish ----
131 int64_t t_end = _apps_time_monotonic_ns();
132 double dt_ms = (double)(t_end - t_start) / 1e6;
133 if (dt_ms > 32.0 && en_debug)
134 {
135 printf("WARNING: IMU callback took too long: %8.3f ms\n", dt_ms);
136 }
137
138 if (active_callbacks.fetch_sub(1, std::memory_order_release) == 1)
139 {
140 std::lock_guard<std::mutex> lk(reset_mtx);
141 reset_cv.notify_one();
142 }
143}
144
145/**
146 * @brief Callback for IMU disconnect events
147 *
148 * This function is called when the IMU service disconnects. It handles
149 * the cleanup and state management required when IMU data becomes unavailable.
150 *
151 * The function uses thread-safe mutex locking to ensure proper
152 * state management during disconnection events.
153 *
154 * @param ch Channel number (unused)
155 * @param context Context pointer (unused)
156 */
157void _imu_disconnect_cb(__attribute__((unused)) int ch,
158 __attribute__((unused)) void *context)
159// THREAD SAFE DISCONNECT CALLBACK
160{
161 std::lock_guard<std::mutex> lg(imu_lock_mutex);
162 if (!is_imu_connected.load())
163 return;
164 pipe_client_flush(IMU_CH);
165 // Small delay to ensure pending operations complete
166 usleep(50000);
167 is_imu_connected.store(false, std::memory_order_release);
168 return;
169}
170
171/**
172 * @brief Creates IMU pipe client and associated callbacks
173 *
174 * This function sets up the disconnect and data handler callbacks,
175 * and opens the client pipe connection to the IMU service. It initializes
176 * the complete IMU data pipeline for the VIO system.
177 *
178 * The function performs the following operations:
179 * - Sets up disconnect callback for graceful handling of service disconnection
180 * - Sets up data handler callback for processing incoming IMU measurements
181 * - Configures thread priority for high-frequency IMU processing
182 * - Opens the client pipe connection to the IMU service
183 * - Configures the pipe for optimal data flow
184 * - Sets the IMU connection status flag
185 *
186 * @return 0 on success, -1 on failure
187 */
189{
190 // MPA REGULAR CLIENT SETUP
191
192 pipe_client_set_disconnect_cb(IMU_CH, _imu_disconnect_cb, NULL);
193 pipe_client_set_simple_helper_cb(IMU_CH, _imu_data_handler_cb, NULL);
194 pipe_client_set_helper_thread_priority(IMU_CH, THREAD_PRIORITY_RT_HIGH);
195
196 int flags = CLIENT_FLAG_EN_SIMPLE_HELPER;
197
198 if (pipe_client_open(IMU_CH, imu_name, PROCESS_NAME, flags,
199 IMU_RECOMMENDED_READ_BUF_SIZE * 2) != 0)
200 {
201 fprintf(stderr, "failed to open imu client pipe\n");
202 vio_error_codes |= ERROR_CODE_IMU_MISSING;
203 return -1;
204 }
205 is_imu_connected = true;
206
207 return 0;
208}
void _imu_disconnect_cb(__attribute__((unused)) int ch, __attribute__((unused)) void *context)
Callback for IMU disconnect events.
void _imu_data_handler_cb(int ch, char *data, int bytes, void *context)
Handler for incoming IMU data.
int connect_imu_service(void)
Creates IMU pipe client and associated callbacks.
std::mutex imu_lock_mutex
Mutex for IMU data access synchronization.
IMU interface and data handling for VOXL OpenVINS.
volatile int64_t last_imu_timestamp_ns
Timestamp of last IMU data (nanoseconds)
Definition VoxlVars.cpp:178
std::atomic< uint32_t > active_callbacks
Number of callbacks inside the system.
Definition VoxlVars.cpp:63
char imu_name[64]
IMU device name.
Definition VoxlVars.cpp:165
voxl::FrameTransform frame_transform
Global frame transform instance.
Definition VoxlVars.cpp:181
std::mutex reset_mtx
Mutex used by reset thread.
Definition VoxlVars.cpp:66
imu_model_t imu_model
Active IMU model.
Definition VoxlVars.cpp:168
std::unique_ptr< ov_msckf::VioManager > vio_manager
Main VIO manager instance.
Definition VoxlVars.cpp:31
int en_debug
Enable debug output.
Definition VoxlVars.cpp:149
std::condition_variable reset_cv
Reset conditional variable.
Definition VoxlVars.cpp:69
std::atomic< bool > is_resetting
VIO reset state flag.
std::atomic< uint32_t > vio_error_codes
VIO error codes.
std::atomic< bool > is_imu_connected
IMU connection state.
#define PROCESS_NAME
Process name for the VOXL OpenVINS server.
Definition VoxlVars.h:241
#define IMU_CH
MPA client channel for IMU data input.
Definition VoxlVars.h:174