verify_heater: Add initial support for verifying heaters and sensors

Add runtime checks to heaters and temperature sensors to check for
possible hardware faults.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2018-03-11 00:22:44 -05:00
parent b549c3927e
commit 5208fc38ed
4 changed files with 91 additions and 4 deletions

View File

@ -122,6 +122,28 @@
# See the example.cfg for the definition of the above parameters.
# Heater and temperature sensor verification. Heater verification is
# automatically enabled for each heater that is configured on the
# printer. Use verify_heater sections to change the default settings.
#[verify_heater heater_config_name]
#heating_gain: 2
# The minimum temperature (in Celsius) that the heater must increase
# by when approaching a new target temperature. The default is 2.
#check_gain_time:
# The amount of time (in seconds) that the heating_gain must be met
# in before an error is raised. The default is 20 seconds for
# extruders and 60 seconds for heater_bed.
#hysteresis: 4
# The difference between the target temperature and the current
# temperature for the heater to be considered within range of the
# target temperature. The default is 4.
#check_time: 10
# The amount of time (in seconds) a heater that has reached the
# target temperature (as defined by the hysteresis field) may fall
# outside the target temperature range before an error is
# raised. The default is 10.
# Multi-stepper axes. On a cartesian style printer, the stepper
# controlling a given axis may have additional config blocks defining
# steppers that should be stepped in concert with the primary

View File

@ -44,10 +44,6 @@ Safety features
endstop detection is a good idea because of spurious signals caused
by electrical noise.)
* Support validating that heaters are heating at expected rates. This
can be useful to detect a sensor failure (eg, thermistor short) that
could otherwise cause the PID to command excessive heating.
Testing features
================

View File

@ -0,0 +1,67 @@
# Heater/sensor verification code
#
# Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
import logging
import extruder
class HeaterCheck:
def __init__(self, config):
self.printer = config.get_printer()
self.heater_name = config.get_name().split()[1]
self.heater = None
self.hysteresis = config.getfloat('hysteresis', 4., above=0.)
self.check_time = config.getfloat('check_time', 10., minval=1.)
self.heating_gain = config.getfloat('heating_gain', 2., above=0.)
default_gain_time = 20.
if self.heater_name == 'heater_bed':
default_gain_time = 60.
self.check_gain_time = config.getfloat(
'check_gain_time', default_gain_time, minval=1.)
self.met_target = False
self.last_target = self.goal_temp = 0.
self.fault_systime = self.printer.get_reactor().NEVER
def printer_state(self, state):
if state == 'connect':
self.heater = extruder.get_printer_heater(
self.printer, self.heater_name)
logging.info("Starting heater checks for %s", self.heater_name)
reactor = self.printer.get_reactor()
reactor.register_timer(self.check_event, reactor.NOW)
def check_event(self, eventtime):
temp, target = self.heater.get_temp(eventtime)
if temp >= target - self.hysteresis:
# Temperature near target - reset checks
if not self.met_target:
logging.info("Heater %s within range of %.3f",
self.heater_name, target)
self.met_target = True
self.fault_systime = eventtime + self.check_time
elif self.met_target:
if target != self.last_target:
# Target changed - reset checks
logging.info("Heater %s approaching new target of %.3f",
self.heater_name, target)
self.met_target = False
self.goal_temp = temp + self.heating_gain
self.fault_systime = eventtime + self.check_gain_time
elif eventtime >= self.fault_systime:
# Failure due to inability to maintain target temperature
return self.heater_fault()
elif temp >= self.goal_temp:
# Temperature approaching target - reset checks
self.goal_temp = temp + self.heating_gain
self.fault_systime = eventtime + self.check_gain_time
elif eventtime >= self.fault_systime:
# Failure due to inability to approach target temperature
return self.heater_fault()
self.last_target = target
return eventtime + 1.
def heater_fault(self):
logging.error("Heater %s not heating at expected rate", self.heater_name)
self.printer.invoke_shutdown("Heater %s failsafe" % (self.heater_name,))
return self.printer.get_reactor().NEVER
def load_config_prefix(config):
return HeaterCheck(config)

View File

@ -141,6 +141,8 @@ class PrinterHeater:
# pwm caching
self.next_pwm_time = 0.
self.last_pwm_value = 0.
# Load verify_heater module
printer.try_load_module(config, "verify_heater %s" % (self.name,))
def set_pwm(self, read_time, value):
if self.target_temp <= 0.:
value = 0.