ArduinoMega2560_SPI 1.0
Cargando...
Buscando...
Nada coincide
pid.cpp
Ir a la documentación de este archivo.
1/**
2 * @file pid.cpp
3 * @brief Implementación del controlador PID con anti-windup, derivative-on-measurement
4 * y limitación de cambio de salida (slew-rate limit).
5 */
6
7#include "pid.h"
8
9/**
10 * @brief Constructor del controlador PID.
11 *
12 * @param Kp Ganancia proporcional.
13 * @param Ki Ganancia integral.
14 * @param Kd Ganancia derivativa.
15 * @param outputMin Límite mínimo de salida.
16 * @param outputMax Límite máximo de salida.
17 * @param dt Tiempo de muestreo en segundos.
18 * @param outputMaxChanged Máximo cambio permitido por ciclo (slew-rate).
19 */
20PID::PID(float Kp, float Ki, float Kd,
21 float outputMin, float outputMax,
22 float dt, float outputMaxChanged)
23{
24 this->Kp = Kp;
25 this->Ki = Ki;
26 this->Kd = Kd;
27
28 this->outputMin = outputMin;
29 this->outputMax = outputMax;
30
31 this->dt = statedt(dt);
32 this->outputMaxChanged = outputMaxChanged;
33
34 this->error = 0.0f;
35 this->prevError = 0.0f;
36 this->integral = 0.0f;
37 this->derivative = 0.0f;
38 this->output = 0.0f;
39
40 this->prevFeedback = 0.0f;
41 this->prevOutput = 0.0f;
42}
43
44/**
45 * @brief Calcula la salida del controlador PID.
46 *
47 * Implementa:
48 * - Proporcional
49 * - Integral con anti-windup condicional
50 * - Derivative-on-measurement (evita derivative kick)
51 * - Slew-rate limit (limitación de cambio por ciclo)
52 * - Saturación final
53 *
54 * @param setpoint Valor deseado.
55 * @param feedback Valor medido.
56 * @return Salida del controlador PID.
57 */
58float PID::calculoPID(float setpoint, float feedback, bool debugMSG)
59{
60 // 1) Error actual
61 this->error = setpoint - feedback;
62
63 // 2) Proporcional
64 this->proportional = this->Kp * this->error;
65
66 // Protección dt
67 if (this->dt <= 0.0f)
68 return this->output;
69
70 // 3) Derivada (derivative-on-measurement)
71 this->derivative = -(feedback - this->prevFeedback) / this->dt;
72
73 // 4) Anti-windup condicional
74 this->pidNoIntegral = this->proportional + this->Kd * this->derivative;
75 this->saturated = (this->pidNoIntegral > this->outputMax) || (this->pidNoIntegral < this->outputMin);
76
77 if (!this->saturated)
78 {
79 this->integral += this->error * this->dt;
80
81 if (this->integral > this->outputMax) this->integral = this->outputMax;
82 if (this->integral < this->outputMin) this->integral = this->outputMin;
83 }
84
85 // 5) PID completo sin limitación de cambio
86 this->rawOutput = this->proportional +
87 (this->Ki * this->integral) +
88 (this->Kd * this->derivative);
89
90 // 6) Slew-rate limit
91 this->deltaOutput = this->rawOutput - this->prevOutput;
92
93 if (this->deltaOutput > this->outputMaxChanged)
94 this->output = this->prevOutput + this->outputMaxChanged;
95 else if (this->deltaOutput < -this->outputMaxChanged)
96 this->output = this->prevOutput - this->outputMaxChanged;
97 else
98 this->output = this->rawOutput;
99
100 // 7) Saturación final
101 if (this->output > this->outputMax) this->output = this->outputMax;
102 if (this->output < this->outputMin) this->output = this->outputMin;
103
104 // 8) Guardar estado
105 this->prevError = this->error;
106 this->prevFeedback = feedback;
107 this->prevOutput = this->output;
108
109
110 // 9) Debug
111 if (debugMSG) printDebugPID(setpoint, feedback);
112
113 return this->output;
114
115};
116
117/**
118 * @brief Establece nuevas ganancias PID.
119 *
120 * @param Kp Nueva ganancia proporcional.
121 * @param Ki Nueva ganancia integral.
122 * @param Kd Nueva ganancia derivativa.
123 */
124void PID::setKPID(float Kp, float Ki, float Kd)
125{
126 this->Kp = Kp;
127 this->Ki = Ki;
128 this->Kd = Kd;
129}
130
131/**
132 * @brief Establece los límites de salida del PID.
133 *
134 * @param outputMin Nuevo límite mínimo.
135 * @param outputMax Nuevo límite máximo.
136 */
138{
139 this->outputMin = outputMin;
140 this->outputMax = outputMax;
141}
142
143/**
144 * @brief Establece un nuevo tiempo de muestreo.
145 *
146 * @param dt Nuevo dt.
147 */
148void PID::setDt(float dt)
149{
150 this->dt = statedt(dt);
151}
152
153/**
154 * @brief Reinicia el estado interno del PID.
155 */
157{
158 this->error = 0.0f;
159 this->prevError = 0.0f;
160 this->integral = 0.0f;
161 this->derivative = 0.0f;
162 this->output = 0.0f;
163 this->prevFeedback = 0.0f;
164 this->prevOutput = 0.0f;
165}
166
167/**
168 * @brief Valida el tiempo de muestreo.
169 *
170 * @param dt Tiempo de muestreo solicitado.
171 * @return dt válido (mínimo 0.1f).
172 */
173float PID::statedt(float dt)
174{
175 if (dt <= 0.0f)
176 return 0.1f;
177
178 return dt;
179}
180
181
182/**
183 * @brief Muestra en consola el estado interno del PID en formato tabla.
184 *
185 * @param setpoint Valor deseado.
186 * @param feedback Valor medido.
187 */
188void PID::printDebugPID(float setpoint, float feedback)
189{
190 Serial.println(F("--------------------------------------------------------------------------"));
191 Serial.println(F("| SP | FB | Error | P | I | D | RawOut | Out |"));
192 Serial.println(F("--------------------------------------------------------------------------"));
193
194 Serial.print(F("| "));
195 Serial.print(setpoint, 3);
196 Serial.print(F(" | "));
197
198 Serial.print(feedback, 3);
199 Serial.print(F(" | "));
200
201 Serial.print(this->error, 3);
202 Serial.print(F(" | "));
203
204 Serial.print(this->proportional, 3);
205 Serial.print(F(" | "));
206
207 Serial.print(this->integral, 3);
208 Serial.print(F(" | "));
209
210 Serial.print(this->derivative, 3);
211 Serial.print(F(" | "));
212
213 Serial.print(this->rawOutput, 3);
214 Serial.print(F(" | "));
215
216 Serial.print(this->output, 3);
217 Serial.println(F(" |"));
218
219 Serial.println(F("--------------------------------------------------------------------------"));
220}
float integral
Acumulador integral.
Definition pid.h:106
float Kd
Ganancia derivativa.
Definition pid.h:93
bool saturated
Indica si el PID está saturado.
Definition pid.h:108
PID(float Kp, float Ki, float Kd, float outputMin, float outputMax, float dt, float outputMaxChanged)
Constructor del controlador PID.
Definition pid.cpp:20
float prevError
Error previo.
Definition pid.h:104
void resetPID()
Reinicia el estado interno del PID.
Definition pid.cpp:156
float deltaOutput
Cambio entre salidas.
Definition pid.h:113
float error
Error actual.
Definition pid.h:103
float outputMax
Límite máximo de salida.
Definition pid.h:97
float statedt(float dt)
Valida y corrige el tiempo de muestreo.
Definition pid.cpp:173
float output
Salida final del PID.
Definition pid.h:110
float derivative
Término derivativo.
Definition pid.h:109
float Kp
Ganancia proporcional.
Definition pid.h:91
void printDebugPID(float setpoint, float feedback)
Imprime información de depuración del PID.
Definition pid.cpp:188
float outputMaxChanged
Máximo cambio permitido por ciclo.
Definition pid.h:117
void setOutputLimits(float outputMin, float outputMax)
Establece los límites de salida del PID.
Definition pid.cpp:137
float rawOutput
Salida sin limitación de cambio.
Definition pid.h:111
float outputMin
Límite mínimo de salida.
Definition pid.h:96
float dt
Tiempo de muestreo.
Definition pid.h:100
float prevOutput
Salida previa.
Definition pid.h:112
float prevFeedback
Feedback previo para derivative-on-measurement.
Definition pid.h:114
float Ki
Ganancia integral.
Definition pid.h:92
float proportional
Término proporcional.
Definition pid.h:105
float pidNoIntegral
PID sin término integral.
Definition pid.h:107
void setDt(float dt)
Establece un nuevo tiempo de muestreo.
Definition pid.cpp:148
float calculoPID(float setpoint, float feedback, bool debugMSG=false)
Calcula la salida del controlador PID.
Definition pid.cpp:58
void setKPID(float Kp, float Ki, float Kd)
Establece nuevas ganancias PID.
Definition pid.cpp:124