2018-11-25 03:41:25 +01:00
|
|
|
# BLTouch support
|
|
|
|
#
|
bltouch: Update command timing
Prior to the BLTouch v3, the recommended command times were 700us
(pin_down), 1200us (touch_mode), 1500us (pin_up), 1800us (self_test),
and 2200us (reset). However, the recommended Marlin timing (via servo
"angles") was 647.111, 1162.667, 1472, 1781.333, and 2193.778us.
As of the BLTouch v3, the recommended times are now 650, 1165, 1475,
1780, and 2190us. The v3 continues to recommended Marlin timings of
647.111, 1162.667, 1472, 1781.333, and 2193.778us.
Update Klipper to use the new BL-Touch v3 recommended timing. The new
timings are required for the BL-Touch v3 and they are closer to what
the Marlin firmware has historically used.
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
2019-05-21 00:50:56 +02:00
|
|
|
# Copyright (C) 2018-2019 Kevin O'Connor <kevin@koconnor.net>
|
2018-11-25 03:41:25 +01:00
|
|
|
#
|
|
|
|
# This file may be distributed under the terms of the GNU GPLv3 license.
|
2018-12-04 15:45:11 +01:00
|
|
|
import math, logging
|
2018-11-25 03:41:25 +01:00
|
|
|
import homing, probe
|
|
|
|
|
bltouch: Update command timing
Prior to the BLTouch v3, the recommended command times were 700us
(pin_down), 1200us (touch_mode), 1500us (pin_up), 1800us (self_test),
and 2200us (reset). However, the recommended Marlin timing (via servo
"angles") was 647.111, 1162.667, 1472, 1781.333, and 2193.778us.
As of the BLTouch v3, the recommended times are now 650, 1165, 1475,
1780, and 2190us. The v3 continues to recommended Marlin timings of
647.111, 1162.667, 1472, 1781.333, and 2193.778us.
Update Klipper to use the new BL-Touch v3 recommended timing. The new
timings are required for the BL-Touch v3 and they are closer to what
the Marlin firmware has historically used.
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
2019-05-21 00:50:56 +02:00
|
|
|
SIGNAL_PERIOD = 0.020
|
|
|
|
MIN_CMD_TIME = 5 * SIGNAL_PERIOD
|
2018-11-25 03:41:25 +01:00
|
|
|
|
|
|
|
TEST_TIME = 5 * 60.
|
2019-01-29 18:09:58 +01:00
|
|
|
RETRY_RESET_TIME = 1.
|
2018-12-13 22:45:32 +01:00
|
|
|
ENDSTOP_REST_TIME = .001
|
2018-11-25 03:41:25 +01:00
|
|
|
ENDSTOP_SAMPLE_TIME = .000015
|
|
|
|
ENDSTOP_SAMPLE_COUNT = 4
|
|
|
|
|
2018-12-04 04:52:32 +01:00
|
|
|
Commands = {
|
bltouch: Update command timing
Prior to the BLTouch v3, the recommended command times were 700us
(pin_down), 1200us (touch_mode), 1500us (pin_up), 1800us (self_test),
and 2200us (reset). However, the recommended Marlin timing (via servo
"angles") was 647.111, 1162.667, 1472, 1781.333, and 2193.778us.
As of the BLTouch v3, the recommended times are now 650, 1165, 1475,
1780, and 2190us. The v3 continues to recommended Marlin timings of
647.111, 1162.667, 1472, 1781.333, and 2193.778us.
Update Klipper to use the new BL-Touch v3 recommended timing. The new
timings are required for the BL-Touch v3 and they are closer to what
the Marlin firmware has historically used.
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
2019-05-21 00:50:56 +02:00
|
|
|
None: 0.0, 'pin_down': 0.000650, 'touch_mode': 0.001165,
|
|
|
|
'pin_up': 0.001475, 'self_test': 0.001780, 'reset': 0.002190,
|
2020-02-24 04:32:07 +01:00
|
|
|
'set_5V_output_mode' : 0.001988, 'set_OD_output_mode' : 0.002091,
|
|
|
|
'output_mode_store' : 0.001884,
|
2018-12-04 04:52:32 +01:00
|
|
|
}
|
2018-11-25 03:41:25 +01:00
|
|
|
|
|
|
|
# BLTouch "endstop" wrapper
|
|
|
|
class BLTouchEndstopWrapper:
|
|
|
|
def __init__(self, config):
|
|
|
|
self.printer = config.get_printer()
|
2019-01-05 02:37:42 +01:00
|
|
|
self.printer.register_event_handler("klippy:connect",
|
|
|
|
self.handle_connect)
|
2018-11-25 03:41:25 +01:00
|
|
|
self.position_endstop = config.getfloat('z_offset')
|
2020-02-13 16:29:28 +01:00
|
|
|
self.stow_on_each_sample = config.getboolean('stow_on_each_sample',
|
|
|
|
True)
|
2018-11-25 03:41:25 +01:00
|
|
|
# Create a pwm object to handle the control pin
|
|
|
|
ppins = self.printer.lookup_object('pins')
|
|
|
|
self.mcu_pwm = ppins.setup_pin('pwm', config.get('control_pin'))
|
|
|
|
self.mcu_pwm.setup_max_duration(0.)
|
|
|
|
self.mcu_pwm.setup_cycle_time(SIGNAL_PERIOD)
|
2019-01-05 17:18:07 +01:00
|
|
|
self.next_cmd_time = 0.
|
2018-11-25 03:41:25 +01:00
|
|
|
# Create an "endstop" object to handle the sensor pin
|
|
|
|
pin = config.get('sensor_pin')
|
|
|
|
pin_params = ppins.lookup_pin(pin, can_invert=True, can_pullup=True)
|
|
|
|
mcu = pin_params['chip']
|
|
|
|
mcu.register_config_callback(self._build_config)
|
|
|
|
self.mcu_endstop = mcu.setup_pin('endstop', pin_params)
|
2020-02-24 04:32:07 +01:00
|
|
|
# output mode
|
|
|
|
self.output_mode = config.getchoice('set_output_mode',
|
|
|
|
{'5V': '5V', 'OD': 'OD',
|
|
|
|
None: None}, None)
|
2018-12-13 22:58:34 +01:00
|
|
|
# Setup for sensor test
|
|
|
|
self.next_test_time = 0.
|
2019-01-05 02:20:02 +01:00
|
|
|
self.pin_up_not_triggered = config.getboolean(
|
|
|
|
'pin_up_reports_not_triggered', True)
|
2019-01-05 02:41:56 +01:00
|
|
|
self.pin_up_touch_triggered = config.getboolean(
|
|
|
|
'pin_up_touch_mode_reports_triggered', True)
|
2019-01-05 01:12:50 +01:00
|
|
|
self.start_mcu_pos = []
|
2018-12-04 15:45:11 +01:00
|
|
|
# Calculate pin move time
|
2019-01-31 15:53:21 +01:00
|
|
|
pmt = max(config.getfloat('pin_move_time', 0.675), MIN_CMD_TIME)
|
2018-12-04 15:45:11 +01:00
|
|
|
self.pin_move_time = math.ceil(pmt / SIGNAL_PERIOD) * SIGNAL_PERIOD
|
2018-11-25 03:41:25 +01:00
|
|
|
# Wrappers
|
|
|
|
self.get_mcu = self.mcu_endstop.get_mcu
|
|
|
|
self.add_stepper = self.mcu_endstop.add_stepper
|
|
|
|
self.get_steppers = self.mcu_endstop.get_steppers
|
|
|
|
self.home_wait = self.mcu_endstop.home_wait
|
|
|
|
self.query_endstop = self.mcu_endstop.query_endstop
|
2018-12-04 04:52:32 +01:00
|
|
|
# Register BLTOUCH_DEBUG command
|
|
|
|
self.gcode = self.printer.lookup_object('gcode')
|
|
|
|
self.gcode.register_command("BLTOUCH_DEBUG", self.cmd_BLTOUCH_DEBUG,
|
|
|
|
desc=self.cmd_BLTOUCH_DEBUG_help)
|
2020-02-24 04:32:07 +01:00
|
|
|
self.gcode.register_command("BLTOUCH_STORE", self.cmd_BLTOUCH_STORE,
|
|
|
|
desc=self.cmd_BLTOUCH_STORE_help)
|
2020-02-13 16:29:28 +01:00
|
|
|
# multi probes state
|
|
|
|
self.multi = 'OFF'
|
2018-11-25 03:41:25 +01:00
|
|
|
def _build_config(self):
|
|
|
|
kin = self.printer.lookup_object('toolhead').get_kinematics()
|
2020-01-14 03:39:55 +01:00
|
|
|
for stepper in kin.get_steppers():
|
|
|
|
if stepper.is_active_axis('z'):
|
|
|
|
self.add_stepper(stepper)
|
2019-01-05 02:37:42 +01:00
|
|
|
def handle_connect(self):
|
2020-02-24 04:32:07 +01:00
|
|
|
self.set_output_mode(self.output_mode)
|
2019-01-05 02:37:42 +01:00
|
|
|
try:
|
|
|
|
self.raise_probe()
|
2019-06-03 19:07:22 +02:00
|
|
|
except homing.CommandError as e:
|
2019-01-29 17:57:08 +01:00
|
|
|
logging.warning("BLTouch raise probe error: %s", str(e))
|
2019-01-05 01:18:09 +01:00
|
|
|
def sync_mcu_print_time(self):
|
|
|
|
curtime = self.printer.get_reactor().monotonic()
|
|
|
|
est_time = self.mcu_pwm.get_mcu().estimated_print_time(curtime)
|
|
|
|
self.next_cmd_time = max(self.next_cmd_time, est_time + MIN_CMD_TIME)
|
2019-01-05 17:18:07 +01:00
|
|
|
def sync_print_time(self):
|
|
|
|
toolhead = self.printer.lookup_object('toolhead')
|
|
|
|
print_time = toolhead.get_last_move_time()
|
|
|
|
if self.next_cmd_time > print_time:
|
|
|
|
toolhead.dwell(self.next_cmd_time - print_time)
|
|
|
|
else:
|
|
|
|
self.next_cmd_time = print_time
|
|
|
|
def send_cmd(self, cmd, duration=MIN_CMD_TIME):
|
|
|
|
self.mcu_pwm.set_pwm(self.next_cmd_time, Commands[cmd] / SIGNAL_PERIOD)
|
2019-01-07 18:05:37 +01:00
|
|
|
# Translate duration to ticks to avoid any secondary mcu clock skew
|
|
|
|
mcu = self.mcu_pwm.get_mcu()
|
|
|
|
cmd_clock = mcu.print_time_to_clock(self.next_cmd_time)
|
|
|
|
cmd_clock += mcu.seconds_to_clock(max(duration, MIN_CMD_TIME))
|
|
|
|
self.next_cmd_time = mcu.clock_to_print_time(cmd_clock)
|
2019-01-05 17:18:07 +01:00
|
|
|
return self.next_cmd_time
|
2019-01-05 02:20:02 +01:00
|
|
|
def verify_state(self, check_start_time, check_end_time, triggered, msg):
|
|
|
|
# Perform endstop check to verify bltouch reports desired state
|
|
|
|
self.mcu_endstop.home_start(check_start_time, ENDSTOP_SAMPLE_TIME,
|
|
|
|
ENDSTOP_SAMPLE_COUNT, ENDSTOP_REST_TIME,
|
|
|
|
triggered=triggered)
|
2020-02-19 18:07:30 +01:00
|
|
|
did_trigger = self.mcu_endstop.home_wait(check_end_time)
|
|
|
|
if not did_trigger:
|
2019-01-05 02:20:02 +01:00
|
|
|
raise homing.EndstopError("BLTouch failed to %s" % (msg,))
|
2019-01-05 02:37:42 +01:00
|
|
|
def raise_probe(self):
|
2019-01-29 18:09:58 +01:00
|
|
|
for retry in range(3):
|
|
|
|
self.sync_mcu_print_time()
|
2019-01-31 15:55:53 +01:00
|
|
|
if retry or not self.pin_up_not_triggered:
|
|
|
|
self.send_cmd('reset')
|
2019-01-29 18:09:58 +01:00
|
|
|
check_start_time = self.send_cmd('pin_up',
|
|
|
|
duration=self.pin_move_time)
|
|
|
|
check_end_time = self.send_cmd(None)
|
|
|
|
if self.pin_up_not_triggered:
|
|
|
|
try:
|
|
|
|
self.verify_state(check_start_time, check_end_time,
|
|
|
|
False, "raise probe")
|
2019-06-03 19:07:22 +02:00
|
|
|
except homing.CommandError as e:
|
2019-01-29 18:09:58 +01:00
|
|
|
if retry >= 2:
|
|
|
|
raise
|
|
|
|
msg = "Failed to verify BLTouch probe is raised; retrying."
|
|
|
|
self.gcode.respond_info(msg)
|
|
|
|
self.next_cmd_time += RETRY_RESET_TIME
|
|
|
|
continue
|
|
|
|
break
|
2020-02-13 16:29:28 +01:00
|
|
|
def lower_probe(self):
|
|
|
|
self.test_sensor()
|
|
|
|
self.sync_print_time()
|
|
|
|
duration = max(MIN_CMD_TIME, self.pin_move_time - MIN_CMD_TIME)
|
|
|
|
self.send_cmd('pin_down', duration=duration)
|
|
|
|
self.send_cmd(None)
|
2018-11-25 03:41:25 +01:00
|
|
|
def test_sensor(self):
|
2019-01-05 02:41:56 +01:00
|
|
|
if not self.pin_up_touch_triggered:
|
|
|
|
# Nothing to test
|
2018-12-13 22:58:34 +01:00
|
|
|
return
|
2018-11-25 03:41:25 +01:00
|
|
|
toolhead = self.printer.lookup_object('toolhead')
|
|
|
|
print_time = toolhead.get_last_move_time()
|
|
|
|
if print_time < self.next_test_time:
|
|
|
|
self.next_test_time = print_time + TEST_TIME
|
|
|
|
return
|
2018-12-02 04:09:06 +01:00
|
|
|
# Raise the bltouch probe and test if probe is raised
|
2019-01-05 17:18:07 +01:00
|
|
|
self.sync_print_time()
|
|
|
|
check_start_time = self.send_cmd('reset', duration=self.pin_move_time)
|
|
|
|
check_end_time = self.send_cmd('touch_mode')
|
|
|
|
self.send_cmd(None)
|
2019-01-05 02:20:02 +01:00
|
|
|
self.verify_state(check_start_time, check_end_time, True,
|
|
|
|
"verify sensor state")
|
2018-12-02 04:09:06 +01:00
|
|
|
# Test was successful
|
2019-01-05 17:18:07 +01:00
|
|
|
self.next_test_time = check_end_time + TEST_TIME
|
|
|
|
self.sync_print_time()
|
2020-02-12 19:37:55 +01:00
|
|
|
def multi_probe_begin(self):
|
2020-02-13 16:29:28 +01:00
|
|
|
if self.stow_on_each_sample:
|
|
|
|
return
|
|
|
|
self.multi = 'FIRST'
|
2020-02-12 19:37:55 +01:00
|
|
|
def multi_probe_end(self):
|
2020-02-13 16:29:28 +01:00
|
|
|
if self.stow_on_each_sample:
|
|
|
|
return
|
|
|
|
self.raise_probe()
|
|
|
|
self.multi = 'OFF'
|
2020-02-12 19:03:42 +01:00
|
|
|
def probe_prepare(self):
|
2020-02-13 16:29:28 +01:00
|
|
|
if self.multi == 'OFF' or self.multi == 'FIRST':
|
|
|
|
self.lower_probe()
|
|
|
|
if self.multi == 'FIRST':
|
|
|
|
self.multi = 'ON'
|
2019-01-05 17:18:07 +01:00
|
|
|
self.sync_print_time()
|
2019-11-14 05:34:21 +01:00
|
|
|
toolhead = self.printer.lookup_object('toolhead')
|
|
|
|
toolhead.flush_step_generation()
|
2019-01-05 01:12:50 +01:00
|
|
|
self.start_mcu_pos = [(s, s.get_mcu_position())
|
|
|
|
for s in self.mcu_endstop.get_steppers()]
|
2020-02-12 19:03:42 +01:00
|
|
|
def probe_finalize(self):
|
2020-02-13 16:29:28 +01:00
|
|
|
if self.multi == 'OFF':
|
|
|
|
self.raise_probe()
|
2019-01-05 17:18:07 +01:00
|
|
|
self.sync_print_time()
|
2019-01-05 01:12:50 +01:00
|
|
|
# Verify the probe actually deployed during the attempt
|
|
|
|
for s, mcu_pos in self.start_mcu_pos:
|
|
|
|
if s.get_mcu_position() == mcu_pos:
|
|
|
|
raise homing.EndstopError("BLTouch failed to deploy")
|
2020-02-19 17:38:11 +01:00
|
|
|
def home_start(self, print_time, sample_time, sample_count, rest_time):
|
2018-12-13 22:45:32 +01:00
|
|
|
rest_time = min(rest_time, ENDSTOP_REST_TIME)
|
2020-02-19 17:38:11 +01:00
|
|
|
return self.mcu_endstop.home_start(print_time, sample_time,
|
|
|
|
sample_count, rest_time)
|
2018-11-25 03:41:25 +01:00
|
|
|
def get_position_endstop(self):
|
|
|
|
return self.position_endstop
|
2020-02-24 04:32:07 +01:00
|
|
|
def set_output_mode(self, mode):
|
|
|
|
# If this is inadvertently/purposely issued for a
|
|
|
|
# BLTOUCH pre V3.0 and clones:
|
|
|
|
# No reaction at all.
|
|
|
|
# BLTOUCH V3.0 and V3.1:
|
|
|
|
# This will set the mode.
|
|
|
|
if mode is None:
|
|
|
|
return
|
|
|
|
logging.info("BLTouch set output mode: %s", mode)
|
|
|
|
self.sync_mcu_print_time()
|
|
|
|
if mode == '5V':
|
|
|
|
self.send_cmd('set_5V_output_mode')
|
|
|
|
if mode == 'OD':
|
|
|
|
self.send_cmd('set_OD_output_mode')
|
|
|
|
def store_output_mode(self, mode):
|
|
|
|
# If this command is inadvertently/purposely issued for a
|
|
|
|
# BLTOUCH pre V3.0 and clones:
|
|
|
|
# No reaction at all to this sequence apart from a pin-down/pin-up
|
|
|
|
# BLTOUCH V3.0:
|
|
|
|
# This will set the mode (twice) and sadly, a pin-up is needed at
|
|
|
|
# the end, because of the pin-down
|
|
|
|
# BLTOUCH V3.1:
|
|
|
|
# This will set the mode and store it in the eeprom.
|
|
|
|
# The pin-up is not needed but does not hurt
|
|
|
|
logging.info("BLTouch store output mode: %s", mode)
|
|
|
|
self.sync_print_time()
|
|
|
|
self.send_cmd('pin_down')
|
|
|
|
if mode == '5V':
|
|
|
|
self.send_cmd('set_5V_output_mode')
|
|
|
|
else:
|
|
|
|
self.send_cmd('set_OD_output_mode')
|
|
|
|
self.send_cmd('output_mode_store')
|
|
|
|
if mode == '5V':
|
|
|
|
self.send_cmd('set_5V_output_mode')
|
|
|
|
else:
|
|
|
|
self.send_cmd('set_OD_output_mode')
|
|
|
|
self.send_cmd('pin_up')
|
|
|
|
self.send_cmd(None)
|
2018-12-04 04:52:32 +01:00
|
|
|
cmd_BLTOUCH_DEBUG_help = "Send a command to the bltouch for debugging"
|
|
|
|
def cmd_BLTOUCH_DEBUG(self, params):
|
|
|
|
cmd = self.gcode.get_str('COMMAND', params, None)
|
|
|
|
if cmd is None or cmd not in Commands:
|
|
|
|
self.gcode.respond_info("BLTouch commands: %s" % (
|
|
|
|
", ".join(sorted([c for c in Commands if c is not None]))))
|
|
|
|
return
|
2019-03-04 19:04:18 +01:00
|
|
|
self.gcode.respond_info("Sending BLTOUCH_DEBUG COMMAND=%s" % (cmd,))
|
2019-01-05 17:18:07 +01:00
|
|
|
self.sync_print_time()
|
|
|
|
self.send_cmd(cmd, duration=self.pin_move_time)
|
|
|
|
self.send_cmd(None)
|
|
|
|
self.sync_print_time()
|
2020-02-24 04:32:07 +01:00
|
|
|
cmd_BLTOUCH_STORE_help = "Store an output mode in the BLTouch EEPROM"
|
|
|
|
def cmd_BLTOUCH_STORE(self, params):
|
|
|
|
cmd = self.gcode.get_str('MODE', params, None)
|
|
|
|
if cmd is None or cmd not in ['5V', 'OD']:
|
|
|
|
self.gcode.respond_info("BLTouch output modes: 5V, OD")
|
|
|
|
return
|
|
|
|
self.gcode.respond_info("Storing BLTouch output mode: %s" % (cmd,))
|
|
|
|
self.sync_print_time()
|
|
|
|
self.store_output_mode(cmd)
|
|
|
|
self.sync_print_time()
|
2018-11-25 03:41:25 +01:00
|
|
|
|
|
|
|
def load_config(config):
|
|
|
|
blt = BLTouchEndstopWrapper(config)
|
|
|
|
config.get_printer().add_object('probe', probe.PrinterProbe(config, blt))
|
|
|
|
return blt
|