1. 先画清角度,重力符号才不会错
考虑竖直平面中的两个转动关节。世界 x 水平向右、y 竖直向上,重力加速度为 [0,−g0]T。第一杆角 q1 从水平正轴逆时针量,第二杆角 q2 相对第一杆量。因此第二杆的绝对角是 q1+q2。
| 参数 | 意义 | 单位 |
|---|
| l1,c1,c2 | 第一杆长度、第一/第二杆质心到相应关节的距离 | m |
| m1,m2 | 两杆质量 | kg |
| I1,I2 | 各杆绕自身质心、垂直运动平面的转动惯量 | kg·m² |
| qi,q˙i,q¨i | 关节角、角速度、角加速度 | rad、rad/s、rad/s² |
| τi | 作用在关节上的驱动力矩 | N·m |
本课刚体、平面、固定基座;不含柔性和齿隙。杆长不是质心距离,不能直接把 ci 当 li;也不能把绕关节惯量和绕质心惯量重复相加。
2. 为什么动力学要先做一遍运动学
两个质心的位置是
r1=[c1cosq1c1sinq1],r2=[l1cosq1+c2cos(q1+q2)l1sinq1+c2sin(q1+q2)].
对时间求导,用 dcosq/dt=−sinqq˙。第一杆速度平方为 ∥r˙1∥2=c12q˙12。第二杆两段速度相加,平方展开中的交叉项由两段切向方向夹角 q2 给出:
∥r˙2∥2=l12q˙12+c22(q˙1+q˙2)2+2l1c2cosq2q˙1(q˙1+q˙2).
这个交叉项就是关节耦合的来源之一。若忽略它,就等于假装第二杆质心的两个运动分量互不影响。
3. 把动能整理成惯性矩阵
每杆动能等于质心平动能加绕质心转动能:
T=21m1∥r˙1∥2+21I1q˙12+21m2∥r˙2∥2+21I2(q˙1+q˙2)2.
定义三个常量以缩短代数:
a=I1+I2+m1c12+m2(l12+c22),β=m2l1c2,d=I2+m2c22.
三者单位都是 kg·m²。把同类项归并成 T=21q˙TM(q)q˙,便读出
M(q)=[a+2βcosq2d+βcosq2d+βcosq2d].
对称的两个非对角元并不是巧合:二次型中的交叉速度项要求一致的系数。M12 表明第二关节加速度会影响第一关节所需力矩。M 随 q2 变化,意味着机械臂伸直与折叠时的“惯性负担”不同。
4. 势能决定重力补偿,不需要凭直觉猜
取基座高度为零,重力势能为
U=m1g0c1sinq1+m2g0[l1sinq1+c2sin(q1+q2)].
因为角度从水平轴量,势能含正弦,对角度求偏导后重力项含余弦:
g(q)=[(m1c1+m2l1)g0cosq1+m2c2g0cos(q1+q2)m2c2g0cos(q1+q2)].
方程左侧的 g 是为了抵消重力所需的广义力,不是实际重力本身的符号。当两杆水平伸向右边时,两个 gi 都为正,电机要施加逆时针力矩防止下落。两杆竖直时相应力臂为零,这是一个立即可做的符号检查。
5. 速度乘积项从哪来
以第一关节为例:
∂q˙1∂T=M11q˙1+M12q˙2.
对时间求导不仅要微分速度,还要微分随 q2 变化的 M:
dtd∂q˙1∂T=M11q¨1+M12q¨2−2βsinq2q˙1q˙2−βsinq2q˙22.
这里 T 不显含 q1,所以 ∂T/∂q1=0。第二关节需要再减去 ∂T/∂q2。令 h=βsinq2,把两个容易漏掉的混合项分别写出:
dtd∂q˙2∂T∂q2∂T=M12q¨1+M22q¨2−hq˙1q˙2,=−h(q˙12+q˙1q˙2).
两者相减时,−hq˙1q˙2 与 +hq˙1q˙2 抵消,速度项只剩 +hq˙12。连同第一关节,整理得
c(q,q˙)=[−βsinq2(2q˙1q˙2+q˙22)βsinq2q˙12].
于是完整方程是 Mq¨+c+g=τ。c 用 N·m;它不含加速度,但含速度乘积,来源是运动坐标与连杆耦合。
把 c=Cq˙ 写成矩阵时,一种方便的选择为
C=[−hq˙2hq˙1−h(q˙1+q˙2)0],h=βsinq2.
C 的表达不唯一,物理上确定的是 Cq˙。 为能量分析,常选满足 M˙−2C 反对称的形式。本例
M˙−2C=[0−h(2q˙1+q˙2)h(2q˙1+q˙2)0].
任意实向量 z 满足 zT(M˙−2C)z=0。这说明某些速度耦合只在自由度间交换能量,而不是凭空产生能量。
6. 把电机与摩擦接进来
简单关节摩擦可建成 fi=biq˙i+τc,itanh(q˙i/ϵ)。bi 是黏性摩擦系数,τc,i 是近似库仑摩擦力矩,ϵ 是小速度尺度。双曲正切是数值平滑近似,并不能真实表示所有静摩擦滞回。
若输入是电机电压,还需要
Lei˙=V−Rei−keωm,τj≈ηNkti.
i 为电流 A,V 为电压 V,Le 为电感 H,Re 为电阻 Ω,keωm 是反电动势,kti 是电机力矩,N=ωm/q˙ 是减速比,η 是传动效率。不同能流方向的效率可能不同。
若驱动器内电流环足够快,可把关节力矩当近似输入;否则应将电流增广为状态。不能在控制律里请求无限带宽、无限力矩,再用“理论稳定”解释实机震荡。
7. 为什么会想到计算力矩控制
目标是跟踪 qd(t)。定义误差 e=q−qd,e˙=q˙−q˙d。先设计一个容易稳定的虚拟加速度
ac=q¨d−Kde˙−Kpe.
Kp 的单位为 s−2,Kd 为 s−1,每项都是角加速度。然后用模型把“我希望的加速度”转换成实际力矩:
τ=M^(q)ac+c^(q,q˙)+g^(q)+f^(q˙).
为什么使用当前 q,q˙ 计算补偿?因为真实系统此时的重力、惯性、摩擦由当前状态决定,而不是由期望状态决定。参考加速度则来自轨迹规划器。
若模型精确、测量准确、力矩能实现,代回动力学得到 q¨=ac,因此
e¨+Kde˙+Kpe=0.
非线性耦合系统被变成每轴可设计的二阶误差系统。取对角正定增益,每轴特征方程是 s2+kds+kp=0;选 kp=ωn2、kd=2ζωn,即可由自然频率和阻尼比设计响应。
Lyapunov 证明不是写一个负号就结束
对误差系统取
Ve=21e˙Te˙+21eTKpe.
它不是实际机械能,而是误差的正定度量;量纲可用统一尺度归一化。对时间求导并代入误差方程:
V˙e=e˙Te¨+e˙TKpe=−e˙TKde˙≤0.
仅得到半负定,因为瞬间 e˙=0 时导数为零。还需检查不变集:若一直 e˙=0,则 e¨=−Kpe=0,正定 Kp 迫使 e=0。由不变集论证得到理想误差系统渐近收敛;等价地也可由线性特征根证明指数稳定。不能把这份证明直接套到有饱和、延迟、错误模型的系统。
8. 更稳健的起点:PD 加重力补偿
只保持固定构型时,可先用
τ=g(q)−Kpτe−Kdτq˙,e=q−qd.
这里 Kpτ,Kdτ 为对称正定的力矩反馈增益,单位分别为 N·m/rad、N·m·s/rad,不能直接照搬上一节虚拟加速度增益的数值。设重力模型准确、摩擦耗散、目标固定,取实际动能加误差弹性势能
V=21q˙TM(q)q˙+21eTKpτe.
利用上面的反对称性质,可推得 V˙=−q˙TKdτq˙−q˙Tf(q˙)≤0。它不需要精确抵消所有惯性和速度项,因而是理解“利用物理结构设计控制”的好入口。角度多圈与关节限位需明确,不能把欧氏误差的全局证明等同于所有姿态参数空间上的全局稳定。
模型不准时,计算力矩误差会表现为剩余广义力 Δ。若能证明其有界,可研究输入到状态稳定性或最终有界,而不是继续声称零误差。积分、扰动观测器、自适应控制都应从这份剩余误差的结构出发设计。
9. 数值练习与 C++ 核心
设 m1=m2=1 kg,l1=1 m,c1=c2=0.5 m,I1=I2=1/12 kg·m²。在 q1=q2=0、速度为零时,先计算 M 和 g,再求实现 [1,0]T rad/s² 所需力矩。
展开完整计算与可编译测试
有 a=5/3、β=1/2、d=1/3,所以
M=[8/35/65/61/3],g=[19.62,4.905]T Nm.
因此需求力矩为 [22.2866667,5.7383333]T N·m。第二关节期望加速度为零仍需额外力矩,因为它需要抵消第一关节加速对它的耦合作用。
#include <array>
#include <cmath>
#include <cassert>
using V2=std::array<double,2>;
struct Arm { double m11,m12,m22; V2 c,g; };
Arm model(double q1,double q2,double v1,double v2) {
const double a=5.0/3, beta=0.5,d=1.0/3,h=beta*std::sin(q2);
return {a+2*beta*std::cos(q2),d+beta*std::cos(q2),d,
{-h*(2*v1*v2+v2*v2),h*v1*v1},
{1.5*9.81*std::cos(q1)+0.5*9.81*std::cos(q1+q2),
0.5*9.81*std::cos(q1+q2)}};
}
V2 inverse(const Arm& a,V2 dd) {
return {a.m11*dd[0]+a.m12*dd[1]+a.c[0]+a.g[0],
a.m12*dd[0]+a.m22*dd[1]+a.c[1]+a.g[1]};
}
V2 forward(const Arm& a,V2 tau) {
const double d=a.m11*a.m22-a.m12*a.m12;
assert(d>0);
const double b0=tau[0]-a.c[0]-a.g[0],b1=tau[1]-a.c[1]-a.g[1];
return {(a.m22*b0-a.m12*b1)/d,(-a.m12*b0+a.m11*b1)/d};
}
int main() {
Arm a=model(0,0,0,0); auto t=inverse(a,{1,0});
assert(std::abs(t[0]-(19.62+8.0/3))<1e-12);
assert(std::abs(t[1]-(4.905+5.0/6))<1e-12);
for(double q2: {-2.0,-0.4,0.0,1.2,3.0}) {
auto m=model(0.7,q2,0.3,-0.6);
assert(m.m11>0 && m.m11*m.m22>m.m12*m.m12);
auto r=forward(m,inverse(m,{0.2,-0.8}));
assert(std::abs(r[0]-0.2)<1e-10 && std::abs(r[1]+0.8)<1e-10);
}
}
上述二阶显式解只为手算小例子,规模增大应使用稳定线性求解器。继续练习可做PID 在线题,再把输出从归一化指令改成带单位的力矩,并分析饱和后的积分处理。
来源与边界
两连杆参数与数例为本课自选,逐项推导不复制教材段落。动力学结构对照 Modern Robotics 8.1,计算力矩的模型补偿结构对照 作者官方 11.4 课程。进一步做扰动估计可接扰动观测器,但不能省略力矩实现、测量同步和可观测性检查。