教程 · 入门 · 25 分钟

每毫米步数:皮带、丝杠与分辨率

80 和 400 步/毫米是怎么来的,皮带和丝杠为何在分辨率与速度之间各有取舍,以及如何用尺子标定这个数,而不是盲信它。

一个数,一个公式

步进驱动器数脉冲。你的机器以毫米移动。把两者换算起来的那个数是每毫米步数,而机器上其他每一项标定都依赖它是对的。

这个公式从不变:

steps/mm = (full steps per revolution × microstepping) ÷ travel per revolution

分子由电机和驱动器定死——一台 1.8° 电机在 1/16 微步下是 200 × 16 = 3200 微步每转,永远如此。分母是唯一依赖你机器的部分,而它是一个关于机械的问题:轴转一圈,轴走多远?

上下两栏。上面一栏是一颗二十齿 GT2 同步轮和从它出来的齿形皮带,两个带齿之间标出 2 毫米节距,算式是二十齿乘 2 毫米等于每转 40 毫米,然后 200 乘 16 除以 40 等于每毫米 80 步。下面一栏是一根带四个不同颜色螺纹头的 T8 丝杠,上面骑着螺母,标出 8 毫米导程,算式是 200 乘 16 除以 8 等于每毫米 400 步。
几乎每一台业余机器都用的两种机构,以及你在配置文件里已经见过的那两个数。变的只有分母。 下载 SVG

皮带

对齿形皮带来说,每转行程就是同步轮上的齿数乘以皮带节距。GT2 皮带节距 2 mm,而 20 齿同步轮几乎是每一台业余机器的默认选择:

travel  = 20 teeth × 2 mm = 40 mm per revolution
steps/mm = (200 × 16) ÷ 40 = 80

就是这个——每一台 3D 打印机 X、Y 配置里那个 80 步/mm。它不是一个神奇常数;它是 20 齿 GT2 配十六微步,而你如果装一颗 16 齿同步轮,它就变成 100。

同步轮 每转行程 1/16 下的步/mm 分辨率
16 齿 GT2 32 mm 100 0.010 mm
20 齿 GT2 40 mm 80 0.0125 mm
30 齿 GT2 60 mm 53.33 0.019 mm
20 齿 GT3(3 mm) 60 mm 53.33 0.019 mm

注意 30 齿那一行除不整。53.333… 步/mm 完全合法——固件把它存成浮点并累积小数步——但这意味着没有任何一个位置会正好落在步进边界上,这也是大家都用那几种齿数的一个小理由。

丝杠

对丝杠来说,每转行程是导程——而导程不等于螺距。这是整个主题里最常见的错误。

  • 螺距是相邻螺纹之间的距离。
  • 导程是螺母转一圈走多远。
  • 导程 = 螺距 × 头数。

单头丝杠的导程等于螺距。但“无处不在的 T8”丝杠是 2 mm 螺距、四条独立螺纹螺旋并排绕在一起,所以转一圈螺母前进四个螺纹:

lead     = 2 mm pitch × 4 starts = 8 mm per revolution
steps/mm = (200 × 16) ÷ 8 = 400

而这就是你见过的另一个数。如果你用卡尺量 T8 的螺纹间距,量到 2 mm,算出 1600 步/mm,于是每一次移动都短了四倍。数一数丝杠端部的螺纹头数——你能看见那四条独立螺旋——或者干脆对着尺子转一整圈。

丝杠 螺距 头数 导程 1/16 下的步/mm
T8,四头(“T8x8”) 2 mm 4 8 mm 400
T8,双头(“T8x4”) 2 mm 2 4 mm 800
T8,单头(“T8x2”) 2 mm 1 2 mm 1600
M5 螺纹杆 0.8 mm 1 0.8 mm 4000
滚珠丝杠 1605 5 mm 1 5 mm 640

两者之间怎么选

分辨率不是免费的。一根分辨率是皮带十倍的丝杠,相同距离也需要十倍的脉冲——所以在固定最高步进率下它就慢十倍。这就是取舍,而且是个硬的:

GT2 皮带,20 齿 T8 丝杠
每转行程 40 mm 8 mm
1/16 下的分辨率 0.0125 mm 0.0025 mm
100 mm/s 所需步/s 8 000 40 000
实用极速 300+ mm/s 约 30 mm/s
轴上出力 小——皮带会拉伸 大——5 倍机械增益
断电能否保持位置 否 通常能(自锁)
背隙 张紧后很小 真实存在,就在螺母里
用在哪 X、Y——快、轻 Z——慢、重、掉不得

这正是 3D 打印机 X、Y 用皮带而 Z 用丝杠的原因。X、Y 动得快,几乎不承载东西。Z 动得慢,承载着平台或龙门梁的重量,而且断电时不能下垂——T8 的浅螺旋角让它自锁,所以它在负载下不会反向被驱。

那张表里的 40 000 步/s 也是一个真实的天花板,不是理论值。Arduino Uno 用位操作打步进脉冲大约在每秒 10 000 到 15 000 就到顶了,再快循环就跟不上,而这在 T8 配 1/16 微步下大约就是 30 mm/s。如果你需要丝杠轴动得更快,答案是更少的微步、更快的板子,或者硬件定时器——而不是更大的电机。

转矩,以及那张表没说的事

换机构换掉的不只是速度,还有电机看到的负载。丝杠大致按 2π × 半径 ÷ 导程 放大力,所以 T8 能把不算大的电机转矩变成相当可观的轴向力——这正是 Z 轴上用一台小电机也能抬起沉重平台的原因。

皮带正相反。20 齿 GT2 同步轮的节径是 12.7 mm,所以皮带张力等于电机转矩除以 6.4 mm。一台输出 0.3 N·m 的电机在皮带上大约给出 47 N,而你拿到的就这些。如果你的 X 轴一撞到东西就丢步,这套算术就是原因。

折算惯量同样会变,而且方向一致:机构越细,滑车质量对电机的影响越小,这也是丝杠轴能容忍皮带轴受不了的激进加速度的原因之一。你可以在步进模拟器里直接看到这个效应——其他一切保持不变,只把机构从皮带换成丝杠,然后观察失步角发生了什么。

标定它,别信它

算出来的数是起点,不是答案。皮带会拉伸,同步轮有制造公差,丝杠是带着乐观描述卖的。量:

  1. 在固定参考物上给滑车做标记。一条胶带加一道锋利的铅笔线。
  2. 下发一次长距离移动——100 mm,不是 10 mm。误差是个百分比,所以移动越长量得越准。
  3. 用卡尺或钢尺量实际发生了什么。
  4. 用一个比值修正:
new steps/mm = old steps/mm × (commanded ÷ measured)

指令 100 mm,量到 98.4 mm,当前是 80:80 × 100 ÷ 98.4 = 81.3 步/mm。

然后重复测量确认。修正一次却不收敛,说明这个误差不是标度误差——而这个区别本身就是诊断:

测量模式 原因
每个距离都恒定偏百分比 步/mm 错了——用上面的计算修
与距离无关地恒定偏一个量 背隙或同步轮上的紧定螺钉松了
每次偏的量都不一样 丢步——电流、速度或加速度
一个方向对、另一个方向短 背隙,而且你在两个方向上都量了
正好差 2 倍、4 倍或 16 倍 微步跳线与固件设置不一致
丝杠轴正好短 4 倍 该用导程的地方你用了螺距

最后两行能抓住大部分第一次的制作,而两者都是算术问题,不是机械问题。

旋转轴:每度步数

不是每根轴都是线性的。转台、挤出机、相机滑轨的横摇轴和机器人关节,问的是同一个问题、只是分母不同——而对旋转轴来说,分母通常是一个减速比而不是一种机构:

steps/degree = (full steps × microstepping × gear ratio) ÷ 360

一台 1.8° 电机在 1/16 微步配 5:1 减速下给出 (200 × 16 × 5) ÷ 360 = 每度 44.4 步,也就是 0.0225° 的分辨率。值得注意:这和皮带是同一套算术,只不过把每转毫米换成了 360 度。

3D 打印机的挤出机是那个异类,因为它虽然是旋转驱动,却按每毫米耗材的步数标称。分母是那个滚花齿轮的有效周长,而不是它的标称直径——齿咬进耗材,所以真实的抓持半径比零件上印的那个小。这就是为什么没人算 E 步数、所有人都去量它:

  1. 在挤出机入口上方 120 mm 的耗材上做标记。
  2. 精确挤出 100 mm。
  3. 从入口到标记再量一次。如果读到 27 mm,那你挤了 93 mm,不是 100。
  4. 新值 = 旧值 × 100 ÷ 93。在 93 步/mm 的基础上就是 100 步/mm。

起点取 120 mm 是有意为之:它留足了耗材,使得即使挤出机严重过挤,那个标记也永远到不了入口。

非整数的每毫米步数

一旦标定完,这个数就不再是整数——80 变成 81.3,而一次 10 mm 的移动变成 813.0 步。固件能正确处理这件事,但手写的代码通常不能,因为那个显而易见的实现每次移动都把小数扔掉:

// Wrong: truncates on every call. Two hundred 0.1 mm moves land 1.4 mm short.
long stepsFor(float mm) { return (long)(mm * stepsPerMm); }

在 81.3 步/mm 下,一次 0.1 mm 的移动是 8.13 步,截断成 8。那 0.13 被扔掉了,而且在下一次移动时又被扔掉,再下一次也是。几百段这样的短移动之后——而曲线或填充图案恰恰就是由几百段短移动组成的——误差就累积成看得见的量。

修法是保留余数而不是保留位置:

// Right: carry the fraction forward, so the error never accumulates past one step.
float carry = 0;

long stepsFor(float mm) {
  float exact = mm * stepsPerMm + carry;
  long whole = lround(exact);
  carry = exact - whole;        // always within half a step
  return whole;
}

现在任何时刻的最坏误差是半步——在这根轴上是 0.006 mm——而且它永不长大。这正是 Bresenham 直线光栅化用的同一个技巧,也是固件用步数而不是毫米跟踪位置的同一个原因:整数步数漂不了,而浮点的毫米位置会漂。

在固件里

Marlin 和 GRBL 都把这个数存成可设参数,所以你很少需要重新编译:

; Marlin — X, Y, Z, E
M92 X80 Y80 Z400 E93
M500          ; save to EEPROM

; GRBL
$100=80       ; X steps/mm
$101=80       ; Y
$102=400      ; Z

把你设的值写下来。这个问题最让人抓狂的版本,是一台曾经被正确标定过、重新刷了固件、然后悄悄退回固件默认值的机器。

下一步

上面这个数告诉机器它走了多远。它对自己是从哪里出发的只字不提——而一台开环机器在上电时没法知道这一点。那就是对着限位归零要做的事。

探索关联图谱

本教程所属的搭建

包含本教程的项目和学习路线。

延伸阅读

参考资料