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 知识体系总览
下面这张图,是我自己总结的摩擦力补偿完整流程,从模型到辨识再到补偿,一步到位:
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 决定了负阻尼区的宽度,估大了会让补偿器“误判”摩擦特性。
摩擦力补偿做到位了,低速控制就成功了一大半。剩下的就是机械谐振抑制和观测器设计,我们后面再聊。