首页那只机械臂,是怎么够到你的鼠标的
从转动一个手肘,到让三个关节轮流让步。五张可以摸的插图,拆开首页那只机械臂背后的几何,也看看它没有替真实机器人解决什么。
在首页挪动鼠标,那只机械臂会弯弯手肘,把夹爪伸过去。
看起来像「知道你想让它去哪」。但鼠标只交给它一个点,没有告诉它肩膀转几度、手肘朝哪边、腕部该不该跟着动。这个简单动作的难处,就藏在位置已经知道,姿势还没决定里面。
不妨把首页拆成五张小图。每张只问一件事:先转关节,再挪目标,最后看看那几行程序是怎么轮流劝动三个关节的。
给角度,像沿着地址找过去
先只留肩膀和手肘两个关节。
从肩膀朝某个方向走完上臂,再顺着前臂的方向走完前臂,落脚处就是指尖。只要长度和角度都知道,这趟路没有岔口。
先拖夹爪,只转手肘。然后拖手肘上的圈,改转肩膀。看指尖留下的圆弧,圆心会搬家。
这叫正运动学:从关节姿态算出末端位置。名字听起来比动作严肃,其实就是顺着两根杆走过去。
若肩角是 ,肘相对于上臂的转角是 ,两节长度是 ,那么以肩为原点:
前臂用的是 ,不是单独的肘角。肩膀已经转过一次,手肘是在那个方向上继续转。正文公式按数学课本:y 朝上、逆时针为正。SVG 的 y 朝下,代码内部角度符号相反;图里的角度读数已经翻回正文约定。
给位置,却像一个地址有两条路
现在把问题倒过来:指尖必须到十字靶,两个关节该怎么摆?
这叫逆运动学。先别急着求解:把肩、肘、目标连成一个三角形。上臂和前臂是两条固定边,肩到目标的距离是第三条边。
同一个三角形可以往两边翻。下面的实线和虚线,就是朝两边翻的两只肘。
只指定指尖位置,通常有两个姿势。贴着圆环边缘时,三角形被压平,两个姿势合成一个;出了圆环,就没有姿势能做到。
这张图的杆长是 100 和 65。最远够到 165,这不奇怪;最近却只能到 35。两节不一样长,折到最紧也不能完全抵消。太近和太远,都可能够不到。
把三角形翻译成公式
设目标与肩的距离为 r。余弦定理给出肘角:
可达时, 对应两支解。再用目标方位角减掉三角形在肩部张开的角:
如果 r 不在 内,就别硬把它塞进反余弦。图中明确标出无解,并画出最近姿态。两节等长、目标恰好在肩上的情况更特殊:完全折叠后,肩可以朝任意方向,有无穷多个解。
多一个关节,多出一点自由
首页有三节连杆。如果仍然只要求指尖到一个平面位置,就比刚才多了一点「姿势上的余地」。
把下面的指尖钉住,再慢慢改变肩角。肩后的关节点换了位置,剩下两节重新解一次三角形,仍能接回同一个目标。
现在不只是两条路,而是一段连续的姿势。多出来的自由度,叫冗余。
冗余不是多余的零件。真实手臂可以用它绕开障碍、避开关节极限,或让动作更顺。但它也把问题从「求一个答案」变成了「在许多答案里,挑哪个」。
不一次想明白,先劝离手最近的那个关节
首页选择了一种很朴素的策略:每次只转一个关节。
先看最末端的腕关节。从它画两条线,一条指向夹爪,一条指向目标。把第一条往第二条转一点,夹爪就沿着这个关节的圆周靠近目标。然后换肘,再换肩。
从腕到肩扫完一遍,通常还没到,便再扫一遍。它叫 CCD,循环坐标下降;这里的「坐标」是轮流调整的关节角,不是把 x、y 轮流改掉。
它没有先列出全部姿势,也不要求每一步就到目标。每个关节只处理眼前的夹角,许多小让步累积起来,把指尖挪过去。固定目标、没有关节限位、每次取最短转角且比例在 0 到 1 之间时,这种转动不会增加末端到目标的距离。但「不变远」不保证一定能到:目标可能不可达,也可能卡在不再进展的姿态。
首页那只手,只藏了两个手感旋钮
首页三节杆长是 82、86、50,底座在 SVG 的 (80, 252)。每次不是把夹角全转完,而是转 60%;每个动画帧从腕到肩扫 6 遍。
下面保留同样的杆长、初姿态和求解循环。先用默认参数挪一个目标,再恢复初姿态,把比例调到 0.1,只算一帧。相同的计算次数,指尖会留下更大的距离。
比例小,单次步子小;多扫几遍,可以补一些进度。比例 1 在固定目标下未必会抖,反而常常更快——别把「阻尼让动作温和」误记成「不加阻尼就一定不稳定」。鼠标还在移动时,追踪的手感才是另一层比较。
首页真正计算关节角的部分就是这些。以下保留了原来的循环,只省去 TypeScript 的参数类型:
function solve(t, iters = 6, gain = 0.6) {
for (let iter = 0; iter < iters; iter++) {
for (let i = 2; i >= 0; i--) {
const pts = forward(ang);
const pivot = pts[i], end = pts[3];
const a1 = Math.atan2(end.y - pivot.y, end.x - pivot.x);
const a2 = Math.atan2(t.y - pivot.y, t.x - pivot.x);
let d = a2 - a1;
d = Math.atan2(Math.sin(d), Math.cos(d));
for (let k = i; k < 3; k++) ang[k] += d * gain;
}
}
}
atan2(sin(d), cos(d)) 把夹角换成一圈以内的最短转向。最后一行给 i 后面的角度都加上同一个量,因为代码存的是每节杆的绝对朝向:转肘时,前臂和腕后的杆都得一起跟过去。
正文前面的公式用关节相对角,代码这里用连杆绝对角。这不是两种物理,只是两种记账方式。漏掉这个区别,很容易写出「肘转了,夹爪那节却留在原地」的怪手臂。
能够到,还没有获得开机许可
首页那只手不承重,也不接电机。它没有关节限位、没有碰撞检测,也没有规定夹爪必须朝哪个方向。
把目标挪到底座附近,它可能折出真实机械臂根本做不到的姿势。这不是再调一下 gain 就能补好的:运动学解,只回答了几何上怎样摆,不回答能否安全地走过去。
真实机器人还要选解、避障、规划一条连续路径,再让控制器执行。伸直附近还会碰到奇异位形:某些方向很难靠微小关节转动产生位移。那是继续学习雅可比矩阵的好入口,但不必为了看懂首页,今天就把整本书读完。
这五张图的数学集中在 arm.js,检验文件会把逆解代回正运动学,检查指尖有没有真到目标。它们只是浏览器里的几何,不连接真实硬件。
下次回首页挪动鼠标,你看到的就不只是一只跟手的小动画了。那是三个关节在轮流让一点,把一个还没想明白的姿势,慢慢让到你指的地方。
Modern RoboticsLynch 与 Park 的开放教材配套资料:从刚体运动继续走向运动学、规划与控制。modernrobotics.northwestern.edu Robotics, Vision and Control 工具Peter Corke 的 Robotics Toolbox:把纸上的运动学继续放进工具里试。petercorke.com