diff options
Diffstat (limited to 'klippy')
-rw-r--r-- | klippy/extras/bed_mesh.py | 122 |
1 files changed, 93 insertions, 29 deletions
diff --git a/klippy/extras/bed_mesh.py b/klippy/extras/bed_mesh.py index bcb16d45..f6322596 100644 --- a/klippy/extras/bed_mesh.py +++ b/klippy/extras/bed_mesh.py @@ -10,6 +10,8 @@ import json import probe import collections +BED_SHAPES = {'rectangular': 0, 'round': 1} + class BedMeshError(Exception): pass @@ -163,6 +165,7 @@ class BedMeshCalibrate: def __init__(self, config, bedmesh): self.printer = config.get_printer() self.name = config.get_name() + self.radius = None self.bedmesh = bedmesh self.probed_z_table = None self.build_map = False @@ -185,14 +188,29 @@ class BedMeshCalibrate: 'BED_MESH_PROFILE', self.cmd_BED_MESH_PROFILE, desc=self.cmd_BED_MESH_PROFILE_help) def _generate_points(self, config): - x_cnt, y_cnt = parse_pair( - config, ('probe_count', '3'), check=False, cast=int, minval=3) + shape = config.getchoice('bed_shape', BED_SHAPES, 'rectangular') + if shape == BED_SHAPES['round']: + x_cnt = y_cnt = config.getint('probe_count', 5) + # 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") + self.radius = config.getfloat('radius', above=0.) + # radius may have precision to .1mm + self.radius = math.floor(self.radius * 10) / 10 + min_x = min_y = -self.radius + max_x = max_y = self.radius + else: + # rectangular + x_cnt, y_cnt = parse_pair( + config, ('probe_count', '3'), check=False, cast=int, minval=3) + min_x, min_y = parse_pair(config, ('min_point',)) + max_x, max_y = parse_pair(config, ('max_point',)) + if max_x <= min_x or max_y <= min_y: + raise config.error('bed_mesh: invalid min/max points') + self.probe_params['x_count'] = x_cnt self.probe_params['y_count'] = y_cnt - min_x, min_y = parse_pair(config, ('min_point',)) - max_x, max_y = parse_pair(config, ('max_point',)) - if max_x <= min_x or max_y <= min_y: - raise config.error('bed_mesh: invalid min/max points') x_dist = (max_x - min_x) / (x_cnt - 1) y_dist = (max_y - min_y) / (y_cnt - 1) # floor distances down to next hundredth @@ -200,8 +218,16 @@ class BedMeshCalibrate: y_dist = math.floor(y_dist * 100) / 100 if x_dist <= 1. or y_dist <= 1.: raise config.error("bed_mesh: min/max points too close together") - # re-calc x_max - max_x = min_x + x_dist * (x_cnt - 1) + + if self.radius is not None: + # round bed, min/max needs to be recalculated + y_dist = x_dist + new_r = (x_cnt / 2) * x_dist + min_x = min_y = -new_r + max_x = max_y = new_r + else: + # rectangular bed, only re-calc max_x + max_x = min_x + x_dist * (x_cnt - 1) pos_y = min_y points = [] for i in range(y_cnt): @@ -212,7 +238,14 @@ class BedMeshCalibrate: else: # move in negative direction pos_x = max_x - j * x_dist - points.append((pos_x, pos_y)) + if self.radius is None: + # rectangular bed, append + 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) + if dist_from_origin <= self.radius: + points.append((pos_x, pos_y)) pos_y += y_dist logging.info('bed_mesh: generated points') for p in points: @@ -358,27 +391,58 @@ class BedMeshCalibrate: z_offset = offsets[2] x_cnt = self.probe_params['x_count'] y_cnt = self.probe_params['y_count'] - # create a 2-D array representing the probed z-positions. - self.probed_z_table = [ - [0. for i in range(x_cnt)] for j in range(y_cnt)] - # Check for multi-sampled points - z_table_len = x_cnt * y_cnt - if len(positions) != z_table_len: - raise self.gcode.error( - ("bed_mesh: Invalid probe table length:\n" - "Sampled table length: %d") % len(positions)) - # Populate the organized probed table - for i in range(z_table_len): - y_position = i / x_cnt - x_position = 0 - if y_position & 1 == 0: - # Even y count, x probed in positive directon - x_position = i % x_cnt + + self.probed_z_table = [] + row = [] + prev_pos = positions[0] + for pos in positions: + if not isclose(pos[1], prev_pos[1], abs_tol=.1): + # y has changed, append row and start new + self.probed_z_table.append(row) + row = [] + if pos[0] > prev_pos[0]: + # probed in the positive direction + row.append(pos[2] - z_offset) else: - # Odd y count, x probed in the negative directon - x_position = (x_cnt - 1) - (i % x_cnt) - self.probed_z_table[y_position][x_position] = \ - positions[i][2] - z_offset + # probed in the negative direction + row.insert(0, pos[2] - z_offset) + prev_pos = pos + # append last row + self.probed_z_table.append(row) + + # make sure the y-axis is the correct length + if len(self.probed_z_table) != y_cnt: + raise self.gcode.error( + ("bed_mesh: Invalid y-axis table length\n" + "Probed table length: %d Probed Table:\n%s") % + (len(self.probed_z_table), str(self.probed_z_table))) + + if self.radius is not None: + # round bed, extrapolate probed values to create a square mesh + for row in self.probed_z_table: + row_size = len(row) + if not row_size & 1: + # an even number of points in a row shouldn't be possible + msg = "bed_mesh: incorrect number of points sampled on X\n" + msg += "Probed Table:\n" + msg += str(self.probed_z_table) + raise self.gcode.error(msg) + buf_cnt = (x_cnt - row_size) / 2 + if buf_cnt == 0: + continue + left_buffer = [row[0]] * buf_cnt + right_buffer = [row[row_size-1]] * buf_cnt + row[0:0] = left_buffer + row.extend(right_buffer) + + # make sure that the x-axis is the correct length + for row in self.probed_z_table: + 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(self.probed_z_table), str(self.probed_z_table))) + if self.build_map: params = self.probe_params outdict = { |