第三节:经典PID力矩控制

各位同学,今天我们来聊聊力矩控制里最经典、也最实用的方法——PID控制。说实话,我在这个行业摸爬滚打十几年,PID控制几乎无处不在。你想想看,从工业机器人到无人机,从伺服电机到手术机器人,PID都是那个最靠谱的“老黄牛”。

3.1 PID控制原理

PID控制,说白了就是三个字:比例、积分、微分。它的核心思想很简单——根据当前误差、过去误差的累积、以及误差的变化趋势,来调整输出。

公式长这样:

u(t) = Kp * e(t) + Ki * ∫e(τ)dτ + Kd * de(t)/dt

其中:

  • Kp(比例项):直接响应当前误差。误差大,输出就大。我习惯先调Kp,让它能快速响应。
  • Ki(积分项):消除稳态误差。说白了就是“算旧账”,把过去累积的误差补回来。
  • Kd(微分项):预测未来趋势。误差变化快了,它就提前刹车,防止超调。

我在项目中遇到过一件事:有个六轴机器人,末端抖动得厉害。我一开始以为是机械间隙,后来发现是Kd设得太小,微分项没起作用。调大Kd后,抖动立刻消失了。嗯,这就是微分项的妙用。

核心要点:PID三个参数各有分工。Kp决定响应速度,Ki消除静差,Kd抑制振荡。调参顺序我建议:先P,再I,最后D。

3.2 力矩环PID设计

力矩环PID,和位置环、速度环不太一样。它的控制对象是电机输出的力矩(或电流),响应速度要求极高。一般力矩环的采样频率在1kHz到10kHz之间,比位置环快得多。

设计力矩环PID时,我通常会考虑以下几点:

  1. 带宽匹配:力矩环的带宽要远高于速度环和位置环。一般力矩环带宽是速度环的5-10倍。
  2. 抗噪声:力矩信号(电流信号)噪声大,微分项容易放大噪声。我建议加一个低通滤波器。
  3. 饱和处理:电机输出力矩有限,积分项容易饱和。这个我们后面细说。

一个典型的力矩环PID结构是这样的:

// 力矩环PID伪代码
float torque_pid_control(float target_torque, float actual_torque) {
    float error = target_torque - actual_torque;
    
    // 比例项
    float p_out = Kp * error;
    
    // 积分项(带抗积分饱和)
    integral += Ki * error * dt;
    integral = clamp(integral, -integral_limit, integral_limit);
    
    // 微分项(带滤波)
    derivative = (error - last_error) / dt;
    derivative = lowpass_filter(derivative, cutoff_freq);
    float d_out = Kd * derivative;
    
    last_error = error;
    
    return p_out + integral + d_out;
}

个人经验:力矩环的Ki不要设太大。我见过很多新手把Ki调得过高,结果系统低频振荡,嗡嗡响。Ki的作用是消除静差,不是用来提高响应速度的。

3.3 抗积分饱和

积分饱和,是PID控制里最坑的问题之一。为什么会这样?

你想想看,当电机输出已经达到最大力矩(比如10Nm),但误差还在,积分项还在不断累积。等误差反向时,积分项里已经存了一大笔“旧账”,需要很长时间才能消化掉。这段时间里,系统响应会严重滞后,甚至振荡。

我曾经在一个焊接机器人项目上吃过这个亏。机器人启动时,积分项疯狂累积,导致启动瞬间力矩过冲,直接把焊枪撞歪了。从那以后,我再也不敢忽视抗积分饱和了。

常用的抗积分饱和方法有三种:

方法 原理 优缺点
限幅法 积分项输出超过阈值时截断 简单,但可能引起积分项突变
积分回退法 输出饱和时,积分项回退到饱和值对应的积分量 效果好,但计算稍复杂
条件积分法 只在特定条件下才积分(如误差较小或未饱和时) 灵活,但需要调条件阈值

我个人最常用的是限幅法,简单可靠。代码实现如下:

// 抗积分饱和实现
float integral = 0;
float integral_limit = 5.0;  // 积分限幅值

void update_integral(float error, float dt) {
    integral += Ki * error * dt;
    
    // 限幅
    if (integral > integral_limit) integral = integral_limit;
    if (integral < -integral_limit) integral = -integral_limit;
}

注意:积分限幅值不是随便设的。我建议根据电机最大输出力矩的10%-20%来设定。设得太小,积分项没作用;设得太大,抗饱和效果差。

3.4 前馈补偿

前馈补偿,说白了就是“提前给力”。PID是事后纠偏,前馈是事前预防。两者结合,效果翻倍。

在力矩控制中,前馈补偿主要用来抵消已知的干扰,比如:

  • 重力补偿:机器人关节在重力作用下需要额外的力矩保持位置
  • 摩擦力补偿:电机和减速器的摩擦力,尤其在低速时明显
  • 惯性力补偿:加速过程中需要的额外力矩

前馈补偿的公式很简单:

u_total = u_pid + u_feedforward

其中u_feedforward是根据模型计算出来的。比如重力补偿:

// 重力前馈补偿
float gravity_feedforward(float joint_angle) {
    // 根据关节角度计算重力矩
    float torque = m * g * L * sin(joint_angle);
    return torque;
}

我在做协作机器人时,重力补偿是必须的。没有重力补偿,机器人一断电就往下掉,夹到人手可不是闹着玩的。加了重力补偿后,机器人可以悬停在任意位置,推都推不动——嗯,这就是前馈的魅力。

关键点:前馈补偿不改变系统稳定性,只提高响应速度和精度。PID负责处理未知扰动,前馈负责处理已知扰动。两者是互补关系,不是替代关系。

知识体系总览

下面这张图,是我自己画的PID力矩控制知识体系。你可以把它当作学习地图:

PID力矩控制知识体系 PID力矩控制 PID控制原理 比例项 Kp 积分项 Ki 微分项 Kd 力矩环PID设计 带宽匹配 抗噪声滤波 抗积分饱和 限幅法 积分回退法 条件积分法 前馈补偿 重力补偿 摩擦力补偿 惯性力补偿

这张图把今天讲的内容串起来了。从PID原理出发,到力矩环设计,再到抗积分饱和和前馈补偿。每个模块之间都有联系,不是孤立的。

好了,这一节的内容就到这里。PID力矩控制看起来简单,但真正用好它,需要大量的实践和调试。我建议你回去后,找个电机试试手,调一调Kp、Ki、Kd,感受一下每个参数的作用。纸上得来终觉浅,绝知此事要躬行。

最后一个小建议:调试PID时,先把积分项关掉(Ki=0),只调P和D。等系统稳定了,再慢慢加积分。这样不容易翻车。

可可精品资料库