libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
pid.hpp
1#pragma once
2
3#include <algorithm>
4#include <cmath>
5#include <utility>
6
7#include "cycle_value.hpp"
8
9namespace LibXR
10{
11using DefaultScalar = LIBXR_DEFAULT_SCALAR;
12
13constexpr DefaultScalar PID_SIGMA = 1e-6f;
14
25template <typename Scalar = DefaultScalar>
26class PID
27{
28 public:
33 struct Param
34 {
35 Scalar k = 1.0;
36 Scalar p = 0.0;
37 Scalar i = 0.0;
38 Scalar d = 0.0;
39 Scalar i_limit = 0.0;
40 Scalar out_limit = 0.0;
41 bool cycle = false;
42 };
43
52 template <typename P>
53 PID(P&& p) : param_(std::forward<P>(p))
54 {
55 Reset();
56 }
57
74 Scalar Calculate(Scalar sp, Scalar fb, Scalar dt)
75 {
76 if (!std::isfinite(sp) || !std::isfinite(fb) || !std::isfinite(dt) || dt <= Scalar(0))
77 {
78 return last_out_;
79 }
80
81 // Compute error
82 const Scalar ERR = param_.cycle ? (CycleValue<Scalar>(sp) - fb) : (sp - fb);
83 const Scalar E_K = ERR * param_.k;
84
85 // Derivative from feedback change (scaled by k)
86 Scalar fb_dot = (fb - last_fb_) / dt;
87 if (!std::isfinite(fb_dot))
88 {
89 fb_dot = Scalar(0);
90 }
91
92 Scalar fb_d_k = fb_dot * param_.k;
93 if (!std::isfinite(fb_d_k))
94 {
95 fb_d_k = Scalar(0);
96 }
97
98 // Compute PD
99 const Scalar OUTPUT_PD = (E_K * param_.p) - (fb_d_k * param_.d);
100
101 // -------------------------------
102 // Integrator update: anti-windup + allow unwind
103 // Rule: i_limit == 0 disables I (force i_ = 0)
104 // -------------------------------
105 if (param_.i > PID_SIGMA && param_.i_limit > PID_SIGMA)
106 {
107 Scalar i_candidate = i_ + E_K * dt;
108
109 if (std::isfinite(i_candidate))
110 {
111 // Clamp integrator state
112 i_candidate = std::clamp(i_candidate, -param_.i_limit, param_.i_limit);
113
114 bool accept = true;
115
116 // Output-limit-aware gating (windup prevention + unwind)
117 if (param_.out_limit > PID_SIGMA)
118 {
119 const Scalar OUT_BEFORE = OUTPUT_PD + (i_ * param_.i) + feed_forward_;
120 const Scalar OUT_AFTER = OUTPUT_PD + (i_candidate * param_.i) + feed_forward_;
121
122 if (std::isfinite(OUT_BEFORE) && std::isfinite(OUT_AFTER))
123 {
124 const bool BEFORE_SAT = (std::abs(OUT_BEFORE) > param_.out_limit);
125 const bool AFTER_SAT = (std::abs(OUT_AFTER) > param_.out_limit);
126
127 if (AFTER_SAT)
128 {
129 // If saturated (or would be), only allow integral update if it reduces
130 // saturation magnitude
131 // - If not saturated before but would saturate after: reject (prevent
132 // windup)
133 // - If already saturated: allow only if |out_after| < |out_before| (unwind)
134 accept = BEFORE_SAT && (std::abs(OUT_AFTER) < std::abs(OUT_BEFORE));
135 }
136 }
137 else
138 {
139 accept = false;
140 }
141 }
142
143 if (accept)
144 {
145 i_ = i_candidate;
146 }
147 }
148 }
149 else
150 {
151 // Disable I
152 i_ = Scalar(0);
153 }
154
155 const Scalar I_OUT = i_ * param_.i;
156
157 // Apply output limits
158 Scalar output = OUTPUT_PD + I_OUT + feed_forward_;
159 if (std::isfinite(output) && param_.out_limit > PID_SIGMA)
160 {
161 output = std::clamp(output, -param_.out_limit, param_.out_limit);
162 }
163
164 // Store states
165 last_err_ = ERR;
166 last_fb_ = fb; // store raw feedback
167 last_out_ = output;
168 last_der_ = fb_d_k; // store scaled derivative: k * d(fb)/dt
169 return output;
170 }
171
189 Scalar Calculate(Scalar sp, Scalar fb, Scalar fb_dot, Scalar dt)
190 {
191 if (!std::isfinite(sp) || !std::isfinite(fb) || !std::isfinite(fb_dot) ||
192 !std::isfinite(dt) || dt <= Scalar(0))
193 {
194 return last_out_;
195 }
196
197 // Compute error
198 const Scalar ERR = param_.cycle ? (CycleValue<Scalar>(sp) - fb) : (sp - fb);
199 const Scalar E_K = ERR * param_.k;
200
201 // Use externally provided derivative (scaled by k)
202 Scalar fb_d_k = fb_dot * param_.k;
203 if (!std::isfinite(fb_d_k))
204 {
205 fb_d_k = Scalar(0);
206 }
207
208 // Compute PD
209 const Scalar OUTPUT_PD = (E_K * param_.p) - (fb_d_k * param_.d);
210
211 // -------------------------------
212 // Integrator update: anti-windup + allow unwind
213 // Rule: i_limit == 0 disables I (force i_ = 0)
214 // -------------------------------
215 if (param_.i > PID_SIGMA && param_.i_limit > PID_SIGMA)
216 {
217 Scalar i_candidate = i_ + E_K * dt;
218
219 if (std::isfinite(i_candidate))
220 {
221 // Clamp integrator state
222 i_candidate = std::clamp(i_candidate, -param_.i_limit, param_.i_limit);
223
224 bool accept = true;
225
226 if (param_.out_limit > PID_SIGMA)
227 {
228 const Scalar OUT_BEFORE = OUTPUT_PD + (i_ * param_.i) + feed_forward_;
229 const Scalar OUT_AFTER = OUTPUT_PD + (i_candidate * param_.i) + feed_forward_;
230
231 if (std::isfinite(OUT_BEFORE) && std::isfinite(OUT_AFTER))
232 {
233 const bool BEFORE_SAT = (std::abs(OUT_BEFORE) > param_.out_limit);
234 const bool AFTER_SAT = (std::abs(OUT_AFTER) > param_.out_limit);
235
236 if (AFTER_SAT)
237 {
238 accept = BEFORE_SAT && (std::abs(OUT_AFTER) < std::abs(OUT_BEFORE));
239 }
240 }
241 else
242 {
243 accept = false;
244 }
245 }
246
247 if (accept)
248 {
249 i_ = i_candidate;
250 }
251 }
252 }
253 else
254 {
255 // Disable I
256 i_ = Scalar(0);
257 }
258
259 const Scalar I_OUT = i_ * param_.i;
260
261 // Apply output limits
262 Scalar output = OUTPUT_PD + I_OUT + feed_forward_;
263 if (std::isfinite(output) && param_.out_limit > PID_SIGMA)
264 {
265 output = std::clamp(output, -param_.out_limit, param_.out_limit);
266 }
267
268 // Store states
269 last_err_ = ERR;
270 last_fb_ = fb; // store raw feedback
271 last_out_ = output;
272 last_der_ = fb_d_k; // store scaled derivative: k * d(fb)/dt
273 return output;
274 }
275
277 void SetK(Scalar k) { param_.k = k; }
279 void SetP(Scalar p) { param_.p = p; }
281 void SetI(Scalar i) { param_.i = i; }
283 void SetD(Scalar d) { param_.d = d; }
285 void SetILimit(Scalar limit) { param_.i_limit = limit; }
287 void SetOutLimit(Scalar limit) { param_.out_limit = limit; }
288
290 Scalar K() const { return param_.k; }
292 Scalar P() const { return param_.p; }
294 Scalar I() const { return param_.i; }
296 Scalar D() const { return param_.d; }
298 Scalar ILimit() const { return param_.i_limit; }
300 Scalar OutLimit() const { return param_.out_limit; }
302 Scalar LastError() const { return last_err_; }
304 Scalar LastFeedback() const { return last_fb_; }
306 Scalar LastOutput() const { return last_out_; }
308 Scalar LastDerivative() const { return last_der_; }
309
314 void Reset()
315 {
316 i_ = 0;
317 last_err_ = 0;
318 last_fb_ = 0;
319 last_out_ = 0;
320 last_der_ = 0;
321 }
322
328 void SetIntegralError(Scalar err) { i_ = err; }
329
335 Scalar GetIntegralError() const { return i_; }
336
342 void SetFeedForward(Scalar feed_forward) { feed_forward_ = feed_forward; }
343
349 Scalar GetFeedForward() const { return feed_forward_; }
350
351 private:
353 Scalar i_ = 0;
354 Scalar last_err_ = 0;
355 Scalar last_fb_ = 0;
356 Scalar last_der_ = 0;
357 Scalar last_out_ = 0;
358 Scalar feed_forward_ = 0;
359};
360
361} // namespace LibXR
角度循环处理类,用于处理周期性角度计算。 A cyclic angle handling class for periodic angle calculations.
通用 PID 控制器类。 Generic PID controller.
Definition pid.hpp:27
Scalar D() const
获取 D 项系数 Get derivative gain
Definition pid.hpp:296
void SetOutLimit(Scalar limit)
设置输出限幅 Set output limit
Definition pid.hpp:287
Scalar ILimit() const
获取积分限幅 Get integral limit
Definition pid.hpp:298
Scalar LastFeedback() const
获取上一次反馈值(未缩放)Get last feedback (raw)
Definition pid.hpp:304
Scalar last_err_
上次误差 Last error
Definition pid.hpp:354
Scalar GetFeedForward() const
获取前馈项 Get feedforward
Definition pid.hpp:349
Scalar P() const
获取 P 项系数 Get proportional gain
Definition pid.hpp:292
Scalar LastDerivative() const
获取上一次导数(k * d(fb)/dt 或 k * fb_dot)Get last derivative (scaled by k)
Definition pid.hpp:308
Scalar LastOutput() const
获取上一次输出 Get last output
Definition pid.hpp:306
void SetD(Scalar d)
设置 D 项系数 Set derivative gain
Definition pid.hpp:283
void Reset()
重置控制器状态。 Reset all internal states.
Definition pid.hpp:314
Scalar last_fb_
上次反馈(未缩放)Last feedback (raw)
Definition pid.hpp:355
void SetP(Scalar p)
设置 P 项系数 Set proportional gain
Definition pid.hpp:279
Scalar last_der_
上次导数(k 缩放)Last derivative (scaled by k)
Definition pid.hpp:356
Scalar Calculate(Scalar sp, Scalar fb, Scalar dt)
使用反馈值计算 PID 输出。 Compute output from feedback only.
Definition pid.hpp:74
void SetILimit(Scalar limit)
设置积分限幅 Set integral limit
Definition pid.hpp:285
Scalar I() const
获取 I 项系数 Get integral gain
Definition pid.hpp:294
Scalar OutLimit() const
获取输出限幅 Get output limit
Definition pid.hpp:300
Scalar Calculate(Scalar sp, Scalar fb, Scalar fb_dot, Scalar dt)
使用外部导数计算 PID 输出。 Compute output using external feedback derivative.
Definition pid.hpp:189
Scalar last_out_
上次输出 Last output
Definition pid.hpp:357
void SetIntegralError(Scalar err)
设置累计误差 Set integral error
Definition pid.hpp:328
Scalar GetIntegralError() const
获取累计误差 Get integral error
Definition pid.hpp:335
void SetI(Scalar i)
设置 I 项系数 Set integral gain
Definition pid.hpp:281
void SetK(Scalar k)
设置全局比例系数 Set global proportional gain
Definition pid.hpp:277
Scalar i_
积分状态 Integral state
Definition pid.hpp:353
Param param_
PID 参数 PID parameter set.
Definition pid.hpp:352
Scalar feed_forward_
前馈项 Feedforward term
Definition pid.hpp:358
Scalar LastError() const
获取上一次误差 Get last error
Definition pid.hpp:302
Scalar K() const
获取全局比例系数 Get global proportional gain
Definition pid.hpp:290
PID(P &&p)
构造 PID 控制器。 Construct a PID controller.
Definition pid.hpp:53
void SetFeedForward(Scalar feed_forward)
设置前馈项 Set feedforward
Definition pid.hpp:342
LibXR 命名空间
PID 参数结构体。 Structure holding PID parameters.
Definition pid.hpp:34
Scalar i_limit
积分限幅 Integral limit
Definition pid.hpp:39
Scalar out_limit
输出限幅 Output limit
Definition pid.hpp:40
Scalar p
比例项 Proportional gain
Definition pid.hpp:36
bool cycle
是否处理周期误差 Whether input is cyclic
Definition pid.hpp:41
Scalar k
全局比例因子 Global gain
Definition pid.hpp:35
Scalar i
积分项 Integral gain
Definition pid.hpp:37
Scalar d
微分项 Derivative gain
Definition pid.hpp:38