1use crate::Demands;
10use crate::VehicleState;
11
12use crate::filters;
13
14use crate::utils::constrain_f;
15
16use crate::clock::DT;
17
18const DTERM_LPF1_DYN_MIN_HZ: f32 = 75.0;
19const DTERM_LPF1_DYN_MAX_HZ: f32 = 150.0;
20const DTERM_LPF2_HZ: f32 = 150.0;
21const D_MIN_LOWPASS_HZ: f32 = 35.0;
22const ITERM_RELAX_CUTOFF: f32 = 15.0;
23const D_MIN_RANGE_HZ: f32 = 85.0;
24
25const DYN_LPF_THROTTLE_UPDATE_DELAY_US: u32 = 5000;
27
28const DYN_LPF_THROTTLE_STEPS: f32 = 100.0;
29
30const ITERM_LIMIT: f32 = 400.0;
31
32const ITERM_WINDUP_POINT_PERCENT: f32 = 85.0;
33
34const ITERM_RELAX_SETPOINT_THRESHOLD: f32 = 40.0;
36
37const D_MIN: f32 = 30.0;
38const D_MIN_GAIN: f32 = 37.0;
39const D_MIN_ADVANCE: f32 = 20.0;
40
41const FEEDFORWARD_MAX_RATE_LIMIT: f32 = 900.0;
42
43const DYN_LPF_CURVE_EXPO: f32 = 5.0;
44
45const D_MIN_GAIN_FACTOR: f32 = 0.00008;
47const D_MIN_SETPOINT_GAIN_FACTOR: f32 = 0.00008;
48
49const RATE_ACCEL_LIMIT: f32 = 0.0;
50const YAW_RATE_ACCEL_LIMIT: f32 = 0.0;
51
52const OUTPUT_SCALING: f32 = 1000.0;
53const LIMIT_CYCLIC: f32 = 500.0;
54const LIMIT_YAW: f32 = 400.0;
55
56const YAW_LOWPASS_HZ: f32 = 100.0;
57
58#[derive(Clone)]
59pub struct Pid {
60 k_rate_p: f32,
61 k_rate_i: f32,
62 k_rate_d: f32,
63 k_rate_f: f32,
64 k_level_p: f32,
65 usec_prev: u32,
66 roll : CyclicAxis,
67 pitch : CyclicAxis,
68 yaw: Axis,
69 dyn_lpf_previous_quantized_throttle: i32,
70 pterm_yaw_lpf: filters::Pt1
71}
72
73pub fn make(
74 k_rate_p: f32,
75 k_rate_i: f32,
76 k_rate_d: f32,
77 k_rate_f: f32,
78 k_level_p: f32) -> Pid {
79
80 Pid {
81 k_rate_p: k_rate_p,
82 k_rate_i: k_rate_i,
83 k_rate_d: k_rate_d,
84 k_rate_f: k_rate_f,
85 k_level_p: k_level_p,
86 usec_prev: 0,
87 roll : make_cyclic_axis(),
88 pitch : make_cyclic_axis(),
89 yaw: make_axis(),
90 dyn_lpf_previous_quantized_throttle: 0,
91 pterm_yaw_lpf : filters::make_pt1(YAW_LOWPASS_HZ)
92 }
93}
94
95pub fn get_demands(
96 pid: &mut Pid,
97 usec: &u32,
98 demands: &Demands,
99 vstate: &VehicleState,
100 reset: &bool) -> Demands {
101
102 let d_usec = *usec - pid.usec_prev;
103 pid.usec_prev = *usec;
104
105 let roll_demand = rescale_axis(demands.roll);
106 let pitch_demand = rescale_axis(demands.pitch);
107 let yaw_demand = rescale_axis(demands.yaw);
108
109 let max_velocity = RATE_ACCEL_LIMIT * 100.0 * DT;
110
111 let roll =
112 update_cyclic(
113 &mut pid.roll,
114 pid.k_level_p,
115 pid.k_rate_p,
116 pid.k_rate_i,
117 pid.k_rate_d,
118 pid.k_rate_f,
119 roll_demand,
120 vstate.phi,
121 vstate.dphi,
122 max_velocity);
123
124
125 let pitch =
126 update_cyclic(
127 &mut pid.pitch,
128 pid.k_level_p,
129 pid.k_rate_p,
130 pid.k_rate_i,
131 pid.k_rate_d,
132 pid.k_rate_f,
133 pitch_demand,
134 vstate.theta,
135 vstate.dtheta,
136 max_velocity);
137
138 let yaw = update_yaw(
139 &mut pid.yaw,
140 pid.pterm_yaw_lpf,
141 pid.k_rate_p,
142 pid.k_rate_i,
143 yaw_demand,
144 vstate.dpsi);
145
146 pid.roll.axis.integral = if *reset { 0.0 } else { pid.roll.axis.integral };
147 pid.pitch.axis.integral = if *reset { 0.0 } else { pid.pitch.axis.integral };
148 pid.yaw.integral = if *reset { 0.0 } else { pid.yaw.integral };
149
150 if d_usec >= DYN_LPF_THROTTLE_UPDATE_DELAY_US {
151
152 let quantized_throttle = (demands.throttle * DYN_LPF_THROTTLE_STEPS) as i32;
154
155 if quantized_throttle != pid.dyn_lpf_previous_quantized_throttle {
156
157 let dyn_lpf_throttle = (quantized_throttle as f32) / DYN_LPF_THROTTLE_STEPS;
160
161 let cutoff_freq = dyn_lpf_cutoff_freq(dyn_lpf_throttle,
162 DTERM_LPF1_DYN_MIN_HZ,
163 DTERM_LPF1_DYN_MAX_HZ,
164 DYN_LPF_CURVE_EXPO);
165
166 init_lpf1(&mut pid.roll, cutoff_freq);
167 init_lpf1(&mut pid.pitch, cutoff_freq);
168
169 pid.dyn_lpf_previous_quantized_throttle = quantized_throttle;
170 }
171 }
172
173 Demands {
174 throttle : demands.throttle,
175 roll : constrain_output(roll, LIMIT_CYCLIC),
176 pitch : constrain_output(pitch, LIMIT_CYCLIC),
177 yaw : constrain_output(yaw, LIMIT_YAW)
178 }
179 }
180
181#[derive(Clone,Copy)]
182struct Axis {
183
184 previous_setpoint : f32,
185 integral : f32
186}
187
188#[derive(Clone)]
189struct CyclicAxis {
190
191 axis: Axis,
192 dterm_lpf1 : filters::Pt1,
193 dterm_lpf2 : filters::Pt1,
194 d_min_lpf: filters::Pt2,
195 d_min_range: filters::Pt2,
196 windup_lpf: filters::Pt1,
197 previous_dterm: f32
198}
199
200fn update_cyclic(
201 cyclic_axis: &mut CyclicAxis,
202 k_level_p: f32,
203 k_rate_p: f32,
204 k_rate_i: f32,
205 k_rate_d: f32,
206 k_rate_f: f32,
207 demand: f32,
208 angle: f32,
209 angvel: f32,
210 max_velocity: f32) -> f32
211{
212 let axis: &mut Axis = &mut cyclic_axis.axis;
213
214 let current_setpoint =
215 if max_velocity > 0.0
216 {acceleration_limit(axis, demand, max_velocity)}
218 else {demand};
219
220 let new_setpoint = level_pid(k_level_p, current_setpoint, angle);
221
222 let error_rate = new_setpoint - angvel;
224
225 let setpoint_lpf = filters::apply_pt1(cyclic_axis.windup_lpf, current_setpoint);
226
227 let setpoint_hpf = (current_setpoint - setpoint_lpf).abs();
228
229 let iterm_relax_factor =
230 (1.0 - setpoint_hpf / ITERM_RELAX_SETPOINT_THRESHOLD).max(0.0);
231
232 let is_decreasing_i =
233 ((axis.integral > 0.0) && (error_rate < 0.0)) ||
234 ((axis.integral < 0.0) && (error_rate > 0.0));
235
236 let iterm_error_rate = error_rate * (if !is_decreasing_i {iterm_relax_factor} else {1.0} );
238
239 let frequency = 1.0 / DT;
240
241 let pterm = k_rate_p * error_rate;
243
244 axis.integral = constrain_f(axis.integral + (k_rate_i * DT) * iterm_error_rate,
246 -ITERM_LIMIT, ITERM_LIMIT);
247
248 let dterm = filters::apply_pt1(
251 cyclic_axis.dterm_lpf2,
252 filters::apply_pt1(cyclic_axis.dterm_lpf1, angvel));
253
254 let delta = -(dterm - cyclic_axis.previous_dterm) * frequency;
260
261 let pre_t_pa_d = k_rate_d * delta;
262
263 let d_min_percent = if D_MIN > 0.0 && D_MIN < k_rate_d { D_MIN / k_rate_d } else { 0.0 };
264
265 let demand_delta: f32 = 0.0;
266
267 let d_min_gyro_gain = D_MIN_GAIN * D_MIN_GAIN_FACTOR / D_MIN_LOWPASS_HZ;
268
269 let d_min_gyro_factor = (filters::apply_pt2(cyclic_axis.d_min_range, delta)).abs() * d_min_gyro_gain;
270
271 let d_min_setpoint_gain =
272 D_MIN_GAIN * D_MIN_SETPOINT_GAIN_FACTOR * D_MIN_ADVANCE * frequency /
273 (100.0 * D_MIN_LOWPASS_HZ);
274
275 let d_min_setpoint_factor = (demand_delta).abs() * d_min_setpoint_gain;
276
277 let d_min_factor =
278 d_min_percent + (1.0 - d_min_percent) * d_min_gyro_factor.max(d_min_setpoint_factor);
279
280 let d_min_factor_filtered = filters::apply_pt2(cyclic_axis.d_min_lpf, d_min_factor);
281
282 let d_min_factor = d_min_factor_filtered.min(1.0);
283
284 cyclic_axis.previous_dterm = dterm;
285
286 let dterm = pre_t_pa_d * d_min_factor;
288
289 let feed_forward = k_rate_f * demand_delta * frequency;
295
296 let feedforward_max_rate: f32 = 670.0;
297
298 let feedforward_max_rate_limit =
299 feedforward_max_rate * FEEDFORWARD_MAX_RATE_LIMIT * 0.01;
300
301 let fterm = if feedforward_max_rate_limit != 0.0 {
302 apply_feeedforward_limit(
303 feed_forward,
304 current_setpoint,
305 k_rate_p,
306 feedforward_max_rate_limit) }
307 else {
308 feed_forward
309 };
310
311 pterm + axis.integral + dterm + fterm
312
313} fn update_yaw(
317 axis: &mut Axis,
318 pterm_lpf: filters::Pt1,
319 kp: f32,
320 ki: f32,
321 demand: f32,
322 angvel: f32) -> f32 {
323
324 let iterm_windup_point_inv = 1.0 / (1.0 - (ITERM_WINDUP_POINT_PERCENT / 100.0));
326
327 let dyn_ci = DT * (if iterm_windup_point_inv > 1.0
328 {constrain_f(iterm_windup_point_inv, 0.0, 1.0)}
329 else {1.0});
330
331 let max_velocity = YAW_RATE_ACCEL_LIMIT * 100.0 * DT;
332
333 let current_setpoint =
334 if max_velocity > 0.0 {acceleration_limit(axis, demand, max_velocity)} else {demand};
335
336 let error_rate = current_setpoint - angvel;
337
338 let pterm = filters::apply_pt1(pterm_lpf, kp * error_rate);
340
341 axis.integral =
343 constrain_f(axis.integral + (ki * dyn_ci) * error_rate, -ITERM_LIMIT, ITERM_LIMIT);
344
345 pterm + axis.integral
346 }
347
348
349fn make_cyclic_axis() -> CyclicAxis {
350
351 CyclicAxis {
352 axis: make_axis(),
353 dterm_lpf1 : filters::make_pt1(DTERM_LPF1_DYN_MIN_HZ),
354 dterm_lpf2 : filters::make_pt1(DTERM_LPF2_HZ),
355 d_min_lpf: filters::make_pt2(D_MIN_LOWPASS_HZ),
356 d_min_range: filters::make_pt2(D_MIN_RANGE_HZ),
357 windup_lpf: filters::make_pt1(ITERM_RELAX_CUTOFF),
358 previous_dterm: 0.0 }
359}
360
361fn make_axis() -> Axis {
362
363 Axis { previous_setpoint: 0.0, integral: 0.0 }
364}
365
366fn rescale_axis(command: f32) -> f32 {
368
369 const CTR: f32 = 0.104;
370
371 let expof = command * command.abs();
372 let angle_rate = command * CTR + (1.0 - CTR) * expof;
373
374 670.0 * angle_rate
375}
376
377fn level_pid(k_level_p: f32, current_setpoint: f32, current_angle: f32) -> f32
378{
379 const LEVEL_ANGLE_LIMIT: f32 = 45.0;
383
384 let angle = constrain_f(LEVEL_ANGLE_LIMIT * current_setpoint,
385 -LEVEL_ANGLE_LIMIT, LEVEL_ANGLE_LIMIT);
386
387 let angle_error = angle - (current_angle / 10.0);
388
389 if k_level_p > 0.0 {angle_error * k_level_p } else {current_setpoint}
390}
391
392fn acceleration_limit(axis: &mut Axis, current_setpoint: f32, max_velocity: f32) -> f32 {
393
394 let current_velocity = current_setpoint - axis.previous_setpoint;
395
396 let new_setpoint =
397 if current_velocity.abs() > max_velocity
398 { if current_velocity > 0.0
399 { axis.previous_setpoint + max_velocity }
400 else { axis.previous_setpoint - max_velocity }
401 }
402 else { current_setpoint };
403
404 axis.previous_setpoint = new_setpoint;
405
406 new_setpoint
407}
408
409
410fn apply_feeedforward_limit(
411 value: f32,
412 current_setpoint: f32,
413 k_rate_p : f32,
414 max_rate_limit: f32) -> f32 {
415
416 if value * current_setpoint > 0.0 {
417 if current_setpoint.abs() <= max_rate_limit
418 { constrain_f(value, (-max_rate_limit -
419 current_setpoint) * k_rate_p,
420 (max_rate_limit - current_setpoint) * k_rate_p)}
421 else {
422 0.0
423 }
424 }
425 else {
426 0.0
427 }
428 }
429
430fn init_lpf1(cyclic_axis: &mut CyclicAxis, cutoff_freq: f32) {
431
432 filters::adjust_pt1_gain(cyclic_axis.dterm_lpf1, cutoff_freq);
433}
434
435fn dyn_lpf_cutoff_freq(throttle: f32, dyn_lpf_min: f32, dyn_lpf_max: f32, expo: f32) -> f32 {
436 let expof = expo / 10.0;
437 let curve = throttle * (1.0 - throttle) * expof + throttle;
438
439 (dyn_lpf_max - dyn_lpf_min) * curve + dyn_lpf_min
440}
441
442
443fn constrain_output(demand: f32, limit: f32) -> f32 {
444
445 constrain_f(demand, -limit, limit) / OUTPUT_SCALING
446}