This repository has been archived on 2025-02-01. You can view files and clone it, but cannot push or open issues or pull requests.
reprapfirmware-dc42/src/Heating/Pid.h
David Crocker 88e3092b78 Version 1.17 dev 4
Support concurrenrt execution of commands form different channels
M143 now supports individual temperature limits per heater
Fixed issue with dely of up to 2 seconds when switching Duet WiFi heater
channel 3 to servo mode
When enable polarity is set using the M569 R parameter, disable the
corresponding drive
Add exdperimental S99 option on G1 command to log probe changes (Duet
WiFi only)
2016-11-17 21:29:20 +00:00

199 lines
7.3 KiB
C++

/*
* Pid.h
*
* Created on: 21 Jul 2016
* Author: David
*/
#ifndef SRC_PID_H_
#define SRC_PID_H_
/**
* This class implements a PID controller for the heaters
*/
#include "FOPDT.h"
class PID
{
enum class HeaterMode : uint8_t
{
// The order of these is important because we test "mode > HeatingMode::off" to determine whether the heater is active
fault,
off,
heating,
cooling,
stable,
// All states from here onwards must be PID tuning states because function IsTuning assumes that
tuning0,
tuning1,
tuning2,
lastTuningMode = tuning2
};
static const size_t NumPreviousTemperatures = 4; // How many samples we average the temperature derivative over
public:
PID(Platform* p, int8_t h);
void Init(float pGain, float pTc, float pTd, float tempLimit, bool usePid); // (Re)Set everything to start
void Reset();
void Spin(); // Called in a tight loop to keep things running
void SetActiveTemperature(float t);
float GetActiveTemperature() const;
void SetStandbyTemperature(float t);
float GetStandbyTemperature() const;
void SetTemperatureLimit(float t);
float GetTemperatureLimit() const;
void Activate(); // Switch from idle to active
void Standby(); // Switch from active to idle
bool Active() const; // Are we active?
void SwitchOff(); // Not even standby - all heater power off
bool SwitchedOff() const; // Are we switched off?
bool FaultOccurred() const; // Has a heater fault occurred?
void ResetFault(); // Reset a fault condition - only call this if you know what you are doing
float GetTemperature() const; // Get the current temperature
float GetAveragePWM() const; // Return the running average PWM to the heater. Answer is a fraction in [0, 1].
uint32_t GetLastSampleTime() const; // Return when the temp sensor was last sampled
float GetAccumulator() const; // Return the integral accumulator
void StartAutoTune(float maxTemp, float maxPwm, StringRef& reply); // Start an auto tune cycle for this PID
bool IsTuning() const;
void GetAutoTuneStatus(StringRef& reply); // Get the auto tune status or last result
const FopDt& GetModel() const // Get the process model
{ return model; }
bool SetModel(float gain, float tc, float td, float maxPwm, bool usePid); // Set the process model
bool IsModelUsed() const // Is the model being used to determine the PID parameters?
{ return useModel; }
void UseModel(bool b) // Use or don't use the model to provide the PID parameters
{ useModel = b; }
bool IsHeaterEnabled() const // Is this heater enabled?
{ return model.IsEnabled(); }
void GetHeaterProtection(float& pMaxTempExcursion, float& pMaxFaultTime) const
{ pMaxTempExcursion = maxTempExcursion; pMaxFaultTime = maxHeatingFaultTime; }
void SetHeaterProtection(float pMaxTempExcursion, float pMaxFaultTime)
{ maxTempExcursion = pMaxTempExcursion; maxHeatingFaultTime = pMaxFaultTime; }
private:
void SwitchOn(); // Turn the heater on and set the mode
void SetHeater(float power) const; // Power is a fraction in [0,1]
TemperatureError ReadTemperature(); // Read and store the temperature of this heater
void DoTuningStep(); // Called on each temperature sample when auto tuning
bool ReadingsStable(size_t numReadings, float maxDiff) const
pre(numReadings >= 2; numReadings <= MaxTuningTempReadings);
static size_t GetMaxRateIndex(); // Auto tune helper function
void DisplayBuffer(const char *intro); // Debug helper
void FitCurve(); // Calculate G, td and tc from the accumulated readings
float GetExpectedHeatingRate() const; // Get the minimum heating rate we expect
Platform* platform; // The instance of the class that is the RepRap hardware
float activeTemperature; // The required active temperature
float standbyTemperature; // The required standby temperature
float temperatureLimit; // The maximum allowed temperature for this heater
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
float temperature; // The current temperature
float previousTemperatures[NumPreviousTemperatures]; // The temperatures of the previous NumDerivativeSamples measurements, used for calculating the derivative
size_t previousTemperatureIndex; // Which slot in previousTemperature we fill in next
FopDt model; // The process model and PID parameters
float iAccumulator; // The integral PID component
float lastPwm; // The last PWM value we output, before scaling by kS
float averagePWM; // The running average of the PWM, after scaling.
uint32_t timeSetHeating; // When we turned on the heater
uint32_t lastSampleTime; // Time when the temperature was last sampled by Spin()
uint16_t heatingFaultCount; // Count of questionable heating behaviours
int8_t heater; // The index of our heater
uint8_t previousTemperaturesGood; // Bitmap indicating which previous temperature were good readings
HeaterMode mode; // Current state of the heater
bool active; // Are we active or standby?
bool tuned; // True if tuning was successful
bool useModel; // Use the model to calculate the PID parameters
uint8_t badTemperatureCount; // Count of sequential dud readings
static_assert(sizeof(previousTemperaturesGood) * 8 >= NumPreviousTemperatures, "too few bits in previousTemperaturesGood");
static float *tuningTempReadings; // the readings from the heater being tuned
static float tuningStartTemp; // the temperature when we turned on the heater
static float tuningPwm; // the PWM to use, 0..1
static float tuningMaxTemp; // the maximum temperature we are allowed to reach
static uint32_t tuningBeginTime; // when we started the tuning process
static uint32_t tuningPhaseStartTime; // when we started the current tuning phase
static uint32_t tuningReadingInterval; // how often we are sampling, in milliseconds
static size_t tuningReadingsTaken; // how many temperature samples we have taken
static float tuningTimeOfFastestRate; // how long after turn-on the fastest temperature rise occurred
static float tuningFastestRate; // the fastest temperature rise
static const size_t MaxTuningTempReadings = 128; // The maximum number of readings we keep. Must be an even number.
};
inline bool PID::Active() const
{
return active;
}
inline float PID::GetActiveTemperature() const
{
return activeTemperature;
}
inline float PID::GetStandbyTemperature() const
{
return standbyTemperature;
}
inline void PID::SetTemperatureLimit(float t)
{
temperatureLimit = t;
}
inline float PID::GetTemperatureLimit() const
{
return temperatureLimit;
}
inline float PID::GetTemperature() const
{
return temperature;
}
inline bool PID::FaultOccurred() const
{
return mode == HeaterMode::fault;
}
inline bool PID::SwitchedOff() const
{
return mode == HeaterMode::off;
}
inline uint32_t PID::GetLastSampleTime() const
{
return lastSampleTime;
}
inline float PID::GetAccumulator() const
{
return iAccumulator;
}
inline void PID::SetHeater(float power) const
{
platform->SetHeater(heater, power);
}
inline bool PID::IsTuning() const
{
return mode >= HeaterMode::tuning0;
}
#endif /* SRC_PID_H_ */