模式:本页「
运动模拟」承载全部运动学能力;「三维模型」为纯静态模型视图(关节锁定在设计零位、无目标点与求解控件),「装配图」为二维图纸。运动模拟下左栏只保留 IK 结果与关节角度,零件树/打印清单自动收走。
目标:使 TCP(末端工具法兰 P09 安装面中心,可加“工具长”)到达给定点,并在一切满足限位的可行构型中取
各电机需转过的角度之和最小者(相对当前姿态的行程;连续轴 θ 与 θ±360 是同一物理位形,角差一律取 ±180° 内的短弧,见第 6 条;离线批算不给参考姿态时退化为 Σ|θᵢ| 最小)。开启上方“
姿态控制”后,
约束升级为
位置 3 + 姿态 3(工具轴指向 + 绕轴滚转),见第 5 条。
姿态操控:姿态开启后目标球处出现方向箭头与粉色侧球——
箭头指向即工具朝外方向(法兰面法向朝外,也就是工具伸出的方向)。
拖箭头头部用弧球法(指针射线与以目标为球心、半径=箭长的球求交,方向=交点−球心)连续调整方位/俯仰;
拖箭杆或粉色侧球按指针绕轴的转角增量改滚转;右侧数字框随时同步,可精确微调,
「取当前」把真实工具姿态读回、「垂直向下」一键设为爪取常用姿态。
约定:求解器内部工具坐标系 z 轴取法兰面法向(朝臂内,与 TCP 外伸反向);界面上的方位/仰角/滚转、
箭头与绿色当前轴线均以朝外法向描述,入栈时绕工具 x 轴翻 180° 换算,两者看到的物理姿态完全一致。
- 先消去一维(仅位置任务):TCP 恰好落在 J6 轴线上,绕 J6 转动不改变 TCP 位置 ⇒ 对“到点”任务取
θ6 = 0 即已最优。
- 识别结构:J2 / J4 / J5 三轴严格平行(轴向 Y,过 x = 19.5),J1 轴为 X,J3 轴沿臂长方向 Z。
记
A = X−X0、R = |(Y−Y0, Z−Z1)|、φ = atan2(Z−Z1, Y−Y0),
则 X = X0 + a,而 (Y, Z) 由 (b, c) 绕 J1 轴旋转 φ 得到:
a = Vx·cosθ3·cosθ2 + Vz·sinθ2,b = −Vx·sinθ3,
c = C0 + (−Vx·cosθ3·sinθ2 + Vz·cosθ2),
其中 Vx, Vz 只是 (θ4, θ5) 的函数。
- 两式联立消元(关键一步):由
a = A 得恒等式
A² + n² = Vx² + Vz²(n = −Vx·cosθ3·sinθ2 + Vz·cosθ2);
代入 b² + c² = R² 后 θ3 的项全部抵消,于是
n = (R² + A² − Vx² − Vz² − C0²) / (2·C0) —— 唯一确定;
再由 n² + A² = Vx²·cos²θ3 + Vz² 得
cos²θ3 = (n² + A² − Vz²) / Vx² ⇒ θ3 共四支 ±σ, ±(π−σ);
最后 θ2 与 θ1 各由一个 2×2 线性方程组唯一确定:
cosθ2 = (κA + Vz·n)/(κ² + Vz²),sinθ2 = (Vz·A − κ·n)/(κ² + Vz²),
κ = Vx·cosθ3;θ1 = φ − atan2(c, b)。
- 遍历冗余(按行裁剪到可行段):(θ4, θ5) 就是二维冗余。闭式支只在平面支有解时才存在,
限位盒内只有 7~27% 的网格点能过判据,且实测(5 个目标 × 全部 θ4 行)每行的可行集都是单一连续段
—— 于是先用探测步找出每行的可行段、向两端各放宽一个探测步兜住段界,段内再按步长精扫。
段内密度与全域扫一致,因此解的质量不动,粗扫采样量降约 4.6×(但全量总耗时只降约 1.10×——局部加密窗口是 ±2h 步长 h/8,格数恒为 32×32/种子、与 h 无关,精修才是耗时地板)。
之所以不把粗扫一起放松:根枚举目前不保证完备,漏根时要靠粗扫的窄带候选兜底,
实测把粗扫同步放松会换来上百度级的代价劣化。
- 姿态任务(6 自由度):工具坐标系姿态
R = R₁·R₂·…·R₆(与场景图 6 级矩阵链一致)。
结构上 J5 轴与 J6 轴在腕心 (19.5, 128, 222) 垂直相交,因此 θ6 只提供绕工具自身轴的滚转:
工具轴指向 = (R₁…R₅)·ẑ,与 θ6 无关,TCP 位置也与 θ6 无关。每条位置闭式支都附带确定的 R₅
(= R₁…R₅),滚转角随之闭式解出:N = R₅ᵀ·R_des(需为 Rz(−θ6))⇒
θ6 = −atan2(N₁₀, N₀₀);姿态偏差 e = ∠(R₅·Rz(−θ6), R_des) ≤ 2° 的支才收入。
- 姿态 = 孤立根求解:闭式支把 θ1..θ3 吸收掉之后,姿态任务只剩「工具轴指向 = 目标轴」
这 2 个方程、2 个未知数 (θ4,θ5),解是孤立点(独立密集种子 + 牛顿普查实测只有 1~2 个根),
滚转再由 θ6 闭式补上。所以不再用网格密度去撞那条斜窄谷:逐行对残差两个分量找变号括号、
从括号中点起跑阻尼高斯-牛顿(奇异时加大阻尼而非退出),并对每支的 ‖e‖ 最小节点补种以收
切向相切的根;代价最优的若干条入选候选再各收口一次。于是
姿态残差量级从 ~10⁻²° 变为 10⁻⁶°(工程意义上的精确),且 Σ|θ| 不劣于原路径。
- 两处判据陷阱(都验过,写在这里防止被自证):其一,切向残差在工具轴反平时同样为零,
同向判据只能在收口时验,当作迭代中止条件会让每支一进来就作废;其二,求根按支下标对齐
prev/cur,不可行的支必须留 null 占位,否则下标错开、括号判据失配,实测会整支漏掉一个真根、
多付 130° 关节角。确有少数奇异「刀尖」构型无精确根,此时牛顿收敛到 ‖e‖ 的真实最小,
报出的残差不再是采样伪影。
- 混合优先(比重可调折中):优先级下拉的第三种模式——一根滑杆自由分配两端:
0% 即姿态优先、100% 即位置优先(两端直接交给上面两条专用算法,结果逐位一致),
中间值在两端锚点之间最小化归一化折中代价
J = w·(e/e_ref)² + (1−w)·(o/o_ref)²。两端尺度取锚点自身:
e_ref = 姿态优先解的 TCP 位置差、o_ref = 位置优先解的姿态残差,
于是滑杆读数就是「沿折中历程的进度」、与目标的绝对误差量级无关(50% ≈ 两端各自归一后对半)。
之所以不用「1 mm ↔ 1°」的绝对量纲:实测两端误差常在 100 mm / 40° 量级,绝对量纲会把读数整体挤向
位置端(折线中点落到 ~13% 处),滑杆就不好用了。两端锚点复用上面两条算法——位置端 = 位置精确族 +
闭式滚转 + 孤立根收口(位置不可达时退化为最近可达位置),姿态端 = 工具轴闭式对齐 + θ6 补滚转
(姿态精确、位置最近);中间值以两锚点及关节空间插值为种子,对 6 维残差
[√w·(p−t)/e_ref , √(1−w)·RV°/o_ref] 做阻尼高斯-牛顿 + 单轴抛光,取 J 最小者
(J 同量级 2% 带内取行程 — 相对当前姿态的 Σ|wrap(θᵢ−refᵢ)| — 更小者,防等价支横跳)。两端中任一端在另一维也达标
(≤0.05)时折中无意义、直接返回该端——注意位置端不达标而姿态端在位置上达标时返回姿态端
(它两维同时占优:位置优先族收不到的到达解,姿态端收得到)。全程无随机数,同一输入逐位可复现;
拖动走快路(同「实时续解」条哲学,归一化尺度沿用最近一次全量的缓存),松手必走全量。
- 连续优先(最小移动角 / 防倒摆):等价多分支(θ3 的 ±σ/±(π−σ)、肘上/肘下、J1/J3 镜像族)之间只按 Σ|θ| 选优时,
目标微动就会在分支间跳来跳去、绕远路(实测目标挪 20 mm 就翻族:垂直向下时左右移动单步最大 74.8°、
累计绕出 348°,而目标实际只扫过 160°)。交互求解以当前手臂姿态为参考位姿,选解判据取
所有电机需要转过的角度之和最小——
Σ|wrap180(θᵢ−refᵢ)|:连续轴(J1/J3/J6)无机械限位,
θ 与 θ±360 是同一物理位形,故角差一律取短弧;末尾 1e-6·Σ|θ| 只作并列时的次序稳定项。
同一条扫描路径实测:单步最大 5.0°、累计 160.0°,与目标实际扫过的角度一致。
拖动动画同样对连续轴取「离起始角最近的等价角」再插值,避免 +151.9°→−167.0° 反向扫 318.9° 绕一整圈。
- 实时续解(拖动快路):目标每帧只挪几毫米时,真解在 (θ4,θ5) 平面上连续移动,
没必要为重扫整个冗余维付全价。
solveWarm 只在上一帧解附近取同一闭式支、走一小步同支搜索,
姿态任务再收口一次;任一校验不过(换支、越限、位置残差超差、姿态没收口、关节跳太大)就返回 null
自动回落全量粗扫,松手后的求解一定不带 warm、走全量。快路只负责「能快的时候快」,不改变正确性判据。
- 代表角:位姿以 360° 为周期,解角一律取 ±180° 内的等价角(|θ| 最小);J2 / J4 / J5 另受相邻件实测机械区间约束,越限即丢弃。
- 自检:每次求解都用闭式 FK 与场景图真实 6 级矩阵链各算一次 TCP 和工具姿态并与目标比对(见上表残差)。
验证数据(本机实测,可复现)
| 检查项 | 结果 |
| 闭式 FK vs 6 级矩阵链(1500 组随机位形) | 4.6 × 10⁻¹³ mm |
| 逆解分支重构(200 组随机可行位形) | 200 / 200 命中 |
| θ6 不变性(0° → 137°,TCP 位移) | 0.00 mm |
| 姿态参数 ↔ 旋转矩阵往返(2000 组随机) | 2.4 × 10⁻⁶° |
| 姿态重构达标率(200 组随机可行位形,step 0.5,A/B 同机) | 中位残差 0.0234° → 0.000000°;>0.05° 的例数 2 → 0(改造前文档口径 185–191/200) |
| 姿态解 Σ|θ| vs 改造前(60 组,step 0.25 + 连续项) | 中位 +0.03°,最大 +8.4°(该例是新解更贴参考位姿、Σ|θ| 反而更大,属连续项的正常取舍而非漏解) |
| 位置解 vs 0.05° 参考网格(100 目标,step 0.25) | 中位 +0.000°,最大 +0.49°,>1° 例数 0 |
| 全量求解耗时(60 组,step 0.25 + 连续项) | 仅位置 70.6 → 63.3 ms;位置+姿态 88.8 → 81.0 ms(约 1.10×;粗扫采样量降 4.6×,但精修才是地板) |
| 实时续解快路(每帧 3 mm + 1.5°,240 帧) | 位置命中 96%、均 0.058 ms;姿态命中 65%、均 0.59 ms —— 对全量 81 ms 约 140~1400×,是交互延迟的主要收益来源 |
| 快路结果的独立复核(fkChain / 全 6 轴 orient,非求解器自报) | 位置 5.5×10⁻¹³ mm · 姿态 1.7×10⁻⁶° |
| 姿态模式候选表长度(供互异构型/碰撞改选取样) | 26 → 13(精确根集合本就只有 1~2 个,达标门收紧后可选样变少;动态碰撞改选若依赖宽候选需留意) |
| 滚转角交互 roll 0→90(参考位姿连续) | Δθ6 = 89.99°,θ1..θ5 变化 < 0.01° |
| 60 个可达目标:失败次数 / 最大残差 | 0 次 / 3.5 × 10⁻¹³ mm |
| 相对 0.05° 极细网格参考的最大劣化 | 0.02° |
| vs 4000 次随机多起点数值解 | 0 / 20 次劣于数值解 |
| 等价分支跳变 · 4 条扫描路径(修复前 → 后) | >10° 跳变 14 → 5 次;最大单步 163.5° → 16.8° |
| 单次求解耗时 | 拖动跟随走快路 ~0.1 ms;全量求解默认步长下位置 ~20 ms、姿态 ~100 ms(node 侧本机实测,浏览器同量级) |
限位:电机行程各轴 ±360°(=滑块范围);解角取 ±180° 内的等价角——位姿以 360° 为周期,超出 ±180° 不产生新位姿。
相邻打印件的实测机械区间封顶:J2 ∈ [−107, 128],J4 ∈ [−112, 112],J5 ∈ [−96, 96],J1 / J3 / J6 可整周。
参考:零位静态扫描 J2 [−106, 9]、J4 [−111, 16]、J5 [−95, 34] 只在其它轴全零时对固定立柱成立,已不再当可行域;
跨组零件对(腕/法兰撞立柱那类)由胶囊碰撞模型按当前姿态实时判定(实测 J1=90° 时 J2 正端从 +8° 放到 +107°)。
局限:胶囊模型故意不检相邻组零件对(|Δg|=1),那部分由上面的实测机械区间兜底;换模型须重跑
scratch/probe_adj.py 更新 collide.json 的 adj。若需要更舒展的姿态,可从上方“互异构型”列表改选次优解。
不可达:若目标超出工作空间,自动求最近可达位姿——阻尼最小二乘
从当前姿态锚定起步(抑制退化方向的无用漂移)、固定种子的确定性重启(同一点重复解算逐位一致)、再经零空间抛光取最小总关节角的代表值;报告的距离为抛光后真实值。
姿态不可达:姿态任务超可达空间时,阻尼最小二乘误差向量升级为 6 维(位置 mm + 姿态 deg,按 20 mm/rad 折算),返回位置与姿态联合最近的位姿,两个残差分别显示。
混合优先不可达:位置超可达空间时,位置端锚点退化为「最近可达位置」、姿态端仍取「姿态精确、位置最近」,
再按同一权重折中,两端各自的残差在结果栏如实列出(与位置优先的历史兜底——6 维联合 DLS——是两个不同的代表值,切换模式可得)。
API:控制台可用
IK.solver.solve([x,y,z],{step:0.25,tool:0,pose:{R:ArmIK.poseMat(az,el,roll)}});
IK.setPose(az,el,roll) 可直接设定目标姿态;
IK.setPrio('mix',0.3) 切到混合优先并设比重;
IK.solver.solveTo([x,y,z],{pose:{R:…},priority:'mix',mixW:0.3}) 直接取折中解(0 与 1 分别等于姿态优先 / 位置优先)。