Skip to content

Commit d862291

Browse files
committed
Add code of parking controller
1 parent ba7d01e commit d862291

File tree

1 file changed

+109
-1
lines changed

1 file changed

+109
-1
lines changed

src/SimpleKiteControllers.jl

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,113 @@
11
module SimpleKiteControllers
22

3-
# Write your package code here.
3+
using DiscretePIDs, Parameters
44

5+
@with_kw mutable struct ParkingControllerSettings @deftype Float64
6+
dt
7+
# turn rate controller settings
8+
kp_tr=0.06
9+
ki_tr=0.0012
10+
# outer controller (heading/ course) settings
11+
kp=15
12+
ki=0.5
13+
# NDI block settings
14+
va_min = 5.0 # minimum apparent wind speed
15+
va_max = 100.0 # maximum apparent wind speed
16+
k_ds = 2.0 # influence of the depower settings on the steering sensitivity
17+
c1 = 0.048 # v9 kite model
18+
c2 = 0 # a value other than zero creates more problems than it solves
519
end
20+
21+
mutable struct ParkingController
22+
pcs::ParkingControllerSettings
23+
pid_tr::DiscretePID
24+
pid_outer::DiscretePID
25+
last_heading::Float64
26+
chi_set::Float64
27+
last_ndi_gain::Float64
28+
end
29+
30+
function ParkingController(pcs::ParkingControllerSettings; last_heading = 0.0)
31+
Ts = pcs.dt
32+
pid_tr = DiscretePID(;K=pcs.kp_tr, Ti=pcs.kp_tr/ pcs.ki_tr, Ts)
33+
pid_outer = DiscretePID(;K=pcs.kp, Ti=pcs.kp/ pcs.ki, Ts)
34+
return ParkingController(pcs, pid_tr, pid_outer, last_heading, 0, 0)
35+
end
36+
37+
"""
38+
linearize(pcs::ParkingControllerSettings, psi_dot, psi, elevation, v_app; ud_prime=0)
39+
40+
Nonlinear, dynamic inversion block (NDI) according to Eq. 6.4 and Eq. 6.12.
41+
42+
Parameters:
43+
- psi_dot: desired turn rate in radians per second
44+
- psi: heading in radians
45+
- elevation: elevation angle in radians
46+
- v_app: apparent wind speed in m/s
47+
- ud_prime: depower setting in the range of 0 to 1, 0 means fully powered, 1 means fully depowered
48+
"""
49+
function linearize(pc::ParkingController, psi_dot, psi, elevation, v_app; ud_prime=0)
50+
pcs = pc.pcs
51+
# Eq. 6.13: calculate va_hat
52+
va_hat = clamp(v_app, pcs.va_min, pcs.va_max)
53+
# Eq. 6.12: calculate the steering from the desired turn rate
54+
u_s = (1.0 + pcs.k_ds * ud_prime) / (pcs.c1 * va_hat) * (psi_dot - pcs.c2 / va_hat * sin(psi) * cos(elevation))
55+
if abs(psi_dot) < 1e-6
56+
ndi_gain = pc.last_ndi_gain
57+
else
58+
ndi_gain = clamp(u_s / psi_dot, -20, 20.0)
59+
end
60+
pc.last_ndi_gain = ndi_gain
61+
return u_s, ndi_gain
62+
end
63+
64+
"""
65+
navigate(fpc, limit=50.0)
66+
67+
Calculate the desired flight direction chi_set using great circle navigation.
68+
Limit delta_beta to the value of the parameter limit (in degrees).
69+
"""
70+
function navigate(pc::ParkingController, azimuth, elevation; limit=50.0)
71+
phi_set = 0.0 # azimuth
72+
beta_set = deg2rad(77) # zenith
73+
beta = elevation
74+
phi = azimuth
75+
# println("beta: $(rad2deg(beta)), phi: $(rad2deg(phi))")
76+
r_limit = deg2rad(limit)
77+
if beta_set - beta > r_limit
78+
beta_set = beta + r_limit
79+
elseif beta_set - beta < -r_limit
80+
beta_set = beta - r_limit
81+
end
82+
y = sin(phi_set - phi) * cos(beta_set)
83+
x = cos(beta) * sin(beta_set) - sin(beta) * cos(beta_set) * cos(phi_set - phi)
84+
pc.chi_set = atan(y, x)
85+
end
86+
87+
"""
88+
calc_steering(pc::ParkingController, heading; elevation=0.0, v_app=10.0, ud_prime=0.0)
89+
90+
Calculate rel_steering and ndi_gain from the actual heading, elevation, and apparent wind speed.
91+
92+
Parameters:
93+
- pc: parking controller
94+
- heading: actual heading in radians
95+
- elevation: elevation angle in radians
96+
- v_app: apparent wind speed in m/s
97+
- ud_prime: depower setting in the range of 0 to 1, 0 means fully powered, 1 means fully depowered
98+
99+
"""
100+
function calc_steering(pc::ParkingController, heading, chi_set; elevation=0.0, v_app=10.0, ud_prime=0.0)
101+
# calculate the desired turn rate
102+
heading = wrap2pi(heading) # a different wrap2pi function is needed that avoids any jumps
103+
psi_dot_set = pc.pid_outer(wrap2pi(chi_set), heading)
104+
psi_dot = (wrap2pi(heading - pc.last_heading)) / pc.pcs.dt
105+
pc.last_heading = heading
106+
psi_dot_in = pc.pid_tr(psi_dot_set, psi_dot)
107+
# linearize the NDI block
108+
u_s, ndi_gain = linearize(pc, psi_dot_in, heading, elevation, v_app; ud_prime)
109+
u_s, ndi_gain, psi_dot, psi_dot_set
110+
end
111+
112+
end
113+

0 commit comments

Comments
 (0)