forked from Klipper3d/klipper
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
G
authored and
G
committed
Jan 11, 2024
1 parent
4c0aabc
commit 1bc41c3
Showing
1 changed file
with
63 additions
and
63 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
# Tracking of PWM controlled heaters and their temperature control | ||
# Feed filament by step motor, control by switch or holl senser. | ||
# | ||
# Copyright (C) 2016-2020 Kevin O'Connor <[email protected]> | ||
# Copyright (C) 2024 guoge | ||
# | ||
# This file may be distributed under the terms of the GNU GPLv3 license. | ||
import os, logging, threading | ||
|
@@ -10,12 +10,12 @@ | |
# Heater | ||
###################################################################### | ||
|
||
KELVIN_TO_CELSIUS = -273.15 | ||
MAX_HEAT_TIME = 5.0 | ||
AMBIENT_TEMP = 25. | ||
PID_PARAM_BASE = 255. | ||
# KELVIN_TO_CELSIUS = -273.15 | ||
# MAX_HEAT_TIME = 5.0 | ||
# AMBIENT_TEMP = 25. | ||
# PID_PARAM_BASE = 255. | ||
|
||
class Heater: | ||
class Feeder: #Heater: | ||
def __init__(self, config, sensor): | ||
self.printer = config.get_printer() | ||
self.reactor = self.printer.get_reactor() #add by guoge 20231130. | ||
|
@@ -47,16 +47,16 @@ def __init__(self, config, sensor): | |
algos = {'watermark': ControlBangBang, 'pid': ControlPID} | ||
algo = config.getchoice('control', algos) | ||
self.control = algo(self, config) | ||
# Setup output heater pin | ||
heater_pin = config.get('heater_pin') | ||
# Setup output feeder motor | ||
feeder_pin = config.get('feeder_pin') | ||
ppins = self.printer.lookup_object('pins') | ||
self.mcu_pwm = ppins.setup_pin('pwm', heater_pin) | ||
self.mcu_pwm = ppins.setup_pin('pwm', feeder_pin) | ||
pwm_cycle_time = config.getfloat('pwm_cycle_time', 0.100, above=0., | ||
maxval=self.pwm_delay) | ||
self.mcu_pwm.setup_cycle_time(pwm_cycle_time) | ||
self.mcu_pwm.setup_max_duration(MAX_HEAT_TIME) | ||
# Load additional modules | ||
self.printer.load_object(config, "verify_heater %s" % (self.name,)) | ||
self.printer.load_object(config, "verify_feeder %s" % (self.name,)) | ||
self.printer.load_object(config, "pid_calibrate") | ||
gcode = self.printer.lookup_object("gcode") | ||
gcode.register_mux_command("SET_HEATER_TEMPERATURE", "HEATER", | ||
|
@@ -88,11 +88,11 @@ def temperature_callback(self, read_time, temp): | |
adj_time = min(time_diff * self.inv_smooth_time, 1.) | ||
self.smoothed_temp += temp_diff * adj_time | ||
if self.smoothed_temp > 500 : | ||
logging.info(" *** Temp callbacke Error @ %.3f, heater: %s temp:%.3f/%.3f @ read time:%.3f - %.3f, timeDiff:%.2f, tempDiff:%.3f, too high", | ||
logging.info(" *** Temp callbacke Error @ %.3f, feeder: %s temp:%.3f/%.3f @ read time:%.3f - %.3f, timeDiff:%.2f, tempDiff:%.3f, too high", | ||
curtime, self.name, self.smoothed_temp, temp, read_time, last_time, time_diff, temp_diff) | ||
self.smoothed_temp = 500; | ||
if self.smoothed_temp < -100 : | ||
logging.info(" *** Temp callbacke Error @% .3f, heater: %s temp:%.3f/%.3f @ read time:%.3f - %.3f, timeDiff:%.2f, tempDiff:%.3f, too low", | ||
logging.info(" *** Temp callbacke Error @% .3f, feeder: %s temp:%.3f/%.3f @ read time:%.3f - %.3f, timeDiff:%.2f, tempDiff:%.3f, too low", | ||
curtime, self.name, self.smoothed_temp, temp, read_time, last_time, time_diff, temp_diff) | ||
self.smoothed_temp = -100 | ||
self.can_extrude = (self.smoothed_temp >= self.min_extrude_temp) | ||
|
@@ -146,21 +146,21 @@ def get_status(self, eventtime): | |
last_pwm_value = self.last_pwm_value | ||
return {'temperature': round(smoothed_temp, 2), 'target': target_temp, | ||
'power': last_pwm_value} | ||
cmd_SET_HEATER_TEMPERATURE_help = "Sets a heater temperature" | ||
cmd_SET_HEATER_TEMPERATURE_help = "Sets a feeder temperature" | ||
def cmd_SET_HEATER_TEMPERATURE(self, gcmd): | ||
temp = gcmd.get_float('TARGET', 0.) | ||
pheaters = self.printer.lookup_object('heaters') | ||
pheaters.set_temperature(self, temp) | ||
pfeeders = self.printer.lookup_object('feeders') | ||
pfeeders.set_temperature(self, temp) | ||
|
||
|
||
###################################################################### | ||
# Bang-bang control algo | ||
###################################################################### | ||
|
||
class ControlBangBang: | ||
def __init__(self, heater, config): | ||
self.heater = heater | ||
self.heater_max_power = heater.get_max_power() | ||
def __init__(self, feeder, config): | ||
self.feeder = feeder | ||
self.feeder_max_power = feeder.get_max_power() | ||
self.max_delta = config.getfloat('max_delta', 2.0, above=0.) | ||
self.heating = False | ||
def temperature_update(self, read_time, temp, target_temp): | ||
|
@@ -169,9 +169,9 @@ def temperature_update(self, read_time, temp, target_temp): | |
elif not self.heating and temp <= target_temp-self.max_delta: | ||
self.heating = True | ||
if self.heating: | ||
self.heater.set_pwm(read_time, self.heater_max_power) | ||
self.feeder.set_pwm(read_time, self.feeder_max_power) | ||
else: | ||
self.heater.set_pwm(read_time, 0.) | ||
self.feeder.set_pwm(read_time, 0.) | ||
def check_busy(self, eventtime, smoothed_temp, target_temp): | ||
return smoothed_temp < target_temp-self.max_delta | ||
|
||
|
@@ -184,16 +184,16 @@ def check_busy(self, eventtime, smoothed_temp, target_temp): | |
PID_SETTLE_SLOPE = .1 | ||
|
||
class ControlPID: | ||
def __init__(self, heater, config): | ||
self.heater = heater | ||
self.heater_max_power = heater.get_max_power() | ||
def __init__(self, feeder, config): | ||
self.feeder = feeder | ||
self.feeder_max_power = feeder.get_max_power() | ||
self.Kp = config.getfloat('pid_Kp') / PID_PARAM_BASE | ||
self.Ki = config.getfloat('pid_Ki') / PID_PARAM_BASE | ||
self.Kd = config.getfloat('pid_Kd') / PID_PARAM_BASE | ||
self.min_deriv_time = heater.get_smooth_time() | ||
self.min_deriv_time = feeder.get_smooth_time() | ||
self.temp_integ_max = 0. | ||
if self.Ki: | ||
self.temp_integ_max = self.heater_max_power / self.Ki | ||
self.temp_integ_max = self.feeder_max_power / self.Ki | ||
self.prev_temp = AMBIENT_TEMP | ||
self.prev_temp_time = 0. | ||
self.prev_temp_deriv = 0. | ||
|
@@ -215,8 +215,8 @@ def temperature_update(self, read_time, temp, target_temp): | |
co = self.Kp*temp_err + self.Ki*temp_integ - self.Kd*temp_deriv | ||
#logging.debug("pid: %f@%.3f -> diff=%f deriv=%f err=%f integ=%f co=%d", | ||
# temp, read_time, temp_diff, temp_deriv, temp_err, temp_integ, co) | ||
bounded_co = max(0., min(self.heater_max_power, co)) | ||
self.heater.set_pwm(read_time, bounded_co) | ||
bounded_co = max(0., min(self.feeder_max_power, co)) | ||
self.feeder.set_pwm(read_time, bounded_co) | ||
# Store state for next measurement | ||
self.prev_temp = temp | ||
self.prev_temp_time = read_time | ||
|
@@ -230,22 +230,22 @@ def check_busy(self, eventtime, smoothed_temp, target_temp): | |
|
||
|
||
###################################################################### | ||
# Sensor and heater lookup | ||
# Sensor and feeder lookup | ||
###################################################################### | ||
|
||
class PrinterHeaters: | ||
class FilaFeeders: #PrinterHeaters: | ||
def __init__(self, config): | ||
self.printer = config.get_printer() | ||
self.sensor_factories = {} | ||
self.heaters = {} | ||
self.feeders = {} | ||
self.gcode_id_to_sensor = {} | ||
self.available_heaters = [] | ||
self.available_feeders = [] | ||
self.available_sensors = [] | ||
self.available_monitors = [] | ||
self.has_started = self.have_load_sensors = False | ||
self.printer.register_event_handler("klippy:ready", self._handle_ready) | ||
self.printer.register_event_handler("gcode:request_restart", | ||
self.turn_off_all_heaters) | ||
self.turn_off_all_feeders) | ||
# Register commands | ||
gcode = self.printer.lookup_object('gcode') | ||
gcode.register_command("TURN_OFF_HEATERS", self.cmd_TURN_OFF_HEATERS, | ||
|
@@ -267,24 +267,24 @@ def load_config(self, config): | |
self.printer.load_object(dconfig, c.get_name()) | ||
def add_sensor_factory(self, sensor_type, sensor_factory): | ||
self.sensor_factories[sensor_type] = sensor_factory | ||
def setup_heater(self, config, gcode_id=None): | ||
heater_name = config.get_name().split()[-1] | ||
if heater_name in self.heaters: | ||
raise config.error("Heater %s already registered" % (heater_name,)) | ||
def setup_feeder(self, config, gcode_id=None): | ||
feeder_name = config.get_name().split()[-1] | ||
if feeder_name in self.feeders: | ||
raise config.error("Heater %s already registered" % (feeder_name,)) | ||
# Setup sensor | ||
sensor = self.setup_sensor(config) | ||
# Create heater | ||
self.heaters[heater_name] = heater = Heater(config, sensor) | ||
self.register_sensor(config, heater, gcode_id) | ||
self.available_heaters.append(config.get_name()) | ||
return heater | ||
def get_all_heaters(self): | ||
return self.available_heaters | ||
def lookup_heater(self, heater_name): | ||
if heater_name not in self.heaters: | ||
# Create feeder | ||
self.feeders[feeder_name] = feeder = Feeder(config, sensor) | ||
self.register_sensor(config, feeder, gcode_id) | ||
self.available_feeders.append(config.get_name()) | ||
return feeder | ||
def get_all_feeders(self): | ||
return self.available_feeders | ||
def lookup_feeder(self, feeder_name): | ||
if feeder_name not in self.feeders: | ||
raise self.printer.config_error( | ||
"Unknown heater '%s'" % (heater_name,)) | ||
return self.heaters[heater_name] | ||
"Unknown feeder '%s'" % (feeder_name,)) | ||
return self.feeders[feeder_name] | ||
def setup_sensor(self, config): | ||
if not self.have_load_sensors: | ||
self.load_config(config) | ||
|
@@ -308,15 +308,15 @@ def register_sensor(self, config, psensor, gcode_id=None): | |
def register_monitor(self, config): | ||
self.available_monitors.append(config.get_name()) | ||
def get_status(self, eventtime): | ||
return {'available_heaters': self.available_heaters, | ||
return {'available_feeders': self.available_feeders, | ||
'available_sensors': self.available_sensors, | ||
'available_monitors': self.available_monitors} | ||
def turn_off_all_heaters(self, print_time=0.): | ||
for heater in self.heaters.values(): | ||
heater.set_temp(0.) | ||
cmd_TURN_OFF_HEATERS_help = "Turn off all heaters" | ||
def turn_off_all_feeders(self, print_time=0.): | ||
for feeder in self.feeders.values(): | ||
feeder.set_temp(0.) | ||
cmd_TURN_OFF_HEATERS_help = "Turn off all feeders" | ||
def cmd_TURN_OFF_HEATERS(self, gcmd): | ||
self.turn_off_all_heaters() | ||
self.turn_off_all_feeders() | ||
# G-Code M105 temperature reporting | ||
def _handle_ready(self): | ||
self.has_started = True | ||
|
@@ -337,24 +337,24 @@ def cmd_M105(self, gcmd): | |
did_ack = gcmd.ack(msg) | ||
if not did_ack: | ||
gcmd.respond_raw(msg) | ||
def _wait_for_temperature(self, heater): | ||
# Helper to wait on heater.check_busy() and report M105 temperatures | ||
def _wait_for_temperature(self, feeder): | ||
# Helper to wait on feeder.check_busy() and report M105 temperatures | ||
if self.printer.get_start_args().get('debugoutput') is not None: | ||
return | ||
toolhead = self.printer.lookup_object("toolhead") | ||
gcode = self.printer.lookup_object("gcode") | ||
reactor = self.printer.get_reactor() | ||
eventtime = reactor.monotonic() | ||
while not self.printer.is_shutdown() and heater.check_busy(eventtime): | ||
while not self.printer.is_shutdown() and feeder.check_busy(eventtime): | ||
print_time = toolhead.get_last_move_time() | ||
gcode.respond_raw(self._get_temp(eventtime)) | ||
eventtime = reactor.pause(eventtime + 1.) | ||
def set_temperature(self, heater, temp, wait=False): | ||
def set_temperature(self, feeder, temp, wait=False): | ||
toolhead = self.printer.lookup_object('toolhead') | ||
toolhead.register_lookahead_callback((lambda pt: None)) | ||
heater.set_temp(temp) | ||
feeder.set_temp(temp) | ||
if wait and temp: | ||
self._wait_for_temperature(heater) | ||
self._wait_for_temperature(feeder) | ||
cmd_TEMPERATURE_WAIT_help = "Wait for a temperature on a sensor" | ||
def cmd_TEMPERATURE_WAIT(self, gcmd): | ||
sensor_name = gcmd.get('SENSOR') | ||
|
@@ -367,8 +367,8 @@ def cmd_TEMPERATURE_WAIT(self, gcmd): | |
"Error on 'TEMPERATURE_WAIT': missing MINIMUM or MAXIMUM.") | ||
if self.printer.get_start_args().get('debugoutput') is not None: | ||
return | ||
if sensor_name in self.heaters: | ||
sensor = self.heaters[sensor_name] | ||
if sensor_name in self.feeders: | ||
sensor = self.feeders[sensor_name] | ||
else: | ||
sensor = self.printer.lookup_object(sensor_name) | ||
toolhead = self.printer.lookup_object("toolhead") | ||
|
@@ -383,4 +383,4 @@ def cmd_TEMPERATURE_WAIT(self, gcmd): | |
eventtime = reactor.pause(eventtime + 1.) | ||
|
||
def load_config(config): | ||
return PrinterHeaters(config) | ||
return FilaFeeders(config) #PrinterHeaters(config) |