Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Crocker <dcrocker@eschertech.com>2017-07-18 20:25:12 +0300
committerDavid Crocker <dcrocker@eschertech.com>2017-07-18 20:25:12 +0300
commit4e31deb2a5a5e0f517ffe55ec1671bafd621a53e (patch)
treede60248c717efdff8904587041461de73fd11156 /src/Heating
parent6f81b7594ba0a9795dc19b3e3784a21aba544de4 (diff)
Release 1.19beta10
New features: Refactored and completed 4-leadscrew bed levelling code Probe deployment and retraction for G30 and G29 commands is now handled automatically. You should still include a M401 command before the first G30 command in bed.g and a M402 command after the last one, so that the probe deploys and retracts once for the entire sequence instead of once per G30 command. M577 now allows separate X and Y spacings, use Sxxx:yyy Volumetric extrusion is now supported (M200) Additional tool/heater data is provided to DWC (thanks chrishamm). Using Heater 0 as a tool heater should now work. The '(' character in a gcode file now introduces a comment, just as the ';' character does. The comment is terminated at end-of-line. This is not the same as in some CNC gcodes, where a comment introduced by '(' is terminated by ')'. Heater tuning peak detection algorithm changed (but still needs more work). This may fix some "no peak detected" reports during auto tuning. The heater dead time is how taken as 60% of the peak delay time intead of 100%, which results in more aggressive PID parameters. Bug fixes: M669 with no parameters now reports the bed offset on a SCARA machine as well as the other parameters M671 with no parameters now reports the maximum correction as well as the leadscrew positions Heater model max PWM is now set to tuning PWM after auto tuning (thanks cangelis) If an HTML file uploaded over USB contained an embedded leading substring of the EOF string, incorrect data was written to file (thanks cangelis) Fixed incorrect movement following a tool change on an IDEX machine (thanks lars) RADDS build would not start up Other changes: TEMPERATURE_CLOSE_ENOUGH reduced from 2.5C to 1.0C Reduced the maximum number of random probe points on Duet WiFi/Ethernet to 32 to avoid running out of memory during delta auto calibration Simplified the axis orthogonality correction code Added new bitmap types along with function templates to work on them Clear HSMCI callback when exiting RepRap module e.g. to flash new firmware Use lrintf() instead of round() DriveMovement structures are now allocated dynamically from a freelist, to allow more moves to be queued in typical cases. The number free and minimum ever free is included in the M122 report.
Diffstat (limited to 'src/Heating')
-rw-r--r--src/Heating/Heat.cpp27
-rw-r--r--src/Heating/Heat.h20
-rw-r--r--src/Heating/Pid.cpp83
3 files changed, 84 insertions, 46 deletions
diff --git a/src/Heating/Heat.cpp b/src/Heating/Heat.cpp
index bfb982a6..89a1fc8c 100644
--- a/src/Heating/Heat.cpp
+++ b/src/Heating/Heat.cpp
@@ -51,10 +51,28 @@ void Heat::ResetHeaterModels()
}
}
+void Heat::SetBedHeater(int8_t heater)
+{
+ if (bedHeater >= 0)
+ {
+ pids[bedHeater]->SwitchOff();
+ }
+ bedHeater = heater;
+}
+
+void Heat::SetChamberHeater(int8_t heater)
+{
+ if (chamberHeater >= 0)
+ {
+ pids[chamberHeater]->SwitchOff();
+ }
+ chamberHeater = heater;
+}
+
void Heat::Init()
{
// Set up the real heaters and the corresponding PIDs
- for (size_t heater : ARRAY_INDICES(pids))
+ for (size_t heater = 0; heater < Heaters; ++heater)
{
heaterSensors[heater] = nullptr; // no temperature sensor assigned yet
if ((int)heater == DefaultBedHeater || (int)heater == DefaultChamberHeater)
@@ -72,6 +90,7 @@ void Heat::Init()
{
pids[heater]->Init(DefaultHotEndHeaterGain, DefaultHotEndHeaterTimeConstant, DefaultHotEndHeaterDeadTime, DefaultExtruderTemperatureLimit, true);
}
+ lastStandbyTools[heater] = nullptr;
}
// Set up the virtual heaters
@@ -82,7 +101,7 @@ void Heat::Init()
}
// Set up default virtual heaters for MCU temperature and TMC driver overheat sensors
-#ifndef __RADDS
+#ifndef __RADDS__
virtualHeaterSensors[0] = TemperatureSensor::Create(CpuTemperatureSenseChannel);
virtualHeaterSensors[0]->SetHeaterName("MCU"); // name this virtual heater so that it appears in DWC
#endif
@@ -253,6 +272,7 @@ void Heat::SwitchOff(int8_t heater)
if (heater >= 0 && heater < (int)Heaters)
{
pids[heater]->SwitchOff();
+ lastStandbyTools[heater] = nullptr;
}
}
@@ -264,11 +284,12 @@ void Heat::SwitchOffAll()
}
}
-void Heat::Standby(int8_t heater)
+void Heat::Standby(int8_t heater, const Tool *tool)
{
if (heater >= 0 && heater < (int)Heaters)
{
pids[heater]->Standby();
+ lastStandbyTools[heater] = tool;
}
}
diff --git a/src/Heating/Heat.h b/src/Heating/Heat.h
index a793f25f..e231c928 100644
--- a/src/Heating/Heat.h
+++ b/src/Heating/Heat.h
@@ -66,7 +66,7 @@ public:
void SetTemperatureLimit(int8_t heater, float t);
float GetTemperatureLimit(int8_t heater) const;
void Activate(int8_t heater); // Turn on a heater
- void Standby(int8_t heater); // Set a heater idle
+ void Standby(int8_t heater, const Tool* tool); // Set a heater to standby
float GetTemperature(int8_t heater) const; // Get the temperature of a heater
float GetTargetTemperature(int8_t heater) const; // Get the target temperature
HeaterStatus GetStatus(int8_t heater) const; // Get the off/standby/active status
@@ -122,6 +122,12 @@ public:
float GetTemperature(size_t heater, TemperatureError& err); // Result is in degrees Celsius
+ const Tool* GetLastStandbyTool(int heater) const
+ pre(heater >= 0; heater < Heaters)
+ {
+ return lastStandbyTools[heater];
+ }
+
#ifdef DUET_NG
void SuspendHeaters(bool sus); // Suspend the heaters to conserve power
bool WriteBedAndChamberTempSettings(FileStore *f) const; // Save some resume information
@@ -135,6 +141,8 @@ private:
Platform& platform; // The instance of the RepRap hardware class
PID* pids[Heaters]; // A PID controller for each heater
+ const Tool* lastStandbyTools[Heaters]; // The last tool that caused the corresponding heater to be set to standby
+
TemperatureSensor *heaterSensors[Heaters]; // The sensor used by the real heaters
TemperatureSensor *virtualHeaterSensors[MaxVirtualHeaters]; // Sensors for virtual heaters
@@ -166,21 +174,11 @@ inline int8_t Heat::GetBedHeater() const
return bedHeater;
}
-inline void Heat::SetBedHeater(int8_t heater)
-{
- bedHeater = heater;
-}
-
inline int8_t Heat::GetChamberHeater() const
{
return chamberHeater;
}
-inline void Heat::SetChamberHeater(int8_t heater)
-{
- chamberHeater = heater;
-}
-
// Get the process model for the specified heater
inline const FopDt& Heat::GetHeaterModel(size_t heater) const
{
diff --git a/src/Heating/Pid.cpp b/src/Heating/Pid.cpp
index c8494f4e..4f93cb7e 100644
--- a/src/Heating/Pid.cpp
+++ b/src/Heating/Pid.cpp
@@ -127,31 +127,34 @@ TemperatureError PID::ReadTemperature()
// This must be called whenever the heater is turned on, and any time the heater is active and the target temperature is changed
void PID::SwitchOn()
{
- if (mode == HeaterMode::fault)
- {
- if (reprap.Debug(Module::moduleHeat))
- {
- platform.MessageF(GENERIC_MESSAGE, "Heater %d not switched on due to temperature fault\n", heater);
- }
- }
- else if (model.IsEnabled())
+ if (model.IsEnabled())
{
-//debugPrintf("Heater %d on temp %.1f\n", heater, temperature);
- const float target = (active) ? activeTemperature : standbyTemperature;
- const HeaterMode oldMode = mode;
- mode = (temperature + TEMPERATURE_CLOSE_ENOUGH < target) ? HeaterMode::heating
- : (temperature > target + TEMPERATURE_CLOSE_ENOUGH) ? HeaterMode::cooling
- : HeaterMode::stable;
- if (mode != oldMode)
+ if (mode == HeaterMode::fault)
{
- heatingFaultCount = 0;
- if (mode == HeaterMode::heating)
+ if (reprap.Debug(Module::moduleHeat))
{
- timeSetHeating = millis();
+ platform.MessageF(GENERIC_MESSAGE, "Heater %d not switched on due to temperature fault\n", heater);
}
- if (reprap.Debug(Module::moduleHeat) && oldMode == HeaterMode::off)
+ }
+ else if (model.IsEnabled())
+ {
+ //debugPrintf("Heater %d on, temp %.1f\n", heater, temperature);
+ const float target = (active) ? activeTemperature : standbyTemperature;
+ const HeaterMode oldMode = mode;
+ mode = (temperature + TEMPERATURE_CLOSE_ENOUGH < target) ? HeaterMode::heating
+ : (temperature > target + TEMPERATURE_CLOSE_ENOUGH) ? HeaterMode::cooling
+ : HeaterMode::stable;
+ if (mode != oldMode)
{
- platform.MessageF(GENERIC_MESSAGE, "Heater %d switched on\n", heater);
+ heatingFaultCount = 0;
+ if (mode == HeaterMode::heating)
+ {
+ timeSetHeating = millis();
+ }
+ if (reprap.Debug(Module::moduleHeat) && oldMode == HeaterMode::off)
+ {
+ platform.MessageF(GENERIC_MESSAGE, "Heater %d switched on\n", heater);
+ }
}
}
}
@@ -664,7 +667,7 @@ void PID::DoTuningStep()
const int peakIndex = GetPeakTempIndex();
if (peakIndex < 0)
{
- if (millis() - tuningPhaseStartTime < 120 * 1000) // allow 2 minutes for the bed temperature to start falling
+ if (millis() - tuningPhaseStartTime < 60 * 1000) // allow 1 minute for the bed temperature reach peal temperature
{
return; // still waiting for peak temperature
}
@@ -739,7 +742,8 @@ void PID::DoTuningStep()
}
// Calculate which reading gave us the peak temperature.
-// Return -1 if peak not identified yet, 0 if we failed to find a peak, else the index of the peak (which can't be zero because we always average 3 readings)
+// Return -1 if peak not identified yet, 0 if we are never going to find a peak, else the index of the peak
+// If the readings show a continuous decrease then we return 1, because zero dead time would lead to infinities
/*static*/ int PID::GetPeakTempIndex()
{
// Check we have enough readings to look for the peak
@@ -758,20 +762,25 @@ void PID::DoTuningStep()
peakIndex = IdentifyPeak(5);
if (peakIndex < 0)
{
- return 0; // more than one peak
+ peakIndex = IdentifyPeak(7);
+ if (peakIndex < 0)
+ {
+ return 0; // more than one peak
+ }
}
}
}
// If we have found one peak and it's not too near the end of the readings, return it
- return ((size_t)peakIndex + 6 < tuningReadingsTaken) ? peakIndex : -1;
+ return ((size_t)peakIndex + 3 < tuningReadingsTaken) ? max<int>(peakIndex, 1) : -1;
}
// See if there is exactly one peak in the readings.
-// Return -1 if more than one peak, else the index of the peak. The so-called peak may be right at the end , in which case it isn't really a peak.
+// Return -1 if more than one peak, else the index of the peak. The so-called peak may be right at the end, in which case it isn't really a peak.
+// With a well-insulated bed heater the temperature may not start dropping appreciably within the 120 second time limit allowed.
/*static*/ int PID::IdentifyPeak(size_t numToAverage)
{
- int firstPeakIndex = -1;
+ int firstPeakIndex = -1, lastSameIndex = -1;
float peakTempTimesN = -999.0;
for (size_t i = 0; i + numToAverage <= tuningReadingsTaken; ++i)
{
@@ -780,18 +789,22 @@ void PID::DoTuningStep()
{
peak += tuningTempReadings[i + j];
}
- if (peak >= peakTempTimesN)
+ if (peak > peakTempTimesN)
{
- if ((int)i == firstPeakIndex + 1)
+ if ((int)i == lastSameIndex + 1)
{
- firstPeakIndex = (int)i; // readings still going up or staying the same, so advance the first peak index
+ firstPeakIndex = lastSameIndex = (int)i; // readings still going up or staying the same, so advance the first peak index
peakTempTimesN = peak;
}
else
{
- return -1; // error, more than one peak
+ return -1; // error, more than one peak
}
}
+ else if (peak == peakTempTimesN) // exact equality can occur because the floating point value is computed from an integral value
+ {
+ lastSameIndex = (int)i;
+ }
}
return firstPeakIndex + (numToAverage - 1)/2;
}
@@ -804,11 +817,17 @@ void PID::CalculateModel()
DisplayBuffer("At completion");
}
const float tc = (float)((tuningReadingsTaken - 1) * tuningReadingInterval)/(1000.0 * log((tuningTempReadings[0] - tuningStartTemp)/(tuningTempReadings[tuningReadingsTaken - 1] - tuningStartTemp)));
- const float td = (float)tuningPeakDelay * 0.001;
const float heatingTime = (tuningHeatingTime - tuningPeakDelay) * 0.001;
const float gain = (tuningHeaterOffTemp - tuningStartTemp)/(1.0 - exp(-heatingTime/tc));
- tuned = SetModel(gain, tc, td, model.GetMaxPwm(), true);
+ // There are two ways of calculating the dead time:
+ // 1. Based on the delay to peak temperature after we turned the heater off. Adding 0.5sec and then taking 65% of the result is about right.
+ // 2. Based on the peak temperature compared to the temperature at which we turned the heater off.
+ // Try #2 because it is easier to identify the peak temperature than the delay to peak temperature. It can be slightly to aggressive, so add 30%.
+ //const float td = (float)(tuningPeakDelay + 500) * 0.00065; // take the dead time as 65% of the delay to peak rounded up to a half second
+ const float td = tc * logf((gain + tuningStartTemp - tuningHeaterOffTemp)/(gain + tuningStartTemp - tuningPeakTemperature)) * 1.3;
+
+ tuned = SetModel(gain, tc, td, tuningPwm, true);
if (tuned)
{
platform.MessageF(GENERIC_MESSAGE,