自制工业控制系统:插补基础——从一段几何到一串脉冲,机床是怎么走出一条斜线的
Contents
起因
写插补实战的时候发现一个缺口:那篇默认读者已经知道插补是什么,一上来就是偏差函数和递推。可"插补"恰恰是数控黑话里对开发者最不友好的一类词——两个字都认识,连起来不知道在说什么;教科书讲它之前先铺了一百页机床结构,厂商手册更干脆,一句"支持直线/圆弧插补"就翻篇。系列的规矩是不留知识黑洞,而插补是整个数控最中央的概念——解析器交出的段表、电机篇备好的脉冲、放电篇留的变频入口,最后全部汇到它身上。所以实战篇之前单开这篇,把概念从零垫平:插补是什么、为什么非有它不可、它站在系统哪一环。只假设两件事:你写过代码,并且知道步进电机来一个脉冲走一步。
这个词的来历就是答案的一半。interpolation 在数学里是"插值":已知两个点,把中间的点补出来。1952 年 MIT 改造的那台首台数控铣床面对的正是这道题——纸带上打的只有端点,起点到终点之间无穷多个中间位置,纸带打不起也存不下,必须由机床自己补出来。“插补"由此成了数控的专有动词,干的就是字面意思的事:在程序给的点之间,把中间的路一步步补出来。补路的角色叫插补器(interpolator),最早是控制柜里一抽屉门电路,后来是软件里的一个状态机——补路的家伙换了四代,题目没换过。
一、问题的模样:程序给的是几何,电机吃的是脉冲
拿一条最短的程序段开工:
|
|
在程序语言的世界里,这是一条连续线段,上面有无穷多个点。再看电机那头的世界:X、Y 是两台各听各脉冲的步进电机(电机篇)——X 来一个脉冲,工作台沿 X 挪 1µm;Y 来一个脉冲,沿 Y 挪 1µm。注意一个物理事实:没有任何电机能"斜着走”。工作台从不斜着滑,它只会横着挪一步、竖着挪一步,或者两边同时各挪一步。
所以"机床走出一条斜线"的真相是:把 X 方向的 10000 步和 Y 方向的 5000 步(1µm 当量)排成一个先后顺序,让工作台踩出的阶梯尽量贴住那条看不见的斜线。**插补,就是排这个顺序的算法。**把当量放大到 1mm 画出来(真实系统是 1µm,阶梯小一千倍,肉眼看就是一条光洁的直线):
|
|
一个容易转不过来的弯:插补不是"算出轨迹上每个点的坐标、再命令电机去那里",而是反着来——在"这一步只有 X+、X−、Y+、Y− 几个选项"的硬约束下,把几何一步一步兑现出来。约束不是数学给的,是硬件给的:接口只认脉冲沿,电机只走整步。下一节把"为什么不能顺着直觉来"的账算完。
二、为什么不直接"算坐标、发命令"——三笔账
写软件的人第一直觉都一样:来个循环,for i in 0..N { 命令电机去 (x0+i·dx, y0+i·dy) },坐标线性递增,多自然。这条路在三处同时碰壁:
接口账(最根本)。开环步进的世界里不存在"去坐标 X"这条命令,PUL/DIR 两根线只认脉冲沿——你只能喂步,不能指路。“指路"的世界(总线伺服那一族)是另一份合同(电机篇第八节),我们的目标机是步进开环,合同里没这一条。
节拍账。就算退一步只要求"按时喂步”:空走 5m/min、1µm 当量,节拍是 83kHz(电机篇第五节的账),每拍 12µs。83kHz 的中断每秒打断 CPU 八万次,每次进出栈加分发一两微秒,CPU 吃掉一成还带微秒级抖动——抖动直接变成低速爬行。结论:喂步的钟必须由硬件敲(FPGA),软件只决定"哪一步"。这正是实战篇"模式与节拍分离"的来由。
量化账。再退一步,换能指路的伺服:坐标是连续量,物理落点仍然量化到分辨率,阶梯并没有被消灭,只是从插补器搬进驱动器里排。轨迹离散是物理事实,不是算法将就——先接受它,后面的数学才立得住。
三笔账算完,问题定型成它真正的样子:**每一拍做一个极小的决定——这一拍 X 出不出步、Y 出不出步。**上面那条 10mm 斜线要做一万五千次,每次决定的预算只有几次加减和比较。插补这门学问的全部内容,就是怎么用加减比较去逼近本该乘除开方才能描述的几何。
顺带钉一个词:资料里的"插补周期"。数据采样式 CNC(伺服那一族)里插补器每隔 1ms 算一次各轴的位置设定值,这个 1ms 叫插补周期;脉冲增量式的世界里对应的是单个脉冲的节拍,12µs 量级,密近百倍。两个门派的分野和我们的选型(接口决定算法),实战篇第一节展开。
三、最笨的办法最聪明:走一步、看一眼、再走一步
人在这个问题上先给出了答案。手动车锥度的老师傅两只手各摇一个手轮,大拖板进一点、小拖板进一点,节奏有轻有重,刀尖走出来的就是斜线——他脑子里的判据并不复杂:看一眼刀偏到哪边了,下一步往回找。五十年代的硬接线数控柜把这套手感原样搬进逻辑电路:每走一个当量判一次方向,逐点比较法由此得名——走一步、比一次、再走一步。
判什么?得有个记分牌告诉机器"当前点偏在哪边"。直线 (0,0)→(10,5) 的记分牌取 F = Xe·Y − Ye·X(Xe、Ye 是全段增量,这里 =10、=5;X、Y 是当前点,教学尺度当量 1mm):理想的线是 Y = X/2,点落在线上方 Y 偏大、F > 0;落在线下方 F < 0;压线 F = 0。
每步的规则只有一条:X 走一步、Y 走一步,两个候选各算一下走完之后的 F,哪个让 |F| 更小就走哪个——永远朝"更贴线"的那边迈。前 10 步手算出来:
| 步 | 当前点 | F | 走 X 后 F′=F−5 | 走 Y 后 F′=F+10 | 走哪 | 走完位置 |
|---|---|---|---|---|---|---|
| 1 | (0,0) | 0 | −5 | +10 | X(|−5| 小) | (1,0) |
| 2 | (1,0) | −5 | −10 | +5 | Y | (1,1) |
| 3 | (1,1) | +5 | 0 | +15 | X | (2,1) |
| 4 | (2,1) | 0 | −5 | +10 | X | (3,1) |
| 5 | (3,1) | −5 | −10 | +5 | Y | (3,2) |
| 6 | (3,2) | +5 | 0 | +15 | X | (4,2) |
| 7 | (4,2) | 0 | −5 | +10 | X | (5,2) |
| 8 | (5,2) | −5 | −10 | +5 | Y | (5,3) |
| 9 | (5,3) | +5 | 0 | +15 | X | (6,3) |
| 10 | (6,3) | 0 | −5 | +10 | X | (7,3) |
三个看点。第一,节奏:X 多 Y 少、平均二比一——斜率 1/2 长这个样子,没有人把比例教给算法,它从"挑 |F| 小"里自己长出来;第 3、6、9 步走完 F 正好归零,踩在线上,是这套节奏的锚点。第二,F 不用重算:X 走一步 F 就减 5、Y 走一步 F 就加 10,两个增量整段不变——这就是实战篇里"偏差递推"的全部内容,加减法伺候,一个乘法都没有。第三,终点不用算距离:X 剩余量、Y 剩余量各自数到零就到,总步数 15 = |10| + |5|,一笔明账,多一步少一步都是有 bug。
再补一刀精度:全程 |F| ≤ 5,折成几何偏差 |F|/√(Xe²+Ye²) ≤ 5/√125 ≈ 0.45 当量——阶梯的贴线误差不到半个台阶,这就是阶梯轨迹"宏观上就是直线"的定量版本。
这套数学还有段值得记的身世:1962 年 IBM 的 Bresenham 在绘图仪上独立推导出同一个 F、同一种递推(往像素网格里画直线该点亮哪格),后来成了所有光栅显示器和打印机画线的底层算法——机床和绘图仪两个世界互不知晓,殊途同归到同一条递推。3B 纸带的 J/G/Z 三个字段,就是这套逻辑硬件时代的寄存器投影(详解篇讲过来历)。
四、插补器站在链条的哪一环
把全链画出来,看"单位"怎么一路变形:
|
|
链条上每一环只认自己的输入输出,插补器是其中唯一"既懂数学、又懂硬件脾气"的一环:上游交给它的是纯几何(µm 整数的段表),它交出去的是纯决策(这一拍谁动)。中间还藏着一个分工:几何它自己批量算,节拍交给 FPGA 按变频频率播放——模式与节拍分离,实战篇第四节的主角,这里先立桩。
五、这个词的边界:圆弧、四轴和样条
圆弧插补是同一道题换了"贴"的对象:记分牌从"离直线偏多少"换成"离圆周偏多少"(F = x²+y²−R²,圆外为正、圆内为负),规则不变——走一步、比一次,点在圆外就往圆心那侧迈,圆内就往外迈,宏观上就是贴着圆周走。四轴联动是给四个电机各配一个放行闸门,同一节拍下按几何比例放步:XY 走轮廓、UV 摆锥度(锥形切割)。
日常语境里"插补"已经泛化成"把离散程序点之间的轨迹补出来"这一整类问题:高档铣削系统有样条插补(NURBS)、螺旋插补、渐开线插补——记分牌换得更复杂,套路没变。线切割的日常是二维轮廓,直线加圆弧全覆盖,3B 时代六十年就这两样,够用是被历史验过的;上下异形那种真三维活,本质是直线插补在四轴上的推广,不是新记分牌。我们的系统先把两样做扎实——每多一种记分牌,验证面就大一圈,这是自己写系统才体会到的账。
顺手拆一对常被混的词:驱动器手册里的"细分“和插补的”步“不在一层。细分是电机内部的电气粒度——绕组电流按正弦切了多少微步(电机篇第三节,它买的是平稳不是精度);插补是轨迹上的几何粒度——工作台一拍走几个脉冲当量。一个在电机里,一个在轨迹上,互不替代。
总结
这篇就干一件事:把"插补"从一个黑话变成一个能讲清的问题。三句话版本——程序给的是几何(段表里一段段 µm 整数的线段和圆弧),电机吃的是脉冲(每拍只有 X/Y 出不出步几个选项),插补是中间排步序的算法(每一拍用加减和比较,朝更贴轨迹的方向迈一步)。三笔账解释了为什么不能"算坐标、发命令”(接口只认喂步不认指路、83kHz 节拍必须硬件敲、量化躲不掉);逐点比较的记分牌 F 和"挑 |F| 小"给了这个问题最省的解,上面那张 15 步手算表就是实战篇 LineGen 的前传。
验收三条:能把插补讲给一个没碰过机床的程序员听懂;能算出 G01 X10 Y5 在 1µm 当量下的总步数(15000)并说出为什么是两轴步数之和;能在全链图上指出插补器吞什么吐什么。过了这三条,插补实战剩下的就只是把这套直觉写成带符号的 Rust 递推、塞进 12µs 的节拍里。
参考链接
- Wikipedia: Numerical control——1952 年 MIT 首台数控机床,插补问题诞生的地方
- Wikipedia: Bresenham’s line algorithm——同一数学在绘图仪/光栅世界的独立推导,1962
- 本系列:插补实战——逐点比较法、偏差递推与脉冲节拍(本篇的代码版)、G代码与3B解析实战(段表契约)、G代码与3B代码详解(J/G/Z 与逐点比较法的硬件来路)、电机驱动基础(脉冲当量、83kHz 与细分的账)、放电加工与高频电源(节拍的变频来源)
Author 软件开发大郭
LastMod 2026-09-11