STM32直线倒立摆实战:从硬件到PID调参全解析
简介直线倒立摆STM32控制程序是一份面向嵌入式与自动控制学习者的完整工程源码基于STM32F10x系列Cortex-M3/M4实现倒立摆系统实时平衡控制。工程涵盖硬件驱动、传感器数据处理、PWM电机控制及多种控制策略包含PD、PID、微分先行、梯形积分、抗积分饱和与积分分离等算法适合用于控制理论实验、竞赛训练及嵌入式开发进阶。压缩包共214个文件核心代码以55个h与48个c为主同时包含编译生成的o、d、crf、axf、hex、map等中间与固件文件以及uvprojx、uvopt等Keil工程配置整体约3.79MB目录按BALANCE、HARDWARE、SYSTEM、USER等模块划分层次清晰。源码基于标准外设库STM32F10x_FWLib编写便于理解外设配置与算法实现细节已有818人学习可作为参考来快速搭建直线倒立摆实验平台、掌握PID调参与抗积分饱和等工程技巧。 直线倒立摆这玩意儿大学那会儿第一次在实验室看见摆杆直挺挺地立在小车上电机嗡嗡一响它居然能一直保持着那个危险的平衡点我当时就觉得这比什么流水灯、数码管带劲多了。后来自己动手用STM32做了一台从硬件焊接到PID调参中间踩了不少坑也把整套控制逻辑彻底吃透了。这篇文章就把整个项目从思路到落地掰开揉碎讲清楚给准备做这个方向或者想拿它当毕设题目的朋友一个完整的参考。1. 项目整体设计与控制方案选型1.1 直线倒立摆的本质与技术难点先把这个系统的控制对象说清楚。直线倒立摆是一个典型的一阶不稳定系统小车在轨道上做直线运动摆杆通过转轴安装在小车顶部重心在转轴上方。正常状态下摆杆会因为重力倒下去我们的任务就是通过控制小车在轨道上的加加速度让摆杆一直立在竖直位置附近。这玩意儿难在哪在于它“天生就不稳”。你可以把它理解成一个倒过来的钟摆你越想让它站稳它倒得越快。控制系统的任务本质上就是一个实时的“动态纠偏”摆杆往左倒小车就向左加速去“接住”它摆杆往右倒小车就向右加速。整个系统的响应速度要非常快控制周期稍微一慢摆杆就“咣当”一声砸下去了。系统的输入是小车的驱动力由电机提供输出是小车位移和摆杆角度。要控制的是两个物理量但它们又互相耦合——拉小车会让摆杆晃动摆杆晃动又反过来影响小车的位置。这就是典型的欠驱动系统自由度比控制输入多所以控制起来特别考验算法设计。1.2 控制方案选型PID与LQR的博弈常见的直线倒立摆控制算法有这么几类PID控制、LQR最优控制、模糊控制、根轨迹法、极点配置法。我最终选的是“PID为主、串级结构”的方案没上LQR。原因很简单第一PID思路直观调参过程能让你对系统动态特性有非常直观的体感对新手尤其友好第二在这个项目里PID配合串级结构内环角度环、外环位置环完全能把摆杆立住而且系统鲁棒性并不差第三LQR需要准确的系统模型和状态空间矩阵建模误差大的时候实际效果反而不如PID来得皮实。但这不意味着PID方案就是“无脑”的。它的难点在于两个环的耦合处理。内环角度环负责把摆杆稳定在竖直位置外环位置环负责把小车的位移控制在轨道中间。位置环的输出要作为角度环的给定值叠加进去——也就是说当小车偏离中心位置时位置环会“故意”给角度环一个角度偏置让小车朝着回中位的方向移动同时摆杆依然保持动态平衡。这套逻辑想通了整个程序框架就清晰了。2. 硬件选型与系统搭建细节2.1 主控芯片选型STM32F103系列足够了主控用的是STM32F103RCT6属于F1系列里的中端型号72MHz主频、256KB Flash、48KB RAM外设资源也够用。有些人一上来就想着上F4、F7其实没必要。倒立摆控制的核心是“快”但这里的快指的是控制周期足够短1ms到5ms级别F103的主频完全应付得来。F4的优势在于浮点运算单元和更丰富的外设但PID运算用定点数配合合适的缩放照样跑得很顺。选型时重点看这几个外设资源是不是够用高级定时器输出PWM、通用定时器编码器接口模式、ADC采集角度传感器电压、UART调试输出。F103系列这些都有而且标准库和HAL库的资料满天飞遇到问题随便一搜就能找到答案。开发环境我用的是Keil MDK5配合ST-Link V2下载调试稳定省心。2.2 传感与执行机构的搭配思路直线倒立摆的硬件构成主要分三块轨道与小车机械部分、电机与驱动执行部分、角度传感器与编码器反馈部分。我用的轨道是铝型材加同步带传动方案同步带轮传动的优势是结构简单、成本低电机的旋转运动通过同步带变成小车的直线位移响应也比较直接。电机选择的是带减速箱的直流减速电机配增量式编码器霍尔式分辨率为每圈13线经过4倍频后是52个脉冲/圈。减速比选1:30这样小车速度不会太快扭矩又够驱动整个结构。角度传感器是关键件。摆杆角度我用了常见的导电塑料电位器精度虽然不如编码器但胜在响应快、数据连续而且和STM32的ADC直接对接电路非常简单。电位器的线性度在±0.5%左右对于倒立摆这个应用场景完全够用。注意电位器是有旋转角度范围的通常345度安装的时候要让摆杆在竖直位置附近对应电位器中间区域保证ADC采样值在合适区间。还有一点容易忽略电机驱动芯片的选型。我用的是TB6612FNG比起L298N它的压降小很多响应也更快。虽然驱动能力只有1.2A但控制这种小功率直流减速电机绰绰有余。TB6612的PWM频率我设的是20kHz这个频率段人耳听不见明显噪声而且电机响应速度也在一个比较合理的位置。3. 控制程序设计核心要点3.1 系统架构两个闭环的分工配合程序框架上我采用的是经典的串级PID结构内环是角度环外环是位置环。整个控制周期定为2ms500Hz用定时器中断触发这也是我试过多个周期后觉得在响应速度和电机承受能力之间最合适的平衡点。角度环的任务是让摆杆保持在竖直位置附近它的输入是摆杆角度与目标角度的偏差输出是电机的PWM占空比。位置环的输入是小车位移与目标位置的偏差输出是对角度环目标角度的修正量。两个环串起来之后位置环的输出会叠加到角度环的设定值上形成“位置偏差通过角度修正传递给电机”的完整链路。这样设计的原因在于直接用一个位置环去控制电机PWM摆杆会瞬间倒掉因为电机加减速对摆杆角度的扰动远远大于对位置的影响。反过来只做角度环不做位置环摆杆虽然能立住但小车会一直朝一个方向加速很快就撞到限位开关。两个环必须同时工作各自负责一个物理量系统才能既稳得住摆杆又守得住位置。3.2 关键参数计算过程程序设计里参数计算是容易让人一头雾水的地方。我踩过坑后来把所有单位都统一了之后整个逻辑就顺畅了。增量式编码器的距离换算编码器分辨率是每圈52个脉冲13线×4倍频减速比1:30同步带轮的节圆直径是26mm那么小车移动1mm对应的脉冲数计算如下电机转一圈减速箱输出轴转1/30圈同步带轮走一个周长π×26≈81.68mm对应52个脉冲所以每毫米对应的脉冲数为52÷81.68≈0.637。但要注意编码器在电机端小车走1mm电机要转30×81.68/26×π我算一下等等这里需要仔细。统一算一下小车位移s与电机轴转角θ_m的关系是s (θ_m / (2π)) × (πd / n)其中d是同步带轮直径n是减速比。小车走1mm电机轴需要转过的圈数是n × (1mm / (πd)) 30 × (1 / 81.68) 0.367圈。编码器每圈52个脉冲那么1mm对应编码器脉冲数为0.367×52≈19.1个脉冲。这个数值是后续位置环PID处理时的重要系数。角度数据的处理相对简单电位器输出电压0V到3.3V对应角度范围约345度。ADC是12位的所以每个ADC单位对应的角度是345/4096≈0.084度。我把单位统一成“度”PID计算时直接用这个单位调试时打印出来也直观。PID参数我最终调试下来的参考值角度环Kp120Ki8Kd50位置环Kp0.8Ki0.05Kd0。不同机械结构差异很大这些数值仅供参考。但有个规律是通用的角度环的参数普遍比位置环大一到两个数量级因为角度是直接决定系统稳定性的量必须响应快、纠偏强。3.3 定时器配置与中断程序设计控制主循环放在定时器中断里用TIM3的更新事件触发中断周期2ms。TIM3的时钟源是APB1外设时钟72MHz预分频设为72-171那么计数频率变成1MHz自动重装载值设为2000-11999这样中断频率就是1MHz/2000500Hz即2ms一次。PWM输出用TIM1的通道1挂在PA8引脚上通过GPIO复用功能配置成推挽输出。PWM频率设20kHz那么自动重装载值就是72MHz/20000-13599。占空比通过CCR1寄存器控制范围0到3599对应0%到100%。编码器读取用TIM4的编码器接口模式TIM4的CH1和CH2分别接编码器的A相和B相输出。配置成编码器模式3双倍计数这样正反转都能正确计数。位移值用定时器的CNT寄存器直接读出来初始值在系统上电时通过一个“找零点”的校准动作来设定。中断里执行的内容尽量精简读编码器计数、读ADC角度、计算位置环和角度环PID、更新PWM占空比。整个过程在2ms内完成实测耗时大约0.3ms左右完全够用。调试信息的发送放在主循环里处理通过串口在需要的时候输出避免在中断里做串口传输阻塞控制周期。4. 实测调参过程与踩坑经验4.1 调参的优先级先站住再走稳调参的顺序非常关键。我第一次做的时候一上来就两环全挂上结果系统疯狂震荡摆杆根本立不起来。后来一步步拆开才找到规律。第一步只调角度环。把位置环的系数全部置零手动把小车固定在轨道中间我是用胶带临时绑住的只让角度环工作。这时候你会发现系统会以一种“抖”的方式让摆杆保持竖直——如果Kp太小摆杆会慢慢倒下去如果Kp太大摆杆会高频振荡。先把Kp调到“倒不了”的状态再慢慢加Kd抑制振荡。Kd的作用是阻尼它能让系统“冷静下来”。角度环稳定之后第二步松开小车让系统在轨道上自由运行。这时候你会发现小车会慢慢飘向一侧直到撞上轨道边缘。这是正常的因为没有位置环在“管着”它。此时把位置环的Kp加进去从一个很小的值开始比如0.1然后观察小车是否在向中间位置靠拢。位置环Kp过大会导致小车来回窜过小则回中速度太慢要找到一个“温和但持续”的拉力状态。最后一步微调参数和限制输出。实际运行中我用了一个“抗积分饱和”的处理PID输出限幅在±80%占空比同时积分项只在输出未饱和时累加这样避免了系统长时间饱和后积分项“爆掉”导致的超调和振荡。4.2 常见问题排查速查表我在调试过程中遇到的高频问题基本可以整理成下面这张表现象可能原因处理方法摆杆完全立不住一上电就倒角度环Kp过小逐步增大Kp直到有支撑感摆杆持续高频抖动角度环Kd不足或过大Kd从小到大试观察振动频率变化小车反复冲撞轨道两端位置环Kp过大降低位置环Kp或增加输出限幅摆杆能立住但小车缓慢偏移位置环Ki缺失加入位置环积分项但注意防饱和上电瞬间摆杆乱甩初始角度未校准写一个上电零点校准流程控制周期内执行超时中断里做了串口打印把调试输出移到主循环还有一个比较容易踩的坑编码器接线方向。如果电机正转时编码器读数反而减小需要检查编码器A、B相接反了还是TIM的编码器模式配置错了。最简单的方法是写一个测试函数手动转动电机看CNT寄存器的增减方向方向不对就交换A、B相输入。另外关于“上电零点校准”由于电位器是模拟传感器每次上电时摆杆的位置角度多少会有点偏差。我在程序中做了一个简单的校准逻辑——上电后读取当前ADC值作为“零点”然后让摆杆自由垂下记录此时角度与“零点”的差值作为零点偏移量。这样即使每次装夹的角度不同程序也能自动适配不至于一上电就因为角度偏差过大而失控。4.3 一些可能用得上的延伸玩法程序稳定之后我还做了几个小改动让这个项目更有意思。一个是“摆起控制”现在很多倒立摆项目只做“立起来”也就是手动把摆杆扶正之后系统保持平衡。如果想让摆杆从自然下垂状态自动立起来需要在程序里加一个“能量控制”模块——先让小车高频小幅往复运动给摆杆注入能量当摆杆快要接近竖直位置时再切换成PID控制模式整个切换过程要调好阈值。另一个是角度给定值的动态调节在直立状态下如果你给角度环一个缓慢变化的目标角度小车就会带着摆杆做前后移动。这其实就是倒立摆变成“自平衡移动平台”的基础后续如果加上无线遥控或者循迹传感器就能做出一辆“会走路的倒立摆”。最后再聊一句调试工具的使用。我用串口加上一个简单的上位机波形显示工具把角度、位置、PID输出这几个变量实时打出来对观察系统动态特别有帮助。参数调优的时候不要“盲调”看着波形曲线去调整PID参数效率和效果都比纯靠感觉好太多。串口波特率我用的115200输出频率设为50Hz也就是每20个控制周期输出一次数据不影响控制实时性又能看到清晰的动态趋势。本文还有配套的精品资源点击获取