Klipper-probe模块

配置信息
powershell 复制代码
[probe]  
pin: !PD4
x_offset: 0 
y_offset: 0 
z_offset: -0.20 #the distance between nozzle and level switch
speed: 10
samples: 2 #probe one point three times get an average
samples_result: average  
sample_retract_dist: 5
samples_tolerance: 0.05 # precision
samples_tolerance_retries: 5 
入口
python 复制代码
def load_config(config):
    return PrinterProbe(config, ProbeEndstopWrapper(config))
初始化
python 复制代码
class PrinterProbe:
    def __init__(self, config, mcu_probe):
        self.printer = config.get_printer()
        self.name = config.get_name()
        self.mcu_probe = mcu_probe
        self.speed = config.getfloat('speed', 5.0, above=0.)
        self.lift_speed = config.getfloat('lift_speed', self.speed, above=0.)
        self.x_offset = config.getfloat('x_offset', 0.)
        self.y_offset = config.getfloat('y_offset', 0.)
        self.z_offset = config.getfloat('z_offset')
        self.probe_calibrate_z = 0.
        self.multi_probe_pending = False
        self.last_state = False
        self.last_z_result = 0.
        self.gcode_move = self.printer.load_object(config, "gcode_move")
        # Infer Z position to move to during a probe
        if config.has_section('stepper_z'):
            zconfig = config.getsection('stepper_z')
            self.z_position = zconfig.getfloat('position_min', 0.,
                                               note_valid=False)
        else:
            pconfig = config.getsection('printer')
            self.z_position = pconfig.getfloat('minimum_z_position', 0.,
                                               note_valid=False)
        # Multi-sample support (for improved accuracy)
        self.sample_count = config.getint('samples', 1, minval=1)
        self.sample_retract_dist = config.getfloat('sample_retract_dist', 2.,
                                                   above=0.)
        atypes = {'median': 'median', 'average': 'average'}
        self.samples_result = config.getchoice('samples_result', atypes,
                                               'average')
        self.samples_tolerance = config.getfloat('samples_tolerance', 0.100,
                                                 minval=0.)
        self.samples_retries = config.getint('samples_tolerance_retries', 0,
                                             minval=0)
        # Register z_virtual_endstop pin
        self.printer.lookup_object('pins').register_chip('probe', self)
        # Register homing event handlers
        self.printer.register_event_handler("homing:homing_move_begin",
                                            self._handle_homing_move_begin)
        self.printer.register_event_handler("homing:homing_move_end",
                                            self._handle_homing_move_end)
        self.printer.register_event_handler("homing:home_rails_begin",
                                            self._handle_home_rails_begin)
        self.printer.register_event_handler("homing:home_rails_end",
                                            self._handle_home_rails_end)
        self.printer.register_event_handler("gcode:command_error",
                                            self._handle_command_error)
        # Register PROBE/QUERY_PROBE commands
        self.gcode = self.printer.lookup_object('gcode')
        self.gcode.register_command('PROBE', self.cmd_PROBE,
                                    desc=self.cmd_PROBE_help)
        self.gcode.register_command('QUERY_PROBE', self.cmd_QUERY_PROBE,
                                    desc=self.cmd_QUERY_PROBE_help)
        self.gcode.register_command('PROBE_CALIBRATE', self.cmd_PROBE_CALIBRATE,
                                    desc=self.cmd_PROBE_CALIBRATE_help)
        self.gcode.register_command('PROBE_ACCURACY', self.cmd_PROBE_ACCURACY,
                                    desc=self.cmd_PROBE_ACCURACY_help)
        self.gcode.register_command('Z_OFFSET_APPLY_PROBE',
                                    self.cmd_Z_OFFSET_APPLY_PROBE,
                                    desc=self.cmd_Z_OFFSET_APPLY_PROBE_help)
  • 初始化打印机对象和探针参数
    • self.printer:通过 config.get_printer() 获取打印机对象。
    • self.name:通过 config.get_name() 获取探针名称。
    • self.mcu_probe:保存传入的 MCU 探针对象。
    • 速度设置:speedlift_speedx_offsety_offsetz_offsetprobe_calibrate_z 等控制探针的移动速度和偏移。
  • 推断探针的 Z 轴位置
    • 根据配置文件,确定探针在探测过程中的 Z 轴移动位置。
    • 如果配置中有 stepper_z 段,使用其中 position_min 定义的 Z 轴最小位置。
    • 否则,从 printer 配置的 minimum_z_position 获取 Z 轴最小位置。配置里minimum_z_position: -5
  • 多重采样设置(提高测量精度)
    • sample_count:设定采样次数,以便进行多次测量来提高精度。
    • sample_retract_dist:设定每次采样后探针提升的距离。
    • samples_result:采样结果的处理方式,可以选择 'median'(中位数)或 'average'(平均值)。
    • samples_tolerancesamples_retries:设定采样的误差容忍度和重试次数,用于提高多重采样的稳定性。
  • 注册探针的 Z 虚拟端点
    • 使用 self.printer.lookup_object('pins').register_chip('probe', self) 将探针注册为 Z 虚拟端点,使其在打印机控制系统中可以作为端点来使用。
  • 注册归位事件处理器
    • homing 相关事件处理器会在归位过程的不同阶段触发,分别在归位移动开始和结束时执行 _handle_homing_move_begin_handle_homing_move_end,在归位轨道的开始和结束时执行 _handle_home_rails_begin_handle_home_rails_end。如果在 GCode 命令中遇到错误,则会触发 _handle_command_error
  • 注册 GCode 命令
    • PROBE:触发一次探针操作。
    • QUERY_PROBE:查询探针状态。
    • PROBE_CALIBRATE:校准探针的 Z 轴偏移。
    • PROBE_ACCURACY:测量探针的精度。
    • Z_OFFSET_APPLY_PROBE:将当前 Z 轴偏移应用到探针。
python 复制代码
class ProbeEndstopWrapper:
    def __init__(self, config):
        self.printer = config.get_printer()
        self.position_endstop = config.getfloat('z_offset')
        self.stow_on_each_sample = config.getboolean(
            'deactivate_on_each_sample', True)
        gcode_macro = self.printer.load_object(config, 'gcode_macro')
        self.activate_gcode = gcode_macro.load_template(
            config, 'activate_gcode', '')
        self.deactivate_gcode = gcode_macro.load_template(
            config, 'deactivate_gcode', '')
        # Create an "endstop" object to handle the probe pin
        ppins = self.printer.lookup_object('pins')
        pin = config.get('pin')
        pin_params = ppins.lookup_pin(pin, can_invert=True, can_pullup=True)
        mcu = pin_params['chip']
        self.mcu_endstop = mcu.setup_pin('endstop', pin_params)
        self.printer.register_event_handler('klippy:mcu_identify',
                                            self._handle_mcu_identify)
        # Wrappers
        self.get_mcu = self.mcu_endstop.get_mcu
        self.add_stepper = self.mcu_endstop.add_stepper
        self.get_steppers = self.mcu_endstop.get_steppers
        self.home_start = self.mcu_endstop.home_start
        self.home_wait = self.mcu_endstop.home_wait
        self.query_endstop = self.mcu_endstop.query_endstop
        # multi probes state
        self.multi = 'OFF'
  1. 初始化打印机对象和配置参数
    • self.printer 使用 config.get_printer() 获取打印机对象。
    • self.position_endstop 设定了 z_offset(Z 轴端点偏移量),用于定义探针的初始位置或偏移。
    • self.stow_on_each_sample 用于配置探针是否在每次采样后停放,默认为 True
  2. 加载 GCode 宏
    • 使用 gcode_macro 对象从配置中加载探针激活和停用的 GCode 模板:
      • activate_gcode:在探针激活时执行的 GCode。
      • deactivate_gcode:在探针停用时执行的 GCode。
  3. 创建端点对象
    • 使用 pins 对象(通过 self.printer.lookup_object('pins') 获得)查找探针的 pin(引脚)配置。
    • 通过 lookup_pin() 配置引脚参数,包括是否可以反转或上拉电阻,随后得到引脚参数 pin_params
    • 使用引脚所在的 mcu 芯片设置一个 endstop 引脚对象 mcu_endstop,负责处理探针状态。
  4. 注册事件处理程序
    • 注册事件 klippy:mcu_identify,当触发该事件时调用 _handle_mcu_identify 方法。这个方法通常用于在初始化或连接时对探针或端点进行识别和确认。
  5. 简化调用的包装函数
    • 定义一些包装函数用于直接调用 mcu_endstop 对象的相关方法,包括:
      • get_mcu:获取探针所在的 MCU 对象。
      • add_stepper:将步进电机添加到探针控制中。
      • get_steppers:获取当前与探针关联的步进电机。
      • home_starthome_wait:用于控制探针的归位和等待状态。
      • query_endstop:查询端点的当前状态(是否被触发)。
  6. 多重探针状态
    • 定义 self.multi,表示多重探针采样状态,默认为 'OFF'
python 复制代码
class ProbePointsHelper:
    def __init__(self, config, finalize_callback, default_points=None):
        self.printer = config.get_printer()
        self.finalize_callback = finalize_callback
        self.probe_points = default_points
        self.name = config.get_name()
        self.gcode = self.printer.lookup_object('gcode')
        # Read config settings
        if default_points is None or config.get('points', None) is not None:
            self.probe_points = config.getlists('points', seps=(',', '\n'),
                                                parser=float, count=2)
        self.horizontal_move_z = config.getfloat('horizontal_move_z', 5.)
        self.speed = config.getfloat('speed', 50., above=0.)
        self.use_offsets = False
        # Internal probing state
        self.lift_speed = self.speed
        self.probe_offsets = (0., 0., 0.)
        self.results = []
  • 该对象会在 bed_mesh 和 delta_calibrate 模块加载时进行初始化,并传入回调函数和探测点points等信息。
探测判断
python 复制代码
# delta 校准
ProbePointsHelper.start_probe (probe.py) -> ProbePointsHelper._move_next (probe.py) -> 
DeltaCalibrate.probe_finalize (delta_calibrate.py)

# bed_mesh 校准
ProbePointsHelper.start_probe (probe.py) -> ProbePointsHelper._move_next (probe.py) -> 
BedMeshCalibrate.probe_finalize (bed_mesh.py)
探测是否结束代码逻辑
python 复制代码
def _move_next(self):
    toolhead = self.printer.lookup_object('toolhead')
    # Lift toolhead
    speed = self.lift_speed
    if not self.results:
        # Use full speed to first probe position
        speed = self.speed
    toolhead.manual_move([None, None, self.horizontal_move_z], speed)
    # Check if done probing
    if len(self.results) >= len(self.probe_points):
        toolhead.get_last_move_time()
        res = self.finalize_callback(self.probe_offsets, self.results)
        if res != "retry":
            return True
        self.results = []
    # Move to next XY probe point
    nextpos = list(self.probe_points[len(self.results)])
    if self.use_offsets:
        nextpos[0] -= self.probe_offsets[0]
        nextpos[1] -= self.probe_offsets[1]
    toolhead.manual_move(nextpos, self.speed)
    return False
  • 提升探针或工具头
    • 通过调用 toolhead.manual_move,将探针或工具头移动到指定的高度 self.horizontal_move_z
    • 如果这是第一次探测(self.results为空),会使用较快的初始速度(self.speed)。否则使用探针提升速度(self.lift_speed)。
  • 检查探测是否完成
    • 检查已完成探测点的数量是否达到预定的探测点总数(len(self.probe_points))。
    • 如果所有点都探测完成:
      • 调用 toolhead.get_last_move_time() 记录最后的移动时间。
      • 执行 self.finalize_callback,处理探测结果(如计算网格调整数据等)。
  • 处理探测结果
    • finalize_callback 返回值决定后续操作:
    • 如果返回值不是 "retry",探测结束,方法返回 True
    • 如果返回值为 "retry",表示需要重新探测,清空结果 self.results 并从头开始。
  • 移动到下一个探测点
    • 确定下一个探测点的坐标:
      • self.probe_points 列表中取出对应位置的点。
      • 如果启用了偏移(self.use_offsets),会调整 X、Y 坐标以考虑探针的实际偏移量。
    • 将探针移动到下一个点,准备进行探测。
  • 返回继续探测
    • 方法返回 False,表示探测未完成,需要继续执行探测流程。