diff options
author | David Crocker <dcrocker@eschertech.com> | 2020-11-10 14:55:46 +0300 |
---|---|---|
committer | David Crocker <dcrocker@eschertech.com> | 2020-11-10 14:55:46 +0300 |
commit | 74588201ba5dd8c7df5eb7e65343cc9d9d07033c (patch) | |
tree | cfdad584f478cfc49b221bb4b8c149d6f478b1e3 /src | |
parent | 7c99da590fbc00b558ef5f39690ceac111a8690f (diff) |
Added tuning with/without fans on
Diffstat (limited to 'src')
-rw-r--r-- | src/Fans/FansManager.cpp | 5 | ||||
-rw-r--r-- | src/Fans/FansManager.h | 1 | ||||
-rw-r--r-- | src/GCodes/GCodes.cpp | 3 | ||||
-rw-r--r-- | src/Heating/LocalHeater.cpp | 142 | ||||
-rw-r--r-- | src/Heating/LocalHeater.h | 36 |
5 files changed, 131 insertions, 56 deletions
diff --git a/src/Fans/FansManager.cpp b/src/Fans/FansManager.cpp index b752e8ba..1b9f2c5f 100644 --- a/src/Fans/FansManager.cpp +++ b/src/Fans/FansManager.cpp @@ -188,6 +188,11 @@ void FansManager::SetFanValue(size_t fanNum, float speed) noexcept (void)SetFanValue(fanNum, speed, dummy.GetRef()); } +void FansManager::SetFansValue(FansBitmap whichFans, float speed) noexcept +{ + whichFans.Iterate([speed, this](unsigned int i, unsigned int) noexcept { SetFanValue(i, speed); }); +} + // Check if the given fan can be controlled manually so that DWC can decide whether or not to show the corresponding fan // controls. This is the case if no thermostatic control is enabled and if the fan was configured at least once before. bool FansManager::IsFanControllable(size_t fanNum) const noexcept diff --git a/src/Fans/FansManager.h b/src/Fans/FansManager.h index 587658ce..85208625 100644 --- a/src/Fans/FansManager.h +++ b/src/Fans/FansManager.h @@ -35,6 +35,7 @@ public: float GetFanValue(size_t fanNum) const noexcept; GCodeResult SetFanValue(size_t fanNum, float speed, const StringRef& reply) noexcept; void SetFanValue(size_t fanNum, float speed) noexcept; + void SetFansValue(FansBitmap whichFans, float speed) noexcept; bool IsFanControllable(size_t fanNum) const noexcept; const char *GetFanName(size_t fanNum) const noexcept; int32_t GetFanRPM(size_t fanNum) const noexcept; diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp index 7e35aeff..72168c0e 100644 --- a/src/GCodes/GCodes.cpp +++ b/src/GCodes/GCodes.cpp @@ -3407,8 +3407,7 @@ void GCodes::SetMappedFanSpeed(float f) noexcept } else { - const FansBitmap fanMap = ct->GetFanMapping(); - fanMap.Iterate([f](unsigned int i, unsigned int) noexcept { reprap.GetFansManager().SetFanValue(i, f); }); + reprap.GetFansManager().SetFansValue(ct->GetFanMapping(), f); } } diff --git a/src/Heating/LocalHeater.cpp b/src/Heating/LocalHeater.cpp index 189b102d..c515849f 100644 --- a/src/Heating/LocalHeater.cpp +++ b/src/Heating/LocalHeater.cpp @@ -12,30 +12,33 @@ #include "HeaterMonitor.h" #include "Platform.h" #include "RepRap.h" +#include <Tools/Tool.h> // Private constants const uint32_t InitialTuningReadingInterval = 250; // the initial reading interval in milliseconds const uint32_t TempSettleTimeout = 20000; // how long we allow the initial temperature to settle -// Static class variables - -DeviationAccumulator LocalHeater::tuningStartTemp; // the temperature when we turned on the heater -float LocalHeater::tuningPwm; // the PWM to use -float LocalHeater::tuningTargetTemp; // the maximum temperature we are allowed to reach -uint32_t LocalHeater::tuningBeginTime; // when we started the tuning process - -DeviationAccumulator LocalHeater::dHigh; -DeviationAccumulator LocalHeater::dLow; -DeviationAccumulator LocalHeater::tOn; -DeviationAccumulator LocalHeater::tOff; -DeviationAccumulator LocalHeater::coolingTimeConstant; -uint32_t LocalHeater::lastOffTime; -uint32_t LocalHeater::lastOnTime; -float LocalHeater::peakTemp; -uint32_t LocalHeater::peakTime; +// Variables used during heater tuning +static float tuningPwm; // the PWM to use, 0..1 +static float tuningTargetTemp; // the target temperature +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 coolingTimeConstant; +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 FansBitmap tuningFans; +static bool fanOn; // whether we are running with the fan on or off + +static LocalHeater::HeaterParameters fanOffParams, fanOnParams; #if HAS_VOLTAGE_MONITOR -DeviationAccumulator LocalHeater::tuningVoltage; // the voltage readings we take during the heating phase +static DeviationAccumulator tuningVoltage; // sum of the voltage readings we take during the heating phase #endif // Member functions and constructors @@ -464,8 +467,11 @@ float LocalHeater::GetExpectedHeatingRate() const noexcept // Auto tune this heater. The caller has already checked that on other heater is being tuned. GCodeResult LocalHeater::StartAutoTune(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeException) { + // Get the target temperature (required) gb.MustSee('S'); const float targetTemp = gb.GetFValue(); + + // Get the optional PWM const float maxPwm = (gb.Seen('P')) ? gb.GetFValue() : GetModel().GetMaxPwm(); if (maxPwm < 0.1 || maxPwm > 1.0) { @@ -473,6 +479,24 @@ GCodeResult LocalHeater::StartAutoTune(GCodeBuffer& gb, const StringRef& reply) return GCodeResult::error; } + // Get the optional tool number + int toolNumber = (gb.Seen('T')) ? gb.GetIValue() : -1; + if (toolNumber >= 0) + { + auto tool = reprap.GetTool(toolNumber); + if (tool.IsNull()) + { + reply.printf("Tool %d not found", toolNumber); + return GCodeResult::error; + } + tuningFans = tool->GetFanMapping(); + reprap.GetFansManager().SetFansValue(tuningFans, 0.0); + } + else + { + tuningFans.Clear(); + } + if (!GetModel().IsEnabled()) { reply.printf("heater %u cannot be auto tuned while it is disabled", GetHeaterNumber()); @@ -486,9 +510,9 @@ GCodeResult LocalHeater::StartAutoTune(GCodeBuffer& gb, const StringRef& reply) } const float limit = GetHighestTemperatureLimit(); - if (targetTemp > limit) + if (targetTemp >= limit) { - reply.printf("heater %u target temperature must be no higher than the temperature limit for this heater (%.1fC)", GetHeaterNumber(), (double)limit); + reply.printf("heater %u target temperature must be below the temperature limit for this heater (%.1fC)", GetHeaterNumber(), (double)limit); return GCodeResult::error; } @@ -499,15 +523,40 @@ GCodeResult LocalHeater::StartAutoTune(GCodeBuffer& gb, const StringRef& reply) return GCodeResult::error; } - mode = HeaterMode::tuning0; - tuned = false; // assume failure + const bool seenA = gb.Seen('A'); + const float ambientTemp = (seenA) ? gb.GetFValue() : temperature; + if (ambientTemp + 20 >= targetTemp) + { + reply.printf("Target temperature must be at least 20C above ambient temperature"); + } + + reply.printf("Auto tuning heater %u using target temperature %.1f" DEGREE_SYMBOL "C and PWM %.2f - do not leave printer unattended", + GetHeaterNumber(), (double)targetTemp, (double)maxPwm); tuningPwm = maxPwm; tuningTargetTemp = targetTemp; - tuningBeginTime = millis(); tuningStartTemp.Clear(); - reply.printf("Auto tuning heater %u using target temperature %.1f" DEGREE_SYMBOL "C and PWM %.2f - do not leave printer unattended", - GetHeaterNumber(), (double)targetTemp, (double)maxPwm); + tuningBeginTime = millis(); + tuned = false; // assume failure + fanOn = false; + + if (seenA) + { + tuningStartTemp.Add(ambientTemp); + dHigh.Clear(); + dLow.Clear(); + tOn.Clear(); + tOff.Clear(); + coolingTimeConstant.Clear(); + timeSetHeating = millis(); + lastPwm = tuningPwm; // turn on heater at specified power + mode = HeaterMode::tuning1; + } + else + { + mode = HeaterMode::tuning0; + } + return GCodeResult::ok; } @@ -677,8 +726,32 @@ void LocalHeater::DoTuningStep() noexcept ) ) { - CalculateModel(); - break; + if (fanOn) + { + reprap.GetFansManager().SetFansValue(tuningFans, 0.0); + CalculateModel(fanOnParams); + ReportModel(); + break; + } + else + { + CalculateModel(fanOffParams); + if (tuningFans.IsEmpty()) + { + ReportModel(); + break; + } + else + { + reprap.GetFansManager().SetFansValue(tuningFans, 1.0); + fanOn = true; + dHigh.Clear(); + dLow.Clear(); + tOn.Clear(); + tOff.Clear(); + coolingTimeConstant.Clear(); + } + } } } lastOnTime = peakTime = now; @@ -720,7 +793,7 @@ void LocalHeater::DoTuningStep() noexcept } // Calculate the heater model from the accumulated heater parameters -void LocalHeater::CalculateModel() noexcept +void LocalHeater::CalculateModel(HeaterParameters& params) noexcept { if (reprap.Debug(moduleHeat)) { @@ -737,12 +810,18 @@ void LocalHeater::CalculateModel() noexcept } const float cycleTime = tOn.GetMean() + tOff.GetMean(); // in milliseconds - const float deadTime = (((dHigh.GetMean() * tOff.GetMean()) + (dLow.GetMean() * tOn.GetMean())) * 0.001)/cycleTime; // in seconds + params.deadTime = (((dHigh.GetMean() * tOff.GetMean()) + (dLow.GetMean() * tOn.GetMean())) * 0.001)/cycleTime; // in seconds + params.coolingTimeConstant = coolingTimeConstant.GetMean() * 0.001; // in seconds const float gain = ((tuningTargetTemp - tuningStartTemp.GetMean() - TuningHysteresis) * cycleTime) / (tOn.GetMean() * tuningPwm); - const float tc = coolingTimeConstant.GetMean() * 0.001; // in seconds + params.heatingRate = gain/params.coolingTimeConstant; + reprap.GetPlatform().MessageF(LoggedGenericMessage, "R%.1f A%.1f C%.1f D%.2f\n", + (double)params.heatingRate, (double)params.GetGain(), (double)params.coolingTimeConstant, (double)params.deadTime); +} +void LocalHeater::ReportModel() noexcept +{ String<1> dummy; - const GCodeResult rslt = SetModel(gain, tc, deadTime, tuningPwm, + const GCodeResult rslt = SetModel(fanOffParams.GetGain(), fanOffParams.coolingTimeConstant, fanOffParams.deadTime, tuningPwm, #if HAS_VOLTAGE_MONITOR tuningVoltage.GetMean(), #else @@ -751,6 +830,7 @@ void LocalHeater::CalculateModel() noexcept true, false, dummy.GetRef()); if (rslt == GCodeResult::ok || rslt == GCodeResult::warning) { + tuned = true; reprap.GetPlatform().MessageF(LoggedGenericMessage, "Auto tuning heater %u completed after %u cycles in %" PRIu32 " seconds. This heater needs the following M307 command:\n" " M307 H%u A%.1f C%.1f D%.2f S%.2f V%.1f\n", @@ -769,7 +849,7 @@ void LocalHeater::CalculateModel() noexcept else { reprap.GetPlatform().MessageF(WarningMessage, "Auto tune of heater %u failed due to bad curve fit (A=%.1f, C=%.1f, D=%.1f)\n", - GetHeaterNumber(), (double)gain, (double)tc, (double)deadTime); + GetHeaterNumber(), (double)fanOffParams.GetGain(), (double)fanOffParams.coolingTimeConstant, (double)fanOffParams.deadTime); } } diff --git a/src/Heating/LocalHeater.h b/src/Heating/LocalHeater.h index a34a499d..1bcef486 100644 --- a/src/Heating/LocalHeater.h +++ b/src/Heating/LocalHeater.h @@ -23,9 +23,18 @@ class HeaterMonitor; class LocalHeater : public Heater { - static const size_t NumPreviousTemperatures = 4; // How many samples we average the temperature derivative over + static const size_t NumPreviousTemperatures = 4; // How many samples we average the temperature derivative over public: + struct HeaterParameters + { + float heatingRate; + float coolingTimeConstant; + float deadTime; + + float GetGain() const noexcept { return heatingRate * coolingTimeConstant; } + }; + LocalHeater(unsigned int heaterNum) noexcept; ~LocalHeater() noexcept; @@ -59,7 +68,8 @@ private: void SetHeater(float power) const noexcept; // Power is a fraction in [0,1] TemperatureError ReadTemperature() noexcept; // Read and store the temperature of this heater void DoTuningStep() noexcept; // Called on each temperature sample when auto tuning - void CalculateModel() noexcept; // Calculate G, td and tc from the accumulated readings + void CalculateModel(HeaterParameters& params) noexcept; // Calculate G, td and tc from the accumulated readings + void ReportModel() noexcept; float GetExpectedHeatingRate() const noexcept; // Get the minimum heating rate we expect void RaiseHeaterFault(const char *format, ...) noexcept; @@ -84,27 +94,7 @@ private: static constexpr unsigned int MinTuningHeaterCycles = 5; static constexpr unsigned int MaxTuningHeaterCycles = 20; - static constexpr float TuningHysteresis = 2.0; - - // Variables used during heater tuning - static float tuningPwm; // the PWM to use, 0..1 - static float tuningTargetTemp; // the target temperature - - 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 coolingTimeConstant; - 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 - -#if HAS_VOLTAGE_MONITOR - static DeviationAccumulator tuningVoltage; // sum of the voltage readings we take during the heating phase -#endif + static constexpr float TuningHysteresis = 3.0; }; #endif /* SRC_LOCALHEATER_H_ */ |