aboutsummaryrefslogtreecommitdiffstats
path: root/klippy/extras/temperature_probe.py
diff options
context:
space:
mode:
Diffstat (limited to 'klippy/extras/temperature_probe.py')
-rw-r--r--klippy/extras/temperature_probe.py210
1 files changed, 93 insertions, 117 deletions
diff --git a/klippy/extras/temperature_probe.py b/klippy/extras/temperature_probe.py
index c480ddae..1d5327d7 100644
--- a/klippy/extras/temperature_probe.py
+++ b/klippy/extras/temperature_probe.py
@@ -12,6 +12,7 @@ KELVIN_TO_CELSIUS = -273.15
# Polynomial Helper Classes and Functions
######################################################################
+
def calc_determinant(matrix):
m = matrix
aei = m[0][0] * m[1][1] * m[2][2]
@@ -22,6 +23,7 @@ def calc_determinant(matrix):
afh = m[0][0] * m[2][1] * m[1][2]
return aei + bfg + cdh - ceg - bdi - afh
+
class Polynomial2d:
def __init__(self, a, b, c):
self.a = a
@@ -65,13 +67,9 @@ class Polynomial2d:
sum_x3 = sum([x**3 for x in xlist])
sum_x4 = sum([x**4 for x in xlist])
sum_xy = sum([x * y for x, y in coords])
- sum_x2y = sum([y*x**2 for x, y in coords])
+ sum_x2y = sum([y * x**2 for x, y in coords])
vector_b = [sum_y, sum_xy, sum_x2y]
- m = [
- [count, sum_x, sum_x2],
- [sum_x, sum_x2, sum_x3],
- [sum_x2, sum_x3, sum_x4]
- ]
+ m = [[count, sum_x, sum_x2], [sum_x, sum_x2, sum_x3], [sum_x2, sum_x3, sum_x4]]
m0 = [vector_b, m[1], m[2]]
m1 = [m[0], vector_b, m[2]]
m2 = [m[0], m[1], vector_b]
@@ -81,52 +79,47 @@ class Polynomial2d:
a2 = calc_determinant(m2) / det_m
return cls(a0, a1, a2)
+
class TemperatureProbe:
def __init__(self, config):
self.name = config.get_name()
self.printer = config.get_printer()
self.gcode = self.printer.lookup_object("gcode")
- self.speed = config.getfloat("speed", None, above=0.)
- self.horizontal_move_z = config.getfloat(
- "horizontal_move_z", 2., above=0.
- )
- self.resting_z = config.getfloat("resting_z", .4, above=0.)
- self.cal_pos = config.getfloatlist(
- "calibration_position", None, count=3
- )
- self.cal_bed_temp = config.getfloat(
- "calibration_bed_temp", None, above=50.
- )
+ self.speed = config.getfloat("speed", None, above=0.0)
+ self.horizontal_move_z = config.getfloat("horizontal_move_z", 2.0, above=0.0)
+ self.resting_z = config.getfloat("resting_z", 0.4, above=0.0)
+ self.cal_pos = config.getfloatlist("calibration_position", None, count=3)
+ self.cal_bed_temp = config.getfloat("calibration_bed_temp", None, above=50.0)
self.cal_extruder_temp = config.getfloat(
- "calibration_extruder_temp", None, above=50.
- )
- self.cal_extruder_z = config.getfloat(
- "extruder_heating_z", 50., above=0.
+ "calibration_extruder_temp", None, above=50.0
)
+ self.cal_extruder_z = config.getfloat("extruder_heating_z", 50.0, above=0.0)
# Setup temperature sensor
- smooth_time = config.getfloat("smooth_time", 2., above=0.)
- self.inv_smooth_time = 1. / smooth_time
+ smooth_time = config.getfloat("smooth_time", 2.0, above=0.0)
+ self.inv_smooth_time = 1.0 / smooth_time
self.min_temp = config.getfloat(
"min_temp", KELVIN_TO_CELSIUS, minval=KELVIN_TO_CELSIUS
)
- self.max_temp = config.getfloat(
- "max_temp", 99999999.9, above=self.min_temp
- )
+ self.max_temp = config.getfloat("max_temp", 99999999.9, above=self.min_temp)
pheaters = self.printer.load_object(config, "heaters")
self.sensor = pheaters.setup_sensor(config)
self.sensor.setup_minmax(self.min_temp, self.max_temp)
self.sensor.setup_callback(self._temp_callback)
pheaters.register_sensor(config, self)
- self.last_temp_read_time = 0.
- self.last_measurement = (0., 99999999., 0.,)
+ self.last_temp_read_time = 0.0
+ self.last_measurement = (
+ 0.0,
+ 99999999.0,
+ 0.0,
+ )
# Calibration State
self.cal_helper = None
- self.next_auto_temp = 99999999.
+ self.next_auto_temp = 99999999.0
self.target_temp = 0
self.expected_count = 0
self.sample_count = 0
self.in_calibration = False
- self.step = 2.
+ self.step = 2.0
self.last_zero_pos = None
self.total_expansion = 0
self.start_pos = []
@@ -134,15 +127,19 @@ class TemperatureProbe:
# Register GCode Commands
pname = self.name.split(maxsplit=1)[-1]
self.gcode.register_mux_command(
- "TEMPERATURE_PROBE_CALIBRATE", "PROBE", pname,
+ "TEMPERATURE_PROBE_CALIBRATE",
+ "PROBE",
+ pname,
self.cmd_TEMPERATURE_PROBE_CALIBRATE,
- desc=self.cmd_TEMPERATURE_PROBE_CALIBRATE_help
+ desc=self.cmd_TEMPERATURE_PROBE_CALIBRATE_help,
)
self.gcode.register_mux_command(
- "TEMPERATURE_PROBE_ENABLE", "PROBE", pname,
+ "TEMPERATURE_PROBE_ENABLE",
+ "PROBE",
+ pname,
self.cmd_TEMPERATURE_PROBE_ENABLE,
- desc=self.cmd_TEMPERATURE_PROBE_ENABLE_help
+ desc=self.cmd_TEMPERATURE_PROBE_ENABLE_help,
)
# Register Drift Compensation Helper with probe
@@ -166,20 +163,18 @@ class TemperatureProbe:
time_diff = read_time - self.last_temp_read_time
self.last_temp_read_time = read_time
temp_diff = temp - smoothed_temp
- adj_time = min(time_diff * self.inv_smooth_time, 1.)
+ adj_time = min(time_diff * self.inv_smooth_time, 1.0)
smoothed_temp += temp_diff * adj_time
measured_min = min(measured_min, smoothed_temp)
measured_max = max(measured_max, smoothed_temp)
self.last_measurement = (smoothed_temp, measured_min, measured_max)
if self.in_calibration and smoothed_temp >= self.next_auto_temp:
- self.printer.get_reactor().register_async_callback(
- self._check_kick_next
- )
+ self.printer.get_reactor().register_async_callback(self._check_kick_next)
def _check_kick_next(self, eventtime):
smoothed_temp = self.last_measurement[0]
if self.in_calibration and smoothed_temp >= self.next_auto_temp:
- self.next_auto_temp = 99999999.
+ self.next_auto_temp = 99999999.0
self.gcode.run_script("TEMPERATURE_PROBE_NEXT")
def get_temp(self, eventtime=None):
@@ -204,8 +199,9 @@ class TemperatureProbe:
# Register our own abort command now that the manual
# probe has finished and unregistered
self.gcode.register_command(
- "ABORT", self.cmd_TEMPERATURE_PROBE_ABORT,
- desc=self.cmd_TEMPERATURE_PROBE_ABORT_help
+ "ABORT",
+ self.cmd_TEMPERATURE_PROBE_ABORT,
+ desc=self.cmd_TEMPERATURE_PROBE_ABORT_help,
)
probe_speed = self._get_speeds()[1]
# Move tool down to the resting position
@@ -217,8 +213,7 @@ class TemperatureProbe:
self.next_auto_temp = last_temp + self.step
self.gcode.respond_info(
"%s: collected sample %d/%d at temp %.2fC, next sample scheduled "
- "at temp %.2fC"
- % (self.name, cnt, exp_cnt, last_temp, self.next_auto_temp)
+ "at temp %.2fC" % (self.name, cnt, exp_cnt, last_temp, self.next_auto_temp)
)
def _manual_probe_finalize(self, kin_pos):
@@ -230,8 +225,7 @@ class TemperatureProbe:
z_diff = self.last_zero_pos[2] - kin_pos[2]
self.total_expansion += z_diff
logging.info(
- "Estimated Total Thermal Expansion: %.6f"
- % (self.total_expansion,)
+ "Estimated Total Thermal Expansion: %.6f" % (self.total_expansion,)
)
self.last_zero_pos = kin_pos
toolhead = self.printer.lookup_object("toolhead")
@@ -255,11 +249,11 @@ class TemperatureProbe:
raise
def _finalize_drift_cal(self, success, msg=None):
- self.next_auto_temp = 99999999.
+ self.next_auto_temp = 99999999.0
self.target_temp = 0
self.expected_count = 0
self.sample_count = 0
- self.step = 2.
+ self.step = 2.0
self.in_calibration = False
self.last_zero_pos = None
self.total_expansion = 0
@@ -293,21 +287,19 @@ class TemperatureProbe:
toolhead = self.printer.lookup_object("toolhead")
extr_name = toolhead.get_extruder().get_name()
self.gcode.run_script_from_command(
- "SET_HEATER_TEMPERATURE HEATER=%s TARGET=%f"
- % (extr_name, temp)
+ "SET_HEATER_TEMPERATURE HEATER=%s TARGET=%f" % (extr_name, temp)
)
if wait:
self.gcode.run_script_from_command(
- "TEMPERATURE_WAIT SENSOR=%s MINIMUM=%f"
- % (extr_name, temp)
+ "TEMPERATURE_WAIT SENSOR=%s MINIMUM=%f" % (extr_name, temp)
)
+
def _set_bed_temp(self, temp):
if self.cal_bed_temp is None:
# Bed temperature not configured
return
self.gcode.run_script_from_command(
- "SET_HEATER_TEMPERATURE HEATER=heater_bed TARGET=%f"
- % (temp,)
+ "SET_HEATER_TEMPERATURE HEATER=heater_bed TARGET=%f" % (temp,)
)
def _check_homed(self):
@@ -317,9 +309,7 @@ class TemperatureProbe:
h_axes = status["homed_axes"]
for axis in "xyz":
if axis not in h_axes:
- raise self.gcode.error(
- "Printer must be homed before calibration"
- )
+ raise self.gcode.error("Printer must be homed before calibration")
def _move_to_start(self):
toolhead = self.printer.lookup_object("toolhead")
@@ -348,20 +338,17 @@ class TemperatureProbe:
cmd_TEMPERATURE_PROBE_CALIBRATE_help = (
"Calibrate probe temperature drift compensation"
)
+
def cmd_TEMPERATURE_PROBE_CALIBRATE(self, gcmd):
if self.cal_helper is None:
- raise gcmd.error(
- "No calibration helper registered for [%s]"
- % (self.name,)
- )
+ raise gcmd.error("No calibration helper registered for [%s]" % (self.name,))
self._check_homed()
probe = self._get_probe()
probe_name = probe.get_status(None)["name"]
short_name = probe_name.split(maxsplit=1)[-1]
if short_name != self.name.split(maxsplit=1)[-1]:
raise self.gcode.error(
- "[%s] not linked to registered probe [%s]."
- % (self.name, probe_name)
+ "[%s] not linked to registered probe [%s]." % (self.name, probe_name)
)
manual_probe.verify_no_manual_probe(self.printer)
if self.in_calibration:
@@ -371,25 +358,23 @@ class TemperatureProbe:
)
cur_temp = self.last_measurement[0]
target_temp = gcmd.get_float("TARGET", above=cur_temp)
- step = gcmd.get_float("STEP", 2., minval=1.0)
- expected_count = int(
- (target_temp - cur_temp) / step + .5
- )
+ step = gcmd.get_float("STEP", 2.0, minval=1.0)
+ expected_count = int((target_temp - cur_temp) / step + 0.5)
if expected_count < 3:
raise gcmd.error(
"Invalid STEP and/or TARGET parameters resulted "
- "in too few expected samples: %d"
- % (expected_count,)
+ "in too few expected samples: %d" % (expected_count,)
)
try:
self.gcode.register_command(
- "TEMPERATURE_PROBE_NEXT", self.cmd_TEMPERATURE_PROBE_NEXT,
- desc=self.cmd_TEMPERATURE_PROBE_NEXT_help
+ "TEMPERATURE_PROBE_NEXT",
+ self.cmd_TEMPERATURE_PROBE_NEXT,
+ desc=self.cmd_TEMPERATURE_PROBE_NEXT_help,
)
self.gcode.register_command(
"TEMPERATURE_PROBE_COMPLETE",
self.cmd_TEMPERATURE_PROBE_COMPLETE,
- desc=self.cmd_TEMPERATURE_PROBE_NEXT_help
+ desc=self.cmd_TEMPERATURE_PROBE_NEXT_help,
)
except self.printer.config_error:
raise gcmd.error(
@@ -411,14 +396,13 @@ class TemperatureProbe:
# Capture start position and begin initial probe
toolhead = self.printer.lookup_object("toolhead")
self.start_pos = toolhead.get_position()[:2]
- manual_probe.ManualProbeHelper(
- self.printer, gcmd, self._manual_probe_finalize
- )
+ manual_probe.ManualProbeHelper(self.printer, gcmd, self._manual_probe_finalize)
cmd_TEMPERATURE_PROBE_NEXT_help = "Sample next probe drift temperature"
+
def cmd_TEMPERATURE_PROBE_NEXT(self, gcmd):
manual_probe.verify_no_manual_probe(self.printer)
- self.next_auto_temp = 99999999.
+ self.next_auto_temp = 99999999.0
toolhead = self.printer.lookup_object("toolhead")
# Lift and Move to nozzle back to start position
curpos = toolhead.get_position()
@@ -433,22 +417,23 @@ class TemperatureProbe:
curpos[2] = start_z
toolhead.manual_move(curpos, probe_speed)
self.gcode.register_command("ABORT", None)
- manual_probe.ManualProbeHelper(
- self.printer, gcmd, self._manual_probe_finalize
- )
+ manual_probe.ManualProbeHelper(self.printer, gcmd, self._manual_probe_finalize)
cmd_TEMPERATURE_PROBE_COMPLETE_help = "Finish Probe Drift Calibration"
+
def cmd_TEMPERATURE_PROBE_COMPLETE(self, gcmd):
manual_probe.verify_no_manual_probe(self.printer)
self._finalize_drift_cal(self.sample_count >= 3)
cmd_TEMPERATURE_PROBE_ABORT_help = "Abort Probe Drift Calibration"
+
def cmd_TEMPERATURE_PROBE_ABORT(self, gcmd):
self._finalize_drift_cal(False)
cmd_TEMPERATURE_PROBE_ENABLE_help = (
"Set adjustment factor applied to drift correction"
)
+
def cmd_TEMPERATURE_PROBE_ENABLE(self, gcmd):
if self.cal_helper is not None:
self.cal_helper.set_enabled(gcmd)
@@ -467,11 +452,11 @@ class TemperatureProbe:
"measured_max_temp": round(measured_max, 2),
"in_calibration": self.in_calibration,
"estimated_expansion": self.total_expansion,
- "compensation_enabled": dcomp_enabled
+ "compensation_enabled": dcomp_enabled,
}
def stats(self, eventtime):
- return False, '%s: temp=%.1f' % (self.name, self.last_measurement[0])
+ return False, "%s: temp=%.1f" % (self.name, self.last_measurement[0])
#####################################################################
@@ -482,26 +467,23 @@ class TemperatureProbe:
DRIFT_SAMPLE_COUNT = 9
+
class EddyDriftCompensation:
def __init__(self, config, sensor):
self.printer = config.get_printer()
self.temp_sensor = sensor
self.name = config.get_name()
- self.cal_temp = config.getfloat("calibration_temp", 0.)
+ self.cal_temp = config.getfloat("calibration_temp", 0.0)
self.drift_calibration = None
self.calibration_samples = None
- self.max_valid_temp = config.getfloat("max_validation_temp", 60.)
- self.dc_min_temp = config.getfloat("drift_calibration_min_temp", 0.)
- dc = config.getlists(
- "drift_calibration", None, seps=(',', '\n'), parser=float
- )
- self.min_freq = 999999999999.
+ self.max_valid_temp = config.getfloat("max_validation_temp", 60.0)
+ self.dc_min_temp = config.getfloat("drift_calibration_min_temp", 0.0)
+ dc = config.getlists("drift_calibration", None, seps=(",", "\n"), parser=float)
+ self.min_freq = 999999999999.0
if dc is not None:
for coefs in dc:
if len(coefs) != 3:
- raise config.error(
- "Invalid polynomial in drift calibration"
- )
+ raise config.error("Invalid polynomial in drift calibration")
self.drift_calibration = [Polynomial2d(*coefs) for coefs in dc]
cal = self.drift_calibration
start_temp, end_temp = self.dc_min_temp, self.max_valid_temp
@@ -517,16 +499,14 @@ class EddyDriftCompensation:
else:
logging.info(
"%s: No drift calibration configured, disabling temperature "
- "drift compensation"
- % (self.name,)
+ "drift compensation" % (self.name,)
)
self.enabled = has_dc = self.drift_calibration is not None
if self.cal_temp < 1e-6 and has_dc:
self.enabled = False
logging.info(
"%s: No temperature saved for eddy probe calibration, "
- "disabling temperature drift compensation."
- % (self.name,)
+ "disabling temperature drift compensation." % (self.name,)
)
def is_enabled(self):
@@ -552,21 +532,20 @@ class EddyDriftCompensation:
def note_z_calibration_finish(self):
self.cal_temp = (self.cal_temp + self.get_temperature()) / 2.0
- configfile = self.printer.lookup_object('configfile')
+ configfile = self.printer.lookup_object("configfile")
configfile.set(self.name, "calibration_temp", "%.6f " % (self.cal_temp))
gcode = self.printer.lookup_object("gcode")
gcode.respond_info(
"%s: Z Calibration Temperature set to %.2f. "
"The SAVE_CONFIG command will update the printer config "
- "file and restart the printer."
- % (self.name, self.cal_temp)
+ "file and restart the printer." % (self.name, self.cal_temp)
)
def collect_sample(self, kin_pos, tool_zero_z, speeds):
if self.calibration_samples is None:
self.calibration_samples = [[] for _ in range(DRIFT_SAMPLE_COUNT)]
move_times = []
- temps = [0. for _ in range(DRIFT_SAMPLE_COUNT)]
+ temps = [0.0 for _ in range(DRIFT_SAMPLE_COUNT)]
probe_samples = [[] for _ in range(DRIFT_SAMPLE_COUNT)]
toolhead = self.printer.lookup_object("toolhead")
cur_pos = toolhead.get_position()
@@ -588,39 +567,39 @@ class EddyDriftCompensation:
temps[idx] = cur_temp
probe_samples[idx].append(sample)
return True
+
sect_name = "probe_eddy_current " + self.name.split(maxsplit=1)[-1]
self.printer.lookup_object(sect_name).add_client(_on_bulk_data_recd)
for i in range(DRIFT_SAMPLE_COUNT):
if i == 0:
# Move down to first sample location
- cur_pos[2] = tool_zero_z + .05
+ cur_pos[2] = tool_zero_z + 0.05
else:
# Sample each .5mm in z
- cur_pos[2] += 1.
+ cur_pos[2] += 1.0
toolhead.manual_move(cur_pos, lift_speed)
- cur_pos[2] -= .5
+ cur_pos[2] -= 0.5
toolhead.manual_move(cur_pos, probe_speed)
- start = toolhead.get_last_move_time() + .05
- end = start + .1
+ start = toolhead.get_last_move_time() + 0.05
+ end = start + 0.1
move_times.append((i, start, end))
- toolhead.dwell(.2)
+ toolhead.dwell(0.2)
toolhead.wait_moves()
# Wait for sample collection to finish
reactor = self.printer.get_reactor()
evttime = reactor.monotonic()
while move_times:
- evttime = reactor.pause(evttime + .1)
+ evttime = reactor.pause(evttime + 0.1)
sample_temp = sum(temps) / len(temps)
for i, data in enumerate(probe_samples):
freqs = [d[1] for d in data]
zvals = [d[2] for d in data]
avg_freq = sum(freqs) / len(freqs)
avg_z = sum(zvals) / len(zvals)
- kin_z = i * .5 + .05 + kin_pos[2]
+ kin_z = i * 0.5 + 0.05 + kin_pos[2]
logging.info(
"Probe Values at Temp %.2fC, Z %.4fmm: Avg Freq = %.6f, "
- "Avg Measured Z = %.6f"
- % (sample_temp, kin_z, avg_freq, avg_z)
+ "Avg Measured Z = %.6f" % (sample_temp, kin_z, avg_freq, avg_z)
)
self.calibration_samples[i].append((sample_temp, avg_freq))
return sample_temp
@@ -636,28 +615,25 @@ class EddyDriftCompensation:
return
gcode = self.printer.lookup_object("gcode")
if len(cal_samples) < 3:
- raise gcode.error(
- "calibration error, not enough samples"
- )
+ raise gcode.error("calibration error, not enough samples")
min_temp, _ = cal_samples[0][0]
max_temp, _ = cal_samples[-1][0]
polynomials = []
for i, coords in enumerate(cal_samples):
- height = .05 + i * .5
+ height = 0.05 + i * 0.5
poly = Polynomial2d.fit(coords)
polynomials.append(poly)
logging.info("Polynomial at Z=%.2f: %s" % (height, repr(poly)))
end_vld_temp = max(self.max_valid_temp, max_temp)
self._check_calibration(polynomials, min_temp, end_vld_temp)
coef_cfg = "\n" + "\n".join([str(p) for p in polynomials])
- configfile = self.printer.lookup_object('configfile')
+ configfile = self.printer.lookup_object("configfile")
configfile.set(self.name, "drift_calibration", coef_cfg)
configfile.set(self.name, "drift_calibration_min_temp", min_temp)
gcode.respond_info(
"%s: generated %d 2D polynomials\n"
"The SAVE_CONFIG command will update the printer config "
- "file and restart the printer."
- % (self.name, len(polynomials))
+ "file and restart the printer." % (self.name, len(polynomials))
)
def _check_calibration(self, calibration, start_temp, end_temp, error=None):
@@ -706,9 +682,9 @@ class EddyDriftCompensation:
# Frequency above max calibration value
err = poly(dest_temp) - low_freq
return freq + err
- t = min(1., max(0., (freq - low_freq) / (high_freq - low_freq)))
+ t = min(1.0, max(0.0, (freq - low_freq) / (high_freq - low_freq)))
low_tgt_freq = poly(dest_temp)
- high_tgt_freq = dc[pos-1](dest_temp)
+ high_tgt_freq = dc[pos - 1](dest_temp)
return (1 - t) * low_tgt_freq + t * high_tgt_freq
# Frequency below minimum, no correction
return freq