diff --git a/src/Heating/LocalHeater.cpp b/src/Heating/LocalHeater.cpp index d22a43735..d87f29b83 100644 --- a/src/Heating/LocalHeater.cpp +++ b/src/Heating/LocalHeater.cpp @@ -287,64 +287,64 @@ void LocalHeater::Spin() noexcept { // Get the target temperature and the error const float targetTemperature = min<float>(GetTargetTemperature() + extrusionTemperatureBoost, GetHighestTemperatureLimit()); - const float error = targetTemperature - temperature; - if (extrusionTemperatureBoost != 0.0 || lastExtrusionTemperatureBoost != extrusionTemperatureBoost) + if (IsPidMode(mode) && extrusionTemperatureBoost != lastExtrusionTemperatureBoost) { // Calculate new heater mode to prevent heater fault due to exceededAllowedExcursion - String<1> dummy; - (void)SwitchOn(dummy.GetRef()); + mode = (temperature + TemperatureCloseEnough < targetTemperature) ? HeaterMode::heating + : (temperature > targetTemperature + TemperatureCloseEnough) ? HeaterMode::cooling + : HeaterMode::stable; + lastExtrusionTemperatureBoost = extrusionTemperatureBoost; } - lastExtrusionTemperatureBoost = extrusionTemperatureBoost; + + const float error = targetTemperature - temperature; // Do the heating checks - switch(mode) + switch (mode) { case HeaterMode::heating: + if (error <= TemperatureCloseEnough) { - if (error <= TemperatureCloseEnough) + mode = HeaterMode::stable; + heatingFaultCount = 0; + } + else + { + const uint32_t now = millis(); + if ((float)(now - timeSetHeating) < GetModel().GetDeadTime() * SecondsToMillis * 2) // wait for twice the dead time before we start looking at the temperature rise { - mode = HeaterMode::stable; - heatingFaultCount = 0; + // Record the temperature for when we are past the dead time + lastTemperatureValue = temperature; + lastTemperatureMillis = now; } - else + else if (gotDerivative) // this is a check in case we just had a temperature spike { - const uint32_t now = millis(); - if ((float)(now - timeSetHeating) < GetModel().GetDeadTime() * SecondsToMillis * 2) // wait for twice the dead time before we start looking at the temperature rise - { - // Record the temperature for when we are past the dead time - lastTemperatureValue = temperature; - lastTemperatureMillis = now; - } - else if (gotDerivative) // this is a check in case we just had a temperature spike + const float expectedRate = GetExpectedHeatingRate(); + const float minSamplingInterval = 3.0/expectedRate; // only check the temperature when we expect at least 3C rise since last time + const float actualInterval = (float)(now - lastTemperatureMillis) * MillisToSeconds; + if (actualInterval >= minSamplingInterval) { - const float expectedRate = GetExpectedHeatingRate(); - const float minSamplingInterval = 3.0/expectedRate; // only check the temperature when we expect at least 3C rise since last time - const float actualInterval = (float)(now - lastTemperatureMillis) * MillisToSeconds; - if (actualInterval >= minSamplingInterval) + // Check that we are heating fast enough, and if so, take another sample + const float expectedTemperatureRise = expectedRate * actualInterval; + const float actualTemperatureRise = temperature - lastTemperatureValue; + // Bed heaters sometimes have much slower long term heating rates than their short term heating rates, so allow them a lower measured heating rate + if (actualTemperatureRise < expectedTemperatureRise * ((IsBedOrChamber()) ? MinBedTemperatureRiseFactor : MinToolTemperatureRiseFactor)) { - // Check that we are heating fast enough, and if so, take another sample - const float expectedTemperatureRise = expectedRate * actualInterval; - const float actualTemperatureRise = temperature - lastTemperatureValue; - // Bed heaters sometimes have much slower long term heating rates than their short term heating rates, so allow them a lower measured heating rate - if (actualTemperatureRise < expectedTemperatureRise * ((IsBedOrChamber()) ? MinBedTemperatureRiseFactor : MinToolTemperatureRiseFactor)) + ++heatingFaultCount; + if (heatingFaultCount * HeatSampleIntervalMillis > GetMaxHeatingFaultTime() * SecondsToMillis) { - ++heatingFaultCount; - if (heatingFaultCount * HeatSampleIntervalMillis > GetMaxHeatingFaultTime() * SecondsToMillis) - { - RaiseHeaterFault(HeaterFaultType::temperatureRisingTooSlowly, - "expected %.2f" DEGREE_SYMBOL "C/sec measured %.2f" DEGREE_SYMBOL "C/sec", - (double)expectedRate, (double)(actualTemperatureRise/actualInterval)); - } + RaiseHeaterFault(HeaterFaultType::temperatureRisingTooSlowly, + "expected %.2f" DEGREE_SYMBOL "C/sec measured %.2f" DEGREE_SYMBOL "C/sec", + (double)expectedRate, (double)(actualTemperatureRise/actualInterval)); } - else + } + else + { + lastTemperatureValue = temperature; + lastTemperatureMillis = now; + if (heatingFaultCount != 0) { - lastTemperatureValue = temperature; - lastTemperatureMillis = now; - if (heatingFaultCount != 0) - { - --heatingFaultCount; - } + --heatingFaultCount; } } } diff --git a/src/Movement/DDARing.cpp b/src/Movement/DDARing.cpp index 4760195e3..f28e9a3f7 100644 --- a/src/Movement/DDARing.cpp +++ b/src/Movement/DDARing.cpp @@ -84,6 +84,7 @@ void DDARing::Init1(unsigned int numDdas) noexcept getPointer = addPointer; lastFeedForwardTool = nullptr; + lastAverageExtrusionSpeed = 0.0; } // This must be called from Move::Init, not from the Move constructor, because it indirectly refers to the GCodes module which must therefore be initialised first @@ -731,6 +732,8 @@ uint32_t DDARing::ManageIOBitsAndFeedForward() noexcept SetBasePriority(NvicPriorityStep); DDA *cdda = getPointer; const uint32_t now = StepTimer::GetMovementTimerTicks(); + const Tool *_ecv_null feedForwardTool; + float feedForwardAverageExtrusionSpeed = 0.0; while (cdda->IsCommitted()) { @@ -752,22 +755,25 @@ uint32_t DDARing::ManageIOBitsAndFeedForward() noexcept } } - const Tool *_ecv_null t; - if (!doneFeedForward && (t = cdda->GetTool()) != nullptr && timeToMoveStart < (int32_t)t->GetFeedForwardAdvanceClocks() && timeToMoveEnd > (int32_t)t->GetFeedForwardAdvanceClocks()) + if (!doneFeedForward) { - // This move is current from the perspective of feedforward - if (!cdda->HaveDoneFeedForward()) + feedForwardTool = cdda->GetTool(); + if (feedForwardTool != nullptr && timeToMoveStart < (int32_t)feedForwardTool->GetFeedForwardAdvanceClocks() && timeToMoveEnd > (int32_t)feedForwardTool->GetFeedForwardAdvanceClocks()) { - // Don't set feedforward here because we have set a very high base priority and we may need to send CAN messages. Just record that we need to set it. - setFeedForward = true; - lastFeedForwardTool = t; - cdda->SetDoneFeedForward(); - } - nextWakeupDelay = min<uint32_t>(nextWakeupDelay, (uint32_t)timeToMoveEnd > t->GetFeedForwardAdvanceClocks()); - doneFeedForward = true; - if (doneIoBits) - { - break; + // This move is current from the perspective of feedforward + if (!cdda->HaveDoneFeedForward()) + { + // Don't set feedforward here because we have set a very high base priority and we may need to send CAN messages. Just record that we need to set it. + cdda->SetDoneFeedForward(); + feedForwardAverageExtrusionSpeed = cdda->GetAverageExtrusionSpeed(); + setFeedForward = true; + } + nextWakeupDelay = min<uint32_t>(nextWakeupDelay, (uint32_t)timeToMoveEnd > feedForwardTool->GetFeedForwardAdvanceClocks()); + doneFeedForward = true; + if (doneIoBits) + { + break; + } } } cdda = cdda->GetNext(); @@ -782,12 +788,18 @@ uint32_t DDARing::ManageIOBitsAndFeedForward() noexcept if (setFeedForward) { - lastFeedForwardTool->ApplyExtrusionFeedForward(cdda->GetAverageExtrusionSpeed()); + if (feedForwardTool != lastFeedForwardTool || fabsf(feedForwardAverageExtrusionSpeed - lastAverageExtrusionSpeed) > lastAverageExtrusionSpeed * 0.05) + { + feedForwardTool->ApplyExtrusionFeedForward(feedForwardAverageExtrusionSpeed); + lastFeedForwardTool = feedForwardTool; + lastAverageExtrusionSpeed = feedForwardAverageExtrusionSpeed; + } } - else if (!doneFeedForward && lastFeedForwardTool != nullptr) + else if (!doneFeedForward && lastFeedForwardTool != nullptr && lastAverageExtrusionSpeed != 0.0) { lastFeedForwardTool->StopExtrusionFeedForward(); // no move with a tool active so cancel the last feedforward we commanded lastFeedForwardTool = nullptr; + lastAverageExtrusionSpeed = 0.0; } return (nextWakeupDelay + StepClockRate/1000 - 1)/(StepClockRate/1000); // convert step clocks to milliseconds, rounding up diff --git a/src/Movement/DDARing.h b/src/Movement/DDARing.h index 0db2cf07f..8b946f73a 100644 --- a/src/Movement/DDARing.h +++ b/src/Movement/DDARing.h @@ -98,6 +98,7 @@ class DDARing INHERIT_OBJECT_MODEL uint32_t gracePeriod; // The minimum idle time in milliseconds, before we should start a move. Better to have a few moves in the queue so that we can do lookahead const Tool *_ecv_null lastFeedForwardTool; // the tool we last applied heater feedforward to + float lastAverageExtrusionSpeed; // the extrusion speed we last set heater feedforward for uint32_t scheduledMoves; // Number of moves scheduled in this ring uint32_t completedMoves; // Number of moves completed in this ring diff --git a/src/Version.h b/src/Version.h index 905ca2335..528222911 100644 --- a/src/Version.h +++ b/src/Version.h @@ -10,7 +10,7 @@ #ifndef VERSION // Note: the complete VERSION string must be in standard version number format and must not contain spaces! This is so that DWC can parse it. -# define MAIN_VERSION "3.6.0-beta.1+3" +# define MAIN_VERSION "3.6.0-beta.2" # ifdef USE_CAN0 # define VERSION_SUFFIX "(CAN0)" # else