简介:这套基于STM32F429与MPU9250的姿态解算资料,面向嵌入式开发者及无人机、机器人姿态估计学习者,解决从惯性传感器原始数据到航向角、横滚角、俯仰角的提取与融合问题。资料采用正点原子阿波罗F429开发板读取MPU9250数据,经椭球矫正与均值滤波后,以基于四元数的Madgwick算法完成多轴数据融合,四元数亦可直接转换为横滚角与俯仰角,便于姿态显示或运动控制。压缩包整体约18.73MB,内容包含STM32工程源码与Matlab处理脚本,前者覆盖传感器驱动、矫正滤波和姿态融合主流程,后者可用于数据读取、算法验证与结果可视化。目前已有4918人学习,适合具备一定STM32基础、希望移植或改进姿态解算算法的开发者。作者提示均值滤波部分可进一步调整,读者可结合实际硬件修改参数,借此加深对Madgwick融合原理及椭球矫正作用的理解。
1. 基于MPU9250的航向角获取:从椭球矫正到Madgwick融合,一份能直接跑的STM32与MATLAB源码
把MPU9250装到小车或云台上,最让人头疼的不是I2C通信,而是磁力计数据一塌糊涂——航向角转着转着就偏了,静止时也在漂,转了一圈回来角度回不到原点。这个问题的根源不在于姿态解算算法本身,而在于磁力计没有做椭球矫正,加上滤波参数没调对。我拆过一份基于MPU9250获取航向角的STM32与MATLAB源码包,它把整个链路打通了:MATLAB端做基于最小二乘的椭球矫正参数求解,STM32端跑Madgwick算法做九轴姿态融合,最后直接输出稳定的航向角。对于正在做惯导入门、云台控制或者机器人导航的开发者来说,这份资源的价值在于它把磁力计矫正这个最容易被跳过的环节补上了,而且给了完整的实测流程。下面按实际使用顺序拆开讲。
2. 椭球矫正:磁力计数据为什么是歪的,最小二乘怎么把它拉回正圆
2.1 磁力计误差模型与椭球假设
MPU9250内部的磁力計是HMC5883L兼容的三轴磁阻传感器,原始输出是三个轴的磁场分量。理想情况下,把传感器在空中转一圈,三轴数据在三维空间里应该落在一个球面上,球心在原点。但实际情况远非如此:首先,PCB板上元器件和电池会产生硬磁干扰,这类干扰相当于在磁场矢量上叠加了一个固定偏置,效果是把球心从原点平移走了;其次,电路板走线、外壳金属件产生的软磁干扰会让某个轴方向的灵敏度比其他轴大,效果是把球面压扁或拉长成椭球;再加上传感器本身三轴的灵敏度不一致和温漂,最终你看到的三轴数据落在一个既不居中、轴长也不等的椭球面上。
这意味着直接用原始数据做航向解算,测得的地磁场方向是斜的,航向角自然不准。椭球矫正的目标就是求出这个椭球的球心和三个轴的缩放系数,然后把数据变换回标准球面。常见做法是:先采集足够多的数据点(覆盖各个方向),然后用最小二乘法拟合椭球方程。椭球的一般方程写出来是:
ax² + by² + cz² + 2fyz + 2gzx + 2hxy + 2px + 2qy + 2rz + d = 0
求解这十个参数就能得到椭球的中心、轴长和旋转方向。不过一般MPU9250的应用场景里,我们通常假设椭球的三个主轴和传感器坐标轴基本对齐,忽略交叉项,简化为六个参数的求解,这样在STM32上跑起来也省事。但这份MATLAB源码里用的是完整的二次型拟合,精度更高,拟合完还能把旋转矩阵也求出来。
2.2 MATLAB端最小二乘椭球拟合代码拆解
MATLAB脚本的核心功能有两个:一是读取采集到的原始磁力计数据,二是拟合椭球并输出矫正参数。先看数据读取和椭球拟合部分:
% 加载采集的原始磁力计数据,格式为 [mag_x, mag_y, mag_z] raw_data = load('mag_raw_data.csv'); x = raw_data(:,1); y = raw_data(:,2); z = raw_data(:,3); % 构造椭球拟合矩阵 D = [x.^2, y.^2, z.^2, 2*y.*z, 2*x.*z, 2*x.*y, 2*x, 2*y, 2*z, ones(n,1)] n = length(x); D = [x.^2, y.^2, z.^2, 2*y.*z, 2*x.*z, 2*x.*y, 2*x, 2*y, 2*z, ones(n,1)]; % 约束条件矩阵 C,保证拟合结果为椭球而非双曲面 C = zeros(10,10); C(1,2) = -1; C(1,3) = -1; C(2,1) = -1; C(3,1) = -1; C(2,3) = -1; C(3,2) = -1; % 广义特征值法求解最小二乘问题 D'*D*v = lambda*C*v [V, ~] = eig(D'*D, C); for i = 1:size(V,2) v = V(:,i); % 归一化:保证拟合结果满足约束 if v'*C*v > 0 && abs(v(1)) > 1e-10 v = v / norm(v); % 提取椭球参数 a = v(1); b = v(2); c = v(3); f = v(4); g = v(5); h = v(6); p = v(7); q = v(8); r = v(9); d = v(10); % 后续处理... end end这里的逻辑是:把椭球方程改写成矩阵形式后,利用广义特征值分解在约束条件下求最小二乘解。约束矩阵C的作用是保证拟合结果确实是椭球(正定二次型)而不是其他二次曲面。代码中D'*D是被最小化的目标,C是约束。
参数说明:raw_data必须是至少覆盖6个方向的数据,实际建议采集1000组以上,转得越均匀越好,否则拟合出来的椭球在某个轴向上会失真。eig(D'*D, C)求解的是广义特征值问题,其结果中满足约束的特征向量就是椭球系数。这段代码跑完会输出一组椭球参数[center_x, center_y, center_z, scale_x, scale_y, scale_z],以及可选的旋转矩阵。
2.3 矫正参数怎么用:从椭球系数到数据变换
拿到椭球参数后,矫正一个原始磁力计数据点[mx, my, mz]的变换流程是:先减去球心偏移,再按轴长缩放,最后如果有旋转矩阵就乘上去。对应的MATLAB代码片段:
% 椭球拟合结果示例 center = [center_x, center_y, center_z]; scale = [scale_x, scale_y, scale_z]; % 矫正单个点 corrected = (raw_point - center) ./ scale; % 完整数据矫正 corrected_data = (raw_data - repmat(center, n, 1)) ./ repmat(scale, n, 1);在实际的STM32固件里,这段变换会被展开成整数运算,因为浮点运算在Cortex-M4上虽然没问题,但为了效率一般都会把1/scale预先算好存成定点数。注意,椭球矫正和加速度计陀螺仪的校准是两回事,加速度计零偏是单独标定的,不要混在一起做。
避坑点:如果采集数据时传感器只在水平面上转,Z轴数据变化范围很小,拟合出的Z轴scale会严重失真。我一般会要求数据采集时把传感器倾斜45度以上转,或者干脆做球面螺旋运动,保证三轴都能拉到最大值。另外,椭球矫正要等传感器静止放置时做,磁力计对振动不敏感但会被电机磁场干扰,如果数据里有明显的周期波动,先检查供电电流是不是太大了。
3. STM32端Madgwick融合:从原始数据到四元数再到航向角
3.1 MPU9250初始化、读取与数据对齐
MPU9250内部是三颗独立的传感器:加速度计和陀螺仪在AKM8963的旁边,磁力计则是通过I2C总线挂在内部的一个从设备上。因此初始化分两步:先初始化MPU9250的加速度计和陀螺仪,再通过MPU9250的I2C主机接口去访问磁力计。常见的初始化顺序是:
// MPU9250初始化 void mpu9250_init(void) { // 复位 write_reg(MPU9250_PWR_MGMT_1, 0x80); delay_ms(100); write_reg(MPU9250_PWR_MGMT_1, 0x00); // 正常模式 // 配置加速度计量程为±8g,陀螺仪量程为±2000dps write_reg(MPU9250_ACCEL_CONFIG, 0x10); write_reg(MPU9250_GYRO_CONFIG, 0x18); // 配置数字低通滤波器,带宽184Hz write_reg(MPU9250_CONFIG, 0x01); // 配置采样率分频器,输出频率为1kHz write_reg(MPU9250_SMPLRT_DIV, 0x04); // 磁力计初始化 write_reg(MPU9250_I2C_MST_CTRL, 0x0D); // I2C模式配置 write_reg(MPU9250_I2C_SLV0_ADDR, 0x0C); // 磁力计地址 write_reg(MPU9250_I2C_SLV0_REG, 0x02); // 从寄存器0x02开始连续读取 write_reg(MPU9250_I2C_SLV0_CTRL, 0x88); // 使能连续读取,每次读8字节 }初始化完成后,读数据的顺序有个小坑:磁力计的原始数据更新频率通常是100Hz,而加速度计和陀螺仪能到1kHz,如果你用高频读取磁力计,会读到重复的旧值。在Madgwick融合里,磁力计数据更新频率较低不是问题,但要注意读取时拿一个标志位来判断新数据是否就绪。我一般会在读取磁力计数据时检查ST1寄存器(0x02)的DRDY位,确认数据准备好了再读HXL到HZH六个字节。
数据对齐是另一个坑:MPU9250的加速度计和陀螺仪是24位寄存器左对齐存储的,去掉低两位后需要做算术右移补符号位;磁力计则是16位补码存储。把它们统一转换成int16后再带入算法。
3.2 Madgwick算法核心:梯度下降与互补权重
Madgwick算法的核心思想是用梯度下降法把加速度计和磁力计测得的姿态方向与陀螺仪积分方向之间的误差最小化,然后用一个权重因子把它们融合起来。它的优势在于只用一个可调的增益参数beta,不像EKF那样需要调协方差矩阵,而且计算量小,在72MHz主频的STM32F103上跑起来毫无压力。
算法每轮迭代的流程是:先用陀螺仪数据更新四元数,计算陀螺仪积分带来的姿态变化;然后根据加速度计和磁力计的测量值计算目标姿态,用梯度下降法求误差函数的梯度;最后用beta决定陀螺仪积分和梯度下降修正之间的权重,合成最终四元数。
// Madgwick算法更新函数(关键部分) void madgwick_update(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz) { float q1 = q[0], q2 = q[1], q3 = q[2], q4 = q[3]; float norm; float f1, f2, f3, f4, f5, f6; float s1, s2, s3, s4; float qDot1, qDot2, qDot3, qDot4; // 归一化加速度计和磁力计数据 norm = sqrt(ax*ax + ay*ay + az*az); ax /= norm; ay /= norm; az /= norm; norm = sqrt(mx*mx + my*my + mz*mz); mx /= norm; my /= norm; mz /= norm; // 计算目标观测方程f与雅可比矩阵J,求出梯度s f1 = 2*(q2*q4 - q1*q3) - ax; f2 = 2*(q1*q2 + q3*q4) - ay; f3 = 2*(0.5 - q2*q2 - q3*q3) - az; f4 = 2*mx*(0.5 - q3*q3 - q4*q4) + 2*my*(q2*q4 - q1*q3) + 2*mz*(q2*q3 + q1*q4) - mx; f5 = 2*mx*(q2*q3 - q1*q4) + 2*my*(0.5 - q2*q2 - q4*q4) + 2*mz*(q3*q4 + q1*q2) - my; f6 = 2*mx*(q2*q4 + q1*q3) + 2*my*(q3*q4 - q1*q2) + 2*mz*(0.5 - q2*q2 - q3*q3) - mz; // 雅可比矩阵J乘以f得到梯度 s1 = -4*f1*q3 + 4*f2*q2 - 4*f4*q3 - 4*f5*q4 - 2*f6*q3; s2 = 4*f1*q4 + 4*f2*q1 + 4*f3*q2 + 4*f4*q4 - 4*f5*q2 + 4*f6*q1; s3 = -4*f1*q1 + 4*f2*q4 - 4*f3*q3 + 4*f4*q2 - 4*f5*q1 - 2*f6*q4; s4 = 4*f1*q2 + 4*f2*q3 + 4*f3*q4 + 4*f4*q1 + 4*f5*q4 - 2*f6*q3; // 归一化梯度 norm = sqrt(s1*s1 + s2*s2 + s3*s3 + s4*s4); s1 /= norm; s2 /= norm; s3 /= norm; s4 /= norm; // 陀螺仪积分:qDot = 0.5 * q * gyro qDot1 = 0.5f*(-q2*gx - q3*gy - q4*gz); qDot2 = 0.5f*( q1*gx + q3*gz - q4*gy); qDot3 = 0.5f*( q1*gy - q2*gz + q4*gx); qDot4 = 0.5f*( q1*gz + q2*gy - q3*gx); // 融合:梯度下降修正项加权beta叠加到陀螺仪积分项 q1 += (qDot1 - beta*s1) * sample_freq; q2 += (qDot2 - beta*s2) * sample_freq; q3 += (qDot3 - beta*s3) * sample_freq; q4 += (qDot4 - beta*s4) * sample_freq; // 四元数归一化 norm = sqrt(q1*q1 + q2*q2 + q3*q3 + q4*q4); q[0] = q1 / norm; q[1] = q2 / norm; q[2] = q3 / norm; q[3] = q4 / norm; }参数说明:sample_freq是姿态解算频率,一般和陀螺仪输出频率一致,本工程中设为200Hz。beta是Madgwick论文推荐值0.8,但实际使用时需要根据传感器噪声水平调整:如果加速度计噪声大,beta适当增大(比如1.0~1.5);如果陀螺仪零偏稳定而磁力计干扰多,beta调小到0.3左右波形更平滑。这个参数没有标准答案,我通常用串口把原始姿态打印出来,一边转传感器一边调整。
3.3 从四元数到航向角的转换与坐标系约定
有了归一化四元数后,航向角yaw的计算公式是:
// 四元数转欧拉角,航向角单位是度 float yaw = atan2f(2.0f * (q[1]*q[2] + q[0]*q[3]), q[0]*q[0] + q[1]*q[1] - q[2]*q[2] - q[3]*q[3]) * 180.0f / PI;坐标系约定在这里非常关键。MPU9250的数据手册定义的是右手坐标系:X轴指向传感器的前方,Y轴指向左方,Z轴向上。四元数转欧拉角时如果坐标轴定义不对,出来的航向角会跟实际方向正好差90度或反号。
这份源码里航向角的参考系是:绕Z轴旋转为正方向,0度对应磁北方向。注意这里有个容易被忽略的点——磁北和地理北极之间有磁偏角,不同地区的磁偏角可以差十几度。如果要求地理航向,需要在最后加上磁偏角修正:
// 磁偏角修正,比如北京地区约-6度 yaw += declination_angle; if (yaw > 180.0f) yaw -= 360.0f; if (yaw < -180.0f) yaw += 360.0f;避坑点:很多开发者把atan2f的参数写反了,导致航向角在正负90度附近跳变。自查方法很简单:把传感器水平放在桌面上,让X轴指向磁北方向,此时输出的yaw应该接近0;顺时针旋转90度,yaw应该变成90左右。如果不是这样,检查四元数定义顺序是[w, x, y, z]还是[x, y, z, w],并检查atan2f两个参数的顺序。
4. MATLAB端数据回读与算法验证:离线解算和在线调试两手抓
4.1 用串口把STM32的姿态数据回传到MATLAB
实时调试姿态解算效果时,最直接的办法是让STM32通过串口把原始IMU数据和解算出的四元数、欧拉角一起发出来。串口发送的数据帧格式一般是:
帧头(0xAA 0x55) + 数据长度 + 帧类型(0x01) + 时间戳 + 原始加速度(3×short) + 原始陀螺(3×short) + 原始磁力(3×short) + 四元数(4×float) + 欧拉角(3×float) + 校验和MATLAB端写一个串口读取函数来解析这个帧:
% 串口配置:波特率921600,与STM32端保持一致 s = serialport('COM3', 921600, 'Timeout', 2); s.configureTerminator('LF'); % 读取数据并解析(示例帧类型0x01) data_buffer = zeros(1, 64); while true raw = read(s, 64, 'uint8'); if raw(1) == 0xAA && raw(2) == 0x55 payload_len = raw(3); % 解析四元数(4个float) quat = typecast(uint8(raw(10:25)), 'single'); % 解析欧拉角(3个float) euler = typecast(uint8(raw(27:38)), 'single'); % 实时绘制航向角曲线 plot_data(euler(3)); end end这里的参数要注意serialport的缓冲区大小和读取长度必须和数据帧长度严格匹配,否则帧同步会错位。另外,642字节的数据帧加上头尾,实际发送频率不能超过波特率允许的上限。921600波特率下每秒最多约92KB,如果发送频率是200Hz、每帧64字节,数据量是12.8KB/s,余量充足。
4.2 用MATLAB离线跑Madgwick和在线对比
这套源码包的另一个实用之处是它把MATLAB的离线处理脚本也提供了。用法是:先在STM32端把采集到的原始数据(六轴+磁力计)存到SD卡或者通过串口全量发出来,然后在MATLAB里用同样的Madgwick算法离线跑一遍姿态解算,和STM32实时解算的结果做对比。
离线跑的好处是你可以用完整数据集反复调整beta参数,对比不同参数下的姿态曲线变化,找到最优值后再写回STM32的代码。我经常这么干:先在线采集一组数据存成CSV,然后在MATLAB里试五个不同的beta值,画出航向角曲线,挑最平滑且不滞后的那一个。
离线解算代码的核心部分和STM32端一样,只是把定点运算换成MATLAB浮点运算,参数全部双精度。注意离线跑的时候采样率要和STM32端保持一致,否则beta的实际效果会不同——因为beta的单位隐含了采样率相关的时间步长。
4.3 使用MATLAB的曲线对比验证椭球矫正效果
验证椭球矫正是否有效的办法很简单:分别用矫正前后的磁力计数据计算航向角,然后对比在同一运动轨迹下航向角的波动幅度。矫正前如果航向角随姿态倾斜出现周期性加偏差,波动幅度可能超过正负10度;矫正后同一动作的航向角波动应该小于正负2度。
对比代码里可以加一个统计量,比如计算矫正前后航向角的均方根误差:
% 矫正前后航向角误差对比 yaw_before = calculate_yaw_from_mag(raw_data); yaw_after = calculate_yaw_from_mag(corrected_data); % 取一个参考段(传感器保持水平旋转的那一段) ref_segment = 100:500; err_before = rms(yaw_before(ref_segment) - reference_angle); err_after = rms(yaw_after(ref_segment) - reference_angle); fprintf('矫正前RMS误差: %.2f deg\n', err_before); fprintf('矫正后RMS误差: %.2f deg\n', err_after);如果矫正后RMS误差没有明显下降,最可能的三个原因是:采集数据时没有覆盖完整的姿态空间,或者运动过程中有电机磁场干扰,或者拟合算法里有奇异值没有处理掉。逐个排查即可。
5. 避坑与参数调试:从姿态跳变到Z轴漂移的六个实操记录
5.1 磁力计矫正后航向角仍然不准
现象:椭球矫正参数已经写入固件,但传感器水平旋转时航向角偏差依然在5度以上,且误差随转动方向不同而变化。
原因:椭球矫正没有考虑磁力计和加速度计/陀螺仪之间的时间对齐问题。磁力计采样频率低,如果姿态解算时用的是旧数据,就会在运动过程中引入偏差。
解决:确认MPU9250磁力计的采样率,在读取磁力计数据时检查数据就绪标志位;如果确实需要高频姿态输出,可以引入插值或简单地降低融合频率,让三种传感器数据的时间戳对齐。另外,检查椭球矫正参数是不是只在特定温度下有效——温漂会导致矫正参数变化,如果工作环境温度变化大,考虑做温度补偿。
5.2 静止时航向角缓慢漂移
现象:传感器静止放在桌面上,航向角以每分钟1~2度的速度缓慢漂移,陀螺仪零偏已经补偿过了,还是不行。
原因:陀螺仪的零偏在每次上电后会有细微变化,单纯减一个固定值补偿不彻底。另外,Madgwick算法在静止时完全依赖陀螺仪积分修正,如果beta调得过小,微小零偏无法被抑制。
解决:代码里加静态检测逻辑——当加速度计模长接近1g且陀螺仪三轴模长低于阈值(比如0.5dps)时,判定为静止,此时不断用当前的加速度计和磁力计姿态覆盖积分结果,把漂移清零。这个方法简单有效,比调大beta带来的动态响应变差要好得多。
5.3 快速转动时航向角出现跳变
现象:快速甩动传感器时,航向角偶尔会突然跳变几十度甚至180度,然后慢慢转回来。
原因:快速转动时陀螺仪瞬间输出可能饱和(±2000dps的量程被超出),或者磁力计在加速度过大时出现临时失准。更常见的原因是四元数在极端姿态下出现数值奇异性,导致atan2f的参数接近零。
解决:在算法入口加量程检测,若陀螺仪任一分量超过1800dps,这轮迭代只用陀螺仪积分而不用磁力计修正;同时对atan2f的两个参数加绝对值下限保护,防止除零和无穷值。我还会在代码里用saturate函数把四元数每个分量限制在[-1,1]范围内再归一化。
5.4 椭球拟合时提示矩阵奇异
现象:在MATLAB端运行椭球拟合脚本时,eig(D'*D, C)报错矩阵接近奇异,拟合结果明显不对。
原因:采集的数据点几乎都集中在一个平面上,Z轴信息严重不足,导致椭球在Z方向的参数无法唯一确定。这是最常见的操作问题。
解决:重新采集数据,刻意让传感器做倾斜旋转。我会按照一个固定的模式转:先水平转两圈,然后让Z轴朝上倾斜45度转两圈,再朝下倾斜45度转两圈,最后绕Z轴自转两圈。这样能保证数据点在三维空间均匀分布,拟合矩阵的条件数会小很多。
5.5 STM32端解算频率跑不到期望值
现象:代码里配的是200Hz解算频率,但实际用定时器测量只有90Hz左右,导致输出姿态有明显的阶梯感。
原因:MPU9250的原始数据读取放在主循环里,如果中间有阻塞操作(比如OLED显示、串口打印大数据帧),读取周期就被拉长了。
解决:把姿态解算放入定时器中断,数据读取也放在中断里;主循环只做显示和通信。中断优先级要高于串口接收,避免解算被串口中断打断。另外,如果使用I2C读取MPU9250数据,中断里要避免等待I2C总线——建议用DMA方式读取。
5.6 磁力计矫正参数在MATLAB拟合结果与STM32端效果不一致
现象:MATLAB拟合出的椭球参数带回去跑,STM32输出的航向角比MATLAB离线解算差很多。
原因:一个是数值精度问题——MATLAB里是双精度,STM32端为了速度把参数转成了单精度浮点或定点数,中间有舍入误差;另一个是矫正公式中坐标轴顺序没对上。
解决:在STM32端打印矫正后的磁力计数据,和MATLAB打印的矫正后数据对比,看每一轴的数值是否接近。如果差异只在一个固定的比例上,那就是坐标轴映射或者正负号反了。这种事情很玄学,但我每次都先做这一步再调其他参数,能省很多时间。
6. 把航向角做到可信:三步验证法和终值滤波技巧
拿到能跑的源码不是结束,真正痛苦的环节是验证输出到底对不对。我的做法是建立一套三步验证流程,每次改完代码都强制走一遍,过程不复杂但能挡住绝大多数翻车情况。
第一步是静态测试。把传感器固定在水平台面上,分别让X轴、Y轴朝向磁北方向,记录航向角输出,两个方向的读数应分别接近0度和90度,误差不超过2度。然后让传感器静止5分钟,航向角漂移总量应小于1度。如果这一步都过不了,不要急着往下走,问题大概率在磁力计矫正或者坐标系定义上,这块调通了后面才不会反复返工。
第二步是平面旋转测试。让传感器在水平面内匀速旋转三圈,记录航向角连续变化曲线。正常情况应该是平滑的锯齿波,每圈误差不超过3度,转完回到起点时角度差在2度以内。如果回程和去程曲线不重合,说明磁力计矫正不彻底或者有外部磁场干扰;如果曲线出现阶梯跳跃,检查四元数归一化是否稳定。
第三步是动态倾斜测试。把传感器装在一个可旋转的云台上,让其在俯仰和横滚方向做±45度的往复运动,同时记录航向角。这一步的目的是验证九轴融合在姿态变化时航向是否保持稳定——如果航向随俯仰角明显波动,说明磁力计的倾斜补偿或者椭球矫正参数有偏差。
验证过关后,还有一个影响使用体验的小技巧:航向角输出加一个终值滤波。不要用简单的滑动平均——那会把快速转动时的响应也钝化掉。我一般用一个一阶低通滤波,截止频率设在5Hz左右:
// 航向角一阶低通滤波 float yaw_filtered = yaw_filtered + alpha * (yaw_raw - yaw_filtered);这里的alpha取值0.2~0.4,取决于你需要的响应速度和噪声抑制之间的平衡。但注意,航向角在正负180度边界处会跳变,不能直接对角度值滤波。要先转成复数形式再滤波:
// 把角度转成复平面上的向量做滤波,避免边界跳变问题 float cos_yaw = cosf(yaw_raw * DEG_TO_RAD); float sin_yaw = sinf(yaw_raw * DEG_TO_RAD); float cos_f = cos_f + alpha * (cos_yaw - cos_f); float sin_f = sin_f + alpha * (sin_yaw - sin_f); yaw_filtered = atan2f(sin_f, cos_f) * RAD_TO_DEG;从那以后我每次做和航向角相关的项目,都强制走一遍三阶段验证流程,再处理滤波和边界问题——这套组合用下来确实没再打过脸。希望帮到你,少踩几个磁力计的坑。
本文还有配套的精品资源,点击获取