1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
|
/*
* Heater.h
*
* Created on: 24 Jul 2019
* Author: David
*/
#ifndef SRC_HEATING_HEATER_H_
#define SRC_HEATING_HEATER_H_
#include <RepRapFirmware.h>
#include <General/NamedEnum.h>
#include "FOPDT.h"
#include "HeaterMonitor.h"
#include <ObjectModel/ObjectModel.h>
#include <Math/DeviationAccumulator.h>
#include <RRF3Common.h>
#if SUPPORT_CAN_EXPANSION
# include "CanId.h"
#endif
#define TUNE_WITH_HALF_FAN 0
class HeaterMonitor;
struct CanMessageHeaterTuningReport;
struct CanHeaterReport;
#if SUPPORT_REMOTE_COMMANDS
struct CanMessageHeaterModelNewNew;
struct CanMessageSetHeaterTemperature;
struct CanMessageSetHeaterMonitors;
struct CanMessageHeaterTuningCommand;
struct CanMessageSetHeaterFaultDetectionParameters;
#endif
// Enumeration to describe the status of a heater. Note that the web interface returns the numerical values, so don't change them.
NamedEnum(HeaterStatus, uint8_t, off, standby, active, fault, tuning, offline);
class Heater INHERIT_OBJECT_MODEL
{
public:
Heater(unsigned int num) noexcept;
virtual ~Heater() noexcept;
Heater(const Heater&) = delete;
// Configuration methods
virtual GCodeResult ConfigurePortAndSensor(const char *portName, PwmFrequency freq, unsigned int sn, const StringRef& reply) = 0;
virtual GCodeResult SetPwmFrequency(PwmFrequency freq, const StringRef& reply) = 0;
virtual GCodeResult ReportDetails(const StringRef& reply) const noexcept = 0;
virtual float GetTemperature() const noexcept = 0; // Get the current temperature and error status
virtual float GetAveragePWM() const noexcept = 0; // Return the running average PWM to the heater. Answer is a fraction in [0, 1].
virtual GCodeResult ResetFault(const StringRef& reply) noexcept = 0; // Reset a fault condition - only call this if you know what you are doing
virtual void SwitchOff() noexcept = 0;
virtual void Spin() noexcept = 0;
virtual void Suspend(bool sus) noexcept = 0; // Suspend the heater to conserve power or while doing Z probing
virtual float GetAccumulator() const noexcept = 0; // Get the inertial term accumulator
virtual void FeedForwardAdjustment(float fanPwmChange, float extrusionChange) noexcept = 0;
virtual void SetExtrusionFeedForward(float pwm) noexcept = 0;
#if SUPPORT_CAN_EXPANSION
virtual bool IsLocal() const noexcept = 0;
virtual void UpdateRemoteStatus(CanAddress src, const CanHeaterReport& report) noexcept = 0;
virtual void UpdateHeaterTuning(CanAddress src, const CanMessageHeaterTuningReport& msg) noexcept = 0;
#endif
HeaterStatus GetStatus() const noexcept; // Get the status of the heater
unsigned int GetHeaterNumber() const noexcept { return heaterNumber; }
const char *GetSensorName() const noexcept; // Get the name of the sensor for this heater, or nullptr if it hasn't been named
void SetTemperature(float t, bool activeNotStandby) THROWS(GCodeException);
float GetActiveTemperature() const noexcept { return activeTemperature; }
float GetStandbyTemperature() const noexcept { return standbyTemperature; }
GCodeResult SetActiveOrStandby(bool setActive, const StringRef& reply) noexcept; // Switch from idle to active or standby
GCodeResult StartAutoTune(GCodeBuffer& gb, const StringRef& reply, FansBitmap fans) THROWS(GCodeException);
// Start an auto tune cycle for this heater
void GetAutoTuneStatus(const StringRef& reply) const noexcept; // Get the auto tune status or last result
GCodeResult ConfigureFaultDetectionParameters(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeException);
GCodeResult ConfigureMonitor(GCodeBuffer &gb, const StringRef &reply) THROWS(GCodeException);
float GetHighestTemperatureLimit() const noexcept;
float GetLowestTemperatureLimit() const noexcept; // Get the lowest temperature limit
const FopDt& GetModel() const noexcept { return model; } // Get the process model
GCodeResult SetOrReportModel(unsigned int heater, GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeException);
#if SUPPORT_REMOTE_COMMANDS
virtual GCodeResult TuningCommand(const CanMessageHeaterTuningCommand& msg, const StringRef& reply) noexcept = 0;
GCodeResult SetModel(unsigned int heater, const CanMessageHeaterModelNewNew& msg, const StringRef& reply) noexcept;
GCodeResult SetTemperature(const CanMessageSetHeaterTemperature& msg, const StringRef& reply) noexcept;
GCodeResult SetFaultDetectionParameters(const CanMessageSetHeaterFaultDetectionParameters& msg, const StringRef& reply) noexcept;
GCodeResult SetHeaterMonitors(const CanMessageSetHeaterMonitors& msg, const StringRef& reply) noexcept;
#endif
bool IsHeaterEnabled() const noexcept // Is this heater enabled?
{ return model.IsEnabled(); }
void SetM301PidParameters(const M301PidParameters& params) noexcept
{ model.SetM301PidParameters(params); }
void ClearModelAndMonitors() noexcept;
void SetAsToolHeater() noexcept;
void SetAsBedOrChamberHeater() noexcept;
bool IsCoolingDevice() const noexcept { return model.IsInverted(); }
#if SUPPORT_REMOTE_COMMANDS
uint8_t GetModeByte() const { return (uint8_t)GetMode(); }
#endif
protected:
DECLARE_OBJECT_MODEL_WITH_ARRAYS
struct HeaterParameters
{
float heatingRate;
float coolingRate;
float deadTime;
float gain;
unsigned int numCycles;
float GetNormalGain() const noexcept { return heatingRate/coolingRate; }
};
virtual void ResetHeater() noexcept = 0;
virtual HeaterMode GetMode() const noexcept = 0;
virtual GCodeResult SwitchOn(const StringRef& reply) noexcept = 0;
virtual GCodeResult UpdateModel(const StringRef& reply) noexcept = 0;
virtual GCodeResult UpdateFaultDetectionParameters(const StringRef& reply) noexcept = 0;
virtual GCodeResult UpdateHeaterMonitors(const StringRef& reply) noexcept = 0;
virtual GCodeResult StartAutoTune(const StringRef& reply, bool seenA, float ambientTemp) noexcept = 0;
int GetSensorNumber() const noexcept { return sensorNumber; }
void SetSensorNumber(int sn) noexcept;
float GetMaxTemperatureExcursion() const noexcept { return maxTempExcursion; }
float GetMaxHeatingFaultTime() const noexcept { return maxHeatingFaultTime; }
uint32_t GetMaxBadTemperatureCount() const noexcept { return maxBadTemperatureCount; }
float GetTargetTemperature() const noexcept { return (active) ? activeTemperature : standbyTemperature; }
bool IsBedOrChamber() const noexcept { return isBedOrChamber; }
GCodeResult SetModel(float hr, float bcr, float fcr, float coolingRateExponent, float td, float maxPwm, float voltage, bool usePid, bool inverted, const StringRef& reply) noexcept;
// set the process model
void ReportTuningUpdate() noexcept; // tell the user what's happening
void CalculateModel(HeaterParameters& params) noexcept; // calculate G, td and tc from the accumulated readings
void SetAndReportModelAfterTuning(bool usingFans) noexcept;
HeaterMonitor monitors[MaxMonitorsPerHeater]; // embedding them in the Heater uses less memory than dynamic allocation
bool tuned; // true if tuning was successful
// Constants used during heater tuning
static constexpr uint32_t TempSettleTimeout = 20000; // how long we allow the initial temperature to settle
static constexpr unsigned int TuningHeaterMinIdleCycles = 3; // minimum number of idle cycles after heating up, including the initial overshoot and cool down
static constexpr unsigned int TuningHeaterMaxIdleCycles = 10;
static constexpr unsigned int MinTuningHeaterCycles = 5;
static constexpr unsigned int MaxTuningHeaterCycles = 25;
static constexpr float DefaultTuningHysteresis = 5.0;
static constexpr float DefaultTuningFanPwm = 0.7;
static constexpr float TuningPeakTempDrop = 2.0; // must be well below TuningHysteresis
static constexpr float HeaterSettledCoolingTimeRatio = 0.93;
// Variables used during heater tuning
static float tuningPwm; // the PWM to use, 0..1
static float tuningTargetTemp; // the target temperature
static float tuningHysteresis;
static float tuningFanPwm;
static DeviationAccumulator tuningStartTemp; // the temperature when we turned on the heater
static uint32_t tuningBeginTime; // when we started the tuning process
static DeviationAccumulator dHigh;
static DeviationAccumulator dLow;
static DeviationAccumulator tOn;
static DeviationAccumulator tOff;
static DeviationAccumulator heatingRate;
static DeviationAccumulator coolingRate;
static DeviationAccumulator tuningVoltage; // sum of the voltage readings we take during the heating phase
static uint32_t lastOffTime;
static uint32_t lastOnTime;
static float peakTemp; // max or min temperature
static uint32_t peakTime; // the time at which we recorded peakTemp
static float afterPeakTemp; // temperature after max from which we start timing the cooling rate
static uint32_t afterPeakTime; // the time at which we recorded afterPeakTemp
static float lastCoolingRate;
static FansBitmap tuningFans;
static unsigned int tuningPhase;
static uint8_t idleCyclesDone;
static bool tuningQuietMode;
static HeaterParameters fanOffParams, fanOnParams;
static void ClearCounters() noexcept;
private:
static const char* const TuningPhaseText[];
FopDt model;
unsigned int heaterNumber;
int sensorNumber; // the sensor number used by this heater
float activeTemperature; // the required active temperature
float standbyTemperature; // the required standby temperature
float maxTempExcursion; // the maximum temperature excursion permitted while maintaining the setpoint
float maxHeatingFaultTime; // how long a heater fault is permitted to persist before a heater fault is raised
uint32_t maxBadTemperatureCount; // the number of consecutive bad sensor readings we allow before raising a fault
bool isBedOrChamber; // true if this was a bed or chamber heater when we were switched on
bool active; // are we active or standby?
bool modelSetByUser;
bool monitorsSetByUser;
};
#endif /* SRC_HEATING_HEATER_H_ */
|