别再死磕PID参数了!用STM32做平衡小车,我的卡尔曼滤波与三环控制调试心得

张开发
2026/4/20 3:47:10 15 分钟阅读

分享文章

别再死磕PID参数了!用STM32做平衡小车,我的卡尔曼滤波与三环控制调试心得
从零到稳STM32平衡小车实战调试全记录调试平衡小车的夜晚实验室里只剩下我和那台不断摔倒的倔强小车。当它终于稳稳立在桌面时我才明白——参数只是表象真正需要调校的是我们对系统理解的深度。本文将分享那些调试手册不会告诉你的实战细节从传感器数据到三环耦合带你避开我曾踩过的每一个坑。1. 传感器数据平衡小车的眼睛校准MPU6050的原始数据就像未经驯服的野马直接使用只会让小车疯狂摇摆。我的第一个教训来自未校准的传感器——即使放在水平桌面原始加速度计读数也显示有3°倾斜。传感器校准不是可选项而是必选项。校准加速度计的实用方法// 在水平静止状态下采集100组数据求均值 void MPU6050_Calibrate() { int32_t acc_sum[3] {0}; for(int i0; i100; i) { MPU6050_Read_Accel(ax, ay, az); acc_sum[0] ax; acc_sum[1] ay; acc_sum[2] az; HAL_Delay(10); } acc_offset[0] acc_sum[0]/100; acc_offset[1] acc_sum[1]/100; acc_offset[2] (acc_sum[2]/100) - 16384; // 假设Z轴朝下 }陀螺仪校准更需注意温度影响。实测发现工作30分钟后零漂会变化15%左右。我的解决方案是在每次上电时自动校准并在主循环中监测温度变化校准方式误差范围(°/s)适用场景上电单次校准±0.5室温环境稳定周期性温度补偿±0.2长时间运行动态自适应校准±0.1高精度要求场景提示校准时务必移除电机振动干扰我曾因忘记断开电机电源导致校准数据完全失效2. 姿态解算滤波算法的艺术选择卡尔曼滤波不是银弹。在资源有限的STM32F103上我发现简化版的互补滤波反而更实用。以下是三种算法的实测对比卡尔曼滤波实现占用15% CPU资源void Kalman_Update(float acc_angle, float gyro_rate) { // 预测阶段 angle (gyro_rate - gyro_bias) * dt; P[0][0] dt * (dt*P[1][1] - P[0][1] - P[1][0] Q_angle); P[0][1] - dt * P[1][1]; P[1][0] - dt * P[1][1]; P[1][1] Q_gyro * dt; // 更新阶段 float S P[0][0] R_angle; K[0] P[0][0] / S; K[1] P[1][0] / S; float y acc_angle - angle; angle K[0] * y; gyro_bias K[1] * y; // 协方差更新 P[0][0] - K[0] * P[0][0]; P[0][1] - K[0] * P[0][1]; P[1][0] - K[1] * P[0][0]; P[1][1] - K[1] * P[0][1]; }互补滤波仅3% CPU占用float Complementary_Filter(float acc_angle, float gyro_rate) { static float angle 0; float alpha 0.98; // 陀螺仪权重 angle alpha * (angle gyro_rate * dt) (1-alpha) * acc_angle; return angle; }实际测试数据算法类型静态误差(°)动态延迟(ms)CPU占用率原始加速度计±2.5101%互补滤波±0.8253%卡尔曼滤波±0.35015%四元数解算±0.58025%在电池供电场景下我最终选择了带动态权重调整的互补滤波——当检测到剧烈运动时自动降低加速度计权重。3. 三环控制调试顺序的奥秘直立环、速度环、转向环就像三个性格迥异的搭档。错误的调试顺序会导致系统永远无法收敛。我的血泪史证明必须先调直立环再调速度环最后才是转向环。3.1 直立环小车的脊柱直立环参数调试步骤将Ki和Kd设为0Kp从5开始逐步增加观察小车反应找到能短暂立住的临界Kp值引入Kd抑制震荡通常从Kp的1/10开始最后加入微量Ki消除稳态误差典型参数范围typedef struct { float Kp; // 比例系数 (范围8.0-15.0) float Ki; // 积分系数 (范围0.001-0.01) float Kd; // 微分系数 (范围0.1-1.5) } PID_Params;注意直立环的Kd对电机响应速度敏感更换电机后必须重新调整3.2 速度环隐形的推手速度环的秘诀在于间接控制。通过修改直立环的目标角度来实现速度控制float target_angle 0; // 直立环目标角度 void Speed_Control(float target_speed) { static float speed_integral 0; float current_speed (motor1_rpm motor2_rpm)/2.0; float error target_speed - current_speed; speed_integral error * dt; speed_integral constrain(speed_integral, -10, 10); // 防饱和 target_angle speed_Kp * error speed_Ki * speed_integral; }常见问题排查表现象可能原因解决方案小车加速后停不下来速度环Ki过大降低Ki增加积分限幅出现周期性前后摇摆速度环与直立环耦合过强减小速度环Kp响应迟钝速度环Kp太小逐步增大Kp直到出现轻微超调3.3 转向环最后的舞者转向环调试要解决的核心矛盾是快速响应 vs 稳定性。我的经验公式转向环Kp ≈ (0.5~0.8) × 速度环Kp 转向环Kd ≈ 直立环Kd × 0.3通过陀螺仪Z轴角速度反馈可以有效抑制转向过冲float Turn_Control(float target_turn) { float turn_error target_turn - gyro_z; static float turn_integral 0; turn_integral turn_error * dt; turn_integral constrain(turn_integral, -100, 100); return turn_Kp * turn_error turn_Ki * turn_integral; }4. 实战调试从理论到稳定的距离实验室理想环境与真实场景的差距往往需要额外的技巧来弥补。以下是我总结的调试工具箱电源噪声处理方案在电机电源并联470μF0.1μF电容组合为STM32增加LC滤波电路10μH10μF软件上采用中值滤波处理ADC采样机械振动抑制方法使用硅胶垫隔离电机与主控板在轮轴处添加O型橡胶圈降低PWM频率到8kHzN20电机最佳点参数自整定技巧void Auto_Tune_PID() { // 施加阶跃扰动 Motor_SetPWM(100, 100); HAL_Delay(50); Motor_SetPWM(0, 0); // 采集响应曲线 Record_Oscillations(); // 根据Ziegler-Nichols法则计算参数 Calculate_PID_Params(); }调试过程中最宝贵的工具是数据可视化。我开发了基于蓝牙的上位机可以实时绘制关键参数曲线当所有环节都调通后那个曾让我夜不能寐的平衡小车终于能优雅地立在桌面上甚至可以用手机蓝牙控制它跳8字舞。这个过程教会我的不仅是PID参数调整更是系统级思考的方式——每个模块的优化都必须放在整体中考量。

更多文章