Skip to content
Merged
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
34 changes: 28 additions & 6 deletions klippy/extras/ldc1612_ng.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
PRODUCT_BTT_EDDY = 1
PRODUCT_CARTOGRAPHER = 2
PRODUCT_MELLOW_FLY = 3
PRODUCT_LDC1612_INTERNAL_CLK = 4

HOME_MODE_NONE = 0
HOME_MODE_HOME = 1
Expand Down Expand Up @@ -86,6 +87,7 @@ def __init__(self, config):
"btt_eddy": PRODUCT_BTT_EDDY,
"cartographer": PRODUCT_CARTOGRAPHER,
"mellow_fly": PRODUCT_MELLOW_FLY,
"ldc1612_internal_clk": PRODUCT_LDC1612_INTERNAL_CLK,
}
self._device_product = config.getchoice("sensor_type", device_choices, PRODUCT_UNKNOWN)

Expand All @@ -103,8 +105,15 @@ def __init__(self, config):
self._ldc_fref_divider = 2
self._ldc_settle_time = 0.00125
self._default_drive_current = 15
elif self._device_product == PRODUCT_LDC1612_INTERNAL_CLK:
# A generic setup that usees internal LDC1612 clock
# using LDC1612 internal typical clock frequency 43.4MHz
self._ldc_freq_clk = 43_400_000
self._ldc_fin_divider = 1
self._ldc_fref_divider = 1
self._ldc_settle_time = 0.00125
self._default_drive_current = 15
else: # Generic/BTT Eddy using external 12MHz clock source
# TODO add a generic setup that usees internal ldc1612 clock
self._ldc_freq_clk = 12_000_000
self._ldc_settle_time = 0.005
self._ldc_fin_divider = 1
Expand Down Expand Up @@ -211,7 +220,10 @@ def handle_batch(msg):
toolhead.dwell(0.100)
toolhead.wait_moves()
old_config = self.read_reg(REG_CONFIG)
self.set_reg(REG_CONFIG, 0x001 | (1 << 9))
if (self._device_product == PRODUCT_LDC1612_INTERNAL_CLK):
self.set_reg(REG_CONFIG, 0x001)
else:
self.set_reg(REG_CONFIG, 0x001 | (1 << 9))
toolhead.wait_moves()
toolhead.dwell(0.100)
toolhead.wait_moves()
Expand Down Expand Up @@ -260,8 +272,13 @@ def _build_config(self):
cq=cmdqueue,
)

# XXX move this to a totally separate thing at some point
self._mcu.register_response(self._handle_debug_print, "debug_print")
if hasattr(self._mcu, "register_serial_response"):
# infuriating: these used to be able to be registered for optional
# things (that the firmware never sends)
#self._mcu.register_serial_response(self._handle_debug_print, "debug_print m=%*s")
pass
else:
self._mcu.register_response(self._handle_debug_print, "debug_print")

def _handle_debug_print(self, params):
logging.info(params["m"])
Expand Down Expand Up @@ -473,8 +490,13 @@ def _init_chip(self):
)
self.set_reg(REG_ERROR_CONFIG, 0b1111_1100_1111_1001) # report everything to STATUS and INTB except ZC
self.set_reg(REG_MUX_CONFIG, 0x0208 | deglitch)
# RP_OVERRIDE_EN | AUTO_AMP_DIS | REF_CLK_SRC=clkin | reserved
self.set_reg(REG_CONFIG, (1 << 12) | (1 << 10) | (1 << 9) | 0x001)
if (self._device_product == PRODUCT_LDC1612_INTERNAL_CLK):
# use internal oscillator
# RP_OVERRIDE_EN | AUTO_AMP_DIS | reserved
self.set_reg(REG_CONFIG, (1 << 12) | (1 << 10) | 0x001)
else:
# RP_OVERRIDE_EN | AUTO_AMP_DIS | REF_CLK_SRC=clkin | reserved
self.set_reg(REG_CONFIG, (1 << 12) | (1 << 10) | (1 << 9) | 0x001)
self.set_reg(REG_DRIVE_CURRENT0, self._drive_current << 11)

self._chip_initialized = True
Expand Down
51 changes: 37 additions & 14 deletions klippy/extras/probe_eddy_ng.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

from dataclasses import dataclass, field
from typing import (
Any,
Dict,
List,
Optional,
Expand All @@ -43,6 +44,7 @@
from klippy.extras.homing import HomingMove

IS_KALICO = True
HAS_PROBE_RESULT_TYPE = False
except ImportError:
import mcu
import pins
Expand All @@ -56,6 +58,7 @@
from .homing import HomingMove

IS_KALICO = False
HAS_PROBE_RESULT_TYPE = hasattr(manual_probe, "ProbeResult")

from . import ldc1612_ng

Expand Down Expand Up @@ -228,6 +231,8 @@ class ProbeEddyParams:
tap_max_samples: int = 5
# The maximum standard deviation for any 3 samples to be considered valid.
tap_samples_stddev: float = 0.020
# Use the median value instead of the mean
tap_use_median: bool = False
# Where in the time range of tap detection start to the time the threshold
# is crossed should the tap be placed. 0.0 places it at the earliest start
# of tap detection; 1.0 places it at the point where the threshold is hit.
Expand Down Expand Up @@ -323,6 +328,7 @@ def load_from_config(self, config: ConfigWrapper):
self.tap_samples = config.getint("tap_samples", self.tap_samples, minval=1)
self.tap_max_samples = config.getint("tap_max_samples", self.tap_max_samples, minval=self.tap_samples)
self.tap_samples_stddev = config.getfloat("tap_samples_stddev", self.tap_samples_stddev, above=0.0)
self.tap_use_median = config.getboolean("tap_use_median", self.tap_use_median)
self.tap_trigger_safe_start_height = config.getfloat(
"tap_trigger_safe_start_height",
-1.0,
Expand Down Expand Up @@ -437,6 +443,7 @@ def __init__(self, config: ConfigWrapper):
"btt_eddy": ldc1612_ng.LDC1612_ng,
"cartographer": ldc1612_ng.LDC1612_ng,
"mellow_fly": ldc1612_ng.LDC1612_ng,
"ldc1612_internal_clk": ldc1612_ng.LDC1612_ng,
}
sensor_type = config.getchoice("sensor_type", {s: s for s in sensors})

Expand Down Expand Up @@ -1116,7 +1123,7 @@ def cmd_SETUP_next(self, gcmd: GCodeCommand, kin_pos: Optional[List[float]]):
)

max_dc_increase = 0
if self._sensor_type == "ldc1612" or self._sensor_type == "btt_eddy":
if self._sensor_type == "ldc1612" or self._sensor_type == "btt_eddy" or self._sensor_type == "ldc1612_internal_clk":
max_dc_increase = 5
max_dc_increase = gcmd.get_int("MAX_DC_INCREASE", max_dc_increase, minval=0, maxval=30)

Expand Down Expand Up @@ -1418,7 +1425,7 @@ def cmd_TEST_DRIVE_CURRENT(self, gcmd: GCodeCommand):
# PrinterProbe interface
#

def get_offsets(self):
def get_offsets(self, *args, **kwargs):
# the z offset is the trigger height, because the probe will trigger
# at z=trigger_height (not at z=0)
return (
Expand Down Expand Up @@ -1478,7 +1485,7 @@ def multi_probe_end(self):

# This is a mishmash of cmd_PROBE and cmd_PROBE_STATIC. This run_probe
# is the old one, different than the scanning session run_probe.
def run_probe(self, gcmd=None):
def run_probe(self, gcmd=None, *args: Any, **kwargs: Any):
z = self.params.home_trigger_height
duration = 0.100

Expand Down Expand Up @@ -1796,6 +1803,7 @@ def cmd_TAP_next(self, gcmd: Optional[GCodeCommand] = None):
samples = gcmd.get_int("SAMPLES", self.params.tap_samples, minval=1)
max_samples = gcmd.get_int("MAX_SAMPLES", self.params.tap_max_samples, minval=samples)
samples_stddev = gcmd.get_float("SAMPLES_STDDEV", self.params.tap_samples_stddev, above=0.0)
use_median: bool = gcmd.get_int("USE_MEDIAN", 1 if self.params.tap_use_median else 0) == 1
home_z: bool = gcmd.get_int("HOME_Z", 1) == 1
write_plot_arg: int = gcmd.get_int("PLOT", None)

Expand Down Expand Up @@ -1901,7 +1909,7 @@ def cmd_TAP_next(self, gcmd: Optional[GCodeCommand] = None):
break

if len(results) >= samples:
tap_z, tap_stddev, tap_overshoot = self._compute_tap_z(results, samples, samples_stddev)
tap_z, tap_stddev, tap_overshoot = self._compute_tap_z(results, samples, samples_stddev, use_median)
if tap_z is not None:
break
finally:
Expand Down Expand Up @@ -1994,7 +2002,7 @@ def cmd_TAP_next(self, gcmd: Optional[GCodeCommand] = None):

# Compute the average tap_z from a set of tap results, taking a cluster of samples
# from the result that has the lowest standard deviation
def _compute_tap_z(self, taps: List[ProbeEddy.TapResult], samples: int, req_stddev: float) -> Tuple[float, float, float]:
def _compute_tap_z(self, taps: List[ProbeEddy.TapResult], samples: int, req_stddev: float, use_median: bool) -> Tuple[float, float, float]:
if len(taps) < samples:
return None, None, None

Expand All @@ -2004,12 +2012,19 @@ def _compute_tap_z(self, taps: List[ProbeEddy.TapResult], samples: int, req_stdd
for cluster in combinations(taps, samples):
tap_zs = np.array([t.probe_z for t in cluster])
overshoots = np.array([t.overshoot for t in cluster])
mean = np.mean(tap_zs)
std = np.std(tap_zs)
if std < std_min:
std_min = std
tap_z = mean
overshoot = np.mean(overshoots)
if use_median:
# we need the corresponding overshoot as well, so
# can't just use np.median().
sorted_indices = np.argsort(tap_zs)
idx = len(tap_zs) // 2
tap_z = tap_zs[sorted_indices[idx]]
overshoot = overshoots[sorted_indices[idx]]
else:
tap_z = np.mean(tap_zs)
overshoot = np.mean(overshoots)

if std_min <= req_stddev:
return float(tap_z), float(std_min), float(overshoot)
Expand Down Expand Up @@ -2223,7 +2238,7 @@ def _rapid_lookahead_cb(self, time, th_pos):
start_time = time - self._sample_time / 2.0
self._notes.append([start_time, time, th_pos])

def run_probe(self, gcmd):
def run_probe(self, gcmd, *args: Any, **kwargs: Any):
th = self._toolhead
th_pos = th.get_position()

Expand Down Expand Up @@ -2281,15 +2296,23 @@ def pull_probed_results(self):
# the probe would 'trigger'", because this is all done in terms of klicky-type probes
z = float(self._scan_z + z_deviation)

results.append([th_pos[0], th_pos[1], z])
if HAS_PROBE_RESULT_TYPE:
bed_x = th_pos[0] + self.eddy.params.x_offset
bed_y = th_pos[1] + self.eddy.params.y_offset
res = manual_probe.ProbeResult(bed_x, bed_y, z_deviation,
th_pos[0], th_pos[1], th_pos[2])
result_wrapper = [res]
self._printer.send_event("probe:update_results", result_wrapper)
res = result_wrapper[0]
else:
res = [th_pos[0], th_pos[1], z]
self._printer.send_event("probe:update_results", res)

results.append(res)

# reset notes so that this session can continue to be used
self._notes = []

# Allow axis_twist_compensation to update results
for epos in results:
self._printer.send_event("probe:update_results", epos)

return results


Expand Down
4 changes: 4 additions & 0 deletions src/sensor_ldc1612_ng.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ enum {
#define PRODUCT_BTT_EDDY 1
#define PRODUCT_CARTOGRAPHER 2
#define PRODUCT_MELLOW_FLY 3
#define PRODUCT_LDC1612_INTERNAL_CLK 4

// Chip registers
#define REG_DATA0_MSB 0x00
Expand Down Expand Up @@ -348,6 +349,9 @@ config_ldc1612_ng(uint32_t oid, uint32_t i2c_oid, uint8_t product, int32_t intb_
// pull that out on the python side.
break;
#endif
case PRODUCT_LDC1612_INTERNAL_CLK:
ld->sensor_cvt = 43400000.0f / (float)(1<<28);
break;
default:
shutdown("ldc1612_ng: unknown product");
}
Expand Down
Loading