diff options
author | David Crocker <dcrocker@eschertech.com> | 2020-11-11 15:42:20 +0300 |
---|---|---|
committer | David Crocker <dcrocker@eschertech.com> | 2020-11-11 15:42:20 +0300 |
commit | 56cc6e24532e74919c29f42cc9ae4e7c564cdb0f (patch) | |
tree | 847b9b7f419ec65d49efc5598470bdc90a6dd2b8 /src/Heating | |
parent | d2e3056950eef02a5614ef8f0e3d34c06140bdb3 (diff) |
Implemented heater feedforward for fan RPM changes
Diffstat (limited to 'src/Heating')
-rw-r--r-- | src/Heating/FOPDT.cpp | 19 | ||||
-rw-r--r-- | src/Heating/FOPDT.h | 11 | ||||
-rw-r--r-- | src/Heating/Heat.cpp | 9 | ||||
-rw-r--r-- | src/Heating/Heat.h | 1 | ||||
-rw-r--r-- | src/Heating/Heater.cpp | 6 | ||||
-rw-r--r-- | src/Heating/Heater.h | 5 | ||||
-rw-r--r-- | src/Heating/LocalHeater.cpp | 10 | ||||
-rw-r--r-- | src/Heating/LocalHeater.h | 1 | ||||
-rw-r--r-- | src/Heating/RemoteHeater.cpp | 13 | ||||
-rw-r--r-- | src/Heating/RemoteHeater.h | 1 |
10 files changed, 54 insertions, 22 deletions
diff --git a/src/Heating/FOPDT.cpp b/src/Heating/FOPDT.cpp index bb62bb9a..4c5e81fd 100644 --- a/src/Heating/FOPDT.cpp +++ b/src/Heating/FOPDT.cpp @@ -38,7 +38,7 @@ constexpr ObjectModelTableEntry FopDt::objectModelTable[] = { "pid", OBJECT_MODEL_FUNC(self, 1), ObjectModelEntryFlags::none }, { "standardVoltage", OBJECT_MODEL_FUNC(self->standardVoltage, 1), ObjectModelEntryFlags::none }, { "timeConstant", OBJECT_MODEL_FUNC(self->GetTimeConstantFanOff(), 1), ObjectModelEntryFlags::none }, - { "timeConstantFanOn", OBJECT_MODEL_FUNC(self->GetTimeConstantFanOn(), 1), ObjectModelEntryFlags::none }, + { "timeConstantFansOn", OBJECT_MODEL_FUNC(self->GetTimeConstantFanOn(), 1), ObjectModelEntryFlags::none }, // 1. PID members { "d", OBJECT_MODEL_FUNC(self->loadChangeParams.tD * self->loadChangeParams.kP, 1), ObjectModelEntryFlags::none }, @@ -58,7 +58,7 @@ DEFINE_GET_OBJECT_MODEL_TABLE(FopDt) // Set up sensible defaults here in case the user enables the heater without specifying values for all the parameters. FopDt::FopDt() noexcept : heatingRate(DefaultHotEndHeaterHeatingRate), - coolingRateFanOff(DefaultHotEndHeaterCoolingRate), coolingRateFanOn(DefaultHotEndHeaterCoolingRate), + coolingRateFanOff(DefaultHotEndHeaterCoolingRate), coolingRateChangeFanOn(0.0), deadTime(DefaultHotEndHeaterDeadTime), maxPwm(1.0), standardVoltage(0.0), enabled(false), usePid(true), inverted(false), pidParametersOverridden(false) { @@ -80,7 +80,7 @@ bool FopDt::SetParameters(float phr, float pcrFanOff, float pcrFanOn, float pdt, { heatingRate = phr; coolingRateFanOff = pcrFanOff; - coolingRateFanOn = pcrFanOn; + coolingRateChangeFanOn = pcrFanOn - pcrFanOff; deadTime = pdt; maxPwm = pMaxPwm; standardVoltage = pVoltage; @@ -121,7 +121,7 @@ bool FopDt::WriteParameters(FileStore *f, size_t heater) const noexcept { String<StringLength256> scratchString; scratchString.printf("M307 H%u R%.3f C%.3f:%.3f D%.2f S%.2f V%.1f B%d\n", - heater, (double)heatingRate, (double)coolingRateFanOff, (double)coolingRateFanOn, (double)deadTime, (double)maxPwm, (double)standardVoltage, (usePid) ? 0 : 1); + heater, (double)heatingRate, (double)GetTimeConstantFanOff(), (double)GetTimeConstantFanOn(), (double)deadTime, (double)maxPwm, (double)standardVoltage, (usePid) ? 0 : 1); bool ok = f->Write(scratchString.c_str()); if (ok && pidParametersOverridden) { @@ -166,7 +166,7 @@ bool FopDt::WriteParameters(FileStore *f, size_t heater) const noexcept void FopDt::CalcPidConstants() noexcept { - const float averageCoolingRate = (coolingRateFanOff + coolingRateFanOn) * 0.5; + const float averageCoolingRate = coolingRateFanOff + 0.5 * coolingRateChangeFanOn; loadChangeParams.kP = 0.7/(heatingRate * deadTime); loadChangeParams.recipTi = powf(averageCoolingRate, 0.25)/(1.14 * powf(deadTime, 0.75)); // Ti = 1.14 * timeConstant^0.25 * deadTime^0.75 (Ho et al) loadChangeParams.tD = deadTime * 0.7; @@ -180,11 +180,14 @@ void FopDt::CalcPidConstants() noexcept #if SUPPORT_CAN_EXPANSION -void FopDt::SetupCanMessage(unsigned int heater, CanMessageUpdateHeaterModel& msg) const noexcept +void FopDt::SetupCanMessage(unsigned int heater, CanMessageUpdateHeaterModelNew& msg) const noexcept { msg.heater = heater; - msg.gain = gain; - msg.timeConstant = timeConstant; + msg.heatingRate = heatingRate; + msg.coolingRate = coolingRateFanOff; + msg.coolingRateChangeFanOn = coolingRateChangeFanOn; + msg.coolingRateChangeExtruding = 0.0; + msg.zero2 = 0.0; msg.deadTime = deadTime; msg.maxPwm = maxPwm; msg.standardVoltage = standardVoltage; diff --git a/src/Heating/FOPDT.h b/src/Heating/FOPDT.h index 728b3c78..eab8d1fb 100644 --- a/src/Heating/FOPDT.h +++ b/src/Heating/FOPDT.h @@ -34,7 +34,7 @@ class FileStore; #endif #if SUPPORT_CAN_EXPANSION -struct CanMessageUpdateHeaterModel; +struct CanMessageUpdateHeaterModelNew; #endif class FopDt INHERIT_OBJECT_MODEL @@ -47,7 +47,8 @@ public: // Stored parameters float GetHeatingRate() const noexcept { return heatingRate; } float GetCoolingRateFanOff() const noexcept { return coolingRateFanOff; } - float GetCoolingRateFanOn() const noexcept { return coolingRateFanOn; } + float GetCoolingRateFanOn() const noexcept { return coolingRateFanOff + coolingRateChangeFanOn; } + float GetCoolingRateChangeFanOn() const noexcept { return coolingRateChangeFanOn; } float GetDeadTime() const noexcept { return deadTime; } float GetMaxPwm() const noexcept { return maxPwm; } float GetVoltage() const noexcept { return standardVoltage; } @@ -58,7 +59,7 @@ public: // Derived parameters float GetGainFanOff() const noexcept { return heatingRate/coolingRateFanOff; } float GetTimeConstantFanOff() const noexcept { return 1.0/coolingRateFanOff; } - float GetTimeConstantFanOn() const noexcept { return 1.0/coolingRateFanOn; } + float GetTimeConstantFanOn() const noexcept { return 1.0/GetCoolingRateFanOn(); } bool ArePidParametersOverridden() const noexcept { return pidParametersOverridden; } M301PidParameters GetM301PidParameters(bool forLoadChange) const noexcept; void SetM301PidParameters(const M301PidParameters& params) noexcept; @@ -73,7 +74,7 @@ public: #endif #if SUPPORT_CAN_EXPANSION - void SetupCanMessage(unsigned int heater, CanMessageUpdateHeaterModel& msg) const noexcept; + void SetupCanMessage(unsigned int heater, CanMessageUpdateHeaterModelNew& msg) const noexcept; #endif protected: @@ -84,7 +85,7 @@ private: float heatingRate; float coolingRateFanOff; - float coolingRateFanOn; + float coolingRateChangeFanOn; float deadTime; float maxPwm; float standardVoltage; // power voltage reading at which tuning was done, or 0 if unknown diff --git a/src/Heating/Heat.cpp b/src/Heating/Heat.cpp index bdd8bf1a..2a3d8e94 100644 --- a/src/Heating/Heat.cpp +++ b/src/Heating/Heat.cpp @@ -727,6 +727,15 @@ void Heat::Standby(int heater, const Tool *tool) noexcept } } +void Heat::PrintCoolingFanPwmChanged(unsigned int heater, float pwmChange) const noexcept +{ + const auto h = FindHeater(heater); + if (h.IsNotNull()) + { + h->PrintCoolingFanPwmChanged(pwmChange); + } +} + GCodeResult Heat::ResetFault(int heater, const StringRef& reply) noexcept { // This gets called for all heater numbers when clearing all temperature faults, so don't report an error if the heater was not found diff --git a/src/Heating/Heat.h b/src/Heating/Heat.h index bbe9bff9..74bccc26 100644 --- a/src/Heating/Heat.h +++ b/src/Heating/Heat.h @@ -131,6 +131,7 @@ public: GCodeResult Activate(int heater, const StringRef& reply) noexcept; // Turn on a heater void Standby(int heater, const Tool* tool) noexcept; // Set a heater to standby void SwitchOff(int heater) noexcept; // Turn off a specific heater + void PrintCoolingFanPwmChanged(unsigned int heater, float pwmChange) const noexcept; #if HAS_MASS_STORAGE bool WriteModelParameters(FileStore *f) const noexcept; // Write heater model parameters to file returning true if no error diff --git a/src/Heating/Heater.cpp b/src/Heating/Heater.cpp index 4d7133bf..9a862383 100644 --- a/src/Heating/Heater.cpp +++ b/src/Heating/Heater.cpp @@ -179,17 +179,17 @@ GCodeResult Heater::SetOrReportModel(unsigned int heater, GCodeBuffer& gb, const } // Set the process model returning true if successful -GCodeResult Heater::SetModel(float gain, float tcOff, float tcOn, float td, float maxPwm, float voltage, bool usePid, bool inverted, const StringRef& reply) noexcept +GCodeResult Heater::SetModel(float heatingRate, float coolingRateFanOff, float coolingRateFanOn, float td, float maxPwm, float voltage, bool usePid, bool inverted, const StringRef& reply) noexcept { GCodeResult rslt; - if (model.SetParameters(gain, tcOff, tcOn, td, maxPwm, GetHighestTemperatureLimit(), voltage, usePid, inverted)) + if (model.SetParameters(heatingRate, coolingRateFanOff, coolingRateFanOn, td, maxPwm, GetHighestTemperatureLimit(), voltage, usePid, inverted)) { if (model.IsEnabled()) { rslt = UpdateModel(reply); if (rslt == GCodeResult::ok) { - const float predictedMaxTemp = gain + NormalAmbientTemperature; + const float predictedMaxTemp = heatingRate/coolingRateFanOff + NormalAmbientTemperature; const float noWarnTemp = (GetHighestTemperatureLimit() - NormalAmbientTemperature) * 1.5 + 50.0; // allow 50% extra power plus enough for an extra 50C if (predictedMaxTemp > noWarnTemp) { diff --git a/src/Heating/Heater.h b/src/Heating/Heater.h index 502e2e74..8c8231e0 100644 --- a/src/Heating/Heater.h +++ b/src/Heating/Heater.h @@ -43,9 +43,10 @@ public: virtual void SwitchOff() noexcept = 0; virtual void Spin() noexcept = 0; virtual GCodeResult StartAutoTune(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeException) = 0; // Start an auto tune cycle for this heater - virtual void GetAutoTuneStatus(const StringRef& reply) const = 0; // Get the auto tune status or last result + virtual void GetAutoTuneStatus(const StringRef& reply) const noexcept = 0; // Get the auto tune status or last result 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 PrintCoolingFanPwmChanged(float pwmChange) noexcept = 0; #if SUPPORT_CAN_EXPANSION virtual void UpdateRemoteStatus(CanAddress src, const CanHeaterReport& report) noexcept = 0; @@ -117,7 +118,7 @@ protected: float GetMaxTemperatureExcursion() const noexcept { return maxTempExcursion; } float GetMaxHeatingFaultTime() const noexcept { return maxHeatingFaultTime; } float GetTargetTemperature() const noexcept { return (active) ? activeTemperature : standbyTemperature; } - GCodeResult SetModel(float gain, float tcOff, float tcOn, float td, float maxPwm, float voltage, bool usePid, bool inverted, const StringRef& reply) noexcept; // Set the process model + GCodeResult SetModel(float heatingRate, float coolingRateFanOff, float coolingRateFanOn, float td, float maxPwm, float voltage, bool usePid, bool inverted, const StringRef& reply) noexcept; // Set the process model HeaterMonitor monitors[MaxMonitorsPerHeater]; // embedding them in the Heater uses less memory than dynamic allocation diff --git a/src/Heating/LocalHeater.cpp b/src/Heating/LocalHeater.cpp index d5764c04..1d0af3f3 100644 --- a/src/Heating/LocalHeater.cpp +++ b/src/Heating/LocalHeater.cpp @@ -596,6 +596,16 @@ void LocalHeater::GetAutoTuneStatus(const StringRef& reply) const noexcept } } +// Call this when the PWM of a cooling fan has changed. If there are multiple fans, caller must divide pwmChange by the number of fans. +void LocalHeater::PrintCoolingFanPwmChanged(float pwmChange) noexcept +{ + if (mode == HeaterMode::stable) + { + const float coolingRateIncrease = GetModel().GetCoolingRateChangeFanOn() * pwmChange; + iAccumulator += (coolingRateIncrease * (GetTargetTemperature() - NormalAmbientTemperature))/GetModel().GetHeatingRate(); + } +} + /* Notes on the auto tune algorithm * * Most 3D printer firmwares use the �str�m-H�gglund relay tuning method (sometimes called Ziegler-Nichols + relay). diff --git a/src/Heating/LocalHeater.h b/src/Heating/LocalHeater.h index 8c32dc39..5cad973b 100644 --- a/src/Heating/LocalHeater.h +++ b/src/Heating/LocalHeater.h @@ -50,6 +50,7 @@ public: GCodeResult StartAutoTune(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeException) override; // Start an auto tune cycle for this heater void GetAutoTuneStatus(const StringRef& reply) const noexcept override; // Get the auto tune status or last result void Suspend(bool sus) noexcept override; // Suspend the heater to conserve power or while doing Z probing + void PrintCoolingFanPwmChanged(float pwmChange) noexcept override; #if SUPPORT_CAN_EXPANSION void UpdateRemoteStatus(CanAddress src, const CanHeaterReport& report) noexcept override { } diff --git a/src/Heating/RemoteHeater.cpp b/src/Heating/RemoteHeater.cpp index 70dfe8bb..94e6f377 100644 --- a/src/Heating/RemoteHeater.cpp +++ b/src/Heating/RemoteHeater.cpp @@ -41,13 +41,13 @@ void RemoteHeater::ResetHeater() noexcept //TODO } -GCodeResult RemoteHeater::ConfigurePortAndSensor(const char *portName, PwmFrequency freq, unsigned int sensorNumber, const StringRef& reply) +GCodeResult RemoteHeater::ConfigurePortAndSensor(const char *portName, PwmFrequency freq, unsigned int sn, const StringRef& reply) { - SetSensorNumber(sensorNumber); + SetSensorNumber(sn); CanMessageGenericConstructor cons(M950HeaterParams); cons.AddUParam('H', GetHeaterNumber()); cons.AddUParam('Q', freq); - cons.AddUParam('T', sensorNumber); + cons.AddUParam('T', sn); cons.AddStringParam('C', portName); return cons.SendAndGetResponse(CanMessageType::m950Heater, boardAddress, reply); } @@ -139,6 +139,11 @@ void RemoteHeater::GetAutoTuneStatus(const StringRef& reply) const noexcept reply.copy("remote heater auto tune not implemented"); } +void RemoteHeater::PrintCoolingFanPwmChanged(float pwmChange) noexcept +{ + //TODO send a CAN message to remote +} + void RemoteHeater::Suspend(bool sus) noexcept { CanMessageBuffer * const buf = CanMessageBuffer::Allocate(); @@ -189,7 +194,7 @@ GCodeResult RemoteHeater::UpdateModel(const StringRef& reply) noexcept if (buf != nullptr) { const CanRequestId rid = CanInterface::AllocateRequestId(boardAddress); - CanMessageUpdateHeaterModel * const msg = buf->SetupRequestMessage<CanMessageUpdateHeaterModel>(rid, CanInterface::GetCanAddress(), boardAddress); + CanMessageUpdateHeaterModelNew * const msg = buf->SetupRequestMessage<CanMessageUpdateHeaterModelNew>(rid, CanInterface::GetCanAddress(), boardAddress); GetModel().SetupCanMessage(GetHeaterNumber(), *msg); return CanInterface::SendRequestAndGetStandardReply(buf, rid, reply); } diff --git a/src/Heating/RemoteHeater.h b/src/Heating/RemoteHeater.h index 676dfdfa..558b49b4 100644 --- a/src/Heating/RemoteHeater.h +++ b/src/Heating/RemoteHeater.h @@ -31,6 +31,7 @@ public: GCodeResult StartAutoTune(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeException) override; // Start an auto tune cycle for this heater void GetAutoTuneStatus(const StringRef& reply) const noexcept override; // Get the auto tune status or last result void Suspend(bool sus) noexcept override; // Suspend the heater to conserve power or while doing Z probing + void PrintCoolingFanPwmChanged(float pwmChange) noexcept override; void UpdateRemoteStatus(CanAddress src, const CanHeaterReport& report) noexcept override; protected: |