23#include <state/State.h>
29 constexpr int kIMUQueueSize = 512;
30 boost::lockfree::spsc_queue<imu_data_t, boost::lockfree::capacity<kIMUQueueSize>> imu_queue;
31 std::atomic<bool> imu_thread_running{
false};
32 std::thread imu_thread;
36 std::shared_ptr<ov_msckf::State> cached_state;
37 std::map<double, std::vector<std::shared_ptr<ov_core::Feature>>> cached_features_map;
41 static int64_t last_rate_timestamp_ns = 0;
42 static constexpr double kImuRateAlpha = 0.1;
44 static inline void update_imu_rate_estimate(
const imu_data_t *arr,
int n_packets)
46 if (n_packets <= 0 || arr ==
nullptr)
51 int64_t dt_ns = arr[n_packets - 1].timestamp_ns - arr[0].timestamp_ns;
52 int64_t samples = (n_packets - 1);
53 if (dt_ns > 0 && samples > 0)
55 double avg_dt_ns =
static_cast<double>(dt_ns) /
static_cast<double>(samples);
56 double inst_rate_hz = 1e9 / avg_dt_ns;
57 double prev =
imu_rate_hz.load(std::memory_order_relaxed);
58 double updated = (1.0 - kImuRateAlpha) * prev + kImuRateAlpha * inst_rate_hz;
59 imu_rate_hz.store(updated, std::memory_order_relaxed);
60 last_rate_timestamp_ns = arr[n_packets - 1].timestamp_ns;
65 int64_t t = arr[n_packets - 1].timestamp_ns;
66 if (last_rate_timestamp_ns > 0 && t > last_rate_timestamp_ns)
68 double dt_ns =
static_cast<double>(t - last_rate_timestamp_ns);
69 double inst_rate_hz = 1e9 / dt_ns;
70 double prev =
imu_rate_hz.load(std::memory_order_relaxed);
71 double updated = (1.0 - kImuRateAlpha) * prev + kImuRateAlpha * inst_rate_hz;
72 imu_rate_hz.store(updated, std::memory_order_relaxed);
74 printf(
"imu_rate_hz: %f\n",
imu_rate_hz.load(std::memory_order_relaxed));
75 last_rate_timestamp_ns = t;
82#define TS_PRINT(msg) \
85 int64_t __ts = _apps_time_monotonic_ns(); \
86 printf("[TS %ld ns] %s\n", __ts, msg); \
116 int64_t t_start = _apps_time_monotonic_ns();
117 int64_t t_prev = t_start;
123 imu_data_t *arr = pipe_validate_imu_data_t(data, bytes, &n_packets);
124 int64_t t_validate = _apps_time_monotonic_ns();
137 std::cout <<
"number of IMU packets: " << n_packets << std::endl;
139 if (!arr || n_packets <= 0)
148 std::vector<ov_core::ImuData> imu_batch;
149 imu_batch.reserve(n_packets);
154 for (
int i = 0; i < n_packets; ++i)
158 ov_core::ImuData sample;
159 sample.timestamp = arr[i].timestamp_ns * 1e-9;
160 sample.wm = Eigen::Vector3d(arr[i].gyro_rad[0], arr[i].gyro_rad[1], arr[i].gyro_rad[2]);
161 sample.am = Eigen::Vector3d(arr[i].accl_ms2[0], arr[i].accl_ms2[1], arr[i].accl_ms2[2]);
167 if (time_diff > 1000000)
169 printf(
"[DEBUG] IMU timestamp regression %ld ns\n", time_diff);
173 imu_batch.push_back(std::move(sample));
180 int64_t t_batch = _apps_time_monotonic_ns();
185 if (imu_batch.empty())
190 std::lock_guard<std::mutex> lk(
reset_mtx);
197 int imu_batch_size = (
imu_model == IMU_MODEL_BMI270) ? 800 : 330;
210 vio_manager->get_state()->_calib_dt_CAMtoIMU->value()(0);
212 std::vector<ov_core::CameraData> batch;
215 for (
const auto &msg : batch)
221 for (
auto &frame : msg.img_frames)
223 if (frame.img.handle_type == modal_flow::ExternalType::ClMem &&
224 frame.img.external_handle != 0)
226 cl_mem handle =
reinterpret_cast<cl_mem
>(
227 static_cast<uintptr_t
>(frame.img.external_handle));
229 cl_int err = clReleaseMemObject(handle);
230 if (err != CL_SUCCESS)
232 fprintf(stderr,
"Failed to release Frame cl_mem, err=%d\n", err);
235 const_cast<modal_flow::ImageView &
>(frame.img).external_handle = 0;
243 cached_features_map =
vio_manager->get_used_features_map();
251 int64_t t_cam = _apps_time_monotonic_ns();
257 int64_t t_end = _apps_time_monotonic_ns();
258 double dt_ms = (double)(t_end - t_start) / 1e6;
259 if (dt_ms / batch.size() > 32.0 &&
en_debug)
261 printf(
"WARNING: IMU callback took too long: %8.3f ms for %d msgs\n", dt_ms, (
int)batch.size());
266 std::lock_guard<std::mutex> lk(
reset_mtx);
284 __attribute__((unused))
void *context)
290 pipe_client_flush(
IMU_CH);
321 pipe_client_set_helper_thread_priority(
IMU_CH, THREAD_PRIORITY_RT_HIGH);
323 int flags = CLIENT_FLAG_EN_SIMPLE_HELPER;
326 IMU_RECOMMENDED_READ_BUF_SIZE * 2) != 0)
328 fprintf(stderr,
"failed to open imu client pipe\n");
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)
std::atomic< uint32_t > active_callbacks
Number of callbacks inside the system.
char imu_name[64]
IMU device name.
voxl::FrameTransform frame_transform
Global frame transform instance.
std::mutex reset_mtx
Mutex used by reset thread.
imu_model_t imu_model
Active IMU model.
std::unique_ptr< ov_msckf::VioManager > vio_manager
Main VIO manager instance.
int en_debug
Enable debug output.
std::condition_variable reset_cv
Reset conditional variable.
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.
std::atomic< double > imu_rate_hz
Estimated IMU sampling rate in Hz.
#define PROCESS_NAME
Process name for the VOXL OpenVINS server.
#define IMU_CH
MPA client channel for IMU data input.
static CameraQueueFusion & getInstance()
Get singleton instance.
bool getSortedBatch(double timestamp_cutoff, std::vector< ov_core::CameraData > &out)
Get sorted batch of camera data.
void publish(std::shared_ptr< ov_msckf::State > state, std::map< double, std::vector< std::shared_ptr< ov_core::Feature > > > used_features_map={})
Publish VIO data.
static Publisher & getInstance()
Get singleton instance.