bed_mesh: Add ability to save mesh state to persistent memory
Signed-off-by: Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
parent
144868c600
commit
b261d31ec5
|
@ -189,6 +189,14 @@ section is enabled:
|
||||||
will be cleared as the process rehomes the printer.
|
will be cleared as the process rehomes the printer.
|
||||||
- `BED_MESH_CLEAR`: This command clears the mesh and removes all
|
- `BED_MESH_CLEAR`: This command clears the mesh and removes all
|
||||||
z adjustment. It is recommended to put this in your end-gcode.
|
z adjustment. It is recommended to put this in your end-gcode.
|
||||||
|
`BED_MESH_PROFILE LOAD=<name> SAVE=<name> REMOVE=<name>`: This
|
||||||
|
command provides profile management for mesh state. LOAD will
|
||||||
|
restore the mesh state from the profile matching the supplied name.
|
||||||
|
SAVE will save the current mesh state to a profile matching the
|
||||||
|
supplied name. Remove will delete the profile matching the
|
||||||
|
supplied name from persistent memory. Note that after SAVE or
|
||||||
|
REMOVE operations have been run the SAVE_CONFIG gcode must be run
|
||||||
|
to make the changes to peristent memory permanent.
|
||||||
|
|
||||||
## Z Tilt
|
## Z Tilt
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import logging
|
||||||
import math
|
import math
|
||||||
import json
|
import json
|
||||||
import probe
|
import probe
|
||||||
|
import collections
|
||||||
|
|
||||||
class BedMeshError(Exception):
|
class BedMeshError(Exception):
|
||||||
pass
|
pass
|
||||||
|
@ -130,14 +131,18 @@ class BedMeshCalibrate:
|
||||||
ALGOS = ['lagrange', 'bicubic']
|
ALGOS = ['lagrange', 'bicubic']
|
||||||
def __init__(self, config, bedmesh):
|
def __init__(self, config, bedmesh):
|
||||||
self.printer = config.get_printer()
|
self.printer = config.get_printer()
|
||||||
|
self.name = config.get_name()
|
||||||
self.bedmesh = bedmesh
|
self.bedmesh = bedmesh
|
||||||
self.probed_z_table = None
|
self.probed_z_table = None
|
||||||
self.build_map = False
|
self.build_map = False
|
||||||
self.probe_params = {}
|
self.probe_params = collections.OrderedDict()
|
||||||
points = self._generate_points(config)
|
points = self._generate_points(config)
|
||||||
self._init_probe_params(config, points)
|
self._init_probe_params(config, points)
|
||||||
self.probe_helper = probe.ProbePointsHelper(
|
self.probe_helper = probe.ProbePointsHelper(
|
||||||
config, self.probe_finalize, points)
|
config, self.probe_finalize, points)
|
||||||
|
# setup persistent storage
|
||||||
|
self.profiles = {}
|
||||||
|
self._load_storage(config)
|
||||||
self.gcode = self.printer.lookup_object('gcode')
|
self.gcode = self.printer.lookup_object('gcode')
|
||||||
self.gcode.register_command(
|
self.gcode.register_command(
|
||||||
'BED_MESH_CALIBRATE', self.cmd_BED_MESH_CALIBRATE,
|
'BED_MESH_CALIBRATE', self.cmd_BED_MESH_CALIBRATE,
|
||||||
|
@ -145,6 +150,9 @@ class BedMeshCalibrate:
|
||||||
self.gcode.register_command(
|
self.gcode.register_command(
|
||||||
'BED_MESH_MAP', self.cmd_BED_MESH_MAP,
|
'BED_MESH_MAP', self.cmd_BED_MESH_MAP,
|
||||||
desc=self.cmd_BED_MESH_MAP_help)
|
desc=self.cmd_BED_MESH_MAP_help)
|
||||||
|
self.gcode.register_command(
|
||||||
|
'BED_MESH_PROFILE', self.cmd_BED_MESH_PROFILE,
|
||||||
|
desc=self.cmd_BED_MESH_PROFILE_help)
|
||||||
def _generate_points(self, config):
|
def _generate_points(self, config):
|
||||||
x_cnt, y_cnt = parse_pair(
|
x_cnt, y_cnt = parse_pair(
|
||||||
config, ('probe_count', '3'), check=False, cast=int, minval=3)
|
config, ('probe_count', '3'), check=False, cast=int, minval=3)
|
||||||
|
@ -184,6 +192,8 @@ class BedMeshCalibrate:
|
||||||
self.probe_params['max_x'] = max(points, key=lambda p: p[0])[0]
|
self.probe_params['max_x'] = max(points, key=lambda p: p[0])[0]
|
||||||
self.probe_params['min_y'] = min(points, key=lambda p: p[1])[1]
|
self.probe_params['min_y'] = min(points, key=lambda p: p[1])[1]
|
||||||
self.probe_params['max_y'] = max(points, key=lambda p: p[1])[1]
|
self.probe_params['max_y'] = max(points, key=lambda p: p[1])[1]
|
||||||
|
self.probe_params['x_offset'] = 0.
|
||||||
|
self.probe_params['y_offset'] = 0.
|
||||||
pps = parse_pair(config, ('mesh_pps', '2'), check=False,
|
pps = parse_pair(config, ('mesh_pps', '2'), check=False,
|
||||||
cast=int, minval=0)
|
cast=int, minval=0)
|
||||||
self.probe_params['mesh_x_pps'] = pps[0]
|
self.probe_params['mesh_x_pps'] = pps[0]
|
||||||
|
@ -196,6 +206,92 @@ class BedMeshCalibrate:
|
||||||
% (self.probe_params['algo']))
|
% (self.probe_params['algo']))
|
||||||
self.probe_params['tension'] = config.getfloat(
|
self.probe_params['tension'] = config.getfloat(
|
||||||
'bicubic_tension', .2, minval=0., maxval=2.)
|
'bicubic_tension', .2, minval=0., maxval=2.)
|
||||||
|
def _load_storage(self, config):
|
||||||
|
stored_profs = config.get_prefix_sections(self.name)
|
||||||
|
# Remove primary bed_mesh section, as it is not a stored profile
|
||||||
|
stored_profs = [s for s in stored_profs
|
||||||
|
if s.get_name() is not self.name]
|
||||||
|
for profile in stored_profs:
|
||||||
|
name = profile.get_name().split(' ', 1)[1]
|
||||||
|
self.profiles[name] = {}
|
||||||
|
z_values = profile.get('points').split('\n')
|
||||||
|
self.profiles[name]['points'] = \
|
||||||
|
[[float(pt.strip()) for pt in line.split(',')]
|
||||||
|
for line in z_values if line.strip()]
|
||||||
|
self.profiles[name]['probe_params'] = params = \
|
||||||
|
collections.OrderedDict()
|
||||||
|
for key, value in self.probe_params.iteritems():
|
||||||
|
if type(value) is int:
|
||||||
|
params[key] = profile.getint(key)
|
||||||
|
elif type(value) is float:
|
||||||
|
params[key] = profile.getfloat(key)
|
||||||
|
elif type(value) is str:
|
||||||
|
params[key] = profile.get(key)
|
||||||
|
def save_profile(self, prof_name):
|
||||||
|
if self.probed_z_table is None:
|
||||||
|
self.gcode.respond_info(
|
||||||
|
"Unable to save to profile [%s], the bed has not been probed"
|
||||||
|
% (prof_name))
|
||||||
|
return
|
||||||
|
configfile = self.printer.lookup_object('configfile')
|
||||||
|
cfg_name = self.name + " " + prof_name
|
||||||
|
# set params
|
||||||
|
z_values = ""
|
||||||
|
for line in self.probed_z_table:
|
||||||
|
z_values += "\n "
|
||||||
|
for p in line:
|
||||||
|
z_values += "%.6f, " % p
|
||||||
|
z_values = z_values[:-2]
|
||||||
|
configfile.set(cfg_name, 'points', z_values)
|
||||||
|
for key, value in self.probe_params.iteritems():
|
||||||
|
configfile.set(cfg_name, key, value)
|
||||||
|
# save copy in local storage
|
||||||
|
self.profiles[prof_name] = profile = {}
|
||||||
|
profile['points'] = list(self.probed_z_table)
|
||||||
|
profile['probe_params'] = collections.OrderedDict(self.probe_params)
|
||||||
|
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))
|
||||||
|
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)
|
||||||
|
self.probed_z_table = profile['points']
|
||||||
|
zmesh = ZMesh(profile['probe_params'])
|
||||||
|
try:
|
||||||
|
zmesh.build_mesh(self.probed_z_table)
|
||||||
|
except BedMeshError as e:
|
||||||
|
raise self.gcode.error(e.message)
|
||||||
|
self.bedmesh.set_mesh(zmesh)
|
||||||
|
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)
|
||||||
|
del self.profiles[prof_name]
|
||||||
|
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))
|
||||||
|
else:
|
||||||
|
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, params):
|
||||||
|
options = collections.OrderedDict({
|
||||||
|
'LOAD': self.load_profile,
|
||||||
|
'SAVE': self.save_profile,
|
||||||
|
'REMOVE': self.remove_profile
|
||||||
|
})
|
||||||
|
for key in options:
|
||||||
|
name = self.gcode.get_str(key, params, None)
|
||||||
|
if name is not None:
|
||||||
|
options[key](name)
|
||||||
|
return
|
||||||
|
self.gcode.respond_error(
|
||||||
|
"Invalid syntax '%s'" % (params['#original']))
|
||||||
cmd_BED_MESH_MAP_help = "Probe the bed and serialize output"
|
cmd_BED_MESH_MAP_help = "Probe the bed and serialize output"
|
||||||
def cmd_BED_MESH_MAP(self, params):
|
def cmd_BED_MESH_MAP(self, params):
|
||||||
self.build_map = True
|
self.build_map = True
|
||||||
|
|
Loading…
Reference in New Issue