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.py122
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 = {