mirror of
https://github.com/Klipper3d/klipper.git
synced 2026-01-18 05:45:44 -07:00
Merge b8e516e3b5 into 48f0b3cad6
This commit is contained in:
commit
11ca4a3f78
4 changed files with 319 additions and 0 deletions
|
|
@ -223,6 +223,81 @@ far above the nozzle as possible to avoid it touching printed parts.
|
|||
If an adjustment is made to the probe position, then rerun the probe
|
||||
calibration steps.
|
||||
|
||||
## Automatic Z-Offset Calibration
|
||||
|
||||
The BLTouch supports automatic z-offset calibration using electrical
|
||||
contact detection between the nozzle and a conductive bed surface.
|
||||
This feature eliminates the need for manual paper testing and provides
|
||||
accurate, repeatable results.
|
||||
|
||||
### Hardware Requirements
|
||||
|
||||
- **Conductive bed surface**: Aluminum, steel, or exposed metal
|
||||
- **GPIO connection**: Bed surface connected to a GPIO pin with pull-up resistor
|
||||
- **Electrical ground**: Nozzle/hotend connected to ground
|
||||
- **Clean nozzle**: Free of plastic residue for reliable contact
|
||||
|
||||
### Configuration
|
||||
|
||||
Add the `nozzle_probe_pin` parameter to your [bltouch] section:
|
||||
|
||||
```
|
||||
[bltouch]
|
||||
# ... existing configuration ...
|
||||
nozzle_probe_pin: ^!P1.25 # GPIO pin for bed connection
|
||||
calibration_position: 100, 100 # XY position for calibration
|
||||
nozzle_temp: 200 # Heating temperature during calibration
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
Basic automatic calibration:
|
||||
```
|
||||
BLTOUCH_AUTO_Z_OFFSET
|
||||
```
|
||||
|
||||
With options:
|
||||
```
|
||||
# Calibration without heating (for testing)
|
||||
BLTOUCH_AUTO_Z_OFFSET HEAT_NOZZLE=0
|
||||
|
||||
# Calibration at specific position
|
||||
BLTOUCH_AUTO_Z_OFFSET POSITION=150,150
|
||||
|
||||
# Custom temperature
|
||||
BLTOUCH_AUTO_Z_OFFSET NOZZLE_TEMP=210
|
||||
```
|
||||
|
||||
The calibration process:
|
||||
1. Homes all axes if needed
|
||||
2. Moves to the calibration position
|
||||
3. Heats the nozzle (if enabled)
|
||||
4. Performs BLTouch probing for reference
|
||||
5. Detects electrical contact between nozzle and bed
|
||||
6. Calculates and updates the z-offset
|
||||
|
||||
After calibration, use `SAVE_CONFIG` to make the new z-offset permanent.
|
||||
|
||||
### Bed Preparation
|
||||
|
||||
**For PEI/PET coated beds**: Carefully scrape away a small 5x5mm area
|
||||
of coating to expose the underlying metal at your calibration position.
|
||||
Clean with isopropyl alcohol.
|
||||
|
||||
**For non-conductive beds**: Apply copper tape or aluminum foil at the
|
||||
calibration position and connect with wire to the GPIO pin.
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
**"Nozzle probe already triggered" error**: Check GPIO pin configuration
|
||||
(pull-up and inversion), verify wiring with multimeter.
|
||||
|
||||
**Inconsistent results**: Clean nozzle thoroughly, check bed conductivity,
|
||||
ensure stable electrical connections.
|
||||
|
||||
**Large offset errors**: Verify BLTouch mounting security, confirm
|
||||
electrical continuity with multimeter.
|
||||
|
||||
## BL-Touch output mode
|
||||
|
||||
* A BL-Touch V3.0 supports setting a 5V or OPEN-DRAIN output mode,
|
||||
|
|
|
|||
|
|
@ -2199,6 +2199,45 @@ control_pin:
|
|||
#samples_tolerance:
|
||||
#samples_tolerance_retries:
|
||||
# See the "probe" section for information on these parameters.
|
||||
#nozzle_probe_pin:
|
||||
# Pin connected to the conductive bed surface for nozzle contact detection
|
||||
# during automatic z-offset calibration. This parameter enables the
|
||||
# BLTOUCH_AUTO_Z_OFFSET command. The pin should be configured with a
|
||||
# pull-up resistor (prefix with ^) and may need logic inversion (prefix
|
||||
# with !). Example: "^!P1.25" for an inverted pin P1.25 with pull-up.
|
||||
# This parameter is optional; if not specified, auto calibration will
|
||||
# not be available.
|
||||
#calibration_position: 5, 5
|
||||
# X, Y coordinates (in mm) where automatic z-offset calibration will be
|
||||
# performed. This should be a position on the bed with good electrical
|
||||
# conductivity and within the probe's reachable area considering the
|
||||
# probe offsets. The default is 5, 5.
|
||||
#nozzle_temp: 200
|
||||
# Nozzle temperature (in Celsius) to use during automatic calibration.
|
||||
# Heating ensures any residual filament is soft and won't interfere
|
||||
# with electrical contact detection. The default is 200.
|
||||
#calibration_probe_speed: 5.0
|
||||
# Speed (in mm/s) for initial probe movements during calibration.
|
||||
# The default is 5.0.
|
||||
#calibration_probe_speed_slow: 1.0
|
||||
# Speed (in mm/s) for final accurate probe movements during calibration.
|
||||
# Lower speeds increase accuracy. The default is 1.0.
|
||||
#calibration_lift_speed: 10.0
|
||||
# Speed (in mm/s) for lift movements between probing operations during
|
||||
# calibration. The default is 10.0.
|
||||
#calibration_retract_dist: 2.0
|
||||
# Distance (in mm) to lift between BLTouch probe attempts during
|
||||
# calibration. The default is 2.0.
|
||||
#calibration_nozzle_retract_dist: 2.0
|
||||
# Distance (in mm) to lift between nozzle touch attempts during
|
||||
# calibration. The default is 2.0.
|
||||
#calibration_nozzle_samples: 1
|
||||
# Number of nozzle touch samples to average for increased accuracy.
|
||||
# More samples increase calibration time but may improve consistency.
|
||||
# Must be between 1 and 10. The default is 1.
|
||||
#calibration_nozzle_diameter: 0.4
|
||||
# Nozzle diameter (in mm) for informational purposes and future
|
||||
# enhancements to the calibration algorithm. The default is 0.4.
|
||||
```
|
||||
|
||||
### [smart_effector]
|
||||
|
|
|
|||
|
|
@ -267,6 +267,28 @@ V3.0 or V3.1 may also support `set_5V_output_mode`,
|
|||
`BLTOUCH_STORE MODE=<output_mode>`: This stores an output mode in the
|
||||
EEPROM of a BLTouch V3.1 Available output_modes are: `5V`, `OD`
|
||||
|
||||
#### BLTOUCH_AUTO_Z_OFFSET
|
||||
`BLTOUCH_AUTO_Z_OFFSET [HEAT_NOZZLE=<0|1>] [NOZZLE_TEMP=<temp>] [POSITION=<x,y>]`:
|
||||
Performs automatic z-offset calibration for the BLTouch using electrical
|
||||
contact detection between the nozzle and a conductive bed surface. This
|
||||
command requires `nozzle_probe_pin` to be configured in the [bltouch]
|
||||
section.
|
||||
|
||||
The calibration process:
|
||||
1. Homes all axes if not already done
|
||||
2. Moves to the calibration position
|
||||
3. Heats the nozzle (if enabled)
|
||||
4. Performs BLTouch probing to establish a reference
|
||||
5. Detects electrical contact between nozzle and bed
|
||||
6. Calculates and updates the z-offset
|
||||
|
||||
Parameters:
|
||||
- `HEAT_NOZZLE`: Set to 0 to skip nozzle heating, 1 to heat (default: 1)
|
||||
- `NOZZLE_TEMP`: Override nozzle temperature in Celsius (default: from config)
|
||||
- `POSITION`: Override calibration position as "x,y" in mm (default: from config)
|
||||
|
||||
Note: After calibration, use `SAVE_CONFIG` to make the new z-offset permanent.
|
||||
|
||||
### [configfile]
|
||||
|
||||
The configfile module is automatically loaded.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# BLTouch support
|
||||
#
|
||||
# Copyright (C) 2018-2024 Kevin O'Connor <kevin@koconnor.net>
|
||||
# Copyright (C) 2025 Marco Abbattista <max.abbattista@llive.it>
|
||||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import logging
|
||||
|
|
@ -41,6 +42,34 @@ class BLTouchProbe:
|
|||
self.finish_home_complete = self.wait_trigger_complete = None
|
||||
# Create an "endstop" object to handle the sensor pin
|
||||
self.mcu_endstop = ppins.setup_pin('endstop', config.get('sensor_pin'))
|
||||
# Setup nozzle probe pin for auto z-offset calibration (optional)
|
||||
nozzle_probe_pin = config.get('nozzle_probe_pin', None)
|
||||
if nozzle_probe_pin is not None:
|
||||
self.nozzle_endstop = ppins.setup_pin('endstop', nozzle_probe_pin)
|
||||
# Register Z steppers with the nozzle endstop
|
||||
probe.LookupZSteppers(config, self.nozzle_endstop.add_stepper)
|
||||
self.calibration_position = config.getfloatlist('calibration_position',
|
||||
default=[5., 5.], count=2)
|
||||
self.nozzle_temp = config.getfloat('nozzle_temp', 200., above=0.)
|
||||
# Calibration probe speeds and distances
|
||||
self.cal_probe_speed = config.getfloat('calibration_probe_speed', 5.0, above=0.)
|
||||
self.cal_probe_speed_slow = config.getfloat('calibration_probe_speed_slow', 1.0, above=0.)
|
||||
self.cal_lift_speed = config.getfloat('calibration_lift_speed', 10.0, above=0.)
|
||||
self.cal_retract_dist = config.getfloat('calibration_retract_dist', 2.0, above=0.)
|
||||
self.cal_nozzle_retract_dist = config.getfloat('calibration_nozzle_retract_dist', 2.0, above=0.)
|
||||
self.cal_nozzle_samples = config.getint('calibration_nozzle_samples', 1, minval=1, maxval=10)
|
||||
self.cal_nozzle_diameter = config.getfloat('calibration_nozzle_diameter', 0.4, above=0.)
|
||||
else:
|
||||
self.nozzle_endstop = None
|
||||
self.calibration_position = None
|
||||
self.nozzle_temp = None
|
||||
self.cal_probe_speed = None
|
||||
self.cal_probe_speed_slow = None
|
||||
self.cal_lift_speed = None
|
||||
self.cal_retract_dist = None
|
||||
self.cal_nozzle_retract_dist = None
|
||||
self.cal_nozzle_samples = None
|
||||
self.cal_nozzle_diameter = None
|
||||
# output mode
|
||||
omodes = ['5V', 'OD', None]
|
||||
self.output_mode = config.getchoice('set_output_mode', omodes, None)
|
||||
|
|
@ -75,6 +104,11 @@ class BLTouchProbe:
|
|||
desc=self.cmd_BLTOUCH_DEBUG_help)
|
||||
self.gcode.register_command("BLTOUCH_STORE", self.cmd_BLTOUCH_STORE,
|
||||
desc=self.cmd_BLTOUCH_STORE_help)
|
||||
# Register auto z-offset calibration command if nozzle probe is configured
|
||||
if self.nozzle_endstop is not None:
|
||||
self.gcode.register_command("BLTOUCH_AUTO_Z_OFFSET",
|
||||
self.cmd_BLTOUCH_AUTO_Z_OFFSET,
|
||||
desc=self.cmd_BLTOUCH_AUTO_Z_OFFSET_help)
|
||||
# Register events
|
||||
self.printer.register_event_handler("klippy:connect",
|
||||
self.handle_connect)
|
||||
|
|
@ -281,6 +315,155 @@ class BLTouchProbe:
|
|||
self.sync_print_time()
|
||||
self.store_output_mode(cmd)
|
||||
self.sync_print_time()
|
||||
cmd_BLTOUCH_AUTO_Z_OFFSET_help = "Automatically calibrate BLTouch z-offset using nozzle probe"
|
||||
def cmd_BLTOUCH_AUTO_Z_OFFSET(self, gcmd):
|
||||
if self.nozzle_endstop is None:
|
||||
raise gcmd.error("nozzle_probe_pin not configured in [bltouch] section")
|
||||
|
||||
# Check if nozzle probe is already triggered before starting
|
||||
curtime = self.printer.get_reactor().monotonic()
|
||||
nozzle_triggered = self.nozzle_endstop.query_endstop(curtime)
|
||||
if nozzle_triggered:
|
||||
raise gcmd.error("Nozzle probe is already triggered. Please check for obstructions and ensure the nozzle is clear before starting calibration.")
|
||||
|
||||
toolhead = self.printer.lookup_object('toolhead')
|
||||
gcode = self.printer.lookup_object('gcode')
|
||||
heaters = self.printer.lookup_object('heaters')
|
||||
|
||||
# Get optional parameters
|
||||
heat_nozzle = gcmd.get_int('HEAT_NOZZLE', 1) # Default: 1 (enabled)
|
||||
nozzle_temp = gcmd.get_float('NOZZLE_TEMP', self.nozzle_temp, above=0.)
|
||||
cal_pos = gcmd.get('POSITION', None)
|
||||
if cal_pos:
|
||||
cal_x, cal_y = [float(v.strip()) for v in cal_pos.split(',')]
|
||||
else:
|
||||
cal_x, cal_y = self.calibration_position
|
||||
|
||||
# Step 1: Home all axes
|
||||
gcode.run_script_from_command("G28")
|
||||
|
||||
# Step 2: Move to calibration position considering BLTouch offset
|
||||
# If we want BLTouch at position (cal_x, cal_y), we need to move toolhead to:
|
||||
# toolhead_x = cal_x - x_offset, toolhead_y = cal_y - y_offset
|
||||
x_offset, y_offset, _ = self.get_offsets()
|
||||
toolhead_x = cal_x - x_offset
|
||||
toolhead_y = cal_y - y_offset
|
||||
toolhead.manual_move([toolhead_x, toolhead_y, None], 50.)
|
||||
|
||||
# Step 3: Heat nozzle if needed and enabled
|
||||
if heat_nozzle and nozzle_temp > 0:
|
||||
gcmd.respond_info("Heating nozzle to %.1f°C..." % nozzle_temp)
|
||||
extruder = toolhead.get_extruder()
|
||||
heaters.set_temperature(extruder.get_heater(), nozzle_temp, True)
|
||||
|
||||
# Step 4: BLTouch probe - EXACT SAME as PROBE_CALIBRATE
|
||||
gcmd.respond_info("Performing BLTouch probe (PROBE_CALIBRATE method)...")
|
||||
|
||||
# Import probe utilities
|
||||
from . import probe
|
||||
|
||||
# Use run_single_probe - EXACT SAME method as PROBE_CALIBRATE
|
||||
# This ensures same coordinate reference system
|
||||
bltouch_pos = probe.run_single_probe(self, gcmd)
|
||||
z_bltouch_reference = bltouch_pos[2]
|
||||
|
||||
gcmd.respond_info("BLTouch reference position: %.6f" % z_bltouch_reference)
|
||||
|
||||
# Step 5: Move up and position nozzle - SAME as PROBE_CALIBRATE
|
||||
# Move away from the bed (same 5mm lift as PROBE_CALIBRATE)
|
||||
lift_pos = list(bltouch_pos)
|
||||
lift_pos[2] += 5.
|
||||
toolhead.manual_move(lift_pos, self.cal_lift_speed)
|
||||
|
||||
# Move the nozzle over the probe point - SAME as PROBE_CALIBRATE
|
||||
x_offset, y_offset, z_offset = self.get_offsets()
|
||||
lift_pos[0] += x_offset
|
||||
lift_pos[1] += y_offset
|
||||
toolhead.manual_move(lift_pos, self.cal_probe_speed)
|
||||
|
||||
gcmd.respond_info("Nozzle positioned over probe point at Z=%.6f" % lift_pos[2])
|
||||
|
||||
# Step 6: Nozzle probe - Use direct probing method for endstop
|
||||
gcmd.respond_info("Performing nozzle probe (PROBE_CALIBRATE coordinate system)...")
|
||||
|
||||
# Use homing module directly with nozzle endstop - SAME coordinate system
|
||||
phoming = self.printer.lookup_object('homing')
|
||||
|
||||
# Get current position and probe down to find bed
|
||||
current_pos = toolhead.get_position()
|
||||
|
||||
# Get Z minimum position safely
|
||||
z_min = -5.0 # Use position_min from config
|
||||
try:
|
||||
config = self.printer.lookup_object('configfile')
|
||||
z_config = config.status_raw_config.get('stepper_z', {})
|
||||
z_min = float(z_config.get('position_min', -5.0))
|
||||
except:
|
||||
z_min = -5.0
|
||||
|
||||
# Create probe target position - probe down to find bed
|
||||
probe_target = [current_pos[0], current_pos[1], z_min]
|
||||
|
||||
gcmd.respond_info("Nozzle probing from Z=%.3f to Z=%.3f..." % (current_pos[2], z_min))
|
||||
|
||||
# Use probing_move with nozzle endstop - SAME coordinate system as BLTouch
|
||||
nozzle_pos = phoming.probing_move(self.nozzle_endstop, probe_target, self.cal_probe_speed_slow)
|
||||
z_nozzle_reference = nozzle_pos[2]
|
||||
|
||||
gcmd.respond_info("Nozzle reference position: %.6f" % z_nozzle_reference)
|
||||
|
||||
# Step 7: Calculate z_offset - EXACT SAME formula as PROBE_CALIBRATE
|
||||
# z_offset = probe_calibrate_z - final_nozzle_z
|
||||
# In PROBE_CALIBRATE: z_offset = self.probe_calibrate_z - kin_pos[2]
|
||||
new_z_offset = z_bltouch_reference - z_nozzle_reference
|
||||
|
||||
gcmd.respond_info("BLTouch reference: %.6f, Nozzle reference: %.6f" %
|
||||
(z_bltouch_reference, z_nozzle_reference))
|
||||
gcmd.respond_info("Calculated z_offset: %.6f" % new_z_offset)
|
||||
|
||||
# Validate against expected physical measurement
|
||||
expected_offset = 4.1 # Your measured physical distance
|
||||
offset_error = abs(new_z_offset - expected_offset)
|
||||
|
||||
gcmd.respond_info("Calculated: %.6f, Expected: %.6f, Error: %.6f" %
|
||||
(new_z_offset, expected_offset, offset_error))
|
||||
|
||||
if offset_error > 1.0:
|
||||
gcmd.respond_info("WARNING: Large offset error detected. Check BLTouch mounting and nozzle probe configuration.")
|
||||
|
||||
# Validate that the offset makes physical sense
|
||||
if new_z_offset < 0:
|
||||
raise gcmd.error(
|
||||
"Invalid z-offset calculation: %.6f\n"
|
||||
"BLTouch Z: %.6f, Nozzle Z: %.6f\n"
|
||||
"The nozzle should trigger at a lower Z position than the BLTouch.\n"
|
||||
"Please check your wiring and probe configuration." %
|
||||
(new_z_offset, z_bltouch_reference, z_nozzle_reference))
|
||||
|
||||
# Move up for safety
|
||||
toolhead.manual_move([None, None, max(z_bltouch_reference, z_nozzle_reference) + 10.], 50.)
|
||||
|
||||
# Save the positive offset value
|
||||
save_z_offset = new_z_offset
|
||||
|
||||
# Save the new z-offset
|
||||
self.position_endstop = save_z_offset
|
||||
configfile = self.printer.lookup_object('configfile')
|
||||
configfile.set('bltouch', 'z_offset', "%.6f" % save_z_offset)
|
||||
|
||||
gcmd.respond_info(
|
||||
"BLTouch z_offset calibration complete!\n"
|
||||
"New z_offset: %.6f\n"
|
||||
"The SAVE_CONFIG command will update the printer config file\n"
|
||||
"with the above and restart the printer." % save_z_offset)
|
||||
|
||||
# Re-home to restore coordinate system integrity
|
||||
gcmd.respond_info("Re-homing to restore coordinate system...")
|
||||
gcode.run_script_from_command("G28")
|
||||
|
||||
# Verify coordinate restoration
|
||||
restored_pos = toolhead.get_position()
|
||||
gcmd.respond_info("Coordinate system restored. Current Z position: %.6f" % restored_pos[2])
|
||||
|
||||
def load_config(config):
|
||||
blt = BLTouchProbe(config)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue