1. 项目概览:为什么非要做自起摆
直线一级倒立摆算是控制领域最经典的入门级硬件了,大学实验室里几乎人手一套。可千万别小看它,这个看似简单的装置串联了建模、状态估计、非线性控制、实时系统一大堆知识点。我最早接触它是在做课程设计那会儿,当时的任务和大多数人一样——小车能稳定平衡就行。但真正上手之后才发现,最有挑战性的不是“稳住”,而是“怎么让它站起来”。
理论上说倒立摆的稳态控制已经非常成熟,线性二次型调节器(LQR)一上,调好权重,几秒钟就能让摆杆稳定在竖直位置。但问题是:摆杆在竖直向下的自然状态时,你没法直接让它倒立。电机功率有限,轨道长度有限,如何利用有限的行程把摆杆从下垂位置“甩”起来,在合适的时间和位置进入稳态控制范围,就是自起摆要解决的问题。
这篇文章我会从系统建模开始讲,重点拆解两段控制逻辑:能量注入式的自起摆设计,以及LQR稳态平衡的实现。中间会穿插我实际调试时遇到过的坑和总结出来的经验,包括参数整定、限幅处理、状态切换等细节。文中所用的参数基于我手上的直线导轨小车倒立摆平台,摆杆长度约30cm,小车质量约1kg,理解思路之后你完全可以迁移到自己的硬件上。
这套方案的价值在于:它不依赖高精度的模型参数,起摆阶段只要求“摆起来就行”,稳态阶段通过LQR保证鲁棒性。整体实现难度适中,适合有自动控制理论基础、想动手做完整闭环的读者参考。
2. 系统建模:把物理装置翻译成数学语言
2.1 拉格朗日方程建模过程
倒立摆的核心是一个经典的两体系统:小车在水平导轨上运动,摆杆通过转轴固定在小车上,可以在竖直平面内自由转动。先明确我用的坐标定义:x为小车水平位移,θ为摆杆与竖直向上方向的夹角。**θ=0表示摆杆竖直向上(目标平衡位置),θ=π表示摆杆自然下垂。**这个定义很多教材不统一,如果看别人代码时符号对不上,多半就是初始角度的定义问题。
建模用拉格朗日方程最清晰,不需要拆解复杂的牛顿力分析。系统的动能包括:
- 小车的平动动能:1/2·M·ẋ²
- 摆杆质心的平动动能:1/2·m·(vx² + vy²)
- 摆杆绕质心的转动动能:1/2·J·θ̇²
其中摆杆质心位置为(x + l·sinθ, l·cosθ),注意这里l是质心到转轴的距离,如果是均质摆杆则l = L/2。联立动能减去势能得到拉格朗日量,代入拉格朗日方程整理后,会得到两个耦合的非线性微分方程。完整推导过程教科书里都有,我直接给实际控制时用的关键结果。
小车运动方程: (M + m)·ẍ + m·l·θ̈·cosθ - m·l·θ̇²·sinθ = F
摆杆转动方程: m·l·ẍ·cosθ + (J + m·l²)·θ̈ - m·g·l·sinθ = 0
这里的F是电机施加在小车上的力。注意方程里有一项m·l·θ̇²·sinθ,这是摆杆旋转带来的离心力项。很多人建模完之后忽略这一项,在摆动幅度大或者摆速快的时候就会明显感觉到模型和实际行为对不上。
2.2 平衡点线性化与状态空间方程
非线性方程没法直接设计线性控制器,但好在我们的控制目标就是让摆杆稳定在θ=0附近的小邻域。在平衡点附近做小角度近似:sinθ≈θ,cosθ≈1,θ̇²项视为高阶小量可以舍弃。把这两个方程联立消元,整理成标准的状态空间形式。
取状态向量X = [x, ẋ, θ, θ̇]ᵀ,输入u = F,输出我取全部四个状态方便观测。线性化后的状态矩阵A和输入矩阵B如下(以我实际系统的参数带入):
A = [0, 1, 0, 0; 0, 0, -m·g/M, 0; 0, 0, 0, 1; 0, 0, (M+m)·g/(M·l), 0]
B = [0; 1/M; 0; -1/(M·l)]
如果摆杆是均质杆,转动惯量J = (1/3)·m·L²,质心到转轴距离l = L/2。代入这些之后A矩阵第四行第三列的值约等于(M+m)·g/(M·l),这个值是系统的关键特征参数,直接决定了系统的自然频率和所需的控制增益量级。
**一个非常重要的检查点:**A矩阵特征值里必然有一个正实部特征值——这是倒立摆的“内在不稳定性”来源,表明系统就是开环不稳定的。如果在仿真里发现特征值全部在左半平面,那一定是你符号定义或者参数代入出错了。
2.3 模型参数获取与实测校准
建模不是写几个公式就完了,参数不准再好的控制器也白搭。我的做法分成三步:
第一,直接测量法。小车质量M用电子秤称,摆杆质量m同样称重。摆杆长度L用游标卡尺量,质心位置l对均质杆就是L/2。但实际买来的摆杆可能一端有配重块或者传感器,质心位置要重新估算,简单的方法是把摆杆水平放置、用棱柱支撑找平衡点,那个点就是质心。
第二,摩擦力辨识。导轨和转轴的摩擦力模型其实相当重要,尤其是低速段。我实测发现静摩擦和动摩擦差别很大,简单线性摩擦模型不够用。更准确的方法是:给小车一个恒定力输入,测稳态速度,改变输入力大小记录多组数据,拟合出摩擦系数。实际操作中如果不做摩擦补偿,会出现稳态误差——摆杆看似平衡了,但小车会缓慢漂移,一直撞击限位开关。
第三,在仿真里验证模型行为。把实际参数代入非线性模型,对摆杆做个自由摆锤仿真,对比实测摆动周期的衰减曲线。如果衰减速率和频率都对得上,说明模型基本可用。这一步别省,后面用能量法设计起摆时,模型的准确性直接影响起摆成功率。
3. 稳态控制与自起摆的完整方案设计
3.1 控制策略选型:为什么是LQR加能量法
倒立摆稳态控制可以从多种方法中选方案:经典PID、极点配置、LQR、滑模控制、自抗扰控制等。我最终选择LQR加能量注入式的起摆策略,核心原因有三:
第一,LQR在设计流程上非常清晰,物理意义明确。四个状态权重矩阵Q的取值直接对应“我多在乎某个状态的偏差”,不需要像PID那样三个参数对着响应曲线反复试探。尤其对于多输入多输出系统,LQR能天然处理状态间的耦合关系。
第二,从起摆到稳态的切换非常自然。起摆阶段我关注的是“总能量”,稳态阶段关注的是“状态偏差”,两者可以通过一个统一的能量/角度切换条件衔接,逻辑清晰。
第三,LQR的鲁棒性在工程上足够用。尽管我们用的是线性化模型,但LQR本身具有一定幅值和相位裕度,对模型参数误差、摩擦力等未建模动态有一定容忍度。实测中我用名义参数设计的增益,换到不同摆杆上依然能稳定,只是起摆和平衡的响应速度略有差异。
3.2 自起摆原理:能量从一个势能谷爬向势能峰
理解自起摆之前,先想明白一个物理事实:摆杆在竖直下垂位置时,系统处于势能最低点。要让摆杆到达竖直向上的倒立位置,需要注入足够的能量让摆杆能翻越水平位置的“势能山坡”。
起摆过程本质上是一个能量控制问题。理想目标不是精确控制某个角度轨迹,而是单调增加摆杆的机械能,让摆杆摆幅逐步增大。摆杆能量表达式为:
E = 1/2·(J + m·l²)·θ̇² + m·g·l·(cosθ - 1)
注意这里我把势能零点定义在竖直向上位置(θ=0),所以目标平衡状态对应的能量是E = 0,而自然下垂状态(θ=π)的能量是E = -2·m·g·l。起摆的全部意义就是让总能量从负值逐步逼近零。
那么小车运动如何影响摆杆能量?对摆杆方程两端乘以θ̇并积分,可以得到能量变化率:
dE/dt = -m·l·ẍ·θ̇·cosθ
这个式子非常关键。它告诉我们,**小车加速度带来的惯性力通过摆杆等效长度做功,从而注入能量。**控制策略非常简单粗暴:当摆杆向下摆动时(θ̇·cosθ的符号为某一方向),让小车产生恰当的加速度,给摆杆“推一把”;当摆杆向上摆动时,不要再注入能量,甚至可以制动一下防止能量过冲。这样每次摆动都叠加一点能量,摆幅不断变大。
3.3 起摆控制律设计与限幅策略
实际使用的起摆控制律我采用了一个简化的能量反馈加摆动同步项:
u_swing = k_E·(E0 - E)·sign(θ̇·cosθ) + k_d·ẋ
这里E0是目标能量(接近0但略小于0,比如-0.05J),sign函数的作用是让力的方向始终和摆杆运动的“可注入能量方向”一致。第二项k_d·ẋ是速度阻尼项,防止小车在有限导轨上越冲越远。
第一版实现我踩过一个大坑:如果不加速度阻尼,小车会为了给摆杆注入能量而越来越快地满导轨乱跑,经常撞到限位。后来我把小车速度反馈的权重调大,起摆过程才可控。经验值:k_E取0.5~1.5之间,k_d取2~5,具体数值和摆杆质量相关,需要实测调整。
此外还有两个防呆限幅:
- 控制量u限制在±15N以内(对应电机PWM限幅约±70%)
- 小车位置x限制在±0.38m(导轨有效行程的一半再加一点安全余量)
- 如果小车距离限位小于0.05m,强制切换为“先回中”的控制模式
起摆结束条件我用的是能量阈值加角度阈值双重判断:当估计能量E > -0.05J且摆杆角度连续50ms落在±20°范围内,立即切换为LQR稳态控制。注意切换瞬间有控制量的阶跃跳变,建议做一阶低通滤波过渡,避免电机电流冲击。
3.4 LQR稳态控制器的权重设计与效果预期
稳态控制的核心是设计状态反馈控制器u = -K·X,通过Riccati方程求解最优增益矩阵K。维度上我的Q矩阵是4×4对角阵:
Q = diag(q_x, q_v, q_theta, q_omega)
实际调参过程中我发现对控制效果影响最大的比例关系是q_theta和q_x的相对大小。如果q_theta远大于q_x,控制器会优先保证摆杆垂直,但小车可能缓慢漂移;反过来则小车稳如磐石,但摆杆抗扰能力变差。我最终用的权重组合:
Q = diag(500, 10, 200, 5),R = 1
对应的LQR增益大约是:K = [-22.36, -31.62, 38.73, 5.19],具体数值和系统参数强相关,不建议直接照抄,但可以作为调参的初始参考。
有人可能会问,为什么Q里x的权重比θ大那么多却还是优先稳摆杆?因为状态量的物理单位不同:x以米为单位本身数值就小,θ以弧度为单位摆个5°就是0.087rad,从对u的贡献来看,增益矩阵会把单位差异自动平衡回来。LQR的美妙之处就在这里:它根据你给的相对权重,自动找到在物理尺度差异下最优的增益分配。
4. 实操:从仿真到实物平台的关键环节
4.1 仿真平台搭建与验证
动手调实物之前,先用MATLAB/Simulink或者Python搭建仿真永远是省时间的第一步。我用的是Python环境,配合scipy的solve_continuous_are函数求解Riccati方程,整个系统不超过200行代码。
仿真的价值主要在三个方面:
第一,验证模型的正确性。把参数代入非线性模型,跑开环自由摆动仿真,看角度变化曲线和真实摆杆摆动周期是否一致。精确匹配不太可能,但周期误差小于10%基本可以接受。
第二,验证起摆控制律的收敛性。仿真的时间尺度可以随意加速,一分钟内能跑几十次起摆流程,快速摸索出合理的k_E和k_d范围。然后再上实物细调,至少节约两三个小时的现场调试时间。
第三,验证切换逻辑的稳定性。仿真里故意加入摆杆初始角度扰动,检查在极限情况下起摆切换到稳态的流程会不会卡死或者振荡。
**有一个特别容易被忽视的坑:仿真里的微分环节对采样时间的敏感性。**实物控制器的采样周期一般是1ms~5ms,仿真如果你用连续求解器,算出来的控制器表现会比实物好很多;建议仿真里务必按实物的采样周期做离散化,这样才能暴露离散化带来的相位延迟问题。
4.2 硬件配置与传感器数据处理
我用的平台构成非常简单:直流有刷电机带编码器驱动小车,摆杆转轴处有另一个编码器测角度,DC-DC降压模块给控制板供电,主控是STM32F407。硬件上值得注意的细节主要是编码器接口电路和电源滤波。
角度和速度的采集处理是整个控制闭环的命门。编码器直接读到的原始计数需要做几件事:
第一,角度归一化。因为摆杆可以360°任意旋转,编码器计数会在绕一圈后发生跳变。处理方式:把原始角度映射到[-π, π]区间,同时维护一个累计转角变量用于起摆阶段的摆幅判断。我用一个小技巧——在中断里做增量换算,每次取当前读数与上次读数之差,如果差值的绝对值大于半个周期就认为是越界,自动调整累计值。
第二,速度估计。直接用位置差分算速度会引入大量噪声,尤其在编码器分辨率不高的时候,差分出来的速度信号几乎是毛刺。实测下来效果最好的是中心差分加滑动平均滤波,窗口取5~8个采样点。代价是引入了约两个采样周期的延迟,但换来的是稳定可靠的速度反馈信号,对平衡控制来说很值。
第三,零位标定。每次上电时不知道摆杆的绝对角度,让摆杆自然下垂静止,读取当前编码器计数,把该位置标定为θ=π。这个操作看起来简单,但很多人忘了做,直接用默认零位会导致起摆阶段能量计算错误。
4.3 控制周期选择与执行代码结构
我的控制主循环跑在定时器中断里,周期设为2ms(500Hz)。选择这个值的原因:系统开环不稳定极点对应的模态频率通常在1~3Hz左右,控制频率至少是系统带宽的20倍以上才能保证较好的抑制效果。2ms的周期对STM32来说绰绰有余,还能留出量做通信和显示。
控制代码的主结构我会拆成几个阶段,所有逻辑放在一个有限状态机里:
- 状态IDLE:系统启动等待,摆杆可自由下垂
- 状态SWING_UP:执行能量注入起摆
- 状态BALANCE:执行LQR稳态平衡
- 状态FAIL:检测到超限或异常,停止电机并报警
每个状态的切换条件集中在同一个函数里,方便维护和调试。我最开始把切换逻辑散写在各个控制函数内部,后来发现排查问题的时候要把整个代码看一遍才能定位,非常痛苦。集中管理之后,每次调试只需打印当前状态编号和切换变量就能快速判断问题所在。
4.4 起摆到稳态的软过渡处理
起摆阶段最后,摆杆的角速度通常还比较大,如果直接切换到LQR控制,控制器会瞬间输出一个很大的反向力矩,轻则引起小车突兀一顿,重则让摆杆再次倒下。解决办法是在切换时加一个过渡增益曲线。
我的实现方式:
#define SWITCH_BLEND_TIME 0.5f // 过渡时间0.5秒 float blend_ratio = (float)((current_tick - switch_start_tick)) / (SWITCH_BLEND_TIME * CONTROL_FREQ); if (blend_ratio > 1.0f) blend_ratio = 1.0f; float control_out = blend_ratio * u_balance + (1.0f - blend_ratio) * u_swing_last;用一个线性插值把起摆控制量平缓过渡到稳态控制量。实测这样处理后切换瞬间的冲击电流减少了80%以上。还有一种做法是在过渡期间把LQR增益整体乘以blend_ratio,效果类似,但线上性插值控制量更直观。
5. 调试实录:常见问题与排查心得
5.1 起摆不起来或越摆越弱是怎么回事
这是最让人抓狂的问题。摆杆在小车跑动下轻微晃动但摆幅不增加,或者越摆越小,通常不是控制律问题,而是能量注入相位错了。
一个排查技巧:把估计的摆杆能量E和起摆控制量u_swing同时录下来,看u_swing变化和θ̇符号的关系。正确的行为应该是每当θ̇的符号翻转后,u_swing也同步改变方向;如果两者出现滞后或者反向,就说明反馈信号有问题,最常见的原因是编码器A、B相接反导致θ̇符号反了。
另一个常见原因:小车导轨摩擦太大,起摆时小车本身移动距离不足,能量注入效率低。判断方法是看起摆过程中小车振幅是否够大——如果摆杆摆幅已经接近45°了但小车位移不到10cm,说明k_E太小或者速度阻尼k_d太大,调整比例即可。
5.2 稳态时小车漂移不停怎么办
这个问题的根源九成是摩擦模型不准。LQR设计中假设系统是理想的无摩擦模型,但实际导轨的静摩擦会让小车的微小位置误差无法被修正,表现为缓慢的单向漂移,直到撞到限位开关。
我尝试过三种方案,最后结合使用效果最好:
- 在控制量中叠加一个低通滤波后的速度补偿项
- 在位置上添加一个死区逻辑:当位置偏差小于1cm且速度趋近于零时,停止修正但不切断LQR输出
- 更彻底的做法是在仿真中把Stribeck摩擦模型加入被控对象,重新优化Q权重
关于死区逻辑,有一个要注意的点:死区过大容易引起极限环振荡,死区过小又起不到作用。我用1mm的死区区段加3mm的迟滞范围,实测稳定性和抑制漂移都满意。
5.3 切换瞬间摆杆掉下来
这个问题主要出现在起摆能量刚好卡在阈值附近的时候。能量阈值设得太高,切换时摆杆还没真正进入线性化区间,LQR输出不够撑住摆杆;阈值设得太低,则摆杆仍在大力甩动,切换瞬间冲击过大。
我的解法是双条件判定:角度偏差小于25°且角速度小于80°/s,两个条件同时满足才切换。同时把目标能量E0从0改为-0.03J,让切换发生在摆杆过冲回落的过程中,此时角速度天然比较小。
经验总结一句话:起摆结束的理想位置是在摆杆接近竖直且速度接近零的时刻,而不是能量刚好到零的时刻。
5.4 高频抖动与电机发热问题
如果LQR增益过高或采样噪声过大,控制量会出现高频振荡,表现为小车高频抖动,电机发热严重。这个问题的根源通常是速度反馈噪声被增益放大。
解决方法优先级从低到高:
- 增加速度滤波窗口长度
- 降低LQR中速度项权重q_v
- 在控制量输出前加一阶低通滤波,截止频率20~50Hz
- 减小编码器倍频,避免高频噪声混入
注意第4条踩过坑:我以为编码器4倍频分辨率越高越好,结果4倍频后的低频噪声反而更明显。后来折中成2倍频,配合滑动平均滤波,效果最好。
5.5 问题排查速查表
为了方便参考,我把调试过程中最常见的问题和对应排查方向整理成一个表格:
| 现象 | 可能原因 | 优先排查项 |
|---|---|---|
| 起摆无效果 | 编码器方向反、反馈相位错误 | 检查θ̇符号与控制量方向是否匹配 |
| 起摆周期长 | k_E过小或k_d过大 | 增大k_E 30%,观察摆幅增长速度 |
| 起摆小车撞限位 | k_d不足、导轨摩擦小 | 加大速度阻尼,增加位置限幅 |
| 平衡稳定但缓慢漂移 | 未建模摩擦影响 | 增加死区或摩擦补偿项 |
| 切换时掉摆 | 切换条件不匹配 | 检查角度、角速度双重阈值 |
| 高频抖动 | 速度噪声或增益过大 | 滤波、降q_v、输出低通滤波 |
| 电机发热严重 | PWM频率过高或控制量振荡 | 检查PWM频率设置和分析控制量波形 |
6. 经验总结和进阶方向
整套系统从建模到跑通,我陆陆续续花了大概两个星期。回头看最值得分享的体会是:倒立摆的控制难点从来不在控制器本身,而在边界条件——起摆的能量管理、切换的平滑处理、实体硬件带来的噪声和摩擦。这些在教科书上不会写,只有亲手调过才知道。
有一点我想特别强调:仿真和实物的差距是巨大的,但仿真依然是调试过程中最值得投入时间的地方。我们在仿真里暴露的问题越多,上实物之后翻车的概率就越低。每次调整算法之后,先在仿真里跑一百次随机初始条件的测试,再上实物验证,这个习惯帮我避开了无数低级错误。
如果看完这篇你还是觉得不过瘾,可以尝试这几个方向:
第一,把稳态控制从LQR换成模型预测控制(MPC)。MPC的优点是可以显式处理约束条件(小车位置限位、电机力矩限幅),在同等稳定裕度下可以把起摆和平衡统一到一个控制框架里,省去切换逻辑。
第二,加入状态观测器。我们现在假设四个状态都可直接测量,但实际工程中角度可以测,小车位置也可以测,角速度的位置差分噪声较大。设计一个降维观测器或者卡尔曼滤波器,把速度和角速度的估计做得更干净,控制品质还能再上一个台阶。
第三,尝试模糊自适应整定。把摆杆长度视为可变参数,在线估计等效摆长,再用增益调度法实时更新LQR增益,可以让同一套系统适应不同的摆杆配置。
直线倒立摆实验的价值在于它涵盖了从建模到工程实现的全链路,做完这个项目你对现代控制理论的理解会有一个质的飞跃。希望这篇文章能帮你顺着坑少走一点弯路,也欢迎在评论区交流各自的调试心得。