(篇一)
前言
原创文章,转载引用务必著名链接,水平有限,如有疏漏,欢迎指正交流。
文章如有更新请访问 DFRobot 社区及 cnblogs 博客园,前者内容较全,后者排版及阅读体验更佳。
感谢 DFRobot 社区美女的催更和我媳妇的鼓励与支持,才有了这篇文章。近期实验的多,整理成文的少,而人一旦停下来,(惰)惯性还是挺大的。
本系列文章的目的是介绍自动 Z 偏移校准的基本原理与两种简单实现,属于抛砖引玉。私以为自动 Z 偏移校准的广泛应用是实现小白无痛使用 3D 打印机的重要变革之一,使得 3D 打印机从专业工具向家用数码产品转变,真正实现开机即打。
视频演示:
- 3D打印机使用Klipper 低成本无痛升级自动Z偏移校准实现完美首层
- 3D打印机使用Klipper低成本无痛自动校准调平器偏移实现完美首层
本文主要介绍原理,详细的示例请参考后续的文章。


硬件列表:
- 压力薄膜开关:原理类似薄膜键盘输出数字通断信号,不是模拟压力传感器,触发距离固定,0.25/0.3mm,此处作为一把精确的尺子取代 A4 纸。
- CR-Touch:创想三维的探针调平器,精度很高,而且目前价格非常便宜,只要几块钱
实际上以上都可以使用涡流传感器、接近开关传感器、压力传感器等替换,原理相同。其中压力传感器触床时可以认为偏移为 0,因为直接喷嘴触床。
一、背景
目前常见的自动 Z 偏移校准方法包括 Klicky,压力喷嘴/压力热床,涡流传感器等,其特点是无需用户使用 A4 纸等工具手动调整,喷嘴移动到 Z=0 位置时正好触碰热床表面,从而获得完美首层打印效果。

【图 1】Z 限位开关偏移与调平器偏移示例 source: https://github.com/protoloft/klipper_z_calibration/wiki/Why-This
二、基本原理
首先说结论:
- 自动 Z 偏移校准需要喷嘴参与
- 限位开关的作用是归位后获得的坐标系 S’ 与热床坐标系 S 重合(理想状态)
相比于 XY 轴,Z 轴对打印效果的影响最大,定位精度要求也最高,毕竟千里之行始于足下,打好地基 “房子” 才能建得好。
对于 Z 轴校准,主要分为三个阶段:
- Phase 1 古法纯手动操作
- 机械微动开关或光电开关作为 Z 轴限位
- 调整限位开关位置和热床调节螺丝,<u>借助 A4 纸</u>,使得归位 Z 轴触发限位开关时,喷嘴接触热床
- 此方式很繁琐,且更换打印打印板后需要重新调整
- Phase 2 增加灵活性:引入 Z Offset 偏移
- 机械微动开关或光电开关作为 Z 轴限位
- 一般归位 Z 轴后喷嘴位于热床外下方
- 引入 Z Offset 值,如 -0.5,代表归位后喷嘴抬升 0.5mm 到达热床表面(喷嘴当前位于热床表面下方 0.5mm)
- 校准 Z Offset 值,归位后,移动喷嘴到热床上方,借助 A4 纸使喷嘴接触热床,根据当前 Z 坐标,计算出 Z Offset 值
- 此方式在更换不同厚度打印板(玻璃、PEI等)后,无需调整限位开关位置
- 类似的还有自动调平器仅做 Z 轴等高校准 + 热床调平螺丝等高校准 + 床网数据生成,仍然使用物理开关作为 Z 限位开关
- Phase 3 自动调平器时代
- 使用自动调平器作为 Z 轴限位开关
- 调平器触发后,继续移动喷嘴,<u>借助 A4 纸</u>,使喷嘴接触热床,从而计算出 Probe Z Offset,此值代表调平器触发后,喷嘴距离热床距离。例如 2.0,代表喷嘴下降 2.0mm 触床。
三、走进新时代——自动 Z 偏移校准
从上面可以看到,所有操作都需要借助 A4 纸(也有采用肉眼观察的),来判断喷嘴触床,从而获得 Z Offset 值,但是 A4 纸法每个人的主观感受不同,且精度不高,所以追求每次都能获得完美首层的话,需要新工具代替 A4 纸,且重复定位精度高,还可以被打印机控制系统读取数值。

【图 2】高精度微动开关接触式调平器
除了 A4 纸,还有这种接触式调平器,但是打印机控制系统无法读取其数值。所以我们希望一个新的测量工具拥有如下特点:
- 比 A4 纸精确,重复定位精度高
- 数值可以被打印机控制系统读取
在操作前,应使用 PROBE_ACCURACY
指令检查调平器重复定位精度是否合格,一般 range
< 0.025,标准差越低越好。看到有些 UP 主调这调那,热床贴纸啥的,结果调平器都不准。
3.1 实例演示1:机械开关作为 Z 轴限位开关
此场景使用机械限位开关,在配置文件种指定其 endstop_position
值,从而告诉系统,触发限位时当前坐标为 endstop_position
。
借助薄膜开关,由于其触发距离已知(0.25/0.3mm,注意归位速度不能太快),通过分别归位 Z 轴以及触发 Probe,可以计算出真实的 endstop_position
值,使得移动到 Z=0 时喷嘴正好触床,具体如下图所示:

注意:
- Probe 前应清理喷嘴餐料
- Probe 时应不止探测一次,用于减少误差影响
- 当使用 U 槽型光电开关时,由于 X 横梁可以穿过光电开关,所以归位后喷嘴可以位于热床上方
- 上图介绍归位后喷嘴位于热床下方的场景,实际上 a. 高于热床低于薄膜高度 b. 高于热床高于薄膜高度 时此等式仍然适用,具体请自行推导
# 准备;
# 1. 无感归位坐标:-13,-7
# 2. position_endstop 启用,初始0,可以校准两次看看
# 3. 注释原Probe
[mcu loadcell]
serial: /dev/serial/by-id/usb-Klipper_rp2040_fly-rht36-if00
[temperature_sensor FLY-RHT36]
sensor_type: temperature_mcu
sensor_mcu: loadcell
[probe]
# 去套,不压紧
pin: ^!loadcell:gpio27
x_offset: 0
y_offset: 0
z_offset: 0.3
# 探测时Z轴移动速度
speed: 3
samples: 3
samples_result: median
sample_retract_dist: 2.0
# 超出此范围可认为偏差过大
samples_tolerance: 0.025
samples_tolerance_retries: 3
# 1. pos 0, g offset 0.45
# 2. runtime pos -0.45 g offset 0.45
# 3. runtime pos -0.45 goff 0 压死了
# 4. pos -0.45 goff0
# 结论:Z_OFFSET_APPLY_ENDSTOP, SAVE_CONFIG后生效,实时的就是Gcode_Offset
# 由于日常使用限位,所以默认pos0,日常使用要save_config
[gcode_macro _AUTO_Z_CALIBRATE_CALC]
description: 用于自动计算并应用 Gcode Offset
gcode:
# 以热床平面为 Z=0, 压力薄膜在热床上触发时的实际坐标。已知为 0.3/0.25 等
{% set REAL_PROBE_POS = printer.configfile.settings.probe.z_offset|float %}
{% set ESTOP_POS = printer.configfile.config.stepper_z.position_endstop|float %}
{% set PROBE_POS = printer["probe"].last_z_result|float %}
# 计算过程
# 1. 归位后喷嘴位于热床下,则偏移距离为负值。
# aka. AUTO_ESTOP_BED_OFFSET
{% set REAL_ESTOP_POS = REAL_PROBE_POS - PROBE_POS + ESTOP_POS |round(2) %}
# TODO: Gcode_Offset, 取反?
# SET_GCODE_OFFSET Z={ESTOP_POS + REAL_ESTOP_POS} MOVE=0
SET_GCODE_OFFSET Z={- ESTOP_POS - REAL_ESTOP_POS} MOVE=0
RESPOND MSG="压力薄膜实际坐标(配置读取): {REAL_PROBE_POS}"
RESPOND MSG="压力薄膜偏移坐标(测量获得): {PROBE_POS}"
RESPOND MSG="限位开关实际坐标(计算获得): {REAL_ESTOP_POS}"
RESPOND MSG="限位开关偏移坐标(配置读取): {ESTOP_POS}"
# RESPOND MSG="限位开关相对热床偏移距离: {REAL_ESTOP_POS} {AUTO_ESTOP_BED_OFFSET}"
# SAVE_CONFIG 重启前不生效。和限位开关实际坐标相同:REAL_ESTOP_POS
Z_OFFSET_APPLY_ENDSTOP
# 日常无压力薄膜,无法每次都测试,故需要保存
# SAVE_CONFIG
[gcode_macro AUTO_Z_CALIBRATE]
description: 使用机械限位归零,再使用压力薄膜在左前方调平螺丝上方探测
# inspried by https://github.com/Ficik/extra-probe
gcode:
{% set SCREW_X = 30.0 %}
{% set SCREW_Y = 20.0 %}
G28
SET_GCODE_OFFSET Z=0 MOVE=0
G0 X{SCREW_X} Y{SCREW_Y} F12000
G91
G0 Z10 F1800
G90
RESPOND MSG="请安装压力传感器...等待8s"
G4 P8000
PROBE
G91
G0 Z15 F1800
G90
_AUTO_Z_CALIBRATE_CALC
注意点:
- 薄膜压力开关触发距离固定,一般是0.25/0.3mm等
- 想要 Z Offset 实时生效请使用
SET_GCODE_OFFSET
指令,而 Z_OFFSET_APPLY_ENDSTOP 指令需要 SAVE_CONFIG 重启后生效
- 由于宏内部不更新坐标,所以使用独立的
_AUTO_Z_CALIBRATE_CALC
宏进行计算
3.2 实例演示2:调平器也作为 Z 轴限位开关

核心难点是定义一个额外的 probe, 因为默认 Klipper 仅支持一个 Probe。这里参考 https://github.com/Ficik/extra-probe/ 项目,但是由于 klipper 代码有改动,需要修改后才能正常使用,具体修改如下:
pi@orangepipcplus:~$ diff extra_probe.py extra_probe.py_mod
125c125,126
< z_offset = self.printer.lookup_object('probe').z_offset
---
> probe = self.printer.lookup_object('probe', default=None)
> z_offset = probe.get_offsets()[2]
如果后续又变了,可以参考 https://github.com/protoloft/klipper_z_calibration 进行修改。
# 准备;
# 1. 无感归位坐标:30,20
# 2. position_endstop 禁用
# 3. Probe offset定为2mm
[mcu loadcell]
serial: /dev/serial/by-id/usb-Klipper_rp2040_fly-rht36-if00
# 归位XY坐标,修改无感归位
[temperature_sensor FLY-RHT36]
sensor_type: temperature_mcu
sensor_mcu: loadcell
[extra_probe loadcell]
# 去套,不压紧
pin: ^!loadcell:gpio27
z_offset: 0.3
samples: 5
speed: 3
sample_retract_dist: 2.0
samples_result: median
samples_tolerance: 0.025
samples_tolerance_retries: 3
[force_move]
enable_force_move: True
[gcode_macro _AUTO_Z_CALIBRATE_CALC]
description: 用于自动计算并应用 Gcode Offset
gcode:
# {% set REAL_PROBE_POS = printer.configfile.config.printer["extra_probe loadcell"].z_offset|float %}
# TODO: 读取
# {% set REAL_EXPROBE_POS = printer["extra_probe loadcell"].z_offset|float %}
# {% set REAL_EXPROBE_POS = printer["extra_probe loadcell"].default_probe_z_offset|float %}
{% set REAL_EXPROBE_POS = 0.3 %}
{% set PROBE_POS = printer.configfile.config.probe.z_offset|float %}
{% set EXPROBE_POS = printer["extra_probe loadcell"].last_z_result|float %}
# 计算过程,REAL_PROBE_POS 也就是 Probe Z Offset
{% set REAL_PROBE_POS = REAL_EXPROBE_POS - EXPROBE_POS + PROBE_POS |round(2) %}
# TODO: Gcode_Offset, 取反?
SET_GCODE_OFFSET Z={ - REAL_PROBE_POS + PROBE_POS} MOVE=0
RESPOND MSG="压力薄膜实际坐标(配置读取): {REAL_EXPROBE_POS}"
RESPOND MSG="压力薄膜偏移坐标(测量获得): {EXPROBE_POS}"
RESPOND MSG="调平器实际坐标(计算获得): {REAL_PROBE_POS}"
RESPOND MSG="调平器偏移坐标(配置读取): {PROBE_POS}"
# RESPOND MSG="限位开关相对热床偏移距离: {REAL_ESTOP_POS} {AUTO_ESTOP_BED_OFFSET}"
# SAVE_CONFIG 重启前不生效。和限位开关实际坐标相同:REAL_ESTOP_POS
Z_OFFSET_APPLY_PROBE
# 日常无压力薄膜,无法每次都测试,故需要保存
# SAVE_CONFIG
[gcode_macro AUTO_Z_CALIBRATE]
description: 探针G28热床Z0, 探针Probe压力POS1,喷嘴Probe压力POS2
# inspried by https://github.com/Ficik/extra-probe
gcode:
# [TODO2]
# 设置喷嘴位于压力传感器正上方时的坐标
{% set NOZZLE_X = 30 %}
{% set NOZZLE_Y = 20 %}
# 设置探针位于压力传感器正上方时的坐标
# {% set TOUCH_X = 60 %}
# {% set TOUCH_Y = -6 %}
# NEW,避免干扰压力传感器,关闭挤出电机。TODO: 多挤出电机
SET_STEPPER_ENABLE STEPPER=extruder ENABLE=0
# 如果未归位,提示归位
G28 # 测试用
M400
# {% if printer.toolhead.homed_axes != "xyz" %}
# {action_respond_info("请首先归位后继续")}
# # G28
# {% else %}
# 清空 Gcode Offset
SET_GCODE_OFFSET Z=0 MOVE=0
# 使用喷嘴探测(5次,压平可能的残料)后抬 5mm
G0 X{NOZZLE_X} Y{NOZZLE_Y} F12000
G91
G0 Z10 F1800
G90
RESPOND MSG="请安装压力传感器"
G4 P8000
EXTRA_PROBE PROBE=loadcell
G91
G0 Z20 F1800
G90
RESPOND MSG="请取下压力传感器"
# G4 P8000
# 使用探针探测后抬 5mm
# TODO: 不需要PROBE?因为就是offset
# G0 X{TOUCH_X} Y{TOUCH_Y} F12000
# PROBE
# G91
# G0 Z5 F1800
# G90
# 由于宏内部不更新坐标,所以使用独立的宏进行计算
_AUTO_Z_CALIBRATE_CALC
# {% endif %}
3.3 实例演示3:机械限位开关 + 调平器组合
之前做的一个项目,具体不再赘述。注意压力传感器容易受干扰,使用时关闭挤出机电机和风扇。
