重力补偿:力矩计算、实现与局限性
各位同学好,我是老张。今天我们来聊聊重力补偿这个话题。
说实话,重力补偿是轨迹规划里最基础、也最容易踩坑的一环。我刚开始做机器人控制那会儿,总觉得重力补偿不就是算个力矩嘛,有啥难的?结果第一次上真机,机械臂直接往下掉,差点把旁边的示教器砸了。嗯,从那以后我再也不敢小看这个环节了。
一、重力矩的计算
先说说重力矩怎么算。说白了,就是每个连杆的重力对关节产生的力矩。
我们拿一个简单的二连杆机械臂来举例。假设连杆1质量m1,质心位置在连杆中心;连杆2质量m2,质心也在中心。那么关节1受到的重力矩,就是两个连杆重力对关节1的力矩之和。
公式长这样:
τ_g1 = m1 * g * Lc1 * cos(q1) + m2 * g * [L1 * cos(q1) + Lc2 * cos(q1+q2)]
τ_g2 = m2 * g * Lc2 * cos(q1+q2)
其中:
- Lc1、Lc2 是质心到关节的距离
- L1 是连杆1的长度
- q1、q2 是关节角度
你可能会问,为什么是cos而不是sin?其实取决于你定义的零位。我个人习惯把机械臂竖直向上定义为0度,这样重力矩就是cos函数。如果你定义水平为0度,那就变成sin了。这个细节,我在项目里吃过亏。
关键点:重力矩只与当前位姿有关,与速度、加速度无关。所以它是个静态量,计算起来相对简单。
对于六轴工业机器人,重力矩的计算就复杂多了。一般用牛顿-欧拉法或者拉格朗日法。我建议你用牛顿-欧拉法,因为它的计算效率更高,适合嵌入式实时控制。
二、重力补偿的实现
重力补偿的实现,说白了就是把这个计算出来的重力矩加到关节力矩指令里。
伪代码大概是这样的:
// 控制循环
while(1) {
// 读取当前关节角度
q = read_joint_angles();
// 计算重力矩
tau_g = compute_gravity_torque(q);
// 计算其他控制量(比如PD控制)
tau_ctrl = compute_pd_control(q_desired, q, qd_desired, qd);
// 最终力矩指令 = 控制量 + 重力补偿
tau_cmd = tau_ctrl + tau_g;
// 输出到电机
set_motor_torque(tau_cmd);
}
这里有个坑,我必须要提醒你:重力补偿的符号一定要搞对。我曾经有一次把正负号搞反了,结果机械臂不仅没补偿,反而加速往下掉。那场面,啧啧,现在想起来还后怕。
我的经验:在调试阶段,先让机械臂处于一个安全位置,然后手动给一个很小的重力补偿值,观察机械臂的运动方向。如果方向对了,再逐渐加大补偿值。千万别一上来就给满补偿。
另外,重力补偿的实现方式有两种:
- 前馈补偿:直接加到力矩指令上,不经过反馈回路。响应快,但依赖模型精度。
- 反馈补偿:通过重力矩观测器来估计,然后补偿。鲁棒性好,但会有延迟。
我个人更倾向于前馈补偿,因为简单直接。前提是你的动力学模型要足够准。
三、重力补偿的局限性
重力补偿不是万能的。我总结了几个常见的局限性:
- 模型误差:你的动力学模型不可能100%准确。质心位置、质量、惯量这些参数,实际值和理论值总有偏差。我遇到过一台机器人,出厂时给的参数和实际差了5%,结果重力补偿后还是有明显的静态误差。
- 摩擦力干扰:重力补偿只补偿了重力,但摩擦力还在。尤其是在低速运动时,摩擦力矩和重力矩相当,这时候光靠重力补偿是不够的。
- 负载变化:机器人末端抓取的工件重量不同,重力补偿的参数就得跟着变。我见过一些工程师,换了个工件忘了更新参数,结果机械臂抖得跟筛子似的。
- 关节柔性:谐波减速器、同步带这些传动元件有柔性,会导致实际关节角度和编码器读数不一致。这时候你用编码器读数算出来的重力矩,和实际需要的重力矩就对不上了。
避坑指南:我曾经在一个项目中,用了高精度的重力补偿,但忽略了关节柔性。结果在高速运动时,补偿力矩和实际力矩相位差越来越大,最后系统失稳。从那以后,我每次做重力补偿都会先评估关节的刚度。
那么,怎么解决这些局限性呢?
- 对于模型误差,可以用自适应控制或者在线参数辨识来修正。
- 对于摩擦力,可以加一个摩擦力补偿模块。
- 对于负载变化,可以加一个力传感器,实时检测末端力。
- 对于关节柔性,可以用力矩传感器做闭环控制。
但这些方法都有各自的代价,比如成本增加、算法复杂度上升。所以实际工程中,要根据需求来取舍。
知识体系总览
下面这张图,是我自己画的重力补偿知识体系。你可以把它当作一个思维导图来看:
这张图把重力补偿的核心内容都串起来了。你从中心节点出发,沿着分支走一遍,就能对整个知识体系有个清晰的认知。
好了,关于重力补偿的内容就讲到这里。记住,理论再漂亮,最终还是要落到实际工程中。多调试、多总结,你也能成为重力补偿的高手。
可可精品资料库