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

Pid.h « Heating « src - github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 8907063a056dc742839b0a2a7583f25c0d0a480a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
/*
 * 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 "RepRapFirmware.h"
#include "FOPDT.h"
#include "TemperatureError.h"

#define NEW_TUNING	(1)

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,
#ifdef NEW_TUNING
		tuning3,
		lastTuningMode = tuning3
#else
		lastTuningMode = tuning2
#endif
	};

	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 targetTemp, 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 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; }

	void SetM301PidParameters(const M301PidParameters& params)
		{ model.SetM301PidParameters(params); }

#ifdef DUET_NG
	void Suspend(bool sus);							// Suspend the heater to conserve power
#endif

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
	static bool ReadingsStable(size_t numReadings, float maxDiff)
		pre(numReadings >= 2; numReadings <= MaxTuningTempReadings);
#ifdef NEW_TUNING
	static int GetPeakTempIndex();					// Auto tune helper function
	static int IdentifyPeak(size_t numToAverage);	// Auto tune helper function
	void CalculateModel();							// Calculate G, td and tc from the accumulated readings
#else
	static size_t GetMaxRateIndex();				// Auto tune helper function
	void FitCurve();								// Calculate G, td and tc from the accumulated readings
#endif
	void DisplayBuffer(const char *intro);			// Debug helper
	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
#ifdef DUET_NG
	bool suspended;									// True if suspended to save power
#endif
	uint8_t badTemperatureCount;					// Count of sequential dud readings

	static_assert(sizeof(previousTemperaturesGood) * 8 >= NumPreviousTemperatures, "too few bits in previousTemperaturesGood");

	// Variables used during heater tuning
	static const size_t MaxTuningTempReadings = 128; // The maximum number of readings we keep. Must be an even number.

	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 tuningTargetTemp;						// 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

#ifdef NEW_TUNING
	static float tuningHeaterOffTemp;				// the temperature when we turned the heater off
	static float tuningPeakTemperature;				// the peak temperature reached, averaged over 3 readings (so slightly less than the true peak)
	static uint32_t tuningHeatingTime;				// how long we had the heating on for
	static uint32_t tuningPeakDelay;				// how many milliseconds the temperature continues to rise after turning the heater off
#else
	static float tuningTimeOfFastestRate;			// how long after turn-on the fastest temperature rise occurred
	static float tuningFastestRate;					// the fastest temperature rise
#endif
};


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 bool PID::IsTuning() const
{
	return mode >= HeaterMode::tuning0;
}

#endif /* SRC_PID_H_ */