4. 低速下的摩擦力补偿:Stribeck模型、库仑摩擦与粘滞摩擦的辨识与补偿

各位做运动控制的同行,低速爬行这个问题,我估计十个人里有九个都头疼过。明明给定速度很稳,电机却在那一顿一顿的,像卡了痰一样。说白了,罪魁祸首就是摩擦力。

摩擦力这东西,在高速时还好,它就是个线性阻尼。但一到低速,它就露出真面目了——非线性、时变、还带记忆效应。我当年调试一个精密转台,0.1 r/min 以下怎么都稳不住,折腾了两周,最后发现是 Stribeck 效应在作怪。今天我们就把它彻底扒开。

4.1 摩擦力的三个“分身”

要补偿摩擦力,先得认识它。在低速域,摩擦力主要由三部分组成:

摩擦分量 物理本质 与速度的关系 典型特征
库仑摩擦 接触面微观凸起的机械互锁 与速度方向相反,大小恒定 速度过零时跳变
粘滞摩擦 润滑剂的剪切阻力 与速度成正比(线性) 高速时占主导
Stribeck 摩擦 边界润滑向流体润滑过渡 速度增加时摩擦力先降后升 负阻尼特性,引起爬行

你想想看,为什么低速会爬行?就是因为 Stribeck 效应在速度极低时,摩擦力随速度增加反而减小,形成了负阻尼。系统在这个区间是不稳定的,就像你踩刹车时刹车片在半结合状态那种抖动。

4.2 Stribeck 模型——把摩擦力“公式化”

工程上最常用的摩擦力模型,就是 Stribeck 模型。它的数学形式是这样的:

F_f(v) = [F_c + (F_s - F_c) * exp(-|v/v_s|^δ)] * sign(v) + B * v

其中:

  • F_c:库仑摩擦力(常数)
  • F_s:静摩擦力(启动瞬间的最大值)
  • v_s:Stribeck 速度(转折点)
  • δ:形状系数(通常取 0.5~2)
  • B:粘滞摩擦系数

这个模型的核心思想是:摩擦力不是简单的“静摩擦+动摩擦”,而是有一个从静摩擦下降到库仑摩擦,再随速度上升的“U型”曲线。

关键认知: Stribeck 曲线的“谷底”位置,就是系统最容易发生爬行的速度区间。找到这个点,补偿就成功了一半。

4.3 摩擦参数辨识——三步走

模型有了,参数怎么来?我个人的习惯是分三步走,不需要昂贵的测力计,用伺服自带的编码器和电流检测就能搞定。

第一步:测库仑摩擦 F_c 和粘滞系数 B

让电机在几个不同的恒定速度下匀速运行(比如 10、50、100、200 r/min),记录每个速度下的稳态电流(或力矩)。然后做线性拟合:

# 伪代码示例
速度序列 = [10, 50, 100, 200]  # r/min
电流序列 = [0.12, 0.15, 0.20, 0.30]  # A

# 线性拟合:电流 = B * 速度 + F_c
# 结果:B ≈ 0.001 A/(r/min), F_c ≈ 0.11 A

注意,这里测的是匀速段,加速度为零,所以电流就是摩擦力矩。我在项目中遇到过有人用加速段数据去拟合,结果粘滞系数偏大一倍——因为加速度本身也需要力矩。

第二步:测静摩擦力 F_s

给电机一个缓慢增加的力矩斜坡,记录电机刚刚开始转动的瞬间力矩值。多测几次取平均。

小技巧: 用位置环锁定,然后缓慢增加力矩指令,同时监视位置误差。当位置误差突然开始持续增大时,就是静摩擦力被克服的时刻。我一般重复测 10 次,去掉最大最小值再平均。

第三步:辨识 Stribeck 参数 v_s 和 δ

这是最麻烦的一步。在极低速区间(比如 0.1~5 r/min),以 0.1 r/min 为步进,测量每个速度点的稳态摩擦力。然后对 Stribeck 公式做非线性最小二乘拟合。

# 使用 scipy.optimize.curve_fit 示例
from scipy.optimize import curve_fit
import numpy as np

def stribeck_model(v, F_c, F_s, v_s, delta, B):
    return (F_c + (F_s - F_c) * np.exp(-(np.abs(v)/v_s)**delta)) * np.sign(v) + B * v

# 实测数据
v_data = np.array([0.1, 0.2, 0.5, 1.0, 2.0, 5.0])
F_data = np.array([0.25, 0.22, 0.18, 0.16, 0.17, 0.20])

# 初始猜测(用前两步的结果)
p0 = [0.11, 0.35, 0.5, 1.0, 0.001]
popt, _ = curve_fit(stribeck_model, v_data, F_data, p0=p0)

# popt = [F_c, F_s, v_s, delta, B]

避坑指南: 我曾经在拟合时遇到过 v_s 收敛到负值的情况。原因是低速数据点太少,或者测量噪声太大。建议 v_s 的初值设为 0.5~1 r/min,并且加上边界约束(v_s > 0)。另外,δ 值一般不会超过 2,如果拟合结果 δ > 3,说明你的数据可能有问题。

4.4 补偿策略——前馈为主,反馈为辅

参数辨识出来了,怎么用?我的做法是:前馈补偿 + 反馈微调。

前馈部分,根据当前速度指令,用 Stribeck 模型计算出期望的摩擦力矩,直接加到电流环的给定上。这样摩擦力在系统响应之前就被“抵消”了。

// 摩擦力前馈计算(C语言伪代码)
float friction_ff(float speed_cmd)
{
    float sign = (speed_cmd > 0) ? 1.0f : -1.0f;
    float abs_v = fabs(speed_cmd);
    float stribeck_term = F_c + (F_s - F_c) * exp(-pow(abs_v / v_s, delta));
    float viscous_term = B * abs_v;
    return (stribeck_term + viscous_term) * sign;
}

// 在电流环中叠加
current_ref = speed_pi_output + friction_ff(speed_cmd);

但前馈不可能完美——温度变化、磨损都会让参数漂移。所以我会保留一个低增益的积分项来吃掉残余误差。积分增益设到正常 PI 的 1/5 就行,太高反而会引起振荡。

4.5 知识体系总览

下面这张图,是我自己总结的摩擦力补偿完整流程,从模型到辨识再到补偿,一步到位:

摩擦力补偿知识体系 摩擦力补偿知识体系 库仑摩擦 F_c Stribeck 摩擦 粘滞摩擦 B·v Stribeck 模型 F_f(v) = [F_c + (F_s-F_c)·exp(-|v/v_s|^δ)]·sign(v) + B·v 参数辨识:三步走 ① 恒速测 F_c & B → ② 力矩斜坡测 F_s → ③ 低速扫频拟合 v_s & δ 补偿策略:前馈 + 反馈 前馈:Stribeck 模型计算 → 叠加到电流环 消除爬行 提高定位精度 低速控制精度提升

4.6 实战中的几个坑

最后,分享几个我踩过的坑,希望能帮你省点时间:

  • 温度漂移: 摩擦参数不是一成不变的。电机运行 30 分钟后,F_c 可能下降 15%~20%。我建议在系统空闲时做一次快速在线辨识,或者用温度传感器做查表修正。
  • 方向不对称: 正反转的摩擦力往往不一样。我遇到过一台设备,正转 F_s = 0.4 N·m,反转只有 0.3 N·m。原因是导轨安装有微小的倾斜。所以一定要正反两个方向分别辨识。
  • 不要过度补偿: 前馈补偿量不要超过实际摩擦力的 90%。留一点余量给反馈环去处理,否则系统会变得“太脆”,对微小扰动过于敏感。
  • 启动瞬间的处理: 速度过零时,sign(v) 函数会跳变,容易引起电流冲击。我习惯在零速附近做一个 0.1 r/min 的滞回区间,平滑过渡。

个人经验: 如果你调试时发现补偿后反而振荡了,大概率是 Stribeck 参数 v_s 估大了。试着把 v_s 减半,往往立竿见影。因为 v_s 决定了负阻尼区的宽度,估大了会让补偿器“误判”摩擦特性。

摩擦力补偿做到位了,低速控制就成功了一大半。剩下的就是机械谐振抑制和观测器设计,我们后面再聊。