基于STM32 HAL库的旋转倒立摆实战:从双环PID调参到自动起摆算法详解

基于STM32 HAL库的旋转倒立摆实战:从双环PID调参到自动起摆算法详解
1. 旋转倒立摆项目概述旋转倒立摆是控制理论中经典的实验平台也是各类电子设计竞赛的热门选题。这个看似简单的装置实际上蕴含着丰富的控制理论知识和实践技巧。作为一个亲身经历过调参地狱的过来人我想分享一些在STM32平台上实现旋转倒立摆的实战经验。这个项目的核心目标是通过STM32控制直流减速电机使摆杆能够从自然下垂状态自动起摆并保持倒立平衡。听起来简单但要让这个系统稳定工作需要解决三个关键问题精确的角度检测、实时的电机控制以及最核心的双环PID算法设计。我们使用的硬件配置包括STM32F103C8T6最小系统板、带编码器的直流减速电机、角位移传感器和TB6612电机驱动模块。2. 硬件配置与传感器调试2.1 关键硬件选型建议在硬件选择上我强烈建议使用带AB相编码器的直流减速电机。编码器分辨率不需要特别高600线就足够但电机减速比很关键。经过实测减速比在1:30到1:50之间效果最佳。太大则响应慢太小则扭矩不足。我最初使用的电机减速比是1:34后来换成1:43发现控制效果明显改善。角位移传感器推荐使用单圈绝对型量程±180°就够用。这里有个坑要注意传感器的安装位置要尽量靠近摆杆旋转轴心如果安装位置偏移会导致角度测量出现非线性误差。我曾经因为这个原因调试了两天都没找出问题所在。2.2 传感器数据采集优化ADC采集角度数据时单次采样往往不够稳定。我的做法是采用滑动窗口均值滤波卡尔曼滤波的组合方案。但由于STM32F103C8T6的Flash空间有限最终只实现了5点滑动滤波。具体实现如下#define FILTER_NUM 5 uint16_t ADC_Read(void) { static uint16_t adc_buf[FILTER_NUM] {0}; static uint8_t index 0; uint32_t sum 0; // 采集新数据放入缓冲区 HAL_ADC_Start(hadc1); adc_buf[index] HAL_ADC_GetValue(hadc1); if(index FILTER_NUM) index 0; // 计算滑动平均值 for(uint8_t i0; iFILTER_NUM; i) { sum adc_buf[i]; } return sum / FILTER_NUM; }编码器配置要注意定时器的工作模式。使用STM32CubeMX配置时要选择Encoder Mode并将两个输入通道都启用。读取编码器值时建议使用32位计数器如果有的话可以避免频繁溢出问题。3. 双环PID控制设计3.1 角度环内环实现角度环是系统的核心直接决定摆杆能否保持直立。我采用了变参数PID设计即KP值随偏差大小动态调整。这种线性KP策略在小偏差时控制柔和大偏差时响应迅速float Gray_PID(int adc_value, int aim_value) { static int last_bias 0; int bias aim_value - adc_value; float current_kp; // 线性KP计算 int abs_bias abs(bias); if(abs_bias 500) { current_kp 0.5; // 小偏差时KP较小 } else { current_kp 0.5 0.001*(abs_bias-500); // 大偏差时KP线性增大 } // 微分项计算 float diff bias - last_bias; last_bias bias; return current_kp*bias - Gray_KD*diff; }调试角度环时有个实用技巧先调KP让系统出现等幅振荡此时的KP值记为Kp0然后取Kp0的0.6倍作为最终KP值。KD的调试方法是观察系统响应当出现高频抖动时逐步增大KD直到抖动消失然后取该值的80%。3.2 位置环外环优化位置环的作用是补偿角度环的稳态误差防止摆杆慢慢偏移。这里我采用了积分分离策略大幅改善了系统稳定性int GetVelocity(int Encoder_Cnt, int AimVelocity) { static int Encoder_Integral 0; static int Encoder_last 0; int Encoder_Err AimVelocity - Encoder_Cnt; // 低通滤波 int Encoder Encoder_Err*0.3 Encoder_last*0.7; Encoder_last Encoder; // 积分分离 if(abs(Encoder) 5) { // 小偏差时启用积分 Encoder_Integral Encoder; if(Encoder_Integral 250) Encoder_Integral 250; if(Encoder_Integral -250) Encoder_Integral -250; } else { Encoder_Integral 0; // 大偏差时清除积分 } return Encoder*kp Encoder_Integral*ki; }位置环的调试顺序应该是先调KP使系统能够抵抗轻微扰动但不会剧烈振荡然后调KI消除稳态误差。KI值过大会引起系统振荡建议从KP值的1/100开始尝试。4. 自动起摆算法详解4.1 基础起摆策略自动起摆是项目中最具挑战性的部分。我尝试过三种方案正弦扫频法、能量控制和 bang-bang 控制。最终采用了改进型 bang-bang 控制在摆杆到达最低点时反转电机方向void Auto_SwingUp(void) { static uint8_t direction 0; static uint16_t wait_count 0; // 检测摆杆通过最低点 if(adc_value 3700 adc_value 3800) { direction !direction; // 反转方向 wait_count 0; } // 施加控制量 if(wait_count 20) { // 短暂延时防止抖动 if(direction) { Moto1 2000; // 正向转动 } else { Moto1 -2000; // 反向转动 } wait_count; } }这个算法的关键参数是控制量大小2000和等待计数20需要根据具体电机特性调整。太小的控制量起摆慢太大则容易过冲。4.2 平滑过渡到平衡状态当摆杆角度接近垂直位置±30°时需要平滑过渡到平衡控制模式。我设计了一个混合控制策略void Balance_Control(void) { if(abs(adc_value - aim_angle) 300) { // 进入平衡区 // 混合控制逐渐减小起摆控制量增加平衡控制量 float blend (300 - abs(adc_value - aim_angle)) / 300.0; Moto1 (1-blend)*Auto_SwingUp() blend*(Vertical_outVelocity_out); } else { Moto1 Auto_SwingUp(); // 继续起摆 } }这种渐进式切换避免了控制量突变导致的振荡。调试时要特别注意平衡区阈值这里是300的选择太大会过早切换太小则可能导致起摆能量不足。5. 圆周运动与抗干扰实现5.1 圆周运动控制在保持倒立的前提下实现圆周运动本质是在位置环的目标值上叠加一个缓慢变化的偏移量void Circle_Motion(void) { static uint16_t angle 0; // 每10ms增加1° angle 1; if(angle 360) angle 0; // 将角度转换为编码器目标值 int target angle * ENCODER_PER_DEGREE; Velocity_out GetVelocity(Encoder_Cnt, target); // 综合控制 Moto1 Vertical_out Velocity_out; }这里ENCODER_PER_DEGREE是每度对应的编码器脉冲数需要根据实际系统测量得出。速度不宜过快建议1-2秒完成一圈。5.2 抗干扰设计为了通过抗干扰测试我在角度环中增加了冲击检测和恢复逻辑// 在角度环中增加冲击检测 if(abs(bias - last_bias) 50) { // 检测到突变 Gray_KD * 2.0; // 临时增大微分项 recovery_timer 10; // 保持10个周期 } else if(recovery_timer 0) { recovery_timer--; if(recovery_timer 0) { Gray_KD / 2.0; // 恢复原KD值 } }这种自适应调节KD的方法能有效抑制突发干扰实测可以使系统在受到扰动后1秒内恢复平衡。参数50和10需要根据具体系统的动态特性调整。6. 调试技巧与常见问题6.1 系统调试步骤单独测试角度环用手扶住摆杆在不同角度观察电机响应是否正确测试位置环给定期望位置观察电机能否准确到达并保持开环测试起摆先手动设置电机转动方向观察摆杆运动是否符合预期闭环起摆调试逐步调整起摆参数记录每次摆动的最大角度平衡控制调试微调PID参数优化稳定性和抗干扰能力6.2 常见问题解决问题1起摆时摆杆来回摆动但幅度不增大原因电机换向时机过早或过晚解决调整换向检测阈值或增加控制量问题2平衡时出现低频振荡原因位置环积分项过大解决减小KI或采用积分分离问题3电机发热严重原因死区设置不当导致H桥直通解决检查电机驱动死区设置确保正反转切换时有足够死区时间问题4角度测量出现跳变原因ADC受到电机干扰解决增加电源滤波电容缩短传感器引线或改用差分测量调试时可以先用VOFA等工具实时查看关键变量波形比单纯看现象要高效得多。特别是观察角度偏差、控制输出和积分项这三者的关系能快速定位问题所在。