Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions docs/Config_Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2829,6 +2829,69 @@ sensor_type: ldc1612
# See the "probe" section for information on these parameters.
```

### [temperature_probe]

Reports probe coil temperature. Includes optional thermal drift
calibration for eddy current based probes. A `[temperature_probe]`
section may be linked to a `[probe_eddy_current]` by using the same
postfix for both sections.

```
[temperature_probe my_probe]
#sensor_type:
#sensor_pin:
#min_temp:
#max_temp:
# Temperature sensor configuration.
# See the "extruder" section for the definition of the above
# parameters.
#smooth_time:
# A time value (in seconds) over which temperature measurements will
# be smoothed to reduce the impact of measurement noise. The default
# is 2.0 seconds.
#gcode_id:
# See the "heater_generic" section for the definition of this
# parameter.
#speed:
# The travel speed [mm/s] for xy moves during calibration. Default
# is the speed defined by the probe.
#horizontal_move_z:
# The z distance [mm] from the bed at which xy moves will occur
# during calibration. Default is 2mm.
#resting_z:
# The z distance [mm] from the bed at which the tool will rest
# to heat the probe coil during calibration. Default is .4mm.
#calibration_position:
# The X, Y, Z position where the tool should be moved when
# probe drift calibration initializes. This is the location
# where the first manual probe will occur. If omitted, the
# default behavior is not to move the tool prior to the first
# manual probe.
#calibration_bed_temp:
# The maximum safe bed temperature (in C) used to heat the probe
# during probe drift calibration. When set, the calibration
# procedure will turn on the bed after the first sample is
# taken. When the calibration procedure is complete the bed
# temperature will be set to zero. When omitted the default
# behavior is not to set the bed temperature.
#calibration_extruder_temp:
# The extruder temperature (in C) set probe during drift calibration.
# When this option is supplied the procedure will wait until the
# specified temperature is reached before requesting the first manual
# probe. When the calibration procedure is complete the extruder
# temperature will be set to 0. When omitted the default behavior is
# not to set the extruder temperature.
#extruder_heating_z: 50.
# The Z location where extruder heating will occur if the
# "calibration_extruder_temp" option is set. It is recommended to heat
# the extruder some distance from the bed to minimize its impact on
# the probe coil temperature. The default is 50.
#max_validation_temp: 60.
# The maximum temperature used to validate the calibration. It is
# recommended to set this to a value between 100 and 120 for enclosed
# printers. The default is 60.
```

### [axis_twist_compensation]

A tool to compensate for inaccurate probe readings due to twist in X or Y
Expand Down
36 changes: 36 additions & 0 deletions docs/G-Codes.md
Original file line number Diff line number Diff line change
Expand Up @@ -1470,6 +1470,42 @@ appropriate DRIVE_CURRENT for the sensor. After running this command
use the SAVE_CONFIG command to store that new setting in the
printer.cfg config file.

### [temperature_probe]

The following commands are available when a
[temperature_probe config section](Config_Reference.md#temperature_probe)
is enabled.

#### TEMPERATURE_PROBE_CALIBRATE
`TEMPERATURE_PROBE_CALIBRATE [PROBE=<probe name>] [TARGET=<value>] [STEP=<value>]`:
Initiates probe drift calibration for eddy current based probes. The `TARGET`
is a target temperature for the last sample. When the temperature recorded
during a sample exceeds the `TARGET` calibration will complete. The `STEP`
parameter sets temperature delta (in C) between samples. After a sample has
been taken, this delta is used to schedule a call to `TEMPERATURE_PROBE_NEXT`.
The default `STEP` is 2.

#### TEMPERATURE_PROBE_NEXT
`TEMPERATURE_PROBE_NEXT`: After calibration has started this command is run to
take the next sample. It is automatically scheduled to run when the delta
specified by `STEP` has been reached, however it is also possible to manually
run this command to force a new sample. This command is only available during
calibration.

#### TEMPERATURE_PROBE_COMPLETE
`TEMPERATURE_PROBE_COMPLETE`: Can be used to end calibration and save the
current result before the `TARGET` temperature is reached. This command
is only available during calibration.

#### ABORT
`ABORT`: Aborts the calibration process, discarding the current results.
This command is only available during drift calibration.

#### TEMPERATURE_PROBE_ENABLE
`TEMPERATURE_PROBE_ENABLE ENABLE=[0|1]`: Sets temperature drift
compensation on or off. If `ENABLE` is set to 0, drift compensation
will be disabled, if set to 1 it is enabled.

### [pwm_cycle_time]

The following command is available when a
Expand Down
36 changes: 27 additions & 9 deletions klippy/extras/probe.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,9 @@ def __init__(self, config, mcu_probe):
self.printer = config.get_printer()
self.name = config.get_name()
self.mcu_probe = mcu_probe
self._allow_zero_sample_retract = self.name.startswith(
"probe_eddy_current "
)
self.speed = config.getfloat("speed", 5.0, above=0.0)
self.retry_speed: float = config.getfloat(
"retry_speed", self.speed, above=0.0
Expand Down Expand Up @@ -326,9 +329,14 @@ def __init__(self, config, mcu_probe):
)
# Multi-sample support (for improved accuracy)
self.sample_count = config.getint("samples", 1, minval=1)
self.sample_retract_dist = config.getfloat(
"sample_retract_dist", 2.0, above=0.0
)
if self._allow_zero_sample_retract:
self.sample_retract_dist = config.getfloat(
"sample_retract_dist", 2.0, minval=0.0
)
else:
self.sample_retract_dist = config.getfloat(
"sample_retract_dist", 2.0, above=0.0
)
atypes = ["median", "average"]
self.samples_result = config.getchoice(
"samples_result", atypes, "average"
Expand Down Expand Up @@ -511,9 +519,14 @@ def _discard_first_result(

# Raise the toolhead at the current x/y location
def _retract(self, gcmd: GCodeCommand):
sample_retract_dist = gcmd.get_float(
"SAMPLE_RETRACT_DIST", self.sample_retract_dist, above=0.0
)
if self._allow_zero_sample_retract:
sample_retract_dist = gcmd.get_float(
"SAMPLE_RETRACT_DIST", self.sample_retract_dist, minval=0.0
)
else:
sample_retract_dist = gcmd.get_float(
"SAMPLE_RETRACT_DIST", self.sample_retract_dist, above=0.0
)
lift_speed = self.get_lift_speed(gcmd)
toolhead: ToolHead = self.printer.lookup_object("toolhead")
pos = toolhead.get_position()
Expand Down Expand Up @@ -627,9 +640,14 @@ def cmd_PROBE_ACCURACY(self, gcmd: GCodeCommand):
speed = gcmd.get_float("PROBE_SPEED", self.speed, above=0.0)
lift_speed = self.get_lift_speed(gcmd)
sample_count = gcmd.get_int("SAMPLES", 10, minval=1)
sample_retract_dist = gcmd.get_float(
"SAMPLE_RETRACT_DIST", self.sample_retract_dist, above=0.0
)
if self._allow_zero_sample_retract:
sample_retract_dist = gcmd.get_float(
"SAMPLE_RETRACT_DIST", self.sample_retract_dist, minval=0.0
)
else:
sample_retract_dist = gcmd.get_float(
"SAMPLE_RETRACT_DIST", self.sample_retract_dist, above=0.0
)
toolhead = self.printer.lookup_object("toolhead")
pos = toolhead.get_position()
gcmd.respond_info(
Expand Down
34 changes: 31 additions & 3 deletions klippy/extras/probe_eddy_current.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class EddyCalibration:
def __init__(self, config):
self.printer = config.get_printer()
self.name = config.get_name()
self.drift_comp = DummyDriftCompensation()
# Current calibration data
self.cal_freqs = []
self.cal_zpos = []
Expand Down Expand Up @@ -48,8 +49,10 @@ def load_calibration(self, cal):
self.cal_zpos = [c[1] for c in cal]

def apply_calibration(self, samples):
cur_temp = self.drift_comp.get_temperature()
for i, (samp_time, freq, dummy_z) in enumerate(samples):
pos = bisect.bisect(self.cal_freqs, freq)
adj_freq = self.drift_comp.adjust_freq(freq, cur_temp)
pos = bisect.bisect(self.cal_freqs, adj_freq)
if pos >= len(self.cal_zpos):
zpos = -99.9
elif pos == 0:
Expand All @@ -62,7 +65,7 @@ def apply_calibration(self, samples):
prev_zpos = self.cal_zpos[pos - 1]
gain = (this_zpos - prev_zpos) / (this_freq - prev_freq)
offset = prev_zpos - prev_freq * gain
zpos = freq * gain + offset
zpos = adj_freq * gain + offset
samples[i] = (samp_time, freq, round(zpos, 6))

def height_to_freq(self, height):
Expand All @@ -80,7 +83,7 @@ def height_to_freq(self, height):
prev_zpos = rev_zpos[pos - 1]
gain = (this_freq - prev_freq) / (this_zpos - prev_zpos)
offset = prev_freq - prev_zpos * gain
return height * gain + offset
return self.drift_comp.unadjust_freq(height * gain + offset)

def do_calibration_moves(self, move_speed):
toolhead = self.printer.lookup_object("toolhead")
Expand All @@ -98,6 +101,7 @@ def handle_batch(msg):

self.printer.lookup_object(self.name).add_client(handle_batch)
toolhead.dwell(1.0)
self.drift_comp.note_z_calibration_start()
# Move to each 40um position
max_z = 4.0
samp_dist = 0.040
Expand Down Expand Up @@ -126,6 +130,7 @@ def handle_batch(msg):
times.append((start_query_time, end_query_time, kin_pos[2]))
toolhead.dwell(1.0)
toolhead.wait_moves()
self.drift_comp.note_z_calibration_finish()
# Finish data collection
is_finished = True
# Correlate query responses
Expand Down Expand Up @@ -211,6 +216,9 @@ def cmd_EDDY_CALIBRATE(self, gcmd):
self.printer, gcmd, self.post_manual_probe
)

def register_drift_compensation(self, comp):
self.drift_comp = comp


# Helper for implementing PROBE style commands
class EddyEndstopWrapper:
Expand Down Expand Up @@ -388,6 +396,26 @@ def __init__(self, config):
def add_client(self, cb):
self.sensor_helper.add_client(cb)

def register_drift_compensation(self, comp):
self.calibration.register_drift_compensation(comp)


class DummyDriftCompensation:
def get_temperature(self):
return 0.0

def note_z_calibration_start(self):
pass

def note_z_calibration_finish(self):
pass

def adjust_freq(self, freq, temp=None):
return freq

def unadjust_freq(self, freq, temp=None):
return freq


def load_config_prefix(config):
return PrinterEddyProbe(config)
Loading
Loading