Trouble removing gravity from calibrated IMU acceleration (dual ICM-20948 + quaternions)

56 views (last 30 days)
Hi everyone,
I’m working on a project where I collect motion data using two ICM-20948 IMUs connected to an ESP32. I apply a 6-pose accelerometer calibration on the microcontroller and later process the data in MATLAB to obtain linear acceleration in the global frame (gravity-free). However, even after rotating the accelerometer data using the quaternions and subtracting gravity, the results still don’t look correct.
Before assuming my processing is wrong, I want to double-check with the community whether my MATLAB approach for gravity removal is correct — and whether I’m handling the quaternion convention properly.📍 Data Acquisition Pipeline (short summary)
  • Hardware: ESP32 + 2× ICM-20948
  • I use the ICM20948_WE library
  • On the ESP32 I:✅ Read accel & gyro✅ Apply bias + gain from 6-pose calibration✅ Log calibrated accel (in g), calibrated gyro, and quaternions
  • No magnetometer used (so yaw may drift, but recordings are 30–120 s only)
  • Data is saved as:
q0 q1 q2 q3 ax ay az gx gy gz
🧠 MATLAB Processing (core part of code)
Below is the section where I align the IMU with the global frame and remove gravity. I use the first ~5 s (static) to estimate the gravity direction, align the IMU Z-axis to global Z, rotate accel using the quaternions, and subtract gravity:
%% CORREÇÃO DA ORIENTAÇÃO INICIAL (PERÍODO PARADO)
fprintf('\n--- Correção da Orientação Inicial (5 s parado) ---\n');
G = 9.80665; % m/s²
Fs_my = 1 / mean(diff(T.t_s));
Nrest = round(5 * Fs_my);
% IMU1
a1_rest = [T.a1x(1:Nrest), T.a1y(1:Nrest), T.a1z(1:Nrest)];
g_est1 = mean(a1_rest, 1);
g_est1 = g_est1 / norm(g_est1);
% direção da gravidade medida
% Quaternion inicial
Q1 = [T.q10, T.q11, T.q12, T.q13];
if mean(abs(Q1(:,1))) < mean(abs(Q1(:,4)))
Q1 = [Q1(:,4), Q1(:,1:3)]; % tentar garantir [w x y z]
end
Q1 = Q1 ./ vecnorm(Q1,2,2);
% Vetor Z global ideal
z_ref = [0 0 1];
% Calcular rotação para alinhar g_est1 -> z_ref
v = cross(g_est1, z_ref);
s = norm(v);
if s ~= 0
c = dot(g_est1, z_ref);
v_skew = [0 -v(3) v(2); v(3) 0 -v(1); -v(2) v(1) 0];
R_align = eye(3) + v_skew + v_skew^2 * ((1 - c)/(s^2));
else
R_align = eye(3);
end
% Converter aceleração e alinhar
a1 = [T.a1x, T.a1y, T.a1z];
a1_gbl = quatrotate(Q1, a1);
a1_gbl_corr = (R_align * a1_gbl')';
% Remover gravidade
a1_free_gbl = a1_gbl_corr - [0 0 G];
(I apply the same procedure for IMU2 if present.)📎 Example of the issue
When visualizing the acceleration before and after gravity removal, the result still does not look physically correct, despite the 6-pose calibration and quaternion rotation.
Image 1: Before gravity removal
Image 2: After gravity removal — still incorrect)
My Main Questions
  1. Is my approach to rotate acceleration into the global frame and remove gravity mathematically correct?(Or am I applying the alignment/rotation in the wrong order?)
  2. Should gravity be removed before or after applying R_align?Some posts suggest subtracting gravity in the sensor frame, others in global frame.
  3. Quaternion convention:I’m assuming MATLAB’s quatrotate expects [w x y z] (scalar-first).Am I handling the quaternion conversion correctly here, or could this be a mismatch with the ICM-20948 library?
  4. Given that I’m not using the magnetometer:For recordings of 30–120 s, is yaw drift likely to significantly affect gravity removal, or should it still work reasonably well?
Any help or guidance would be greatly appreciated — especially if someone spots a conceptual mistake or if there’s a more robust approach to handle gravity removal for this sensor.
Thanks in advance!
  9 Comments
Maria Inês
Maria Inês on 10 Nov 2025 at 8:53
Thank you again, this has been extremely valuable.
I’ll implement the steps you highlighted:
• improve the accelerometer calibration (including scale + misalignment),
• apply tilt-only gravity removal (rather than treating the rotation as a full DCM), and
• run tests with both controlled movements and synthetic data to verify the pipeline before moving forward.
I don’t want to take more of your time at this stage. I’ll apply these changes, analyse the results, and if it’s okay, I may share a short update later just to confirm that I’m interpreting the outcomes correctly.
Your guidance has genuinely helped me correct the conceptual foundation of this part of the project. Thank you for that.

Sign in to comment.

Answers (0)

Products


Release

R2023b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!