当前位置: 首页 > news >正文

Klipper-delta_calibrate模块

配置信息

[delta_calibrate]
radius: 145
horizontal_move_z: 10 #This value is related to the lift height of the nozzle during delta_calibrate
Speed: 100#*# [delta_calibrate]
#*# height0 = -0.2
#*# height0_pos = 23052.500,23066.000,22937.000
#*# height1 = -0.2
#*# height1_pos = 27015.000,27090.000,20666.000
#*# height2 = -0.2
#*# height2_pos = 22532.500,29248.500,22422.500
#*# height3 = -0.2
#*# height3_pos = 20747.000,26212.500,26131.500
#*# height4 = -0.2
#*# height4_pos = 22366.000,22345.000,27131.500
#*# height5 = -0.2
#*# height5_pos = 25721.500,20936.500,25601.500
#*# height6 = -0.2
#*# height6_pos = 28191.500,22492.000,22328.000
  • 服务启动时,加载配置对象时加载该模块并对其进行初始化处理。
入口
def load_config(config):return DeltaCalibrate(config)
初始化
class DeltaCalibrate:def __init__(self, config):self.printer = config.get_printer()self.printer.register_event_handler("klippy:connect",self.handle_connect)# Calculate default probing pointsradius = config.getfloat('radius', above=0.)points = [(0., 0.)]scatter = [.95, .90, .85, .70, .75, .80]for i in range(6):r = math.radians(90. + 60. * i)dist = radius * scatter[i]points.append((math.cos(r) * dist, math.sin(r) * dist))self.probe_helper = probe.ProbePointsHelper(config, self.probe_finalize, default_points=points)self.probe_helper.minimum_points(3)# Restore probe stable positionsself.last_probe_positions = []for i in range(999):height = config.getfloat("height%d" % (i,), None)if height is None:breakheight_pos = load_config_stable(config, "height%d_pos" % (i,))self.last_probe_positions.append((height, height_pos))# Restore manually entered heightsself.manual_heights = []for i in range(999):height = config.getfloat("manual_height%d" % (i,), None)if height is None:breakheight_pos = load_config_stable(config, "manual_height%d_pos"% (i,))self.manual_heights.append((height, height_pos))# Restore distance measurementsself.delta_analyze_entry = {'SCALE': (1.,)}self.last_distances = []for i in range(999):dist = config.getfloat("distance%d" % (i,), None)if dist is None:breakdistance_pos1 = load_config_stable(config, "distance%d_pos1" % (i,))distance_pos2 = load_config_stable(config, "distance%d_pos2" % (i,))self.last_distances.append((dist, distance_pos1, distance_pos2))# Register gcode commandsself.gcode = self.printer.lookup_object('gcode')self.gcode.register_command('DELTA_CALIBRATE', self.cmd_DELTA_CALIBRATE,desc=self.cmd_DELTA_CALIBRATE_help)self.gcode.register_command('DELTA_ANALYZE', self.cmd_DELTA_ANALYZE,desc=self.cmd_DELTA_ANALYZE_help)
  • 初始化打印机与事件处理

    • 使用 config.get_printer() 方法获取打印机对象 self.printer
    • 注册事件处理程序,当事件 "klippy:connect" 触发时调用 self.handle_connect 方法。
  • 计算默认探针点

    • 使用从配置中获取的 radius 参数,生成默认的探针点坐标。初始点 (0., 0.) 加上基于 scatter 数组的随机分布。
    • 计算的点基于 60° 的角度分布,以生成六个均匀分布的探针点。
    • 创建一个 ProbePointsHelper 对象 self.probe_helper,并将生成的默认探针点 points 传递给它,同时设置最少探针点数为 3。
  • 恢复探针的稳定位置

    • 从配置中加载每个 "height%d" 配置的高度和对应的稳定位置。
    • 将每对 (height, position) 添加到 self.last_probe_positions 列表中。
  • 恢复手动输入的高度

    • 从配置中加载每个 "manual_height%d" 和对应的手动输入位置。
    • 将其存储在 self.manual_heights 列表中。
  • 恢复距离测量

    • 使用键名 "distance%d" 来加载每个测量的距离值和两个位置坐标。
    • 这些距离和位置对被保存在 self.last_distances 列表中。
    • self.delta_analyze_entry 是一个字典,包含默认的缩放值 (1.,),可能用于进一步的分析或调整。
  • 注册 GCode 命令

    • 获取 gcode 对象并注册两条新的 GCode 命令:
    • DELTA_CALIBRATE:指向 cmd_DELTA_CALIBRATE 方法。
    • DELTA_ANALYZE:指向 cmd_DELTA_ANALYZE 方法。
  • 根据半径计算调平时探测的坐标点,该坐标点会在热床调平时使用。

  • 初始化后的DeltaCalibrate对象信息。

delta 热床校准完成代码逻辑
def probe_finalize(self, offsets, positions):# Convert positions into (z_offset, stable_position) pairsz_offset = offsets[2]kin = self.printer.lookup_object('toolhead').get_kinematics()delta_params = kin.get_calibration()probe_positions = [(z_offset, delta_params.calc_stable_position(p))for p in positions]# Perform analysisself.calculate_params(probe_positions, self.last_distances)
def calculate_params(self, probe_positions, distances):height_positions = self.manual_heights + probe_positions# Setup for coordinate descent analysiskin = self.printer.lookup_object('toolhead').get_kinematics()orig_delta_params = odp = kin.get_calibration()adj_params, params = odp.coordinate_descent_params(distances)logging.info("Calculating delta_calibrate with:\n%s\n%s\n""Initial delta_calibrate parameters: %s",height_positions, distances, params)z_weight = 1.if distances:z_weight = len(distances) / (MEASURE_WEIGHT * len(probe_positions))# Perform coordinate descentdef delta_errorfunc(params):try:# Build new delta_params for params under testdelta_params = orig_delta_params.new_calibration(params)getpos = delta_params.get_position_from_stable# Calculate z height errorstotal_error = 0.for z_offset, stable_pos in height_positions:x, y, z = getpos(stable_pos)total_error += (z - z_offset)**2total_error *= z_weight# Calculate distance errorsfor dist, stable_pos1, stable_pos2 in distances:x1, y1, z1 = getpos(stable_pos1)x2, y2, z2 = getpos(stable_pos2)d = math.sqrt((x1-x2)**2 + (y1-y2)**2 + (z1-z2)**2)total_error += (d - dist)**2return total_errorexcept ValueError:return 9999999999999.9new_params = mathutil.background_coordinate_descent(self.printer, adj_params, params, delta_errorfunc)# Log and report resultslogging.info("Calculated delta_calibrate parameters: %s", new_params)new_delta_params = orig_delta_params.new_calibration(new_params)for z_offset, spos in height_positions:logging.info("height orig: %.6f new: %.6f goal: %.6f",orig_delta_params.get_position_from_stable(spos)[2],new_delta_params.get_position_from_stable(spos)[2],z_offset)for dist, spos1, spos2 in distances:x1, y1, z1 = orig_delta_params.get_position_from_stable(spos1)x2, y2, z2 = orig_delta_params.get_position_from_stable(spos2)orig_dist = math.sqrt((x1-x2)**2 + (y1-y2)**2 + (z1-z2)**2)x1, y1, z1 = new_delta_params.get_position_from_stable(spos1)x2, y2, z2 = new_delta_params.get_position_from_stable(spos2)new_dist = math.sqrt((x1-x2)**2 + (y1-y2)**2 + (z1-z2)**2)logging.info("distance orig: %.6f new: %.6f goal: %.6f",orig_dist, new_dist, dist)# Store results for SAVE_CONFIGself.save_state(probe_positions, distances, new_delta_params)self.gcode.respond_info("The SAVE_CONFIG command will update the printer config file\n""with these parameters and restart the printer.")
  • probe_finalize
    • 输入:探针偏移 (offsets) 和探测到的位置信息 (positions)。
    • 操作
      • 将探测位置 (positions) 转换为稳定位置 (stable_position) 和 Z 偏移对。
      • 调用 calculate_params 方法,用探测数据和距离测量来进行参数计算。
  • calculate_params
    • 输入:探测结果 (probe_positions) 和距离测量数据 (distances)。
    • 操作
      • 准备探测和手动高度数据,用于后续分析。
      • 初始化 kinematics(运动学)相关参数,并设置优化目标函数。
      • 使用坐标下降法 (coordinate_descent) 来优化 Delta 几何参数。
      • 打印计算结果并保存新校准参数。
坐标下降法
def background_coordinate_descent(printer, adj_params, params, error_func):parent_conn, child_conn = multiprocessing.Pipe()def wrapper():queuelogger.clear_bg_logging()try:res = coordinate_descent(adj_params, params, error_func)except:child_conn.send((True, traceback.format_exc()))child_conn.close()returnchild_conn.send((False, res))child_conn.close()# Start a process to perform the calculationcalc_proc = multiprocessing.Process(target=wrapper)calc_proc.daemon = Truecalc_proc.start()# Wait for the process to finishreactor = printer.get_reactor()gcode = printer.lookup_object("gcode")eventtime = last_report_time = reactor.monotonic()while calc_proc.is_alive():if eventtime > last_report_time + 5.:last_report_time = eventtimegcode.respond_info("Working on calibration...", log=False)eventtime = reactor.pause(eventtime + .1)# Return resultsis_err, res = parent_conn.recv()if is_err:raise Exception("Error in coordinate descent: %s" % (res,))calc_proc.join()parent_conn.close()return res
  • 多进程初始化
    • multiprocessing.Pipe:
      • 创建父子连接,用于主进程与计算进程之间的数据通信。
    • wrapper 函数:
      • 包装实际的优化函数 coordinate_descent,捕获异常并将结果通过 child_conn 返回。
  • 优化计算的子进程
    • 使用 multiprocessing.Process 创建后台进程运行 wrapper
    • 进程设置为守护进程(daemon=True),确保主程序退出时它会自动终止。
  • 主进程的状态监控与反馈
    • 监控进程状态
      • 每隔 5 秒发送一条用户友好的状态更新,提示校准过程正在进行。
      • 使用 reactor.pause 延迟循环,避免占用 CPU 资源。
while calc_proc.is_alive():if eventtime > last_report_time + 5.:last_report_time = eventtimegcode.respond_info("Working on calibration...", log=False)eventtime = reactor.pause(eventtime + .1)
  • 结果处理
    • 获取优化结果:从子进程接收数据。如果收到错误标志(is_err=True),抛出异常。
is_err, res = parent_conn.recv()
if is_err:raise Exception("Error in coordinate descent: %s" % (res,))
  • 清理资源
    • 确保进程完全退出并关闭管道连接。
calc_proc.join()
parent_conn.close()
  • 返回优化结果
    • 子进程正常结束后,将优化结果返回主进程继续使用。
def coordinate_descent(adj_params, params, error_func):# Define potential changesparams = dict(params)dp = {param_name: 1. for param_name in adj_params}# Calculate the errorbest_err = error_func(params)logging.info("Coordinate descent initial error: %s", best_err)threshold = 0.00001rounds = 0while sum(dp.values()) > threshold and rounds < 10000:rounds += 1for param_name in adj_params:orig = params[param_name]params[param_name] = orig + dp[param_name]err = error_func(params)if err < best_err:# There was some improvementbest_err = errdp[param_name] *= 1.1continueparams[param_name] = orig - dp[param_name]err = error_func(params)if err < best_err:# There was some improvementbest_err = errdp[param_name] *= 1.1continueparams[param_name] = origdp[param_name] *= 0.9logging.info("Coordinate descent best_err: %s  rounds: %d",best_err, rounds)return params
  • 多轮循环,达到坐标下降优化
def delta_errorfunc(params):try:# Build new delta_params for params under testdelta_params = orig_delta_params.new_calibration(params)getpos = delta_params.get_position_from_stable# Calculate z height errorstotal_error = 0.for z_offset, stable_pos in height_positions:x, y, z = getpos(stable_pos)total_error += (z - z_offset)**2total_error *= z_weight# Calculate distance errorsfor dist, stable_pos1, stable_pos2 in distances:x1, y1, z1 = getpos(stable_pos1)x2, y2, z2 = getpos(stable_pos2)d = math.sqrt((x1-x2)**2 + (y1-y2)**2 + (z1-z2)**2)total_error += (d - dist)**2return total_errorexcept ValueError:return 9999999999999.9
  • 计算距离误差
http://www.lryc.cn/news/624391.html

相关文章:

  • Read View 在 MVCC 里如何工作的?
  • 《C++异常处理完全指南》
  • 如何在 Ubuntu 24.04 或 22.04 LTS 上安装 PowerShell
  • Spring Boot 实用小技巧:多级缓存(Caffeine + Redis)- 第545篇
  • 【网络安全实验报告】实验四: PGP邮件加密软件应用
  • C++STL之list详解
  • 【Linux指南】gcc/g++编译器:从源码到可执行文件的全流程解析
  • 8.18 机器学习-决策树(1)
  • goland怎么取消自动删除未使用的包
  • SWMM排水管网水力、水质建模及在海绵与水环境中的应用技术-模拟降雨和污染物质经过地面、排水管网、蓄水和处理
  • 【前端面试题】JavaScript 核心知识点解析(第一题到第三十题)
  • 2025 世界机器人大会启示录:机构学 × AI × 视频链路的融合之路
  • 从零开始部署经典开源项目管理系统最新版redmine6-Linux Debian12
  • 粉刷房子(简单多状态dp问题)
  • 场外期权的股票停牌了怎么处理?
  • 226. 翻转二叉树
  • 《Unity Shader入门精要》学习笔记二
  • IOPaint 远程修图:cpolar 内网穿透服务实现跨设备图片编辑
  • 旧物回收小程序的商业变现路径探索
  • LeetCode 刷题【45. 跳跃游戏 II】
  • nuScence数据集
  • AI应用商业化加速落地 2025智能体爆发与端侧创新成增长引擎
  • 【2025CVPR-目标检测方向】RaCFormer:通过基于查询的雷达-相机融合实现高质量的 3D 目标检测
  • 机器学习(决策树)
  • 【音视频】瑞芯微、全志芯片在运动相机和行车记录仪产品分析
  • 从决策树基础到熵与信息增益
  • 机器学习的多种算法
  • 常见的光源频闪控制方式
  • 20. 云计算-Service MeshServerless
  • 用本地代理 + ZIP 打包 + Excel 命名,优雅批量下载跨域 PDF