From a4457c3d04cf878f57b1a878b65010112ddf7430 Mon Sep 17 00:00:00 2001 From: HelgeKeck Date: Sun, 1 Dec 2024 22:01:10 +0100 Subject: [PATCH 01/17] PLUGIN: gantry twist mesh creation --- configuration/klippy/ratos.py | 109 ++++++++++++++++++++++++- configuration/z-probe/beacon.cfg | 136 +++++++++++++++++++++++++++++-- 2 files changed, 237 insertions(+), 8 deletions(-) diff --git a/configuration/klippy/ratos.py b/configuration/klippy/ratos.py index f105a71d1..37e41075e 100644 --- a/configuration/klippy/ratos.py +++ b/configuration/klippy/ratos.py @@ -1,4 +1,4 @@ -import os, logging, re, glob +import os, logging, re, glob, math import logging, collections, pathlib import json, asyncio, subprocess from . import bed_mesh as BedMesh @@ -33,6 +33,8 @@ def __init__(self, config): self.old_is_graph_files = [] self.contact_mesh = None + self.gantry_mesh = None + self.gantry_mesh_points = [] self.pmgr = BedMeshProfileManager(self.config, self) self.load_settings() @@ -76,6 +78,9 @@ def register_commands(self): self.gcode.register_command('RATOS_LOG', self.cmd_RATOS_LOG, desc=(self.desc_RATOS_LOG)) self.gcode.register_command('PROCESS_GCODE_FILE', self.cmd_PROCESS_GCODE_FILE, desc=(self.desc_PROCESS_GCODE_FILE)) self.gcode.register_command('BEACON_APPLY_SCAN_COMPENSATION', self.cmd_BEACON_APPLY_SCAN_COMPENSATION, desc=(self.desc_BEACON_APPLY_SCAN_COMPENSATION)) + self.gcode.register_command('RESET_GANTRY_TWIST_MESH', self.cmd_RESET_GANTRY_TWIST_MESH, desc=(self.desc_RESET_GANTRY_TWIST_MESH)) + self.gcode.register_command('ADD_GANTRY_TWIST_MESH_VALUE', self.cmd_ADD_GANTRY_TWIST_MESH_VALUE, desc=(self.desc_ADD_GANTRY_TWIST_MESH_VALUE)) + self.gcode.register_command('SET_GANTRY_TWIST_MESH', self.cmd_SET_GANTRY_TWIST_MESH, desc=(self.desc_SET_GANTRY_TWIST_MESH)) self.gcode.register_command('TEST_PROCESS_GCODE_FILE', self.cmd_TEST_PROCESS_GCODE_FILE, desc=(self.desc_TEST_PROCESS_GCODE_FILE)) desc_TEST_PROCESS_GCODE_FILE = "Test the G-code post-processor for IDEX and RMMU, only for debugging purposes" @@ -166,6 +171,29 @@ def cmd_BEACON_APPLY_SCAN_COMPENSATION(self, gcmd): raise self.printer.command_error("Could not load profile " + str(profile) + " for Beacon scan compensation") self.compensate_beacon_scan(profile) + desc_RESET_GANTRY_TWIST_MESH = "Resets a gantry twist mesh and sets all values to 0." + def cmd_RESET_GANTRY_TWIST_MESH(self, gcmd): + profile = gcmd.get('PROFILE', "Gantry") + if not profile.strip(): + raise gcmd.error("Value for parameter 'PROFILE' must be specified") + if profile not in self.pmgr.get_profiles(): + raise self.printer.command_error("Profile " + str(profile) + " not found for reset gantry twist mesh") + # self.gantry_mesh = self.pmgr.save_profile(profile) + self.gantry_mesh = self.pmgr.load_profile(profile) + if not self.gantry_mesh: + raise self.printer.command_error("Could not load profile " + str(profile) + " for reset gantry twist mesh") + self.reset_gantry_twist_mesh(profile) + + desc_ADD_GANTRY_TWIST_MESH_VALUE = "Adds a new value to the gantry twist mesh cache." + def cmd_ADD_GANTRY_TWIST_MESH_VALUE(self, gcmd): + value = gcmd.get_float('VALUE', None) + self.gantry_mesh_points.append(value) + + desc_SET_GANTRY_TWIST_MESH = "Sets the gantry twist cache to the gantry twist mesh." + def cmd_SET_GANTRY_TWIST_MESH(self, gcmd): + profile = gcmd.get('PROFILE', "Gantry") + self.set_gantry_twist_mesh(profile) + ##### # Beacon Scan Compensation ##### @@ -196,6 +224,48 @@ def compensate_beacon_scan(self, profile): except BedMesh.BedMeshError as e: self.console_echo("Beacon scan compensation error", "error", str(e)) + def reset_gantry_twist_mesh(self, profile): + self.gantry_mesh_points = [] + systime = self.reactor.monotonic() + try: + if self.bed_mesh.z_mesh: + profile_name = self.bed_mesh.z_mesh.get_profile_name() + if profile_name == profile: + points = self.bed_mesh.get_status(systime)["profiles"][profile_name]["points"] + new_points = [] + for y in range(len(points)): + new_points.append([]) + for x in range(len(points[0])): + new_points[y].append(0) + self.bed_mesh.z_mesh.build_mesh(new_points) + self.bed_mesh.save_profile(profile_name) + self.bed_mesh.set_mesh(self.bed_mesh.z_mesh) + self.console_echo("Reset gantry twist mesh", "debug", "Gantry twist profile %s resetted %s" % (str(profile_name), str(profile))) + except BedMesh.BedMeshError as e: + self.console_echo("Reset gantry twist mesh error", "error", str(e)) + + def set_gantry_twist_mesh(self, profile): + systime = self.reactor.monotonic() + try: + if self.bed_mesh.z_mesh: + profile_name = self.bed_mesh.z_mesh.get_profile_name() + if profile_name == profile: + points = self.bed_mesh.get_status(systime)["profiles"][profile_name]["points"] + index = 0 + new_points = [] + for y in range(len(points)): + new_points.append([]) + for x in range(len(points[0])): + new_points[y].append(self.gantry_mesh_points[index]) + index = index + 1 + self.bed_mesh.z_mesh.build_mesh(new_points) + self.bed_mesh.save_profile(profile_name) + self.bed_mesh.set_mesh(self.bed_mesh.z_mesh) + else: + raise self.printer.command_error("Wrong profile loaded " + str(profile) + " for add gantry twist mesh value") + except BedMesh.BedMeshError as e: + self.console_echo("Reset gantry twist mesh error", "error", str(e)) + def process_gcode_file(self, filename, enable_post_processing): try: [path, size] = self.get_gcode_file_info(filename) @@ -336,7 +406,6 @@ def _process_output(eventtime): raise return False - def get_gcode_file_info(self, filename): files = self.v_sd.get_file_list(True) flist = [f[0] for f in files] @@ -418,6 +487,7 @@ def get_status(self, eventtime): ##### # Bed Mesh Profile Manager ##### +PROFILE_VERSION = 1 class BedMeshProfileManager: def __init__(self, config, bedmesh): self.name = "bed_mesh" @@ -466,6 +536,41 @@ def load_profile(self, prof_name): except BedMesh.BedMeshError as e: raise self.gcode.error(str(e)) return z_mesh + # def save_profile(self, prof_name): + # z_mesh = self.bedmesh.get_mesh() + # if z_mesh is None: + # self.gcode.respond_info( + # "Unable to save to profile [%s], the bed has not been probed" + # % (prof_name)) + # return + # probed_matrix = z_mesh.get_probed_matrix() + # mesh_params = z_mesh.get_mesh_params() + # configfile = self.printer.lookup_object('configfile') + # cfg_name = self.name + " " + prof_name + # # set params + # z_values = "" + # for line in probed_matrix: + # z_values += "\n " + # for p in line: + # z_values += "%.6f, " % p + # z_values = z_values[:-2] + # configfile.set(cfg_name, 'version', PROFILE_VERSION) + # configfile.set(cfg_name, 'points', z_values) + # for key, value in mesh_params.items(): + # configfile.set(cfg_name, key, value) + # # save copy in local storage + # # ensure any self.profiles returned as status remains immutable + # profiles = dict(self.profiles) + # profiles[prof_name] = profile = {} + # profile['points'] = probed_matrix + # profile['mesh_params'] = collections.OrderedDict(mesh_params) + # self.profiles = profiles + # self.bedmesh.update_status() + # self.gcode.respond_info( + # "Bed Mesh state has been saved to profile [%s]\n" + # "for the current session. The SAVE_CONFIG command will\n" + # "update the printer config file and restart the printer." + # % (prof_name)) ##### # Loader diff --git a/configuration/z-probe/beacon.cfg b/configuration/z-probe/beacon.cfg index 7d7eaf3ea..64d175fbb 100644 --- a/configuration/z-probe/beacon.cfg +++ b/configuration/z-probe/beacon.cfg @@ -47,7 +47,7 @@ variable_beacon_contact_z_tilt_adjust_samples: 2 # probe samples for cont variable_beacon_scan_compensation_enable: False # Enables the beacon scan compensation variable_beacon_scan_compensation_profile: "Contact" # The contact profile name for the scan compensation -variable_beacon_scan_compensation_probe_count: 15,15 # The contact probe count for the scan compensation +variable_beacon_scan_compensation_resolution: 40 # The mesh resolution in mm for the scan compensation variable_beacon_contact_poke_bottom_limit: -1 # The bottom limit for the contact poke test @@ -735,9 +735,6 @@ gcode: # parameters {% set location = params.LOCATION|lower %} - # config - {% set default_toolhead = printer["gcode_macro RatOS"].default_toolhead|default(0)|int %} - # get last probe result {% set last_z = printer.beacon.last_offset_result["delta"]|default(0)|float %} @@ -812,9 +809,22 @@ gcode: # config {% set default_toolhead = printer["gcode_macro RatOS"].default_toolhead|default(0)|int %} {% set beacon_scan_compensation_enable = true if printer["gcode_macro RatOS"].beacon_scan_compensation_enable|default(false)|lower == 'true' else false %} - {% set probe_count = printer["gcode_macro RatOS"].beacon_scan_compensation_probe_count %} + {% set mesh_resolution = printer["gcode_macro RatOS"].beacon_scan_compensation_resolution|float %} {% set bed_heat_soak_time = printer["gcode_macro RatOS"].bed_heat_soak_time|default(0)|int %} + # get bed mesh config object + {% set mesh_config = printer.configfile.config.bed_mesh %} + + # get configured bed mesh area + {% set min_x = mesh_config.mesh_min.split(",")[0]|float %} + {% set min_y = mesh_config.mesh_min.split(",")[1]|float %} + {% set max_x = mesh_config.mesh_max.split(",")[0]|float %} + {% set max_y = mesh_config.mesh_max.split(",")[1]|float %} + + # calculate probe counts + {% set probe_count_x = ((max_x - min_x) / mesh_resolution + 1)|int %} + {% set probe_count_y = ((max_y - min_y) / mesh_resolution + 1)|int %} + {% if not beacon_scan_compensation_enable %} RATOS_ECHO MSG="Beacon scan compensation is disabled!" @@ -875,7 +885,7 @@ gcode: BEACON_AUTO_CALIBRATE SKIP_MODEL_CREATION=1 # create contact mesh - BED_MESH_CALIBRATE PROBE_METHOD=contact USE_CONTACT_AREA=1 SAMPLES=2 SAMPLES_DROP=1 SAMPLES_TOLERANCE_RETRIES=10 PROBE_COUNT={probe_count[0]},{probe_count[1]} PROFILE={profile} + BED_MESH_CALIBRATE PROBE_METHOD=contact USE_CONTACT_AREA=1 SAMPLES=2 SAMPLES_DROP=1 SAMPLES_TOLERANCE_RETRIES=10 PROBE_COUNT={probe_count_x},{probe_count_y} PROFILE={profile} # turn bed and extruder heaters off {% if not automated %} @@ -888,6 +898,9 @@ gcode: _CHAMBER_HEATER_OFF {% endif %} + # Go to safe home + _MOVE_TO_SAFE_Z_HOME Z_HOP=True + # home z BEACON_AUTO_CALIBRATE SKIP_MODEL_CREATION=1 @@ -935,6 +948,117 @@ gcode: {% endif %} +##### +# BEACON GANTRY TWIST COMPENSATION +##### +[gcode_macro _COPY_CONTACT_MESH] +gcode: + # load contact mesh + BED_MESH_PROFILE LOAD="Contact" + + # save contact mesh as gantry mesh + BED_MESH_PROFILE REMOVE="Gantry" + BED_MESH_PROFILE SAVE="Gantry" + + # save config to make the gantry mesh accessible through the bed mesh manager in klipper + SAVE_CONFIG + + +[gcode_macro BEACON_CREATE_GANTRY_TWIST_COMPENSATION_MESH] +variable_reference_z: 0.0 +gcode: + # config + {% set speed = printer["gcode_macro RatOS"].macro_travel_speed|float * 60 %} + + # beacon config + {% set poke_bottom = printer["gcode_macro RatOS"].beacon_contact_poke_bottom_limit|default(-1)|float %} + {% set beacon_contact_start_print_true_zero = true if printer["gcode_macro RatOS"].beacon_contact_start_print_true_zero|default(false)|lower == 'true' else false %} + {% set mesh_resolution = printer["gcode_macro RatOS"].beacon_scan_compensation_resolution|float %} + + # get bed mesh config object + {% set mesh_config = printer.configfile.config.bed_mesh %} + + # get configured bed mesh area + {% set min_x = mesh_config.mesh_min.split(",")[0]|float %} + {% set min_y = mesh_config.mesh_min.split(",")[1]|float %} + {% set max_x = mesh_config.mesh_max.split(",")[0]|float %} + {% set max_y = mesh_config.mesh_max.split(",")[1]|float %} + + # calculate probe counts and distances + {% set probe_count_x = ((max_x - min_x) / mesh_resolution + 1)|int %} + {% set probe_count_y = ((max_y - min_y) / mesh_resolution + 1)|int %} + {% set probe_dist_x = ((max_x - min_x) / probe_count_x)|float %} + {% set probe_dist_y = ((max_y - min_y) / probe_count_y)|float %} + + DEBUG_ECHO PREFIX="BEACON_CREATE_GANTRY_TWIST_COMPENSATION_MESH" MSG="mesh_resolution: {mesh_resolution}mm, mesh_min: [{min_x},{min_y}], mesh_max: [{max_x},{max_y}], probe_count: [{probe_count_x},{probe_count_y}], probe_dist: [{probe_dist_x},{probe_dist_y}]" + + {% if beacon_contact_start_print_true_zero %} + + # load gantry mesh + BED_MESH_PROFILE LOAD="Gantry" + + # reset gantry mesh values to 0 + RESET_GANTRY_TWIST_MESH PROFILE="Gantry" + + # home and abl the printer if needed + _BEACON_HOME_AND_ABL + + # visual feedback + _LED_BEACON_CALIBRATION_START + + # echo + RATOS_ECHO PREFIX="BEACON" MSG="Measure gantry twist..." + + # settle the mechanics down + {% for i in range(10) %} + beacon_poke speed=3 top=5 bottom={poke_bottom} + {% endfor %} + + # probe reference location + _BEACON_PROBE_GANTRY_TWIST + _BEACON_STORE_GANTRY_TWIST_TO_MESH LOCATION="center" + + # create gantry twist mesh + {% for y in range(probe_count_y) %} + {% set y_pos = min_y + y * probe_dist_y %} + {% for x in range(probe_count_x) %} + {% set x_pos = min_x + x * probe_dist_x %} + DEBUG_ECHO PREFIX="xx" MSG="measure gantry twist at: {x_pos},{y_pos}" + G0 X{x_pos} Y{y_pos} F{speed} + _BEACON_PROBE_GANTRY_TWIST + _BEACON_STORE_GANTRY_TWIST_TO_MESH + {% endfor %} + {% endfor %} + + # save gantry twist values to the gantry twist mesh + SET_GANTRY_TWIST_MESH + + # move back to home position + _MOVE_TO_SAFE_Z_HOME Z_HOP=True + + # visual feedback + _LED_BEACON_CALIBRATION_END + + # save config + SAVE_CONFIG + + {% endif %} + + +[gcode_macro _BEACON_STORE_GANTRY_TWIST_TO_MESH] +gcode: + # get last probe result + {% set last_z = printer.beacon.last_offset_result["delta"]|default(0)|float %} + + # set gantry offset + {% if params.LOCATION is defined %} + SET_GCODE_VARIABLE MACRO=BEACON_CREATE_GANTRY_TWIST_COMPENSATION_MESH VARIABLE=reference_z VALUE={last_z} + {% else %} + {% set reference_z = printer["gcode_macro BEACON_CREATE_GANTRY_TWIST_COMPENSATION_MESH"].reference_z|default(0)|float %} + ADD_GANTRY_TWIST_MESH_VALUE X={x} Y={y} VALUE={(last_z - reference_z)} + {% endif %} + + ##### # BEACON UTILS ##### From 752cbeec787db2844357c4b6987acdb32d90cdf5 Mon Sep 17 00:00:00 2001 From: HelgeKeck Date: Mon, 2 Dec 2024 07:58:47 +0100 Subject: [PATCH 02/17] fix beacon scan compensation calculation --- configuration/klippy/ratos.py | 83 ++++----------- configuration/z-probe/beacon.cfg | 175 +++++++++++++++---------------- 2 files changed, 103 insertions(+), 155 deletions(-) diff --git a/configuration/klippy/ratos.py b/configuration/klippy/ratos.py index 37e41075e..a4208b361 100644 --- a/configuration/klippy/ratos.py +++ b/configuration/klippy/ratos.py @@ -32,9 +32,8 @@ def __init__(self, config): self.reactor = self.printer.get_reactor() self.old_is_graph_files = [] - self.contact_mesh = None - self.gantry_mesh = None - self.gantry_mesh_points = [] + self.offset_mesh = None + self.offset_mesh_points = [[]] self.pmgr = BedMeshProfileManager(self.config, self) self.load_settings() @@ -78,9 +77,8 @@ def register_commands(self): self.gcode.register_command('RATOS_LOG', self.cmd_RATOS_LOG, desc=(self.desc_RATOS_LOG)) self.gcode.register_command('PROCESS_GCODE_FILE', self.cmd_PROCESS_GCODE_FILE, desc=(self.desc_PROCESS_GCODE_FILE)) self.gcode.register_command('BEACON_APPLY_SCAN_COMPENSATION', self.cmd_BEACON_APPLY_SCAN_COMPENSATION, desc=(self.desc_BEACON_APPLY_SCAN_COMPENSATION)) - self.gcode.register_command('RESET_GANTRY_TWIST_MESH', self.cmd_RESET_GANTRY_TWIST_MESH, desc=(self.desc_RESET_GANTRY_TWIST_MESH)) - self.gcode.register_command('ADD_GANTRY_TWIST_MESH_VALUE', self.cmd_ADD_GANTRY_TWIST_MESH_VALUE, desc=(self.desc_ADD_GANTRY_TWIST_MESH_VALUE)) - self.gcode.register_command('SET_GANTRY_TWIST_MESH', self.cmd_SET_GANTRY_TWIST_MESH, desc=(self.desc_SET_GANTRY_TWIST_MESH)) + self.gcode.register_command('CACHE_BEACON_OFFSET_MESH_VALUE', self.cmd_CACHE_BEACON_OFFSET_MESH_VALUE, desc=(self.desc_CACHE_BEACON_OFFSET_MESH_VALUE)) + self.gcode.register_command('SET_BEACON_OFFSET_MESH', self.cmd_SET_BEACON_OFFSET_MESH, desc=(self.desc_SET_BEACON_OFFSET_MESH)) self.gcode.register_command('TEST_PROCESS_GCODE_FILE', self.cmd_TEST_PROCESS_GCODE_FILE, desc=(self.desc_TEST_PROCESS_GCODE_FILE)) desc_TEST_PROCESS_GCODE_FILE = "Test the G-code post-processor for IDEX and RMMU, only for debugging purposes" @@ -161,38 +159,28 @@ def cmd_PROCESS_GCODE_FILE(self, gcmd): desc_BEACON_APPLY_SCAN_COMPENSATION = "Compensates magnetic inaccuracies for beacon scan meshes." def cmd_BEACON_APPLY_SCAN_COMPENSATION(self, gcmd): - profile = gcmd.get('PROFILE', "Contact") + profile = gcmd.get('PROFILE', "Offset") if not profile.strip(): raise gcmd.error("Value for parameter 'PROFILE' must be specified") if profile not in self.pmgr.get_profiles(): raise self.printer.command_error("Profile " + str(profile) + " not found for Beacon scan compensation") - self.contact_mesh = self.pmgr.load_profile(profile) - if not self.contact_mesh: + self.offset_mesh = self.pmgr.load_profile(profile) + if not self.offset_mesh: raise self.printer.command_error("Could not load profile " + str(profile) + " for Beacon scan compensation") self.compensate_beacon_scan(profile) - desc_RESET_GANTRY_TWIST_MESH = "Resets a gantry twist mesh and sets all values to 0." - def cmd_RESET_GANTRY_TWIST_MESH(self, gcmd): - profile = gcmd.get('PROFILE', "Gantry") - if not profile.strip(): - raise gcmd.error("Value for parameter 'PROFILE' must be specified") - if profile not in self.pmgr.get_profiles(): - raise self.printer.command_error("Profile " + str(profile) + " not found for reset gantry twist mesh") - # self.gantry_mesh = self.pmgr.save_profile(profile) - self.gantry_mesh = self.pmgr.load_profile(profile) - if not self.gantry_mesh: - raise self.printer.command_error("Could not load profile " + str(profile) + " for reset gantry twist mesh") - self.reset_gantry_twist_mesh(profile) - - desc_ADD_GANTRY_TWIST_MESH_VALUE = "Adds a new value to the gantry twist mesh cache." - def cmd_ADD_GANTRY_TWIST_MESH_VALUE(self, gcmd): + desc_CACHE_BEACON_OFFSET_MESH_VALUE = "Adds a new value to the gantry twist mesh cache." + def cmd_CACHE_BEACON_OFFSET_MESH_VALUE(self, gcmd): + y = gcmd.get_int('Y', 0) value = gcmd.get_float('VALUE', None) - self.gantry_mesh_points.append(value) + if len(self.offset_mesh_points) < y + 1: + self.offset_mesh_points.append([]) + self.offset_mesh_points[y].append(value) - desc_SET_GANTRY_TWIST_MESH = "Sets the gantry twist cache to the gantry twist mesh." - def cmd_SET_GANTRY_TWIST_MESH(self, gcmd): - profile = gcmd.get('PROFILE', "Gantry") - self.set_gantry_twist_mesh(profile) + desc_SET_BEACON_OFFSET_MESH = "Sets the gantry twist cache to the gantry twist mesh." + def cmd_SET_BEACON_OFFSET_MESH(self, gcmd): + profile = gcmd.get('PROFILE', "Offset") + self.set_beacon_offset_mesh(profile) ##### # Beacon Scan Compensation @@ -214,8 +202,8 @@ def compensate_beacon_scan(self, profile): x_pos = params["min_x"] + x * x_step y_pos = params["min_y"] + y * y_step z_val = points[y][x] - contact_z = self.contact_mesh.calc_z(x_pos, y_pos) - new_z = z_val - (z_val - contact_z) + beacon_offset = self.offset_mesh.calc_z(x_pos, y_pos) + new_z = z_val - beacon_offset new_points[y].append(new_z) self.bed_mesh.z_mesh.build_mesh(new_points) self.bed_mesh.save_profile(profile_name) @@ -224,41 +212,12 @@ def compensate_beacon_scan(self, profile): except BedMesh.BedMeshError as e: self.console_echo("Beacon scan compensation error", "error", str(e)) - def reset_gantry_twist_mesh(self, profile): - self.gantry_mesh_points = [] - systime = self.reactor.monotonic() - try: - if self.bed_mesh.z_mesh: - profile_name = self.bed_mesh.z_mesh.get_profile_name() - if profile_name == profile: - points = self.bed_mesh.get_status(systime)["profiles"][profile_name]["points"] - new_points = [] - for y in range(len(points)): - new_points.append([]) - for x in range(len(points[0])): - new_points[y].append(0) - self.bed_mesh.z_mesh.build_mesh(new_points) - self.bed_mesh.save_profile(profile_name) - self.bed_mesh.set_mesh(self.bed_mesh.z_mesh) - self.console_echo("Reset gantry twist mesh", "debug", "Gantry twist profile %s resetted %s" % (str(profile_name), str(profile))) - except BedMesh.BedMeshError as e: - self.console_echo("Reset gantry twist mesh error", "error", str(e)) - - def set_gantry_twist_mesh(self, profile): - systime = self.reactor.monotonic() + def set_beacon_offset_mesh(self, profile): try: if self.bed_mesh.z_mesh: profile_name = self.bed_mesh.z_mesh.get_profile_name() if profile_name == profile: - points = self.bed_mesh.get_status(systime)["profiles"][profile_name]["points"] - index = 0 - new_points = [] - for y in range(len(points)): - new_points.append([]) - for x in range(len(points[0])): - new_points[y].append(self.gantry_mesh_points[index]) - index = index + 1 - self.bed_mesh.z_mesh.build_mesh(new_points) + self.bed_mesh.z_mesh.build_mesh(self.offset_mesh_points) self.bed_mesh.save_profile(profile_name) self.bed_mesh.set_mesh(self.bed_mesh.z_mesh) else: diff --git a/configuration/z-probe/beacon.cfg b/configuration/z-probe/beacon.cfg index 64d175fbb..139022b76 100644 --- a/configuration/z-probe/beacon.cfg +++ b/configuration/z-probe/beacon.cfg @@ -46,7 +46,7 @@ variable_beacon_contact_z_tilt_adjust: False # z-tilt adjust with con variable_beacon_contact_z_tilt_adjust_samples: 2 # probe samples for contact z-tilt adjust variable_beacon_scan_compensation_enable: False # Enables the beacon scan compensation -variable_beacon_scan_compensation_profile: "Contact" # The contact profile name for the scan compensation +variable_beacon_scan_compensation_profile: "Offset" # The beacon offset profile name for the scan compensation variable_beacon_scan_compensation_resolution: 40 # The mesh resolution in mm for the scan compensation variable_beacon_contact_poke_bottom_limit: -1 # The bottom limit for the contact poke test @@ -119,7 +119,7 @@ gcode: # scan calibration {% if beacon_contact_start_print_true_zero %} - BEACON_MEASURE_GANTRY_TWIST + BEACON_MEASURE_BEACON_OFFSET _BEACON_MAYBE_SCAN_COMPENSATION {% endif %} @@ -612,9 +612,9 @@ gcode: ##### -# BEACON MEASURE GANTRY TWIST +# BEACON MEASURE BEACON OFFSET ##### -[gcode_macro BEACON_MEASURE_GANTRY_TWIST] +[gcode_macro BEACON_MEASURE_BEACON_OFFSET] variable_needs_compensation: False variable_reference_z: 0.0 variable_front: 0.0 @@ -648,7 +648,7 @@ gcode: {% if beacon_contact_start_print_true_zero %} # reset varaible - SET_GCODE_VARIABLE MACRO=BEACON_MEASURE_GANTRY_TWIST VARIABLE=needs_compensation VALUE=False + SET_GCODE_VARIABLE MACRO=BEACON_MEASURE_BEACON_OFFSET VARIABLE=needs_compensation VALUE=False # home and abl the printer if needed _BEACON_HOME_AND_ABL @@ -657,7 +657,7 @@ gcode: _LED_BEACON_CALIBRATION_START # echo - RATOS_ECHO PREFIX="BEACON" MSG="Measure gantry twist..." + RATOS_ECHO PREFIX="BEACON" MSG="Measure beacon offset..." # settle the mechanics down {% for i in range(10) %} @@ -665,54 +665,54 @@ gcode: {% endfor %} # probe reference location - _BEACON_PROBE_GANTRY_TWIST - _BEACON_STORE_GANTRY_TWIST LOCATION="center" + _BEACON_OFFSET_COMPARE + _BEACON_STORE_BEACON_OFFSET LOCATION="center" # probe front left G0 X{margin_x} Y{margin_y} F{speed} - _BEACON_PROBE_GANTRY_TWIST - _BEACON_STORE_GANTRY_TWIST LOCATION="front_left" + _BEACON_OFFSET_COMPARE + _BEACON_STORE_BEACON_OFFSET LOCATION="front_left" # probe front G0 X{safe_home_x} Y{margin_y} F{speed} - _BEACON_PROBE_GANTRY_TWIST - _BEACON_STORE_GANTRY_TWIST LOCATION="front" + _BEACON_OFFSET_COMPARE + _BEACON_STORE_BEACON_OFFSET LOCATION="front" # probe front right G0 X{(printable_x_max - margin_x)} Y{margin_y} F{speed} - _BEACON_PROBE_GANTRY_TWIST - _BEACON_STORE_GANTRY_TWIST LOCATION="front_right" + _BEACON_OFFSET_COMPARE + _BEACON_STORE_BEACON_OFFSET LOCATION="front_right" # probe right G0 X{(printable_x_max - margin_x)} Y{safe_home_y} F{speed} - _BEACON_PROBE_GANTRY_TWIST - _BEACON_STORE_GANTRY_TWIST LOCATION="right" + _BEACON_OFFSET_COMPARE + _BEACON_STORE_BEACON_OFFSET LOCATION="right" # probe back right G0 X{(printable_x_max - margin_x)} Y{(printable_y_max - margin_y)} F{speed} - _BEACON_PROBE_GANTRY_TWIST - _BEACON_STORE_GANTRY_TWIST LOCATION="back_right" + _BEACON_OFFSET_COMPARE + _BEACON_STORE_BEACON_OFFSET LOCATION="back_right" # probe back G0 X{safe_home_x} Y{(printable_y_max - margin_y)} F{speed} - _BEACON_PROBE_GANTRY_TWIST - _BEACON_STORE_GANTRY_TWIST LOCATION="back" + _BEACON_OFFSET_COMPARE + _BEACON_STORE_BEACON_OFFSET LOCATION="back" # probe back left G0 X{margin_x} Y{(printable_y_max - margin_y)} F{speed} - _BEACON_PROBE_GANTRY_TWIST - _BEACON_STORE_GANTRY_TWIST LOCATION="back_left" + _BEACON_OFFSET_COMPARE + _BEACON_STORE_BEACON_OFFSET LOCATION="back_left" # probe left G0 X{margin_x} Y{safe_home_y} F{speed} - _BEACON_PROBE_GANTRY_TWIST - _BEACON_STORE_GANTRY_TWIST LOCATION="left" + _BEACON_OFFSET_COMPARE + _BEACON_STORE_BEACON_OFFSET LOCATION="left" # move back to home position _MOVE_TO_SAFE_Z_HOME Z_HOP=True # echo results - _BEACON_ECHO_GANTRY_TWIST + _BEACON_ECHO_BEACON_OFFSET # visual feedback _LED_BEACON_CALIBRATION_END @@ -720,17 +720,7 @@ gcode: {% endif %} -[gcode_macro _BEACON_PROBE_GANTRY_TWIST] -gcode: - # echo - RATOS_ECHO PREFIX="BEACON" MSG="Probing..." - - # probe - BEACON_OFFSET_COMPARE - BEACON_QUERY - - -[gcode_macro _BEACON_STORE_GANTRY_TWIST] +[gcode_macro _BEACON_STORE_BEACON_OFFSET] gcode: # parameters {% set location = params.LOCATION|lower %} @@ -740,25 +730,25 @@ gcode: # set gantry offset {% if location == "center" %} - SET_GCODE_VARIABLE MACRO=BEACON_MEASURE_GANTRY_TWIST VARIABLE=reference_z VALUE={last_z} + SET_GCODE_VARIABLE MACRO=BEACON_MEASURE_BEACON_OFFSET VARIABLE=reference_z VALUE={last_z} {% else %} - {% set reference_z = printer["gcode_macro BEACON_MEASURE_GANTRY_TWIST"].reference_z|default(0)|float %} - SET_GCODE_VARIABLE MACRO=BEACON_MEASURE_GANTRY_TWIST VARIABLE={location} VALUE={(last_z - reference_z)} + {% set reference_z = printer["gcode_macro BEACON_MEASURE_BEACON_OFFSET"].reference_z|default(0)|float %} + SET_GCODE_VARIABLE MACRO=BEACON_MEASURE_BEACON_OFFSET VARIABLE={location} VALUE={(last_z - reference_z)} {% endif %} -[gcode_macro _BEACON_ECHO_GANTRY_TWIST] +[gcode_macro _BEACON_ECHO_BEACON_OFFSET] gcode: # get results - {% set reference_z = printer["gcode_macro BEACON_MEASURE_GANTRY_TWIST"].reference_z|default(0)|float * 1000 %} - {% set front_left = printer["gcode_macro BEACON_MEASURE_GANTRY_TWIST"].front_left|default(0)|float * 1000 %} - {% set front = printer["gcode_macro BEACON_MEASURE_GANTRY_TWIST"].front|default(0)|float * 1000 %} - {% set front_right = printer["gcode_macro BEACON_MEASURE_GANTRY_TWIST"].front_right|default(0)|float * 1000 %} - {% set right = printer["gcode_macro BEACON_MEASURE_GANTRY_TWIST"].right|default(0)|float * 1000 %} - {% set back_right = printer["gcode_macro BEACON_MEASURE_GANTRY_TWIST"].back_right|default(0)|float * 1000 %} - {% set back = printer["gcode_macro BEACON_MEASURE_GANTRY_TWIST"].back|default(0)|float * 1000 %} - {% set back_left = printer["gcode_macro BEACON_MEASURE_GANTRY_TWIST"].back_left|default(0)|float * 1000 %} - {% set left = printer["gcode_macro BEACON_MEASURE_GANTRY_TWIST"].left|default(0)|float * 1000 %} + {% set reference_z = printer["gcode_macro BEACON_MEASURE_BEACON_OFFSET"].reference_z|default(0)|float * 1000 %} + {% set front_left = printer["gcode_macro BEACON_MEASURE_BEACON_OFFSET"].front_left|default(0)|float * 1000 %} + {% set front = printer["gcode_macro BEACON_MEASURE_BEACON_OFFSET"].front|default(0)|float * 1000 %} + {% set front_right = printer["gcode_macro BEACON_MEASURE_BEACON_OFFSET"].front_right|default(0)|float * 1000 %} + {% set right = printer["gcode_macro BEACON_MEASURE_BEACON_OFFSET"].right|default(0)|float * 1000 %} + {% set back_right = printer["gcode_macro BEACON_MEASURE_BEACON_OFFSET"].back_right|default(0)|float * 1000 %} + {% set back = printer["gcode_macro BEACON_MEASURE_BEACON_OFFSET"].back|default(0)|float * 1000 %} + {% set back_left = printer["gcode_macro BEACON_MEASURE_BEACON_OFFSET"].back_left|default(0)|float * 1000 %} + {% set left = printer["gcode_macro BEACON_MEASURE_BEACON_OFFSET"].left|default(0)|float * 1000 %} {% set line_1 = "Front left: %.6fμm" % (front_left) %} {% set line_2 = "Front center: %.6fμm" % (front) %} @@ -772,27 +762,27 @@ gcode: {% set max_value = [(front_left|abs), (front|abs), (front_right|abs), (left|abs), (right|abs), (back_left|abs), (back|abs), (back_right|abs)]|max %} {% if max_value <= 50 %} {% set type = "success" %} - {% set recommendation = "Very low gantry twist: %.6fμm._N_No beacon scan compensation needed." % max_value %} + {% set recommendation = "Very low beacon offset: %.6fμm._N_No beacon scan compensation needed." % max_value %} {% elif max_value > 50 and max_value <= 100 %} {% set type = "info" %} - {% set recommendation = "Low gantry twist: %.6fμm._N_You may experience first layer inconsistensies, consider beacon scan compensation." % max_value %} - SET_GCODE_VARIABLE MACRO=BEACON_MEASURE_GANTRY_TWIST VARIABLE=needs_compensation VALUE=True + {% set recommendation = "Low beacon offset: %.6fμm._N_You may experience first layer inconsistensies, consider beacon scan compensation." % max_value %} + SET_GCODE_VARIABLE MACRO=BEACON_MEASURE_BEACON_OFFSET VARIABLE=needs_compensation VALUE=True {% elif max_value > 100 and max_value <= 150 %} {% set type = "warning" %} - {% set recommendation = "High gantry twist: %.6fμm._N_High chance of first layer problems, beacon scan compensation is highly encouraged." % max_value %} - SET_GCODE_VARIABLE MACRO=BEACON_MEASURE_GANTRY_TWIST VARIABLE=needs_compensation VALUE=True + {% set recommendation = "High beacon offset: %.6fμm._N_High chance of first layer problems, beacon scan compensation is highly encouraged." % max_value %} + SET_GCODE_VARIABLE MACRO=BEACON_MEASURE_BEACON_OFFSET VARIABLE=needs_compensation VALUE=True {% elif max_value > 150 and max_value <= 200 %} {% set type = "alert" %} - {% set recommendation = "Very High gantry twist: %.6fμm._N_You will encounter first layer problems on large prints unless you activate beacon scan compensation." % max_value %} - SET_GCODE_VARIABLE MACRO=BEACON_MEASURE_GANTRY_TWIST VARIABLE=needs_compensation VALUE=True + {% set recommendation = "Very High beacon offset: %.6fμm._N_You will encounter first layer problems on large prints unless you activate beacon scan compensation." % max_value %} + SET_GCODE_VARIABLE MACRO=BEACON_MEASURE_BEACON_OFFSET VARIABLE=needs_compensation VALUE=True {% elif max_value > 200 %} {% set type = "alert" %} - {% set recommendation = "Extremely high gantry twist: %.6fμm._N_You have significant scan/contact inconsistency which is indicative of mechanical problems, please investigate before resorting to software compensation." % max_value %} - SET_GCODE_VARIABLE MACRO=BEACON_MEASURE_GANTRY_TWIST VARIABLE=needs_compensation VALUE=True + {% set recommendation = "Extremely high beacon offset: %.6fμm._N_You have significant scan/contact inconsistency which is indicative of mechanical problems, please investigate before resorting to software compensation." % max_value %} + SET_GCODE_VARIABLE MACRO=BEACON_MEASURE_BEACON_OFFSET VARIABLE=needs_compensation VALUE=True {% endif %} # console echo - CONSOLE_ECHO TITLE="Gantry twist relative to the center" TYPE={type} MSG={'"_N_%s_N__N_%s_N_%s_N_%s_N_%s_N_%s_N_%s_N_%s_N_%s"' % (recommendation, line_1, line_2, line_3, line_4, line_5, line_6, line_7, line_8)} + CONSOLE_ECHO TITLE="Beacon offset relative to the center" TYPE={type} MSG={'"_N_%s_N__N_%s_N_%s_N_%s_N_%s_N_%s_N_%s_N_%s_N_%s"' % (recommendation, line_1, line_2, line_3, line_4, line_5, line_6, line_7, line_8)} ##### @@ -941,7 +931,7 @@ gcode: {% set chamber_temp = params.CHAMBER_TEMP|default(0)|int %} # beacon config - {% set needs_scan_compensation = true if printer["gcode_macro BEACON_MEASURE_GANTRY_TWIST"].needs_compensation|default(false)|lower == 'true' else false %} + {% set needs_scan_compensation = true if printer["gcode_macro BEACON_MEASURE_BEACON_OFFSET"].needs_compensation|default(false)|lower == 'true' else false %} {% if needs_scan_compensation %} BEACON_CREATE_SCAN_COMPENSATION_MESH _AUTOMATED=True BED_TEMP={bed_temp} CHAMBER_TEMP={chamber_temp} @@ -949,23 +939,22 @@ gcode: ##### -# BEACON GANTRY TWIST COMPENSATION +# BEACON OFFSET COMPENSATION ##### [gcode_macro _COPY_CONTACT_MESH] gcode: # load contact mesh BED_MESH_PROFILE LOAD="Contact" - # save contact mesh as gantry mesh - BED_MESH_PROFILE REMOVE="Gantry" - BED_MESH_PROFILE SAVE="Gantry" + # save contact mesh as offset mesh + BED_MESH_PROFILE REMOVE="Offset" + BED_MESH_PROFILE SAVE="Offset" - # save config to make the gantry mesh accessible through the bed mesh manager in klipper + # save config to make the offset mesh accessible through the bed mesh manager in klipper SAVE_CONFIG -[gcode_macro BEACON_CREATE_GANTRY_TWIST_COMPENSATION_MESH] -variable_reference_z: 0.0 +[gcode_macro BEACON_CREATE_BEACON_OFFSET_COMPENSATION_MESH] gcode: # config {% set speed = printer["gcode_macro RatOS"].macro_travel_speed|float * 60 %} @@ -990,16 +979,10 @@ gcode: {% set probe_dist_x = ((max_x - min_x) / probe_count_x)|float %} {% set probe_dist_y = ((max_y - min_y) / probe_count_y)|float %} - DEBUG_ECHO PREFIX="BEACON_CREATE_GANTRY_TWIST_COMPENSATION_MESH" MSG="mesh_resolution: {mesh_resolution}mm, mesh_min: [{min_x},{min_y}], mesh_max: [{max_x},{max_y}], probe_count: [{probe_count_x},{probe_count_y}], probe_dist: [{probe_dist_x},{probe_dist_y}]" + DEBUG_ECHO PREFIX="BEACON_CREATE_BEACON_OFFSET_COMPENSATION_MESH" MSG="mesh_resolution: {mesh_resolution}mm, mesh_min: [{min_x},{min_y}], mesh_max: [{max_x},{max_y}], probe_count: [{probe_count_x},{probe_count_y}], probe_dist: [{probe_dist_x},{probe_dist_y}]" {% if beacon_contact_start_print_true_zero %} - # load gantry mesh - BED_MESH_PROFILE LOAD="Gantry" - - # reset gantry mesh values to 0 - RESET_GANTRY_TWIST_MESH PROFILE="Gantry" - # home and abl the printer if needed _BEACON_HOME_AND_ABL @@ -1007,31 +990,29 @@ gcode: _LED_BEACON_CALIBRATION_START # echo - RATOS_ECHO PREFIX="BEACON" MSG="Measure gantry twist..." + RATOS_ECHO PREFIX="BEACON" MSG="Measure beacon offset..." # settle the mechanics down {% for i in range(10) %} beacon_poke speed=3 top=5 bottom={poke_bottom} {% endfor %} - # probe reference location - _BEACON_PROBE_GANTRY_TWIST - _BEACON_STORE_GANTRY_TWIST_TO_MESH LOCATION="center" - - # create gantry twist mesh + # create beacon offset mesh {% for y in range(probe_count_y) %} {% set y_pos = min_y + y * probe_dist_y %} {% for x in range(probe_count_x) %} {% set x_pos = min_x + x * probe_dist_x %} - DEBUG_ECHO PREFIX="xx" MSG="measure gantry twist at: {x_pos},{y_pos}" G0 X{x_pos} Y{y_pos} F{speed} - _BEACON_PROBE_GANTRY_TWIST - _BEACON_STORE_GANTRY_TWIST_TO_MESH + _BEACON_OFFSET_COMPARE + _BEACON_CACHE_BEACON_OFFSET Y={y} {% endfor %} {% endfor %} - # save gantry twist values to the gantry twist mesh - SET_GANTRY_TWIST_MESH + # load offset mesh + BED_MESH_PROFILE LOAD="Offset" + + # save beacon offset values to the beacon offset mesh + SET_BEACON_OFFSET_MESH # move back to home position _MOVE_TO_SAFE_Z_HOME Z_HOP=True @@ -1045,18 +1026,16 @@ gcode: {% endif %} -[gcode_macro _BEACON_STORE_GANTRY_TWIST_TO_MESH] +[gcode_macro _BEACON_CACHE_BEACON_OFFSET] gcode: + # parameters + {% set y = params.Y|int %} + # get last probe result {% set last_z = printer.beacon.last_offset_result["delta"]|default(0)|float %} - # set gantry offset - {% if params.LOCATION is defined %} - SET_GCODE_VARIABLE MACRO=BEACON_CREATE_GANTRY_TWIST_COMPENSATION_MESH VARIABLE=reference_z VALUE={last_z} - {% else %} - {% set reference_z = printer["gcode_macro BEACON_CREATE_GANTRY_TWIST_COMPENSATION_MESH"].reference_z|default(0)|float %} - ADD_GANTRY_TWIST_MESH_VALUE X={x} Y={y} VALUE={(last_z - reference_z)} - {% endif %} + # cache beacon offset + CACHE_BEACON_OFFSET_MESH_VALUE Y={y} VALUE={last_z} ##### @@ -1172,3 +1151,13 @@ gcode: {% endif %} {% endif %} + + +[gcode_macro _BEACON_OFFSET_COMPARE] +gcode: + # echo + RATOS_ECHO PREFIX="BEACON" MSG="Probing..." + + # probe + BEACON_OFFSET_COMPARE + BEACON_QUERY From eac5055a52a4a094a67992dd2bd4d9605c1ed90e Mon Sep 17 00:00:00 2001 From: HelgeKeck Date: Mon, 9 Dec 2024 15:41:59 +0100 Subject: [PATCH 03/17] BEACON: final compensation mesh creation --- configuration/klippy/ratos.py | 104 +++++++++++------------------ configuration/z-probe/beacon.cfg | 111 +++---------------------------- 2 files changed, 50 insertions(+), 165 deletions(-) diff --git a/configuration/klippy/ratos.py b/configuration/klippy/ratos.py index a4208b361..289eaa9e2 100644 --- a/configuration/klippy/ratos.py +++ b/configuration/klippy/ratos.py @@ -77,8 +77,7 @@ def register_commands(self): self.gcode.register_command('RATOS_LOG', self.cmd_RATOS_LOG, desc=(self.desc_RATOS_LOG)) self.gcode.register_command('PROCESS_GCODE_FILE', self.cmd_PROCESS_GCODE_FILE, desc=(self.desc_PROCESS_GCODE_FILE)) self.gcode.register_command('BEACON_APPLY_SCAN_COMPENSATION', self.cmd_BEACON_APPLY_SCAN_COMPENSATION, desc=(self.desc_BEACON_APPLY_SCAN_COMPENSATION)) - self.gcode.register_command('CACHE_BEACON_OFFSET_MESH_VALUE', self.cmd_CACHE_BEACON_OFFSET_MESH_VALUE, desc=(self.desc_CACHE_BEACON_OFFSET_MESH_VALUE)) - self.gcode.register_command('SET_BEACON_OFFSET_MESH', self.cmd_SET_BEACON_OFFSET_MESH, desc=(self.desc_SET_BEACON_OFFSET_MESH)) + self.gcode.register_command('CREATE_BEACON_COMPENSATION_MESH', self.cmd_CREATE_BEACON_COMPENSATION_MESH, desc=(self.desc_CREATE_BEACON_COMPENSATION_MESH)) self.gcode.register_command('TEST_PROCESS_GCODE_FILE', self.cmd_TEST_PROCESS_GCODE_FILE, desc=(self.desc_TEST_PROCESS_GCODE_FILE)) desc_TEST_PROCESS_GCODE_FILE = "Test the G-code post-processor for IDEX and RMMU, only for debugging purposes" @@ -169,18 +168,12 @@ def cmd_BEACON_APPLY_SCAN_COMPENSATION(self, gcmd): raise self.printer.command_error("Could not load profile " + str(profile) + " for Beacon scan compensation") self.compensate_beacon_scan(profile) - desc_CACHE_BEACON_OFFSET_MESH_VALUE = "Adds a new value to the gantry twist mesh cache." - def cmd_CACHE_BEACON_OFFSET_MESH_VALUE(self, gcmd): - y = gcmd.get_int('Y', 0) - value = gcmd.get_float('VALUE', None) - if len(self.offset_mesh_points) < y + 1: - self.offset_mesh_points.append([]) - self.offset_mesh_points[y].append(value) - - desc_SET_BEACON_OFFSET_MESH = "Sets the gantry twist cache to the gantry twist mesh." - def cmd_SET_BEACON_OFFSET_MESH(self, gcmd): + desc_CREATE_BEACON_COMPENSATION_MESH = "Sets the gantry twist cache to the gantry twist mesh." + def cmd_CREATE_BEACON_COMPENSATION_MESH(self, gcmd): profile = gcmd.get('PROFILE', "Offset") - self.set_beacon_offset_mesh(profile) + if not profile.strip(): + raise gcmd.error("Value for parameter 'PROFILE' must be specified") + self.create_compensation_mesh(profile) ##### # Beacon Scan Compensation @@ -201,9 +194,14 @@ def compensate_beacon_scan(self, profile): for x in range(len(points[0])): x_pos = params["min_x"] + x * x_step y_pos = params["min_y"] + y * y_step - z_val = points[y][x] - beacon_offset = self.offset_mesh.calc_z(x_pos, y_pos) - new_z = z_val - beacon_offset + scan_z = points[y][x] + offset_z = self.offset_mesh.calc_z(x_pos, y_pos) + new_z = scan_z - offset_z + + self.gcode.respond_raw('scan_z: ' + str(scan_z)) + self.gcode.respond_raw('offset_z: ' + str(offset_z)) + self.gcode.respond_raw('new_z: ' + str(new_z)) + new_points[y].append(new_z) self.bed_mesh.z_mesh.build_mesh(new_points) self.bed_mesh.save_profile(profile_name) @@ -212,19 +210,32 @@ def compensate_beacon_scan(self, profile): except BedMesh.BedMeshError as e: self.console_echo("Beacon scan compensation error", "error", str(e)) - def set_beacon_offset_mesh(self, profile): - try: - if self.bed_mesh.z_mesh: - profile_name = self.bed_mesh.z_mesh.get_profile_name() - if profile_name == profile: - self.bed_mesh.z_mesh.build_mesh(self.offset_mesh_points) - self.bed_mesh.save_profile(profile_name) - self.bed_mesh.set_mesh(self.bed_mesh.z_mesh) - else: - raise self.printer.command_error("Wrong profile loaded " + str(profile) + " for add gantry twist mesh value") - except BedMesh.BedMeshError as e: - self.console_echo("Reset gantry twist mesh error", "error", str(e)) + def create_compensation_mesh(self, profile): + systime = self.reactor.monotonic() + if self.bed_mesh.z_mesh: + self.gcode.run_script_from_command("BED_MESH_PROFILE LOAD='RatOSTempOffsetScan'") + scan_mesh_points = self.bed_mesh.get_status(systime)["profiles"]["RatOSTempOffsetScan"]["points"] + self.gcode.run_script_from_command("BED_MESH_PROFILE LOAD='%s'" % profile) + try: + points = self.bed_mesh.get_status(systime)["profiles"][profile]["points"] + new_points = [] + for y in range(len(points)): + new_points.append([]) + for x in range(len(points[0])): + z_val = points[y][x] + scan_mesh_z_val = scan_mesh_points[y][x] + new_z = z_val - scan_mesh_z_val + new_points[y].append(new_z) + self.bed_mesh.z_mesh.build_mesh(new_points) + self.bed_mesh.save_profile(profile) + self.bed_mesh.set_mesh(self.bed_mesh.z_mesh) + self.console_echo("Beacon scan compensation", "debug", "Compensation Mesh %s created" % (str(profile))) + except BedMesh.BedMeshError as e: + self.console_echo("Beacon scan compensation error", "error", str(e)) + ##### + # Gcode Post Processor + ##### def process_gcode_file(self, filename, enable_post_processing): try: [path, size] = self.get_gcode_file_info(filename) @@ -495,44 +506,9 @@ def load_profile(self, prof_name): except BedMesh.BedMeshError as e: raise self.gcode.error(str(e)) return z_mesh - # def save_profile(self, prof_name): - # z_mesh = self.bedmesh.get_mesh() - # if z_mesh is None: - # self.gcode.respond_info( - # "Unable to save to profile [%s], the bed has not been probed" - # % (prof_name)) - # return - # probed_matrix = z_mesh.get_probed_matrix() - # mesh_params = z_mesh.get_mesh_params() - # configfile = self.printer.lookup_object('configfile') - # cfg_name = self.name + " " + prof_name - # # set params - # z_values = "" - # for line in probed_matrix: - # z_values += "\n " - # for p in line: - # z_values += "%.6f, " % p - # z_values = z_values[:-2] - # configfile.set(cfg_name, 'version', PROFILE_VERSION) - # configfile.set(cfg_name, 'points', z_values) - # for key, value in mesh_params.items(): - # configfile.set(cfg_name, key, value) - # # save copy in local storage - # # ensure any self.profiles returned as status remains immutable - # profiles = dict(self.profiles) - # profiles[prof_name] = profile = {} - # profile['points'] = probed_matrix - # profile['mesh_params'] = collections.OrderedDict(mesh_params) - # self.profiles = profiles - # self.bedmesh.update_status() - # self.gcode.respond_info( - # "Bed Mesh state has been saved to profile [%s]\n" - # "for the current session. The SAVE_CONFIG command will\n" - # "update the printer config file and restart the printer." - # % (prof_name)) ##### # Loader ##### def load_config(config): - return RatOS(config) + return RatOS(config) \ No newline at end of file diff --git a/configuration/z-probe/beacon.cfg b/configuration/z-probe/beacon.cfg index 139022b76..8811e5bbb 100644 --- a/configuration/z-probe/beacon.cfg +++ b/configuration/z-probe/beacon.cfg @@ -877,6 +877,15 @@ gcode: # create contact mesh BED_MESH_CALIBRATE PROBE_METHOD=contact USE_CONTACT_AREA=1 SAMPLES=2 SAMPLES_DROP=1 SAMPLES_TOLERANCE_RETRIES=10 PROBE_COUNT={probe_count_x},{probe_count_y} PROFILE={profile} + # create scan mesh + BED_MESH_CALIBRATE METHOD=automatic PROBE_COUNT={probe_count_x},{probe_count_y} PROFILE="RatOSTempOffsetScan" + + # create compensation mesh + CREATE_BEACON_COMPENSATION_MESH PROFILE={profile} + + # remove temp scan mesh + BED_MESH_PROFILE REMOVE="RatOSTempOffsetScan" + # turn bed and extruder heaters off {% if not automated %} SET_HEATER_TEMPERATURE HEATER={'extruder' if default_toolhead == 0 else 'extruder1'} TARGET=0 @@ -938,106 +947,6 @@ gcode: {% endif %} -##### -# BEACON OFFSET COMPENSATION -##### -[gcode_macro _COPY_CONTACT_MESH] -gcode: - # load contact mesh - BED_MESH_PROFILE LOAD="Contact" - - # save contact mesh as offset mesh - BED_MESH_PROFILE REMOVE="Offset" - BED_MESH_PROFILE SAVE="Offset" - - # save config to make the offset mesh accessible through the bed mesh manager in klipper - SAVE_CONFIG - - -[gcode_macro BEACON_CREATE_BEACON_OFFSET_COMPENSATION_MESH] -gcode: - # config - {% set speed = printer["gcode_macro RatOS"].macro_travel_speed|float * 60 %} - - # beacon config - {% set poke_bottom = printer["gcode_macro RatOS"].beacon_contact_poke_bottom_limit|default(-1)|float %} - {% set beacon_contact_start_print_true_zero = true if printer["gcode_macro RatOS"].beacon_contact_start_print_true_zero|default(false)|lower == 'true' else false %} - {% set mesh_resolution = printer["gcode_macro RatOS"].beacon_scan_compensation_resolution|float %} - - # get bed mesh config object - {% set mesh_config = printer.configfile.config.bed_mesh %} - - # get configured bed mesh area - {% set min_x = mesh_config.mesh_min.split(",")[0]|float %} - {% set min_y = mesh_config.mesh_min.split(",")[1]|float %} - {% set max_x = mesh_config.mesh_max.split(",")[0]|float %} - {% set max_y = mesh_config.mesh_max.split(",")[1]|float %} - - # calculate probe counts and distances - {% set probe_count_x = ((max_x - min_x) / mesh_resolution + 1)|int %} - {% set probe_count_y = ((max_y - min_y) / mesh_resolution + 1)|int %} - {% set probe_dist_x = ((max_x - min_x) / probe_count_x)|float %} - {% set probe_dist_y = ((max_y - min_y) / probe_count_y)|float %} - - DEBUG_ECHO PREFIX="BEACON_CREATE_BEACON_OFFSET_COMPENSATION_MESH" MSG="mesh_resolution: {mesh_resolution}mm, mesh_min: [{min_x},{min_y}], mesh_max: [{max_x},{max_y}], probe_count: [{probe_count_x},{probe_count_y}], probe_dist: [{probe_dist_x},{probe_dist_y}]" - - {% if beacon_contact_start_print_true_zero %} - - # home and abl the printer if needed - _BEACON_HOME_AND_ABL - - # visual feedback - _LED_BEACON_CALIBRATION_START - - # echo - RATOS_ECHO PREFIX="BEACON" MSG="Measure beacon offset..." - - # settle the mechanics down - {% for i in range(10) %} - beacon_poke speed=3 top=5 bottom={poke_bottom} - {% endfor %} - - # create beacon offset mesh - {% for y in range(probe_count_y) %} - {% set y_pos = min_y + y * probe_dist_y %} - {% for x in range(probe_count_x) %} - {% set x_pos = min_x + x * probe_dist_x %} - G0 X{x_pos} Y{y_pos} F{speed} - _BEACON_OFFSET_COMPARE - _BEACON_CACHE_BEACON_OFFSET Y={y} - {% endfor %} - {% endfor %} - - # load offset mesh - BED_MESH_PROFILE LOAD="Offset" - - # save beacon offset values to the beacon offset mesh - SET_BEACON_OFFSET_MESH - - # move back to home position - _MOVE_TO_SAFE_Z_HOME Z_HOP=True - - # visual feedback - _LED_BEACON_CALIBRATION_END - - # save config - SAVE_CONFIG - - {% endif %} - - -[gcode_macro _BEACON_CACHE_BEACON_OFFSET] -gcode: - # parameters - {% set y = params.Y|int %} - - # get last probe result - {% set last_z = printer.beacon.last_offset_result["delta"]|default(0)|float %} - - # cache beacon offset - CACHE_BEACON_OFFSET_MESH_VALUE Y={y} VALUE={last_z} - - ##### # BEACON UTILS ##### @@ -1160,4 +1069,4 @@ gcode: # probe BEACON_OFFSET_COMPARE - BEACON_QUERY + BEACON_QUERY \ No newline at end of file From 4b9127aaf7640d759f42f1f36f191add32aa7299 Mon Sep 17 00:00:00 2001 From: HelgeKeck Date: Mon, 9 Dec 2024 15:43:31 +0100 Subject: [PATCH 04/17] BEACON: default compensation mesh name changed --- configuration/z-probe/beacon.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configuration/z-probe/beacon.cfg b/configuration/z-probe/beacon.cfg index 8811e5bbb..c1dd2bf32 100644 --- a/configuration/z-probe/beacon.cfg +++ b/configuration/z-probe/beacon.cfg @@ -793,7 +793,7 @@ gcode: # parameters {% set bed_temp = params.BED_TEMP|default(85)|int %} {% set chamber_temp = params.CHAMBER_TEMP|default(0)|int %} - {% set profile = params.PROFILE|default("Contact")|string %} + {% set profile = params.PROFILE|default("Compensation")|string %} {% set automated = true if params._AUTOMATED|default(false)|lower == 'true' else false %} # config From 079971186c93e3c1b1c213334deaa28e824d35fe Mon Sep 17 00:00:00 2001 From: HelgeKeck Date: Mon, 9 Dec 2024 15:57:15 +0100 Subject: [PATCH 05/17] BEACON: debug output added to scan compensation --- configuration/klippy/ratos.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/configuration/klippy/ratos.py b/configuration/klippy/ratos.py index 289eaa9e2..14e680ae2 100644 --- a/configuration/klippy/ratos.py +++ b/configuration/klippy/ratos.py @@ -197,11 +197,7 @@ def compensate_beacon_scan(self, profile): scan_z = points[y][x] offset_z = self.offset_mesh.calc_z(x_pos, y_pos) new_z = scan_z - offset_z - - self.gcode.respond_raw('scan_z: ' + str(scan_z)) - self.gcode.respond_raw('offset_z: ' + str(offset_z)) - self.gcode.respond_raw('new_z: ' + str(new_z)) - + self.debug_echo("Beacon scan compensation", "scan: %0.4f offset: %0.4f new: %0.4f" % (scan_z, offset_z, new_z)) new_points[y].append(new_z) self.bed_mesh.z_mesh.build_mesh(new_points) self.bed_mesh.save_profile(profile_name) From 6d4715ad2cb1f1570d972bc13febb566022955f4 Mon Sep 17 00:00:00 2001 From: HelgeKeck Date: Mon, 9 Dec 2024 16:03:12 +0100 Subject: [PATCH 06/17] BEACON: better variable names --- configuration/klippy/ratos.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configuration/klippy/ratos.py b/configuration/klippy/ratos.py index 14e680ae2..a23b37d2e 100644 --- a/configuration/klippy/ratos.py +++ b/configuration/klippy/ratos.py @@ -218,9 +218,9 @@ def create_compensation_mesh(self, profile): for y in range(len(points)): new_points.append([]) for x in range(len(points[0])): - z_val = points[y][x] - scan_mesh_z_val = scan_mesh_points[y][x] - new_z = z_val - scan_mesh_z_val + contact_z = points[y][x] + scan_z = scan_mesh_points[y][x] + new_z = contact_z - scan_z new_points[y].append(new_z) self.bed_mesh.z_mesh.build_mesh(new_points) self.bed_mesh.save_profile(profile) From a9a7837f9c4f72a5b730b62e635ce6c14cb559db Mon Sep 17 00:00:00 2001 From: HelgeKeck Date: Mon, 9 Dec 2024 16:03:48 +0100 Subject: [PATCH 07/17] BEACON: better variable name --- configuration/klippy/ratos.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configuration/klippy/ratos.py b/configuration/klippy/ratos.py index a23b37d2e..bce48d026 100644 --- a/configuration/klippy/ratos.py +++ b/configuration/klippy/ratos.py @@ -220,8 +220,8 @@ def create_compensation_mesh(self, profile): for x in range(len(points[0])): contact_z = points[y][x] scan_z = scan_mesh_points[y][x] - new_z = contact_z - scan_z - new_points[y].append(new_z) + offset_z = contact_z - scan_z + new_points[y].append(offset_z) self.bed_mesh.z_mesh.build_mesh(new_points) self.bed_mesh.save_profile(profile) self.bed_mesh.set_mesh(self.bed_mesh.z_mesh) From 75856f9707cbc900d161092381beed765748090b Mon Sep 17 00:00:00 2001 From: HelgeKeck Date: Mon, 9 Dec 2024 16:07:03 +0100 Subject: [PATCH 08/17] MACRO: default profile changed for BEACON_CREATE_SCAN_COMPENSATION_MESH --- configuration/z-probe/beacon.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configuration/z-probe/beacon.cfg b/configuration/z-probe/beacon.cfg index c1dd2bf32..8fce61706 100644 --- a/configuration/z-probe/beacon.cfg +++ b/configuration/z-probe/beacon.cfg @@ -793,7 +793,7 @@ gcode: # parameters {% set bed_temp = params.BED_TEMP|default(85)|int %} {% set chamber_temp = params.CHAMBER_TEMP|default(0)|int %} - {% set profile = params.PROFILE|default("Compensation")|string %} + {% set profile = params.PROFILE|default("Offset")|string %} {% set automated = true if params._AUTOMATED|default(false)|lower == 'true' else false %} # config From ee8a1d95d67e90a223ccdc6b2c07f55fa98797c5 Mon Sep 17 00:00:00 2001 From: HelgeKeck Date: Mon, 9 Dec 2024 16:20:07 +0100 Subject: [PATCH 09/17] MACRO: add hotend heat soke time to BEACON_CREATE_SCAN_COMPENSATION_MESH --- configuration/z-probe/beacon.cfg | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/configuration/z-probe/beacon.cfg b/configuration/z-probe/beacon.cfg index 8fce61706..84f69b7f6 100644 --- a/configuration/z-probe/beacon.cfg +++ b/configuration/z-probe/beacon.cfg @@ -801,6 +801,7 @@ gcode: {% set beacon_scan_compensation_enable = true if printer["gcode_macro RatOS"].beacon_scan_compensation_enable|default(false)|lower == 'true' else false %} {% set mesh_resolution = printer["gcode_macro RatOS"].beacon_scan_compensation_resolution|float %} {% set bed_heat_soak_time = printer["gcode_macro RatOS"].bed_heat_soak_time|default(0)|int %} + {% set hotend_heat_soak_time = printer["gcode_macro RatOS"].hotend_heat_soak_time|default(0)|int %} # get bed mesh config object {% set mesh_config = printer.configfile.config.bed_mesh %} @@ -853,6 +854,12 @@ gcode: {% if bed_heat_soak_time > 0 %} RATOS_ECHO MSG="Heat soaking bed for {bed_heat_soak_time} seconds..." G4 P{(bed_heat_soak_time * 1000)} + {% else %} + # Wait for extruder thermal expansion + {% if hotend_heat_soak_time > 0 %} + RATOS_ECHO MSG="Heat soaking hotend for {hotend_heat_soak_time} seconds..." + G4 P{(hotend_heat_soak_time * 1000)} + {% endif %} {% endif %} {% endif %} From c536ebc729ebdbb8f194ef6a492d4ebe3b88f185 Mon Sep 17 00:00:00 2001 From: HelgeKeck Date: Mon, 9 Dec 2024 16:26:00 +0100 Subject: [PATCH 10/17] MACRO: commetn changed in BEACON_CREATE_SCAN_COMPENSATION_MESH --- configuration/z-probe/beacon.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configuration/z-probe/beacon.cfg b/configuration/z-probe/beacon.cfg index 84f69b7f6..234f8e1e6 100644 --- a/configuration/z-probe/beacon.cfg +++ b/configuration/z-probe/beacon.cfg @@ -884,7 +884,7 @@ gcode: # create contact mesh BED_MESH_CALIBRATE PROBE_METHOD=contact USE_CONTACT_AREA=1 SAMPLES=2 SAMPLES_DROP=1 SAMPLES_TOLERANCE_RETRIES=10 PROBE_COUNT={probe_count_x},{probe_count_y} PROFILE={profile} - # create scan mesh + # create temp scan mesh BED_MESH_CALIBRATE METHOD=automatic PROBE_COUNT={probe_count_x},{probe_count_y} PROFILE="RatOSTempOffsetScan" # create compensation mesh From 971307e6fe66cc15ad148e2cc2fe54de42ed802c Mon Sep 17 00:00:00 2001 From: HelgeKeck Date: Mon, 9 Dec 2024 16:27:00 +0100 Subject: [PATCH 11/17] PLUGIN: unused variables removed --- configuration/klippy/ratos.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/configuration/klippy/ratos.py b/configuration/klippy/ratos.py index bce48d026..10209927b 100644 --- a/configuration/klippy/ratos.py +++ b/configuration/klippy/ratos.py @@ -7,14 +7,6 @@ # RatOS ##### -PRUSA_SLICER = "prusaslicer" -SUPER_SLICER = "superslicer" -ORCA_SLICER = "orcaslicer" -UNKNOWN_SLICER = "unknown" - -CHANGED_BY_POST_PROCESSOR = " ; Changed by RatOS post processor: " -REMOVED_BY_POST_PROCESSOR = "; Removed by RatOS post processor: " - class RatOS: ##### From 0f66c59b54c15571e270b390a85894cb04e2712f Mon Sep 17 00:00:00 2001 From: HelgeKeck Date: Mon, 9 Dec 2024 18:36:53 +0100 Subject: [PATCH 12/17] BEACON: offset calculation inverted --- configuration/klippy/ratos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configuration/klippy/ratos.py b/configuration/klippy/ratos.py index 0581bb78a..b6e165c77 100644 --- a/configuration/klippy/ratos.py +++ b/configuration/klippy/ratos.py @@ -214,7 +214,7 @@ def create_compensation_mesh(self, profile): for x in range(len(points[0])): contact_z = points[y][x] scan_z = scan_mesh_points[y][x] - offset_z = contact_z - scan_z + offset_z = scan_z - contact_z new_points[y].append(offset_z) self.bed_mesh.z_mesh.build_mesh(new_points) self.bed_mesh.save_profile(profile) From a30525bb55fb1ad49243c5b7d892ce59dec91da4 Mon Sep 17 00:00:00 2001 From: HelgeKeck Date: Tue, 10 Dec 2024 05:43:49 +0100 Subject: [PATCH 13/17] BEACON: fix compensation calculation --- configuration/klippy/ratos.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configuration/klippy/ratos.py b/configuration/klippy/ratos.py index b6e165c77..eb0ba6799 100644 --- a/configuration/klippy/ratos.py +++ b/configuration/klippy/ratos.py @@ -190,7 +190,7 @@ def compensate_beacon_scan(self, profile): y_pos = params["min_y"] + y * y_step scan_z = points[y][x] offset_z = self.offset_mesh.calc_z(x_pos, y_pos) - new_z = scan_z - offset_z + new_z = scan_z + offset_z self.debug_echo("Beacon scan compensation", "scan: %0.4f offset: %0.4f new: %0.4f" % (scan_z, offset_z, new_z)) new_points[y].append(new_z) self.bed_mesh.z_mesh.build_mesh(new_points) @@ -214,7 +214,7 @@ def create_compensation_mesh(self, profile): for x in range(len(points[0])): contact_z = points[y][x] scan_z = scan_mesh_points[y][x] - offset_z = scan_z - contact_z + offset_z = contact_z - scan_z new_points[y].append(offset_z) self.bed_mesh.z_mesh.build_mesh(new_points) self.bed_mesh.save_profile(profile) From 1cfe9498a23666dc81b67ee8dd55cec6f8b48b98 Mon Sep 17 00:00:00 2001 From: HelgeKeck Date: Tue, 10 Dec 2024 05:48:23 +0100 Subject: [PATCH 14/17] BEACON: debug output added to create_compensation_mesh --- configuration/klippy/ratos.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/configuration/klippy/ratos.py b/configuration/klippy/ratos.py index eb0ba6799..352dbf42b 100644 --- a/configuration/klippy/ratos.py +++ b/configuration/klippy/ratos.py @@ -215,13 +215,14 @@ def create_compensation_mesh(self, profile): contact_z = points[y][x] scan_z = scan_mesh_points[y][x] offset_z = contact_z - scan_z + self.debug_echo("Create compensation mesh", "scan: %0.4f contact: %0.4f offset: %0.4f" % (scan_z, contact_z, offset_z)) new_points[y].append(offset_z) self.bed_mesh.z_mesh.build_mesh(new_points) self.bed_mesh.save_profile(profile) self.bed_mesh.set_mesh(self.bed_mesh.z_mesh) - self.console_echo("Beacon scan compensation", "debug", "Compensation Mesh %s created" % (str(profile))) + self.console_echo("Create compensation mesh", "debug", "Compensation Mesh %s created" % (str(profile))) except BedMesh.BedMeshError as e: - self.console_echo("Beacon scan compensation error", "error", str(e)) + self.console_echo("Create compensation mesh error", "error", str(e)) ##### # Gcode Post Processor From cf3453b3ca68f614c977d06a162ec70f713fc3f9 Mon Sep 17 00:00:00 2001 From: HelgeKeck Date: Tue, 10 Dec 2024 06:03:25 +0100 Subject: [PATCH 15/17] BEACON: make beacon calibration idex aware --- configuration/z-probe/beacon.cfg | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/configuration/z-probe/beacon.cfg b/configuration/z-probe/beacon.cfg index 234f8e1e6..f306eb330 100644 --- a/configuration/z-probe/beacon.cfg +++ b/configuration/z-probe/beacon.cfg @@ -98,6 +98,11 @@ gcode: {% set default_toolhead = printer["gcode_macro RatOS"].default_toolhead|default(0)|int %} {% set beacon_contact_start_print_true_zero = true if printer["gcode_macro RatOS"].beacon_contact_start_print_true_zero|default(false)|lower == 'true' else false %} + # activate IDEX default + {% if printer["dual_carriage"] is defined %} + _IDEX_SINGLE INIT=1 + {% endif %} + # calibration BEACON_INITIAL_CALIBRATION _AUTOMATED=True @@ -821,6 +826,11 @@ gcode: {% else %} + # activate IDEX default + {% if printer["dual_carriage"] is defined %} + _IDEX_SINGLE INIT=1 + {% endif %} + # home the printer if needed MAYBE_HOME @@ -959,6 +969,11 @@ gcode: ##### [gcode_macro _BEACON_HOME_AND_ABL] gcode: + # activate IDEX default + {% if printer["dual_carriage"] is defined %} + _IDEX_SINGLE INIT=1 + {% endif %} + # home X/Y if not homed already MAYBE_HOME X=True Y=True From f2ccbc3f5deff57c6ffc09ec53bce566594b1f29 Mon Sep 17 00:00:00 2001 From: HelgeKeck Date: Tue, 10 Dec 2024 07:04:59 +0100 Subject: [PATCH 16/17] BEACON: moving beacon compensation into beacon_mesh.py --- configuration/klippy/beacon_mesh.py | 177 ++++++++++++++++++++++++++ configuration/klippy/ratos.py | 140 +------------------- configuration/scripts/ratos-common.sh | 1 + 3 files changed, 180 insertions(+), 138 deletions(-) create mode 100644 configuration/klippy/beacon_mesh.py diff --git a/configuration/klippy/beacon_mesh.py b/configuration/klippy/beacon_mesh.py new file mode 100644 index 000000000..0134e8b15 --- /dev/null +++ b/configuration/klippy/beacon_mesh.py @@ -0,0 +1,177 @@ +import logging, collections +from . import bed_mesh as BedMesh + +##### +# Beacon Mesh +##### + +class BeaconMesh: + + ##### + # Initialize + ##### + def __init__(self, config): + self.config = config + self.printer = config.get_printer() + self.name = config.get_name() + self.gcode = self.printer.lookup_object('gcode') + self.reactor = self.printer.get_reactor() + + self.offset_mesh = None + self.offset_mesh_points = [[]] + self.pmgr = BedMeshProfileManager(self.config, self) + + self.register_commands() + self.register_handler() + + ##### + # Handler + ##### + def register_handler(self): + self.printer.register_event_handler("klippy:connect", self._connect) + + def _connect(self): + if self.config.has_section("ratos"): + self.ratos = self.printer.lookup_object('ratos') + if self.config.has_section("bed_mesh"): + self.bed_mesh = self.printer.lookup_object('bed_mesh') + + ##### + # Gcode commands + ##### + def register_commands(self): + self.gcode.register_command('BEACON_APPLY_SCAN_COMPENSATION', self.cmd_BEACON_APPLY_SCAN_COMPENSATION, desc=(self.desc_BEACON_APPLY_SCAN_COMPENSATION)) + self.gcode.register_command('CREATE_BEACON_COMPENSATION_MESH', self.cmd_CREATE_BEACON_COMPENSATION_MESH, desc=(self.desc_CREATE_BEACON_COMPENSATION_MESH)) + + desc_BEACON_APPLY_SCAN_COMPENSATION = "Compensates a beacon scan mesh with the beacon compensation mesh." + def cmd_BEACON_APPLY_SCAN_COMPENSATION(self, gcmd): + profile = gcmd.get('PROFILE', "Offset") + if not profile.strip(): + raise gcmd.error("Value for parameter 'PROFILE' must be specified") + if profile not in self.pmgr.get_profiles(): + raise self.printer.command_error("Profile " + str(profile) + " not found for Beacon scan compensation") + self.offset_mesh = self.pmgr.load_profile(profile) + if not self.offset_mesh: + raise self.printer.command_error("Could not load profile " + str(profile) + " for Beacon scan compensation") + self.compensate_beacon_scan(profile) + + desc_CREATE_BEACON_COMPENSATION_MESH = "Creates the beacon compensation mesh by joining a contact and a scan mesh." + def cmd_CREATE_BEACON_COMPENSATION_MESH(self, gcmd): + profile = gcmd.get('PROFILE', "Offset") + if not profile.strip(): + raise gcmd.error("Value for parameter 'PROFILE' must be specified") + self.create_compensation_mesh(profile) + + ##### + # Beacon Scan Compensation + ##### + def compensate_beacon_scan(self, profile): + systime = self.reactor.monotonic() + try: + if self.bed_mesh.z_mesh: + profile_name = self.bed_mesh.z_mesh.get_profile_name() + if profile_name != profile: + points = self.bed_mesh.get_status(systime)["profiles"][profile_name]["points"] + params = self.bed_mesh.z_mesh.get_mesh_params() + x_step = ((params["max_x"] - params["min_x"]) / (len(points[0]) - 1)) + y_step = ((params["max_y"] - params["min_y"]) / (len(points) - 1)) + new_points = [] + for y in range(len(points)): + new_points.append([]) + for x in range(len(points[0])): + x_pos = params["min_x"] + x * x_step + y_pos = params["min_y"] + y * y_step + scan_z = points[y][x] + offset_z = self.offset_mesh.calc_z(x_pos, y_pos) + new_z = scan_z + offset_z + self.ratos.debug_echo("Beacon scan compensation", "scan: %0.4f offset: %0.4f new: %0.4f" % (scan_z, offset_z, new_z)) + new_points[y].append(new_z) + self.bed_mesh.z_mesh.build_mesh(new_points) + self.bed_mesh.save_profile(profile_name) + self.bed_mesh.set_mesh(self.bed_mesh.z_mesh) + self.ratos.console_echo("Beacon scan compensation", "debug", "Mesh scan profile %s compensated with contact profile %s" % (str(profile_name), str(profile))) + except BedMesh.BedMeshError as e: + self.ratos.console_echo("Beacon scan compensation error", "error", str(e)) + + def create_compensation_mesh(self, profile): + systime = self.reactor.monotonic() + if self.bed_mesh.z_mesh: + self.gcode.run_script_from_command("BED_MESH_PROFILE LOAD='RatOSTempOffsetScan'") + scan_mesh_points = self.bed_mesh.get_status(systime)["profiles"]["RatOSTempOffsetScan"]["points"] + self.gcode.run_script_from_command("BED_MESH_PROFILE LOAD='%s'" % profile) + try: + points = self.bed_mesh.get_status(systime)["profiles"][profile]["points"] + new_points = [] + for y in range(len(points)): + new_points.append([]) + for x in range(len(points[0])): + contact_z = points[y][x] + scan_z = scan_mesh_points[y][x] + offset_z = contact_z - scan_z + self.ratos.debug_echo("Create compensation mesh", "scan: %0.4f contact: %0.4f offset: %0.4f" % (scan_z, contact_z, offset_z)) + new_points[y].append(offset_z) + self.bed_mesh.z_mesh.build_mesh(new_points) + self.bed_mesh.save_profile(profile) + self.bed_mesh.set_mesh(self.bed_mesh.z_mesh) + self.ratos.console_echo("Create compensation mesh", "debug", "Compensation Mesh %s created" % (str(profile))) + except BedMesh.BedMeshError as e: + self.ratos.console_echo("Create compensation mesh error", "error", str(e)) + +##### +# Bed Mesh Profile Manager +##### +PROFILE_VERSION = 1 +class BedMeshProfileManager: + def __init__(self, config, bedmesh): + self.name = "bed_mesh" + self.printer = config.get_printer() + self.gcode = self.printer.lookup_object('gcode') + self.bedmesh = bedmesh + self.profiles = {} + self.incompatible_profiles = [] + # Fetch stored profiles from Config + stored_profs = config.get_prefix_sections(self.name) + stored_profs = [s for s in stored_profs + if s.get_name() != self.name] + for profile in stored_profs: + name = profile.get_name().split(' ', 1)[1] + version = profile.getint('version', 0) + if version != BedMesh.PROFILE_VERSION: + logging.info( + "bed_mesh: Profile [%s] not compatible with this version\n" + "of bed_mesh. Profile Version: %d Current Version: %d " + % (name, version, BedMesh.PROFILE_VERSION)) + self.incompatible_profiles.append(name) + continue + self.profiles[name] = {} + zvals = profile.getlists('points', seps=(',', '\n'), parser=float) + self.profiles[name]['points'] = zvals + self.profiles[name]['mesh_params'] = params = \ + collections.OrderedDict() + for key, t in BedMesh.PROFILE_OPTIONS.items(): + if t is int: + params[key] = profile.getint(key) + elif t is float: + params[key] = profile.getfloat(key) + elif t is str: + params[key] = profile.get(key) + def get_profiles(self): + return self.profiles + def load_profile(self, prof_name): + profile = self.profiles.get(prof_name, None) + if profile is None: + return None + probed_matrix = profile['points'] + mesh_params = profile['mesh_params'] + z_mesh = BedMesh.ZMesh(mesh_params, prof_name) + try: + z_mesh.build_mesh(probed_matrix) + except BedMesh.BedMeshError as e: + raise self.gcode.error(str(e)) + return z_mesh + +##### +# Loader +##### +def load_config(config): + return BeaconMesh(config) \ No newline at end of file diff --git a/configuration/klippy/ratos.py b/configuration/klippy/ratos.py index 352dbf42b..a6ffbd523 100644 --- a/configuration/klippy/ratos.py +++ b/configuration/klippy/ratos.py @@ -1,7 +1,5 @@ -import os, logging, re, glob, math -import logging, collections, pathlib -import json, asyncio, subprocess -from . import bed_mesh as BedMesh +import os, logging, glob +import json, subprocess, pathlib ##### # RatOS @@ -24,9 +22,6 @@ def __init__(self, config): self.reactor = self.printer.get_reactor() self.old_is_graph_files = [] - self.offset_mesh = None - self.offset_mesh_points = [[]] - self.pmgr = BedMeshProfileManager(self.config, self) self.load_settings() self.register_commands() @@ -41,8 +36,6 @@ def register_handler(self): def _connect(self): self.v_sd = self.printer.lookup_object('virtual_sdcard', None) self.sdcard_dirname = self.v_sd.sdcard_dirname - if self.config.has_section("bed_mesh"): - self.bed_mesh = self.printer.lookup_object('bed_mesh') self.dual_carriage = None if self.config.has_section("dual_carriage"): self.dual_carriage = self.printer.lookup_object("dual_carriage", None) @@ -68,8 +61,6 @@ def register_commands(self): self.gcode.register_command('CONSOLE_ECHO', self.cmd_CONSOLE_ECHO, desc=(self.desc_CONSOLE_ECHO)) self.gcode.register_command('RATOS_LOG', self.cmd_RATOS_LOG, desc=(self.desc_RATOS_LOG)) self.gcode.register_command('PROCESS_GCODE_FILE', self.cmd_PROCESS_GCODE_FILE, desc=(self.desc_PROCESS_GCODE_FILE)) - self.gcode.register_command('BEACON_APPLY_SCAN_COMPENSATION', self.cmd_BEACON_APPLY_SCAN_COMPENSATION, desc=(self.desc_BEACON_APPLY_SCAN_COMPENSATION)) - self.gcode.register_command('CREATE_BEACON_COMPENSATION_MESH', self.cmd_CREATE_BEACON_COMPENSATION_MESH, desc=(self.desc_CREATE_BEACON_COMPENSATION_MESH)) self.gcode.register_command('TEST_PROCESS_GCODE_FILE', self.cmd_TEST_PROCESS_GCODE_FILE, desc=(self.desc_TEST_PROCESS_GCODE_FILE)) desc_TEST_PROCESS_GCODE_FILE = "Test the G-code post-processor for IDEX and RMMU, only for debugging purposes" @@ -150,80 +141,6 @@ def cmd_PROCESS_GCODE_FILE(self, gcmd): if self.process_gcode_file(filename, True): self.v_sd.cmd_SDCARD_PRINT_FILE(gcmd) - desc_BEACON_APPLY_SCAN_COMPENSATION = "Compensates magnetic inaccuracies for beacon scan meshes." - def cmd_BEACON_APPLY_SCAN_COMPENSATION(self, gcmd): - profile = gcmd.get('PROFILE', "Offset") - if not profile.strip(): - raise gcmd.error("Value for parameter 'PROFILE' must be specified") - if profile not in self.pmgr.get_profiles(): - raise self.printer.command_error("Profile " + str(profile) + " not found for Beacon scan compensation") - self.offset_mesh = self.pmgr.load_profile(profile) - if not self.offset_mesh: - raise self.printer.command_error("Could not load profile " + str(profile) + " for Beacon scan compensation") - self.compensate_beacon_scan(profile) - - desc_CREATE_BEACON_COMPENSATION_MESH = "Sets the gantry twist cache to the gantry twist mesh." - def cmd_CREATE_BEACON_COMPENSATION_MESH(self, gcmd): - profile = gcmd.get('PROFILE', "Offset") - if not profile.strip(): - raise gcmd.error("Value for parameter 'PROFILE' must be specified") - self.create_compensation_mesh(profile) - - ##### - # Beacon Scan Compensation - ##### - def compensate_beacon_scan(self, profile): - systime = self.reactor.monotonic() - try: - if self.bed_mesh.z_mesh: - profile_name = self.bed_mesh.z_mesh.get_profile_name() - if profile_name != profile: - points = self.bed_mesh.get_status(systime)["profiles"][profile_name]["points"] - params = self.bed_mesh.z_mesh.get_mesh_params() - x_step = ((params["max_x"] - params["min_x"]) / (len(points[0]) - 1)) - y_step = ((params["max_y"] - params["min_y"]) / (len(points) - 1)) - new_points = [] - for y in range(len(points)): - new_points.append([]) - for x in range(len(points[0])): - x_pos = params["min_x"] + x * x_step - y_pos = params["min_y"] + y * y_step - scan_z = points[y][x] - offset_z = self.offset_mesh.calc_z(x_pos, y_pos) - new_z = scan_z + offset_z - self.debug_echo("Beacon scan compensation", "scan: %0.4f offset: %0.4f new: %0.4f" % (scan_z, offset_z, new_z)) - new_points[y].append(new_z) - self.bed_mesh.z_mesh.build_mesh(new_points) - self.bed_mesh.save_profile(profile_name) - self.bed_mesh.set_mesh(self.bed_mesh.z_mesh) - self.console_echo("Beacon scan compensation", "debug", "Mesh scan profile %s compensated with contact profile %s" % (str(profile_name), str(profile))) - except BedMesh.BedMeshError as e: - self.console_echo("Beacon scan compensation error", "error", str(e)) - - def create_compensation_mesh(self, profile): - systime = self.reactor.monotonic() - if self.bed_mesh.z_mesh: - self.gcode.run_script_from_command("BED_MESH_PROFILE LOAD='RatOSTempOffsetScan'") - scan_mesh_points = self.bed_mesh.get_status(systime)["profiles"]["RatOSTempOffsetScan"]["points"] - self.gcode.run_script_from_command("BED_MESH_PROFILE LOAD='%s'" % profile) - try: - points = self.bed_mesh.get_status(systime)["profiles"][profile]["points"] - new_points = [] - for y in range(len(points)): - new_points.append([]) - for x in range(len(points[0])): - contact_z = points[y][x] - scan_z = scan_mesh_points[y][x] - offset_z = contact_z - scan_z - self.debug_echo("Create compensation mesh", "scan: %0.4f contact: %0.4f offset: %0.4f" % (scan_z, contact_z, offset_z)) - new_points[y].append(offset_z) - self.bed_mesh.z_mesh.build_mesh(new_points) - self.bed_mesh.save_profile(profile) - self.bed_mesh.set_mesh(self.bed_mesh.z_mesh) - self.console_echo("Create compensation mesh", "debug", "Compensation Mesh %s created" % (str(profile))) - except BedMesh.BedMeshError as e: - self.console_echo("Create compensation mesh error", "error", str(e)) - ##### # Gcode Post Processor ##### @@ -448,59 +365,6 @@ def get_ratos_version(self): def get_status(self, eventtime): return {'name': self.name, 'last_processed_file_result': self.last_processed_file_result} -##### -# Bed Mesh Profile Manager -##### -PROFILE_VERSION = 1 -class BedMeshProfileManager: - def __init__(self, config, bedmesh): - self.name = "bed_mesh" - self.printer = config.get_printer() - self.gcode = self.printer.lookup_object('gcode') - self.bedmesh = bedmesh - self.profiles = {} - self.incompatible_profiles = [] - # Fetch stored profiles from Config - stored_profs = config.get_prefix_sections(self.name) - stored_profs = [s for s in stored_profs - if s.get_name() != self.name] - for profile in stored_profs: - name = profile.get_name().split(' ', 1)[1] - version = profile.getint('version', 0) - if version != BedMesh.PROFILE_VERSION: - logging.info( - "bed_mesh: Profile [%s] not compatible with this version\n" - "of bed_mesh. Profile Version: %d Current Version: %d " - % (name, version, BedMesh.PROFILE_VERSION)) - self.incompatible_profiles.append(name) - continue - self.profiles[name] = {} - zvals = profile.getlists('points', seps=(',', '\n'), parser=float) - self.profiles[name]['points'] = zvals - self.profiles[name]['mesh_params'] = params = \ - collections.OrderedDict() - for key, t in BedMesh.PROFILE_OPTIONS.items(): - if t is int: - params[key] = profile.getint(key) - elif t is float: - params[key] = profile.getfloat(key) - elif t is str: - params[key] = profile.get(key) - def get_profiles(self): - return self.profiles - def load_profile(self, prof_name): - profile = self.profiles.get(prof_name, None) - if profile is None: - return None - probed_matrix = profile['points'] - mesh_params = profile['mesh_params'] - z_mesh = BedMesh.ZMesh(mesh_params, prof_name) - try: - z_mesh.build_mesh(probed_matrix) - except BedMesh.BedMeshError as e: - raise self.gcode.error(str(e)) - return z_mesh - ##### # Loader ##### diff --git a/configuration/scripts/ratos-common.sh b/configuration/scripts/ratos-common.sh index b3e65ef57..c34a5b96f 100755 --- a/configuration/scripts/ratos-common.sh +++ b/configuration/scripts/ratos-common.sh @@ -190,6 +190,7 @@ verify_registered_extensions() ["z_offset_probe_extension"]=$(realpath "${RATOS_PRINTER_DATA_DIR}/config/RatOS/klippy/z_offset_probe.py") ["resonance_generator_extension"]=$(realpath "${RATOS_PRINTER_DATA_DIR}/config/RatOS/klippy/resonance_generator.py") ["ratos_extension"]=$(realpath "${RATOS_PRINTER_DATA_DIR}/config/RatOS/klippy/ratos.py") + ["beacon_mesh_extension"]=$(realpath "${RATOS_PRINTER_DATA_DIR}/config/RatOS/klippy/beacon_mesh.py") ) declare -A kinematics_extensions=( From 3e11758218769c4d9f4fd4b6799385b7160891f9 Mon Sep 17 00:00:00 2001 From: HelgeKeck Date: Tue, 10 Dec 2024 18:49:06 +0100 Subject: [PATCH 17/17] MACRO: add beacon_mesh printer object to beacon.cfg --- configuration/z-probe/beacon.cfg | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/configuration/z-probe/beacon.cfg b/configuration/z-probe/beacon.cfg index f306eb330..9a6158682 100644 --- a/configuration/z-probe/beacon.cfg +++ b/configuration/z-probe/beacon.cfg @@ -21,6 +21,11 @@ speed: 15. lift_speed: 80. contact_max_hotend_temperature: 275 +##### +# BEACON MESH +##### +[beacon_mesh] + # TODO: remove when automatically calculated by configurator [bed_mesh] mesh_min: 20,30