4. 位置环控制策略:P/PI控制、前馈控制、轨迹规划与插补

位置环,说白了就是让电机精准地停在你想让它去的地方。很多刚入行的工程师觉得这很简单——给个位置指令,电机跑过去不就完了?但实际项目里,你会发现事情远没那么简单。过冲、震荡、跟随误差大,这些问题我几乎在每个项目里都遇到过。

今天我们就来拆解位置环的核心策略。我个人习惯把位置环分成三个层次:基础调节器、前馈补偿、轨迹规划。这三层一层比一层精细,也一层比一层吃功夫。

核心观点:位置环的性能天花板,往往不在调节器本身,而在于你给调节器喂了什么样的指令。

4.1 P控制与PI控制:基础但够用

位置环最常用的就是P控制。比例增益Kp直接把位置误差映射成速度指令。简单、直观、好调。

// 位置环P控制
float pos_err = target_pos - current_pos;
float speed_cmd = Kp * pos_err;

但P控制有个硬伤——稳态误差。比如你让电机停在1000个脉冲的位置,如果负载有摩擦力,它可能停在995就动不了了。为什么?因为误差小了,速度指令也小了,小到不足以克服静摩擦力。

这时候就需要引入积分项。PI控制能消除稳态误差,但代价是可能引入震荡。我在一个贴片机项目里就吃过这个亏——加了积分后,位置环在目标点附近来回晃了3个来回才稳定下来,直接影响了贴片节拍。

特性 P控制 PI控制
稳态误差 有(受摩擦力影响) 无(积分消除)
响应速度 快 略慢(积分滞后)
抗扰能力 弱 强(积分持续补偿)
调试难度 低(一个参数) 中(Kp+Ki配合)
适用场景 低摩擦、高刚性系统 有持续负载、需要精确定位

我的调试习惯:先调P到系统刚好不震荡,再加I。I的积分限幅一定要做,否则积分饱和会让你吃大亏。我曾经在卷绕机上没做限幅,结果积分项攒了半天的误差,一释放直接把膜拉断了。

4.2 前馈控制:让系统跑得更快更准

纯反馈控制有个本质问题——它总是等误差出现了才去纠正。你想想看,这就像开车时你总是等车偏了才打方向盘,永远在追误差。

前馈控制的思路完全不同:它提前计算出系统需要多少力,直接给出去。反馈只负责修正模型误差和扰动。

// 速度前馈 + 位置环PI
float pos_err = target_pos - current_pos;
float speed_feedforward = target_vel * Kff;  // 前馈项
float speed_feedback = Kp * pos_err + Ki * integral;  // 反馈项
float speed_cmd = speed_feedforward + speed_feedback;

前馈系数Kff的理想值是1.0——意味着前馈完全承担了速度指令,反馈只负责修正。但实际项目中,我一般从0.8开始试。为什么?因为模型不准,Kff=1.0反而可能让系统震荡。

前馈的类型不止一种。我个人常用的是:

  • 速度前馈:最基础,补偿匀速段
  • 加速度前馈:补偿加减速段的惯性力
  • 摩擦力前馈:补偿静摩擦和库仑摩擦

注意:前馈不是万能的。如果系统模型偏差太大,前馈反而会帮倒忙。我曾经在一条老旧的传送带上试加速度前馈,结果因为机械间隙太大,前馈给的力全变成了冲击,位置精度反而下降了30%。

4.3 轨迹规划:给电机喂"好"的指令

前面说的都是怎么控制电机去追指令。但你有没有想过——指令本身是不是合理的?

直接给一个阶跃位置指令,相当于让电机瞬间从0速跳到目标速度。物理上不可能,实际表现就是过冲和震荡。所以我们需要轨迹规划,把粗暴的阶跃指令变成平滑的S曲线。

最常用的就是S形速度曲线。它把运动分成7段:加加速、匀加速、减加速、匀速、加减速、匀减速、减减速。

// S形曲线位置插补(简化版)
float t = current_time - start_time;
float T = total_time;  // 总运动时间

if (t < T/4) {
    // 加加速段:位置与t³成正比
    pos = 0.5 * accel_max * t * t * (2 * t / T);
} else if (t < 3*T/4) {
    // 匀速段
    pos = ...;
} else {
    // 减减速段
    pos = ...;
}

实际项目中,我很少用完整的7段S曲线。为什么?计算量大,而且很多场景用不上。对于大多数伺服应用,梯形速度曲线加一个简单的低通滤波就够用了。

我的经验:轨迹规划的平滑度要和机械系统的带宽匹配。你规划得再平滑,如果机械共振频率在100Hz,而你的轨迹激励了120Hz的分量,照样震荡。我一般会在轨迹规划后加一个陷波滤波器,专门干掉机械共振频率。

4.4 插补算法:让运动连续起来

轨迹规划算出了整条路径,但控制器在每个控制周期(比如1ms)都需要一个位置指令。这就需要插补——在规划好的轨迹点上,实时计算出当前时刻的位置。

插补算法主要有两种:

  • 时间基插补:以时间为自变量,查表或计算位置。简单,但要求控制周期严格固定。
  • 距离基插补:以走过的距离为自变量,适合多轴联动。复杂,但更精确。

我做过一个焊接机器人项目,要求6轴同步运动。时间基插补在单轴上没问题,但6轴一联动,每个轴的控制周期抖动导致轨迹跑偏。后来换成距离基插补,问题才解决。

// 时间基线性插补
float t_ratio = (current_time - segment_start_time) / segment_duration;
float pos = start_pos + (end_pos - start_pos) * t_ratio;

插补的精度直接影响最终定位精度。一般来说,插补周期越短越好,但受限于CPU算力。我建议:

  • 伺服系统:插补周期 ≤ 1ms
  • 步进系统:插补周期 ≤ 5ms
  • 多轴联动:插补周期 ≤ 500μs

4.5 整体策略:怎么搭才合理?

说了这么多,我们来画一张整体架构图。这是我做项目时常用的位置环分层结构:

位置环控制策略整体架构 轨迹规划层 S形曲线 / 梯形曲线 / 多项式 插补层 时间基 / 距离基 / 线性插补 前馈补偿层 速度前馈 / 加速度前馈 / 摩擦力前馈 反馈调节层 P控制 / PI控制 / 抗积分饱和 指令从顶层向下流动,每层都在减少误差和冲击,最终输出平滑、精准的位置控制

这个架构的核心思想是分层解耦。轨迹规划只管"怎么走",插补只管"当前在哪",前馈只管"提前给力",反馈只管"修偏差"。每一层各司其职,互不干扰。

实际项目中,我建议从下往上调。先把反馈层调稳,再加前馈提响应,最后用轨迹规划保证平滑。反过来调,出了问题你都不知道是哪一层的问题。

避坑指南:我曾经在一个项目中,把轨迹规划做得特别平滑,但反馈层参数没调好,结果电机在匀速段一直有微小震荡。查了两天才发现是反馈的Ki太大,积分项在匀速段持续累积误差。所以记住——上层再漂亮,下层不稳也是白搭。

好了,位置环的策略就聊到这里。这些方法我在十几个项目里反复验证过,从几块钱的步进电机到几万块的伺服驱动器,核心逻辑都一样。你只要把这几层搭好,位置精度做到0.01度或者0.1mm,基本不是问题。