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,
|
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')
|
|
|
|
# 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)
|
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
|
|
|
|
self.query_endstop_wait = self.mcu_endstop.query_endstop_wait
|
|
|
|
self.TimeoutError = self.mcu_endstop.TimeoutError
|
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)
|
2018-11-25 03:41:25 +01:00
|
|
|
def _build_config(self):
|
|
|
|
kin = self.printer.lookup_object('toolhead').get_kinematics()
|
|
|
|
for stepper in kin.get_steppers('Z'):
|
|
|
|
stepper.add_to_endstop(self)
|
2019-01-05 02:37:42 +01:00
|
|
|
def handle_connect(self):
|
|
|
|
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
|
|
|
|
prev_positions = [s.get_commanded_position()
|
|
|
|
for s in self.mcu_endstop.get_steppers()]
|
|
|
|
self.mcu_endstop.home_start(check_start_time, ENDSTOP_SAMPLE_TIME,
|
|
|
|
ENDSTOP_SAMPLE_COUNT, ENDSTOP_REST_TIME,
|
|
|
|
triggered=triggered)
|
|
|
|
try:
|
|
|
|
self.mcu_endstop.home_wait(check_end_time)
|
|
|
|
except self.mcu_endstop.TimeoutError as e:
|
|
|
|
raise homing.EndstopError("BLTouch failed to %s" % (msg,))
|
|
|
|
for s, pos in zip(self.mcu_endstop.get_steppers(), prev_positions):
|
|
|
|
s.set_commanded_position(pos)
|
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
|
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()
|
2018-11-25 03:41:25 +01:00
|
|
|
def home_prepare(self):
|
|
|
|
self.test_sensor()
|
2019-01-05 17:18:07 +01:00
|
|
|
self.sync_print_time()
|
2019-01-05 01:18:09 +01:00
|
|
|
self.send_cmd('pin_down', duration=self.pin_move_time - MIN_CMD_TIME)
|
|
|
|
self.send_cmd(None)
|
2019-01-05 17:18:07 +01:00
|
|
|
self.sync_print_time()
|
2018-11-25 03:41:25 +01:00
|
|
|
self.mcu_endstop.home_prepare()
|
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()]
|
2018-11-25 03:41:25 +01:00
|
|
|
def home_finalize(self):
|
2019-01-05 02:37:42 +01:00
|
|
|
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")
|
2018-11-25 03:41:25 +01:00
|
|
|
self.mcu_endstop.home_finalize()
|
2018-12-13 22:45:32 +01:00
|
|
|
def home_start(self, print_time, sample_time, sample_count, rest_time):
|
|
|
|
rest_time = min(rest_time, ENDSTOP_REST_TIME)
|
|
|
|
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
|
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()
|
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
|