aboutsummaryrefslogtreecommitdiffstats
path: root/klippy/extras/bed_mesh.py
diff options
context:
space:
mode:
Diffstat (limited to 'klippy/extras/bed_mesh.py')
-rw-r--r--klippy/extras/bed_mesh.py934
1 files changed, 535 insertions, 399 deletions
diff --git a/klippy/extras/bed_mesh.py b/klippy/extras/bed_mesh.py
index a8e5764c..921b6296 100644
--- a/klippy/extras/bed_mesh.py
+++ b/klippy/extras/bed_mesh.py
@@ -8,56 +8,74 @@ from . import probe
PROFILE_VERSION = 1
PROFILE_OPTIONS = {
- 'min_x': float, 'max_x': float, 'min_y': float, 'max_y': float,
- 'x_count': int, 'y_count': int, 'mesh_x_pps': int, 'mesh_y_pps': int,
- 'algo': str, 'tension': float
+ "min_x": float,
+ "max_x": float,
+ "min_y": float,
+ "max_y": float,
+ "x_count": int,
+ "y_count": int,
+ "mesh_x_pps": int,
+ "mesh_y_pps": int,
+ "algo": str,
+ "tension": float,
}
+
class BedMeshError(Exception):
pass
+
# PEP 485 isclose()
def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
- return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
+ return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
+
# return true if a coordinate is within the region
# specified by min_c and max_c
def within(coord, min_c, max_c, tol=0.0):
- return (max_c[0] + tol) >= coord[0] >= (min_c[0] - tol) and \
- (max_c[1] + tol) >= coord[1] >= (min_c[1] - tol)
+ return (max_c[0] + tol) >= coord[0] >= (min_c[0] - tol) and (
+ max_c[1] + tol
+ ) >= coord[1] >= (min_c[1] - tol)
+
# Constrain value between min and max
def constrain(val, min_val, max_val):
return min(max_val, max(min_val, val))
+
# Linear interpolation between two values
def lerp(t, v0, v1):
- return (1. - t) * v0 + t * v1
+ return (1.0 - t) * v0 + t * v1
+
# retrieve comma separated pair from config
def parse_config_pair(config, option, default, minval=None, maxval=None):
pair = config.getintlist(option, (default, default))
if len(pair) != 2:
if len(pair) != 1:
- raise config.error("bed_mesh: malformed '%s' value: %s"
- % (option, config.get(option)))
+ raise config.error(
+ "bed_mesh: malformed '%s' value: %s" % (option, config.get(option))
+ )
pair = (pair[0], pair[0])
if minval is not None:
if pair[0] < minval or pair[1] < minval:
raise config.error(
"Option '%s' in section bed_mesh must have a minimum of %s"
- % (option, str(minval)))
+ % (option, str(minval))
+ )
if maxval is not None:
if pair[0] > maxval or pair[1] > maxval:
raise config.error(
"Option '%s' in section bed_mesh must have a maximum of %s"
- % (option, str(maxval)))
+ % (option, str(maxval))
+ )
return pair
+
# retrieve comma separated pair from a g-code command
def parse_gcmd_pair(gcmd, name, minval=None, maxval=None):
try:
- pair = [int(v.strip()) for v in gcmd.get(name).split(',')]
+ pair = [int(v.strip()) for v in gcmd.get(name).split(",")]
except:
raise gcmd.error("Unable to parse parameter '%s'" % (name,))
if len(pair) != 2:
@@ -66,18 +84,21 @@ def parse_gcmd_pair(gcmd, name, minval=None, maxval=None):
pair = (pair[0], pair[0])
if minval is not None:
if pair[0] < minval or pair[1] < minval:
- raise gcmd.error("Parameter '%s' must have a minimum of %d"
- % (name, minval))
+ raise gcmd.error(
+ "Parameter '%s' must have a minimum of %d" % (name, minval)
+ )
if maxval is not None:
if pair[0] > maxval or pair[1] > maxval:
- raise gcmd.error("Parameter '%s' must have a maximum of %d"
- % (name, maxval))
+ raise gcmd.error(
+ "Parameter '%s' must have a maximum of %d" % (name, maxval)
+ )
return pair
+
# retrieve comma separated coordinate from a g-code command
def parse_gcmd_coord(gcmd, name):
try:
- v1, v2 = [float(v.strip()) for v in gcmd.get(name).split(',')]
+ v1, v2 = [float(v.strip()) for v in gcmd.get(name).split(",")]
except:
raise gcmd.error("Unable to parse parameter '%s'" % (name,))
return v1, v2
@@ -85,55 +106,59 @@ def parse_gcmd_coord(gcmd, name):
class BedMesh:
FADE_DISABLE = 0x7FFFFFFF
+
def __init__(self, config):
self.printer = config.get_printer()
- self.printer.register_event_handler("klippy:connect",
- self.handle_connect)
- self.last_position = [0., 0., 0., 0.]
+ self.printer.register_event_handler("klippy:connect", self.handle_connect)
+ self.last_position = [0.0, 0.0, 0.0, 0.0]
self.bmc = BedMeshCalibrate(config, self)
self.z_mesh = None
self.toolhead = None
- self.horizontal_move_z = config.getfloat('horizontal_move_z', 5.)
- self.fade_start = config.getfloat('fade_start', 1.)
- self.fade_end = config.getfloat('fade_end', 0.)
+ self.horizontal_move_z = config.getfloat("horizontal_move_z", 5.0)
+ self.fade_start = config.getfloat("fade_start", 1.0)
+ self.fade_end = config.getfloat("fade_end", 0.0)
self.fade_dist = self.fade_end - self.fade_start
- if self.fade_dist <= 0.:
+ if self.fade_dist <= 0.0:
self.fade_start = self.fade_end = self.FADE_DISABLE
self.log_fade_complete = False
- self.base_fade_target = config.getfloat('fade_target', None)
- self.fade_target = 0.
- self.tool_offset = 0.
- self.gcode = self.printer.lookup_object('gcode')
+ self.base_fade_target = config.getfloat("fade_target", None)
+ self.fade_target = 0.0
+ self.tool_offset = 0.0
+ self.gcode = self.printer.lookup_object("gcode")
self.splitter = MoveSplitter(config, self.gcode)
# setup persistent storage
self.pmgr = ProfileManager(config, self)
self.save_profile = self.pmgr.save_profile
# register gcodes
self.gcode.register_command(
- 'BED_MESH_OUTPUT', self.cmd_BED_MESH_OUTPUT,
- desc=self.cmd_BED_MESH_OUTPUT_help)
+ "BED_MESH_OUTPUT",
+ self.cmd_BED_MESH_OUTPUT,
+ desc=self.cmd_BED_MESH_OUTPUT_help,
+ )
self.gcode.register_command(
- 'BED_MESH_MAP', self.cmd_BED_MESH_MAP,
- desc=self.cmd_BED_MESH_MAP_help)
+ "BED_MESH_MAP", self.cmd_BED_MESH_MAP, desc=self.cmd_BED_MESH_MAP_help
+ )
self.gcode.register_command(
- 'BED_MESH_CLEAR', self.cmd_BED_MESH_CLEAR,
- desc=self.cmd_BED_MESH_CLEAR_help)
+ "BED_MESH_CLEAR", self.cmd_BED_MESH_CLEAR, desc=self.cmd_BED_MESH_CLEAR_help
+ )
self.gcode.register_command(
- 'BED_MESH_OFFSET', self.cmd_BED_MESH_OFFSET,
- desc=self.cmd_BED_MESH_OFFSET_help)
- # Register dump webhooks
- webhooks = self.printer.lookup_object('webhooks')
- webhooks.register_endpoint(
- "bed_mesh/dump_mesh", self._handle_dump_request
+ "BED_MESH_OFFSET",
+ self.cmd_BED_MESH_OFFSET,
+ desc=self.cmd_BED_MESH_OFFSET_help,
)
+ # Register dump webhooks
+ webhooks = self.printer.lookup_object("webhooks")
+ webhooks.register_endpoint("bed_mesh/dump_mesh", self._handle_dump_request)
# Register transform
- gcode_move = self.printer.load_object(config, 'gcode_move')
+ gcode_move = self.printer.load_object(config, "gcode_move")
gcode_move.set_move_transform(self)
# initialize status dict
self.update_status()
+
def handle_connect(self):
- self.toolhead = self.printer.lookup_object('toolhead')
+ self.toolhead = self.printer.lookup_object("toolhead")
self.bmc.print_generated_points(logging.info, truncate=True)
+
def set_mesh(self, mesh):
if mesh is not None and self.fade_end != self.FADE_DISABLE:
self.log_fade_complete = True
@@ -142,42 +167,45 @@ class BedMesh:
else:
self.fade_target = self.base_fade_target
min_z, max_z = mesh.get_z_range()
- if (not min_z <= self.fade_target <= max_z and
- self.fade_target != 0.):
+ if not min_z <= self.fade_target <= max_z and self.fade_target != 0.0:
# fade target is non-zero, out of mesh range
err_target = self.fade_target
self.z_mesh = None
- self.fade_target = 0.
+ self.fade_target = 0.0
raise self.gcode.error(
"bed_mesh: ERROR, fade_target lies outside of mesh z "
"range\nmin: %.4f, max: %.4f, fade_target: %.4f"
- % (min_z, max_z, err_target))
+ % (min_z, max_z, err_target)
+ )
min_z, max_z = mesh.get_z_range()
if self.fade_dist <= max(abs(min_z), abs(max_z)):
self.z_mesh = None
- self.fade_target = 0.
+ self.fade_target = 0.0
raise self.gcode.error(
"bed_mesh: Mesh extends outside of the fade range, "
"please see the fade_start and fade_end options in"
"example-extras.cfg. fade distance: %.2f mesh min: %.4f"
- "mesh max: %.4f" % (self.fade_dist, min_z, max_z))
+ "mesh max: %.4f" % (self.fade_dist, min_z, max_z)
+ )
else:
- self.fade_target = 0.
- self.tool_offset = 0.
+ self.fade_target = 0.0
+ self.tool_offset = 0.0
self.z_mesh = mesh
self.splitter.initialize(mesh, self.fade_target)
# cache the current position before a transform takes place
- gcode_move = self.printer.lookup_object('gcode_move')
+ gcode_move = self.printer.lookup_object("gcode_move")
gcode_move.reset_last_position()
self.update_status()
+
def get_z_factor(self, z_pos):
z_pos += self.tool_offset
if z_pos >= self.fade_end:
- return 0.
+ return 0.0
elif z_pos >= self.fade_start:
return (self.fade_end - z_pos) / self.fade_dist
else:
- return 1.
+ return 1.0
+
def get_position(self):
# Return last, non-transformed position
if self.z_mesh is None:
@@ -189,22 +217,24 @@ class BedMesh:
cur_pos = self.toolhead.get_position()
x, y, z = cur_pos[:3]
max_adj = self.z_mesh.calc_z(x, y)
- factor = 1.
+ factor = 1.0
z_adj = max_adj - self.fade_target
fade_z_pos = z + self.tool_offset
if min(fade_z_pos, (fade_z_pos - max_adj)) >= self.fade_end:
# Fade out is complete, no factor
- factor = 0.
+ factor = 0.0
elif max(fade_z_pos, (fade_z_pos - max_adj)) >= self.fade_start:
# Likely in the process of fading out adjustment.
# Because we don't yet know the gcode z position, use
# algebra to calculate the factor from the toolhead pos
- factor = ((self.fade_end + self.fade_target - fade_z_pos) /
- (self.fade_dist - z_adj))
- factor = constrain(factor, 0., 1.)
+ factor = (self.fade_end + self.fade_target - fade_z_pos) / (
+ self.fade_dist - z_adj
+ )
+ factor = constrain(factor, 0.0, 1.0)
final_z_adj = factor * z_adj + self.fade_target
self.last_position[:] = [x, y, z - final_z_adj] + cur_pos[3:]
return list(self.last_position)
+
def move(self, newpos, speed):
factor = self.get_z_factor(newpos[2])
if self.z_mesh is None or not factor:
@@ -214,7 +244,8 @@ class BedMesh:
self.log_fade_complete = False
logging.info(
"bed_mesh fade complete: Current Z: %.4f fade_target: %.4f "
- % (z, self.fade_target))
+ % (z, self.fade_target)
+ )
self.toolhead.move([x, y, z + self.fade_target] + newpos[3:], speed)
else:
self.splitter.build_move(self.last_position, newpos, factor)
@@ -223,36 +254,40 @@ class BedMesh:
if split_move:
self.toolhead.move(split_move, speed)
else:
- raise self.gcode.error(
- "Mesh Leveling: Error splitting move ")
+ raise self.gcode.error("Mesh Leveling: Error splitting move ")
self.last_position[:] = newpos
+
def get_status(self, eventtime=None):
return self.status
+
def update_status(self):
self.status = {
"profile_name": "",
- "mesh_min": (0., 0.),
- "mesh_max": (0., 0.),
+ "mesh_min": (0.0, 0.0),
+ "mesh_max": (0.0, 0.0),
"probed_matrix": [[]],
"mesh_matrix": [[]],
- "profiles": self.pmgr.get_profiles()
+ "profiles": self.pmgr.get_profiles(),
}
if self.z_mesh is not None:
params = self.z_mesh.get_mesh_params()
- mesh_min = (params['min_x'], params['min_y'])
- mesh_max = (params['max_x'], params['max_y'])
+ mesh_min = (params["min_x"], params["min_y"])
+ mesh_max = (params["max_x"], params["max_y"])
probed_matrix = self.z_mesh.get_probed_matrix()
mesh_matrix = self.z_mesh.get_mesh_matrix()
- self.status['profile_name'] = self.z_mesh.get_profile_name()
- self.status['mesh_min'] = mesh_min
- self.status['mesh_max'] = mesh_max
- self.status['probed_matrix'] = probed_matrix
- self.status['mesh_matrix'] = mesh_matrix
+ self.status["profile_name"] = self.z_mesh.get_profile_name()
+ self.status["mesh_min"] = mesh_min
+ self.status["mesh_max"] = mesh_max
+ self.status["probed_matrix"] = probed_matrix
+ self.status["mesh_matrix"] = mesh_matrix
+
def get_mesh(self):
return self.z_mesh
+
cmd_BED_MESH_OUTPUT_help = "Retrieve interpolated grid of probed z-points"
+
def cmd_BED_MESH_OUTPUT(self, gcmd):
- if gcmd.get_int('PGP', 0):
+ if gcmd.get_int("PGP", 0):
# Print Generated Points instead of mesh
self.bmc.print_generated_points(gcmd.respond_info)
elif self.z_mesh is None:
@@ -260,34 +295,42 @@ class BedMesh:
else:
self.z_mesh.print_probed_matrix(gcmd.respond_info)
self.z_mesh.print_mesh(gcmd.respond_raw, self.horizontal_move_z)
+
cmd_BED_MESH_MAP_help = "Serialize mesh and output to terminal"
+
def cmd_BED_MESH_MAP(self, gcmd):
if self.z_mesh is not None:
params = self.z_mesh.get_mesh_params()
outdict = {
- 'mesh_min': (params['min_x'], params['min_y']),
- 'mesh_max': (params['max_x'], params['max_y']),
- 'z_positions': self.z_mesh.get_probed_matrix()}
+ "mesh_min": (params["min_x"], params["min_y"]),
+ "mesh_max": (params["max_x"], params["max_y"]),
+ "z_positions": self.z_mesh.get_probed_matrix(),
+ }
gcmd.respond_raw("mesh_map_output " + json.dumps(outdict))
else:
gcmd.respond_info("Bed has not been probed")
+
cmd_BED_MESH_CLEAR_help = "Clear the Mesh so no z-adjustment is made"
+
def cmd_BED_MESH_CLEAR(self, gcmd):
self.set_mesh(None)
+
cmd_BED_MESH_OFFSET_help = "Add X/Y offsets to the mesh lookup"
+
def cmd_BED_MESH_OFFSET(self, gcmd):
if self.z_mesh is not None:
offsets = [None, None]
- for i, axis in enumerate(['X', 'Y']):
+ for i, axis in enumerate(["X", "Y"]):
offsets[i] = gcmd.get_float(axis, None)
self.z_mesh.set_mesh_offsets(offsets)
tool_offset = gcmd.get_float("ZFADE", None)
if tool_offset is not None:
self.tool_offset = tool_offset
- gcode_move = self.printer.lookup_object('gcode_move')
+ gcode_move = self.printer.lookup_object("gcode_move")
gcode_move.reset_last_position()
else:
gcmd.respond_info("No mesh loaded to offset")
+
def _handle_dump_request(self, web_request):
eventtime = self.printer.get_reactor().monotonic()
prb = self.printer.lookup_object("probe", None)
@@ -298,7 +341,7 @@ class BedMesh:
"name": self.z_mesh.get_profile_name(),
"probed_matrix": self.z_mesh.get_probed_matrix(),
"mesh_matrix": self.z_mesh.get_mesh_matrix(),
- "mesh_params": self.z_mesh.get_mesh_params()
+ "mesh_params": self.z_mesh.get_mesh_params(),
}
mesh_args = web_request.get_dict("mesh_args", {})
gcmd = None
@@ -317,43 +360,43 @@ class BedMesh:
class ZrefMode:
DISABLED = 0 # Zero reference disabled
- IN_MESH = 1 # Zero reference position within mesh
- PROBE = 2 # Zero refrennce position outside of mesh, probe needed
+ IN_MESH = 1 # Zero reference position within mesh
+ PROBE = 2 # Zero refrennce position outside of mesh, probe needed
class BedMeshCalibrate:
- ALGOS = ['lagrange', 'bicubic']
+ ALGOS = ["lagrange", "bicubic"]
+
def __init__(self, config, bedmesh):
self.printer = config.get_printer()
- self.orig_config = {'radius': None, 'origin': None}
+ self.orig_config = {"radius": None, "origin": None}
self.radius = self.origin = None
- self.mesh_min = self.mesh_max = (0., 0.)
- self.adaptive_margin = config.getfloat('adaptive_margin', 0.0)
+ self.mesh_min = self.mesh_max = (0.0, 0.0)
+ self.adaptive_margin = config.getfloat("adaptive_margin", 0.0)
self.bedmesh = bedmesh
self.mesh_config = collections.OrderedDict()
self._init_mesh_config(config)
- self.probe_mgr = ProbeManager(
- config, self.orig_config, self.probe_finalize
- )
+ self.probe_mgr = ProbeManager(config, self.orig_config, self.probe_finalize)
try:
self.probe_mgr.generate_points(
- self.mesh_config, self.mesh_min, self.mesh_max,
- self.radius, self.origin
+ self.mesh_config, self.mesh_min, self.mesh_max, self.radius, self.origin
)
except BedMeshError as e:
raise config.error(str(e))
self._profile_name = "default"
- self.gcode = self.printer.lookup_object('gcode')
+ self.gcode = self.printer.lookup_object("gcode")
self.gcode.register_command(
- 'BED_MESH_CALIBRATE', self.cmd_BED_MESH_CALIBRATE,
- desc=self.cmd_BED_MESH_CALIBRATE_help)
+ "BED_MESH_CALIBRATE",
+ self.cmd_BED_MESH_CALIBRATE,
+ desc=self.cmd_BED_MESH_CALIBRATE_help,
+ )
+
def print_generated_points(self, print_func, truncate=False):
- x_offset = y_offset = 0.
- probe = self.printer.lookup_object('probe', None)
+ x_offset = y_offset = 0.0
+ probe = self.printer.lookup_object("probe", None)
if probe is not None:
x_offset, y_offset = probe.get_offsets()[:2]
- print_func("bed_mesh: generated points\nIndex"
- " | Tool Adjusted | Probe")
+ print_func("bed_mesh: generated points\nIndex" " | Tool Adjusted | Probe")
points = self.probe_mgr.get_base_points()
for i, (x, y) in enumerate(points):
if i >= 50 and truncate:
@@ -362,8 +405,7 @@ class BedMeshCalibrate:
break
adj_pt = "(%.1f, %.1f)" % (x - x_offset, y - y_offset)
mesh_pt = "(%.1f, %.1f)" % (x, y)
- print_func(
- " %-4d| %-16s| %s" % (i, adj_pt, mesh_pt))
+ print_func(" %-4d| %-16s| %s" % (i, adj_pt, mesh_pt))
zero_ref_pos = self.probe_mgr.get_zero_ref_pos()
if zero_ref_pos is not None:
print_func(
@@ -375,83 +417,90 @@ class BedMeshCalibrate:
print_func("bed_mesh: faulty region points")
for i, v in substitutes.items():
pt = points[i]
- print_func("%d (%.2f, %.2f), substituted points: %s"
- % (i, pt[0], pt[1], repr(v)))
+ print_func(
+ "%d (%.2f, %.2f), substituted points: %s"
+ % (i, pt[0], pt[1], repr(v))
+ )
+
def _init_mesh_config(self, config):
mesh_cfg = self.mesh_config
orig_cfg = self.orig_config
- self.radius = config.getfloat('mesh_radius', None, above=0.)
+ self.radius = config.getfloat("mesh_radius", None, above=0.0)
if self.radius is not None:
- self.origin = config.getfloatlist('mesh_origin', (0., 0.), count=2)
- x_cnt = y_cnt = config.getint('round_probe_count', 5, minval=3)
+ self.origin = config.getfloatlist("mesh_origin", (0.0, 0.0), count=2)
+ x_cnt = y_cnt = config.getint("round_probe_count", 5, minval=3)
# round beds must have an odd number of points along each axis
if not x_cnt & 1:
- raise config.error(
- "bed_mesh: probe_count must be odd for round beds")
+ raise config.error("bed_mesh: probe_count must be odd for round beds")
# radius may have precision to .1mm
self.radius = math.floor(self.radius * 10) / 10
- orig_cfg['radius'] = self.radius
- orig_cfg['origin'] = self.origin
+ orig_cfg["radius"] = self.radius
+ orig_cfg["origin"] = self.origin
min_x = min_y = -self.radius
max_x = max_y = self.radius
else:
# rectangular
- x_cnt, y_cnt = parse_config_pair(config, 'probe_count', 3, minval=3)
- min_x, min_y = config.getfloatlist('mesh_min', count=2)
- max_x, max_y = config.getfloatlist('mesh_max', count=2)
+ x_cnt, y_cnt = parse_config_pair(config, "probe_count", 3, minval=3)
+ min_x, min_y = config.getfloatlist("mesh_min", count=2)
+ max_x, max_y = config.getfloatlist("mesh_max", count=2)
if max_x <= min_x or max_y <= min_y:
- raise config.error('bed_mesh: invalid min/max points')
- orig_cfg['x_count'] = mesh_cfg['x_count'] = x_cnt
- orig_cfg['y_count'] = mesh_cfg['y_count'] = y_cnt
- orig_cfg['mesh_min'] = self.mesh_min = (min_x, min_y)
- orig_cfg['mesh_max'] = self.mesh_max = (max_x, max_y)
+ raise config.error("bed_mesh: invalid min/max points")
+ orig_cfg["x_count"] = mesh_cfg["x_count"] = x_cnt
+ orig_cfg["y_count"] = mesh_cfg["y_count"] = y_cnt
+ orig_cfg["mesh_min"] = self.mesh_min = (min_x, min_y)
+ orig_cfg["mesh_max"] = self.mesh_max = (max_x, max_y)
- pps = parse_config_pair(config, 'mesh_pps', 2, minval=0)
- orig_cfg['mesh_x_pps'] = mesh_cfg['mesh_x_pps'] = pps[0]
- orig_cfg['mesh_y_pps'] = mesh_cfg['mesh_y_pps'] = pps[1]
- orig_cfg['algo'] = mesh_cfg['algo'] = \
- config.get('algorithm', 'lagrange').strip().lower()
- orig_cfg['tension'] = mesh_cfg['tension'] = config.getfloat(
- 'bicubic_tension', .2, minval=0., maxval=2.)
+ pps = parse_config_pair(config, "mesh_pps", 2, minval=0)
+ orig_cfg["mesh_x_pps"] = mesh_cfg["mesh_x_pps"] = pps[0]
+ orig_cfg["mesh_y_pps"] = mesh_cfg["mesh_y_pps"] = pps[1]
+ orig_cfg["algo"] = mesh_cfg["algo"] = (
+ config.get("algorithm", "lagrange").strip().lower()
+ )
+ orig_cfg["tension"] = mesh_cfg["tension"] = config.getfloat(
+ "bicubic_tension", 0.2, minval=0.0, maxval=2.0
+ )
self._verify_algorithm(config.error)
+
def _verify_algorithm(self, error):
params = self.mesh_config
- x_pps = params['mesh_x_pps']
- y_pps = params['mesh_y_pps']
- if params['algo'] not in self.ALGOS:
- raise error(
- "bed_mesh: Unknown algorithm <%s>"
- % (self.mesh_config['algo']))
+ x_pps = params["mesh_x_pps"]
+ y_pps = params["mesh_y_pps"]
+ if params["algo"] not in self.ALGOS:
+ raise error("bed_mesh: Unknown algorithm <%s>" % (self.mesh_config["algo"]))
# Check the algorithm against the current configuration
- max_probe_cnt = max(params['x_count'], params['y_count'])
- min_probe_cnt = min(params['x_count'], params['y_count'])
+ max_probe_cnt = max(params["x_count"], params["y_count"])
+ min_probe_cnt = min(params["x_count"], params["y_count"])
if max(x_pps, y_pps) == 0:
# Interpolation disabled
- self.mesh_config['algo'] = 'direct'
- elif params['algo'] == 'lagrange' and max_probe_cnt > 6:
+ self.mesh_config["algo"] = "direct"
+ elif params["algo"] == "lagrange" and max_probe_cnt > 6:
# Lagrange interpolation tends to oscillate when using more
# than 6 samples
raise error(
"bed_mesh: cannot exceed a probe_count of 6 when using "
- "lagrange interpolation. Configured Probe Count: %d, %d" %
- (self.mesh_config['x_count'], self.mesh_config['y_count']))
- elif params['algo'] == 'bicubic' and min_probe_cnt < 4:
+ "lagrange interpolation. Configured Probe Count: %d, %d"
+ % (self.mesh_config["x_count"], self.mesh_config["y_count"])
+ )
+ elif params["algo"] == "bicubic" and min_probe_cnt < 4:
if max_probe_cnt > 6:
raise error(
"bed_mesh: invalid probe_count option when using bicubic "
"interpolation. Combination of 3 points on one axis with "
"more than 6 on another is not permitted. "
- "Configured Probe Count: %d, %d" %
- (self.mesh_config['x_count'], self.mesh_config['y_count']))
+ "Configured Probe Count: %d, %d"
+ % (self.mesh_config["x_count"], self.mesh_config["y_count"])
+ )
else:
logging.info(
"bed_mesh: bicubic interpolation with a probe_count of "
"less than 4 points detected. Forcing lagrange "
- "interpolation. Configured Probe Count: %d, %d" %
- (self.mesh_config['x_count'], self.mesh_config['y_count']))
- params['algo'] = 'lagrange'
+ "interpolation. Configured Probe Count: %d, %d"
+ % (self.mesh_config["x_count"], self.mesh_config["y_count"])
+ )
+ params["algo"] = "lagrange"
+
def set_adaptive_mesh(self, gcmd):
- if not gcmd.get_int('ADAPTIVE', 0):
+ if not gcmd.get_int("ADAPTIVE", 0):
return False
exclude_objects = self.printer.lookup_object("exclude_object", None)
if exclude_objects is None:
@@ -460,7 +509,7 @@ class BedMeshCalibrate:
objects = exclude_objects.get_status().get("objects", [])
if not objects:
return False
- margin = gcmd.get_float('ADAPTIVE_MARGIN', self.adaptive_margin)
+ margin = gcmd.get_float("ADAPTIVE_MARGIN", self.adaptive_margin)
# List all exclude_object points by axis and iterate over
# all polygon points, and pick the min and max or each axis
@@ -479,68 +528,83 @@ class BedMeshCalibrate:
adjusted_mesh_max = [x + margin for x in mesh_max]
# Force margin to respect original mesh bounds
- adjusted_mesh_min[0] = max(adjusted_mesh_min[0],
- self.orig_config["mesh_min"][0])
- adjusted_mesh_min[1] = max(adjusted_mesh_min[1],
- self.orig_config["mesh_min"][1])
- adjusted_mesh_max[0] = min(adjusted_mesh_max[0],
- self.orig_config["mesh_max"][0])
- adjusted_mesh_max[1] = min(adjusted_mesh_max[1],
- self.orig_config["mesh_max"][1])
+ adjusted_mesh_min[0] = max(
+ adjusted_mesh_min[0], self.orig_config["mesh_min"][0]
+ )
+ adjusted_mesh_min[1] = max(
+ adjusted_mesh_min[1], self.orig_config["mesh_min"][1]
+ )
+ adjusted_mesh_max[0] = min(
+ adjusted_mesh_max[0], self.orig_config["mesh_max"][0]
+ )
+ adjusted_mesh_max[1] = min(
+ adjusted_mesh_max[1], self.orig_config["mesh_max"][1]
+ )
- adjusted_mesh_size = (adjusted_mesh_max[0] - adjusted_mesh_min[0],
- adjusted_mesh_max[1] - adjusted_mesh_min[1])
+ adjusted_mesh_size = (
+ adjusted_mesh_max[0] - adjusted_mesh_min[0],
+ adjusted_mesh_max[1] - adjusted_mesh_min[1],
+ )
# Compute a ratio between the adapted and original sizes
- ratio = (adjusted_mesh_size[0] /
- (self.orig_config["mesh_max"][0] -
- self.orig_config["mesh_min"][0]),
- adjusted_mesh_size[1] /
- (self.orig_config["mesh_max"][1] -
- self.orig_config["mesh_min"][1]))
+ ratio = (
+ adjusted_mesh_size[0]
+ / (self.orig_config["mesh_max"][0] - self.orig_config["mesh_min"][0]),
+ adjusted_mesh_size[1]
+ / (self.orig_config["mesh_max"][1] - self.orig_config["mesh_min"][1]),
+ )
- gcmd.respond_info("Original mesh bounds: (%s,%s)" %
- (self.orig_config["mesh_min"],
- self.orig_config["mesh_max"]))
- gcmd.respond_info("Original probe count: (%s,%s)" %
- (self.mesh_config["x_count"],
- self.mesh_config["y_count"]))
- gcmd.respond_info("Adapted mesh bounds: (%s,%s)" %
- (adjusted_mesh_min, adjusted_mesh_max))
+ gcmd.respond_info(
+ "Original mesh bounds: (%s,%s)"
+ % (self.orig_config["mesh_min"], self.orig_config["mesh_max"])
+ )
+ gcmd.respond_info(
+ "Original probe count: (%s,%s)"
+ % (self.mesh_config["x_count"], self.mesh_config["y_count"])
+ )
+ gcmd.respond_info(
+ "Adapted mesh bounds: (%s,%s)" % (adjusted_mesh_min, adjusted_mesh_max)
+ )
gcmd.respond_info("Ratio: (%s, %s)" % ratio)
- new_x_probe_count = int(
- math.ceil(self.mesh_config["x_count"] * ratio[0]))
- new_y_probe_count = int(
- math.ceil(self.mesh_config["y_count"] * ratio[1]))
+ new_x_probe_count = int(math.ceil(self.mesh_config["x_count"] * ratio[0]))
+ new_y_probe_count = int(math.ceil(self.mesh_config["y_count"] * ratio[1]))
# There is one case, where we may have to adjust the probe counts:
# axis0 < 4 and axis1 > 6 (see _verify_algorithm).
min_num_of_probes = 3
- if max(new_x_probe_count, new_y_probe_count) > 6 and \
- min(new_x_probe_count, new_y_probe_count) < 4:
+ if (
+ max(new_x_probe_count, new_y_probe_count) > 6
+ and min(new_x_probe_count, new_y_probe_count) < 4
+ ):
min_num_of_probes = 4
new_x_probe_count = max(min_num_of_probes, new_x_probe_count)
new_y_probe_count = max(min_num_of_probes, new_y_probe_count)
- gcmd.respond_info("Adapted probe count: (%s,%s)" %
- (new_x_probe_count, new_y_probe_count))
+ gcmd.respond_info(
+ "Adapted probe count: (%s,%s)" % (new_x_probe_count, new_y_probe_count)
+ )
# If the adapted mesh size is too small, adjust it to something
# useful.
- adjusted_mesh_size = (max(adjusted_mesh_size[0], new_x_probe_count),
- max(adjusted_mesh_size[1], new_y_probe_count))
+ adjusted_mesh_size = (
+ max(adjusted_mesh_size[0], new_x_probe_count),
+ max(adjusted_mesh_size[1], new_y_probe_count),
+ )
if self.radius is not None:
- adapted_radius = math.sqrt((adjusted_mesh_size[0] ** 2) +
- (adjusted_mesh_size[1] ** 2)) / 2
- adapted_origin = (adjusted_mesh_min[0] +
- (adjusted_mesh_size[0] / 2),
- adjusted_mesh_min[1] +
- (adjusted_mesh_size[1] / 2))
- to_adapted_origin = math.sqrt(adapted_origin[0]**2 +
- adapted_origin[1]**2)
+ adapted_radius = (
+ math.sqrt((adjusted_mesh_size[0] ** 2) + (adjusted_mesh_size[1] ** 2))
+ / 2
+ )
+ adapted_origin = (
+ adjusted_mesh_min[0] + (adjusted_mesh_size[0] / 2),
+ adjusted_mesh_min[1] + (adjusted_mesh_size[1] / 2),
+ )
+ to_adapted_origin = math.sqrt(
+ adapted_origin[0] ** 2 + adapted_origin[1] ** 2
+ )
# If the adapted mesh size is smaller than the default/full
# mesh, adjust the parameters. Otherwise, just do the full mesh.
if adapted_radius + to_adapted_origin < self.radius:
@@ -551,8 +615,9 @@ class BedMeshCalibrate:
new_probe_count = max(new_x_probe_count, new_y_probe_count)
# Adaptive meshes require odd number of points
new_probe_count += 1 - (new_probe_count % 2)
- self.mesh_config["x_count"] = self.mesh_config["y_count"] = \
- new_probe_count
+ self.mesh_config["x_count"] = self.mesh_config["y_count"] = (
+ new_probe_count
+ )
else:
self.mesh_min = adjusted_mesh_min
self.mesh_max = adjusted_mesh_max
@@ -560,12 +625,13 @@ class BedMeshCalibrate:
self.mesh_config["y_count"] = new_y_probe_count
self._profile_name = None
return True
+
def update_config(self, gcmd):
# reset default configuration
- self.radius = self.orig_config['radius']
- self.origin = self.orig_config['origin']
- self.mesh_min = self.orig_config['mesh_min']
- self.mesh_max = self.orig_config['mesh_max']
+ self.radius = self.orig_config["radius"]
+ self.origin = self.orig_config["origin"]
+ self.mesh_min = self.orig_config["mesh_min"]
+ self.mesh_max = self.orig_config["mesh_max"]
for key in list(self.mesh_config.keys()):
self.mesh_config[key] = self.orig_config[key]
@@ -579,34 +645,34 @@ class BedMeshCalibrate:
self.mesh_max = (self.radius, self.radius)
need_cfg_update = True
if "MESH_ORIGIN" in params:
- self.origin = parse_gcmd_coord(gcmd, 'MESH_ORIGIN')
+ self.origin = parse_gcmd_coord(gcmd, "MESH_ORIGIN")
need_cfg_update = True
if "ROUND_PROBE_COUNT" in params:
- cnt = gcmd.get_int('ROUND_PROBE_COUNT', minval=3)
- self.mesh_config['x_count'] = cnt
- self.mesh_config['y_count'] = cnt
+ cnt = gcmd.get_int("ROUND_PROBE_COUNT", minval=3)
+ self.mesh_config["x_count"] = cnt
+ self.mesh_config["y_count"] = cnt
need_cfg_update = True
else:
if "MESH_MIN" in params:
- self.mesh_min = parse_gcmd_coord(gcmd, 'MESH_MIN')
+ self.mesh_min = parse_gcmd_coord(gcmd, "MESH_MIN")
need_cfg_update = True
if "MESH_MAX" in params:
- self.mesh_max = parse_gcmd_coord(gcmd, 'MESH_MAX')
+ self.mesh_max = parse_gcmd_coord(gcmd, "MESH_MAX")
need_cfg_update = True
if "PROBE_COUNT" in params:
- x_cnt, y_cnt = parse_gcmd_pair(gcmd, 'PROBE_COUNT', minval=3)
- self.mesh_config['x_count'] = x_cnt
- self.mesh_config['y_count'] = y_cnt
+ x_cnt, y_cnt = parse_gcmd_pair(gcmd, "PROBE_COUNT", minval=3)
+ self.mesh_config["x_count"] = x_cnt
+ self.mesh_config["y_count"] = y_cnt
need_cfg_update = True
if "MESH_PPS" in params:
- xpps, ypps = parse_gcmd_pair(gcmd, 'MESH_PPS', minval=0)
- self.mesh_config['mesh_x_pps'] = xpps
- self.mesh_config['mesh_y_pps'] = ypps
+ xpps, ypps = parse_gcmd_pair(gcmd, "MESH_PPS", minval=0)
+ self.mesh_config["mesh_x_pps"] = xpps
+ self.mesh_config["mesh_y_pps"] = ypps
need_cfg_update = True
if "ALGORITHM" in params:
- self.mesh_config['algo'] = gcmd.get('ALGORITHM').strip().lower()
+ self.mesh_config["algo"] = gcmd.get("ALGORITHM").strip().lower()
need_cfg_update = True
need_cfg_update |= self.set_adaptive_mesh(gcmd)
@@ -615,17 +681,25 @@ class BedMeshCalibrate:
if need_cfg_update:
self._verify_algorithm(gcmd.error)
self.probe_mgr.generate_points(
- self.mesh_config, self.mesh_min, self.mesh_max,
- self.radius, self.origin, probe_method
+ self.mesh_config,
+ self.mesh_min,
+ self.mesh_max,
+ self.radius,
+ self.origin,
+ probe_method,
)
- msg = "\n".join(["%s: %s" % (k, v)
- for k, v in self.mesh_config.items()])
+ msg = "\n".join(["%s: %s" % (k, v) for k, v in self.mesh_config.items()])
logging.info("Updated Mesh Configuration:\n" + msg)
else:
self.probe_mgr.generate_points(
- self.mesh_config, self.mesh_min, self.mesh_max,
- self.radius, self.origin, probe_method
+ self.mesh_config,
+ self.mesh_min,
+ self.mesh_max,
+ self.radius,
+ self.origin,
+ probe_method,
)
+
def dump_calibration(self, gcmd=None):
if gcmd is not None and gcmd.get_command_parameters():
self.update_config(gcmd)
@@ -638,11 +712,13 @@ class BedMeshCalibrate:
"points": self.probe_mgr.get_base_points(),
"config": cfg,
"probe_path": self.probe_mgr.get_std_path(),
- "rapid_path": list(self.probe_mgr.iter_rapid_path())
+ "rapid_path": list(self.probe_mgr.iter_rapid_path()),
}
+
cmd_BED_MESH_CALIBRATE_help = "Perform Mesh Bed Leveling"
+
def cmd_BED_MESH_CALIBRATE(self, gcmd):
- self._profile_name = gcmd.get('PROFILE', "default")
+ self._profile_name = gcmd.get("PROFILE", "default")
if not self._profile_name.strip():
raise gcmd.error("Value for parameter 'PROFILE' must be specified")
self.bedmesh.set_mesh(None)
@@ -651,26 +727,25 @@ class BedMeshCalibrate:
except BedMeshError as e:
raise gcmd.error(str(e))
self.probe_mgr.start_probe(gcmd)
+
def probe_finalize(self, offsets, positions):
z_offset = offsets[2]
- positions = [[round(p[0], 2), round(p[1], 2), p[2]]
- for p in positions]
+ positions = [[round(p[0], 2), round(p[1], 2), p[2]] for p in positions]
if self.probe_mgr.get_zero_ref_mode() == ZrefMode.PROBE:
ref_pos = positions.pop()
logging.info(
"bed_mesh: z-offset replaced with probed z value at "
- "position (%.2f, %.2f, %.6f)"
- % (ref_pos[0], ref_pos[1], ref_pos[2])
+ "position (%.2f, %.2f, %.6f)" % (ref_pos[0], ref_pos[1], ref_pos[2])
)
z_offset = ref_pos[2]
base_points = self.probe_mgr.get_base_points()
params = dict(self.mesh_config)
- params['min_x'] = min(base_points, key=lambda p: p[0])[0]
- params['max_x'] = max(base_points, key=lambda p: p[0])[0]
- params['min_y'] = min(base_points, key=lambda p: p[1])[1]
- params['max_y'] = max(base_points, key=lambda p: p[1])[1]
- x_cnt = params['x_count']
- y_cnt = params['y_count']
+ params["min_x"] = min(base_points, key=lambda p: p[0])[0]
+ params["max_x"] = max(base_points, key=lambda p: p[0])[0]
+ params["min_y"] = min(base_points, key=lambda p: p[1])[1]
+ params["max_y"] = max(base_points, key=lambda p: p[1])[1]
+ x_cnt = params["x_count"]
+ y_cnt = params["y_count"]
substitutes = self.probe_mgr.get_substitutes()
probed_pts = positions
@@ -687,15 +762,15 @@ class BedMeshCalibrate:
idx = i + idx_offset
# Add "normal" points
corrected_pts.extend(positions[start_idx:idx])
- avg_z = sum([p[2] for p in positions[idx:idx+len(pts)]]) \
- / len(pts)
+ avg_z = sum([p[2] for p in positions[idx : idx + len(pts)]]) / len(pts)
idx_offset += len(pts) - 1
start_idx = idx + len(pts)
fpt.append(avg_z)
logging.info(
"bed_mesh: Replacing value at faulty index %d"
" (%.4f, %.4f): avg value = %.6f, avg w/ z_offset = %.6f"
- % (i, fpt[0], fpt[1], avg_z, avg_z - z_offset))
+ % (i, fpt[0], fpt[1], avg_z, avg_z - z_offset)
+ )
corrected_pts.append(fpt)
corrected_pts.extend(positions[start_idx:])
positions = corrected_pts
@@ -714,9 +789,8 @@ class BedMeshCalibrate:
prev_pos = base_points[0]
for pos, result in zip(base_points, positions):
offset_pos = [p - o for p, o in zip(pos, offsets[:2])]
- if (
- not isclose(offset_pos[0], result[0], abs_tol=.5) or
- not isclose(offset_pos[1], result[1], abs_tol=.5)
+ if not isclose(offset_pos[0], result[0], abs_tol=0.5) or not isclose(
+ offset_pos[1], result[1], abs_tol=0.5
):
logging.info(
"bed_mesh: point deviation > .5mm: orig pt = (%.2f, %.2f)"
@@ -724,7 +798,7 @@ class BedMeshCalibrate:
% (offset_pos[0], offset_pos[1], result[0], result[1])
)
z_pos = result[2] - z_offset
- if not isclose(pos[1], prev_pos[1], abs_tol=.1):
+ if not isclose(pos[1], prev_pos[1], abs_tol=0.1):
# y has changed, append row and start new
probed_matrix.append(row)
row = []
@@ -741,9 +815,12 @@ class BedMeshCalibrate:
# make sure the y-axis is the correct length
if len(probed_matrix) != y_cnt:
raise self.gcode.error(
- ("bed_mesh: Invalid y-axis table length\n"
- "Probed table length: %d Probed Table:\n%s") %
- (len(probed_matrix), str(probed_matrix)))
+ (
+ "bed_mesh: Invalid y-axis table length\n"
+ "Probed table length: %d Probed Table:\n%s"
+ )
+ % (len(probed_matrix), str(probed_matrix))
+ )
if self.radius is not None:
# round bed, extrapolate probed values to create a square mesh
@@ -759,7 +836,7 @@ class BedMeshCalibrate:
if buf_cnt == 0:
continue
left_buffer = [row[0]] * buf_cnt
- right_buffer = [row[row_size-1]] * buf_cnt
+ right_buffer = [row[row_size - 1]] * buf_cnt
row[0:0] = left_buffer
row.extend(right_buffer)
@@ -767,9 +844,12 @@ class BedMeshCalibrate:
for row in probed_matrix:
if len(row) != x_cnt:
raise self.gcode.error(
- ("bed_mesh: invalid x-axis table length\n"
- "Probed table length: %d Probed Table:\n%s") %
- (len(probed_matrix), str(probed_matrix)))
+ (
+ "bed_mesh: invalid x-axis table length\n"
+ "Probed table length: %d Probed Table:\n%s"
+ )
+ % (len(probed_matrix), str(probed_matrix))
+ )
z_mesh = ZMesh(params, self._profile_name)
try:
@@ -786,6 +866,7 @@ class BedMeshCalibrate:
self.gcode.respond_info("Mesh Bed Leveling Complete")
if self._profile_name is not None:
self.bedmesh.save_profile(self._profile_name)
+
def _dump_points(self, probed_pts, corrected_pts, offsets):
# logs generated points with offset applied, points received
# from the finalize callback, and the list of corrected points
@@ -793,7 +874,8 @@ class BedMeshCalibrate:
max_len = max([len(points), len(probed_pts), len(corrected_pts)])
logging.info(
"bed_mesh: calibration point dump\nIndex | %-17s| %-25s|"
- " Corrected Point" % ("Generated Point", "Probed Point"))
+ " Corrected Point" % ("Generated Point", "Probed Point")
+ )
for i in list(range(max_len)):
gen_pt = probed_pt = corr_pt = ""
if i < len(points):
@@ -803,13 +885,13 @@ class BedMeshCalibrate:
probed_pt = "(%.2f, %.2f, %.4f)" % tuple(probed_pts[i])
if i < len(corrected_pts):
corr_pt = "(%.2f, %.2f, %.4f)" % tuple(corrected_pts[i])
- logging.info(
- " %-4d| %-17s| %-25s| %s" % (i, gen_pt, probed_pt, corr_pt))
+ logging.info(" %-4d| %-17s| %-25s| %s" % (i, gen_pt, probed_pt, corr_pt))
+
class ProbeManager:
def __init__(self, config, orig_config, finalize_cb):
self.printer = config.get_printer()
- self.cfg_overshoot = config.getfloat("scan_overshoot", 0, minval=1.)
+ self.cfg_overshoot = config.getfloat("scan_overshoot", 0, minval=1.0)
self.orig_config = orig_config
self.faulty_regions = []
self.overshoot = self.cfg_overshoot
@@ -827,8 +909,7 @@ class ProbeManager:
def _init_faulty_regions(self, config):
for i in list(range(1, 100, 1)):
- start = config.getfloatlist("faulty_region_%d_min" % (i,), None,
- count=2)
+ start = config.getfloatlist("faulty_region_%d_min" % (i,), None, count=2)
if start is None:
break
end = config.getfloatlist("faulty_region_%d_max" % (i,), count=2)
@@ -851,16 +932,16 @@ class ProbeManager:
raise config.error(
"bed_mesh: Existing faulty_region_%d %s overlaps "
"added faulty_region_%d %s"
- % (j+1, repr([prev_c1, prev_c3]),
- i, repr([c1, c3])))
+ % (j + 1, repr([prev_c1, prev_c3]), i, repr([c1, c3]))
+ )
# Validate that no new corner is within an existing region
for coord in [c1, c2, c3, c4]:
if within(coord, prev_c1, prev_c3):
raise config.error(
"bed_mesh: Added faulty_region_%d %s overlaps "
"existing faulty_region_%d %s"
- % (i, repr([c1, c3]),
- j+1, repr([prev_c1, prev_c3])))
+ % (i, repr([c1, c3]), j + 1, repr([prev_c1, prev_c3]))
+ )
self.faulty_regions.append((c1, c3))
def start_probe(self, gcmd):
@@ -885,11 +966,10 @@ class ProbeManager:
return self.substitutes
def generate_points(
- self, mesh_config, mesh_min, mesh_max, radius, origin,
- probe_method="automatic"
+ self, mesh_config, mesh_min, mesh_max, radius, origin, probe_method="automatic"
):
- x_cnt = mesh_config['x_count']
- y_cnt = mesh_config['y_count']
+ x_cnt = mesh_config["x_count"]
+ y_cnt = mesh_config["y_count"]
min_x, min_y = mesh_min
max_x, max_y = mesh_max
x_dist = (max_x - min_x) / (x_cnt - 1)
@@ -897,7 +977,7 @@ class ProbeManager:
# floor distances down to next hundredth
x_dist = math.floor(x_dist * 100) / 100
y_dist = math.floor(y_dist * 100) / 100
- if x_dist < 1. or y_dist < 1.:
+ if x_dist < 1.0 or y_dist < 1.0:
raise BedMeshError("bed_mesh: min/max points too close together")
if radius is not None:
@@ -924,10 +1004,9 @@ class ProbeManager:
points.append((pos_x, pos_y))
else:
# round bed, check distance from origin
- dist_from_origin = math.sqrt(pos_x*pos_x + pos_y*pos_y)
+ dist_from_origin = math.sqrt(pos_x * pos_x + pos_y * pos_y)
if dist_from_origin <= radius:
- points.append(
- (origin[0] + pos_x, origin[1] + pos_y))
+ points.append((origin[0] + pos_x, origin[1] + pos_y))
pos_y += y_dist
if self.zero_ref_pos is None or probe_method == "manual":
# Zero Reference Disabled
@@ -961,7 +1040,11 @@ class ProbeManager:
"bed_mesh: Cannot probe zero reference position at "
"(%.2f, %.2f) as it is located within a faulty region."
" Check the value for option '%s'"
- % (self.zero_ref_pos[0], self.zero_ref_pos[1], opt,)
+ % (
+ self.zero_ref_pos[0],
+ self.zero_ref_pos[1],
+ opt,
+ )
)
# Check to see if any points fall within faulty regions
last_y = self.base_points[0][1]
@@ -972,11 +1055,14 @@ class ProbeManager:
last_y = coord[1]
adj_coords = []
for min_c, max_c in self.faulty_regions:
- if within(coord, min_c, max_c, tol=.00001):
+ if within(coord, min_c, max_c, tol=0.00001):
# Point lies within a faulty region
adj_coords = [
- (min_c[0], coord[1]), (coord[0], min_c[1]),
- (coord[0], max_c[1]), (max_c[0], coord[1])]
+ (min_c[0], coord[1]),
+ (coord[0], min_c[1]),
+ (coord[0], max_c[1]),
+ (max_c[0], coord[1]),
+ ]
if is_reversed:
# Swap first and last points for zig-zag pattern
first = adj_coords[0]
@@ -990,10 +1076,10 @@ class ProbeManager:
for ac in adj_coords:
# make sure that coordinates are within the mesh boundary
if radius is None:
- if within(ac, min_pt, max_pt, .000001):
+ if within(ac, min_pt, max_pt, 0.000001):
valid_coords.append(ac)
else:
- dist_from_origin = math.sqrt(ac[0]*ac[0] + ac[1]*ac[1])
+ dist_from_origin = math.sqrt(ac[0] * ac[0] + ac[1] * ac[1])
if dist_from_origin <= radius:
valid_coords.append(ac)
if not valid_coords:
@@ -1030,9 +1116,7 @@ class ProbeManager:
# increasing Y indicates direction change
dir_change = not isclose(pt[1], last_base_pt[1], abs_tol=1e-6)
if idx in self.substitutes:
- fp_gen = self._gen_faulty_path(
- last_mv_pt, idx, ascnd_x, dir_change
- )
+ fp_gen = self._gen_faulty_path(last_mv_pt, idx, ascnd_x, dir_change)
for sub_pt, is_smp in fp_gen:
yield sub_pt, is_smp
last_mv_pt = sub_pt
@@ -1113,10 +1197,10 @@ class ProbeManager:
return
# overshoot X beyond the outer point
xdir = 1 if ascnd_x else -1
- overshoot = 2. if self.overshoot >= 3. else self.overshoot
+ overshoot = 2.0 if self.overshoot >= 3.0 else self.overshoot
ovr_pt = (last_pt[0] + overshoot * xdir, last_pt[1])
yield ovr_pt
- if self.overshoot < 3.:
+ if self.overshoot < 3.0:
# No room to generate an arc, move up to next y
yield (next_pt[0] + overshoot * xdir, next_pt[1])
else:
@@ -1130,17 +1214,16 @@ class ProbeManager:
origin = [ovr_pt[0], last_pt[1] + radius]
next_origin_y = next_pt[1] - radius
# determine angle
- if xdiff < .01:
+ if xdiff < 0.01:
# Move is aligned on the x-axis
angle = 90
- if next_origin_y - origin[1] < .05:
+ if next_origin_y - origin[1] < 0.05:
# The move can be completed in a single arc
angle = 180
else:
angle = int(math.degrees(math.atan(ydiff / xdiff)))
- if (
- (ascnd_x and next_pt[0] < last_pt[0]) or
- (not ascnd_x and next_pt[0] > last_pt[0])
+ if (ascnd_x and next_pt[0] < last_pt[0]) or (
+ not ascnd_x and next_pt[0] > last_pt[0]
):
angle = 180 - angle
count = int(angle // STEP_ANGLE)
@@ -1172,15 +1255,16 @@ class ProbeManager:
yield (origin[0] + adj, origin[1] + opp)
-MAX_HIT_DIST = 2.
+MAX_HIT_DIST = 2.0
MM_WIN_SPEED = 125
+
class RapidScanHelper:
def __init__(self, config, probe_mgr, finalize_cb):
self.printer = config.get_printer()
self.probe_manager = probe_mgr
- self.speed = config.getfloat("speed", 50., above=0.)
- self.scan_height = config.getfloat("horizontal_move_z", 5.)
+ self.speed = config.getfloat("speed", 50.0, above=0.0)
+ self.scan_height = config.getfloat("horizontal_move_z", 5.0)
self.finalize_callback = finalize_cb
def perform_rapid_scan(self, gcmd):
@@ -1233,7 +1317,7 @@ class RapidScanHelper:
return
pparams = pprobe.get_probe_params(gcmd)
lift_speed = pparams["lift_speed"]
- cur_pos[2] = self.scan_height + .5
+ cur_pos[2] = self.scan_height + 0.5
toolhead.manual_move(cur_pos, lift_speed)
def _move_to_scan_height(self, gcmd, scan_height):
@@ -1244,11 +1328,11 @@ class RapidScanHelper:
pparams = pprobe.get_probe_params(gcmd)
lift_speed = pparams["lift_speed"]
probe_speed = pparams["probe_speed"]
- cur_pos[2] = scan_height + .5
+ cur_pos[2] = scan_height + 0.5
toolhead.manual_move(cur_pos, lift_speed)
cur_pos[2] = scan_height
toolhead.manual_move(cur_pos, probe_speed)
- toolhead.dwell(time_window / 2 + .01)
+ toolhead.dwell(time_window / 2 + 0.01)
def _apply_offsets(self, point, offsets):
return [(pos - ofs) for pos, ofs in zip(point, offsets)]
@@ -1256,16 +1340,18 @@ class RapidScanHelper:
class MoveSplitter:
def __init__(self, config, gcode):
- self.split_delta_z = config.getfloat(
- 'split_delta_z', .025, minval=0.01)
+ self.split_delta_z = config.getfloat("split_delta_z", 0.025, minval=0.01)
self.move_check_distance = config.getfloat(
- 'move_check_distance', 5., minval=3.)
+ "move_check_distance", 5.0, minval=3.0
+ )
self.z_mesh = None
- self.fade_offset = 0.
+ self.fade_offset = 0.0
self.gcode = gcode
+
def initialize(self, mesh, fade_offset):
self.z_mesh = mesh
self.fade_offset = fade_offset
+
def build_move(self, prev_pos, next_pos, factor):
self.prev_pos = tuple(prev_pos)
self.next_pos = tuple(next_pos)
@@ -1273,30 +1359,35 @@ class MoveSplitter:
self.z_factor = factor
self.z_offset = self._calc_z_offset(prev_pos)
self.traverse_complete = False
- self.distance_checked = 0.
+ self.distance_checked = 0.0
axes_d = [np - pp for np, pp in zip(self.next_pos, self.prev_pos)]
- self.total_move_length = math.sqrt(sum([d*d for d in axes_d[:3]]))
- self.axis_move = [not isclose(d, 0., abs_tol=1e-10) for d in axes_d]
+ self.total_move_length = math.sqrt(sum([d * d for d in axes_d[:3]]))
+ self.axis_move = [not isclose(d, 0.0, abs_tol=1e-10) for d in axes_d]
+
def _calc_z_offset(self, pos):
z = self.z_mesh.calc_z(pos[0], pos[1])
offset = self.fade_offset
return self.z_factor * (z - offset) + offset
+
def _set_next_move(self, distance_from_prev):
t = distance_from_prev / self.total_move_length
- if t > 1. or t < 0.:
+ if t > 1.0 or t < 0.0:
raise self.gcode.error(
"bed_mesh: Slice distance is negative "
- "or greater than entire move length")
+ "or greater than entire move length"
+ )
for i in range(len(self.next_pos)):
if self.axis_move[i]:
- self.current_pos[i] = lerp(
- t, self.prev_pos[i], self.next_pos[i])
+ self.current_pos[i] = lerp(t, self.prev_pos[i], self.next_pos[i])
+
def split(self):
if not self.traverse_complete:
if self.axis_move[0] or self.axis_move[1]:
# X and/or Y axis move, traverse if necessary
- while self.distance_checked + self.move_check_distance \
- < self.total_move_length:
+ while (
+ self.distance_checked + self.move_check_distance
+ < self.total_move_length
+ ):
self.distance_checked += self.move_check_distance
self._set_next_move(self.distance_checked)
next_z = self._calc_z_offset(self.current_pos)
@@ -1323,54 +1414,57 @@ class ZMesh:
self.profile_name = name or "adaptive-%X" % (id(self),)
self.probed_matrix = self.mesh_matrix = None
self.mesh_params = params
- self.mesh_offsets = [0., 0.]
- logging.debug('bed_mesh: probe/mesh parameters:')
+ self.mesh_offsets = [0.0, 0.0]
+ logging.debug("bed_mesh: probe/mesh parameters:")
for key, value in self.mesh_params.items():
logging.debug("%s : %s" % (key, value))
- self.mesh_x_min = params['min_x']
- self.mesh_x_max = params['max_x']
- self.mesh_y_min = params['min_y']
- self.mesh_y_max = params['max_y']
+ self.mesh_x_min = params["min_x"]
+ self.mesh_x_max = params["max_x"]
+ self.mesh_y_min = params["min_y"]
+ self.mesh_y_max = params["max_y"]
logging.debug(
"bed_mesh: Mesh Min: (%.2f,%.2f) Mesh Max: (%.2f,%.2f)"
- % (self.mesh_x_min, self.mesh_y_min,
- self.mesh_x_max, self.mesh_y_max))
+ % (self.mesh_x_min, self.mesh_y_min, self.mesh_x_max, self.mesh_y_max)
+ )
# Set the interpolation algorithm
interpolation_algos = {
- 'lagrange': self._sample_lagrange,
- 'bicubic': self._sample_bicubic,
- 'direct': self._sample_direct
+ "lagrange": self._sample_lagrange,
+ "bicubic": self._sample_bicubic,
+ "direct": self._sample_direct,
}
- self._sample = interpolation_algos.get(params['algo'])
+ self._sample = interpolation_algos.get(params["algo"])
# Number of points to interpolate per segment
- mesh_x_pps = params['mesh_x_pps']
- mesh_y_pps = params['mesh_y_pps']
- px_cnt = params['x_count']
- py_cnt = params['y_count']
+ mesh_x_pps = params["mesh_x_pps"]
+ mesh_y_pps = params["mesh_y_pps"]
+ px_cnt = params["x_count"]
+ py_cnt = params["y_count"]
self.mesh_x_count = (px_cnt - 1) * mesh_x_pps + px_cnt
self.mesh_y_count = (py_cnt - 1) * mesh_y_pps + py_cnt
self.x_mult = mesh_x_pps + 1
self.y_mult = mesh_y_pps + 1
- logging.debug("bed_mesh: Mesh grid size - X:%d, Y:%d"
- % (self.mesh_x_count, self.mesh_y_count))
- self.mesh_x_dist = (self.mesh_x_max - self.mesh_x_min) / \
- (self.mesh_x_count - 1)
- self.mesh_y_dist = (self.mesh_y_max - self.mesh_y_min) / \
- (self.mesh_y_count - 1)
+ logging.debug(
+ "bed_mesh: Mesh grid size - X:%d, Y:%d"
+ % (self.mesh_x_count, self.mesh_y_count)
+ )
+ self.mesh_x_dist = (self.mesh_x_max - self.mesh_x_min) / (self.mesh_x_count - 1)
+ self.mesh_y_dist = (self.mesh_y_max - self.mesh_y_min) / (self.mesh_y_count - 1)
+
def get_mesh_matrix(self):
if self.mesh_matrix is not None:
- return [[round(z, 6) for z in line]
- for line in self.mesh_matrix]
+ return [[round(z, 6) for z in line] for line in self.mesh_matrix]
return [[]]
+
def get_probed_matrix(self):
if self.probed_matrix is not None:
- return [[round(z, 6) for z in line]
- for line in self.probed_matrix]
+ return [[round(z, 6) for z in line] for line in self.probed_matrix]
return [[]]
+
def get_mesh_params(self):
return self.mesh_params
+
def get_profile_name(self):
return self.profile_name
+
def print_probed_matrix(self, print_func):
if self.probed_matrix is not None:
msg = "Mesh Leveling Probed Z positions:\n"
@@ -1381,6 +1475,7 @@ class ZMesh:
print_func(msg)
else:
print_func("bed_mesh: bed has not been probed")
+
def print_mesh(self, print_func, move_z=None):
matrix = self.get_mesh_matrix()
if matrix is not None:
@@ -1388,12 +1483,13 @@ class ZMesh:
if move_z is not None:
msg += "Search Height: %d\n" % (move_z)
msg += "Mesh Offsets: X=%.4f, Y=%.4f\n" % (
- self.mesh_offsets[0], self.mesh_offsets[1])
+ self.mesh_offsets[0],
+ self.mesh_offsets[1],
+ )
msg += "Mesh Average: %.2f\n" % (self.get_z_average())
rng = self.get_z_range()
msg += "Mesh Range: min=%.4f max=%.4f\n" % (rng[0], rng[1])
- msg += "Interpolation Algorithm: %s\n" \
- % (self.mesh_params['algo'])
+ msg += "Interpolation Algorithm: %s\n" % (self.mesh_params["algo"])
msg += "Measured points:\n"
for y_line in range(self.mesh_y_count - 1, -1, -1):
for z in matrix[y_line]:
@@ -1402,10 +1498,12 @@ class ZMesh:
print_func(msg)
else:
print_func("bed_mesh: Z Mesh not generated")
+
def build_mesh(self, z_matrix):
self.probed_matrix = z_matrix
self._sample(z_matrix)
self.print_mesh(logging.debug)
+
def set_zero_reference(self, xpos, ypos):
offset = self.calc_z(xpos, ypos)
logging.info(
@@ -1416,42 +1514,50 @@ class ZMesh:
for yidx in range(len(matrix)):
for xidx in range(len(matrix[yidx])):
matrix[yidx][xidx] -= offset
+
def set_mesh_offsets(self, offsets):
for i, o in enumerate(offsets):
if o is not None:
self.mesh_offsets[i] = o
+
def get_x_coordinate(self, index):
return self.mesh_x_min + self.mesh_x_dist * index
+
def get_y_coordinate(self, index):
return self.mesh_y_min + self.mesh_y_dist * index
+
def calc_z(self, x, y):
if self.mesh_matrix is not None:
tbl = self.mesh_matrix
tx, xidx = self._get_linear_index(x + self.mesh_offsets[0], 0)
ty, yidx = self._get_linear_index(y + self.mesh_offsets[1], 1)
- z0 = lerp(tx, tbl[yidx][xidx], tbl[yidx][xidx+1])
- z1 = lerp(tx, tbl[yidx+1][xidx], tbl[yidx+1][xidx+1])
+ z0 = lerp(tx, tbl[yidx][xidx], tbl[yidx][xidx + 1])
+ z1 = lerp(tx, tbl[yidx + 1][xidx], tbl[yidx + 1][xidx + 1])
return lerp(ty, z0, z1)
else:
# No mesh table generated, no z-adjustment
- return 0.
+ return 0.0
+
def get_z_range(self):
if self.mesh_matrix is not None:
mesh_min = min([min(x) for x in self.mesh_matrix])
mesh_max = max([max(x) for x in self.mesh_matrix])
return mesh_min, mesh_max
else:
- return 0., 0.
+ return 0.0, 0.0
+
def get_z_average(self):
if self.mesh_matrix is not None:
- avg_z = (sum([sum(x) for x in self.mesh_matrix]) /
- sum([len(x) for x in self.mesh_matrix]))
+ avg_z = sum([sum(x) for x in self.mesh_matrix]) / sum(
+ [len(x) for x in self.mesh_matrix]
+ )
# Round average to the nearest 100th. This
# should produce an offset that is divisible by common
# z step distances
return round(avg_z, 2)
else:
- return 0.
+ return 0.0
+
def _get_linear_index(self, coord, axis):
if axis == 0:
# X-axis
@@ -1465,21 +1571,29 @@ class ZMesh:
mesh_cnt = self.mesh_y_count
mesh_dist = self.mesh_y_dist
cfunc = self.get_y_coordinate
- t = 0.
+ t = 0.0
idx = int(math.floor((coord - mesh_min) / mesh_dist))
idx = constrain(idx, 0, mesh_cnt - 2)
t = (coord - cfunc(idx)) / mesh_dist
- return constrain(t, 0., 1.), idx
+ return constrain(t, 0.0, 1.0), idx
+
def _sample_direct(self, z_matrix):
self.mesh_matrix = z_matrix
+
def _sample_lagrange(self, z_matrix):
x_mult = self.x_mult
y_mult = self.y_mult
- self.mesh_matrix = \
- [[0. if ((i % x_mult) or (j % y_mult))
- else z_matrix[j//y_mult][i//x_mult]
- for i in range(self.mesh_x_count)]
- for j in range(self.mesh_y_count)]
+ self.mesh_matrix = [
+ [
+ (
+ 0.0
+ if ((i % x_mult) or (j % y_mult))
+ else z_matrix[j // y_mult][i // x_mult]
+ )
+ for i in range(self.mesh_x_count)
+ ]
+ for j in range(self.mesh_y_count)
+ ]
xpts, ypts = self._get_lagrange_coords()
# Interpolate X coordinates
for i in range(self.mesh_y_count):
@@ -1498,43 +1612,52 @@ class ZMesh:
continue
y = self.get_y_coordinate(j)
self.mesh_matrix[j][i] = self._calc_lagrange(ypts, y, i, 1)
+
def _get_lagrange_coords(self):
xpts = []
ypts = []
- for i in range(self.mesh_params['x_count']):
+ for i in range(self.mesh_params["x_count"]):
xpts.append(self.get_x_coordinate(i * self.x_mult))
- for j in range(self.mesh_params['y_count']):
+ for j in range(self.mesh_params["y_count"]):
ypts.append(self.get_y_coordinate(j * self.y_mult))
return xpts, ypts
+
def _calc_lagrange(self, lpts, c, vec, axis=0):
pt_cnt = len(lpts)
- total = 0.
+ total = 0.0
for i in range(pt_cnt):
- n = 1.
- d = 1.
+ n = 1.0
+ d = 1.0
for j in range(pt_cnt):
if j == i:
continue
- n *= (c - lpts[j])
- d *= (lpts[i] - lpts[j])
+ n *= c - lpts[j]
+ d *= lpts[i] - lpts[j]
if axis == 0:
# Calc X-Axis
- z = self.mesh_matrix[vec][i*self.x_mult]
+ z = self.mesh_matrix[vec][i * self.x_mult]
else:
# Calc Y-Axis
- z = self.mesh_matrix[i*self.y_mult][vec]
+ z = self.mesh_matrix[i * self.y_mult][vec]
total += z * n / d
return total
+
def _sample_bicubic(self, z_matrix):
# should work for any number of probe points above 3x3
x_mult = self.x_mult
y_mult = self.y_mult
- c = self.mesh_params['tension']
- self.mesh_matrix = \
- [[0. if ((i % x_mult) or (j % y_mult))
- else z_matrix[j//y_mult][i//x_mult]
- for i in range(self.mesh_x_count)]
- for j in range(self.mesh_y_count)]
+ c = self.mesh_params["tension"]
+ self.mesh_matrix = [
+ [
+ (
+ 0.0
+ if ((i % x_mult) or (j % y_mult))
+ else z_matrix[j // y_mult][i // x_mult]
+ )
+ for i in range(self.mesh_x_count)
+ ]
+ for j in range(self.mesh_y_count)
+ ]
# Interpolate X values
for y in range(self.mesh_y_count):
if y % y_mult != 0:
@@ -1551,6 +1674,7 @@ class ZMesh:
continue
pts = self._get_y_ctl_pts(x, y)
self.mesh_matrix[y][x] = self._cardinal_spline(pts, c)
+
def _get_x_ctl_pts(self, x, y):
# Fetch control points and t for a X value in the mesh
x_mult = self.x_mult
@@ -1559,7 +1683,7 @@ class ZMesh:
if x < x_mult:
p0 = p1 = x_row[0]
p2 = x_row[x_mult]
- p3 = x_row[2*x_mult]
+ p3 = x_row[2 * x_mult]
t = x / float(x_mult)
elif x > last_pt:
p0 = x_row[last_pt - x_mult]
@@ -1573,14 +1697,14 @@ class ZMesh:
p0 = x_row[i - x_mult]
p1 = x_row[i]
p2 = x_row[i + x_mult]
- p3 = x_row[i + 2*x_mult]
+ p3 = x_row[i + 2 * x_mult]
t = (x - i) / float(x_mult)
found = True
break
if not found:
- raise BedMeshError(
- "bed_mesh: Error finding x control points")
+ raise BedMeshError("bed_mesh: Error finding x control points")
return p0, p1, p2, p3, t
+
def _get_y_ctl_pts(self, x, y):
# Fetch control points and t for a Y value in the mesh
y_mult = self.y_mult
@@ -1589,7 +1713,7 @@ class ZMesh:
if y < y_mult:
p0 = p1 = y_col[0][x]
p2 = y_col[y_mult][x]
- p3 = y_col[2*y_mult][x]
+ p3 = y_col[2 * y_mult][x]
t = y / float(y_mult)
elif y > last_pt:
p0 = y_col[last_pt - y_mult][x]
@@ -1603,23 +1727,23 @@ class ZMesh:
p0 = y_col[i - y_mult][x]
p1 = y_col[i][x]
p2 = y_col[i + y_mult][x]
- p3 = y_col[i + 2*y_mult][x]
+ p3 = y_col[i + 2 * y_mult][x]
t = (y - i) / float(y_mult)
found = True
break
if not found:
- raise BedMeshError(
- "bed_mesh: Error finding y control points")
+ raise BedMeshError("bed_mesh: Error finding y control points")
return p0, p1, p2, p3, t
+
def _cardinal_spline(self, p, tension):
t = p[4]
- t2 = t*t
- t3 = t2*t
+ t2 = t * t
+ t3 = t2 * t
m1 = tension * (p[2] - p[0])
m2 = tension * (p[3] - p[1])
- a = p[1] * (2*t3 - 3*t2 + 1)
- b = p[2] * (-2*t3 + 3*t2)
- c = m1 * (t3 - 2*t2 + t)
+ a = p[1] * (2 * t3 - 3 * t2 + 1)
+ b = p[2] * (-2 * t3 + 3 * t2)
+ c = m1 * (t3 - 2 * t2 + t)
d = m2 * (t3 - t2)
return a + b + c + d
@@ -1628,29 +1752,28 @@ class ProfileManager:
def __init__(self, config, bedmesh):
self.name = config.get_name()
self.printer = config.get_printer()
- self.gcode = self.printer.lookup_object('gcode')
+ 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]
+ 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)
+ name = profile.get_name().split(" ", 1)[1]
+ version = profile.getint("version", 0)
if version != 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, PROFILE_VERSION))
+ % (name, version, 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()
+ 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 PROFILE_OPTIONS.items():
if t is int:
params[key] = profile.getint(key)
@@ -1660,31 +1783,38 @@ class ProfileManager:
params[key] = profile.get(key)
# Register GCode
self.gcode.register_command(
- 'BED_MESH_PROFILE', self.cmd_BED_MESH_PROFILE,
- desc=self.cmd_BED_MESH_PROFILE_help)
+ "BED_MESH_PROFILE",
+ self.cmd_BED_MESH_PROFILE,
+ desc=self.cmd_BED_MESH_PROFILE_help,
+ )
+
def get_profiles(self):
return self.profiles
+
def _check_incompatible_profiles(self):
if self.incompatible_profiles:
- configfile = self.printer.lookup_object('configfile')
+ configfile = self.printer.lookup_object("configfile")
for profile in self.incompatible_profiles:
- configfile.remove_section('bed_mesh ' + profile)
+ configfile.remove_section("bed_mesh " + profile)
self.gcode.respond_info(
"The following incompatible profiles have been detected\n"
"and are scheduled for removal:\n%s\n"
"The SAVE_CONFIG command will update the printer config\n"
- "file and restart the printer" %
- (('\n').join(self.incompatible_profiles)))
+ "file and restart the printer"
+ % (("\n").join(self.incompatible_profiles))
+ )
+
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))
+ % (prof_name)
+ )
return
probed_matrix = z_mesh.get_probed_matrix()
mesh_params = z_mesh.get_mesh_params()
- configfile = self.printer.lookup_object('configfile')
+ configfile = self.printer.lookup_object("configfile")
cfg_name = self.name + " " + prof_name
# set params
z_values = ""
@@ -1693,40 +1823,41 @@ class ProfileManager:
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)
+ 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)
+ 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))
+ "update the printer config file and restart the printer." % (prof_name)
+ )
+
def load_profile(self, prof_name):
profile = self.profiles.get(prof_name, None)
if profile is None:
- raise self.gcode.error(
- "bed_mesh: Unknown profile [%s]" % prof_name)
- probed_matrix = profile['points']
- mesh_params = profile['mesh_params']
+ raise self.gcode.error("bed_mesh: Unknown profile [%s]" % prof_name)
+ probed_matrix = profile["points"]
+ mesh_params = profile["mesh_params"]
z_mesh = ZMesh(mesh_params, prof_name)
try:
z_mesh.build_mesh(probed_matrix)
except BedMeshError as e:
raise self.gcode.error(str(e))
self.bedmesh.set_mesh(z_mesh)
+
def remove_profile(self, prof_name):
if prof_name in self.profiles:
- configfile = self.printer.lookup_object('configfile')
- configfile.remove_section('bed_mesh ' + prof_name)
+ configfile = self.printer.lookup_object("configfile")
+ configfile.remove_section("bed_mesh " + prof_name)
profiles = dict(self.profiles)
del profiles[prof_name]
self.profiles = profiles
@@ -1734,17 +1865,21 @@ class ProfileManager:
self.gcode.respond_info(
"Profile [%s] removed from storage for this session.\n"
"The SAVE_CONFIG command will update the printer\n"
- "configuration and restart the printer" % (prof_name))
+ "configuration and restart the printer" % (prof_name)
+ )
else:
- self.gcode.respond_info(
- "No profile named [%s] to remove" % (prof_name))
+ self.gcode.respond_info("No profile named [%s] to remove" % (prof_name))
+
cmd_BED_MESH_PROFILE_help = "Bed Mesh Persistent Storage management"
+
def cmd_BED_MESH_PROFILE(self, gcmd):
- options = collections.OrderedDict({
- 'LOAD': self.load_profile,
- 'SAVE': self.save_profile,
- 'REMOVE': self.remove_profile
- })
+ options = collections.OrderedDict(
+ {
+ "LOAD": self.load_profile,
+ "SAVE": self.save_profile,
+ "REMOVE": self.remove_profile,
+ }
+ )
for key in options:
name = gcmd.get(key, None)
if name is not None:
@@ -1752,10 +1887,11 @@ class ProfileManager:
raise gcmd.error(
"Value for parameter '%s' must be specified" % (key)
)
- if name == "default" and key == 'SAVE':
+ if name == "default" and key == "SAVE":
gcmd.respond_info(
"Profile 'default' is reserved, please choose"
- " another profile name.")
+ " another profile name."
+ )
else:
options[key](name)
return