# pragma once #include #include #ifndef PI #define PI 3.14159265358979323846 #define PI_FL 3.141592f #endif class IMUProcessor { // theta is the angle of camera rotation in x, y and z components float3 theta; std::mutex theta_mtx; /* alpha indicates the part that gyro and accelerometer take in computation of theta; higher alpha gives more weight to gyro, but too high values cause drift; lower alpha gives more weight to accelerometer, which is more sensitive to disturbances */ float alpha = 0.9f; bool firstGyro = true; bool firstAccel = true; // Keeps the arrival time of previous gyro frame double last_ts_gyro = 0; public: // Function to calculate the change in angle of motion based on data from gyro void process_gyro(rs2_vector gyro_data, double ts) { if (firstGyro) // On the first iteration, use only data from accelerometer to set the camera's initial position { firstGyro = false; last_ts_gyro = ts; return; } // Holds the change in angle, as calculated from gyro float3 gyro_angle; // Initialize gyro_angle with data from gyro gyro_angle.x = gyro_data.x; // Pitch gyro_angle.y = gyro_data.y; // Yaw gyro_angle.z = gyro_data.z; // Roll // Compute the difference between arrival times of previous and current gyro frames double dt_gyro = (ts - last_ts_gyro) / 1000.0; last_ts_gyro = ts; // Change in angle equals gyro measures * time passed since last measurement gyro_angle = gyro_angle * static_cast(dt_gyro); // Apply the calculated change of angle to the current angle (theta) std::lock_guard lock(theta_mtx); theta.add(-gyro_angle.z, -gyro_angle.y, gyro_angle.x); } void process_accel(rs2_vector accel_data) { // Holds the angle as calculated from accelerometer data float3 accel_angle; // Calculate rotation angle from accelerometer data accel_angle.z = atan2(accel_data.y, accel_data.z); accel_angle.x = atan2(accel_data.x, sqrt(accel_data.y * accel_data.y + accel_data.z * accel_data.z)); // If it is the first iteration, set initial pose of camera according to accelerometer data (note the different handling for Y axis) std::lock_guard lock(theta_mtx); if (firstAccel) { firstAccel = false; theta = accel_angle; // Since we can't infer the angle around Y axis using accelerometer data, we'll use PI as a convetion for the initial pose theta.y = PI_FL; } else { /* Apply Complementary Filter: - high-pass filter = theta * alpha: allows short-duration signals to pass through while filtering out signals that are steady over time, is used to cancel out drift. - low-pass filter = accel * (1- alpha): lets through long term changes, filtering out short term fluctuations */ theta.x = theta.x * alpha + accel_angle.x * (1 - alpha); theta.z = theta.z * alpha + accel_angle.z * (1 - alpha); } } // Returns the current rotation angle float3 get_theta() { std::lock_guard lock(theta_mtx); return theta; } };